All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3] m88brs2000 DVB-S frontend and tuner module.
@ 2012-01-22 10:38 Malcolm Priestley
  2012-01-26 16:56 ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 56+ messages in thread
From: Malcolm Priestley @ 2012-01-22 10:38 UTC (permalink / raw)
  To: linux-media

Support for m88brs2000 chip used in lmedm04 driver.

Note there are still lock problems.

Slow channel change due to the large block of registers sent in set_frontend.

Signed-off-by: Malcolm Priestley <tvboxspy@gmail.com>
---
 drivers/media/dvb/frontends/Kconfig     |    7 +
 drivers/media/dvb/frontends/Makefile    |    1 +
 drivers/media/dvb/frontends/m88rs2000.c |  867 +++++++++++++++++++++++++++++++
 drivers/media/dvb/frontends/m88rs2000.h |   57 ++
 4 files changed, 932 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/dvb/frontends/m88rs2000.c
 create mode 100644 drivers/media/dvb/frontends/m88rs2000.h

diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index ebb5ed7..fe6bcce 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -698,6 +698,13 @@ config DVB_IT913X_FE
 	  A DVB-T tuner module.
 	  Say Y when you want to support this frontend.
 
+config DVB_M88RS2000
+	tristate "M88RS2000 DVB-S"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S tuner module. Say Y when you want to support this frontend.
+
 comment "Tools to develop new frontends"
 
 config DVB_DUMMY_FE
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 00a2063..642c805 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -96,4 +96,5 @@ obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o
 obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o
 obj-$(CONFIG_DVB_A8293) += a8293.o
 obj-$(CONFIG_DVB_TDA10071) += tda10071.o
+obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
 
diff --git a/drivers/media/dvb/frontends/m88rs2000.c b/drivers/media/dvb/frontends/m88rs2000.c
new file mode 100644
index 0000000..a614ffe
--- /dev/null
+++ b/drivers/media/dvb/frontends/m88rs2000.c
@@ -0,0 +1,867 @@
+/*
+	Driver for M88RS2000 demodulator and tuner
+
+	Copyright (C) 2012 Malcolm Priestley (tvboxspy@gmail.com)
+
+	Beta Driver
+
+	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 <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+
+#include "dvb_frontend.h"
+#include "m88rs2000.h"
+
+struct m88rs2000_state {
+	struct i2c_adapter *i2c;
+	const struct m88rs2000_config *config;
+	struct dvb_frontend frontend;
+	u8 no_lock_count;
+	u32 tuner_frequency;
+	u32 symbol_rate;
+	fe_code_rate_t fec_inner;
+	u8 tuner_level;
+	int errmode;
+};
+
+static int debug;
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(KERN_DEBUG "m88rs2000: " args); \
+	} while (0)
+
+
+static int m88rs2000_writereg(struct m88rs2000_state *state, u8 tuner,
+	u8 reg, u8 data)
+{
+	int ret;
+	u8 addr = (tuner == 0) ? state->config->tuner_addr :
+		state->config->demod_addr;
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = {
+		.addr = addr,
+		.flags = 0,
+		.buf = buf,
+		.len = 2
+	};
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
+			"ret == %i)\n", __func__, reg, data, ret);
+
+	return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static int m88rs2000_demod_write(struct m88rs2000_state *state, u8 reg, u8 data)
+{
+	return m88rs2000_writereg(state, 1, reg, data);
+}
+
+static int m88rs2000_tuner_write(struct m88rs2000_state *state, u8 reg, u8 data)
+{
+	m88rs2000_demod_write(state, 0x81, 0x84);
+	return m88rs2000_writereg(state, 0, reg, data);
+}
+
+static int m88rs2000_write(struct dvb_frontend *fe, const u8 buf[], int len)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+
+	if (len != 2)
+		return -EINVAL;
+
+	return m88rs2000_writereg(state, 1, buf[0], buf[1]);
+}
+
+static u8 m88rs2000_readreg(struct m88rs2000_state *state, u8 tuner, u8 reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	u8 addr = (tuner == 0) ? state->config->tuner_addr :
+		state->config->demod_addr;
+	struct i2c_msg msg[] = {
+		{
+			.addr = addr,
+			.flags = 0,
+			.buf = b0,
+			.len = 1
+		}, {
+			.addr = addr,
+			.flags = I2C_M_RD,
+			.buf = b1,
+			.len = 1
+		}
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
+				__func__, reg, ret);
+
+	return b1[0];
+}
+
+static u8 m88rs2000_demod_read(struct m88rs2000_state *state, u8 reg)
+{
+	return m88rs2000_readreg(state, 1, reg);
+}
+
+static u8 m88rs2000_tuner_read(struct m88rs2000_state *state, u8 reg)
+{
+	m88rs2000_demod_write(state, 0x81, 0x85);
+	return m88rs2000_readreg(state, 0, reg);
+}
+
+static int m88rs2000_set_symbolrate(struct dvb_frontend *fe, u32 srate)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	int ret;
+	u32 temp;
+	u8 b[4];
+
+	if ((srate < 1000000) || (srate > 45000000))
+		return -EINVAL;
+	b[3] = m88rs2000_demod_read(state, 0x86);
+
+	temp = srate / 1000;
+	temp *= 11831;
+	temp /= 68;
+	temp -= 3;
+
+	b[0] = (u8) (temp >> 16) & 0xff;
+	b[1] = (u8) (temp >> 8) & 0xff;
+	b[2] = (u8) temp & 0xff;
+	ret = m88rs2000_demod_write(state, 0x93, b[2]);
+	ret |= m88rs2000_demod_write(state, 0x94, b[1]);
+	ret |= m88rs2000_demod_write(state, 0x95, b[0]);
+
+	dprintk("m88rs2000: m88rs2000_set_symbolrate\n");
+	return ret;
+}
+
+static int m88rs2000_send_diseqc_msg(struct dvb_frontend *fe,
+				    struct dvb_diseqc_master_cmd *m)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+
+	int i;
+	u8 reg;
+	dprintk("%s\n", __func__);
+	m88rs2000_demod_write(state, 0x9a, 0x30);
+	msleep(50);
+	reg = m88rs2000_demod_read(state, 0xb2);
+	m88rs2000_demod_write(state, 0xb2, 0x01);
+	for (i = 0; i <  m->msg_len; i++)
+		m88rs2000_demod_write(state, 0xb3 + i, m->msg[i]);
+
+	m88rs2000_demod_write(state, 0xb1, 0x1f);
+
+	for (i = 0; i < 10; i++)
+		if ((m88rs2000_demod_read(state, 0xb1) & 0x40) == 0x0)
+			break;
+	if (m88rs2000_demod_read(state, 0xb1) == 0x1f)
+		m88rs2000_demod_write(state, 0xb1, 0x5f);
+	m88rs2000_demod_write(state, 0xb2, reg);
+	m88rs2000_demod_write(state, 0x9a, 0xb0);
+
+
+	return 0;
+}
+
+static int m88rs2000_send_diseqc_burst(struct dvb_frontend *fe,
+						fe_sec_mini_cmd_t burst)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	u8 reg0, reg1;
+	dprintk("%s\n", __func__);
+	m88rs2000_demod_write(state, 0x9a, 0x30);
+	msleep(50);
+	reg0 = m88rs2000_demod_read(state, 0xb1);
+	reg1 = m88rs2000_demod_read(state, 0xb2);
+
+	m88rs2000_demod_write(state, 0xb2, reg1);
+	m88rs2000_demod_write(state, 0xb1, reg0);
+	m88rs2000_demod_write(state, 0x9a, 0xb0);
+
+	return 0;
+}
+
+static int m88rs2000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	u8 reg0, reg1;
+	m88rs2000_demod_write(state, 0x9a, 0x30);
+	reg0 = m88rs2000_demod_read(state, 0xb1);
+	reg1 = m88rs2000_demod_read(state, 0xb2);
+
+	switch (tone) {
+	case SEC_TONE_ON:
+		reg0 = 0x1c;
+		reg1 = 0x01;
+	break;
+
+	case SEC_TONE_OFF:
+		reg0 = 0x5f;
+		reg1 = 0x81;
+	break;
+
+	default:
+		return -EINVAL;
+	}
+	m88rs2000_demod_write(state, 0xb2, reg1);
+	m88rs2000_demod_write(state, 0xb1, reg0);
+	m88rs2000_demod_write(state, 0x9a, 0xb0);
+	return 0;
+}
+
+struct inittab {
+	u8 cmd;
+	u8 reg;
+	u8 val;
+};
+
+struct inittab m88rs2000_setup[] = {
+	{DEMOD_WRITE, 0x9a, 0x30},
+	{DEMOD_WRITE, 0x00, 0x01},
+	{WRITE_DELAY, 0x19, 0x00},
+	{DEMOD_WRITE, 0x00, 0x00},
+	{DEMOD_WRITE, 0x9a, 0xb0},
+	{DEMOD_WRITE, 0x81, 0xc1},
+	{TUNER_WRITE, 0x42, 0x73},
+	{TUNER_WRITE, 0x05, 0x07},
+	{TUNER_WRITE, 0x20, 0x27},
+	{TUNER_WRITE, 0x07, 0x02},
+	{TUNER_WRITE, 0x11, 0xff},
+	{TUNER_WRITE, 0x60, 0xf9},
+	{TUNER_WRITE, 0x08, 0x01},
+	{TUNER_WRITE, 0x00, 0x41},
+	{DEMOD_WRITE, 0x81, 0x81},
+	{DEMOD_WRITE, 0x86, 0xc6},
+	{DEMOD_WRITE, 0x9a, 0x30},
+	{DEMOD_WRITE, 0xf0, 0x22},
+	{DEMOD_WRITE, 0xf1, 0xbf},
+	{DEMOD_WRITE, 0xb0, 0x45},
+	{DEMOD_WRITE, 0x9a, 0xb0},
+	{0xff, 0xaa, 0xff}
+};
+
+struct inittab tuner_reset[] = {
+	{TUNER_WRITE, 0x42, 0x73},
+	{TUNER_WRITE, 0x05, 0x07},
+	{TUNER_WRITE, 0x20, 0x27},
+	{TUNER_WRITE, 0x07, 0x02},
+	{TUNER_WRITE, 0x11, 0xff},
+	{TUNER_WRITE, 0x60, 0xa1}, /* also f9 0xa1 0x99 */
+	{TUNER_WRITE, 0x08, 0x01},
+	{TUNER_WRITE, 0x00, 0x41},
+	{0xff, 0xaa, 0xff}
+};
+
+struct inittab fe_reset[] = {
+	{DEMOD_WRITE, 0xf1, 0xbf},
+	{DEMOD_WRITE, 0x00, 0x01},
+	{DEMOD_WRITE, 0x20, 0x81},
+	{DEMOD_WRITE, 0x21, 0x80},
+	{DEMOD_WRITE, 0x10, 0x33},
+	{DEMOD_WRITE, 0x11, 0x44},
+	{DEMOD_WRITE, 0x12, 0x07},
+	{DEMOD_WRITE, 0x18, 0x20},
+	{DEMOD_WRITE, 0x28, 0x04},
+	{DEMOD_WRITE, 0x29, 0x8e},
+	{DEMOD_WRITE, 0x3b, 0xff},
+	{DEMOD_WRITE, 0x32, 0x10},
+	{DEMOD_WRITE, 0x33, 0x02},
+	{DEMOD_WRITE, 0x34, 0x30},
+	{DEMOD_WRITE, 0x35, 0xff},
+	{DEMOD_WRITE, 0x38, 0x50},
+	{DEMOD_WRITE, 0x39, 0x68},
+	{DEMOD_WRITE, 0x3c, 0x7f},
+	{DEMOD_WRITE, 0x3d, 0x0f},
+	{DEMOD_WRITE, 0x45, 0x20},
+	{DEMOD_WRITE, 0x46, 0x24},
+	{DEMOD_WRITE, 0x47, 0x7c},
+	{DEMOD_WRITE, 0x48, 0x16},
+	{DEMOD_WRITE, 0x49, 0x04},
+	{DEMOD_WRITE, 0x4a, 0x01},
+	{DEMOD_WRITE, 0x4b, 0x78},
+	{DEMOD_WRITE, 0X4d, 0xd2},
+	{DEMOD_WRITE, 0x4e, 0x6d},
+	{DEMOD_WRITE, 0x50, 0x30},
+	{DEMOD_WRITE, 0x51, 0x30},
+	{DEMOD_WRITE, 0x54, 0x7b},
+	{DEMOD_WRITE, 0x56, 0x09},
+	{DEMOD_WRITE, 0x58, 0x59},
+	{DEMOD_WRITE, 0x59, 0x37},
+	{DEMOD_WRITE, 0x63, 0xfa},
+	{0xff, 0xaa, 0xff}
+};
+
+struct inittab fe_trigger[] = {
+	{DEMOD_WRITE, 0x97, 0x04},
+	{DEMOD_WRITE, 0x99, 0x77},
+	{DEMOD_WRITE, 0x9a, 0xb0},
+	{DEMOD_WRITE, 0x9b, 0x64},
+	{DEMOD_WRITE, 0x9e, 0x00},
+	{DEMOD_WRITE, 0x9f, 0xf8},
+	{DEMOD_WRITE, 0xa0, 0x20},
+	{DEMOD_WRITE, 0xa1, 0xe0},
+	{DEMOD_WRITE, 0xa3, 0x38},
+	{DEMOD_WRITE, 0x98, 0xff},
+	{DEMOD_WRITE, 0xc0, 0x0f},
+	{DEMOD_WRITE, 0x89, 0x01},
+	{DEMOD_WRITE, 0x00, 0x00},
+	{DEMOD_WRITE, 0x00, 0x01},
+	{DEMOD_WRITE, 0x00, 0x00},
+	{0xff, 0xaa, 0xff}
+};
+
+static int m88rs2000_tab_set(struct m88rs2000_state *state,
+		struct inittab *tab)
+{
+	int ret = 0;
+	u8 i;
+	if (tab == NULL)
+		return -EINVAL;
+
+	for (i = 0; i < 255; i++) {
+		switch (tab[i].cmd) {
+		case 0x01:
+			ret = m88rs2000_demod_write(state, tab[i].reg,
+				tab[i].val);
+			break;
+		case 0x02:
+			ret = m88rs2000_tuner_write(state, tab[i].reg,
+				tab[i].val);
+			break;
+		case 0x10:
+			if (tab[i].reg > 0)
+				mdelay(tab[i].reg);
+			break;
+		case 0xff:
+			if (tab[i].reg == 0xaa && tab[i].val == 0xff)
+				return 0;
+		case 0x00:
+			break;
+		default:
+			return -EINVAL;
+		}
+		if (ret < 0)
+			return -ENODEV;
+	}
+	return 0;
+}
+
+static int m88rs2000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
+{
+	dprintk("%s: %s\n", __func__,
+		volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
+		volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
+
+	return 0;
+}
+
+static int m88rs2000_startup(struct m88rs2000_state *state)
+{
+	int ret;
+	u8 reg;
+
+	ret = m88rs2000_tab_set(state, m88rs2000_setup);
+
+	ret |= m88rs2000_demod_write(state, 0x9a, 0x30);
+	reg = m88rs2000_demod_read(state, 0x00);
+	if (reg != 2)
+		ret = -ENODEV;
+	ret |= m88rs2000_demod_write(state, 0x9a, 0xb0);
+
+	return (ret < 0) ? -ENODEV : 0;
+}
+
+static int m88rs2000_init(struct dvb_frontend *fe)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	int ret;
+	u8 reg;
+
+	dprintk("m88rs2000: init chip\n");
+
+	ret = m88rs2000_demod_write(state, 0x9a, 0x30);
+	reg = m88rs2000_demod_read(state, 0x00);
+	if (reg != 2)
+		if (m88rs2000_startup(state) < 0)
+			ret = -ENODEV;
+	/* only write upper nibble */
+	ret |= m88rs2000_demod_write(state, 0x9a, 0xb0);
+
+	return (ret < 0) ? -ENODEV : 0;
+}
+
+static int m88rs2000_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+
+	u8 reg = m88rs2000_demod_read(state, 0x8c);
+	*status = 0;
+	if (reg & 0xc0)
+		*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+	if (reg & 0xd0)
+		*status |= FE_HAS_VITERBI;
+	if (reg & 0x0e) {
+		*status |= FE_HAS_LOCK;
+		state->no_lock_count = 0;
+	} else {
+		state->no_lock_count++;
+		if (state->no_lock_count > 10) {
+			reg = m88rs2000_demod_read(state, 0x70);
+			if (reg == 0xf9)
+				m88rs2000_demod_write(state, 0x70, 0xfd);
+			else
+				m88rs2000_demod_write(state, 0x70, 0xf9);
+			state->no_lock_count = 0;
+		}
+	}
+	return 0;
+}
+
+static int m88rs2000_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	dprintk("m88rs2000_read_ber %d\n", *ber);
+	*ber = 0;
+	return 0;
+}
+
+
+static int m88rs2000_read_signal_strength(struct dvb_frontend *fe,
+	u16 *strength)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+
+	*strength = (m88rs2000_demod_read(state, 0x21) << 8) +
+			m88rs2000_demod_read(state, 0x22);
+
+	return 0;
+}
+static int m88rs2000_sleep(struct dvb_frontend *fe)
+{
+	return 0;
+}
+static int m88rs2000_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	dprintk("m88rs2000_read_snr %d\n", *snr);
+	*snr = 0xffff - ((m88rs2000_demod_read(state, 0x65) << 8));
+	return 0;
+}
+
+static int m88rs2000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	dprintk("m88rs2000_read_ber %d\n", *ucblocks);
+	*ucblocks = 0;
+	return 0;
+}
+
+static int m88rs2000_set_property(struct dvb_frontend *fe,
+	struct dtv_property *p)
+{
+	dprintk("%s(..)\n", __func__);
+	return 0;
+}
+
+static int m88rs2000_get_property(struct dvb_frontend *fe,
+	struct dtv_property *p)
+{
+	dprintk("%s(..)\n", __func__);
+	return 0;
+}
+
+static int m88rs2000_tuner_gate_ctrl(struct m88rs2000_state *state, u8 offset)
+{
+	int ret;
+	ret = m88rs2000_tuner_write(state, 0x51, 0x1f - offset);
+	ret |= m88rs2000_tuner_write(state, 0x51, 0x1f);
+	ret |= m88rs2000_tuner_write(state, 0x50, offset);
+	ret |= m88rs2000_tuner_write(state, 0x50, 0x00);
+	msleep(20);
+	return ret;
+}
+
+static int m88rs2000_set_tuner(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	int ret;
+	u32 symbol_rate = (c->symbol_rate / 1000);
+	u32 freq;
+	u8 lo = 0x01;
+	u8 reg, bw;
+
+	/* Reset Tuner */
+	ret = m88rs2000_tab_set(state, tuner_reset);
+
+	/* Calc Frequency */
+	if (c->frequency < 1060000) {
+		freq = c->frequency - 493000;
+		freq *= 3;
+		freq /= 83;
+		freq += c->frequency - 493000;
+		freq /= 1000;
+		freq *= 2;
+		freq += 1;
+		lo |= 0x10;
+	} else {
+		freq = c->frequency - 986000;
+		freq *= 3;
+		freq /= 83;
+		freq += c->frequency - 986000;
+		freq /= 1000;
+	}
+
+	ret = m88rs2000_tuner_write(state, 0x10, 0x80 | lo);
+
+	/* Bandwidth Settings */
+	if (symbol_rate < 6000)
+		bw = 0x5;
+	else if (symbol_rate < 8000)
+		bw = 0x4;
+	else if (symbol_rate < 10000)
+		bw = 0x6;
+	else if (symbol_rate < 12000)
+		bw = 0x7;
+	else if (symbol_rate < 14000)
+		bw = 0x8;
+	else if (symbol_rate < 16000)
+		bw = 0x9;
+	else if (symbol_rate < 18000)
+		bw = 0xa;
+	else if (symbol_rate < 20000)
+		bw = 0xb;
+	else if (symbol_rate < 22000)
+		bw = 0xc;
+	else if (symbol_rate < 24000)
+		bw = 0xd;
+	else if (symbol_rate < 26000)
+		bw = 0xe;
+	else if (symbol_rate < 28000)
+		bw = 0xf;
+	else
+		bw = 0x10;
+
+	/* Frequency */
+	ret |= m88rs2000_tuner_write(state, 0x01, freq >> 8);
+	ret |= m88rs2000_tuner_write(state, 0x02, freq & 0xff);
+	ret |= m88rs2000_tuner_write(state, 0x03, 0x06);
+
+	ret |= m88rs2000_tuner_gate_ctrl(state, 0x10);
+	if (ret < 0)
+		return -ENODEV;
+
+	/* Tuner Frequency Range */
+	ret = m88rs2000_tuner_write(state, 0x10, lo);
+
+	ret |= m88rs2000_tuner_gate_ctrl(state, 0x08);
+
+	ret |= m88rs2000_tuner_write(state, 0x04, 0x2e);
+
+	ret |= m88rs2000_tuner_gate_ctrl(state, 0x04);
+	if (ret < 0)
+		return -ENODEV;
+
+	reg = m88rs2000_tuner_read(state, 0x26);
+	/* Gain control */
+	if (bw == 0xf)
+		ret = m88rs2000_tuner_write(state, 0x04, 0x2f);
+	else
+		ret = m88rs2000_tuner_write(state, 0x04, 0x32);
+	/* Bandwidth */
+	ret |= m88rs2000_tuner_write(state, 0x06, bw);
+
+	ret |= m88rs2000_tuner_gate_ctrl(state, 0x04);
+
+	ret |= m88rs2000_tuner_gate_ctrl(state, 0x01);
+
+	return (ret < 0) ? -EINVAL : 0;
+}
+
+static int m88rs2000_set_fec(struct m88rs2000_state *state,
+		fe_code_rate_t fec)
+{
+	int ret;
+	u16 fec_set;
+	switch (fec) {
+	/* This is not confirmed kept for reference */
+/*	case FEC_1_2:
+		fec_set = 0x88;
+		break;
+	case FEC_2_3:
+		fec_set = 0x68;
+		break;
+	case FEC_3_4:
+		fec_set = 0x48;
+		break;
+	case FEC_5_6:
+		fec_set = 0x28;
+		break;
+	case FEC_7_8:
+		fec_set = 0x18;
+		break; */
+	case FEC_AUTO:
+	default:
+		fec_set = 0x08;
+	}
+	ret = m88rs2000_demod_write(state, 0x76, fec_set);
+
+	return 0;
+}
+
+
+static fe_code_rate_t m88rs2000_get_fec(struct m88rs2000_state *state)
+{
+	u8 reg;
+	m88rs2000_demod_write(state, 0x9a, 0x30);
+	reg = m88rs2000_demod_read(state, 0x76);
+	m88rs2000_demod_write(state, 0x9a, 0xb0);
+
+	switch (reg) {
+	case 0x88:
+		return FEC_1_2;
+	case 0x68:
+		return FEC_2_3;
+	case 0x48:
+		return FEC_3_4;
+	case 0x28:
+		return FEC_5_6;
+	case 0x18:
+		return FEC_7_8;
+	case 0x08:
+	default:
+		break;
+	}
+
+	return FEC_AUTO;
+}
+
+static int m88rs2000_set_frontend(struct dvb_frontend *fe)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	fe_status_t status;
+	int i, ret;
+	s16 offset;
+	u8 reg;
+
+	state->no_lock_count = 0;
+
+	if (c->delivery_system != SYS_DVBS) {
+			dprintk("%s: unsupported delivery "
+				"system selected (%d)\n",
+				__func__, c->delivery_system);
+			return -EOPNOTSUPP;
+	}
+
+	/* Set Tuner */
+	ret = m88rs2000_set_tuner(fe);
+	if (ret < 0)
+		return -ENODEV;
+
+	ret = m88rs2000_demod_write(state, 0x9a, 0x30);
+	ret |= m88rs2000_demod_write(state, 0x86, 0xc6);
+	ret |= m88rs2000_demod_write(state, 0x9c, 0x00);
+	ret |= m88rs2000_demod_write(state, 0x9d, 0x00);
+	if (ret < 0)
+		return -ENODEV;
+
+	/* Reset Demod */
+	ret = m88rs2000_tab_set(state, fe_reset);
+	if (ret < 0)
+		return -ENODEV;
+
+	/* Unknown */
+	reg = m88rs2000_demod_read(state, 0x70);
+	ret = m88rs2000_demod_write(state, 0x70, reg);
+
+	/* Set FEC */
+	ret |= m88rs2000_set_fec(state, c->fec_inner);
+	ret |= m88rs2000_demod_write(state, 0x85, 0x1);
+	ret |= m88rs2000_demod_write(state, 0x8a, 0xbf);
+	ret |= m88rs2000_demod_write(state, 0x8d, 0x1e);
+	ret |= m88rs2000_demod_write(state, 0x90, 0xf1);
+	ret |= m88rs2000_demod_write(state, 0x91, 0x08);
+
+	if (ret < 0)
+		return -ENODEV;
+
+	/* Set Symbol Rate */
+	ret = m88rs2000_set_symbolrate(fe, c->symbol_rate);
+	if (ret < 0)
+		return -ENODEV;
+
+	/* Set up Demod */
+	ret = m88rs2000_tab_set(state, fe_trigger);
+	if (ret < 0)
+		return -ENODEV;
+
+	for (i = 0; i < 20; i++) {
+		m88rs2000_read_status(fe, &status);
+		if (status & FE_HAS_LOCK)
+			break;
+	}
+
+	offset = (s16)((m88rs2000_demod_read(state, 0x9c) << 8)|
+			m88rs2000_demod_read(state, 0x9d));
+
+	if (offset < -0x1000)
+		offset = 0;
+
+	offset += 0xa0;
+
+	ret = m88rs2000_demod_write(state, 0x9a, 0x30);
+	ret |= m88rs2000_demod_write(state, 0x9c, (u8)(offset >> 8));
+	ret |= m88rs2000_demod_write(state, 0x9d, (u8)offset & 0xff);
+	ret |= m88rs2000_demod_write(state, 0x9a, 0xb0);
+	if (ret < 0)
+		return -ENODEV;
+
+	state->tuner_frequency = c->frequency;
+	state->symbol_rate = c->symbol_rate;
+	return 0;
+}
+
+static int m88rs2000_get_frontend(struct dvb_frontend *fe)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct m88rs2000_state *state = fe->demodulator_priv;
+
+	c->fec_inner = m88rs2000_get_fec(state);
+	c->frequency = state->tuner_frequency;
+	c->symbol_rate = state->symbol_rate;
+
+	return 0;
+}
+
+static int m88rs2000_get_tune_settings(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *fesettings)
+{
+	fesettings->min_delay_ms = 25;
+	return 0;
+}
+
+static int m88rs2000_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+
+	if (enable)
+		m88rs2000_demod_write(state, 0x81, 0x84);
+	else
+		m88rs2000_demod_write(state, 0x81, 0x81);
+
+	return 0;
+}
+
+static void m88rs2000_release(struct dvb_frontend *fe)
+{
+	struct m88rs2000_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops m88rs2000_ops = {
+	.delsys = { SYS_DVBS },
+	.info = {
+		.name			= "M88RS2000 DVB-S",
+		.type			= FE_QPSK,
+		.frequency_min		= 950000,
+		.frequency_max		= 2150000,
+		.frequency_stepsize	= 1000,	 /* kHz for QPSK frontends */
+		.frequency_tolerance	= 0,
+		.symbol_rate_min	= 1000000,
+		.symbol_rate_max	= 45000000,
+		.symbol_rate_tolerance	= 500,	/* ppm */
+		.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_QPSK |
+		      FE_CAN_FEC_AUTO
+	},
+
+	.release = m88rs2000_release,
+	.init = m88rs2000_init,
+	.sleep = m88rs2000_sleep,
+	.write = m88rs2000_write,
+	.i2c_gate_ctrl = m88rs2000_i2c_gate_ctrl,
+	.read_status = m88rs2000_read_status,
+	.read_ber = m88rs2000_read_ber,
+	.read_signal_strength = m88rs2000_read_signal_strength,
+	.read_snr = m88rs2000_read_snr,
+	.read_ucblocks = m88rs2000_read_ucblocks,
+	.diseqc_send_master_cmd = m88rs2000_send_diseqc_msg,
+	.diseqc_send_burst = m88rs2000_send_diseqc_burst,
+	.set_tone = m88rs2000_set_tone,
+	.set_voltage = m88rs2000_set_voltage,
+
+	.set_property = m88rs2000_set_property,
+	.get_property = m88rs2000_get_property,
+	.set_frontend = m88rs2000_set_frontend,
+	.get_frontend = m88rs2000_get_frontend,
+	.get_tune_settings = m88rs2000_get_tune_settings,
+};
+
+struct dvb_frontend *m88rs2000_attach(const struct m88rs2000_config *config,
+				    struct i2c_adapter *i2c)
+{
+	struct m88rs2000_state *state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct m88rs2000_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->tuner_frequency = 0;
+	state->symbol_rate = 0;
+	state->fec_inner = 0;
+
+	if (m88rs2000_startup(state) < 0)
+		goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &m88rs2000_ops,
+			sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+
+	return NULL;
+}
+EXPORT_SYMBOL(m88rs2000_attach);
+
+MODULE_DESCRIPTION("M88RS2000 DVB-S Demodulator driver");
+MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.00");
+
diff --git a/drivers/media/dvb/frontends/m88rs2000.h b/drivers/media/dvb/frontends/m88rs2000.h
new file mode 100644
index 0000000..9915f44
--- /dev/null
+++ b/drivers/media/dvb/frontends/m88rs2000.h
@@ -0,0 +1,57 @@
+/*
+	Driver for M88RS2000 demodulator
+
+	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 M88RS2000_H
+#define M88RS2000_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+struct m88rs2000_config {
+	/* Demodulator i2c address */
+	u8 demod_addr;
+	/* Tuner address */
+	u8 tuner_addr;
+
+	u8 *inittab;
+
+	/* minimum delay before retuning */
+	int min_delay_ms;
+
+	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
+};
+
+#if defined(CONFIG_DVB_M88RS2000) || (defined(CONFIG_DVB_M88RS2000_MODULE) && \
+							defined(MODULE))
+extern struct dvb_frontend *m88rs2000_attach(
+	const struct m88rs2000_config *config, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *m88rs2000_attach(
+	const struct m88rs2000_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_M88RS2000 */
+enum {
+	DEMOD_WRITE = 0x1,
+	TUNER_WRITE,
+	WRITE_DELAY = 0x10,
+};
+#endif /* M88RS2000_H */
-- 
1.7.8.3




^ permalink raw reply related	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/3] m88brs2000 DVB-S frontend and tuner module.
  2012-01-22 10:38 [PATCH 1/3] m88brs2000 DVB-S frontend and tuner module Malcolm Priestley
@ 2012-01-26 16:56 ` Mauro Carvalho Chehab
  2012-01-27 22:26   ` Malcolm Priestley
                     ` (6 more replies)
  0 siblings, 7 replies; 56+ messages in thread
From: Mauro Carvalho Chehab @ 2012-01-26 16:56 UTC (permalink / raw)
  To: Malcolm Priestley; +Cc: linux-media

Em 22-01-2012 08:38, Malcolm Priestley escreveu:
> Support for m88brs2000 chip used in lmedm04 driver.
> 
> Note there are still lock problems.
> 
> Slow channel change due to the large block of registers sent in set_frontend.
> 
> Signed-off-by: Malcolm Priestley <tvboxspy@gmail.com>
> ---

...
> +static int m88rs2000_set_property(struct dvb_frontend *fe,
> +	struct dtv_property *p)
> +{
> +	dprintk("%s(..)\n", __func__);
> +	return 0;
> +}
> +
> +static int m88rs2000_get_property(struct dvb_frontend *fe,
> +	struct dtv_property *p)
> +{
> +	dprintk("%s(..)\n", __func__);
> +	return 0;
> +}
...

Just don't implement set_property/get_property if you're not using them.

Except for that, the code looks ok on my eyes.

Regards,
Mauro

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/3] m88brs2000 DVB-S frontend and tuner module.
  2012-01-26 16:56 ` Mauro Carvalho Chehab
@ 2012-01-27 22:26   ` Malcolm Priestley
  2012-04-15 15:53   ` [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver nibble.max
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 56+ messages in thread
From: Malcolm Priestley @ 2012-01-27 22:26 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

On Thu, 2012-01-26 at 14:56 -0200, Mauro Carvalho Chehab wrote:
> Em 22-01-2012 08:38, Malcolm Priestley escreveu:
> > Support for m88brs2000 chip used in lmedm04 driver.
> > 
> > Note there are still lock problems.
> > 
> > Slow channel change due to the large block of registers sent in set_frontend.
> > 
> > Signed-off-by: Malcolm Priestley <tvboxspy@gmail.com>
> > ---
> 
> ...
> > +static int m88rs2000_set_property(struct dvb_frontend *fe,
> > +	struct dtv_property *p)
> > +{
> > +	dprintk("%s(..)\n", __func__);
> > +	return 0;
> > +}
> > +
> > +static int m88rs2000_get_property(struct dvb_frontend *fe,
> > +	struct dtv_property *p)
> > +{
> > +	dprintk("%s(..)\n", __func__);
> > +	return 0;
> > +}
> ...
> 
> Just don't implement set_property/get_property if you're not using them.
> 
> Except for that, the code looks ok on my eyes.
> 
Hi Mauro

This patch series is now on alpha due to hardware issues.

The hardware becomes completely unresponsive after a full transponder
scan on all systems.

Although, the hardware becomes fully usable again after a few days!?!

Some kind of memory storage?

So, for the time being this driver is not to go upstream.

Regards


Malcolm


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-01-26 16:56 ` Mauro Carvalho Chehab
  2012-01-27 22:26   ` Malcolm Priestley
@ 2012-04-15 15:53   ` nibble.max
  2012-04-19 18:06     ` Mauro Carvalho Chehab
                       ` (2 more replies)
  2012-04-15 15:53   ` [PATCH 2/6] m88ds3103, dvbsky dvb-s2 usb box nibble.max
                     ` (4 subsequent siblings)
  6 siblings, 3 replies; 56+ messages in thread
From: nibble.max @ 2012-04-15 15:53 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

Montage m88ds3103 demodulator and ts2022 tuner driver.

Signed-off-by: Max nibble <nibble.max@gmail.com>
---
 drivers/media/dvb/frontends/Kconfig     |    7 +
 drivers/media/dvb/frontends/Makefile    |    2 +
 drivers/media/dvb/frontends/m88ds3103.c | 1851 +++++++++++++++++++++++++++++++
 drivers/media/dvb/frontends/m88ds3103.h |   53 +
 4 files changed, 1913 insertions(+)
 create mode 100644 drivers/media/dvb/frontends/m88ds3103.c
 create mode 100644 drivers/media/dvb/frontends/m88ds3103.h

diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index e11adb6..d2bb312 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -214,6 +214,13 @@ config DVB_CX24116
 	help
 	  A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
 
+config DVB_M88DS3103
+	tristate "Montage DS3103 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
+	  
 config DVB_SI21XX
 	tristate "Silicon Labs SI21XX based"
 	depends on DVB_CORE && I2C
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 6ca7557..84ddf41 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -98,5 +98,7 @@ obj-$(CONFIG_DVB_A8293) += a8293.o
 obj-$(CONFIG_DVB_TDA10071) += tda10071.o
 obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
 obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
+obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o
 obj-$(CONFIG_DVB_AF9033) += af9033.o
 
+
diff --git a/drivers/media/dvb/frontends/m88ds3103.c b/drivers/media/dvb/frontends/m88ds3103.c
new file mode 100644
index 0000000..a186ba0
--- /dev/null
+++ b/drivers/media/dvb/frontends/m88ds3103.c
@@ -0,0 +1,1851 @@
+/*
+    Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner driver
+
+    Copyright (C) 2011 Max nibble<nibble.max@gmail.com>
+    Copyright (C) 2010 Montage Technology<www.montage-tech.com>
+    Copyright (C) 2009 Konstantin Dimitrov.
+
+    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/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/firmware.h>
+
+#include "dvb_frontend.h"
+#include "m88ds3103.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(KERN_INFO "m88ds3103: " args); \
+	} while (0)
+
+#define FW_DOWN_SIZE 32
+#define FW_DOWN_LOOP (8192/FW_DOWN_SIZE)
+#define DS3103_DEFAULT_FIRMWARE "dvb-fe-ds3103.fw"
+#define DS3000_DEFAULT_FIRMWARE "dvb-fe-ds300x.fw"
+#define MT_FE_MCLK_KHZ 96000 /* in kHz */
+#define MT_FE_CRYSTAL_KHZ   27000 /* in kHz */
+#define FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz 3000
+#define DS3000_ID	0x3000
+#define DS3103_ID	0x3103
+#define TS2020_ID	0x2020
+#define TS2022_ID	0x2022
+#define UNKNOW_ID	0x0000
+
+/* For M88DS3103 demod dvbs mode.*/
+static u8 ds3103_dvbs_init_tab[] = {
+	0x23, 0x07,
+	0x08, 0x03,
+	0x0c, 0x02,
+	0x21, 0x54,
+	0x25, 0x82,
+	0x27, 0x31,
+	0x30, 0x08,
+	0x31, 0x40,
+	0x32, 0x32,
+	0x33, 0x35,
+	0x35, 0xff,
+	0x3a, 0x00,
+	0x37, 0x10,
+	0x38, 0x10,
+	0x39, 0x02,
+	0x42, 0x60,
+	0x4a, 0x80,
+	0x4b, 0x04,
+	0x4d, 0x91,
+	0x5d, 0xc8,
+	0x50, 0x36,
+	0x51, 0x36,
+	0x52, 0x36,
+	0x53, 0x36,
+	0x63, 0x0f,
+	0x64, 0x30,
+	0x65, 0x40,
+	0x68, 0x26,
+	0x69, 0x4c,
+	0x70, 0x20,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x40,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x60,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x80,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0xa0,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x1f,
+	0x76, 0x38,
+	0x77, 0xa6,
+	0x78, 0x0c,
+	0x79, 0x80,
+	0x7f, 0x14,
+	0x7c, 0x00,
+	0xae, 0x82,
+	0x80, 0x64,
+	0x81, 0x66,
+	0x82, 0x44,
+	0x85, 0x04,
+	0xcd, 0xf4,
+	0x90, 0x33,
+	0xa0, 0x44,
+	0xc0, 0x08,
+	0xc3, 0x10,
+	0xc4, 0x08,
+	0xc5, 0xf0,
+	0xc6, 0xff,
+	0xc7, 0x00,
+	0xc8, 0x1a,
+	0xc9, 0x80,
+	0xe0, 0xf8,
+	0xe6, 0x8b,
+	0xd0, 0x40,
+	0xf8, 0x20,
+	0xfa, 0x0f,
+	0x00, 0x00,
+	0xbd, 0x01,
+	0xb8, 0x00,
+};
+/* For M88DS3103 demod dvbs2 mode.*/
+static u8 ds3103_dvbs2_init_tab[] = {
+	0x23, 0x07,
+	0x08, 0x07,
+	0x0c, 0x02,
+	0x21, 0x54,
+	0x25, 0x82,
+	0x27, 0x31,
+	0x30, 0x08,
+	0x32, 0x32,
+	0x33, 0x35,
+	0x35, 0xff,
+	0x3a, 0x00,
+	0x37, 0x10,
+	0x38, 0x10,
+	0x39, 0x02,
+	0x42, 0x60,
+	0x4a, 0x80,
+	0x4b, 0x04,
+	0x4d, 0x91,
+	0x5d, 0xc8,
+	0x50, 0x36,
+	0x51, 0x36,
+	0x52, 0x36,
+	0x53, 0x36,
+	0x63, 0x0f,
+	0x64, 0x10,
+	0x65, 0x20,
+	0x68, 0x46,
+	0x69, 0xcd,
+	0x70, 0x20,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x40,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x60,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x80,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0xa0,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x1f,
+	0x76, 0x38,
+	0x77, 0xa6,
+	0x78, 0x0c,
+	0x79, 0x80,
+	0x7f, 0x14,
+	0x85, 0x08,
+	0xcd, 0xf4,
+	0x90, 0x33,
+	0x86, 0x00,
+	0x87, 0x0f,
+	0x89, 0x00,
+	0x8b, 0x44,
+	0x8c, 0x66,
+	0x9d, 0xc1,
+	0x8a, 0x10,
+	0xad, 0x40,
+	0xa0, 0x44,
+	0xc0, 0x08,
+	0xc1, 0x10,
+	0xc2, 0x08,
+	0xc3, 0x10,
+	0xc4, 0x08,
+	0xc5, 0xf0,
+	0xc6, 0xff,
+	0xc7, 0x00,
+	0xc8, 0x1a,
+	0xc9, 0x80,
+	0xca, 0x23,
+	0xcb, 0x24,
+	0xcc, 0xf4,
+	0xce, 0x74,
+	0x00, 0x00,
+	0xbd, 0x01,
+	0xb8, 0x00,
+};
+
+/* For M88DS3000 demod dvbs mode.*/
+static u8 ds3000_dvbs_init_tab[] = {
+	0x23, 0x05,
+	0x08, 0x03,
+	0x0c, 0x02,
+	0x21, 0x54,
+	0x25, 0x82,
+	0x27, 0x31,
+	0x30, 0x08,
+	0x31, 0x40,
+	0x32, 0x32,
+	0x33, 0x35,
+	0x35, 0xff,
+	0x3a, 0x00,
+	0x37, 0x10,
+	0x38, 0x10,
+	0x39, 0x02,
+	0x42, 0x60,
+	0x4a, 0x40,
+	0x4b, 0x04,
+	0x4d, 0x91,
+	0x5d, 0xc8,
+	0x50, 0x77,
+	0x51, 0x77,
+	0x52, 0x36,
+	0x53, 0x36,
+	0x56, 0x01,
+	0x63, 0x47,
+	0x64, 0x30,
+	0x65, 0x40,
+	0x68, 0x26,
+	0x69, 0x4c,
+	0x70, 0x20,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x40,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x60,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x80,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0xa0,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x1f,
+	0x76, 0x00,
+	0x77, 0xd1,
+	0x78, 0x0c,
+	0x79, 0x80,
+	0x7f, 0x04,
+	0x7c, 0x00,
+	0x80, 0x86,
+	0x81, 0xa6,
+	0x85, 0x04,
+	0xcd, 0xf4,
+	0x90, 0x33,
+	0xa0, 0x44,
+	0xc0, 0x18,
+	0xc3, 0x10,
+	0xc4, 0x08,
+	0xc5, 0x80,
+	0xc6, 0x80,
+	0xc7, 0x0a,
+	0xc8, 0x1a,
+	0xc9, 0x80,
+	0xfe, 0xb6,
+	0xe0, 0xf8,
+	0xe6, 0x8b,
+	0xd0, 0x40,
+	0xf8, 0x20,
+	0xfa, 0x0f,
+	0xad, 0x20,
+	0xae, 0x07,
+	0xb8, 0x00,
+};
+
+/* For M88DS3000 demod dvbs2 mode.*/
+static u8 ds3000_dvbs2_init_tab[] = {
+	0x23, 0x0f,
+	0x08, 0x07,
+	0x0c, 0x02,
+	0x21, 0x54,
+	0x25, 0x82,
+	0x27, 0x31,
+	0x30, 0x08,
+	0x31, 0x32,
+	0x32, 0x32,
+	0x33, 0x35,
+	0x35, 0xff,
+	0x3a, 0x00,
+	0x37, 0x10,
+	0x38, 0x10,
+	0x39, 0x02,
+	0x42, 0x60,
+	0x4a, 0x80,
+	0x4b, 0x04,
+	0x4d, 0x91,
+	0x5d, 0x88,
+	0x50, 0x36,
+	0x51, 0x36,
+	0x52, 0x36,
+	0x53, 0x36,
+	0x63, 0x60,
+	0x64, 0x10,
+	0x65, 0x10,
+	0x68, 0x04,
+	0x69, 0x29,
+	0x70, 0x20,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x40,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x60,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x80,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0xa0,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x1f,
+	0xa0, 0x44,
+	0xc0, 0x08,
+	0xc1, 0x10,
+	0xc2, 0x08,
+	0xc3, 0x10,
+	0xc4, 0x08,
+	0xc5, 0xf0,
+	0xc6, 0xf0,
+	0xc7, 0x0a,
+	0xc8, 0x1a,
+	0xc9, 0x80,
+	0xca, 0x23,
+	0xcb, 0x24,
+	0xce, 0x74,
+	0x56, 0x01,
+	0x90, 0x03,
+	0x76, 0x80,
+	0x77, 0x42,
+	0x78, 0x0a,
+	0x79, 0x80,
+	0xad, 0x40,
+	0xae, 0x07,
+	0x7f, 0xd4,
+	0x7c, 0x00,
+	0x80, 0xa8,
+	0x81, 0xda,
+	0x7c, 0x01,
+	0x80, 0xda,
+	0x81, 0xec,
+	0x7c, 0x02,
+	0x80, 0xca,
+	0x81, 0xeb,
+	0x7c, 0x03,
+	0x80, 0xba,
+	0x81, 0xdb,
+	0x85, 0x08,
+	0x86, 0x00,
+	0x87, 0x02,
+	0x89, 0x80,
+	0x8b, 0x44,
+	0x8c, 0xaa,
+	0x8a, 0x10,
+	0xba, 0x00,
+	0xf5, 0x04,
+	0xd2, 0x32,
+	0xb8, 0x00,
+};
+
+struct m88ds3103_state {
+	struct i2c_adapter *i2c;
+	const struct m88ds3103_config *config;
+	
+	struct dvb_frontend frontend;
+	
+	u32 preBer;
+	u8 skip_fw_load;	
+	u8 first_lock; /* The first time of signal lock */
+	u16 demod_id; /* demod chip type */
+	u16 tuner_id; /* tuner chip type */
+	fe_delivery_system_t delivery_system;
+};
+
+/*demod register operations.*/
+static int m88ds3103_writereg(struct m88ds3103_state *state, int reg, int data)
+{
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = { .addr = state->config->demod_address,
+		.flags = 0, .buf = buf, .len = 2 };
+	int err;
+
+	if (debug > 1)
+		printk("m88ds3103: %s: write reg 0x%02x, value 0x%02x\n",
+			__func__, reg, data);
+
+	err = i2c_transfer(state->i2c, &msg, 1);
+	if (err != 1) {
+		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x,"
+			 " value == 0x%02x)\n", __func__, err, reg, data);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int m88ds3103_readreg(struct m88ds3103_state *state, u8 reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{ .addr = state->config->demod_address, .flags = 0,
+			.buf = b0, .len = 1 },
+		{ .addr = state->config->demod_address, .flags = I2C_M_RD,
+			.buf = b1, .len = 1 }
+	};
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) {
+		printk(KERN_ERR "%s: reg=0x%x (error=%d)\n",
+			__func__, reg, ret);
+		return ret;
+	}
+
+	if (debug > 1)
+		printk(KERN_INFO "m88ds3103: read reg 0x%02x, value 0x%02x\n",
+			reg, b1[0]);
+
+	return b1[0];
+}
+
+/*tuner register operations.*/
+static int m88ds3103_tuner_writereg(struct m88ds3103_state *state, int reg, int data)
+{
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = { .addr = 0x60,
+		.flags = 0, .buf = buf, .len = 2 };
+	int err;
+
+	m88ds3103_writereg(state, 0x03, 0x11);
+	err = i2c_transfer(state->i2c, &msg, 1);
+	
+	if (err != 1) {
+		printk("%s: writereg error(err == %i, reg == 0x%02x,"
+			 " value == 0x%02x)\n", __func__, err, reg, data);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int m88ds3103_tuner_readreg(struct m88ds3103_state *state, u8 reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{ .addr = 0x60, .flags = 0,
+			.buf = b0, .len = 1 },
+		{ .addr = 0x60, .flags = I2C_M_RD,
+			.buf = b1, .len = 1 }
+	};
+
+	m88ds3103_writereg(state, 0x03, 0x11);	
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) {
+		printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);
+		return ret;
+	}
+
+	return b1[0];
+}
+
+/* Bulk demod I2C write, for firmware download. */
+static int m88ds3103_writeregN(struct m88ds3103_state *state, int reg,
+				const u8 *data, u16 len)
+{
+	int ret = -EREMOTEIO;
+	struct i2c_msg msg;
+	u8 *buf;
+
+	buf = kmalloc(len + 1, GFP_KERNEL);
+	if (buf == NULL) {
+		printk("Unable to kmalloc\n");
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	*(buf) = reg;
+	memcpy(buf + 1, data, len);
+
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.buf = buf;
+	msg.len = len + 1;
+
+	if (debug > 1)
+		printk(KERN_INFO "m88ds3103: %s:  write regN 0x%02x, len = %d\n",
+			__func__, reg, len);
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+	if (ret != 1) {
+		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n",
+			 __func__, ret, reg);
+		ret = -EREMOTEIO;
+	}
+	
+error:
+	kfree(buf);
+
+	return ret;
+}
+
+static int m88ds3103_load_firmware(struct dvb_frontend *fe)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	const struct firmware *fw;
+	int i, ret = 0;
+
+	dprintk("%s()\n", __func__);
+		
+	if (state->skip_fw_load)
+		return 0;
+	/* Load firmware */
+	/* request the firmware, this will block until someone uploads it */	
+	if(state->demod_id == DS3000_ID){
+		printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__,
+				DS3000_DEFAULT_FIRMWARE);		
+		ret = request_firmware(&fw, DS3000_DEFAULT_FIRMWARE,
+					state->i2c->dev.parent);
+	}else if(state->demod_id == DS3103_ID){
+		printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__,
+				DS3103_DEFAULT_FIRMWARE);
+		ret = request_firmware(&fw, DS3103_DEFAULT_FIRMWARE,
+					state->i2c->dev.parent);
+	}
+	
+	printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__);
+	if (ret) {
+		printk(KERN_ERR "%s: No firmware uploaded (timeout or file not "
+				"found?)\n", __func__);
+		return ret;
+	}
+
+	/* Make sure we don't recurse back through here during loading */
+	state->skip_fw_load = 1;
+
+	dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
+			fw->size,
+			fw->data[0],
+			fw->data[1],
+			fw->data[fw->size - 2],
+			fw->data[fw->size - 1]);
+			
+	/* stop internal mcu. */
+	m88ds3103_writereg(state, 0xb2, 0x01);
+	/* split firmware to download.*/
+	for(i = 0; i < FW_DOWN_LOOP; i++){
+		ret = m88ds3103_writeregN(state, 0xb0, &(fw->data[FW_DOWN_SIZE*i]), FW_DOWN_SIZE);
+		if(ret != 1) break;		
+	}
+	/* start internal mcu. */
+	if(ret == 1)
+		m88ds3103_writereg(state, 0xb2, 0x00);
+		
+	release_firmware(fw);
+
+	dprintk("%s: Firmware upload %s\n", __func__,
+			ret == 1 ? "complete" : "failed");
+
+	if(ret == 1) ret = 0;
+	
+	/* Ensure firmware is always loaded if required */
+	state->skip_fw_load = 0;
+
+	return ret;
+}
+
+
+static int m88ds3103_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	u8 data;
+
+	dprintk("%s(%d)\n", __func__, voltage);
+
+	dprintk("m88ds3103:pin_ctrl = (%02x)\n", state->config->pin_ctrl);
+	
+	if(state->config->set_voltage)
+		state->config->set_voltage(fe, voltage);
+	
+	data = m88ds3103_readreg(state, 0xa2);
+	
+        if(state->config->pin_ctrl & 0x80){ /*If control pin is assigned.*/
+	        data &= ~0x03; /* bit0 V/H, bit1 off/on */
+	        if(state->config->pin_ctrl & 0x02)
+		     data |= 0x02;
+
+	        switch (voltage) {
+	        case SEC_VOLTAGE_18:
+		     if((state->config->pin_ctrl & 0x01) == 0)
+			  data |= 0x01;
+		     break;
+	        case SEC_VOLTAGE_13:
+		     if(state->config->pin_ctrl & 0x01)
+			  data |= 0x01;
+		     break;
+	        case SEC_VOLTAGE_OFF:
+		     if(state->config->pin_ctrl & 0x02)
+			   data &= ~0x02;			
+		     else
+			   data |= 0x02;
+		     break;
+	         }
+        }
+
+	m88ds3103_writereg(state, 0xa2, data);
+
+	return 0;
+}
+
+static int m88ds3103_read_status(struct dvb_frontend *fe, fe_status_t* status)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	int lock = 0;
+	
+	*status = 0;
+	
+	switch (state->delivery_system){
+	case SYS_DVBS:
+		lock = m88ds3103_readreg(state, 0xd1);
+		dprintk("%s: SYS_DVBS status=%x.\n", __func__, lock);
+		
+		if ((lock & 0x07) == 0x07){
+			/*if((m88ds3103_readreg(state, 0x0d) & 0x07) == 0x07)*/
+				*status = FE_HAS_SIGNAL | FE_HAS_CARRIER 
+					| FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+			
+		}
+		break;
+	case SYS_DVBS2:
+		lock = m88ds3103_readreg(state, 0x0d);
+		dprintk("%s: SYS_DVBS2 status=%x.\n", __func__, lock);
+
+		if ((lock & 0x8f) == 0x8f)
+			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER 
+				| FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+			
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int m88ds3103_read_ber(struct dvb_frontend *fe, u32* ber)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	u8 tmp1, tmp2, tmp3;
+	u32 ldpc_frame_cnt, pre_err_packags, code_rate_fac = 0;
+
+	dprintk("%s()\n", __func__);
+
+	switch (state->delivery_system) {
+	case SYS_DVBS:
+		m88ds3103_writereg(state, 0xf9, 0x04);
+		tmp3 = m88ds3103_readreg(state, 0xf8);
+		if ((tmp3&0x10) == 0){
+			tmp1 = m88ds3103_readreg(state, 0xf7);
+			tmp2 = m88ds3103_readreg(state, 0xf6);
+			tmp3 |= 0x10;
+			m88ds3103_writereg(state, 0xf8, tmp3);
+			state->preBer = (tmp1<<8) | tmp2;
+		}
+		break;
+	case SYS_DVBS2:
+		tmp1 = m88ds3103_readreg(state, 0x7e) & 0x0f;
+		switch(tmp1){
+		case 0:	code_rate_fac = 16008 - 80; break;
+		case 1:	code_rate_fac = 21408 - 80; break;
+		case 2:	code_rate_fac = 25728 - 80; break;
+		case 3:	code_rate_fac = 32208 - 80; break;
+		case 4:	code_rate_fac = 38688 - 80; break;
+		case 5:	code_rate_fac = 43040 - 80; break;
+		case 6:	code_rate_fac = 48408 - 80; break;
+		case 7:	code_rate_fac = 51648 - 80; break;
+		case 8:	code_rate_fac = 53840 - 80; break;
+		case 9:	code_rate_fac = 57472 - 80; break;
+		case 10: code_rate_fac = 58192 - 80; break;
+		}
+		
+		tmp1 = m88ds3103_readreg(state, 0xd7) & 0xff;
+		tmp2 = m88ds3103_readreg(state, 0xd6) & 0xff;
+		tmp3 = m88ds3103_readreg(state, 0xd5) & 0xff;		
+		ldpc_frame_cnt = (tmp1 << 16) | (tmp2 << 8) | tmp3;
+
+		tmp1 = m88ds3103_readreg(state, 0xf8) & 0xff;
+		tmp2 = m88ds3103_readreg(state, 0xf7) & 0xff;
+		pre_err_packags = tmp1<<8 | tmp2;
+		
+		if (ldpc_frame_cnt > 1000){
+			m88ds3103_writereg(state, 0xd1, 0x01);
+			m88ds3103_writereg(state, 0xf9, 0x01);
+			m88ds3103_writereg(state, 0xf9, 0x00);
+			m88ds3103_writereg(state, 0xd1, 0x00);
+			state->preBer = pre_err_packags;
+		} 				
+		break;
+	default:
+		break;
+	}
+	*ber = state->preBer;
+	
+	return 0;
+}
+
+static int m88ds3103_read_signal_strength(struct dvb_frontend *fe,
+						u16 *signal_strength)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	u16 gain;
+	u8 gain1, gain2, gain3 = 0;
+
+	dprintk("%s()\n", __func__);
+
+	gain1 = m88ds3103_tuner_readreg(state, 0x3d) & 0x1f;
+	dprintk("%s: gain1 = 0x%02x \n", __func__, gain1);
+	
+	if (gain1 > 15) gain1 = 15;
+	gain2 = m88ds3103_tuner_readreg(state, 0x21) & 0x1f;
+	dprintk("%s: gain2 = 0x%02x \n", __func__, gain2);
+	
+	if(state->tuner_id == TS2022_ID){
+		gain3 = (m88ds3103_tuner_readreg(state, 0x66)>>3) & 0x07;
+		dprintk("%s: gain3 = 0x%02x \n", __func__, gain3);
+		
+		if (gain2 > 16) gain2 = 16;
+		if (gain2 < 2) gain2 = 2;			
+		if (gain3 > 6) gain3 = 6;
+	}else{
+		if (gain2 > 13) gain2 = 13;
+		gain3 = 0;
+	}
+
+	gain = gain1*23 + gain2*35 + gain3*29;
+	*signal_strength = 60000 - gain*55;
+
+	return 0;
+}
+
+
+static int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *p_snr)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	u8 val, npow1, npow2, spow1, cnt;
+	u16 tmp, snr;
+	u32 npow, spow, snr_total;	
+	static const u16 mes_log10[] ={
+		0,	3010,	4771,	6021, 	6990,	7781,	8451,	9031,	9542,	10000,
+		10414,	10792,	11139,	11461,	11761,	12041,	12304,	12553,	12788,	13010,
+		13222,	13424,	13617,	13802,	13979,	14150,	14314,	14472,	14624,	14771,
+		14914,	15052,	15185,	15315,	15441,	15563,	15682,	15798,	15911,	16021,
+		16128,	16232,	16335,	16435,	16532,	16628,	16721,	16812,	16902,	16990,
+		17076,	17160,	17243,	17324,	17404,	17482,	17559,	17634,	17709,	17782,
+		17853,	17924,	17993,	18062,	18129,	18195,	18261,	18325,	18388,	18451,
+		18513,	18573,	18633,	18692,	18751,	18808,	18865,	18921,	18976,	19031
+	};
+	static const u16 mes_loge[] ={
+		0,	6931,	10986,	13863, 	16094,	17918,	19459,	20794,	21972,	23026,
+		23979,	24849,	25649,	26391,	27081,	27726,	28332,	28904,	29444,	29957,
+		30445,	30910,	31355,	31781,	32189,	32581,	32958,	33322,	33673,	34012,
+		34340,	34657,
+	};
+
+	dprintk("%s()\n", __func__);
+
+	snr = 0;
+	
+	switch (state->delivery_system){
+	case SYS_DVBS:
+		cnt = 10; snr_total = 0;
+		while(cnt > 0){
+			val = m88ds3103_readreg(state, 0xff);
+			snr_total += val;
+			cnt--;
+		}
+		tmp = (u16)(snr_total/80);
+		if(tmp > 0){
+			if (tmp > 32) tmp = 32;
+			snr = (mes_loge[tmp - 1] * 100) / 45;
+		}else{
+			snr = 0;
+		}
+		break;
+	case SYS_DVBS2:
+		cnt  = 10; npow = 0; spow = 0;
+		while(cnt >0){
+			npow1 = m88ds3103_readreg(state, 0x8c) & 0xff;
+			npow2 = m88ds3103_readreg(state, 0x8d) & 0xff;
+			npow += (((npow1 & 0x3f) + (u16)(npow2 << 6)) >> 2);
+
+			spow1 = m88ds3103_readreg(state, 0x8e) & 0xff;
+			spow += ((spow1 * spow1) >> 1);
+			cnt--;
+		}
+		npow /= 10; spow /= 10;
+		if(spow == 0){
+			snr = 0;
+		}else if(npow == 0){
+			snr = 19;
+		}else{
+			if(spow > npow){
+				tmp = (u16)(spow / npow);
+				if (tmp > 80) tmp = 80;
+				snr = mes_log10[tmp - 1]*3;
+			}else{
+				tmp = (u16)(npow / spow);
+				if (tmp > 80) tmp = 80;
+				snr = -(mes_log10[tmp - 1] / 1000);
+			}
+		}			
+		break;
+	default:
+		break;
+	}
+	*p_snr = snr;
+
+	return 0;
+}
+
+
+static int m88ds3103_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	u8 tmp1, tmp2, tmp3, data;
+
+	dprintk("%s()\n", __func__);
+
+	switch (state->delivery_system) {
+	case SYS_DVBS:
+		data = m88ds3103_readreg(state, 0xf8);
+		data |= 0x40;
+		m88ds3103_writereg(state, 0xf8, data);		
+		tmp1 = m88ds3103_readreg(state, 0xf5);
+		tmp2 = m88ds3103_readreg(state, 0xf4);
+		*ucblocks = (tmp1 <<8) | tmp2;		
+		data &= ~0x20;
+		m88ds3103_writereg(state, 0xf8, data);
+		data |= 0x20;
+		m88ds3103_writereg(state, 0xf8, data);
+		data &= ~0x40;
+		m88ds3103_writereg(state, 0xf8, data);
+		break;
+	case SYS_DVBS2:
+		tmp1 = m88ds3103_readreg(state, 0xda);
+		tmp2 = m88ds3103_readreg(state, 0xd9);
+		tmp3 = m88ds3103_readreg(state, 0xd8);
+		*ucblocks = (tmp1 <<16)|(tmp2 <<8)|tmp3;
+		data = m88ds3103_readreg(state, 0xd1);
+		data |= 0x01;
+		m88ds3103_writereg(state, 0xd1, data);
+		data &= ~0x01;
+		m88ds3103_writereg(state, 0xd1, data);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int m88ds3103_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	u8 data_a1, data_a2;
+
+	dprintk("%s(%d)\n", __func__, tone);
+	if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
+		printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
+		return -EINVAL;
+	}
+
+	data_a1 = m88ds3103_readreg(state, 0xa1);
+	data_a2 = m88ds3103_readreg(state, 0xa2);
+	if(state->demod_id == DS3103_ID)
+		data_a2 &= 0xdf; /* Normal mode */
+	switch (tone) {
+	case SEC_TONE_ON:
+		dprintk("%s: SEC_TONE_ON\n", __func__);
+		data_a1 |= 0x04;
+		data_a1 &= ~0x03;
+		data_a1 &= ~0x40;
+		data_a2 &= ~0xc0;
+		break;
+	case SEC_TONE_OFF:
+		dprintk("%s: SEC_TONE_OFF\n", __func__);
+		data_a2 &= ~0xc0;
+		data_a2 |= 0x80;
+		break;
+	}
+	m88ds3103_writereg(state, 0xa2, data_a2);
+	m88ds3103_writereg(state, 0xa1, data_a1);
+	return 0;
+}
+
+static int m88ds3103_send_diseqc_msg(struct dvb_frontend *fe,
+				struct dvb_diseqc_master_cmd *d)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	int i, ret = 0;
+	u8 tmp, time_out;
+
+	/* Dump DiSEqC message */
+	if (debug) {
+		printk(KERN_INFO "m88ds3103: %s(", __func__);
+		for (i = 0 ; i < d->msg_len ;) {
+			printk(KERN_INFO "0x%02x", d->msg[i]);
+			if (++i < d->msg_len)
+				printk(KERN_INFO ", ");
+		}
+	}
+
+	tmp = m88ds3103_readreg(state, 0xa2);
+	tmp &= ~0xc0;
+	if(state->demod_id == DS3103_ID)
+		tmp &= ~0x20;
+	m88ds3103_writereg(state, 0xa2, tmp);
+	
+	for (i = 0; i < d->msg_len; i ++)
+		m88ds3103_writereg(state, (0xa3+i), d->msg[i]);
+
+	tmp = m88ds3103_readreg(state, 0xa1);	
+	tmp &= ~0x38;
+	tmp &= ~0x40;
+	tmp |= ((d->msg_len-1) << 3) | 0x07;
+	tmp &= ~0x80;
+	m88ds3103_writereg(state, 0xa1, tmp);
+	/*	1.5 * 9 * 8	= 108ms	*/
+	time_out = 150;
+	while (time_out > 0){
+		msleep(10);
+		time_out -= 10;
+		tmp = m88ds3103_readreg(state, 0xa1);		
+		if ((tmp & 0x40) == 0)
+			break;
+	}
+	if (time_out == 0){
+		tmp = m88ds3103_readreg(state, 0xa1);
+		tmp &= ~0x80;
+		tmp |= 0x40;
+		m88ds3103_writereg(state, 0xa1, tmp);
+		ret = 1;
+	}
+	tmp = m88ds3103_readreg(state, 0xa2);
+	tmp &= ~0xc0;
+	tmp |= 0x80;
+	m88ds3103_writereg(state, 0xa2, tmp);	
+	return ret;
+}
+
+
+static int m88ds3103_diseqc_send_burst(struct dvb_frontend *fe,
+					fe_sec_mini_cmd_t burst)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	u8	val, time_out;
+	
+	dprintk("%s()\n", __func__);
+
+	val = m88ds3103_readreg(state, 0xa2);
+	val &= ~0xc0;
+	if(state->demod_id == DS3103_ID)
+		val &= 0xdf; /* Normal mode */
+	m88ds3103_writereg(state, 0xa2, val);
+	/* DiSEqC burst */
+	if (burst == SEC_MINI_B)
+		m88ds3103_writereg(state, 0xa1, 0x01);
+	else
+		m88ds3103_writereg(state, 0xa1, 0x02);
+
+	msleep(13);
+
+	time_out = 5;
+	do{
+		val = m88ds3103_readreg(state, 0xa1);
+		if ((val & 0x40) == 0)
+			break;
+		msleep(1);
+		time_out --;
+	} while (time_out > 0);
+
+	val = m88ds3103_readreg(state, 0xa2);
+	val &= ~0xc0;
+	val |= 0x80;
+	m88ds3103_writereg(state, 0xa2, val);
+	
+	return 0;
+}
+
+static void m88ds3103_release(struct dvb_frontend *fe)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+	kfree(state);
+}
+
+static int m88ds3103_check_id(struct m88ds3103_state *state)
+{
+	int val_00, val_01;
+	
+	/*check demod id*/
+	val_01 = m88ds3103_readreg(state, 0x01);
+	printk(KERN_INFO "DS3000 chip version: %x attached.\n", val_01);
+			
+	if(val_01 == 0xD0)
+		state->demod_id = DS3103_ID;
+	else if(val_01 == 0xC0)
+		state->demod_id = DS3000_ID;
+	else
+		state->demod_id = UNKNOW_ID;
+		
+	/*check tuner id*/
+	val_00 = m88ds3103_tuner_readreg(state, 0x00);
+	printk(KERN_INFO "TS202x chip version[1]: %x attached.\n", val_00);
+	val_00 &= 0x03;
+	if(val_00 == 0)
+	{
+		m88ds3103_tuner_writereg(state, 0x00, 0x01);
+		msleep(3);		
+	}
+	m88ds3103_tuner_writereg(state, 0x00, 0x03);
+	msleep(5);
+	
+	val_00 = m88ds3103_tuner_readreg(state, 0x00);
+	printk(KERN_INFO "TS202x chip version[2]: %x attached.\n", val_00);
+	val_00 &= 0xff;
+	if((val_00 == 0x01) || (val_00 == 0x41) || (val_00 == 0x81))
+		state->tuner_id = TS2020_ID;
+	else if(((val_00 & 0xc0)== 0xc0) || (val_00 == 0x83))
+		state->tuner_id = TS2022_ID;
+	else
+		state->tuner_id = UNKNOW_ID;
+			
+	return state->demod_id;	
+}
+
+static struct dvb_frontend_ops m88ds3103_ops;
+static int m88ds3103_initilaze(struct dvb_frontend *fe);
+
+struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *config,
+				    struct i2c_adapter *i2c)
+{
+	struct m88ds3103_state *state = NULL;
+
+	dprintk("%s\n", __func__);
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct m88ds3103_state), GFP_KERNEL);
+	if (state == NULL) {
+		printk(KERN_ERR "Unable to kmalloc\n");
+		goto error2;
+	}
+
+	state->config = config;
+	state->i2c = i2c;
+	state->preBer = 0xffff;
+	state->delivery_system = SYS_DVBS; /*Default to DVB-S.*/
+	
+	/* check demod id */
+	if(m88ds3103_check_id(state) == UNKNOW_ID){
+		printk(KERN_ERR "Unable to find Montage chip\n");
+		goto error3;
+	}
+
+	memcpy(&state->frontend.ops, &m88ds3103_ops,
+			sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	
+	m88ds3103_initilaze(&state->frontend);
+	
+	return &state->frontend;
+
+error3:
+	kfree(state);
+error2:
+	return NULL;
+}
+EXPORT_SYMBOL(m88ds3103_attach);
+
+static int m88ds3103_set_carrier_offset(struct dvb_frontend *fe,
+					s32 carrier_offset_khz)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	s32 tmp;
+
+	tmp = carrier_offset_khz;
+	tmp *= 65536;
+	
+	tmp = (2*tmp + MT_FE_MCLK_KHZ) / (2*MT_FE_MCLK_KHZ);
+
+	if (tmp < 0)
+		tmp += 65536;
+
+	m88ds3103_writereg(state, 0x5f, tmp >> 8);
+	m88ds3103_writereg(state, 0x5e, tmp & 0xff);
+
+	return 0;
+}
+
+static int m88ds3103_set_symrate(struct dvb_frontend *fe)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u16 value;
+	
+	value = (((c->symbol_rate / 1000) << 15) + (MT_FE_MCLK_KHZ / 4)) / (MT_FE_MCLK_KHZ / 2);
+	m88ds3103_writereg(state, 0x61, value & 0x00ff);
+	m88ds3103_writereg(state, 0x62, (value & 0xff00) >> 8);
+
+	return 0;
+}
+
+static int m88ds3103_set_CCI(struct dvb_frontend *fe)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	u8 tmp;
+
+	tmp = m88ds3103_readreg(state, 0x56);
+	tmp &= ~0x01;
+	m88ds3103_writereg(state, 0x56, tmp);
+
+	tmp = m88ds3103_readreg(state, 0x76);
+	tmp &= ~0x80;
+	m88ds3103_writereg(state, 0x76, tmp);
+
+	return 0;
+}
+
+static int m88ds3103_init_reg(struct m88ds3103_state *state, const u8 *p_reg_tab, u32 size)
+{
+	u32 i;
+	
+	for(i = 0; i < size; i+=2)
+		m88ds3103_writereg(state, p_reg_tab[i], p_reg_tab[i+1]);
+		
+	return 0;
+}
+
+static int m88ds3103_demod_connect(struct dvb_frontend *fe, s32 carrier_offset_khz) 
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u16 value;
+	u8 val1,val2,data;
+	
+	dprintk("connect delivery system = %d\n", state->delivery_system);
+	
+	/* ds3000 global reset */
+	m88ds3103_writereg(state, 0x07, 0x80);
+	m88ds3103_writereg(state, 0x07, 0x00);
+	/* ds3000 build-in uC reset */
+	m88ds3103_writereg(state, 0xb2, 0x01);
+	/* ds3000 software reset */
+	m88ds3103_writereg(state, 0x00, 0x01);
+
+	switch (state->delivery_system) {
+	case SYS_DVBS:
+		/* initialise the demod in DVB-S mode */
+		if(state->demod_id == DS3000_ID){
+			m88ds3103_init_reg(state, ds3000_dvbs_init_tab, sizeof(ds3000_dvbs_init_tab));
+			
+			value = m88ds3103_readreg(state, 0xfe);
+			value &= 0xc0;
+			value |= 0x1b;
+			m88ds3103_writereg(state, 0xfe, value);
+			
+			if(state->config->ci_mode)
+				val1 = 0x80;
+			else if(state->config->ts_mode)
+				val1 = 0x60;
+			else
+				val1 = 0x20;
+			m88ds3103_writereg(state, 0xfd, val1);
+			
+		}else if(state->demod_id == DS3103_ID){
+			m88ds3103_init_reg(state, ds3103_dvbs_init_tab, sizeof(ds3103_dvbs_init_tab));
+			
+			/* set ts clock */
+			if(state->config->ts_mode == 0)	{
+				val1 = 3; val2 = 3;
+			}else{
+				val1 = 0; val2 = 0;
+			}
+			val1 -= 1; val2 -= 1;
+			val1 &= 0x3f; val2 &= 0x3f;
+			data = m88ds3103_readreg(state, 0xfe);
+			data &= 0xf0;
+			data |= (val2 >> 2) & 0x0f;
+			m88ds3103_writereg(state, 0xfe, data);
+			data = (val2 & 0x03) << 6;
+			data |= val1;
+			m88ds3103_writereg(state, 0xea, data);
+			
+			m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d));
+			m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30));
+			
+			/* set master clock */
+			val1 = m88ds3103_readreg(state, 0x22);
+			val2 = m88ds3103_readreg(state, 0x24);
+			
+			val1 &= 0x3f;
+			val2 &= 0x3f;
+			val1 |= 0x80;
+			val2 |= 0x40;
+
+			m88ds3103_writereg(state, 0x22, val1);
+			m88ds3103_writereg(state, 0x24, val2);	
+			
+			if(state->config->ci_mode)
+				val1 = 0x03;
+			else if(state->config->ts_mode)
+				val1 = 0x06;
+			else
+				val1 = 0x42;
+			m88ds3103_writereg(state, 0xfd, val1);		
+		}
+		break;
+	case SYS_DVBS2:
+		/* initialise the demod in DVB-S2 mode */
+		if(state->demod_id == DS3000_ID){
+			m88ds3103_init_reg(state, ds3000_dvbs2_init_tab, sizeof(ds3000_dvbs2_init_tab));
+		
+			if (c->symbol_rate >= 30000000)
+				m88ds3103_writereg(state, 0xfe, 0x54);
+			else
+				m88ds3103_writereg(state, 0xfe, 0x98);
+								
+		}else if(state->demod_id == DS3103_ID){
+			m88ds3103_init_reg(state, ds3103_dvbs2_init_tab, sizeof(ds3103_dvbs2_init_tab));
+
+			/* set ts clock */
+			if(state->config->ts_mode == 0){
+				val1 = 5; val2 = 4;
+			}else{
+				val1 = 0; val2 = 0;
+			}
+			val1 -= 1; val2 -= 1;
+			val1 &= 0x3f; val2 &= 0x3f;
+			data = m88ds3103_readreg(state, 0xfe);
+			data &= 0xf0;
+			data |= (val2 >> 2) & 0x0f;
+			m88ds3103_writereg(state, 0xfe, data);
+			data = (val2 & 0x03) << 6;
+			data |= val1;
+			m88ds3103_writereg(state, 0xea, data);
+			
+			m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d));
+			m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30));
+			
+			/* set master clock */
+			val1 = m88ds3103_readreg(state, 0x22);
+			val2 = m88ds3103_readreg(state, 0x24);
+			
+			val1 &= 0x3f;
+			val2 &= 0x3f;
+			if(state->config->ts_mode == 1){
+				val1 |= 0x80;
+				val2 |= 0x40;
+			}else{
+				if (c->symbol_rate >= 28000000){
+					val1 |= 0xc0;
+				}else if (c->symbol_rate >= 18000000){
+					val2 |= 0x40;
+				}else{
+					val1 |= 0x80;
+					val2 |= 0x40;
+				}				
+			}
+			m88ds3103_writereg(state, 0x22, val1);
+			m88ds3103_writereg(state, 0x24, val2);					
+		}
+		
+		if(state->config->ci_mode)
+			val1 = 0x03;
+		else if(state->config->ts_mode)
+			val1 = 0x06;
+		else
+			val1 = 0x42;
+		m88ds3103_writereg(state, 0xfd, val1);
+		
+		break;
+	default:
+		return 1;
+	}
+	/* disable 27MHz clock output */
+	m88ds3103_writereg(state, 0x29, 0x80);
+	/* enable ac coupling */
+	m88ds3103_writereg(state, 0x25, 0x8a);
+
+	if ((c->symbol_rate / 1000) <= 3000){
+		m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 32 * 100 / 64 = 400*/
+		m88ds3103_writereg(state, 0xc8, 0x20);
+		m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/
+		m88ds3103_writereg(state, 0xc7, 0x00);
+	}else if((c->symbol_rate / 1000) <= 10000){
+		m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 16 * 100 / 64 = 200*/
+		m88ds3103_writereg(state, 0xc8, 0x10);
+		m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/
+		m88ds3103_writereg(state, 0xc7, 0x00);
+	}else{
+		m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 6 * 100 / 64 = 75*/
+		m88ds3103_writereg(state, 0xc8, 0x06);
+		m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/
+		m88ds3103_writereg(state, 0xc7, 0x00);
+	}
+
+	m88ds3103_set_symrate(fe);
+	
+	m88ds3103_set_CCI(fe);
+
+	m88ds3103_set_carrier_offset(fe, carrier_offset_khz);
+		
+	/* ds3000 out of software reset */
+	m88ds3103_writereg(state, 0x00, 0x00);
+	/* start ds3000 build-in uC */
+	m88ds3103_writereg(state, 0xb2, 0x00);	
+	
+	return 0;
+}
+
+static int m88ds3103_set_frontend(struct dvb_frontend *fe)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+	int i;
+	fe_status_t status;
+	u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf, div4, capCode, changePLL;
+	s32 offset_khz, lpf_offset_KHz;
+	u16 value, ndiv, lpf_coeff;
+	u32 f3db, gdiv28, realFreq;
+	u8 RFgain;
+
+	dprintk("%s() ", __func__);
+	dprintk("c frequency = %d\n", c->frequency);
+	dprintk("symbol rate = %d\n", c->symbol_rate);
+	dprintk("delivery system = %d\n", c->delivery_system);
+	
+	realFreq = c->frequency;
+	lpf_offset_KHz = 0;
+	if(c->symbol_rate < 5000000){
+		lpf_offset_KHz = FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz;
+		realFreq += FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz;
+	}
+	
+	if (state->config->set_ts_params)
+		state->config->set_ts_params(fe, 0);
+
+	div4 = 0;
+	RFgain = 0;
+	if(state->tuner_id == TS2022_ID){
+		m88ds3103_tuner_writereg(state, 0x10, 0x0a);
+		m88ds3103_tuner_writereg(state, 0x11, 0x40);
+		if (realFreq < 1103000) {
+			m88ds3103_tuner_writereg(state, 0x10, 0x1b);
+			div4 = 1;
+			ndiv = (realFreq * (6 + 8) * 4)/MT_FE_CRYSTAL_KHZ;				
+		}else {
+			ndiv = (realFreq * (6 + 8) * 2)/MT_FE_CRYSTAL_KHZ;
+		}
+		ndiv = ndiv + ndiv%2;
+		if(ndiv < 4095)
+			ndiv = ndiv - 1024;
+		else if (ndiv < 6143)
+			ndiv = ndiv + 1024;
+		else
+			ndiv = ndiv + 3072;	
+		
+		m88ds3103_tuner_writereg(state, 0x01, (ndiv & 0x3f00) >> 8);											
+	}else{
+		m88ds3103_tuner_writereg(state, 0x10, 0x00);			
+		if (realFreq < 1146000){
+			m88ds3103_tuner_writereg(state, 0x10, 0x11);
+			div4 = 1;
+			ndiv = (realFreq * (6 + 8) * 4) / MT_FE_CRYSTAL_KHZ;
+		}else{
+			m88ds3103_tuner_writereg(state, 0x10, 0x01);
+			ndiv = (realFreq * (6 + 8) * 2) / MT_FE_CRYSTAL_KHZ;
+		}
+		ndiv = ndiv + ndiv%2;
+		ndiv = ndiv - 1024;
+		m88ds3103_tuner_writereg(state, 0x01, (ndiv>>8)&0x0f);
+	}
+	/* set pll */
+	m88ds3103_tuner_writereg(state, 0x02, ndiv & 0x00ff);
+	m88ds3103_tuner_writereg(state, 0x03, 0x06);
+	m88ds3103_tuner_writereg(state, 0x51, 0x0f);
+	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
+	m88ds3103_tuner_writereg(state, 0x50, 0x10);
+	m88ds3103_tuner_writereg(state, 0x50, 0x00);	
+
+	if(state->tuner_id == TS2022_ID){
+		if(( realFreq >= 1650000 ) && (realFreq <= 1850000)){
+			msleep(5);
+			value = m88ds3103_tuner_readreg(state, 0x14);
+			value &= 0x7f;
+			if(value < 64){
+				m88ds3103_tuner_writereg(state, 0x10, 0x82);
+				m88ds3103_tuner_writereg(state, 0x11, 0x6f);
+
+				m88ds3103_tuner_writereg(state, 0x51, 0x0f);
+				m88ds3103_tuner_writereg(state, 0x51, 0x1f);
+				m88ds3103_tuner_writereg(state, 0x50, 0x10);
+				m88ds3103_tuner_writereg(state, 0x50, 0x00);
+			}
+		}
+		msleep(5);
+		value = m88ds3103_tuner_readreg(state, 0x14);
+		value &= 0x1f;
+
+		if(value > 19){
+			value = m88ds3103_tuner_readreg(state, 0x10);
+			value &= 0x1d;
+			m88ds3103_tuner_writereg(state, 0x10, value);
+		}				
+	}else{
+		msleep(5);
+		value = m88ds3103_tuner_readreg(state, 0x66);
+		changePLL = (((value & 0x80) >> 7) != div4);
+
+		if(changePLL){
+			m88ds3103_tuner_writereg(state, 0x10, 0x11);
+			div4 = 1;
+			ndiv = (realFreq * (6 + 8) * 4)/MT_FE_CRYSTAL_KHZ;
+			ndiv = ndiv + ndiv%2;
+			ndiv = ndiv - 1024;
+					
+			m88ds3103_tuner_writereg(state, 0x01, (ndiv>>8) & 0x0f);
+			m88ds3103_tuner_writereg(state, 0x02, ndiv & 0xff);
+			
+			m88ds3103_tuner_writereg(state, 0x51, 0x0f);
+			m88ds3103_tuner_writereg(state, 0x51, 0x1f);
+			m88ds3103_tuner_writereg(state, 0x50, 0x10);
+			m88ds3103_tuner_writereg(state, 0x50, 0x00);
+		}		
+	}
+	/*set the RF gain*/
+	if(state->tuner_id == TS2020_ID)
+		m88ds3103_tuner_writereg(state, 0x60, 0x79);
+			
+	m88ds3103_tuner_writereg(state, 0x51, 0x17);
+	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
+	m88ds3103_tuner_writereg(state, 0x50, 0x08);
+	m88ds3103_tuner_writereg(state, 0x50, 0x00);
+	msleep(5);
+
+	if(state->tuner_id == TS2020_ID){
+		RFgain = m88ds3103_tuner_readreg(state, 0x3d);
+		RFgain &= 0x0f;
+		if(RFgain < 15){
+			if(RFgain < 4) 
+				RFgain = 0;
+			else
+				RFgain = RFgain -3;
+			value = ((RFgain << 3) | 0x01) & 0x79;
+			m88ds3103_tuner_writereg(state, 0x60, value);
+			m88ds3103_tuner_writereg(state, 0x51, 0x17);
+			m88ds3103_tuner_writereg(state, 0x51, 0x1f);
+			m88ds3103_tuner_writereg(state, 0x50, 0x08);
+			m88ds3103_tuner_writereg(state, 0x50, 0x00);
+		}
+	}
+	
+	/* set the LPF */
+	if(state->tuner_id == TS2022_ID){
+		m88ds3103_tuner_writereg(state, 0x25, 0x00);
+		m88ds3103_tuner_writereg(state, 0x27, 0x70);
+		m88ds3103_tuner_writereg(state, 0x41, 0x09);
+		m88ds3103_tuner_writereg(state, 0x08, 0x0b);
+	}
+
+	f3db = ((c->symbol_rate / 1000) *135) / 200 + 2000;
+	f3db += lpf_offset_KHz;
+	if (f3db < 7000)
+		f3db = 7000;
+	if (f3db > 40000)
+		f3db = 40000;
+			
+	gdiv28 = (MT_FE_CRYSTAL_KHZ / 1000 * 1694 + 500) / 1000;
+	m88ds3103_tuner_writereg(state, 0x04, gdiv28 & 0xff);
+	m88ds3103_tuner_writereg(state, 0x51, 0x1b);
+	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
+	m88ds3103_tuner_writereg(state, 0x50, 0x04);
+	m88ds3103_tuner_writereg(state, 0x50, 0x00);
+	msleep(5);
+
+	value = m88ds3103_tuner_readreg(state, 0x26);
+	capCode = value & 0x3f;
+	if(state->tuner_id == TS2022_ID){
+		m88ds3103_tuner_writereg(state, 0x41, 0x0d);
+
+		m88ds3103_tuner_writereg(state, 0x51, 0x1b);
+		m88ds3103_tuner_writereg(state, 0x51, 0x1f);
+		m88ds3103_tuner_writereg(state, 0x50, 0x04);
+		m88ds3103_tuner_writereg(state, 0x50, 0x00);
+
+		msleep(2);
+
+		value = m88ds3103_tuner_readreg(state, 0x26);
+		value &= 0x3f;
+		value = (capCode + value) / 2;		
+	}
+	else
+		value = capCode;
+		
+	gdiv28 = gdiv28 * 207 / (value * 2 + 151);	
+	mlpf_max = gdiv28 * 135 / 100;
+	mlpf_min = gdiv28 * 78 / 100;
+	if (mlpf_max > 63)
+		mlpf_max = 63;
+
+	if(state->tuner_id == TS2022_ID)
+		lpf_coeff = 3200;
+	else
+		lpf_coeff = 2766;
+		
+	nlpf = (f3db * gdiv28 * 2 / lpf_coeff / (MT_FE_CRYSTAL_KHZ / 1000)  + 1) / 2 ;	
+	if (nlpf > 23) nlpf = 23;
+	if (nlpf < 1) nlpf = 1;
+
+	lpf_mxdiv = (nlpf * (MT_FE_CRYSTAL_KHZ / 1000) * lpf_coeff * 2 / f3db + 1) / 2;
+
+	if (lpf_mxdiv < mlpf_min){
+		nlpf++;
+		lpf_mxdiv = (nlpf * (MT_FE_CRYSTAL_KHZ / 1000) * lpf_coeff * 2  / f3db + 1) / 2;
+	}
+
+	if (lpf_mxdiv > mlpf_max)
+		lpf_mxdiv = mlpf_max;
+
+	m88ds3103_tuner_writereg(state, 0x04, lpf_mxdiv);
+	m88ds3103_tuner_writereg(state, 0x06, nlpf);
+	m88ds3103_tuner_writereg(state, 0x51, 0x1b);
+	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
+	m88ds3103_tuner_writereg(state, 0x50, 0x04);
+	m88ds3103_tuner_writereg(state, 0x50, 0x00);
+	msleep(5);
+	
+	if(state->tuner_id == TS2022_ID){
+		msleep(2);
+		value = m88ds3103_tuner_readreg(state, 0x26);
+		capCode = value & 0x3f;
+
+		m88ds3103_tuner_writereg(state, 0x41, 0x09);
+
+		m88ds3103_tuner_writereg(state, 0x51, 0x1b);
+		m88ds3103_tuner_writereg(state, 0x51, 0x1f);
+		m88ds3103_tuner_writereg(state, 0x50, 0x04);
+		m88ds3103_tuner_writereg(state, 0x50, 0x00);
+
+		msleep(2);
+		value = m88ds3103_tuner_readreg(state, 0x26);
+		value &= 0x3f;
+		value = (capCode + value) / 2;
+
+		value = value | 0x80;
+		m88ds3103_tuner_writereg(state, 0x25, value);
+		m88ds3103_tuner_writereg(state, 0x27, 0x30);
+
+		m88ds3103_tuner_writereg(state, 0x08, 0x09);		
+	}
+
+	/* Set the BB gain */
+	m88ds3103_tuner_writereg(state, 0x51, 0x1e);
+	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
+	m88ds3103_tuner_writereg(state, 0x50, 0x01);
+	m88ds3103_tuner_writereg(state, 0x50, 0x00);
+	if(state->tuner_id == TS2020_ID){
+		if(RFgain == 15){
+			msleep(40);
+			value = m88ds3103_tuner_readreg(state, 0x21);
+			value &= 0x0f;
+			if(value < 3){
+				m88ds3103_tuner_writereg(state, 0x60, 0x61);
+				m88ds3103_tuner_writereg(state, 0x51, 0x17);
+				m88ds3103_tuner_writereg(state, 0x51, 0x1f);
+				m88ds3103_tuner_writereg(state, 0x50, 0x08);
+				m88ds3103_tuner_writereg(state, 0x50, 0x00);
+			}			
+		}
+	}
+	msleep(60);
+	
+	offset_khz = (ndiv - ndiv % 2 + 1024) * MT_FE_CRYSTAL_KHZ
+		/ (6 + 8) / (div4 + 1) / 2 - realFreq;
+
+	m88ds3103_demod_connect(fe, offset_khz+lpf_offset_KHz);
+
+	for (i = 0; i < 30 ; i++) {
+		m88ds3103_read_status(fe, &status);
+		if (status & FE_HAS_LOCK){
+			break;
+                }
+		msleep(20);
+	}
+	
+	if((status & FE_HAS_LOCK) == 0){
+		state->delivery_system = (state->delivery_system == SYS_DVBS) ? SYS_DVBS2 : SYS_DVBS;
+		m88ds3103_demod_connect(fe, offset_khz);
+	
+		for (i = 0; i < 30 ; i++) {
+			m88ds3103_read_status(fe, &status);
+			if (status & FE_HAS_LOCK){
+				break;
+                	}
+			msleep(20);
+		}
+	}
+	
+	if (status & FE_HAS_LOCK){
+		if(state->config->start_ctrl){
+			if(state->first_lock == 0){
+				state->config->start_ctrl(fe);
+				state->first_lock = 1;	
+			}
+		}		
+	}
+		
+	return 0;
+}
+
+static int m88ds3103_tune(struct dvb_frontend *fe,
+			bool re_tune,
+			unsigned int mode_flags,
+			unsigned int *delay,
+			fe_status_t *status)
+{	
+	*delay = HZ / 5;
+	
+	dprintk("%s() ", __func__);
+	dprintk("re_tune = %d\n", re_tune);
+	
+	if (re_tune) {
+		int ret = m88ds3103_set_frontend(fe);
+		if (ret)
+			return ret;
+	}
+	
+	return m88ds3103_read_status(fe, status);
+}
+
+static enum dvbfe_algo m88ds3103_get_algo(struct dvb_frontend *fe)
+{
+	return DVBFE_ALGO_HW;
+}
+ 
+ /*
+ * Power config will reset and load initial firmware if required
+ */
+static int m88ds3103_initilaze(struct dvb_frontend *fe)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	int ret;
+
+	dprintk("%s()\n", __func__);
+	/* hard reset */
+	m88ds3103_writereg(state, 0x07, 0x80);
+	m88ds3103_writereg(state, 0x07, 0x00);
+	msleep(1);
+	
+	m88ds3103_writereg(state, 0x08, 0x01 | m88ds3103_readreg(state, 0x08));
+	msleep(1);
+
+	if(state->tuner_id == TS2020_ID){
+		/* TS2020 init */
+		m88ds3103_tuner_writereg(state, 0x42, 0x73);
+		msleep(2);
+		m88ds3103_tuner_writereg(state, 0x05, 0x01);
+		m88ds3103_tuner_writereg(state, 0x62, 0xb5);
+		m88ds3103_tuner_writereg(state, 0x07, 0x02);
+		m88ds3103_tuner_writereg(state, 0x08, 0x01);
+	}
+	else if(state->tuner_id == TS2022_ID){
+		/* TS2022 init */
+		m88ds3103_tuner_writereg(state, 0x62, 0x6c);
+		msleep(2);
+		m88ds3103_tuner_writereg(state, 0x42, 0x6c);
+		msleep(2);
+		m88ds3103_tuner_writereg(state, 0x7d, 0x9d);
+		m88ds3103_tuner_writereg(state, 0x7c, 0x9a);
+		m88ds3103_tuner_writereg(state, 0x7a, 0x76);
+
+		m88ds3103_tuner_writereg(state, 0x3b, 0x01);
+		m88ds3103_tuner_writereg(state, 0x63, 0x88);
+
+		m88ds3103_tuner_writereg(state, 0x61, 0x85);
+		m88ds3103_tuner_writereg(state, 0x22, 0x30);
+		m88ds3103_tuner_writereg(state, 0x30, 0x40);
+		m88ds3103_tuner_writereg(state, 0x20, 0x23);
+		m88ds3103_tuner_writereg(state, 0x24, 0x02);
+		m88ds3103_tuner_writereg(state, 0x12, 0xa0);	
+	}
+		
+	if(state->demod_id == DS3103_ID){
+		m88ds3103_writereg(state, 0x07, 0xe0);
+		m88ds3103_writereg(state, 0x07, 0x00);
+		msleep(1);		
+	}
+	m88ds3103_writereg(state, 0xb2, 0x01);
+	
+	/* Load the firmware if required */
+	ret = m88ds3103_load_firmware(fe);
+	if (ret != 0){
+		printk(KERN_ERR "%s: Unable initialize firmware\n", __func__);
+		return ret;
+	}
+	if(state->demod_id == DS3103_ID){
+		m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d));
+		m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30));		
+	}
+
+	return 0;
+}
+
+/*
+ * Initialise or wake up device
+ */
+static int m88ds3103_initfe(struct dvb_frontend *fe)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	u8 val;
+
+	dprintk("%s()\n", __func__);
+
+	/* 1st step to wake up demod */
+	m88ds3103_writereg(state, 0x08, 0x01 | m88ds3103_readreg(state, 0x08));
+	m88ds3103_writereg(state, 0x04, 0xfe & m88ds3103_readreg(state, 0x04));
+	m88ds3103_writereg(state, 0x23, 0xef & m88ds3103_readreg(state, 0x23));
+	
+	/* 2nd step to wake up tuner */
+	val = m88ds3103_tuner_readreg(state, 0x00) & 0xff;
+	if((val & 0x01) == 0){
+		m88ds3103_tuner_writereg(state, 0x00, 0x01);
+		msleep(50);
+	}
+	m88ds3103_tuner_writereg(state, 0x00, 0x03);
+	msleep(50);
+	
+	return 0;	
+}
+
+/* Put device to sleep */
+static int m88ds3103_sleep(struct dvb_frontend *fe)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+
+	dprintk("%s()\n", __func__);
+	
+	/* 1st step to sleep tuner */
+	m88ds3103_tuner_writereg(state, 0x00, 0x00);
+	
+	/* 2nd step to sleep demod */
+	m88ds3103_writereg(state, 0x08, 0xfe & m88ds3103_readreg(state, 0x08));
+	m88ds3103_writereg(state, 0x04, 0x01 | m88ds3103_readreg(state, 0x04));
+	m88ds3103_writereg(state, 0x23, 0x10 | m88ds3103_readreg(state, 0x23));
+	
+
+	return 0;
+}
+
+static struct dvb_frontend_ops m88ds3103_ops = {
+	.delsys = { SYS_DVBS, SYS_DVBS2},
+	.info = {
+		.name = "Montage DS3103/TS2022",
+		.type = FE_QPSK,
+		.frequency_min = 950000,
+		.frequency_max = 2150000,
+		.frequency_stepsize = 1011, /* kHz for QPSK frontends */
+		.frequency_tolerance = 5000,
+		.symbol_rate_min = 1000000,
+		.symbol_rate_max = 45000000,
+		.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+			FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_2G_MODULATION |
+			FE_CAN_QPSK | FE_CAN_RECOVER
+	},
+
+	.release = m88ds3103_release,
+
+	.init = m88ds3103_initfe,
+	.sleep = m88ds3103_sleep,
+	.read_status = m88ds3103_read_status,
+	.read_ber = m88ds3103_read_ber,
+	.read_signal_strength = m88ds3103_read_signal_strength,
+	.read_snr = m88ds3103_read_snr,
+	.read_ucblocks = m88ds3103_read_ucblocks,
+	.set_tone = m88ds3103_set_tone,
+	.set_voltage = m88ds3103_set_voltage,
+	.diseqc_send_master_cmd = m88ds3103_send_diseqc_msg,
+	.diseqc_send_burst = m88ds3103_diseqc_send_burst,
+	.get_frontend_algo = m88ds3103_get_algo,
+	.tune = m88ds3103_tune,
+	.set_frontend = m88ds3103_set_frontend,
+};
+
+MODULE_DESCRIPTION("DVB Frontend module for Montage DS3103/TS2022 hardware");
+MODULE_AUTHOR("Max nibble");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/m88ds3103.h b/drivers/media/dvb/frontends/m88ds3103.h
new file mode 100644
index 0000000..c7b690e
--- /dev/null
+++ b/drivers/media/dvb/frontends/m88ds3103.h
@@ -0,0 +1,53 @@
+/*
+    Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner driver
+
+    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 M88DS3103_H
+#define M88DS3103_H
+
+#include <linux/dvb/frontend.h>
+
+struct m88ds3103_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+	u8 ci_mode;
+	u8 pin_ctrl;
+	u8 ts_mode; /* 0: Parallel, 1: Serial */
+
+	/* Set device param to start dma */
+	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
+    /* Start to transfer data */
+    int (*start_ctrl)(struct dvb_frontend *fe);
+    /* Set LNB voltage */
+    int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
+};
+
+#if defined(CONFIG_DVB_M88DS3103) || \
+	(defined(CONFIG_DVB_M88DS3103_MODULE) && defined(MODULE))
+extern struct dvb_frontend *m88ds3103_attach(
+       const struct m88ds3103_config *config,
+       struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *m88ds3103_attach(
+       const struct m88ds3103_config *config,
+       struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_M88DS3103 */
+#endif /* M88DS3103_H */
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 2/6] m88ds3103, dvbsky dvb-s2 usb box.
  2012-01-26 16:56 ` Mauro Carvalho Chehab
  2012-01-27 22:26   ` Malcolm Priestley
  2012-04-15 15:53   ` [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver nibble.max
@ 2012-04-15 15:53   ` nibble.max
  2012-04-19 18:09     ` Mauro Carvalho Chehab
  2012-04-20  8:08     ` nibble.max
  2012-04-15 15:53   ` [PATCH 3/6] m88ds3103, dvbsky dvb-s2 cx23883 pci card nibble.max
                     ` (3 subsequent siblings)
  6 siblings, 2 replies; 56+ messages in thread
From: nibble.max @ 2012-04-15 15:53 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

dvbsky dvb-s2 usb box based on montage m88ds3103 demodulator.

Signed-off-by: Max nibble <nibble.max@gmail.com>
---
 drivers/media/dvb/dvb-usb/Kconfig  |    1 +
 drivers/media/dvb/dvb-usb/dw2102.c |  236 +++++++++++++++++++++++++++++++++++-
 2 files changed, 236 insertions(+), 1 deletion(-)

diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index be1db75..bf63f29 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -279,6 +279,7 @@ config DVB_USB_DW2102
 	select DVB_STV0288 if !DVB_FE_CUSTOMISE
 	select DVB_STB6000 if !DVB_FE_CUSTOMISE
 	select DVB_CX24116 if !DVB_FE_CUSTOMISE
+	select DVB_M88DS3103 if !DVB_FE_CUSTOMISE
 	select DVB_SI21XX if !DVB_FE_CUSTOMISE
 	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
 	select DVB_MT312 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c
index 451c5a7..0b1bbd2 100644
--- a/drivers/media/dvb/dvb-usb/dw2102.c
+++ b/drivers/media/dvb/dvb-usb/dw2102.c
@@ -19,6 +19,7 @@
 #include "stb6000.h"
 #include "eds1547.h"
 #include "cx24116.h"
+#include "m88ds3103.h"
 #include "tda1002x.h"
 #include "mt312.h"
 #include "zl10039.h"
@@ -882,6 +883,44 @@ static int s660_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 	return 0;
 }
 
+static int bstusb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+
+	struct dvb_usb_adapter *udev_adap =
+		(struct dvb_usb_adapter *)(fe->dvb->priv);
+
+	u8 obuf[3] = { 0xe, 0x80, 0 };
+	u8 ibuf[] = { 0 };
+		
+	info("US6830: %s!\n", __func__);
+				
+	if (voltage == SEC_VOLTAGE_OFF)
+		obuf[2] = 0;
+	else 
+		obuf[2] = 1;
+		
+	if (dvb_usb_generic_rw(udev_adap->dev, obuf, 3, ibuf, 1, 0) < 0)
+		err("command 0x0e transfer failed.");
+	
+	return 0;
+}
+
+static int bstusb_restart(struct dvb_frontend *fe)
+{
+
+	struct dvb_usb_adapter *udev_adap =
+		(struct dvb_usb_adapter *)(fe->dvb->priv);
+	
+	u8 obuf[3] = { 0x36, 3, 0 };
+	u8 ibuf[] = { 0 };
+			
+
+	if (dvb_usb_generic_rw(udev_adap->dev, obuf, 3, ibuf, 1, 0) < 0)
+		err("command 0x36 transfer failed.");
+	
+	return 0;
+}
+
 static void dw210x_led_ctrl(struct dvb_frontend *fe, int offon)
 {
 	static u8 led_off[] = { 0 };
@@ -987,6 +1026,24 @@ static struct ds3000_config su3000_ds3000_config = {
 	.ci_mode = 1,
 };
 
+static struct m88ds3103_config US6830_ds3103_config = {
+	.demod_address = 0x68,
+	.ci_mode = 1,
+	.pin_ctrl = 0x83,
+	.ts_mode = 0,
+	.start_ctrl = bstusb_restart,
+	.set_voltage = bstusb_set_voltage,
+};
+
+static struct m88ds3103_config US6832_ds3103_config = {
+	.demod_address = 0x68,
+	.ci_mode = 1,
+	.pin_ctrl = 0x80,
+	.ts_mode = 0,
+	.start_ctrl = bstusb_restart,
+	.set_voltage = bstusb_set_voltage,
+};
+
 static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
 {
 	struct dvb_tuner_ops *tuner_ops = NULL;
@@ -1214,6 +1271,72 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *d)
 	return 0;
 }
 
+static int US6830_frontend_attach(struct dvb_usb_adapter *d)
+{
+	u8 obuf[3] = { 0xe, 0x83, 0 };
+	u8 ibuf[] = { 0 };
+
+
+	info("US6830: %s!\n", __func__);
+	
+	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+		err("command 0x0e transfer failed.");
+
+	obuf[0] = 0xe;
+	obuf[1] = 0x83;
+	obuf[2] = 1;
+
+	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+		err("command 0x0e transfer failed.");
+
+	obuf[0] = 0x51;
+
+	if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
+		err("command 0x51 transfer failed.");
+
+	d->fe_adap[0].fe = dvb_attach(m88ds3103_attach, &US6830_ds3103_config,
+					&d->dev->i2c_adap);
+	if (d->fe_adap[0].fe == NULL)
+		return -EIO;
+
+	info("Attached M88DS3103!\n");
+
+	return 0;
+}
+
+static int US6832_frontend_attach(struct dvb_usb_adapter *d)
+{
+	u8 obuf[3] = { 0xe, 0x83, 0 };
+	u8 ibuf[] = { 0 };
+
+
+	info("US6832: %s!\n", __func__);
+	
+	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+		err("command 0x0e transfer failed.");
+
+	obuf[0] = 0xe;
+	obuf[1] = 0x83;
+	obuf[2] = 1;
+
+	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+		err("command 0x0e transfer failed.");
+
+	obuf[0] = 0x51;
+
+	if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
+		err("command 0x51 transfer failed.");
+
+	d->fe_adap[0].fe = dvb_attach(m88ds3103_attach, &US6832_ds3103_config,
+					&d->dev->i2c_adap);
+	if (d->fe_adap[0].fe == NULL)
+		return -EIO;
+
+	info("Attached M88DS3103!\n");
+
+	return 0;
+}
+
 static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
 {
 	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
@@ -1451,6 +1574,9 @@ enum dw2102_table_entry {
 	TEVII_S480_1,
 	TEVII_S480_2,
 	X3M_SPC1400HD,
+	BST_US6830HD,
+	BST_US6831HD,
+	BST_US6832HD,
 };
 
 static struct usb_device_id dw2102_table[] = {
@@ -1469,6 +1595,9 @@ static struct usb_device_id dw2102_table[] = {
 	[TEVII_S480_1] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)},
 	[TEVII_S480_2] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)},
 	[X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)},
+	[BST_US6830HD] = {USB_DEVICE(0x0572, 0x6830)},
+	[BST_US6831HD] = {USB_DEVICE(0x0572, 0x6831)},
+	[BST_US6832HD] = {USB_DEVICE(0x0572, 0x6832)},
 	{ }
 };
 
@@ -1874,6 +2003,107 @@ static struct dvb_usb_device_properties su3000_properties = {
 	}
 };
 
+static struct dvb_usb_device_properties US6830_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.size_of_priv = sizeof(struct su3000_state),
+	.power_ctrl = su3000_power_ctrl,
+	.num_adapters = 1,
+	.identify_state	= su3000_identify_state,
+	.i2c_algo = &su3000_i2c_algo,
+
+	.rc.legacy = {
+		.rc_map_table = rc_map_su3000_table,
+		.rc_map_size = ARRAY_SIZE(rc_map_su3000_table),
+		.rc_interval = 150,
+		.rc_query = dw2102_rc_query,
+	},
+
+	.read_mac_address = su3000_read_mac_address,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+	
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl   = su3000_streaming_ctrl,
+			.frontend_attach  = US6830_frontend_attach,
+			.stream = {
+				.type = USB_BULK,
+				.count = 8,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			}
+		}},
+		}
+	},
+	.num_device_descs = 2,
+	.devices = {
+		{ "Bestunar US6830 HD",
+			{ &dw2102_table[BST_US6830HD], NULL },
+			{ NULL },
+		},
+		{ "Bestunar US6831 HD",
+			{ &dw2102_table[BST_US6831HD], NULL },
+			{ NULL },
+		},				
+	}
+};
+
+static struct dvb_usb_device_properties US6832_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.size_of_priv = sizeof(struct su3000_state),
+	.power_ctrl = su3000_power_ctrl,
+	.num_adapters = 1,
+	.identify_state	= su3000_identify_state,
+	.i2c_algo = &su3000_i2c_algo,
+
+	.rc.legacy = {
+		.rc_map_table = rc_map_su3000_table,
+		.rc_map_size = ARRAY_SIZE(rc_map_su3000_table),
+		.rc_interval = 150,
+		.rc_query = dw2102_rc_query,
+	},
+
+	.read_mac_address = su3000_read_mac_address,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = {{
+			.streaming_ctrl   = su3000_streaming_ctrl,
+			.frontend_attach  = US6832_frontend_attach,
+			.stream = {
+				.type = USB_BULK,
+				.count = 8,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			}
+		}},
+		}
+	},
+	.num_device_descs = 1,
+	.devices = {
+		{ "Bestunar US6832 HD",
+			{ &dw2102_table[BST_US6832HD], NULL },
+			{ NULL },
+		},
+				
+	}
+};
+
 static int dw2102_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
@@ -1930,7 +2160,11 @@ static int dw2102_probe(struct usb_interface *intf,
 	    0 == dvb_usb_device_init(intf, p7500,
 			THIS_MODULE, NULL, adapter_nr) ||
 	    0 == dvb_usb_device_init(intf, &su3000_properties,
-				     THIS_MODULE, NULL, adapter_nr))
+     			THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &US6830_properties,
+			THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &US6832_properties,
+			THIS_MODULE, NULL, adapter_nr))
 		return 0;
 
 	return -ENODEV;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 3/6] m88ds3103, dvbsky dvb-s2 cx23883 pci card.
  2012-01-26 16:56 ` Mauro Carvalho Chehab
                     ` (2 preceding siblings ...)
  2012-04-15 15:53   ` [PATCH 2/6] m88ds3103, dvbsky dvb-s2 usb box nibble.max
@ 2012-04-15 15:53   ` nibble.max
  2012-04-15 15:53   ` [PATCH 4/6] m88ds3103, dvbsky dvb-s2 cx23885 pcie card nibble.max
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 56+ messages in thread
From: nibble.max @ 2012-04-15 15:53 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

dvbsky dvb-s2 pci based on montage m88ds3103 demodulator.

Signed-off-by: Max nibble <nibble.max@gmail.com>
---
 drivers/media/video/cx88/Kconfig      |    1 +
 drivers/media/video/cx88/cx88-cards.c |   22 +++++++++
 drivers/media/video/cx88/cx88-dvb.c   |   85 +++++++++++++++++++++++++++++++++
 drivers/media/video/cx88/cx88-input.c |    4 ++
 drivers/media/video/cx88/cx88.h       |    1 +
 5 files changed, 113 insertions(+)

diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 3598dc0..0daef63 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -57,6 +57,7 @@ config VIDEO_CX88_DVB
 	select DVB_ISL6421 if !DVB_FE_CUSTOMISE
 	select DVB_S5H1411 if !DVB_FE_CUSTOMISE
 	select DVB_CX24116 if !DVB_FE_CUSTOMISE
+	select DVB_M88DS3103 if !DVB_FE_CUSTOMISE
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_STV0288 if !DVB_FE_CUSTOMISE
 	select DVB_STB6000 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index cbd5d11..059b22d 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -2309,6 +2309,18 @@ static const struct cx88_board cx88_boards[] = {
 		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
+	[CX88_BOARD_BST_PS8312] = {
+		.name           = "Bestunar PS8312 DVB-S/S2",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
 };
 
 /* ------------------------------------------------------------------ */
@@ -2813,6 +2825,10 @@ static const struct cx88_subid cx88_subids[] = {
 		.subvendor = 0x1822,
 		.subdevice = 0x0023,
 		.card      = CX88_BOARD_TWINHAN_VP1027_DVBS,
+	}, {
+		.subvendor = 0x14f1,
+		.subdevice = 0x8312,
+		.card      = CX88_BOARD_BST_PS8312,
 	},
 };
 
@@ -3547,6 +3563,12 @@ static void cx88_card_setup(struct cx88_core *core)
 		cx_write(MO_SRST_IO, 1);
 		msleep(100);
 		break;
+	case  CX88_BOARD_BST_PS8312:
+		cx_write(MO_GP1_IO, 0x808000);
+		msleep(100);
+		cx_write(MO_GP1_IO, 0x808080);
+		msleep(100);		
+		break;	
 	} /*end switch() */
 
 
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 003937c..5e19ef3 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -54,6 +54,7 @@
 #include "stv0288.h"
 #include "stb6000.h"
 #include "cx24116.h"
+#include "m88ds3103.h"
 #include "stv0900.h"
 #include "stb6100.h"
 #include "stb6100_proc.h"
@@ -458,6 +459,56 @@ static int tevii_dvbs_set_voltage(struct dvb_frontend *fe,
 		return core->prev_set_voltage(fe, voltage);
 	return 0;
 }
+/*CX88_BOARD_BST_PS8312*/
+static int bst_dvbs_set_voltage(struct dvb_frontend *fe,
+				      fe_sec_voltage_t voltage)
+{
+	struct cx8802_dev *dev= fe->dvb->priv;
+	struct cx88_core *core = dev->core;
+
+	cx_write(MO_GP1_IO, 0x111111);
+	switch (voltage) {
+		case SEC_VOLTAGE_13:
+			cx_write(MO_GP1_IO, 0x020200);
+			break;
+		case SEC_VOLTAGE_18:
+			cx_write(MO_GP1_IO, 0x020202);
+			break;
+		case SEC_VOLTAGE_OFF:
+			cx_write(MO_GP1_IO, 0x111100);
+			break;
+	}
+
+	if (core->prev_set_voltage)
+		return core->prev_set_voltage(fe, voltage);
+	return 0;
+}
+
+static int bst_dvbs_set_voltage_v2(struct dvb_frontend *fe,
+				      fe_sec_voltage_t voltage)
+{
+	struct cx8802_dev *dev= fe->dvb->priv;
+	struct cx88_core *core = dev->core;
+
+	cx_write(MO_GP1_IO, 0x111101);
+	switch (voltage) {
+		case SEC_VOLTAGE_13:
+			cx_write(MO_GP1_IO, 0x020200);
+			break;
+		case SEC_VOLTAGE_18:
+
+			cx_write(MO_GP1_IO, 0x020202);
+			break;
+		case SEC_VOLTAGE_OFF:
+
+			cx_write(MO_GP1_IO, 0x111110);
+			break;
+	}
+
+	if (core->prev_set_voltage)
+		return core->prev_set_voltage(fe, voltage);
+	return 0;
+}
 
 static int vp1027_set_voltage(struct dvb_frontend *fe,
 				    fe_sec_voltage_t voltage)
@@ -700,6 +751,11 @@ static struct ds3000_config tevii_ds3000_config = {
 	.set_ts_params = ds3000_set_ts_param,
 };
 
+static struct m88ds3103_config dvbsky_ds3103_config = {
+	.demod_address = 0x68,
+	.set_ts_params = ds3000_set_ts_param,
+};
+
 static const struct stv0900_config prof_7301_stv0900_config = {
 	.demod_address = 0x6a,
 /*	demod_mode = 0,*/
@@ -1470,6 +1526,35 @@ static int dvb_register(struct cx8802_dev *dev)
 			fe0->dvb.frontend->ops.set_voltage =
 							tevii_dvbs_set_voltage;
 		break;
+	case CX88_BOARD_BST_PS8312:
+		fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
+						&dvbsky_ds3103_config,
+						&core->i2c_adap);
+		if (fe0->dvb.frontend != NULL){
+			int ret;
+			u8 b0[] = { 0x60 };
+			u8 b1[2] = { 0 };
+			struct i2c_msg msg[] = {
+				{
+				.addr = 0x50,
+				.flags = 0,
+				.buf = b0,
+				.len = 1
+				}, {
+				.addr = 0x50,
+				.flags = I2C_M_RD,
+				.buf = b1,
+				.len = 2
+				}
+			};
+			ret = i2c_transfer(&core->i2c_adap, msg, 2);
+			printk("PS8312: config = %02x, %02x", b1[0],b1[1]);
+			if(b1[0] == 0xaa)
+				fe0->dvb.frontend->ops.set_voltage = bst_dvbs_set_voltage_v2;
+			else			
+				fe0->dvb.frontend->ops.set_voltage = bst_dvbs_set_voltage;
+		}
+		break;
 	case CX88_BOARD_OMICOM_SS4_PCI:
 	case CX88_BOARD_TBS_8920:
 	case CX88_BOARD_PROF_7300:
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index ebf448c..f698103 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -419,6 +419,10 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
 		rc_type          = RC_TYPE_NEC;
 		ir->sampling     = 0xff00; /* address */
 		break;
+	case CX88_BOARD_BST_PS8312: 
+		ir_codes         = RC_MAP_DVBSKY;
+		ir->sampling     = 0xff00; /* address */
+		break;	
 	}
 
 	if (!ir_codes) {
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index c9659de..a988f14 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -246,6 +246,7 @@ extern const struct sram_channel const cx88_sram_channels[];
 #define CX88_BOARD_WINFAST_DTV1800H_XC4000 88
 #define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36 89
 #define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43 90
+#define CX88_BOARD_BST_PS8312              91
 
 enum cx88_itype {
 	CX88_VMUX_COMPOSITE1 = 1,
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 4/6] m88ds3103, dvbsky dvb-s2 cx23885 pcie card.
  2012-01-26 16:56 ` Mauro Carvalho Chehab
                     ` (3 preceding siblings ...)
  2012-04-15 15:53   ` [PATCH 3/6] m88ds3103, dvbsky dvb-s2 cx23883 pci card nibble.max
@ 2012-04-15 15:53   ` nibble.max
  2012-04-19 18:11     ` Mauro Carvalho Chehab
  2012-04-15 15:53   ` [PATCH 5/6] m88ds3103, dvbsky remote control key map nibble.max
  2012-04-15 15:53   ` [PATCH 6/6] m88ds3103, dvbsky remote control include header file nibble.max
  6 siblings, 1 reply; 56+ messages in thread
From: nibble.max @ 2012-04-15 15:53 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

dvbsky dvb-s2 pcie based on montage m88ds3103 demodulator.

Signed-off-by: Max nibble <nibble.max@gmail.com>
---
 drivers/media/video/cx23885/Kconfig         |    1 +
 drivers/media/video/cx23885/cx23885-cards.c |  107 +++++++++++++++++++++++++++
 drivers/media/video/cx23885/cx23885-dvb.c   |   52 +++++++++++++
 drivers/media/video/cx23885/cx23885-f300.c  |   55 ++++++++++++++
 drivers/media/video/cx23885/cx23885-f300.h  |    6 ++
 drivers/media/video/cx23885/cx23885-input.c |   15 ++++
 drivers/media/video/cx23885/cx23885.h       |    3 +
 7 files changed, 239 insertions(+)

diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
index b391e9b..20337c7 100644
--- a/drivers/media/video/cx23885/Kconfig
+++ b/drivers/media/video/cx23885/Kconfig
@@ -20,6 +20,7 @@ config VIDEO_CX23885
 	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
 	select DVB_STV6110 if !DVB_FE_CUSTOMISE
 	select DVB_CX24116 if !DVB_FE_CUSTOMISE
+	select DVB_M88DS3103 if !DVB_FE_CUSTOMISE
 	select DVB_STV0900 if !DVB_FE_CUSTOMISE
 	select DVB_DS3000 if !DVB_FE_CUSTOMISE
 	select DVB_STV0367 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index 19b5499..fdf9d0f 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -497,6 +497,20 @@ struct cx23885_board cx23885_boards[] = {
 		.name		= "TerraTec Cinergy T PCIe Dual",
 		.portb		= CX23885_MPEG_DVB,
 		.portc		= CX23885_MPEG_DVB,
+	},
+
+	[CX23885_BOARD_BST_PS8512] = {
+		.name		= "Bestunar PS8512",
+		.portb		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_DVBSKY_S950] = {
+		.name		= "DVBSKY S950",
+		.portb		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_DVBSKY_S952] = {
+		.name		= "DVBSKY S952",
+		.portb		= CX23885_MPEG_DVB,
+		.portc		= CX23885_MPEG_DVB,
 	}
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -705,6 +719,18 @@ struct cx23885_subid cx23885_subids[] = {
 		.subvendor = 0x153b,
 		.subdevice = 0x117e,
 		.card      = CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL,
+	}, {
+		.subvendor = 0x14f1,
+		.subdevice = 0x8512,
+		.card      = CX23885_BOARD_BST_PS8512,
+	}, {
+		.subvendor = 0x4254,
+		.subdevice = 0x0950,
+		.card      = CX23885_BOARD_DVBSKY_S950,		
+	}, {
+		.subvendor = 0x4254,
+		.subdevice = 0x0952,
+		.card      = CX23885_BOARD_DVBSKY_S952,
 	},
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -1216,9 +1242,57 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
 		/* enable irq */
 		cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/
 		break;
+	case CX23885_BOARD_DVBSKY_S950:
+	case CX23885_BOARD_BST_PS8512:			
+		cx23885_gpio_enable(dev, GPIO_2, 1);
+		cx23885_gpio_clear(dev, GPIO_2);
+		msleep(100);		
+		cx23885_gpio_set(dev, GPIO_2);
+		break;
+	case CX23885_BOARD_DVBSKY_S952:		
+		cx_write(MC417_CTL, 0x00000037);/* enable GPIO3-18 pins */
+		
+		cx23885_gpio_enable(dev, GPIO_2, 1);
+		cx23885_gpio_enable(dev, GPIO_11, 1);
+		
+		cx23885_gpio_clear(dev, GPIO_2);
+		cx23885_gpio_clear(dev, GPIO_11);
+		msleep(100);		
+		cx23885_gpio_set(dev, GPIO_2);
+		cx23885_gpio_set(dev, GPIO_11);
+		
+		break;
 	}
 }
 
+static int cx23885_ir_patch(struct i2c_adapter *i2c, u8 reg, u8 mask)
+{
+	struct i2c_msg msgs[2];
+	u8 tx_buf[2], rx_buf[1];
+	/* Write register address */
+	tx_buf[0] = reg;
+	msgs[0].addr = 0x4c;
+	msgs[0].flags = 0;
+	msgs[0].len = 1;
+	msgs[0].buf = (char *) tx_buf;
+	/* Read data from register */
+	msgs[1].addr = 0x4c;
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].len = 1;
+	msgs[1].buf = (char *) rx_buf;	
+	
+	i2c_transfer(i2c, msgs, 2);
+
+	tx_buf[0] = reg;
+	tx_buf[1] = rx_buf[0] | mask;
+	msgs[0].addr = 0x4c;
+	msgs[0].flags = 0;
+	msgs[0].len = 2;
+	msgs[0].buf = (char *) tx_buf;
+	
+	return i2c_transfer(i2c, msgs, 1);
+}
+
 int cx23885_ir_init(struct cx23885_dev *dev)
 {
 	static struct v4l2_subdev_io_pin_config ir_rxtx_pin_cfg[] = {
@@ -1301,6 +1375,20 @@ int cx23885_ir_init(struct cx23885_dev *dev)
 		v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
 				 ir_rx_pin_cfg_count, ir_rx_pin_cfg);
 		break;
+	case CX23885_BOARD_BST_PS8512:
+	case CX23885_BOARD_DVBSKY_S950:
+	case CX23885_BOARD_DVBSKY_S952:
+		dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE);
+		if (dev->sd_ir == NULL) {
+			ret = -ENODEV;
+			break;
+		}
+		v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
+				 ir_rx_pin_cfg_count, ir_rx_pin_cfg);
+				 
+		cx23885_ir_patch(&(dev->i2c_bus[2].i2c_adap),0x1f,0x80);
+		cx23885_ir_patch(&(dev->i2c_bus[2].i2c_adap),0x23,0x80);
+		break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
 		if (!enable_885_ir)
 			break;
@@ -1332,6 +1420,9 @@ void cx23885_ir_fini(struct cx23885_dev *dev)
 		break;
 	case CX23885_BOARD_TEVII_S470:
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+	case CX23885_BOARD_BST_PS8512:
+	case CX23885_BOARD_DVBSKY_S950:
+	case CX23885_BOARD_DVBSKY_S952:
 		cx23885_irq_remove(dev, PCI_MSK_AV_CORE);
 		/* sd_ir is a duplicate pointer to the AV Core, just clear it */
 		dev->sd_ir = NULL;
@@ -1375,6 +1466,9 @@ void cx23885_ir_pci_int_enable(struct cx23885_dev *dev)
 		break;
 	case CX23885_BOARD_TEVII_S470:
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+	case CX23885_BOARD_BST_PS8512:
+	case CX23885_BOARD_DVBSKY_S950:
+	case CX23885_BOARD_DVBSKY_S952:
 		if (dev->sd_ir)
 			cx23885_irq_add_enable(dev, PCI_MSK_AV_CORE);
 		break;
@@ -1459,6 +1553,8 @@ void cx23885_card_setup(struct cx23885_dev *dev)
 		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
 		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
 		break;
+	case CX23885_BOARD_BST_PS8512:
+	case CX23885_BOARD_DVBSKY_S950:
 	case CX23885_BOARD_TEVII_S470:
 	case CX23885_BOARD_DVBWORLD_2005:
 		ts1->gen_ctrl_val  = 0x5; /* Parallel */
@@ -1489,6 +1585,14 @@ void cx23885_card_setup(struct cx23885_dev *dev)
 		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
 		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
 		break;
+	case CX23885_BOARD_DVBSKY_S952:
+		ts1->gen_ctrl_val  = 0x5; /* Parallel */
+		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+		ts2->gen_ctrl_val  = 0xe; /* Serial bus + punctured clock */
+		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+		break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
 	case CX23885_BOARD_HAUPPAUGE_HVR1500:
 	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
@@ -1541,6 +1645,9 @@ void cx23885_card_setup(struct cx23885_dev *dev)
 	case CX23885_BOARD_MPX885:
 	case CX23885_BOARD_MYGICA_X8507:
 	case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
+	case CX23885_BOARD_BST_PS8512:
+	case CX23885_BOARD_DVBSKY_S950:
+	case CX23885_BOARD_DVBSKY_S952:
 		dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
 				&dev->i2c_bus[2].i2c_adap,
 				"cx25840", 0x88 >> 1, NULL);
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index 6835eb1..c5a3fa3 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -51,6 +51,7 @@
 #include "stv6110.h"
 #include "lnbh24.h"
 #include "cx24116.h"
+#include "m88ds3103.h"
 #include "cimax2.h"
 #include "lgs8gxx.h"
 #include "netup-eeprom.h"
@@ -489,6 +490,30 @@ static struct xc5000_config mygica_x8506_xc5000_config = {
 	.if_khz = 5380,
 };
 
+/* bestunar single dvb-s2 */
+static struct m88ds3103_config bst_ds3103_config = {
+	.demod_address = 0x68,
+	.ci_mode = 0,
+	.pin_ctrl = 0x82,
+	.ts_mode = 0,
+	.set_voltage = bst_set_voltage,
+};
+/* DVBSKY dual dvb-s2 */
+static struct m88ds3103_config dvbsky_ds3103_config_pri = {
+	.demod_address = 0x68,
+	.ci_mode = 0,
+	.pin_ctrl = 0x82,
+	.ts_mode = 0,
+	.set_voltage = bst_set_voltage,	
+};
+static struct m88ds3103_config dvbsky_ds3103_config_sec = {
+	.demod_address = 0x68,
+	.ci_mode = 0,
+	.pin_ctrl = 0x82,
+	.ts_mode = 1,
+	.set_voltage = dvbsky_set_voltage_sec,	
+};
+
 static int cx23885_dvb_set_frontend(struct dvb_frontend *fe)
 {
 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
@@ -1173,6 +1198,33 @@ static int dvb_register(struct cx23885_tsport *port)
 			break;
 		}
 		break;
+
+	case CX23885_BOARD_BST_PS8512:
+	case CX23885_BOARD_DVBSKY_S950:
+		i2c_bus = &dev->i2c_bus[1];	
+		fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
+					&bst_ds3103_config,
+					&i2c_bus->i2c_adap);
+		break;	
+			
+	case CX23885_BOARD_DVBSKY_S952:
+		switch (port->nr) {
+		/* port B */
+		case 1:
+			i2c_bus = &dev->i2c_bus[1];
+			fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
+						&dvbsky_ds3103_config_pri,
+						&i2c_bus->i2c_adap);
+			break;
+		/* port C */
+		case 2:
+			i2c_bus = &dev->i2c_bus[0];
+			fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
+						&dvbsky_ds3103_config_sec,
+						&i2c_bus->i2c_adap);		
+			break;
+		}
+		break;
 	default:
 		printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
 			" isn't supported yet\n",
diff --git a/drivers/media/video/cx23885/cx23885-f300.c b/drivers/media/video/cx23885/cx23885-f300.c
index 93998f2..6be0369 100644
--- a/drivers/media/video/cx23885/cx23885-f300.c
+++ b/drivers/media/video/cx23885/cx23885-f300.c
@@ -175,3 +175,58 @@ int f300_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 
 	return f300_xfer(fe, buf);
 }
+
+/* bst control */
+int bst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct cx23885_tsport *port = fe->dvb->priv;
+	struct cx23885_dev *dev = port->dev;
+	
+	cx23885_gpio_enable(dev, GPIO_1, 1);
+	cx23885_gpio_enable(dev, GPIO_0, 1);
+
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		cx23885_gpio_set(dev, GPIO_1);
+		cx23885_gpio_clear(dev, GPIO_0);
+		break;
+	case SEC_VOLTAGE_18:
+		cx23885_gpio_set(dev, GPIO_1);
+		cx23885_gpio_set(dev, GPIO_0);
+		break;
+	case SEC_VOLTAGE_OFF:
+		cx23885_gpio_clear(dev, GPIO_1);
+		cx23885_gpio_clear(dev, GPIO_0);
+		break;
+	}
+	
+
+	return 0;
+}
+
+int dvbsky_set_voltage_sec(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct cx23885_tsport *port = fe->dvb->priv;
+	struct cx23885_dev *dev = port->dev;
+	
+	cx23885_gpio_enable(dev, GPIO_12, 1);
+	cx23885_gpio_enable(dev, GPIO_13, 1);
+
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		cx23885_gpio_set(dev, GPIO_13);
+		cx23885_gpio_clear(dev, GPIO_12);
+		break;
+	case SEC_VOLTAGE_18:
+		cx23885_gpio_set(dev, GPIO_13);
+		cx23885_gpio_set(dev, GPIO_12);
+		break;
+	case SEC_VOLTAGE_OFF:
+		cx23885_gpio_clear(dev, GPIO_13);
+		cx23885_gpio_clear(dev, GPIO_12);
+		break;
+	}
+	
+
+	return 0;
+}
\ No newline at end of file
diff --git a/drivers/media/video/cx23885/cx23885-f300.h b/drivers/media/video/cx23885/cx23885-f300.h
index e73344c..cd02d02 100644
--- a/drivers/media/video/cx23885/cx23885-f300.h
+++ b/drivers/media/video/cx23885/cx23885-f300.h
@@ -1,2 +1,8 @@
+extern int dvbsky_set_voltage_sec(struct dvb_frontend *fe,
+				fe_sec_voltage_t voltage);
+				
+extern int bst_set_voltage(struct dvb_frontend *fe,
+				fe_sec_voltage_t voltage);
+
 extern int f300_set_voltage(struct dvb_frontend *fe,
 				fe_sec_voltage_t voltage);
diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c
index ce765e3..69c01f3 100644
--- a/drivers/media/video/cx23885/cx23885-input.c
+++ b/drivers/media/video/cx23885/cx23885-input.c
@@ -87,6 +87,9 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
 	case CX23885_BOARD_HAUPPAUGE_HVR1290:
 	case CX23885_BOARD_TEVII_S470:
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+	case CX23885_BOARD_BST_PS8512:
+	case CX23885_BOARD_DVBSKY_S950:
+	case CX23885_BOARD_DVBSKY_S952:
 		/*
 		 * The only boards we handle right now.  However other boards
 		 * using the CX2388x integrated IR controller should be similar
@@ -138,6 +141,9 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev)
 	case CX23885_BOARD_HAUPPAUGE_HVR1850:
 	case CX23885_BOARD_HAUPPAUGE_HVR1290:
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+	case CX23885_BOARD_BST_PS8512:
+	case CX23885_BOARD_DVBSKY_S950:
+	case CX23885_BOARD_DVBSKY_S952:
 		/*
 		 * The IR controller on this board only returns pulse widths.
 		 * Any other mode setting will fail to set up the device.
@@ -279,6 +285,15 @@ int cx23885_input_init(struct cx23885_dev *dev)
 		/* A guess at the remote */
 		rc_map = RC_MAP_TEVII_NEC;
 		break;
+	case CX23885_BOARD_BST_PS8512:
+	case CX23885_BOARD_DVBSKY_S950:
+	case CX23885_BOARD_DVBSKY_S952:
+		/* Integrated CX2388[58] IR controller */
+		driver_type = RC_DRIVER_IR_RAW;
+		allowed_protos = RC_TYPE_ALL;
+		/* A guess at the remote */
+		rc_map = RC_MAP_DVBSKY;
+		break;
 	default:
 		return -ENODEV;
 	}
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
index f020f05..2724148 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -89,6 +89,9 @@
 #define CX23885_BOARD_MPX885                   32
 #define CX23885_BOARD_MYGICA_X8507             33
 #define CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL 34
+#define CX23885_BOARD_BST_PS8512               35
+#define CX23885_BOARD_DVBSKY_S952              36
+#define CX23885_BOARD_DVBSKY_S950              37
 
 #define GPIO_0 0x00000001
 #define GPIO_1 0x00000002
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 5/6] m88ds3103, dvbsky remote control key map.
  2012-01-26 16:56 ` Mauro Carvalho Chehab
                     ` (4 preceding siblings ...)
  2012-04-15 15:53   ` [PATCH 4/6] m88ds3103, dvbsky dvb-s2 cx23885 pcie card nibble.max
@ 2012-04-15 15:53   ` nibble.max
  2012-04-19 18:16     ` Mauro Carvalho Chehab
  2012-04-15 15:53   ` [PATCH 6/6] m88ds3103, dvbsky remote control include header file nibble.max
  6 siblings, 1 reply; 56+ messages in thread
From: nibble.max @ 2012-04-15 15:53 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

dvbsky remote control key map for pci/pcie card.

Signed-off-by: Max nibble <nibble.max@gmail.com>
---
 drivers/media/rc/keymaps/Makefile    |    1 +
 drivers/media/rc/keymaps/rc-dvbsky.c |   78 ++++++++++++++++++++++++++++++++++
 2 files changed, 79 insertions(+)
 create mode 100644 drivers/media/rc/keymaps/rc-dvbsky.c

diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index 49ce266..e6a882b 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
 			rc-dm1105-nec.o \
 			rc-dntv-live-dvb-t.o \
 			rc-dntv-live-dvbt-pro.o \
+			rc-dvbsky.o \
 			rc-em-terratec.o \
 			rc-encore-enltv2.o \
 			rc-encore-enltv.o \
diff --git a/drivers/media/rc/keymaps/rc-dvbsky.c b/drivers/media/rc/keymaps/rc-dvbsky.c
new file mode 100644
index 0000000..2bd9977
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-dvbsky.c
@@ -0,0 +1,78 @@
+/* rc-dvbsky.c - Keytable for Dvbsky Remote Controllers
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ *
+ * Copyright (c) 2010-2011 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+/*
+ * This table contains the complete RC5 code, instead of just the data part
+ */
+
+static struct rc_map_table rc5_dvbsky[] = {
+	{ 0x0000, KEY_0 },
+	{ 0x0001, KEY_1 },
+	{ 0x0002, KEY_2 },
+	{ 0x0003, KEY_3 },
+	{ 0x0004, KEY_4 },
+	{ 0x0005, KEY_5 },
+	{ 0x0006, KEY_6 },
+	{ 0x0007, KEY_7 },
+	{ 0x0008, KEY_8 },
+	{ 0x0009, KEY_9 },	
+	{ 0x000a, KEY_MUTE },
+	{ 0x000d, KEY_OK },
+	{ 0x000b, KEY_STOP },
+	{ 0x000c, KEY_EXIT },	
+	{ 0x000e, KEY_CAMERA }, /*Snap shot*/
+	{ 0x000f, KEY_SUBTITLE }, /*PIP*/
+	{ 0x0010, KEY_VOLUMEUP },
+	{ 0x0011, KEY_VOLUMEDOWN },
+	{ 0x0012, KEY_FAVORITES },
+	{ 0x0013, KEY_LIST }, /*Info*/
+	{ 0x0016, KEY_PAUSE },
+	{ 0x0017, KEY_PLAY },
+	{ 0x001f, KEY_RECORD },
+	{ 0x0020, KEY_CHANNELDOWN },
+	{ 0x0021, KEY_CHANNELUP },
+	{ 0x0025, KEY_POWER2 },
+	{ 0x0026, KEY_REWIND },
+	{ 0x0027, KEY_FASTFORWARD },
+	{ 0x0029, KEY_LAST },
+	{ 0x002b, KEY_MENU },	
+	{ 0x002c, KEY_EPG },
+	{ 0x002d, KEY_ZOOM },	
+};
+
+static struct rc_map_list rc5_dvbsky_map = {
+	.map = {
+		.scan    = rc5_dvbsky,
+		.size    = ARRAY_SIZE(rc5_dvbsky),
+		.rc_type = RC_TYPE_RC5,
+		.name    = RC_MAP_DVBSKY,
+	}
+};
+
+static int __init init_rc_map_rc5_dvbsky(void)
+{
+	return rc_map_register(&rc5_dvbsky_map);
+}
+
+static void __exit exit_rc_map_rc5_dvbsky(void)
+{
+	rc_map_unregister(&rc5_dvbsky_map);
+}
+
+module_init(init_rc_map_rc5_dvbsky)
+module_exit(exit_rc_map_rc5_dvbsky)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 6/6] m88ds3103, dvbsky remote control include header file.
  2012-01-26 16:56 ` Mauro Carvalho Chehab
                     ` (5 preceding siblings ...)
  2012-04-15 15:53   ` [PATCH 5/6] m88ds3103, dvbsky remote control key map nibble.max
@ 2012-04-15 15:53   ` nibble.max
  6 siblings, 0 replies; 56+ messages in thread
From: nibble.max @ 2012-04-15 15:53 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

dvbsky remote control include header file for pci/pcie card.

Signed-off-by: Max nibble <nibble.max@gmail.com>
---
 include/media/rc-map.h |    1 +
 1 file changed, 1 insertion(+)

diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 8db6741..7176dac 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -85,6 +85,7 @@ void rc_map_init(void);
 #define RC_MAP_DM1105_NEC                "rc-dm1105-nec"
 #define RC_MAP_DNTV_LIVE_DVBT_PRO        "rc-dntv-live-dvbt-pro"
 #define RC_MAP_DNTV_LIVE_DVB_T           "rc-dntv-live-dvb-t"
+#define RC_MAP_DVBSKY                    "rc-dvbsky"
 #define RC_MAP_EMPTY                     "rc-empty"
 #define RC_MAP_EM_TERRATEC               "rc-em-terratec"
 #define RC_MAP_ENCORE_ENLTV2             "rc-encore-enltv2"
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-15 15:53   ` [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver nibble.max
@ 2012-04-19 18:06     ` Mauro Carvalho Chehab
  2012-04-20  8:01       ` nibble.max
  2012-04-19 20:08     ` Mauro Carvalho Chehab
  2012-04-20  8:01     ` nibble.max
  2 siblings, 1 reply; 56+ messages in thread
From: Mauro Carvalho Chehab @ 2012-04-19 18:06 UTC (permalink / raw)
  To: nibble.max; +Cc: linux-media


Hi Max,

Em 15-04-2012 12:53, nibble.max escreveu:
> Montage m88ds3103 demodulator and ts2022 tuner driver.
> 
> Signed-off-by: Max nibble <nibble.max@gmail.com>

Please always test any patch you send upstream with ./scripts/checkpatch.pl.

It analyses the code and checks if it is following the Linux Coding Style
(Documentation/CodingStyle).

>From what I've seen, there are several small CodingStyle issues on this patch.

There's also another problem here: this driver is mixing an I2C tuner driver
with the demod one. Please split. If the tuner is simple enough, you an add
it to:
	drivers/media/common/tuners/tuner-simple.c
or at:
	drivers/media/dvb/frontends/dvb-pll.c

But please don't mix tuners with demods. Mixing it causes code duplication and
more time lost when debugging it (as two different version of the same driver
can have different bugs).

I'll analyze it deeper after you fix those two issues.

Thanks,
Mauro


> ---
>  drivers/media/dvb/frontends/Kconfig     |    7 +
>  drivers/media/dvb/frontends/Makefile    |    2 +
>  drivers/media/dvb/frontends/m88ds3103.c | 1851 +++++++++++++++++++++++++++++++
>  drivers/media/dvb/frontends/m88ds3103.h |   53 +
>  4 files changed, 1913 insertions(+)
>  create mode 100644 drivers/media/dvb/frontends/m88ds3103.c
>  create mode 100644 drivers/media/dvb/frontends/m88ds3103.h
> 
> diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
> index e11adb6..d2bb312 100644
> --- a/drivers/media/dvb/frontends/Kconfig
> +++ b/drivers/media/dvb/frontends/Kconfig
> @@ -214,6 +214,13 @@ config DVB_CX24116
>  	help
>  	  A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
>  
> +config DVB_M88DS3103
> +	tristate "Montage DS3103 based"
> +	depends on DVB_CORE && I2C
> +	default m if DVB_FE_CUSTOMISE
> +	help
> +	  A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
> +	  
>  config DVB_SI21XX
>  	tristate "Silicon Labs SI21XX based"
>  	depends on DVB_CORE && I2C
> diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
> index 6ca7557..84ddf41 100644
> --- a/drivers/media/dvb/frontends/Makefile
> +++ b/drivers/media/dvb/frontends/Makefile
> @@ -98,5 +98,7 @@ obj-$(CONFIG_DVB_A8293) += a8293.o
>  obj-$(CONFIG_DVB_TDA10071) += tda10071.o
>  obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
>  obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
> +obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o
>  obj-$(CONFIG_DVB_AF9033) += af9033.o
>  
> +
> diff --git a/drivers/media/dvb/frontends/m88ds3103.c b/drivers/media/dvb/frontends/m88ds3103.c
> new file mode 100644
> index 0000000..a186ba0
> --- /dev/null
> +++ b/drivers/media/dvb/frontends/m88ds3103.c
> @@ -0,0 +1,1851 @@
> +/*
> +    Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner driver
> +
> +    Copyright (C) 2011 Max nibble<nibble.max@gmail.com>
> +    Copyright (C) 2010 Montage Technology<www.montage-tech.com>
> +    Copyright (C) 2009 Konstantin Dimitrov.
> +
> +    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/slab.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/moduleparam.h>
> +#include <linux/init.h>
> +#include <linux/firmware.h>
> +
> +#include "dvb_frontend.h"
> +#include "m88ds3103.h"
> +
> +static int debug;
> +module_param(debug, int, 0644);
> +MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
> +
> +#define dprintk(args...) \
> +	do { \
> +		if (debug) \
> +			printk(KERN_INFO "m88ds3103: " args); \
> +	} while (0)
> +
> +#define FW_DOWN_SIZE 32
> +#define FW_DOWN_LOOP (8192/FW_DOWN_SIZE)
> +#define DS3103_DEFAULT_FIRMWARE "dvb-fe-ds3103.fw"
> +#define DS3000_DEFAULT_FIRMWARE "dvb-fe-ds300x.fw"
> +#define MT_FE_MCLK_KHZ 96000 /* in kHz */
> +#define MT_FE_CRYSTAL_KHZ   27000 /* in kHz */
> +#define FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz 3000
> +#define DS3000_ID	0x3000
> +#define DS3103_ID	0x3103
> +#define TS2020_ID	0x2020
> +#define TS2022_ID	0x2022
> +#define UNKNOW_ID	0x0000
> +
> +/* For M88DS3103 demod dvbs mode.*/
> +static u8 ds3103_dvbs_init_tab[] = {
> +	0x23, 0x07,
> +	0x08, 0x03,
> +	0x0c, 0x02,
> +	0x21, 0x54,
> +	0x25, 0x82,
> +	0x27, 0x31,
> +	0x30, 0x08,
> +	0x31, 0x40,
> +	0x32, 0x32,
> +	0x33, 0x35,
> +	0x35, 0xff,
> +	0x3a, 0x00,
> +	0x37, 0x10,
> +	0x38, 0x10,
> +	0x39, 0x02,
> +	0x42, 0x60,
> +	0x4a, 0x80,
> +	0x4b, 0x04,
> +	0x4d, 0x91,
> +	0x5d, 0xc8,
> +	0x50, 0x36,
> +	0x51, 0x36,
> +	0x52, 0x36,
> +	0x53, 0x36,
> +	0x63, 0x0f,
> +	0x64, 0x30,
> +	0x65, 0x40,
> +	0x68, 0x26,
> +	0x69, 0x4c,
> +	0x70, 0x20,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x40,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x60,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x80,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0xa0,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x1f,
> +	0x76, 0x38,
> +	0x77, 0xa6,
> +	0x78, 0x0c,
> +	0x79, 0x80,
> +	0x7f, 0x14,
> +	0x7c, 0x00,
> +	0xae, 0x82,
> +	0x80, 0x64,
> +	0x81, 0x66,
> +	0x82, 0x44,
> +	0x85, 0x04,
> +	0xcd, 0xf4,
> +	0x90, 0x33,
> +	0xa0, 0x44,
> +	0xc0, 0x08,
> +	0xc3, 0x10,
> +	0xc4, 0x08,
> +	0xc5, 0xf0,
> +	0xc6, 0xff,
> +	0xc7, 0x00,
> +	0xc8, 0x1a,
> +	0xc9, 0x80,
> +	0xe0, 0xf8,
> +	0xe6, 0x8b,
> +	0xd0, 0x40,
> +	0xf8, 0x20,
> +	0xfa, 0x0f,
> +	0x00, 0x00,
> +	0xbd, 0x01,
> +	0xb8, 0x00,
> +};
> +/* For M88DS3103 demod dvbs2 mode.*/
> +static u8 ds3103_dvbs2_init_tab[] = {
> +	0x23, 0x07,
> +	0x08, 0x07,
> +	0x0c, 0x02,
> +	0x21, 0x54,
> +	0x25, 0x82,
> +	0x27, 0x31,
> +	0x30, 0x08,
> +	0x32, 0x32,
> +	0x33, 0x35,
> +	0x35, 0xff,
> +	0x3a, 0x00,
> +	0x37, 0x10,
> +	0x38, 0x10,
> +	0x39, 0x02,
> +	0x42, 0x60,
> +	0x4a, 0x80,
> +	0x4b, 0x04,
> +	0x4d, 0x91,
> +	0x5d, 0xc8,
> +	0x50, 0x36,
> +	0x51, 0x36,
> +	0x52, 0x36,
> +	0x53, 0x36,
> +	0x63, 0x0f,
> +	0x64, 0x10,
> +	0x65, 0x20,
> +	0x68, 0x46,
> +	0x69, 0xcd,
> +	0x70, 0x20,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x40,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x60,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x80,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0xa0,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x1f,
> +	0x76, 0x38,
> +	0x77, 0xa6,
> +	0x78, 0x0c,
> +	0x79, 0x80,
> +	0x7f, 0x14,
> +	0x85, 0x08,
> +	0xcd, 0xf4,
> +	0x90, 0x33,
> +	0x86, 0x00,
> +	0x87, 0x0f,
> +	0x89, 0x00,
> +	0x8b, 0x44,
> +	0x8c, 0x66,
> +	0x9d, 0xc1,
> +	0x8a, 0x10,
> +	0xad, 0x40,
> +	0xa0, 0x44,
> +	0xc0, 0x08,
> +	0xc1, 0x10,
> +	0xc2, 0x08,
> +	0xc3, 0x10,
> +	0xc4, 0x08,
> +	0xc5, 0xf0,
> +	0xc6, 0xff,
> +	0xc7, 0x00,
> +	0xc8, 0x1a,
> +	0xc9, 0x80,
> +	0xca, 0x23,
> +	0xcb, 0x24,
> +	0xcc, 0xf4,
> +	0xce, 0x74,
> +	0x00, 0x00,
> +	0xbd, 0x01,
> +	0xb8, 0x00,
> +};
> +
> +/* For M88DS3000 demod dvbs mode.*/
> +static u8 ds3000_dvbs_init_tab[] = {
> +	0x23, 0x05,
> +	0x08, 0x03,
> +	0x0c, 0x02,
> +	0x21, 0x54,
> +	0x25, 0x82,
> +	0x27, 0x31,
> +	0x30, 0x08,
> +	0x31, 0x40,
> +	0x32, 0x32,
> +	0x33, 0x35,
> +	0x35, 0xff,
> +	0x3a, 0x00,
> +	0x37, 0x10,
> +	0x38, 0x10,
> +	0x39, 0x02,
> +	0x42, 0x60,
> +	0x4a, 0x40,
> +	0x4b, 0x04,
> +	0x4d, 0x91,
> +	0x5d, 0xc8,
> +	0x50, 0x77,
> +	0x51, 0x77,
> +	0x52, 0x36,
> +	0x53, 0x36,
> +	0x56, 0x01,
> +	0x63, 0x47,
> +	0x64, 0x30,
> +	0x65, 0x40,
> +	0x68, 0x26,
> +	0x69, 0x4c,
> +	0x70, 0x20,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x40,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x60,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x80,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0xa0,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x1f,
> +	0x76, 0x00,
> +	0x77, 0xd1,
> +	0x78, 0x0c,
> +	0x79, 0x80,
> +	0x7f, 0x04,
> +	0x7c, 0x00,
> +	0x80, 0x86,
> +	0x81, 0xa6,
> +	0x85, 0x04,
> +	0xcd, 0xf4,
> +	0x90, 0x33,
> +	0xa0, 0x44,
> +	0xc0, 0x18,
> +	0xc3, 0x10,
> +	0xc4, 0x08,
> +	0xc5, 0x80,
> +	0xc6, 0x80,
> +	0xc7, 0x0a,
> +	0xc8, 0x1a,
> +	0xc9, 0x80,
> +	0xfe, 0xb6,
> +	0xe0, 0xf8,
> +	0xe6, 0x8b,
> +	0xd0, 0x40,
> +	0xf8, 0x20,
> +	0xfa, 0x0f,
> +	0xad, 0x20,
> +	0xae, 0x07,
> +	0xb8, 0x00,
> +};
> +
> +/* For M88DS3000 demod dvbs2 mode.*/
> +static u8 ds3000_dvbs2_init_tab[] = {
> +	0x23, 0x0f,
> +	0x08, 0x07,
> +	0x0c, 0x02,
> +	0x21, 0x54,
> +	0x25, 0x82,
> +	0x27, 0x31,
> +	0x30, 0x08,
> +	0x31, 0x32,
> +	0x32, 0x32,
> +	0x33, 0x35,
> +	0x35, 0xff,
> +	0x3a, 0x00,
> +	0x37, 0x10,
> +	0x38, 0x10,
> +	0x39, 0x02,
> +	0x42, 0x60,
> +	0x4a, 0x80,
> +	0x4b, 0x04,
> +	0x4d, 0x91,
> +	0x5d, 0x88,
> +	0x50, 0x36,
> +	0x51, 0x36,
> +	0x52, 0x36,
> +	0x53, 0x36,
> +	0x63, 0x60,
> +	0x64, 0x10,
> +	0x65, 0x10,
> +	0x68, 0x04,
> +	0x69, 0x29,
> +	0x70, 0x20,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x40,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x60,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x80,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0xa0,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x1f,
> +	0xa0, 0x44,
> +	0xc0, 0x08,
> +	0xc1, 0x10,
> +	0xc2, 0x08,
> +	0xc3, 0x10,
> +	0xc4, 0x08,
> +	0xc5, 0xf0,
> +	0xc6, 0xf0,
> +	0xc7, 0x0a,
> +	0xc8, 0x1a,
> +	0xc9, 0x80,
> +	0xca, 0x23,
> +	0xcb, 0x24,
> +	0xce, 0x74,
> +	0x56, 0x01,
> +	0x90, 0x03,
> +	0x76, 0x80,
> +	0x77, 0x42,
> +	0x78, 0x0a,
> +	0x79, 0x80,
> +	0xad, 0x40,
> +	0xae, 0x07,
> +	0x7f, 0xd4,
> +	0x7c, 0x00,
> +	0x80, 0xa8,
> +	0x81, 0xda,
> +	0x7c, 0x01,
> +	0x80, 0xda,
> +	0x81, 0xec,
> +	0x7c, 0x02,
> +	0x80, 0xca,
> +	0x81, 0xeb,
> +	0x7c, 0x03,
> +	0x80, 0xba,
> +	0x81, 0xdb,
> +	0x85, 0x08,
> +	0x86, 0x00,
> +	0x87, 0x02,
> +	0x89, 0x80,
> +	0x8b, 0x44,
> +	0x8c, 0xaa,
> +	0x8a, 0x10,
> +	0xba, 0x00,
> +	0xf5, 0x04,
> +	0xd2, 0x32,
> +	0xb8, 0x00,
> +};
> +
> +struct m88ds3103_state {
> +	struct i2c_adapter *i2c;
> +	const struct m88ds3103_config *config;
> +	
> +	struct dvb_frontend frontend;
> +	
> +	u32 preBer;
> +	u8 skip_fw_load;	
> +	u8 first_lock; /* The first time of signal lock */
> +	u16 demod_id; /* demod chip type */
> +	u16 tuner_id; /* tuner chip type */
> +	fe_delivery_system_t delivery_system;
> +};
> +
> +/*demod register operations.*/
> +static int m88ds3103_writereg(struct m88ds3103_state *state, int reg, int data)
> +{
> +	u8 buf[] = { reg, data };
> +	struct i2c_msg msg = { .addr = state->config->demod_address,
> +		.flags = 0, .buf = buf, .len = 2 };
> +	int err;
> +
> +	if (debug > 1)
> +		printk("m88ds3103: %s: write reg 0x%02x, value 0x%02x\n",
> +			__func__, reg, data);
> +
> +	err = i2c_transfer(state->i2c, &msg, 1);
> +	if (err != 1) {
> +		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x,"
> +			 " value == 0x%02x)\n", __func__, err, reg, data);
> +		return -EREMOTEIO;
> +	}
> +	return 0;
> +}
> +
> +static int m88ds3103_readreg(struct m88ds3103_state *state, u8 reg)
> +{
> +	int ret;
> +	u8 b0[] = { reg };
> +	u8 b1[] = { 0 };
> +	struct i2c_msg msg[] = {
> +		{ .addr = state->config->demod_address, .flags = 0,
> +			.buf = b0, .len = 1 },
> +		{ .addr = state->config->demod_address, .flags = I2C_M_RD,
> +			.buf = b1, .len = 1 }
> +	};
> +	ret = i2c_transfer(state->i2c, msg, 2);
> +
> +	if (ret != 2) {
> +		printk(KERN_ERR "%s: reg=0x%x (error=%d)\n",
> +			__func__, reg, ret);
> +		return ret;
> +	}
> +
> +	if (debug > 1)
> +		printk(KERN_INFO "m88ds3103: read reg 0x%02x, value 0x%02x\n",
> +			reg, b1[0]);
> +
> +	return b1[0];
> +}
> +
> +/*tuner register operations.*/
> +static int m88ds3103_tuner_writereg(struct m88ds3103_state *state, int reg, int data)
> +{
> +	u8 buf[] = { reg, data };
> +	struct i2c_msg msg = { .addr = 0x60,
> +		.flags = 0, .buf = buf, .len = 2 };
> +	int err;
> +
> +	m88ds3103_writereg(state, 0x03, 0x11);
> +	err = i2c_transfer(state->i2c, &msg, 1);
> +	
> +	if (err != 1) {
> +		printk("%s: writereg error(err == %i, reg == 0x%02x,"
> +			 " value == 0x%02x)\n", __func__, err, reg, data);
> +		return -EREMOTEIO;
> +	}
> +
> +	return 0;
> +}
> +
> +static int m88ds3103_tuner_readreg(struct m88ds3103_state *state, u8 reg)
> +{
> +	int ret;
> +	u8 b0[] = { reg };
> +	u8 b1[] = { 0 };
> +	struct i2c_msg msg[] = {
> +		{ .addr = 0x60, .flags = 0,
> +			.buf = b0, .len = 1 },
> +		{ .addr = 0x60, .flags = I2C_M_RD,
> +			.buf = b1, .len = 1 }
> +	};
> +
> +	m88ds3103_writereg(state, 0x03, 0x11);	
> +	ret = i2c_transfer(state->i2c, msg, 2);
> +
> +	if (ret != 2) {
> +		printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);
> +		return ret;
> +	}
> +
> +	return b1[0];
> +}
> +
> +/* Bulk demod I2C write, for firmware download. */
> +static int m88ds3103_writeregN(struct m88ds3103_state *state, int reg,
> +				const u8 *data, u16 len)
> +{
> +	int ret = -EREMOTEIO;
> +	struct i2c_msg msg;
> +	u8 *buf;
> +
> +	buf = kmalloc(len + 1, GFP_KERNEL);
> +	if (buf == NULL) {
> +		printk("Unable to kmalloc\n");
> +		ret = -ENOMEM;
> +		goto error;
> +	}
> +
> +	*(buf) = reg;
> +	memcpy(buf + 1, data, len);
> +
> +	msg.addr = state->config->demod_address;
> +	msg.flags = 0;
> +	msg.buf = buf;
> +	msg.len = len + 1;
> +
> +	if (debug > 1)
> +		printk(KERN_INFO "m88ds3103: %s:  write regN 0x%02x, len = %d\n",
> +			__func__, reg, len);
> +
> +	ret = i2c_transfer(state->i2c, &msg, 1);
> +	if (ret != 1) {
> +		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n",
> +			 __func__, ret, reg);
> +		ret = -EREMOTEIO;
> +	}
> +	
> +error:
> +	kfree(buf);
> +
> +	return ret;
> +}
> +
> +static int m88ds3103_load_firmware(struct dvb_frontend *fe)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	const struct firmware *fw;
> +	int i, ret = 0;
> +
> +	dprintk("%s()\n", __func__);
> +		
> +	if (state->skip_fw_load)
> +		return 0;
> +	/* Load firmware */
> +	/* request the firmware, this will block until someone uploads it */	
> +	if(state->demod_id == DS3000_ID){
> +		printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__,
> +				DS3000_DEFAULT_FIRMWARE);		
> +		ret = request_firmware(&fw, DS3000_DEFAULT_FIRMWARE,
> +					state->i2c->dev.parent);
> +	}else if(state->demod_id == DS3103_ID){
> +		printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__,
> +				DS3103_DEFAULT_FIRMWARE);
> +		ret = request_firmware(&fw, DS3103_DEFAULT_FIRMWARE,
> +					state->i2c->dev.parent);
> +	}
> +	
> +	printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__);
> +	if (ret) {
> +		printk(KERN_ERR "%s: No firmware uploaded (timeout or file not "
> +				"found?)\n", __func__);
> +		return ret;
> +	}
> +
> +	/* Make sure we don't recurse back through here during loading */
> +	state->skip_fw_load = 1;
> +
> +	dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
> +			fw->size,
> +			fw->data[0],
> +			fw->data[1],
> +			fw->data[fw->size - 2],
> +			fw->data[fw->size - 1]);
> +			
> +	/* stop internal mcu. */
> +	m88ds3103_writereg(state, 0xb2, 0x01);
> +	/* split firmware to download.*/
> +	for(i = 0; i < FW_DOWN_LOOP; i++){
> +		ret = m88ds3103_writeregN(state, 0xb0, &(fw->data[FW_DOWN_SIZE*i]), FW_DOWN_SIZE);
> +		if(ret != 1) break;		
> +	}
> +	/* start internal mcu. */
> +	if(ret == 1)
> +		m88ds3103_writereg(state, 0xb2, 0x00);
> +		
> +	release_firmware(fw);
> +
> +	dprintk("%s: Firmware upload %s\n", __func__,
> +			ret == 1 ? "complete" : "failed");
> +
> +	if(ret == 1) ret = 0;
> +	
> +	/* Ensure firmware is always loaded if required */
> +	state->skip_fw_load = 0;
> +
> +	return ret;
> +}
> +
> +
> +static int m88ds3103_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	u8 data;
> +
> +	dprintk("%s(%d)\n", __func__, voltage);
> +
> +	dprintk("m88ds3103:pin_ctrl = (%02x)\n", state->config->pin_ctrl);
> +	
> +	if(state->config->set_voltage)
> +		state->config->set_voltage(fe, voltage);
> +	
> +	data = m88ds3103_readreg(state, 0xa2);
> +	
> +        if(state->config->pin_ctrl & 0x80){ /*If control pin is assigned.*/
> +	        data &= ~0x03; /* bit0 V/H, bit1 off/on */
> +	        if(state->config->pin_ctrl & 0x02)
> +		     data |= 0x02;
> +
> +	        switch (voltage) {
> +	        case SEC_VOLTAGE_18:
> +		     if((state->config->pin_ctrl & 0x01) == 0)
> +			  data |= 0x01;
> +		     break;
> +	        case SEC_VOLTAGE_13:
> +		     if(state->config->pin_ctrl & 0x01)
> +			  data |= 0x01;
> +		     break;
> +	        case SEC_VOLTAGE_OFF:
> +		     if(state->config->pin_ctrl & 0x02)
> +			   data &= ~0x02;			
> +		     else
> +			   data |= 0x02;
> +		     break;
> +	         }
> +        }
> +
> +	m88ds3103_writereg(state, 0xa2, data);
> +
> +	return 0;
> +}
> +
> +static int m88ds3103_read_status(struct dvb_frontend *fe, fe_status_t* status)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	int lock = 0;
> +	
> +	*status = 0;
> +	
> +	switch (state->delivery_system){
> +	case SYS_DVBS:
> +		lock = m88ds3103_readreg(state, 0xd1);
> +		dprintk("%s: SYS_DVBS status=%x.\n", __func__, lock);
> +		
> +		if ((lock & 0x07) == 0x07){
> +			/*if((m88ds3103_readreg(state, 0x0d) & 0x07) == 0x07)*/
> +				*status = FE_HAS_SIGNAL | FE_HAS_CARRIER 
> +					| FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
> +			
> +		}
> +		break;
> +	case SYS_DVBS2:
> +		lock = m88ds3103_readreg(state, 0x0d);
> +		dprintk("%s: SYS_DVBS2 status=%x.\n", __func__, lock);
> +
> +		if ((lock & 0x8f) == 0x8f)
> +			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER 
> +				| FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
> +			
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return 0;
> +}
> +
> +static int m88ds3103_read_ber(struct dvb_frontend *fe, u32* ber)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	u8 tmp1, tmp2, tmp3;
> +	u32 ldpc_frame_cnt, pre_err_packags, code_rate_fac = 0;
> +
> +	dprintk("%s()\n", __func__);
> +
> +	switch (state->delivery_system) {
> +	case SYS_DVBS:
> +		m88ds3103_writereg(state, 0xf9, 0x04);
> +		tmp3 = m88ds3103_readreg(state, 0xf8);
> +		if ((tmp3&0x10) == 0){
> +			tmp1 = m88ds3103_readreg(state, 0xf7);
> +			tmp2 = m88ds3103_readreg(state, 0xf6);
> +			tmp3 |= 0x10;
> +			m88ds3103_writereg(state, 0xf8, tmp3);
> +			state->preBer = (tmp1<<8) | tmp2;
> +		}
> +		break;
> +	case SYS_DVBS2:
> +		tmp1 = m88ds3103_readreg(state, 0x7e) & 0x0f;
> +		switch(tmp1){
> +		case 0:	code_rate_fac = 16008 - 80; break;
> +		case 1:	code_rate_fac = 21408 - 80; break;
> +		case 2:	code_rate_fac = 25728 - 80; break;
> +		case 3:	code_rate_fac = 32208 - 80; break;
> +		case 4:	code_rate_fac = 38688 - 80; break;
> +		case 5:	code_rate_fac = 43040 - 80; break;
> +		case 6:	code_rate_fac = 48408 - 80; break;
> +		case 7:	code_rate_fac = 51648 - 80; break;
> +		case 8:	code_rate_fac = 53840 - 80; break;
> +		case 9:	code_rate_fac = 57472 - 80; break;
> +		case 10: code_rate_fac = 58192 - 80; break;
> +		}
> +		
> +		tmp1 = m88ds3103_readreg(state, 0xd7) & 0xff;
> +		tmp2 = m88ds3103_readreg(state, 0xd6) & 0xff;
> +		tmp3 = m88ds3103_readreg(state, 0xd5) & 0xff;		
> +		ldpc_frame_cnt = (tmp1 << 16) | (tmp2 << 8) | tmp3;
> +
> +		tmp1 = m88ds3103_readreg(state, 0xf8) & 0xff;
> +		tmp2 = m88ds3103_readreg(state, 0xf7) & 0xff;
> +		pre_err_packags = tmp1<<8 | tmp2;
> +		
> +		if (ldpc_frame_cnt > 1000){
> +			m88ds3103_writereg(state, 0xd1, 0x01);
> +			m88ds3103_writereg(state, 0xf9, 0x01);
> +			m88ds3103_writereg(state, 0xf9, 0x00);
> +			m88ds3103_writereg(state, 0xd1, 0x00);
> +			state->preBer = pre_err_packags;
> +		} 				
> +		break;
> +	default:
> +		break;
> +	}
> +	*ber = state->preBer;
> +	
> +	return 0;
> +}
> +
> +static int m88ds3103_read_signal_strength(struct dvb_frontend *fe,
> +						u16 *signal_strength)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	u16 gain;
> +	u8 gain1, gain2, gain3 = 0;
> +
> +	dprintk("%s()\n", __func__);
> +
> +	gain1 = m88ds3103_tuner_readreg(state, 0x3d) & 0x1f;
> +	dprintk("%s: gain1 = 0x%02x \n", __func__, gain1);
> +	
> +	if (gain1 > 15) gain1 = 15;
> +	gain2 = m88ds3103_tuner_readreg(state, 0x21) & 0x1f;
> +	dprintk("%s: gain2 = 0x%02x \n", __func__, gain2);
> +	
> +	if(state->tuner_id == TS2022_ID){
> +		gain3 = (m88ds3103_tuner_readreg(state, 0x66)>>3) & 0x07;
> +		dprintk("%s: gain3 = 0x%02x \n", __func__, gain3);
> +		
> +		if (gain2 > 16) gain2 = 16;
> +		if (gain2 < 2) gain2 = 2;			
> +		if (gain3 > 6) gain3 = 6;
> +	}else{
> +		if (gain2 > 13) gain2 = 13;
> +		gain3 = 0;
> +	}
> +
> +	gain = gain1*23 + gain2*35 + gain3*29;
> +	*signal_strength = 60000 - gain*55;
> +
> +	return 0;
> +}
> +
> +
> +static int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *p_snr)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	u8 val, npow1, npow2, spow1, cnt;
> +	u16 tmp, snr;
> +	u32 npow, spow, snr_total;	
> +	static const u16 mes_log10[] ={
> +		0,	3010,	4771,	6021, 	6990,	7781,	8451,	9031,	9542,	10000,
> +		10414,	10792,	11139,	11461,	11761,	12041,	12304,	12553,	12788,	13010,
> +		13222,	13424,	13617,	13802,	13979,	14150,	14314,	14472,	14624,	14771,
> +		14914,	15052,	15185,	15315,	15441,	15563,	15682,	15798,	15911,	16021,
> +		16128,	16232,	16335,	16435,	16532,	16628,	16721,	16812,	16902,	16990,
> +		17076,	17160,	17243,	17324,	17404,	17482,	17559,	17634,	17709,	17782,
> +		17853,	17924,	17993,	18062,	18129,	18195,	18261,	18325,	18388,	18451,
> +		18513,	18573,	18633,	18692,	18751,	18808,	18865,	18921,	18976,	19031
> +	};
> +	static const u16 mes_loge[] ={
> +		0,	6931,	10986,	13863, 	16094,	17918,	19459,	20794,	21972,	23026,
> +		23979,	24849,	25649,	26391,	27081,	27726,	28332,	28904,	29444,	29957,
> +		30445,	30910,	31355,	31781,	32189,	32581,	32958,	33322,	33673,	34012,
> +		34340,	34657,
> +	};
> +
> +	dprintk("%s()\n", __func__);
> +
> +	snr = 0;
> +	
> +	switch (state->delivery_system){
> +	case SYS_DVBS:
> +		cnt = 10; snr_total = 0;
> +		while(cnt > 0){
> +			val = m88ds3103_readreg(state, 0xff);
> +			snr_total += val;
> +			cnt--;
> +		}
> +		tmp = (u16)(snr_total/80);
> +		if(tmp > 0){
> +			if (tmp > 32) tmp = 32;
> +			snr = (mes_loge[tmp - 1] * 100) / 45;
> +		}else{
> +			snr = 0;
> +		}
> +		break;
> +	case SYS_DVBS2:
> +		cnt  = 10; npow = 0; spow = 0;
> +		while(cnt >0){
> +			npow1 = m88ds3103_readreg(state, 0x8c) & 0xff;
> +			npow2 = m88ds3103_readreg(state, 0x8d) & 0xff;
> +			npow += (((npow1 & 0x3f) + (u16)(npow2 << 6)) >> 2);
> +
> +			spow1 = m88ds3103_readreg(state, 0x8e) & 0xff;
> +			spow += ((spow1 * spow1) >> 1);
> +			cnt--;
> +		}
> +		npow /= 10; spow /= 10;
> +		if(spow == 0){
> +			snr = 0;
> +		}else if(npow == 0){
> +			snr = 19;
> +		}else{
> +			if(spow > npow){
> +				tmp = (u16)(spow / npow);
> +				if (tmp > 80) tmp = 80;
> +				snr = mes_log10[tmp - 1]*3;
> +			}else{
> +				tmp = (u16)(npow / spow);
> +				if (tmp > 80) tmp = 80;
> +				snr = -(mes_log10[tmp - 1] / 1000);
> +			}
> +		}			
> +		break;
> +	default:
> +		break;
> +	}
> +	*p_snr = snr;
> +
> +	return 0;
> +}
> +
> +
> +static int m88ds3103_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	u8 tmp1, tmp2, tmp3, data;
> +
> +	dprintk("%s()\n", __func__);
> +
> +	switch (state->delivery_system) {
> +	case SYS_DVBS:
> +		data = m88ds3103_readreg(state, 0xf8);
> +		data |= 0x40;
> +		m88ds3103_writereg(state, 0xf8, data);		
> +		tmp1 = m88ds3103_readreg(state, 0xf5);
> +		tmp2 = m88ds3103_readreg(state, 0xf4);
> +		*ucblocks = (tmp1 <<8) | tmp2;		
> +		data &= ~0x20;
> +		m88ds3103_writereg(state, 0xf8, data);
> +		data |= 0x20;
> +		m88ds3103_writereg(state, 0xf8, data);
> +		data &= ~0x40;
> +		m88ds3103_writereg(state, 0xf8, data);
> +		break;
> +	case SYS_DVBS2:
> +		tmp1 = m88ds3103_readreg(state, 0xda);
> +		tmp2 = m88ds3103_readreg(state, 0xd9);
> +		tmp3 = m88ds3103_readreg(state, 0xd8);
> +		*ucblocks = (tmp1 <<16)|(tmp2 <<8)|tmp3;
> +		data = m88ds3103_readreg(state, 0xd1);
> +		data |= 0x01;
> +		m88ds3103_writereg(state, 0xd1, data);
> +		data &= ~0x01;
> +		m88ds3103_writereg(state, 0xd1, data);
> +		break;
> +	default:
> +		break;
> +	}
> +	return 0;
> +}
> +
> +static int m88ds3103_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	u8 data_a1, data_a2;
> +
> +	dprintk("%s(%d)\n", __func__, tone);
> +	if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
> +		printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
> +		return -EINVAL;
> +	}
> +
> +	data_a1 = m88ds3103_readreg(state, 0xa1);
> +	data_a2 = m88ds3103_readreg(state, 0xa2);
> +	if(state->demod_id == DS3103_ID)
> +		data_a2 &= 0xdf; /* Normal mode */
> +	switch (tone) {
> +	case SEC_TONE_ON:
> +		dprintk("%s: SEC_TONE_ON\n", __func__);
> +		data_a1 |= 0x04;
> +		data_a1 &= ~0x03;
> +		data_a1 &= ~0x40;
> +		data_a2 &= ~0xc0;
> +		break;
> +	case SEC_TONE_OFF:
> +		dprintk("%s: SEC_TONE_OFF\n", __func__);
> +		data_a2 &= ~0xc0;
> +		data_a2 |= 0x80;
> +		break;
> +	}
> +	m88ds3103_writereg(state, 0xa2, data_a2);
> +	m88ds3103_writereg(state, 0xa1, data_a1);
> +	return 0;
> +}
> +
> +static int m88ds3103_send_diseqc_msg(struct dvb_frontend *fe,
> +				struct dvb_diseqc_master_cmd *d)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	int i, ret = 0;
> +	u8 tmp, time_out;
> +
> +	/* Dump DiSEqC message */
> +	if (debug) {
> +		printk(KERN_INFO "m88ds3103: %s(", __func__);
> +		for (i = 0 ; i < d->msg_len ;) {
> +			printk(KERN_INFO "0x%02x", d->msg[i]);
> +			if (++i < d->msg_len)
> +				printk(KERN_INFO ", ");
> +		}
> +	}
> +
> +	tmp = m88ds3103_readreg(state, 0xa2);
> +	tmp &= ~0xc0;
> +	if(state->demod_id == DS3103_ID)
> +		tmp &= ~0x20;
> +	m88ds3103_writereg(state, 0xa2, tmp);
> +	
> +	for (i = 0; i < d->msg_len; i ++)
> +		m88ds3103_writereg(state, (0xa3+i), d->msg[i]);
> +
> +	tmp = m88ds3103_readreg(state, 0xa1);	
> +	tmp &= ~0x38;
> +	tmp &= ~0x40;
> +	tmp |= ((d->msg_len-1) << 3) | 0x07;
> +	tmp &= ~0x80;
> +	m88ds3103_writereg(state, 0xa1, tmp);
> +	/*	1.5 * 9 * 8	= 108ms	*/
> +	time_out = 150;
> +	while (time_out > 0){
> +		msleep(10);
> +		time_out -= 10;
> +		tmp = m88ds3103_readreg(state, 0xa1);		
> +		if ((tmp & 0x40) == 0)
> +			break;
> +	}
> +	if (time_out == 0){
> +		tmp = m88ds3103_readreg(state, 0xa1);
> +		tmp &= ~0x80;
> +		tmp |= 0x40;
> +		m88ds3103_writereg(state, 0xa1, tmp);
> +		ret = 1;
> +	}
> +	tmp = m88ds3103_readreg(state, 0xa2);
> +	tmp &= ~0xc0;
> +	tmp |= 0x80;
> +	m88ds3103_writereg(state, 0xa2, tmp);	
> +	return ret;
> +}
> +
> +
> +static int m88ds3103_diseqc_send_burst(struct dvb_frontend *fe,
> +					fe_sec_mini_cmd_t burst)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	u8	val, time_out;
> +	
> +	dprintk("%s()\n", __func__);
> +
> +	val = m88ds3103_readreg(state, 0xa2);
> +	val &= ~0xc0;
> +	if(state->demod_id == DS3103_ID)
> +		val &= 0xdf; /* Normal mode */
> +	m88ds3103_writereg(state, 0xa2, val);
> +	/* DiSEqC burst */
> +	if (burst == SEC_MINI_B)
> +		m88ds3103_writereg(state, 0xa1, 0x01);
> +	else
> +		m88ds3103_writereg(state, 0xa1, 0x02);
> +
> +	msleep(13);
> +
> +	time_out = 5;
> +	do{
> +		val = m88ds3103_readreg(state, 0xa1);
> +		if ((val & 0x40) == 0)
> +			break;
> +		msleep(1);
> +		time_out --;
> +	} while (time_out > 0);
> +
> +	val = m88ds3103_readreg(state, 0xa2);
> +	val &= ~0xc0;
> +	val |= 0x80;
> +	m88ds3103_writereg(state, 0xa2, val);
> +	
> +	return 0;
> +}
> +
> +static void m88ds3103_release(struct dvb_frontend *fe)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +
> +	dprintk("%s\n", __func__);
> +	kfree(state);
> +}
> +
> +static int m88ds3103_check_id(struct m88ds3103_state *state)
> +{
> +	int val_00, val_01;
> +	
> +	/*check demod id*/
> +	val_01 = m88ds3103_readreg(state, 0x01);
> +	printk(KERN_INFO "DS3000 chip version: %x attached.\n", val_01);
> +			
> +	if(val_01 == 0xD0)
> +		state->demod_id = DS3103_ID;
> +	else if(val_01 == 0xC0)
> +		state->demod_id = DS3000_ID;
> +	else
> +		state->demod_id = UNKNOW_ID;
> +		
> +	/*check tuner id*/
> +	val_00 = m88ds3103_tuner_readreg(state, 0x00);
> +	printk(KERN_INFO "TS202x chip version[1]: %x attached.\n", val_00);
> +	val_00 &= 0x03;
> +	if(val_00 == 0)
> +	{
> +		m88ds3103_tuner_writereg(state, 0x00, 0x01);
> +		msleep(3);		
> +	}
> +	m88ds3103_tuner_writereg(state, 0x00, 0x03);
> +	msleep(5);
> +	
> +	val_00 = m88ds3103_tuner_readreg(state, 0x00);
> +	printk(KERN_INFO "TS202x chip version[2]: %x attached.\n", val_00);
> +	val_00 &= 0xff;
> +	if((val_00 == 0x01) || (val_00 == 0x41) || (val_00 == 0x81))
> +		state->tuner_id = TS2020_ID;
> +	else if(((val_00 & 0xc0)== 0xc0) || (val_00 == 0x83))
> +		state->tuner_id = TS2022_ID;
> +	else
> +		state->tuner_id = UNKNOW_ID;
> +			
> +	return state->demod_id;	
> +}
> +
> +static struct dvb_frontend_ops m88ds3103_ops;
> +static int m88ds3103_initilaze(struct dvb_frontend *fe);
> +
> +struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *config,
> +				    struct i2c_adapter *i2c)
> +{
> +	struct m88ds3103_state *state = NULL;
> +
> +	dprintk("%s\n", __func__);
> +
> +	/* allocate memory for the internal state */
> +	state = kzalloc(sizeof(struct m88ds3103_state), GFP_KERNEL);
> +	if (state == NULL) {
> +		printk(KERN_ERR "Unable to kmalloc\n");
> +		goto error2;
> +	}
> +
> +	state->config = config;
> +	state->i2c = i2c;
> +	state->preBer = 0xffff;
> +	state->delivery_system = SYS_DVBS; /*Default to DVB-S.*/
> +	
> +	/* check demod id */
> +	if(m88ds3103_check_id(state) == UNKNOW_ID){
> +		printk(KERN_ERR "Unable to find Montage chip\n");
> +		goto error3;
> +	}
> +
> +	memcpy(&state->frontend.ops, &m88ds3103_ops,
> +			sizeof(struct dvb_frontend_ops));
> +	state->frontend.demodulator_priv = state;
> +	
> +	m88ds3103_initilaze(&state->frontend);
> +	
> +	return &state->frontend;
> +
> +error3:
> +	kfree(state);
> +error2:
> +	return NULL;
> +}
> +EXPORT_SYMBOL(m88ds3103_attach);
> +
> +static int m88ds3103_set_carrier_offset(struct dvb_frontend *fe,
> +					s32 carrier_offset_khz)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	s32 tmp;
> +
> +	tmp = carrier_offset_khz;
> +	tmp *= 65536;
> +	
> +	tmp = (2*tmp + MT_FE_MCLK_KHZ) / (2*MT_FE_MCLK_KHZ);
> +
> +	if (tmp < 0)
> +		tmp += 65536;
> +
> +	m88ds3103_writereg(state, 0x5f, tmp >> 8);
> +	m88ds3103_writereg(state, 0x5e, tmp & 0xff);
> +
> +	return 0;
> +}
> +
> +static int m88ds3103_set_symrate(struct dvb_frontend *fe)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
> +	u16 value;
> +	
> +	value = (((c->symbol_rate / 1000) << 15) + (MT_FE_MCLK_KHZ / 4)) / (MT_FE_MCLK_KHZ / 2);
> +	m88ds3103_writereg(state, 0x61, value & 0x00ff);
> +	m88ds3103_writereg(state, 0x62, (value & 0xff00) >> 8);
> +
> +	return 0;
> +}
> +
> +static int m88ds3103_set_CCI(struct dvb_frontend *fe)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	u8 tmp;
> +
> +	tmp = m88ds3103_readreg(state, 0x56);
> +	tmp &= ~0x01;
> +	m88ds3103_writereg(state, 0x56, tmp);
> +
> +	tmp = m88ds3103_readreg(state, 0x76);
> +	tmp &= ~0x80;
> +	m88ds3103_writereg(state, 0x76, tmp);
> +
> +	return 0;
> +}
> +
> +static int m88ds3103_init_reg(struct m88ds3103_state *state, const u8 *p_reg_tab, u32 size)
> +{
> +	u32 i;
> +	
> +	for(i = 0; i < size; i+=2)
> +		m88ds3103_writereg(state, p_reg_tab[i], p_reg_tab[i+1]);
> +		
> +	return 0;
> +}
> +
> +static int m88ds3103_demod_connect(struct dvb_frontend *fe, s32 carrier_offset_khz) 
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
> +	u16 value;
> +	u8 val1,val2,data;
> +	
> +	dprintk("connect delivery system = %d\n", state->delivery_system);
> +	
> +	/* ds3000 global reset */
> +	m88ds3103_writereg(state, 0x07, 0x80);
> +	m88ds3103_writereg(state, 0x07, 0x00);
> +	/* ds3000 build-in uC reset */
> +	m88ds3103_writereg(state, 0xb2, 0x01);
> +	/* ds3000 software reset */
> +	m88ds3103_writereg(state, 0x00, 0x01);
> +
> +	switch (state->delivery_system) {
> +	case SYS_DVBS:
> +		/* initialise the demod in DVB-S mode */
> +		if(state->demod_id == DS3000_ID){
> +			m88ds3103_init_reg(state, ds3000_dvbs_init_tab, sizeof(ds3000_dvbs_init_tab));
> +			
> +			value = m88ds3103_readreg(state, 0xfe);
> +			value &= 0xc0;
> +			value |= 0x1b;
> +			m88ds3103_writereg(state, 0xfe, value);
> +			
> +			if(state->config->ci_mode)
> +				val1 = 0x80;
> +			else if(state->config->ts_mode)
> +				val1 = 0x60;
> +			else
> +				val1 = 0x20;
> +			m88ds3103_writereg(state, 0xfd, val1);
> +			
> +		}else if(state->demod_id == DS3103_ID){
> +			m88ds3103_init_reg(state, ds3103_dvbs_init_tab, sizeof(ds3103_dvbs_init_tab));
> +			
> +			/* set ts clock */
> +			if(state->config->ts_mode == 0)	{
> +				val1 = 3; val2 = 3;
> +			}else{
> +				val1 = 0; val2 = 0;
> +			}
> +			val1 -= 1; val2 -= 1;
> +			val1 &= 0x3f; val2 &= 0x3f;
> +			data = m88ds3103_readreg(state, 0xfe);
> +			data &= 0xf0;
> +			data |= (val2 >> 2) & 0x0f;
> +			m88ds3103_writereg(state, 0xfe, data);
> +			data = (val2 & 0x03) << 6;
> +			data |= val1;
> +			m88ds3103_writereg(state, 0xea, data);
> +			
> +			m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d));
> +			m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30));
> +			
> +			/* set master clock */
> +			val1 = m88ds3103_readreg(state, 0x22);
> +			val2 = m88ds3103_readreg(state, 0x24);
> +			
> +			val1 &= 0x3f;
> +			val2 &= 0x3f;
> +			val1 |= 0x80;
> +			val2 |= 0x40;
> +
> +			m88ds3103_writereg(state, 0x22, val1);
> +			m88ds3103_writereg(state, 0x24, val2);	
> +			
> +			if(state->config->ci_mode)
> +				val1 = 0x03;
> +			else if(state->config->ts_mode)
> +				val1 = 0x06;
> +			else
> +				val1 = 0x42;
> +			m88ds3103_writereg(state, 0xfd, val1);		
> +		}
> +		break;
> +	case SYS_DVBS2:
> +		/* initialise the demod in DVB-S2 mode */
> +		if(state->demod_id == DS3000_ID){
> +			m88ds3103_init_reg(state, ds3000_dvbs2_init_tab, sizeof(ds3000_dvbs2_init_tab));
> +		
> +			if (c->symbol_rate >= 30000000)
> +				m88ds3103_writereg(state, 0xfe, 0x54);
> +			else
> +				m88ds3103_writereg(state, 0xfe, 0x98);
> +								
> +		}else if(state->demod_id == DS3103_ID){
> +			m88ds3103_init_reg(state, ds3103_dvbs2_init_tab, sizeof(ds3103_dvbs2_init_tab));
> +
> +			/* set ts clock */
> +			if(state->config->ts_mode == 0){
> +				val1 = 5; val2 = 4;
> +			}else{
> +				val1 = 0; val2 = 0;
> +			}
> +			val1 -= 1; val2 -= 1;
> +			val1 &= 0x3f; val2 &= 0x3f;
> +			data = m88ds3103_readreg(state, 0xfe);
> +			data &= 0xf0;
> +			data |= (val2 >> 2) & 0x0f;
> +			m88ds3103_writereg(state, 0xfe, data);
> +			data = (val2 & 0x03) << 6;
> +			data |= val1;
> +			m88ds3103_writereg(state, 0xea, data);
> +			
> +			m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d));
> +			m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30));
> +			
> +			/* set master clock */
> +			val1 = m88ds3103_readreg(state, 0x22);
> +			val2 = m88ds3103_readreg(state, 0x24);
> +			
> +			val1 &= 0x3f;
> +			val2 &= 0x3f;
> +			if(state->config->ts_mode == 1){
> +				val1 |= 0x80;
> +				val2 |= 0x40;
> +			}else{
> +				if (c->symbol_rate >= 28000000){
> +					val1 |= 0xc0;
> +				}else if (c->symbol_rate >= 18000000){
> +					val2 |= 0x40;
> +				}else{
> +					val1 |= 0x80;
> +					val2 |= 0x40;
> +				}				
> +			}
> +			m88ds3103_writereg(state, 0x22, val1);
> +			m88ds3103_writereg(state, 0x24, val2);					
> +		}
> +		
> +		if(state->config->ci_mode)
> +			val1 = 0x03;
> +		else if(state->config->ts_mode)
> +			val1 = 0x06;
> +		else
> +			val1 = 0x42;
> +		m88ds3103_writereg(state, 0xfd, val1);
> +		
> +		break;
> +	default:
> +		return 1;
> +	}
> +	/* disable 27MHz clock output */
> +	m88ds3103_writereg(state, 0x29, 0x80);
> +	/* enable ac coupling */
> +	m88ds3103_writereg(state, 0x25, 0x8a);
> +
> +	if ((c->symbol_rate / 1000) <= 3000){
> +		m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 32 * 100 / 64 = 400*/
> +		m88ds3103_writereg(state, 0xc8, 0x20);
> +		m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/
> +		m88ds3103_writereg(state, 0xc7, 0x00);
> +	}else if((c->symbol_rate / 1000) <= 10000){
> +		m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 16 * 100 / 64 = 200*/
> +		m88ds3103_writereg(state, 0xc8, 0x10);
> +		m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/
> +		m88ds3103_writereg(state, 0xc7, 0x00);
> +	}else{
> +		m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 6 * 100 / 64 = 75*/
> +		m88ds3103_writereg(state, 0xc8, 0x06);
> +		m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/
> +		m88ds3103_writereg(state, 0xc7, 0x00);
> +	}
> +
> +	m88ds3103_set_symrate(fe);
> +	
> +	m88ds3103_set_CCI(fe);
> +
> +	m88ds3103_set_carrier_offset(fe, carrier_offset_khz);
> +		
> +	/* ds3000 out of software reset */
> +	m88ds3103_writereg(state, 0x00, 0x00);
> +	/* start ds3000 build-in uC */
> +	m88ds3103_writereg(state, 0xb2, 0x00);	
> +	
> +	return 0;
> +}
> +
> +static int m88ds3103_set_frontend(struct dvb_frontend *fe)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
> +
> +	int i;
> +	fe_status_t status;
> +	u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf, div4, capCode, changePLL;
> +	s32 offset_khz, lpf_offset_KHz;
> +	u16 value, ndiv, lpf_coeff;
> +	u32 f3db, gdiv28, realFreq;
> +	u8 RFgain;
> +
> +	dprintk("%s() ", __func__);
> +	dprintk("c frequency = %d\n", c->frequency);
> +	dprintk("symbol rate = %d\n", c->symbol_rate);
> +	dprintk("delivery system = %d\n", c->delivery_system);
> +	
> +	realFreq = c->frequency;
> +	lpf_offset_KHz = 0;
> +	if(c->symbol_rate < 5000000){
> +		lpf_offset_KHz = FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz;
> +		realFreq += FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz;
> +	}
> +	
> +	if (state->config->set_ts_params)
> +		state->config->set_ts_params(fe, 0);
> +
> +	div4 = 0;
> +	RFgain = 0;
> +	if(state->tuner_id == TS2022_ID){
> +		m88ds3103_tuner_writereg(state, 0x10, 0x0a);
> +		m88ds3103_tuner_writereg(state, 0x11, 0x40);
> +		if (realFreq < 1103000) {
> +			m88ds3103_tuner_writereg(state, 0x10, 0x1b);
> +			div4 = 1;
> +			ndiv = (realFreq * (6 + 8) * 4)/MT_FE_CRYSTAL_KHZ;				
> +		}else {
> +			ndiv = (realFreq * (6 + 8) * 2)/MT_FE_CRYSTAL_KHZ;
> +		}
> +		ndiv = ndiv + ndiv%2;
> +		if(ndiv < 4095)
> +			ndiv = ndiv - 1024;
> +		else if (ndiv < 6143)
> +			ndiv = ndiv + 1024;
> +		else
> +			ndiv = ndiv + 3072;	
> +		
> +		m88ds3103_tuner_writereg(state, 0x01, (ndiv & 0x3f00) >> 8);											
> +	}else{
> +		m88ds3103_tuner_writereg(state, 0x10, 0x00);			
> +		if (realFreq < 1146000){
> +			m88ds3103_tuner_writereg(state, 0x10, 0x11);
> +			div4 = 1;
> +			ndiv = (realFreq * (6 + 8) * 4) / MT_FE_CRYSTAL_KHZ;
> +		}else{
> +			m88ds3103_tuner_writereg(state, 0x10, 0x01);
> +			ndiv = (realFreq * (6 + 8) * 2) / MT_FE_CRYSTAL_KHZ;
> +		}
> +		ndiv = ndiv + ndiv%2;
> +		ndiv = ndiv - 1024;
> +		m88ds3103_tuner_writereg(state, 0x01, (ndiv>>8)&0x0f);
> +	}
> +	/* set pll */
> +	m88ds3103_tuner_writereg(state, 0x02, ndiv & 0x00ff);
> +	m88ds3103_tuner_writereg(state, 0x03, 0x06);
> +	m88ds3103_tuner_writereg(state, 0x51, 0x0f);
> +	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +	m88ds3103_tuner_writereg(state, 0x50, 0x10);
> +	m88ds3103_tuner_writereg(state, 0x50, 0x00);	
> +
> +	if(state->tuner_id == TS2022_ID){
> +		if(( realFreq >= 1650000 ) && (realFreq <= 1850000)){
> +			msleep(5);
> +			value = m88ds3103_tuner_readreg(state, 0x14);
> +			value &= 0x7f;
> +			if(value < 64){
> +				m88ds3103_tuner_writereg(state, 0x10, 0x82);
> +				m88ds3103_tuner_writereg(state, 0x11, 0x6f);
> +
> +				m88ds3103_tuner_writereg(state, 0x51, 0x0f);
> +				m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +				m88ds3103_tuner_writereg(state, 0x50, 0x10);
> +				m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +			}
> +		}
> +		msleep(5);
> +		value = m88ds3103_tuner_readreg(state, 0x14);
> +		value &= 0x1f;
> +
> +		if(value > 19){
> +			value = m88ds3103_tuner_readreg(state, 0x10);
> +			value &= 0x1d;
> +			m88ds3103_tuner_writereg(state, 0x10, value);
> +		}				
> +	}else{
> +		msleep(5);
> +		value = m88ds3103_tuner_readreg(state, 0x66);
> +		changePLL = (((value & 0x80) >> 7) != div4);
> +
> +		if(changePLL){
> +			m88ds3103_tuner_writereg(state, 0x10, 0x11);
> +			div4 = 1;
> +			ndiv = (realFreq * (6 + 8) * 4)/MT_FE_CRYSTAL_KHZ;
> +			ndiv = ndiv + ndiv%2;
> +			ndiv = ndiv - 1024;
> +					
> +			m88ds3103_tuner_writereg(state, 0x01, (ndiv>>8) & 0x0f);
> +			m88ds3103_tuner_writereg(state, 0x02, ndiv & 0xff);
> +			
> +			m88ds3103_tuner_writereg(state, 0x51, 0x0f);
> +			m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +			m88ds3103_tuner_writereg(state, 0x50, 0x10);
> +			m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +		}		
> +	}
> +	/*set the RF gain*/
> +	if(state->tuner_id == TS2020_ID)
> +		m88ds3103_tuner_writereg(state, 0x60, 0x79);
> +			
> +	m88ds3103_tuner_writereg(state, 0x51, 0x17);
> +	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +	m88ds3103_tuner_writereg(state, 0x50, 0x08);
> +	m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +	msleep(5);
> +
> +	if(state->tuner_id == TS2020_ID){
> +		RFgain = m88ds3103_tuner_readreg(state, 0x3d);
> +		RFgain &= 0x0f;
> +		if(RFgain < 15){
> +			if(RFgain < 4) 
> +				RFgain = 0;
> +			else
> +				RFgain = RFgain -3;
> +			value = ((RFgain << 3) | 0x01) & 0x79;
> +			m88ds3103_tuner_writereg(state, 0x60, value);
> +			m88ds3103_tuner_writereg(state, 0x51, 0x17);
> +			m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +			m88ds3103_tuner_writereg(state, 0x50, 0x08);
> +			m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +		}
> +	}
> +	
> +	/* set the LPF */
> +	if(state->tuner_id == TS2022_ID){
> +		m88ds3103_tuner_writereg(state, 0x25, 0x00);
> +		m88ds3103_tuner_writereg(state, 0x27, 0x70);
> +		m88ds3103_tuner_writereg(state, 0x41, 0x09);
> +		m88ds3103_tuner_writereg(state, 0x08, 0x0b);
> +	}
> +
> +	f3db = ((c->symbol_rate / 1000) *135) / 200 + 2000;
> +	f3db += lpf_offset_KHz;
> +	if (f3db < 7000)
> +		f3db = 7000;
> +	if (f3db > 40000)
> +		f3db = 40000;
> +			
> +	gdiv28 = (MT_FE_CRYSTAL_KHZ / 1000 * 1694 + 500) / 1000;
> +	m88ds3103_tuner_writereg(state, 0x04, gdiv28 & 0xff);
> +	m88ds3103_tuner_writereg(state, 0x51, 0x1b);
> +	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +	m88ds3103_tuner_writereg(state, 0x50, 0x04);
> +	m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +	msleep(5);
> +
> +	value = m88ds3103_tuner_readreg(state, 0x26);
> +	capCode = value & 0x3f;
> +	if(state->tuner_id == TS2022_ID){
> +		m88ds3103_tuner_writereg(state, 0x41, 0x0d);
> +
> +		m88ds3103_tuner_writereg(state, 0x51, 0x1b);
> +		m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +		m88ds3103_tuner_writereg(state, 0x50, 0x04);
> +		m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +
> +		msleep(2);
> +
> +		value = m88ds3103_tuner_readreg(state, 0x26);
> +		value &= 0x3f;
> +		value = (capCode + value) / 2;		
> +	}
> +	else
> +		value = capCode;
> +		
> +	gdiv28 = gdiv28 * 207 / (value * 2 + 151);	
> +	mlpf_max = gdiv28 * 135 / 100;
> +	mlpf_min = gdiv28 * 78 / 100;
> +	if (mlpf_max > 63)
> +		mlpf_max = 63;
> +
> +	if(state->tuner_id == TS2022_ID)
> +		lpf_coeff = 3200;
> +	else
> +		lpf_coeff = 2766;
> +		
> +	nlpf = (f3db * gdiv28 * 2 / lpf_coeff / (MT_FE_CRYSTAL_KHZ / 1000)  + 1) / 2 ;	
> +	if (nlpf > 23) nlpf = 23;
> +	if (nlpf < 1) nlpf = 1;
> +
> +	lpf_mxdiv = (nlpf * (MT_FE_CRYSTAL_KHZ / 1000) * lpf_coeff * 2 / f3db + 1) / 2;
> +
> +	if (lpf_mxdiv < mlpf_min){
> +		nlpf++;
> +		lpf_mxdiv = (nlpf * (MT_FE_CRYSTAL_KHZ / 1000) * lpf_coeff * 2  / f3db + 1) / 2;
> +	}
> +
> +	if (lpf_mxdiv > mlpf_max)
> +		lpf_mxdiv = mlpf_max;
> +
> +	m88ds3103_tuner_writereg(state, 0x04, lpf_mxdiv);
> +	m88ds3103_tuner_writereg(state, 0x06, nlpf);
> +	m88ds3103_tuner_writereg(state, 0x51, 0x1b);
> +	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +	m88ds3103_tuner_writereg(state, 0x50, 0x04);
> +	m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +	msleep(5);
> +	
> +	if(state->tuner_id == TS2022_ID){
> +		msleep(2);
> +		value = m88ds3103_tuner_readreg(state, 0x26);
> +		capCode = value & 0x3f;
> +
> +		m88ds3103_tuner_writereg(state, 0x41, 0x09);
> +
> +		m88ds3103_tuner_writereg(state, 0x51, 0x1b);
> +		m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +		m88ds3103_tuner_writereg(state, 0x50, 0x04);
> +		m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +
> +		msleep(2);
> +		value = m88ds3103_tuner_readreg(state, 0x26);
> +		value &= 0x3f;
> +		value = (capCode + value) / 2;
> +
> +		value = value | 0x80;
> +		m88ds3103_tuner_writereg(state, 0x25, value);
> +		m88ds3103_tuner_writereg(state, 0x27, 0x30);
> +
> +		m88ds3103_tuner_writereg(state, 0x08, 0x09);		
> +	}
> +
> +	/* Set the BB gain */
> +	m88ds3103_tuner_writereg(state, 0x51, 0x1e);
> +	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +	m88ds3103_tuner_writereg(state, 0x50, 0x01);
> +	m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +	if(state->tuner_id == TS2020_ID){
> +		if(RFgain == 15){
> +			msleep(40);
> +			value = m88ds3103_tuner_readreg(state, 0x21);
> +			value &= 0x0f;
> +			if(value < 3){
> +				m88ds3103_tuner_writereg(state, 0x60, 0x61);
> +				m88ds3103_tuner_writereg(state, 0x51, 0x17);
> +				m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +				m88ds3103_tuner_writereg(state, 0x50, 0x08);
> +				m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +			}			
> +		}
> +	}
> +	msleep(60);
> +	
> +	offset_khz = (ndiv - ndiv % 2 + 1024) * MT_FE_CRYSTAL_KHZ
> +		/ (6 + 8) / (div4 + 1) / 2 - realFreq;
> +
> +	m88ds3103_demod_connect(fe, offset_khz+lpf_offset_KHz);
> +
> +	for (i = 0; i < 30 ; i++) {
> +		m88ds3103_read_status(fe, &status);
> +		if (status & FE_HAS_LOCK){
> +			break;
> +                }
> +		msleep(20);
> +	}
> +	
> +	if((status & FE_HAS_LOCK) == 0){
> +		state->delivery_system = (state->delivery_system == SYS_DVBS) ? SYS_DVBS2 : SYS_DVBS;
> +		m88ds3103_demod_connect(fe, offset_khz);
> +	
> +		for (i = 0; i < 30 ; i++) {
> +			m88ds3103_read_status(fe, &status);
> +			if (status & FE_HAS_LOCK){
> +				break;
> +                	}
> +			msleep(20);
> +		}
> +	}
> +	
> +	if (status & FE_HAS_LOCK){
> +		if(state->config->start_ctrl){
> +			if(state->first_lock == 0){
> +				state->config->start_ctrl(fe);
> +				state->first_lock = 1;	
> +			}
> +		}		
> +	}
> +		
> +	return 0;
> +}
> +
> +static int m88ds3103_tune(struct dvb_frontend *fe,
> +			bool re_tune,
> +			unsigned int mode_flags,
> +			unsigned int *delay,
> +			fe_status_t *status)
> +{	
> +	*delay = HZ / 5;
> +	
> +	dprintk("%s() ", __func__);
> +	dprintk("re_tune = %d\n", re_tune);
> +	
> +	if (re_tune) {
> +		int ret = m88ds3103_set_frontend(fe);
> +		if (ret)
> +			return ret;
> +	}
> +	
> +	return m88ds3103_read_status(fe, status);
> +}
> +
> +static enum dvbfe_algo m88ds3103_get_algo(struct dvb_frontend *fe)
> +{
> +	return DVBFE_ALGO_HW;
> +}
> + 
> + /*
> + * Power config will reset and load initial firmware if required
> + */
> +static int m88ds3103_initilaze(struct dvb_frontend *fe)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	int ret;
> +
> +	dprintk("%s()\n", __func__);
> +	/* hard reset */
> +	m88ds3103_writereg(state, 0x07, 0x80);
> +	m88ds3103_writereg(state, 0x07, 0x00);
> +	msleep(1);
> +	
> +	m88ds3103_writereg(state, 0x08, 0x01 | m88ds3103_readreg(state, 0x08));
> +	msleep(1);
> +
> +	if(state->tuner_id == TS2020_ID){
> +		/* TS2020 init */
> +		m88ds3103_tuner_writereg(state, 0x42, 0x73);
> +		msleep(2);
> +		m88ds3103_tuner_writereg(state, 0x05, 0x01);
> +		m88ds3103_tuner_writereg(state, 0x62, 0xb5);
> +		m88ds3103_tuner_writereg(state, 0x07, 0x02);
> +		m88ds3103_tuner_writereg(state, 0x08, 0x01);
> +	}
> +	else if(state->tuner_id == TS2022_ID){
> +		/* TS2022 init */
> +		m88ds3103_tuner_writereg(state, 0x62, 0x6c);
> +		msleep(2);
> +		m88ds3103_tuner_writereg(state, 0x42, 0x6c);
> +		msleep(2);
> +		m88ds3103_tuner_writereg(state, 0x7d, 0x9d);
> +		m88ds3103_tuner_writereg(state, 0x7c, 0x9a);
> +		m88ds3103_tuner_writereg(state, 0x7a, 0x76);
> +
> +		m88ds3103_tuner_writereg(state, 0x3b, 0x01);
> +		m88ds3103_tuner_writereg(state, 0x63, 0x88);
> +
> +		m88ds3103_tuner_writereg(state, 0x61, 0x85);
> +		m88ds3103_tuner_writereg(state, 0x22, 0x30);
> +		m88ds3103_tuner_writereg(state, 0x30, 0x40);
> +		m88ds3103_tuner_writereg(state, 0x20, 0x23);
> +		m88ds3103_tuner_writereg(state, 0x24, 0x02);
> +		m88ds3103_tuner_writereg(state, 0x12, 0xa0);	
> +	}
> +		
> +	if(state->demod_id == DS3103_ID){
> +		m88ds3103_writereg(state, 0x07, 0xe0);
> +		m88ds3103_writereg(state, 0x07, 0x00);
> +		msleep(1);		
> +	}
> +	m88ds3103_writereg(state, 0xb2, 0x01);
> +	
> +	/* Load the firmware if required */
> +	ret = m88ds3103_load_firmware(fe);
> +	if (ret != 0){
> +		printk(KERN_ERR "%s: Unable initialize firmware\n", __func__);
> +		return ret;
> +	}
> +	if(state->demod_id == DS3103_ID){
> +		m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d));
> +		m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30));		
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * Initialise or wake up device
> + */
> +static int m88ds3103_initfe(struct dvb_frontend *fe)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	u8 val;
> +
> +	dprintk("%s()\n", __func__);
> +
> +	/* 1st step to wake up demod */
> +	m88ds3103_writereg(state, 0x08, 0x01 | m88ds3103_readreg(state, 0x08));
> +	m88ds3103_writereg(state, 0x04, 0xfe & m88ds3103_readreg(state, 0x04));
> +	m88ds3103_writereg(state, 0x23, 0xef & m88ds3103_readreg(state, 0x23));
> +	
> +	/* 2nd step to wake up tuner */
> +	val = m88ds3103_tuner_readreg(state, 0x00) & 0xff;
> +	if((val & 0x01) == 0){
> +		m88ds3103_tuner_writereg(state, 0x00, 0x01);
> +		msleep(50);
> +	}
> +	m88ds3103_tuner_writereg(state, 0x00, 0x03);
> +	msleep(50);
> +	
> +	return 0;	
> +}
> +
> +/* Put device to sleep */
> +static int m88ds3103_sleep(struct dvb_frontend *fe)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +
> +	dprintk("%s()\n", __func__);
> +	
> +	/* 1st step to sleep tuner */
> +	m88ds3103_tuner_writereg(state, 0x00, 0x00);
> +	
> +	/* 2nd step to sleep demod */
> +	m88ds3103_writereg(state, 0x08, 0xfe & m88ds3103_readreg(state, 0x08));
> +	m88ds3103_writereg(state, 0x04, 0x01 | m88ds3103_readreg(state, 0x04));
> +	m88ds3103_writereg(state, 0x23, 0x10 | m88ds3103_readreg(state, 0x23));
> +	
> +
> +	return 0;
> +}
> +
> +static struct dvb_frontend_ops m88ds3103_ops = {
> +	.delsys = { SYS_DVBS, SYS_DVBS2},
> +	.info = {
> +		.name = "Montage DS3103/TS2022",
> +		.type = FE_QPSK,
> +		.frequency_min = 950000,
> +		.frequency_max = 2150000,
> +		.frequency_stepsize = 1011, /* kHz for QPSK frontends */
> +		.frequency_tolerance = 5000,
> +		.symbol_rate_min = 1000000,
> +		.symbol_rate_max = 45000000,
> +		.caps = FE_CAN_INVERSION_AUTO |
> +			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
> +			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
> +			FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
> +			FE_CAN_2G_MODULATION |
> +			FE_CAN_QPSK | FE_CAN_RECOVER
> +	},
> +
> +	.release = m88ds3103_release,
> +
> +	.init = m88ds3103_initfe,
> +	.sleep = m88ds3103_sleep,
> +	.read_status = m88ds3103_read_status,
> +	.read_ber = m88ds3103_read_ber,
> +	.read_signal_strength = m88ds3103_read_signal_strength,
> +	.read_snr = m88ds3103_read_snr,
> +	.read_ucblocks = m88ds3103_read_ucblocks,
> +	.set_tone = m88ds3103_set_tone,
> +	.set_voltage = m88ds3103_set_voltage,
> +	.diseqc_send_master_cmd = m88ds3103_send_diseqc_msg,
> +	.diseqc_send_burst = m88ds3103_diseqc_send_burst,
> +	.get_frontend_algo = m88ds3103_get_algo,
> +	.tune = m88ds3103_tune,
> +	.set_frontend = m88ds3103_set_frontend,
> +};
> +
> +MODULE_DESCRIPTION("DVB Frontend module for Montage DS3103/TS2022 hardware");
> +MODULE_AUTHOR("Max nibble");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/media/dvb/frontends/m88ds3103.h b/drivers/media/dvb/frontends/m88ds3103.h
> new file mode 100644
> index 0000000..c7b690e
> --- /dev/null
> +++ b/drivers/media/dvb/frontends/m88ds3103.h
> @@ -0,0 +1,53 @@
> +/*
> +    Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner driver
> +
> +    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 M88DS3103_H
> +#define M88DS3103_H
> +
> +#include <linux/dvb/frontend.h>
> +
> +struct m88ds3103_config {
> +	/* the demodulator's i2c address */
> +	u8 demod_address;
> +	u8 ci_mode;
> +	u8 pin_ctrl;
> +	u8 ts_mode; /* 0: Parallel, 1: Serial */
> +
> +	/* Set device param to start dma */
> +	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
> +    /* Start to transfer data */
> +    int (*start_ctrl)(struct dvb_frontend *fe);
> +    /* Set LNB voltage */
> +    int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
> +};
> +
> +#if defined(CONFIG_DVB_M88DS3103) || \
> +	(defined(CONFIG_DVB_M88DS3103_MODULE) && defined(MODULE))
> +extern struct dvb_frontend *m88ds3103_attach(
> +       const struct m88ds3103_config *config,
> +       struct i2c_adapter *i2c);
> +#else
> +static inline struct dvb_frontend *m88ds3103_attach(
> +       const struct m88ds3103_config *config,
> +       struct i2c_adapter *i2c)
> +{
> +	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
> +	return NULL;
> +}
> +#endif /* CONFIG_DVB_M88DS3103 */
> +#endif /* M88DS3103_H */


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 2/6] m88ds3103, dvbsky dvb-s2 usb box.
  2012-04-15 15:53   ` [PATCH 2/6] m88ds3103, dvbsky dvb-s2 usb box nibble.max
@ 2012-04-19 18:09     ` Mauro Carvalho Chehab
  2012-04-20  8:08     ` nibble.max
  1 sibling, 0 replies; 56+ messages in thread
From: Mauro Carvalho Chehab @ 2012-04-19 18:09 UTC (permalink / raw)
  To: nibble.max; +Cc: linux-media

Em 15-04-2012 12:53, nibble.max escreveu:
> dvbsky dvb-s2 usb box based on montage m88ds3103 demodulator.
> 
> Signed-off-by: Max nibble <nibble.max@gmail.com>
> ---
>  drivers/media/dvb/dvb-usb/Kconfig  |    1 +
>  drivers/media/dvb/dvb-usb/dw2102.c |  236 +++++++++++++++++++++++++++++++++++-
>  2 files changed, 236 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
> index be1db75..bf63f29 100644
> --- a/drivers/media/dvb/dvb-usb/Kconfig
> +++ b/drivers/media/dvb/dvb-usb/Kconfig
> @@ -279,6 +279,7 @@ config DVB_USB_DW2102
>  	select DVB_STV0288 if !DVB_FE_CUSTOMISE
>  	select DVB_STB6000 if !DVB_FE_CUSTOMISE
>  	select DVB_CX24116 if !DVB_FE_CUSTOMISE
> +	select DVB_M88DS3103 if !DVB_FE_CUSTOMISE
>  	select DVB_SI21XX if !DVB_FE_CUSTOMISE
>  	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
>  	select DVB_MT312 if !DVB_FE_CUSTOMISE
> diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c
> index 451c5a7..0b1bbd2 100644
> --- a/drivers/media/dvb/dvb-usb/dw2102.c
> +++ b/drivers/media/dvb/dvb-usb/dw2102.c
> @@ -19,6 +19,7 @@
>  #include "stb6000.h"
>  #include "eds1547.h"
>  #include "cx24116.h"
> +#include "m88ds3103.h"
>  #include "tda1002x.h"
>  #include "mt312.h"
>  #include "zl10039.h"
> @@ -882,6 +883,44 @@ static int s660_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
>  	return 0;
>  }
>  
> +static int bstusb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
> +{
> +
> +	struct dvb_usb_adapter *udev_adap =
> +		(struct dvb_usb_adapter *)(fe->dvb->priv);
> +
> +	u8 obuf[3] = { 0xe, 0x80, 0 };
> +	u8 ibuf[] = { 0 };
> +		
> +	info("US6830: %s!\n", __func__);
> +				
> +	if (voltage == SEC_VOLTAGE_OFF)
> +		obuf[2] = 0;
> +	else 
> +		obuf[2] = 1;
> +		
> +	if (dvb_usb_generic_rw(udev_adap->dev, obuf, 3, ibuf, 1, 0) < 0)
> +		err("command 0x0e transfer failed.");
> +	
> +	return 0;
> +}
> +
> +static int bstusb_restart(struct dvb_frontend *fe)
> +{
> +
> +	struct dvb_usb_adapter *udev_adap =
> +		(struct dvb_usb_adapter *)(fe->dvb->priv);
> +	
> +	u8 obuf[3] = { 0x36, 3, 0 };
> +	u8 ibuf[] = { 0 };
> +			
> +
> +	if (dvb_usb_generic_rw(udev_adap->dev, obuf, 3, ibuf, 1, 0) < 0)
> +		err("command 0x36 transfer failed.");
> +	
> +	return 0;
> +}
> +
>  static void dw210x_led_ctrl(struct dvb_frontend *fe, int offon)
>  {
>  	static u8 led_off[] = { 0 };
> @@ -987,6 +1026,24 @@ static struct ds3000_config su3000_ds3000_config = {
>  	.ci_mode = 1,
>  };
>  
> +static struct m88ds3103_config US6830_ds3103_config = {
> +	.demod_address = 0x68,
> +	.ci_mode = 1,
> +	.pin_ctrl = 0x83,
> +	.ts_mode = 0,
> +	.start_ctrl = bstusb_restart,
> +	.set_voltage = bstusb_set_voltage,
> +};
> +
> +static struct m88ds3103_config US6832_ds3103_config = {
> +	.demod_address = 0x68,
> +	.ci_mode = 1,
> +	.pin_ctrl = 0x80,
> +	.ts_mode = 0,
> +	.start_ctrl = bstusb_restart,
> +	.set_voltage = bstusb_set_voltage,
> +};
> +
>  static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
>  {
>  	struct dvb_tuner_ops *tuner_ops = NULL;
> @@ -1214,6 +1271,72 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *d)
>  	return 0;
>  }
>  
> +static int US6830_frontend_attach(struct dvb_usb_adapter *d)
> +{
> +	u8 obuf[3] = { 0xe, 0x83, 0 };
> +	u8 ibuf[] = { 0 };
> +
> +
> +	info("US6830: %s!\n", __func__);
> +	
> +	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
> +		err("command 0x0e transfer failed.");
> +
> +	obuf[0] = 0xe;
> +	obuf[1] = 0x83;
> +	obuf[2] = 1;
> +
> +	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
> +		err("command 0x0e transfer failed.");
> +
> +	obuf[0] = 0x51;
> +
> +	if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
> +		err("command 0x51 transfer failed.");
> +
> +	d->fe_adap[0].fe = dvb_attach(m88ds3103_attach, &US6830_ds3103_config,
> +					&d->dev->i2c_adap);
> +	if (d->fe_adap[0].fe == NULL)
> +		return -EIO;
> +
> +	info("Attached M88DS3103!\n");
> +
> +	return 0;
> +}
> +
> +static int US6832_frontend_attach(struct dvb_usb_adapter *d)
> +{
> +	u8 obuf[3] = { 0xe, 0x83, 0 };
> +	u8 ibuf[] = { 0 };
> +
> +
> +	info("US6832: %s!\n", __func__);
> +	
> +	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
> +		err("command 0x0e transfer failed.");
> +
> +	obuf[0] = 0xe;
> +	obuf[1] = 0x83;
> +	obuf[2] = 1;
> +
> +	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
> +		err("command 0x0e transfer failed.");
> +
> +	obuf[0] = 0x51;
> +
> +	if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
> +		err("command 0x51 transfer failed.");
> +
> +	d->fe_adap[0].fe = dvb_attach(m88ds3103_attach, &US6832_ds3103_config,
> +					&d->dev->i2c_adap);
> +	if (d->fe_adap[0].fe == NULL)
> +		return -EIO;
> +
> +	info("Attached M88DS3103!\n");
> +
> +	return 0;
> +}
> +
>  static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
>  {
>  	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
> @@ -1451,6 +1574,9 @@ enum dw2102_table_entry {
>  	TEVII_S480_1,
>  	TEVII_S480_2,
>  	X3M_SPC1400HD,
> +	BST_US6830HD,
> +	BST_US6831HD,
> +	BST_US6832HD,
>  };
>  
>  static struct usb_device_id dw2102_table[] = {
> @@ -1469,6 +1595,9 @@ static struct usb_device_id dw2102_table[] = {
>  	[TEVII_S480_1] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)},
>  	[TEVII_S480_2] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)},
>  	[X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)},
> +	[BST_US6830HD] = {USB_DEVICE(0x0572, 0x6830)},
> +	[BST_US6831HD] = {USB_DEVICE(0x0572, 0x6831)},
> +	[BST_US6832HD] = {USB_DEVICE(0x0572, 0x6832)},
>  	{ }
>  };
>  
> @@ -1874,6 +2003,107 @@ static struct dvb_usb_device_properties su3000_properties = {
>  	}
>  };
>  
> +static struct dvb_usb_device_properties US6830_properties = {
> +	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
> +	.usb_ctrl = DEVICE_SPECIFIC,
> +	.size_of_priv = sizeof(struct su3000_state),
> +	.power_ctrl = su3000_power_ctrl,
> +	.num_adapters = 1,
> +	.identify_state	= su3000_identify_state,
> +	.i2c_algo = &su3000_i2c_algo,
> +
> +	.rc.legacy = {
> +		.rc_map_table = rc_map_su3000_table,
> +		.rc_map_size = ARRAY_SIZE(rc_map_su3000_table),
> +		.rc_interval = 150,
> +		.rc_query = dw2102_rc_query,
> +	},


New drivers should use .rc.core instead. For a simple example on how to use,
please take a look at the az6007 driver.

> +
> +	.read_mac_address = su3000_read_mac_address,
> +
> +	.generic_bulk_ctrl_endpoint = 0x01,
> +	
> +	.adapter = {
> +		{
> +		.num_frontends = 1,
> +		.fe = {{
> +			.streaming_ctrl   = su3000_streaming_ctrl,
> +			.frontend_attach  = US6830_frontend_attach,
> +			.stream = {
> +				.type = USB_BULK,
> +				.count = 8,
> +				.endpoint = 0x82,
> +				.u = {
> +					.bulk = {
> +						.buffersize = 4096,
> +					}
> +				}
> +			}
> +		}},
> +		}
> +	},
> +	.num_device_descs = 2,
> +	.devices = {
> +		{ "Bestunar US6830 HD",
> +			{ &dw2102_table[BST_US6830HD], NULL },
> +			{ NULL },
> +		},
> +		{ "Bestunar US6831 HD",
> +			{ &dw2102_table[BST_US6831HD], NULL },
> +			{ NULL },
> +		},				
> +	}
> +};
> +
> +static struct dvb_usb_device_properties US6832_properties = {
> +	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
> +	.usb_ctrl = DEVICE_SPECIFIC,
> +	.size_of_priv = sizeof(struct su3000_state),
> +	.power_ctrl = su3000_power_ctrl,
> +	.num_adapters = 1,
> +	.identify_state	= su3000_identify_state,
> +	.i2c_algo = &su3000_i2c_algo,
> +
> +	.rc.legacy = {
> +		.rc_map_table = rc_map_su3000_table,
> +		.rc_map_size = ARRAY_SIZE(rc_map_su3000_table),
> +		.rc_interval = 150,
> +		.rc_query = dw2102_rc_query,
> +	},
> +
> +	.read_mac_address = su3000_read_mac_address,
> +
> +	.generic_bulk_ctrl_endpoint = 0x01,
> +
> +	.adapter = {
> +		{
> +		.num_frontends = 1,
> +		.fe = {{
> +			.streaming_ctrl   = su3000_streaming_ctrl,
> +			.frontend_attach  = US6832_frontend_attach,
> +			.stream = {
> +				.type = USB_BULK,
> +				.count = 8,
> +				.endpoint = 0x82,
> +				.u = {
> +					.bulk = {
> +						.buffersize = 4096,
> +					}
> +				}
> +			}
> +		}},
> +		}
> +	},
> +	.num_device_descs = 1,
> +	.devices = {
> +		{ "Bestunar US6832 HD",
> +			{ &dw2102_table[BST_US6832HD], NULL },
> +			{ NULL },
> +		},
> +				
> +	}
> +};
> +
>  static int dw2102_probe(struct usb_interface *intf,
>  		const struct usb_device_id *id)
>  {
> @@ -1930,7 +2160,11 @@ static int dw2102_probe(struct usb_interface *intf,
>  	    0 == dvb_usb_device_init(intf, p7500,
>  			THIS_MODULE, NULL, adapter_nr) ||
>  	    0 == dvb_usb_device_init(intf, &su3000_properties,
> -				     THIS_MODULE, NULL, adapter_nr))
> +     			THIS_MODULE, NULL, adapter_nr) ||
> +	    0 == dvb_usb_device_init(intf, &US6830_properties,
> +			THIS_MODULE, NULL, adapter_nr) ||
> +	    0 == dvb_usb_device_init(intf, &US6832_properties,
> +			THIS_MODULE, NULL, adapter_nr))
>  		return 0;
>  
>  	return -ENODEV;


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 4/6] m88ds3103, dvbsky dvb-s2 cx23885 pcie card.
  2012-04-15 15:53   ` [PATCH 4/6] m88ds3103, dvbsky dvb-s2 cx23885 pcie card nibble.max
@ 2012-04-19 18:11     ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 56+ messages in thread
From: Mauro Carvalho Chehab @ 2012-04-19 18:11 UTC (permalink / raw)
  To: nibble.max; +Cc: linux-media

Em 15-04-2012 12:53, nibble.max escreveu:
> dvbsky dvb-s2 pcie based on montage m88ds3103 demodulator.
> 
> Signed-off-by: Max nibble <nibble.max@gmail.com>
> ---
>  drivers/media/video/cx23885/Kconfig         |    1 +
>  drivers/media/video/cx23885/cx23885-cards.c |  107 +++++++++++++++++++++++++++
>  drivers/media/video/cx23885/cx23885-dvb.c   |   52 +++++++++++++
>  drivers/media/video/cx23885/cx23885-f300.c  |   55 ++++++++++++++
>  drivers/media/video/cx23885/cx23885-f300.h  |    6 ++
>  drivers/media/video/cx23885/cx23885-input.c |   15 ++++
>  drivers/media/video/cx23885/cx23885.h       |    3 +
>  7 files changed, 239 insertions(+)
> 
> diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
> index b391e9b..20337c7 100644
> --- a/drivers/media/video/cx23885/Kconfig
> +++ b/drivers/media/video/cx23885/Kconfig
> @@ -20,6 +20,7 @@ config VIDEO_CX23885
>  	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
>  	select DVB_STV6110 if !DVB_FE_CUSTOMISE
>  	select DVB_CX24116 if !DVB_FE_CUSTOMISE
> +	select DVB_M88DS3103 if !DVB_FE_CUSTOMISE
>  	select DVB_STV0900 if !DVB_FE_CUSTOMISE
>  	select DVB_DS3000 if !DVB_FE_CUSTOMISE
>  	select DVB_STV0367 if !DVB_FE_CUSTOMISE
> diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
> index 19b5499..fdf9d0f 100644
> --- a/drivers/media/video/cx23885/cx23885-cards.c
> +++ b/drivers/media/video/cx23885/cx23885-cards.c
> @@ -497,6 +497,20 @@ struct cx23885_board cx23885_boards[] = {
>  		.name		= "TerraTec Cinergy T PCIe Dual",
>  		.portb		= CX23885_MPEG_DVB,
>  		.portc		= CX23885_MPEG_DVB,
> +	},
> +
> +	[CX23885_BOARD_BST_PS8512] = {
> +		.name		= "Bestunar PS8512",
> +		.portb		= CX23885_MPEG_DVB,
> +	},
> +	[CX23885_BOARD_DVBSKY_S950] = {
> +		.name		= "DVBSKY S950",
> +		.portb		= CX23885_MPEG_DVB,
> +	},
> +	[CX23885_BOARD_DVBSKY_S952] = {
> +		.name		= "DVBSKY S952",
> +		.portb		= CX23885_MPEG_DVB,
> +		.portc		= CX23885_MPEG_DVB,
>  	}
>  };
>  const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
> @@ -705,6 +719,18 @@ struct cx23885_subid cx23885_subids[] = {
>  		.subvendor = 0x153b,
>  		.subdevice = 0x117e,
>  		.card      = CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL,
> +	}, {
> +		.subvendor = 0x14f1,
> +		.subdevice = 0x8512,
> +		.card      = CX23885_BOARD_BST_PS8512,
> +	}, {
> +		.subvendor = 0x4254,
> +		.subdevice = 0x0950,
> +		.card      = CX23885_BOARD_DVBSKY_S950,		
> +	}, {
> +		.subvendor = 0x4254,
> +		.subdevice = 0x0952,
> +		.card      = CX23885_BOARD_DVBSKY_S952,
>  	},
>  };
>  const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
> @@ -1216,9 +1242,57 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
>  		/* enable irq */
>  		cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/
>  		break;
> +	case CX23885_BOARD_DVBSKY_S950:
> +	case CX23885_BOARD_BST_PS8512:			
> +		cx23885_gpio_enable(dev, GPIO_2, 1);
> +		cx23885_gpio_clear(dev, GPIO_2);
> +		msleep(100);		
> +		cx23885_gpio_set(dev, GPIO_2);
> +		break;
> +	case CX23885_BOARD_DVBSKY_S952:		
> +		cx_write(MC417_CTL, 0x00000037);/* enable GPIO3-18 pins */
> +		
> +		cx23885_gpio_enable(dev, GPIO_2, 1);
> +		cx23885_gpio_enable(dev, GPIO_11, 1);
> +		
> +		cx23885_gpio_clear(dev, GPIO_2);
> +		cx23885_gpio_clear(dev, GPIO_11);
> +		msleep(100);		
> +		cx23885_gpio_set(dev, GPIO_2);
> +		cx23885_gpio_set(dev, GPIO_11);
> +		
> +		break;
>  	}
>  }
>  
> +static int cx23885_ir_patch(struct i2c_adapter *i2c, u8 reg, u8 mask)
> +{
> +	struct i2c_msg msgs[2];
> +	u8 tx_buf[2], rx_buf[1];
> +	/* Write register address */
> +	tx_buf[0] = reg;
> +	msgs[0].addr = 0x4c;
> +	msgs[0].flags = 0;
> +	msgs[0].len = 1;
> +	msgs[0].buf = (char *) tx_buf;
> +	/* Read data from register */
> +	msgs[1].addr = 0x4c;
> +	msgs[1].flags = I2C_M_RD;
> +	msgs[1].len = 1;
> +	msgs[1].buf = (char *) rx_buf;	
> +	
> +	i2c_transfer(i2c, msgs, 2);
> +
> +	tx_buf[0] = reg;
> +	tx_buf[1] = rx_buf[0] | mask;
> +	msgs[0].addr = 0x4c;
> +	msgs[0].flags = 0;
> +	msgs[0].len = 2;
> +	msgs[0].buf = (char *) tx_buf;
> +	
> +	return i2c_transfer(i2c, msgs, 1);
> +}
> +
>  int cx23885_ir_init(struct cx23885_dev *dev)
>  {
>  	static struct v4l2_subdev_io_pin_config ir_rxtx_pin_cfg[] = {
> @@ -1301,6 +1375,20 @@ int cx23885_ir_init(struct cx23885_dev *dev)
>  		v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
>  				 ir_rx_pin_cfg_count, ir_rx_pin_cfg);
>  		break;
> +	case CX23885_BOARD_BST_PS8512:
> +	case CX23885_BOARD_DVBSKY_S950:
> +	case CX23885_BOARD_DVBSKY_S952:
> +		dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE);
> +		if (dev->sd_ir == NULL) {
> +			ret = -ENODEV;
> +			break;
> +		}
> +		v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
> +				 ir_rx_pin_cfg_count, ir_rx_pin_cfg);
> +				 
> +		cx23885_ir_patch(&(dev->i2c_bus[2].i2c_adap),0x1f,0x80);
> +		cx23885_ir_patch(&(dev->i2c_bus[2].i2c_adap),0x23,0x80);
> +		break;
>  	case CX23885_BOARD_HAUPPAUGE_HVR1250:
>  		if (!enable_885_ir)
>  			break;
> @@ -1332,6 +1420,9 @@ void cx23885_ir_fini(struct cx23885_dev *dev)
>  		break;
>  	case CX23885_BOARD_TEVII_S470:
>  	case CX23885_BOARD_HAUPPAUGE_HVR1250:
> +	case CX23885_BOARD_BST_PS8512:
> +	case CX23885_BOARD_DVBSKY_S950:
> +	case CX23885_BOARD_DVBSKY_S952:
>  		cx23885_irq_remove(dev, PCI_MSK_AV_CORE);
>  		/* sd_ir is a duplicate pointer to the AV Core, just clear it */
>  		dev->sd_ir = NULL;
> @@ -1375,6 +1466,9 @@ void cx23885_ir_pci_int_enable(struct cx23885_dev *dev)
>  		break;
>  	case CX23885_BOARD_TEVII_S470:
>  	case CX23885_BOARD_HAUPPAUGE_HVR1250:
> +	case CX23885_BOARD_BST_PS8512:
> +	case CX23885_BOARD_DVBSKY_S950:
> +	case CX23885_BOARD_DVBSKY_S952:
>  		if (dev->sd_ir)
>  			cx23885_irq_add_enable(dev, PCI_MSK_AV_CORE);
>  		break;
> @@ -1459,6 +1553,8 @@ void cx23885_card_setup(struct cx23885_dev *dev)
>  		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
>  		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
>  		break;
> +	case CX23885_BOARD_BST_PS8512:
> +	case CX23885_BOARD_DVBSKY_S950:
>  	case CX23885_BOARD_TEVII_S470:
>  	case CX23885_BOARD_DVBWORLD_2005:
>  		ts1->gen_ctrl_val  = 0x5; /* Parallel */
> @@ -1489,6 +1585,14 @@ void cx23885_card_setup(struct cx23885_dev *dev)
>  		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
>  		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
>  		break;
> +	case CX23885_BOARD_DVBSKY_S952:
> +		ts1->gen_ctrl_val  = 0x5; /* Parallel */
> +		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
> +		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
> +		ts2->gen_ctrl_val  = 0xe; /* Serial bus + punctured clock */
> +		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
> +		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
> +		break;
>  	case CX23885_BOARD_HAUPPAUGE_HVR1250:
>  	case CX23885_BOARD_HAUPPAUGE_HVR1500:
>  	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
> @@ -1541,6 +1645,9 @@ void cx23885_card_setup(struct cx23885_dev *dev)
>  	case CX23885_BOARD_MPX885:
>  	case CX23885_BOARD_MYGICA_X8507:
>  	case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
> +	case CX23885_BOARD_BST_PS8512:
> +	case CX23885_BOARD_DVBSKY_S950:
> +	case CX23885_BOARD_DVBSKY_S952:
>  		dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
>  				&dev->i2c_bus[2].i2c_adap,
>  				"cx25840", 0x88 >> 1, NULL);
> diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
> index 6835eb1..c5a3fa3 100644
> --- a/drivers/media/video/cx23885/cx23885-dvb.c
> +++ b/drivers/media/video/cx23885/cx23885-dvb.c
> @@ -51,6 +51,7 @@
>  #include "stv6110.h"
>  #include "lnbh24.h"
>  #include "cx24116.h"
> +#include "m88ds3103.h"
>  #include "cimax2.h"
>  #include "lgs8gxx.h"
>  #include "netup-eeprom.h"
> @@ -489,6 +490,30 @@ static struct xc5000_config mygica_x8506_xc5000_config = {
>  	.if_khz = 5380,
>  };
>  
> +/* bestunar single dvb-s2 */
> +static struct m88ds3103_config bst_ds3103_config = {
> +	.demod_address = 0x68,
> +	.ci_mode = 0,
> +	.pin_ctrl = 0x82,
> +	.ts_mode = 0,
> +	.set_voltage = bst_set_voltage,
> +};
> +/* DVBSKY dual dvb-s2 */
> +static struct m88ds3103_config dvbsky_ds3103_config_pri = {
> +	.demod_address = 0x68,
> +	.ci_mode = 0,
> +	.pin_ctrl = 0x82,
> +	.ts_mode = 0,
> +	.set_voltage = bst_set_voltage,	
> +};
> +static struct m88ds3103_config dvbsky_ds3103_config_sec = {
> +	.demod_address = 0x68,
> +	.ci_mode = 0,
> +	.pin_ctrl = 0x82,
> +	.ts_mode = 1,
> +	.set_voltage = dvbsky_set_voltage_sec,	
> +};
> +
>  static int cx23885_dvb_set_frontend(struct dvb_frontend *fe)
>  {
>  	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
> @@ -1173,6 +1198,33 @@ static int dvb_register(struct cx23885_tsport *port)
>  			break;
>  		}
>  		break;
> +
> +	case CX23885_BOARD_BST_PS8512:
> +	case CX23885_BOARD_DVBSKY_S950:
> +		i2c_bus = &dev->i2c_bus[1];	
> +		fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
> +					&bst_ds3103_config,
> +					&i2c_bus->i2c_adap);
> +		break;	
> +			
> +	case CX23885_BOARD_DVBSKY_S952:
> +		switch (port->nr) {
> +		/* port B */
> +		case 1:
> +			i2c_bus = &dev->i2c_bus[1];
> +			fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
> +						&dvbsky_ds3103_config_pri,
> +						&i2c_bus->i2c_adap);
> +			break;
> +		/* port C */
> +		case 2:
> +			i2c_bus = &dev->i2c_bus[0];
> +			fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
> +						&dvbsky_ds3103_config_sec,
> +						&i2c_bus->i2c_adap);		
> +			break;
> +		}
> +		break;
>  	default:
>  		printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
>  			" isn't supported yet\n",
> diff --git a/drivers/media/video/cx23885/cx23885-f300.c b/drivers/media/video/cx23885/cx23885-f300.c
> index 93998f2..6be0369 100644
> --- a/drivers/media/video/cx23885/cx23885-f300.c
> +++ b/drivers/media/video/cx23885/cx23885-f300.c
> @@ -175,3 +175,58 @@ int f300_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
>  
>  	return f300_xfer(fe, buf);
>  }
> +
> +/* bst control */
> +int bst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
> +{
> +	struct cx23885_tsport *port = fe->dvb->priv;
> +	struct cx23885_dev *dev = port->dev;
> +	
> +	cx23885_gpio_enable(dev, GPIO_1, 1);
> +	cx23885_gpio_enable(dev, GPIO_0, 1);
> +
> +	switch (voltage) {
> +	case SEC_VOLTAGE_13:
> +		cx23885_gpio_set(dev, GPIO_1);
> +		cx23885_gpio_clear(dev, GPIO_0);
> +		break;
> +	case SEC_VOLTAGE_18:
> +		cx23885_gpio_set(dev, GPIO_1);
> +		cx23885_gpio_set(dev, GPIO_0);
> +		break;
> +	case SEC_VOLTAGE_OFF:
> +		cx23885_gpio_clear(dev, GPIO_1);
> +		cx23885_gpio_clear(dev, GPIO_0);
> +		break;
> +	}
> +	
> +
> +	return 0;
> +}
> +
> +int dvbsky_set_voltage_sec(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
> +{
> +	struct cx23885_tsport *port = fe->dvb->priv;
> +	struct cx23885_dev *dev = port->dev;
> +	
> +	cx23885_gpio_enable(dev, GPIO_12, 1);
> +	cx23885_gpio_enable(dev, GPIO_13, 1);
> +
> +	switch (voltage) {
> +	case SEC_VOLTAGE_13:
> +		cx23885_gpio_set(dev, GPIO_13);
> +		cx23885_gpio_clear(dev, GPIO_12);
> +		break;
> +	case SEC_VOLTAGE_18:
> +		cx23885_gpio_set(dev, GPIO_13);
> +		cx23885_gpio_set(dev, GPIO_12);
> +		break;
> +	case SEC_VOLTAGE_OFF:
> +		cx23885_gpio_clear(dev, GPIO_13);
> +		cx23885_gpio_clear(dev, GPIO_12);
> +		break;
> +	}
> +	
> +
> +	return 0;
> +}
> \ No newline at end of file

Please add a new line.

> diff --git a/drivers/media/video/cx23885/cx23885-f300.h b/drivers/media/video/cx23885/cx23885-f300.h
> index e73344c..cd02d02 100644
> --- a/drivers/media/video/cx23885/cx23885-f300.h
> +++ b/drivers/media/video/cx23885/cx23885-f300.h
> @@ -1,2 +1,8 @@
> +extern int dvbsky_set_voltage_sec(struct dvb_frontend *fe,
> +				fe_sec_voltage_t voltage);
> +				
> +extern int bst_set_voltage(struct dvb_frontend *fe,
> +				fe_sec_voltage_t voltage);
> +
>  extern int f300_set_voltage(struct dvb_frontend *fe,
>  				fe_sec_voltage_t voltage);
> diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c
> index ce765e3..69c01f3 100644
> --- a/drivers/media/video/cx23885/cx23885-input.c
> +++ b/drivers/media/video/cx23885/cx23885-input.c
> @@ -87,6 +87,9 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
>  	case CX23885_BOARD_HAUPPAUGE_HVR1290:
>  	case CX23885_BOARD_TEVII_S470:
>  	case CX23885_BOARD_HAUPPAUGE_HVR1250:
> +	case CX23885_BOARD_BST_PS8512:
> +	case CX23885_BOARD_DVBSKY_S950:
> +	case CX23885_BOARD_DVBSKY_S952:
>  		/*
>  		 * The only boards we handle right now.  However other boards
>  		 * using the CX2388x integrated IR controller should be similar
> @@ -138,6 +141,9 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev)
>  	case CX23885_BOARD_HAUPPAUGE_HVR1850:
>  	case CX23885_BOARD_HAUPPAUGE_HVR1290:
>  	case CX23885_BOARD_HAUPPAUGE_HVR1250:
> +	case CX23885_BOARD_BST_PS8512:
> +	case CX23885_BOARD_DVBSKY_S950:
> +	case CX23885_BOARD_DVBSKY_S952:
>  		/*
>  		 * The IR controller on this board only returns pulse widths.
>  		 * Any other mode setting will fail to set up the device.
> @@ -279,6 +285,15 @@ int cx23885_input_init(struct cx23885_dev *dev)
>  		/* A guess at the remote */
>  		rc_map = RC_MAP_TEVII_NEC;
>  		break;
> +	case CX23885_BOARD_BST_PS8512:
> +	case CX23885_BOARD_DVBSKY_S950:
> +	case CX23885_BOARD_DVBSKY_S952:
> +		/* Integrated CX2388[58] IR controller */
> +		driver_type = RC_DRIVER_IR_RAW;
> +		allowed_protos = RC_TYPE_ALL;
> +		/* A guess at the remote */
> +		rc_map = RC_MAP_DVBSKY;
> +		break;
>  	default:
>  		return -ENODEV;
>  	}
> diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
> index f020f05..2724148 100644
> --- a/drivers/media/video/cx23885/cx23885.h
> +++ b/drivers/media/video/cx23885/cx23885.h
> @@ -89,6 +89,9 @@
>  #define CX23885_BOARD_MPX885                   32
>  #define CX23885_BOARD_MYGICA_X8507             33
>  #define CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL 34
> +#define CX23885_BOARD_BST_PS8512               35
> +#define CX23885_BOARD_DVBSKY_S952              36
> +#define CX23885_BOARD_DVBSKY_S950              37
>  
>  #define GPIO_0 0x00000001
>  #define GPIO_1 0x00000002


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 5/6] m88ds3103, dvbsky remote control key map.
  2012-04-15 15:53   ` [PATCH 5/6] m88ds3103, dvbsky remote control key map nibble.max
@ 2012-04-19 18:16     ` Mauro Carvalho Chehab
  2012-04-20  8:01       ` nibble.max
  0 siblings, 1 reply; 56+ messages in thread
From: Mauro Carvalho Chehab @ 2012-04-19 18:16 UTC (permalink / raw)
  To: nibble.max; +Cc: linux-media

Em 15-04-2012 12:53, nibble.max escreveu:
> dvbsky remote control key map for pci/pcie card.
> 
> Signed-off-by: Max nibble <nibble.max@gmail.com>
> ---
>  drivers/media/rc/keymaps/Makefile    |    1 +
>  drivers/media/rc/keymaps/rc-dvbsky.c |   78 ++++++++++++++++++++++++++++++++++
>  2 files changed, 79 insertions(+)
>  create mode 100644 drivers/media/rc/keymaps/rc-dvbsky.c
> 
> diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
> index 49ce266..e6a882b 100644
> --- a/drivers/media/rc/keymaps/Makefile
> +++ b/drivers/media/rc/keymaps/Makefile
> @@ -26,6 +26,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
>  			rc-dm1105-nec.o \
>  			rc-dntv-live-dvb-t.o \
>  			rc-dntv-live-dvbt-pro.o \
> +			rc-dvbsky.o \
>  			rc-em-terratec.o \
>  			rc-encore-enltv2.o \
>  			rc-encore-enltv.o \
> diff --git a/drivers/media/rc/keymaps/rc-dvbsky.c b/drivers/media/rc/keymaps/rc-dvbsky.c
> new file mode 100644
> index 0000000..2bd9977
> --- /dev/null
> +++ b/drivers/media/rc/keymaps/rc-dvbsky.c
> @@ -0,0 +1,78 @@
> +/* rc-dvbsky.c - Keytable for Dvbsky Remote Controllers
> + *
> + * keymap imported from ir-keymaps.c

No, you didn't import it from ir-keymaps.c ;) This is the old file where several
keymaps used to be stored.

> + *
> + *
> + * Copyright (c) 2010-2011 by Mauro Carvalho Chehab <mchehab@redhat.com>

Huh? I didn't wrote this keymap.

> + *
> + * 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.
> + */
> +
> +#include <media/rc-map.h>
> +#include <linux/module.h>
> +/*
> + * This table contains the complete RC5 code, instead of just the data part
> + */
> +
> +static struct rc_map_table rc5_dvbsky[] = {
> +	{ 0x0000, KEY_0 },
> +	{ 0x0001, KEY_1 },
> +	{ 0x0002, KEY_2 },
> +	{ 0x0003, KEY_3 },
> +	{ 0x0004, KEY_4 },
> +	{ 0x0005, KEY_5 },
> +	{ 0x0006, KEY_6 },
> +	{ 0x0007, KEY_7 },
> +	{ 0x0008, KEY_8 },
> +	{ 0x0009, KEY_9 },	
> +	{ 0x000a, KEY_MUTE },
> +	{ 0x000d, KEY_OK },
> +	{ 0x000b, KEY_STOP },
> +	{ 0x000c, KEY_EXIT },	
> +	{ 0x000e, KEY_CAMERA }, /*Snap shot*/
> +	{ 0x000f, KEY_SUBTITLE }, /*PIP*/
> +	{ 0x0010, KEY_VOLUMEUP },
> +	{ 0x0011, KEY_VOLUMEDOWN },
> +	{ 0x0012, KEY_FAVORITES },
> +	{ 0x0013, KEY_LIST }, /*Info*/
> +	{ 0x0016, KEY_PAUSE },
> +	{ 0x0017, KEY_PLAY },
> +	{ 0x001f, KEY_RECORD },
> +	{ 0x0020, KEY_CHANNELDOWN },
> +	{ 0x0021, KEY_CHANNELUP },
> +	{ 0x0025, KEY_POWER2 },
> +	{ 0x0026, KEY_REWIND },
> +	{ 0x0027, KEY_FASTFORWARD },
> +	{ 0x0029, KEY_LAST },
> +	{ 0x002b, KEY_MENU },	
> +	{ 0x002c, KEY_EPG },
> +	{ 0x002d, KEY_ZOOM },	

Hmm... are you sure that your IR getkey function is right? 
There are a few RC-5 IR's that uses only 6 bits, but this is not
common. I suspect that your code is missing the higher bits.

It would be nice if you could test it with another RC5 IR, or
to test your RC-5 with some other IR receiver, in order to double
check it.

> +};
> +
> +static struct rc_map_list rc5_dvbsky_map = {
> +	.map = {
> +		.scan    = rc5_dvbsky,
> +		.size    = ARRAY_SIZE(rc5_dvbsky),
> +		.rc_type = RC_TYPE_RC5,
> +		.name    = RC_MAP_DVBSKY,
> +	}
> +};
> +
> +static int __init init_rc_map_rc5_dvbsky(void)
> +{
> +	return rc_map_register(&rc5_dvbsky_map);
> +}
> +
> +static void __exit exit_rc_map_rc5_dvbsky(void)
> +{
> +	rc_map_unregister(&rc5_dvbsky_map);
> +}
> +
> +module_init(init_rc_map_rc5_dvbsky)
> +module_exit(exit_rc_map_rc5_dvbsky)
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");

Again, I didn't write it. You did ;)

Regards,
Mauro



^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-15 15:53   ` [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver nibble.max
  2012-04-19 18:06     ` Mauro Carvalho Chehab
@ 2012-04-19 20:08     ` Mauro Carvalho Chehab
  2012-04-20  8:01     ` nibble.max
  2 siblings, 0 replies; 56+ messages in thread
From: Mauro Carvalho Chehab @ 2012-04-19 20:08 UTC (permalink / raw)
  To: nibble.max; +Cc: linux-media

Hi Max,

Em 15-04-2012 12:53, nibble.max escreveu:
> Montage m88ds3103 demodulator and ts2022 tuner driver.

It was pointed to me that this device were already discussed on:

   http://www.mail-archive.com/linux-media@vger.kernel.org/msg43109.html

If m88ds3103 demod is similar enough to ds3000, it should just add the needed
bits at the existing driver, and not creating a new driver. 

Thanks,
Mauro

> 
> Signed-off-by: Max nibble <nibble.max@gmail.com>
> ---
>  drivers/media/dvb/frontends/Kconfig     |    7 +
>  drivers/media/dvb/frontends/Makefile    |    2 +
>  drivers/media/dvb/frontends/m88ds3103.c | 1851 +++++++++++++++++++++++++++++++
>  drivers/media/dvb/frontends/m88ds3103.h |   53 +
>  4 files changed, 1913 insertions(+)
>  create mode 100644 drivers/media/dvb/frontends/m88ds3103.c
>  create mode 100644 drivers/media/dvb/frontends/m88ds3103.h
> 
> diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
> index e11adb6..d2bb312 100644
> --- a/drivers/media/dvb/frontends/Kconfig
> +++ b/drivers/media/dvb/frontends/Kconfig
> @@ -214,6 +214,13 @@ config DVB_CX24116
>  	help
>  	  A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
>  
> +config DVB_M88DS3103
> +	tristate "Montage DS3103 based"
> +	depends on DVB_CORE && I2C
> +	default m if DVB_FE_CUSTOMISE
> +	help
> +	  A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
> +	  
>  config DVB_SI21XX
>  	tristate "Silicon Labs SI21XX based"
>  	depends on DVB_CORE && I2C
> diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
> index 6ca7557..84ddf41 100644
> --- a/drivers/media/dvb/frontends/Makefile
> +++ b/drivers/media/dvb/frontends/Makefile
> @@ -98,5 +98,7 @@ obj-$(CONFIG_DVB_A8293) += a8293.o
>  obj-$(CONFIG_DVB_TDA10071) += tda10071.o
>  obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
>  obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
> +obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o
>  obj-$(CONFIG_DVB_AF9033) += af9033.o
>  
> +
> diff --git a/drivers/media/dvb/frontends/m88ds3103.c b/drivers/media/dvb/frontends/m88ds3103.c
> new file mode 100644
> index 0000000..a186ba0
> --- /dev/null
> +++ b/drivers/media/dvb/frontends/m88ds3103.c
> @@ -0,0 +1,1851 @@
> +/*
> +    Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner driver
> +
> +    Copyright (C) 2011 Max nibble<nibble.max@gmail.com>
> +    Copyright (C) 2010 Montage Technology<www.montage-tech.com>
> +    Copyright (C) 2009 Konstantin Dimitrov.
> +
> +    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/slab.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/moduleparam.h>
> +#include <linux/init.h>
> +#include <linux/firmware.h>
> +
> +#include "dvb_frontend.h"
> +#include "m88ds3103.h"
> +
> +static int debug;
> +module_param(debug, int, 0644);
> +MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
> +
> +#define dprintk(args...) \
> +	do { \
> +		if (debug) \
> +			printk(KERN_INFO "m88ds3103: " args); \
> +	} while (0)
> +
> +#define FW_DOWN_SIZE 32
> +#define FW_DOWN_LOOP (8192/FW_DOWN_SIZE)
> +#define DS3103_DEFAULT_FIRMWARE "dvb-fe-ds3103.fw"
> +#define DS3000_DEFAULT_FIRMWARE "dvb-fe-ds300x.fw"
> +#define MT_FE_MCLK_KHZ 96000 /* in kHz */
> +#define MT_FE_CRYSTAL_KHZ   27000 /* in kHz */
> +#define FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz 3000
> +#define DS3000_ID	0x3000
> +#define DS3103_ID	0x3103
> +#define TS2020_ID	0x2020
> +#define TS2022_ID	0x2022
> +#define UNKNOW_ID	0x0000
> +
> +/* For M88DS3103 demod dvbs mode.*/
> +static u8 ds3103_dvbs_init_tab[] = {
> +	0x23, 0x07,
> +	0x08, 0x03,
> +	0x0c, 0x02,
> +	0x21, 0x54,
> +	0x25, 0x82,
> +	0x27, 0x31,
> +	0x30, 0x08,
> +	0x31, 0x40,
> +	0x32, 0x32,
> +	0x33, 0x35,
> +	0x35, 0xff,
> +	0x3a, 0x00,
> +	0x37, 0x10,
> +	0x38, 0x10,
> +	0x39, 0x02,
> +	0x42, 0x60,
> +	0x4a, 0x80,
> +	0x4b, 0x04,
> +	0x4d, 0x91,
> +	0x5d, 0xc8,
> +	0x50, 0x36,
> +	0x51, 0x36,
> +	0x52, 0x36,
> +	0x53, 0x36,
> +	0x63, 0x0f,
> +	0x64, 0x30,
> +	0x65, 0x40,
> +	0x68, 0x26,
> +	0x69, 0x4c,
> +	0x70, 0x20,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x40,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x60,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x80,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0xa0,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x1f,
> +	0x76, 0x38,
> +	0x77, 0xa6,
> +	0x78, 0x0c,
> +	0x79, 0x80,
> +	0x7f, 0x14,
> +	0x7c, 0x00,
> +	0xae, 0x82,
> +	0x80, 0x64,
> +	0x81, 0x66,
> +	0x82, 0x44,
> +	0x85, 0x04,
> +	0xcd, 0xf4,
> +	0x90, 0x33,
> +	0xa0, 0x44,
> +	0xc0, 0x08,
> +	0xc3, 0x10,
> +	0xc4, 0x08,
> +	0xc5, 0xf0,
> +	0xc6, 0xff,
> +	0xc7, 0x00,
> +	0xc8, 0x1a,
> +	0xc9, 0x80,
> +	0xe0, 0xf8,
> +	0xe6, 0x8b,
> +	0xd0, 0x40,
> +	0xf8, 0x20,
> +	0xfa, 0x0f,
> +	0x00, 0x00,
> +	0xbd, 0x01,
> +	0xb8, 0x00,
> +};
> +/* For M88DS3103 demod dvbs2 mode.*/
> +static u8 ds3103_dvbs2_init_tab[] = {
> +	0x23, 0x07,
> +	0x08, 0x07,
> +	0x0c, 0x02,
> +	0x21, 0x54,
> +	0x25, 0x82,
> +	0x27, 0x31,
> +	0x30, 0x08,
> +	0x32, 0x32,
> +	0x33, 0x35,
> +	0x35, 0xff,
> +	0x3a, 0x00,
> +	0x37, 0x10,
> +	0x38, 0x10,
> +	0x39, 0x02,
> +	0x42, 0x60,
> +	0x4a, 0x80,
> +	0x4b, 0x04,
> +	0x4d, 0x91,
> +	0x5d, 0xc8,
> +	0x50, 0x36,
> +	0x51, 0x36,
> +	0x52, 0x36,
> +	0x53, 0x36,
> +	0x63, 0x0f,
> +	0x64, 0x10,
> +	0x65, 0x20,
> +	0x68, 0x46,
> +	0x69, 0xcd,
> +	0x70, 0x20,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x40,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x60,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x80,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0xa0,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x1f,
> +	0x76, 0x38,
> +	0x77, 0xa6,
> +	0x78, 0x0c,
> +	0x79, 0x80,
> +	0x7f, 0x14,
> +	0x85, 0x08,
> +	0xcd, 0xf4,
> +	0x90, 0x33,
> +	0x86, 0x00,
> +	0x87, 0x0f,
> +	0x89, 0x00,
> +	0x8b, 0x44,
> +	0x8c, 0x66,
> +	0x9d, 0xc1,
> +	0x8a, 0x10,
> +	0xad, 0x40,
> +	0xa0, 0x44,
> +	0xc0, 0x08,
> +	0xc1, 0x10,
> +	0xc2, 0x08,
> +	0xc3, 0x10,
> +	0xc4, 0x08,
> +	0xc5, 0xf0,
> +	0xc6, 0xff,
> +	0xc7, 0x00,
> +	0xc8, 0x1a,
> +	0xc9, 0x80,
> +	0xca, 0x23,
> +	0xcb, 0x24,
> +	0xcc, 0xf4,
> +	0xce, 0x74,
> +	0x00, 0x00,
> +	0xbd, 0x01,
> +	0xb8, 0x00,
> +};
> +
> +/* For M88DS3000 demod dvbs mode.*/
> +static u8 ds3000_dvbs_init_tab[] = {
> +	0x23, 0x05,
> +	0x08, 0x03,
> +	0x0c, 0x02,
> +	0x21, 0x54,
> +	0x25, 0x82,
> +	0x27, 0x31,
> +	0x30, 0x08,
> +	0x31, 0x40,
> +	0x32, 0x32,
> +	0x33, 0x35,
> +	0x35, 0xff,
> +	0x3a, 0x00,
> +	0x37, 0x10,
> +	0x38, 0x10,
> +	0x39, 0x02,
> +	0x42, 0x60,
> +	0x4a, 0x40,
> +	0x4b, 0x04,
> +	0x4d, 0x91,
> +	0x5d, 0xc8,
> +	0x50, 0x77,
> +	0x51, 0x77,
> +	0x52, 0x36,
> +	0x53, 0x36,
> +	0x56, 0x01,
> +	0x63, 0x47,
> +	0x64, 0x30,
> +	0x65, 0x40,
> +	0x68, 0x26,
> +	0x69, 0x4c,
> +	0x70, 0x20,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x40,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x60,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x80,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0xa0,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x1f,
> +	0x76, 0x00,
> +	0x77, 0xd1,
> +	0x78, 0x0c,
> +	0x79, 0x80,
> +	0x7f, 0x04,
> +	0x7c, 0x00,
> +	0x80, 0x86,
> +	0x81, 0xa6,
> +	0x85, 0x04,
> +	0xcd, 0xf4,
> +	0x90, 0x33,
> +	0xa0, 0x44,
> +	0xc0, 0x18,
> +	0xc3, 0x10,
> +	0xc4, 0x08,
> +	0xc5, 0x80,
> +	0xc6, 0x80,
> +	0xc7, 0x0a,
> +	0xc8, 0x1a,
> +	0xc9, 0x80,
> +	0xfe, 0xb6,
> +	0xe0, 0xf8,
> +	0xe6, 0x8b,
> +	0xd0, 0x40,
> +	0xf8, 0x20,
> +	0xfa, 0x0f,
> +	0xad, 0x20,
> +	0xae, 0x07,
> +	0xb8, 0x00,
> +};
> +
> +/* For M88DS3000 demod dvbs2 mode.*/
> +static u8 ds3000_dvbs2_init_tab[] = {
> +	0x23, 0x0f,
> +	0x08, 0x07,
> +	0x0c, 0x02,
> +	0x21, 0x54,
> +	0x25, 0x82,
> +	0x27, 0x31,
> +	0x30, 0x08,
> +	0x31, 0x32,
> +	0x32, 0x32,
> +	0x33, 0x35,
> +	0x35, 0xff,
> +	0x3a, 0x00,
> +	0x37, 0x10,
> +	0x38, 0x10,
> +	0x39, 0x02,
> +	0x42, 0x60,
> +	0x4a, 0x80,
> +	0x4b, 0x04,
> +	0x4d, 0x91,
> +	0x5d, 0x88,
> +	0x50, 0x36,
> +	0x51, 0x36,
> +	0x52, 0x36,
> +	0x53, 0x36,
> +	0x63, 0x60,
> +	0x64, 0x10,
> +	0x65, 0x10,
> +	0x68, 0x04,
> +	0x69, 0x29,
> +	0x70, 0x20,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x40,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x60,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x80,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0xa0,
> +	0x71, 0x70,
> +	0x72, 0x04,
> +	0x73, 0x00,
> +	0x70, 0x1f,
> +	0xa0, 0x44,
> +	0xc0, 0x08,
> +	0xc1, 0x10,
> +	0xc2, 0x08,
> +	0xc3, 0x10,
> +	0xc4, 0x08,
> +	0xc5, 0xf0,
> +	0xc6, 0xf0,
> +	0xc7, 0x0a,
> +	0xc8, 0x1a,
> +	0xc9, 0x80,
> +	0xca, 0x23,
> +	0xcb, 0x24,
> +	0xce, 0x74,
> +	0x56, 0x01,
> +	0x90, 0x03,
> +	0x76, 0x80,
> +	0x77, 0x42,
> +	0x78, 0x0a,
> +	0x79, 0x80,
> +	0xad, 0x40,
> +	0xae, 0x07,
> +	0x7f, 0xd4,
> +	0x7c, 0x00,
> +	0x80, 0xa8,
> +	0x81, 0xda,
> +	0x7c, 0x01,
> +	0x80, 0xda,
> +	0x81, 0xec,
> +	0x7c, 0x02,
> +	0x80, 0xca,
> +	0x81, 0xeb,
> +	0x7c, 0x03,
> +	0x80, 0xba,
> +	0x81, 0xdb,
> +	0x85, 0x08,
> +	0x86, 0x00,
> +	0x87, 0x02,
> +	0x89, 0x80,
> +	0x8b, 0x44,
> +	0x8c, 0xaa,
> +	0x8a, 0x10,
> +	0xba, 0x00,
> +	0xf5, 0x04,
> +	0xd2, 0x32,
> +	0xb8, 0x00,
> +};
> +
> +struct m88ds3103_state {
> +	struct i2c_adapter *i2c;
> +	const struct m88ds3103_config *config;
> +	
> +	struct dvb_frontend frontend;
> +	
> +	u32 preBer;
> +	u8 skip_fw_load;	
> +	u8 first_lock; /* The first time of signal lock */
> +	u16 demod_id; /* demod chip type */
> +	u16 tuner_id; /* tuner chip type */
> +	fe_delivery_system_t delivery_system;
> +};
> +
> +/*demod register operations.*/
> +static int m88ds3103_writereg(struct m88ds3103_state *state, int reg, int data)
> +{
> +	u8 buf[] = { reg, data };
> +	struct i2c_msg msg = { .addr = state->config->demod_address,
> +		.flags = 0, .buf = buf, .len = 2 };
> +	int err;
> +
> +	if (debug > 1)
> +		printk("m88ds3103: %s: write reg 0x%02x, value 0x%02x\n",
> +			__func__, reg, data);
> +
> +	err = i2c_transfer(state->i2c, &msg, 1);
> +	if (err != 1) {
> +		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x,"
> +			 " value == 0x%02x)\n", __func__, err, reg, data);
> +		return -EREMOTEIO;
> +	}
> +	return 0;
> +}
> +
> +static int m88ds3103_readreg(struct m88ds3103_state *state, u8 reg)
> +{
> +	int ret;
> +	u8 b0[] = { reg };
> +	u8 b1[] = { 0 };
> +	struct i2c_msg msg[] = {
> +		{ .addr = state->config->demod_address, .flags = 0,
> +			.buf = b0, .len = 1 },
> +		{ .addr = state->config->demod_address, .flags = I2C_M_RD,
> +			.buf = b1, .len = 1 }
> +	};
> +	ret = i2c_transfer(state->i2c, msg, 2);
> +
> +	if (ret != 2) {
> +		printk(KERN_ERR "%s: reg=0x%x (error=%d)\n",
> +			__func__, reg, ret);
> +		return ret;
> +	}
> +
> +	if (debug > 1)
> +		printk(KERN_INFO "m88ds3103: read reg 0x%02x, value 0x%02x\n",
> +			reg, b1[0]);
> +
> +	return b1[0];
> +}
> +
> +/*tuner register operations.*/
> +static int m88ds3103_tuner_writereg(struct m88ds3103_state *state, int reg, int data)
> +{
> +	u8 buf[] = { reg, data };
> +	struct i2c_msg msg = { .addr = 0x60,
> +		.flags = 0, .buf = buf, .len = 2 };
> +	int err;
> +
> +	m88ds3103_writereg(state, 0x03, 0x11);
> +	err = i2c_transfer(state->i2c, &msg, 1);
> +	
> +	if (err != 1) {
> +		printk("%s: writereg error(err == %i, reg == 0x%02x,"
> +			 " value == 0x%02x)\n", __func__, err, reg, data);
> +		return -EREMOTEIO;
> +	}
> +
> +	return 0;
> +}
> +
> +static int m88ds3103_tuner_readreg(struct m88ds3103_state *state, u8 reg)
> +{
> +	int ret;
> +	u8 b0[] = { reg };
> +	u8 b1[] = { 0 };
> +	struct i2c_msg msg[] = {
> +		{ .addr = 0x60, .flags = 0,
> +			.buf = b0, .len = 1 },
> +		{ .addr = 0x60, .flags = I2C_M_RD,
> +			.buf = b1, .len = 1 }
> +	};
> +
> +	m88ds3103_writereg(state, 0x03, 0x11);	
> +	ret = i2c_transfer(state->i2c, msg, 2);
> +
> +	if (ret != 2) {
> +		printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);
> +		return ret;
> +	}
> +
> +	return b1[0];
> +}
> +
> +/* Bulk demod I2C write, for firmware download. */
> +static int m88ds3103_writeregN(struct m88ds3103_state *state, int reg,
> +				const u8 *data, u16 len)
> +{
> +	int ret = -EREMOTEIO;
> +	struct i2c_msg msg;
> +	u8 *buf;
> +
> +	buf = kmalloc(len + 1, GFP_KERNEL);
> +	if (buf == NULL) {
> +		printk("Unable to kmalloc\n");
> +		ret = -ENOMEM;
> +		goto error;
> +	}
> +
> +	*(buf) = reg;
> +	memcpy(buf + 1, data, len);
> +
> +	msg.addr = state->config->demod_address;
> +	msg.flags = 0;
> +	msg.buf = buf;
> +	msg.len = len + 1;
> +
> +	if (debug > 1)
> +		printk(KERN_INFO "m88ds3103: %s:  write regN 0x%02x, len = %d\n",
> +			__func__, reg, len);
> +
> +	ret = i2c_transfer(state->i2c, &msg, 1);
> +	if (ret != 1) {
> +		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n",
> +			 __func__, ret, reg);
> +		ret = -EREMOTEIO;
> +	}
> +	
> +error:
> +	kfree(buf);
> +
> +	return ret;
> +}
> +
> +static int m88ds3103_load_firmware(struct dvb_frontend *fe)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	const struct firmware *fw;
> +	int i, ret = 0;
> +
> +	dprintk("%s()\n", __func__);
> +		
> +	if (state->skip_fw_load)
> +		return 0;
> +	/* Load firmware */
> +	/* request the firmware, this will block until someone uploads it */	
> +	if(state->demod_id == DS3000_ID){
> +		printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__,
> +				DS3000_DEFAULT_FIRMWARE);		
> +		ret = request_firmware(&fw, DS3000_DEFAULT_FIRMWARE,
> +					state->i2c->dev.parent);
> +	}else if(state->demod_id == DS3103_ID){
> +		printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__,
> +				DS3103_DEFAULT_FIRMWARE);
> +		ret = request_firmware(&fw, DS3103_DEFAULT_FIRMWARE,
> +					state->i2c->dev.parent);
> +	}
> +	
> +	printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__);
> +	if (ret) {
> +		printk(KERN_ERR "%s: No firmware uploaded (timeout or file not "
> +				"found?)\n", __func__);
> +		return ret;
> +	}
> +
> +	/* Make sure we don't recurse back through here during loading */
> +	state->skip_fw_load = 1;
> +
> +	dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
> +			fw->size,
> +			fw->data[0],
> +			fw->data[1],
> +			fw->data[fw->size - 2],
> +			fw->data[fw->size - 1]);
> +			
> +	/* stop internal mcu. */
> +	m88ds3103_writereg(state, 0xb2, 0x01);
> +	/* split firmware to download.*/
> +	for(i = 0; i < FW_DOWN_LOOP; i++){
> +		ret = m88ds3103_writeregN(state, 0xb0, &(fw->data[FW_DOWN_SIZE*i]), FW_DOWN_SIZE);
> +		if(ret != 1) break;		
> +	}
> +	/* start internal mcu. */
> +	if(ret == 1)
> +		m88ds3103_writereg(state, 0xb2, 0x00);
> +		
> +	release_firmware(fw);
> +
> +	dprintk("%s: Firmware upload %s\n", __func__,
> +			ret == 1 ? "complete" : "failed");
> +
> +	if(ret == 1) ret = 0;
> +	
> +	/* Ensure firmware is always loaded if required */
> +	state->skip_fw_load = 0;
> +
> +	return ret;
> +}
> +
> +
> +static int m88ds3103_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	u8 data;
> +
> +	dprintk("%s(%d)\n", __func__, voltage);
> +
> +	dprintk("m88ds3103:pin_ctrl = (%02x)\n", state->config->pin_ctrl);
> +	
> +	if(state->config->set_voltage)
> +		state->config->set_voltage(fe, voltage);
> +	
> +	data = m88ds3103_readreg(state, 0xa2);
> +	
> +        if(state->config->pin_ctrl & 0x80){ /*If control pin is assigned.*/
> +	        data &= ~0x03; /* bit0 V/H, bit1 off/on */
> +	        if(state->config->pin_ctrl & 0x02)
> +		     data |= 0x02;
> +
> +	        switch (voltage) {
> +	        case SEC_VOLTAGE_18:
> +		     if((state->config->pin_ctrl & 0x01) == 0)
> +			  data |= 0x01;
> +		     break;
> +	        case SEC_VOLTAGE_13:
> +		     if(state->config->pin_ctrl & 0x01)
> +			  data |= 0x01;
> +		     break;
> +	        case SEC_VOLTAGE_OFF:
> +		     if(state->config->pin_ctrl & 0x02)
> +			   data &= ~0x02;			
> +		     else
> +			   data |= 0x02;
> +		     break;
> +	         }
> +        }
> +
> +	m88ds3103_writereg(state, 0xa2, data);
> +
> +	return 0;
> +}
> +
> +static int m88ds3103_read_status(struct dvb_frontend *fe, fe_status_t* status)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	int lock = 0;
> +	
> +	*status = 0;
> +	
> +	switch (state->delivery_system){
> +	case SYS_DVBS:
> +		lock = m88ds3103_readreg(state, 0xd1);
> +		dprintk("%s: SYS_DVBS status=%x.\n", __func__, lock);
> +		
> +		if ((lock & 0x07) == 0x07){
> +			/*if((m88ds3103_readreg(state, 0x0d) & 0x07) == 0x07)*/
> +				*status = FE_HAS_SIGNAL | FE_HAS_CARRIER 
> +					| FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
> +			
> +		}
> +		break;
> +	case SYS_DVBS2:
> +		lock = m88ds3103_readreg(state, 0x0d);
> +		dprintk("%s: SYS_DVBS2 status=%x.\n", __func__, lock);
> +
> +		if ((lock & 0x8f) == 0x8f)
> +			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER 
> +				| FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
> +			
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return 0;
> +}
> +
> +static int m88ds3103_read_ber(struct dvb_frontend *fe, u32* ber)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	u8 tmp1, tmp2, tmp3;
> +	u32 ldpc_frame_cnt, pre_err_packags, code_rate_fac = 0;
> +
> +	dprintk("%s()\n", __func__);
> +
> +	switch (state->delivery_system) {
> +	case SYS_DVBS:
> +		m88ds3103_writereg(state, 0xf9, 0x04);
> +		tmp3 = m88ds3103_readreg(state, 0xf8);
> +		if ((tmp3&0x10) == 0){
> +			tmp1 = m88ds3103_readreg(state, 0xf7);
> +			tmp2 = m88ds3103_readreg(state, 0xf6);
> +			tmp3 |= 0x10;
> +			m88ds3103_writereg(state, 0xf8, tmp3);
> +			state->preBer = (tmp1<<8) | tmp2;
> +		}
> +		break;
> +	case SYS_DVBS2:
> +		tmp1 = m88ds3103_readreg(state, 0x7e) & 0x0f;
> +		switch(tmp1){
> +		case 0:	code_rate_fac = 16008 - 80; break;
> +		case 1:	code_rate_fac = 21408 - 80; break;
> +		case 2:	code_rate_fac = 25728 - 80; break;
> +		case 3:	code_rate_fac = 32208 - 80; break;
> +		case 4:	code_rate_fac = 38688 - 80; break;
> +		case 5:	code_rate_fac = 43040 - 80; break;
> +		case 6:	code_rate_fac = 48408 - 80; break;
> +		case 7:	code_rate_fac = 51648 - 80; break;
> +		case 8:	code_rate_fac = 53840 - 80; break;
> +		case 9:	code_rate_fac = 57472 - 80; break;
> +		case 10: code_rate_fac = 58192 - 80; break;
> +		}
> +		
> +		tmp1 = m88ds3103_readreg(state, 0xd7) & 0xff;
> +		tmp2 = m88ds3103_readreg(state, 0xd6) & 0xff;
> +		tmp3 = m88ds3103_readreg(state, 0xd5) & 0xff;		
> +		ldpc_frame_cnt = (tmp1 << 16) | (tmp2 << 8) | tmp3;
> +
> +		tmp1 = m88ds3103_readreg(state, 0xf8) & 0xff;
> +		tmp2 = m88ds3103_readreg(state, 0xf7) & 0xff;
> +		pre_err_packags = tmp1<<8 | tmp2;
> +		
> +		if (ldpc_frame_cnt > 1000){
> +			m88ds3103_writereg(state, 0xd1, 0x01);
> +			m88ds3103_writereg(state, 0xf9, 0x01);
> +			m88ds3103_writereg(state, 0xf9, 0x00);
> +			m88ds3103_writereg(state, 0xd1, 0x00);
> +			state->preBer = pre_err_packags;
> +		} 				
> +		break;
> +	default:
> +		break;
> +	}
> +	*ber = state->preBer;
> +	
> +	return 0;
> +}
> +
> +static int m88ds3103_read_signal_strength(struct dvb_frontend *fe,
> +						u16 *signal_strength)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	u16 gain;
> +	u8 gain1, gain2, gain3 = 0;
> +
> +	dprintk("%s()\n", __func__);
> +
> +	gain1 = m88ds3103_tuner_readreg(state, 0x3d) & 0x1f;
> +	dprintk("%s: gain1 = 0x%02x \n", __func__, gain1);
> +	
> +	if (gain1 > 15) gain1 = 15;
> +	gain2 = m88ds3103_tuner_readreg(state, 0x21) & 0x1f;
> +	dprintk("%s: gain2 = 0x%02x \n", __func__, gain2);
> +	
> +	if(state->tuner_id == TS2022_ID){
> +		gain3 = (m88ds3103_tuner_readreg(state, 0x66)>>3) & 0x07;
> +		dprintk("%s: gain3 = 0x%02x \n", __func__, gain3);
> +		
> +		if (gain2 > 16) gain2 = 16;
> +		if (gain2 < 2) gain2 = 2;			
> +		if (gain3 > 6) gain3 = 6;
> +	}else{
> +		if (gain2 > 13) gain2 = 13;
> +		gain3 = 0;
> +	}
> +
> +	gain = gain1*23 + gain2*35 + gain3*29;
> +	*signal_strength = 60000 - gain*55;
> +
> +	return 0;
> +}
> +
> +
> +static int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *p_snr)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	u8 val, npow1, npow2, spow1, cnt;
> +	u16 tmp, snr;
> +	u32 npow, spow, snr_total;	
> +	static const u16 mes_log10[] ={
> +		0,	3010,	4771,	6021, 	6990,	7781,	8451,	9031,	9542,	10000,
> +		10414,	10792,	11139,	11461,	11761,	12041,	12304,	12553,	12788,	13010,
> +		13222,	13424,	13617,	13802,	13979,	14150,	14314,	14472,	14624,	14771,
> +		14914,	15052,	15185,	15315,	15441,	15563,	15682,	15798,	15911,	16021,
> +		16128,	16232,	16335,	16435,	16532,	16628,	16721,	16812,	16902,	16990,
> +		17076,	17160,	17243,	17324,	17404,	17482,	17559,	17634,	17709,	17782,
> +		17853,	17924,	17993,	18062,	18129,	18195,	18261,	18325,	18388,	18451,
> +		18513,	18573,	18633,	18692,	18751,	18808,	18865,	18921,	18976,	19031
> +	};
> +	static const u16 mes_loge[] ={
> +		0,	6931,	10986,	13863, 	16094,	17918,	19459,	20794,	21972,	23026,
> +		23979,	24849,	25649,	26391,	27081,	27726,	28332,	28904,	29444,	29957,
> +		30445,	30910,	31355,	31781,	32189,	32581,	32958,	33322,	33673,	34012,
> +		34340,	34657,
> +	};
> +
> +	dprintk("%s()\n", __func__);
> +
> +	snr = 0;
> +	
> +	switch (state->delivery_system){
> +	case SYS_DVBS:
> +		cnt = 10; snr_total = 0;
> +		while(cnt > 0){
> +			val = m88ds3103_readreg(state, 0xff);
> +			snr_total += val;
> +			cnt--;
> +		}
> +		tmp = (u16)(snr_total/80);
> +		if(tmp > 0){
> +			if (tmp > 32) tmp = 32;
> +			snr = (mes_loge[tmp - 1] * 100) / 45;
> +		}else{
> +			snr = 0;
> +		}
> +		break;
> +	case SYS_DVBS2:
> +		cnt  = 10; npow = 0; spow = 0;
> +		while(cnt >0){
> +			npow1 = m88ds3103_readreg(state, 0x8c) & 0xff;
> +			npow2 = m88ds3103_readreg(state, 0x8d) & 0xff;
> +			npow += (((npow1 & 0x3f) + (u16)(npow2 << 6)) >> 2);
> +
> +			spow1 = m88ds3103_readreg(state, 0x8e) & 0xff;
> +			spow += ((spow1 * spow1) >> 1);
> +			cnt--;
> +		}
> +		npow /= 10; spow /= 10;
> +		if(spow == 0){
> +			snr = 0;
> +		}else if(npow == 0){
> +			snr = 19;
> +		}else{
> +			if(spow > npow){
> +				tmp = (u16)(spow / npow);
> +				if (tmp > 80) tmp = 80;
> +				snr = mes_log10[tmp - 1]*3;
> +			}else{
> +				tmp = (u16)(npow / spow);
> +				if (tmp > 80) tmp = 80;
> +				snr = -(mes_log10[tmp - 1] / 1000);
> +			}
> +		}			
> +		break;
> +	default:
> +		break;
> +	}
> +	*p_snr = snr;
> +
> +	return 0;
> +}
> +
> +
> +static int m88ds3103_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	u8 tmp1, tmp2, tmp3, data;
> +
> +	dprintk("%s()\n", __func__);
> +
> +	switch (state->delivery_system) {
> +	case SYS_DVBS:
> +		data = m88ds3103_readreg(state, 0xf8);
> +		data |= 0x40;
> +		m88ds3103_writereg(state, 0xf8, data);		
> +		tmp1 = m88ds3103_readreg(state, 0xf5);
> +		tmp2 = m88ds3103_readreg(state, 0xf4);
> +		*ucblocks = (tmp1 <<8) | tmp2;		
> +		data &= ~0x20;
> +		m88ds3103_writereg(state, 0xf8, data);
> +		data |= 0x20;
> +		m88ds3103_writereg(state, 0xf8, data);
> +		data &= ~0x40;
> +		m88ds3103_writereg(state, 0xf8, data);
> +		break;
> +	case SYS_DVBS2:
> +		tmp1 = m88ds3103_readreg(state, 0xda);
> +		tmp2 = m88ds3103_readreg(state, 0xd9);
> +		tmp3 = m88ds3103_readreg(state, 0xd8);
> +		*ucblocks = (tmp1 <<16)|(tmp2 <<8)|tmp3;
> +		data = m88ds3103_readreg(state, 0xd1);
> +		data |= 0x01;
> +		m88ds3103_writereg(state, 0xd1, data);
> +		data &= ~0x01;
> +		m88ds3103_writereg(state, 0xd1, data);
> +		break;
> +	default:
> +		break;
> +	}
> +	return 0;
> +}
> +
> +static int m88ds3103_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	u8 data_a1, data_a2;
> +
> +	dprintk("%s(%d)\n", __func__, tone);
> +	if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
> +		printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
> +		return -EINVAL;
> +	}
> +
> +	data_a1 = m88ds3103_readreg(state, 0xa1);
> +	data_a2 = m88ds3103_readreg(state, 0xa2);
> +	if(state->demod_id == DS3103_ID)
> +		data_a2 &= 0xdf; /* Normal mode */
> +	switch (tone) {
> +	case SEC_TONE_ON:
> +		dprintk("%s: SEC_TONE_ON\n", __func__);
> +		data_a1 |= 0x04;
> +		data_a1 &= ~0x03;
> +		data_a1 &= ~0x40;
> +		data_a2 &= ~0xc0;
> +		break;
> +	case SEC_TONE_OFF:
> +		dprintk("%s: SEC_TONE_OFF\n", __func__);
> +		data_a2 &= ~0xc0;
> +		data_a2 |= 0x80;
> +		break;
> +	}
> +	m88ds3103_writereg(state, 0xa2, data_a2);
> +	m88ds3103_writereg(state, 0xa1, data_a1);
> +	return 0;
> +}
> +
> +static int m88ds3103_send_diseqc_msg(struct dvb_frontend *fe,
> +				struct dvb_diseqc_master_cmd *d)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	int i, ret = 0;
> +	u8 tmp, time_out;
> +
> +	/* Dump DiSEqC message */
> +	if (debug) {
> +		printk(KERN_INFO "m88ds3103: %s(", __func__);
> +		for (i = 0 ; i < d->msg_len ;) {
> +			printk(KERN_INFO "0x%02x", d->msg[i]);
> +			if (++i < d->msg_len)
> +				printk(KERN_INFO ", ");
> +		}
> +	}
> +
> +	tmp = m88ds3103_readreg(state, 0xa2);
> +	tmp &= ~0xc0;
> +	if(state->demod_id == DS3103_ID)
> +		tmp &= ~0x20;
> +	m88ds3103_writereg(state, 0xa2, tmp);
> +	
> +	for (i = 0; i < d->msg_len; i ++)
> +		m88ds3103_writereg(state, (0xa3+i), d->msg[i]);
> +
> +	tmp = m88ds3103_readreg(state, 0xa1);	
> +	tmp &= ~0x38;
> +	tmp &= ~0x40;
> +	tmp |= ((d->msg_len-1) << 3) | 0x07;
> +	tmp &= ~0x80;
> +	m88ds3103_writereg(state, 0xa1, tmp);
> +	/*	1.5 * 9 * 8	= 108ms	*/
> +	time_out = 150;
> +	while (time_out > 0){
> +		msleep(10);
> +		time_out -= 10;
> +		tmp = m88ds3103_readreg(state, 0xa1);		
> +		if ((tmp & 0x40) == 0)
> +			break;
> +	}
> +	if (time_out == 0){
> +		tmp = m88ds3103_readreg(state, 0xa1);
> +		tmp &= ~0x80;
> +		tmp |= 0x40;
> +		m88ds3103_writereg(state, 0xa1, tmp);
> +		ret = 1;
> +	}
> +	tmp = m88ds3103_readreg(state, 0xa2);
> +	tmp &= ~0xc0;
> +	tmp |= 0x80;
> +	m88ds3103_writereg(state, 0xa2, tmp);	
> +	return ret;
> +}
> +
> +
> +static int m88ds3103_diseqc_send_burst(struct dvb_frontend *fe,
> +					fe_sec_mini_cmd_t burst)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	u8	val, time_out;
> +	
> +	dprintk("%s()\n", __func__);
> +
> +	val = m88ds3103_readreg(state, 0xa2);
> +	val &= ~0xc0;
> +	if(state->demod_id == DS3103_ID)
> +		val &= 0xdf; /* Normal mode */
> +	m88ds3103_writereg(state, 0xa2, val);
> +	/* DiSEqC burst */
> +	if (burst == SEC_MINI_B)
> +		m88ds3103_writereg(state, 0xa1, 0x01);
> +	else
> +		m88ds3103_writereg(state, 0xa1, 0x02);
> +
> +	msleep(13);
> +
> +	time_out = 5;
> +	do{
> +		val = m88ds3103_readreg(state, 0xa1);
> +		if ((val & 0x40) == 0)
> +			break;
> +		msleep(1);
> +		time_out --;
> +	} while (time_out > 0);
> +
> +	val = m88ds3103_readreg(state, 0xa2);
> +	val &= ~0xc0;
> +	val |= 0x80;
> +	m88ds3103_writereg(state, 0xa2, val);
> +	
> +	return 0;
> +}
> +
> +static void m88ds3103_release(struct dvb_frontend *fe)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +
> +	dprintk("%s\n", __func__);
> +	kfree(state);
> +}
> +
> +static int m88ds3103_check_id(struct m88ds3103_state *state)
> +{
> +	int val_00, val_01;
> +	
> +	/*check demod id*/
> +	val_01 = m88ds3103_readreg(state, 0x01);
> +	printk(KERN_INFO "DS3000 chip version: %x attached.\n", val_01);
> +			
> +	if(val_01 == 0xD0)
> +		state->demod_id = DS3103_ID;
> +	else if(val_01 == 0xC0)
> +		state->demod_id = DS3000_ID;
> +	else
> +		state->demod_id = UNKNOW_ID;
> +		
> +	/*check tuner id*/
> +	val_00 = m88ds3103_tuner_readreg(state, 0x00);
> +	printk(KERN_INFO "TS202x chip version[1]: %x attached.\n", val_00);
> +	val_00 &= 0x03;
> +	if(val_00 == 0)
> +	{
> +		m88ds3103_tuner_writereg(state, 0x00, 0x01);
> +		msleep(3);		
> +	}
> +	m88ds3103_tuner_writereg(state, 0x00, 0x03);
> +	msleep(5);
> +	
> +	val_00 = m88ds3103_tuner_readreg(state, 0x00);
> +	printk(KERN_INFO "TS202x chip version[2]: %x attached.\n", val_00);
> +	val_00 &= 0xff;
> +	if((val_00 == 0x01) || (val_00 == 0x41) || (val_00 == 0x81))
> +		state->tuner_id = TS2020_ID;
> +	else if(((val_00 & 0xc0)== 0xc0) || (val_00 == 0x83))
> +		state->tuner_id = TS2022_ID;
> +	else
> +		state->tuner_id = UNKNOW_ID;
> +			
> +	return state->demod_id;	
> +}
> +
> +static struct dvb_frontend_ops m88ds3103_ops;
> +static int m88ds3103_initilaze(struct dvb_frontend *fe);
> +
> +struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *config,
> +				    struct i2c_adapter *i2c)
> +{
> +	struct m88ds3103_state *state = NULL;
> +
> +	dprintk("%s\n", __func__);
> +
> +	/* allocate memory for the internal state */
> +	state = kzalloc(sizeof(struct m88ds3103_state), GFP_KERNEL);
> +	if (state == NULL) {
> +		printk(KERN_ERR "Unable to kmalloc\n");
> +		goto error2;
> +	}
> +
> +	state->config = config;
> +	state->i2c = i2c;
> +	state->preBer = 0xffff;
> +	state->delivery_system = SYS_DVBS; /*Default to DVB-S.*/
> +	
> +	/* check demod id */
> +	if(m88ds3103_check_id(state) == UNKNOW_ID){
> +		printk(KERN_ERR "Unable to find Montage chip\n");
> +		goto error3;
> +	}
> +
> +	memcpy(&state->frontend.ops, &m88ds3103_ops,
> +			sizeof(struct dvb_frontend_ops));
> +	state->frontend.demodulator_priv = state;
> +	
> +	m88ds3103_initilaze(&state->frontend);
> +	
> +	return &state->frontend;
> +
> +error3:
> +	kfree(state);
> +error2:
> +	return NULL;
> +}
> +EXPORT_SYMBOL(m88ds3103_attach);
> +
> +static int m88ds3103_set_carrier_offset(struct dvb_frontend *fe,
> +					s32 carrier_offset_khz)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	s32 tmp;
> +
> +	tmp = carrier_offset_khz;
> +	tmp *= 65536;
> +	
> +	tmp = (2*tmp + MT_FE_MCLK_KHZ) / (2*MT_FE_MCLK_KHZ);
> +
> +	if (tmp < 0)
> +		tmp += 65536;
> +
> +	m88ds3103_writereg(state, 0x5f, tmp >> 8);
> +	m88ds3103_writereg(state, 0x5e, tmp & 0xff);
> +
> +	return 0;
> +}
> +
> +static int m88ds3103_set_symrate(struct dvb_frontend *fe)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
> +	u16 value;
> +	
> +	value = (((c->symbol_rate / 1000) << 15) + (MT_FE_MCLK_KHZ / 4)) / (MT_FE_MCLK_KHZ / 2);
> +	m88ds3103_writereg(state, 0x61, value & 0x00ff);
> +	m88ds3103_writereg(state, 0x62, (value & 0xff00) >> 8);
> +
> +	return 0;
> +}
> +
> +static int m88ds3103_set_CCI(struct dvb_frontend *fe)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	u8 tmp;
> +
> +	tmp = m88ds3103_readreg(state, 0x56);
> +	tmp &= ~0x01;
> +	m88ds3103_writereg(state, 0x56, tmp);
> +
> +	tmp = m88ds3103_readreg(state, 0x76);
> +	tmp &= ~0x80;
> +	m88ds3103_writereg(state, 0x76, tmp);
> +
> +	return 0;
> +}
> +
> +static int m88ds3103_init_reg(struct m88ds3103_state *state, const u8 *p_reg_tab, u32 size)
> +{
> +	u32 i;
> +	
> +	for(i = 0; i < size; i+=2)
> +		m88ds3103_writereg(state, p_reg_tab[i], p_reg_tab[i+1]);
> +		
> +	return 0;
> +}
> +
> +static int m88ds3103_demod_connect(struct dvb_frontend *fe, s32 carrier_offset_khz) 
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
> +	u16 value;
> +	u8 val1,val2,data;
> +	
> +	dprintk("connect delivery system = %d\n", state->delivery_system);
> +	
> +	/* ds3000 global reset */
> +	m88ds3103_writereg(state, 0x07, 0x80);
> +	m88ds3103_writereg(state, 0x07, 0x00);
> +	/* ds3000 build-in uC reset */
> +	m88ds3103_writereg(state, 0xb2, 0x01);
> +	/* ds3000 software reset */
> +	m88ds3103_writereg(state, 0x00, 0x01);
> +
> +	switch (state->delivery_system) {
> +	case SYS_DVBS:
> +		/* initialise the demod in DVB-S mode */
> +		if(state->demod_id == DS3000_ID){
> +			m88ds3103_init_reg(state, ds3000_dvbs_init_tab, sizeof(ds3000_dvbs_init_tab));
> +			
> +			value = m88ds3103_readreg(state, 0xfe);
> +			value &= 0xc0;
> +			value |= 0x1b;
> +			m88ds3103_writereg(state, 0xfe, value);
> +			
> +			if(state->config->ci_mode)
> +				val1 = 0x80;
> +			else if(state->config->ts_mode)
> +				val1 = 0x60;
> +			else
> +				val1 = 0x20;
> +			m88ds3103_writereg(state, 0xfd, val1);
> +			
> +		}else if(state->demod_id == DS3103_ID){
> +			m88ds3103_init_reg(state, ds3103_dvbs_init_tab, sizeof(ds3103_dvbs_init_tab));
> +			
> +			/* set ts clock */
> +			if(state->config->ts_mode == 0)	{
> +				val1 = 3; val2 = 3;
> +			}else{
> +				val1 = 0; val2 = 0;
> +			}
> +			val1 -= 1; val2 -= 1;
> +			val1 &= 0x3f; val2 &= 0x3f;
> +			data = m88ds3103_readreg(state, 0xfe);
> +			data &= 0xf0;
> +			data |= (val2 >> 2) & 0x0f;
> +			m88ds3103_writereg(state, 0xfe, data);
> +			data = (val2 & 0x03) << 6;
> +			data |= val1;
> +			m88ds3103_writereg(state, 0xea, data);
> +			
> +			m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d));
> +			m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30));
> +			
> +			/* set master clock */
> +			val1 = m88ds3103_readreg(state, 0x22);
> +			val2 = m88ds3103_readreg(state, 0x24);
> +			
> +			val1 &= 0x3f;
> +			val2 &= 0x3f;
> +			val1 |= 0x80;
> +			val2 |= 0x40;
> +
> +			m88ds3103_writereg(state, 0x22, val1);
> +			m88ds3103_writereg(state, 0x24, val2);	
> +			
> +			if(state->config->ci_mode)
> +				val1 = 0x03;
> +			else if(state->config->ts_mode)
> +				val1 = 0x06;
> +			else
> +				val1 = 0x42;
> +			m88ds3103_writereg(state, 0xfd, val1);		
> +		}
> +		break;
> +	case SYS_DVBS2:
> +		/* initialise the demod in DVB-S2 mode */
> +		if(state->demod_id == DS3000_ID){
> +			m88ds3103_init_reg(state, ds3000_dvbs2_init_tab, sizeof(ds3000_dvbs2_init_tab));
> +		
> +			if (c->symbol_rate >= 30000000)
> +				m88ds3103_writereg(state, 0xfe, 0x54);
> +			else
> +				m88ds3103_writereg(state, 0xfe, 0x98);
> +								
> +		}else if(state->demod_id == DS3103_ID){
> +			m88ds3103_init_reg(state, ds3103_dvbs2_init_tab, sizeof(ds3103_dvbs2_init_tab));
> +
> +			/* set ts clock */
> +			if(state->config->ts_mode == 0){
> +				val1 = 5; val2 = 4;
> +			}else{
> +				val1 = 0; val2 = 0;
> +			}
> +			val1 -= 1; val2 -= 1;
> +			val1 &= 0x3f; val2 &= 0x3f;
> +			data = m88ds3103_readreg(state, 0xfe);
> +			data &= 0xf0;
> +			data |= (val2 >> 2) & 0x0f;
> +			m88ds3103_writereg(state, 0xfe, data);
> +			data = (val2 & 0x03) << 6;
> +			data |= val1;
> +			m88ds3103_writereg(state, 0xea, data);
> +			
> +			m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d));
> +			m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30));
> +			
> +			/* set master clock */
> +			val1 = m88ds3103_readreg(state, 0x22);
> +			val2 = m88ds3103_readreg(state, 0x24);
> +			
> +			val1 &= 0x3f;
> +			val2 &= 0x3f;
> +			if(state->config->ts_mode == 1){
> +				val1 |= 0x80;
> +				val2 |= 0x40;
> +			}else{
> +				if (c->symbol_rate >= 28000000){
> +					val1 |= 0xc0;
> +				}else if (c->symbol_rate >= 18000000){
> +					val2 |= 0x40;
> +				}else{
> +					val1 |= 0x80;
> +					val2 |= 0x40;
> +				}				
> +			}
> +			m88ds3103_writereg(state, 0x22, val1);
> +			m88ds3103_writereg(state, 0x24, val2);					
> +		}
> +		
> +		if(state->config->ci_mode)
> +			val1 = 0x03;
> +		else if(state->config->ts_mode)
> +			val1 = 0x06;
> +		else
> +			val1 = 0x42;
> +		m88ds3103_writereg(state, 0xfd, val1);
> +		
> +		break;
> +	default:
> +		return 1;
> +	}
> +	/* disable 27MHz clock output */
> +	m88ds3103_writereg(state, 0x29, 0x80);
> +	/* enable ac coupling */
> +	m88ds3103_writereg(state, 0x25, 0x8a);
> +
> +	if ((c->symbol_rate / 1000) <= 3000){
> +		m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 32 * 100 / 64 = 400*/
> +		m88ds3103_writereg(state, 0xc8, 0x20);
> +		m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/
> +		m88ds3103_writereg(state, 0xc7, 0x00);
> +	}else if((c->symbol_rate / 1000) <= 10000){
> +		m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 16 * 100 / 64 = 200*/
> +		m88ds3103_writereg(state, 0xc8, 0x10);
> +		m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/
> +		m88ds3103_writereg(state, 0xc7, 0x00);
> +	}else{
> +		m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 6 * 100 / 64 = 75*/
> +		m88ds3103_writereg(state, 0xc8, 0x06);
> +		m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/
> +		m88ds3103_writereg(state, 0xc7, 0x00);
> +	}
> +
> +	m88ds3103_set_symrate(fe);
> +	
> +	m88ds3103_set_CCI(fe);
> +
> +	m88ds3103_set_carrier_offset(fe, carrier_offset_khz);
> +		
> +	/* ds3000 out of software reset */
> +	m88ds3103_writereg(state, 0x00, 0x00);
> +	/* start ds3000 build-in uC */
> +	m88ds3103_writereg(state, 0xb2, 0x00);	
> +	
> +	return 0;
> +}
> +
> +static int m88ds3103_set_frontend(struct dvb_frontend *fe)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
> +
> +	int i;
> +	fe_status_t status;
> +	u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf, div4, capCode, changePLL;
> +	s32 offset_khz, lpf_offset_KHz;
> +	u16 value, ndiv, lpf_coeff;
> +	u32 f3db, gdiv28, realFreq;
> +	u8 RFgain;
> +
> +	dprintk("%s() ", __func__);
> +	dprintk("c frequency = %d\n", c->frequency);
> +	dprintk("symbol rate = %d\n", c->symbol_rate);
> +	dprintk("delivery system = %d\n", c->delivery_system);
> +	
> +	realFreq = c->frequency;
> +	lpf_offset_KHz = 0;
> +	if(c->symbol_rate < 5000000){
> +		lpf_offset_KHz = FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz;
> +		realFreq += FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz;
> +	}
> +	
> +	if (state->config->set_ts_params)
> +		state->config->set_ts_params(fe, 0);
> +
> +	div4 = 0;
> +	RFgain = 0;
> +	if(state->tuner_id == TS2022_ID){
> +		m88ds3103_tuner_writereg(state, 0x10, 0x0a);
> +		m88ds3103_tuner_writereg(state, 0x11, 0x40);
> +		if (realFreq < 1103000) {
> +			m88ds3103_tuner_writereg(state, 0x10, 0x1b);
> +			div4 = 1;
> +			ndiv = (realFreq * (6 + 8) * 4)/MT_FE_CRYSTAL_KHZ;				
> +		}else {
> +			ndiv = (realFreq * (6 + 8) * 2)/MT_FE_CRYSTAL_KHZ;
> +		}
> +		ndiv = ndiv + ndiv%2;
> +		if(ndiv < 4095)
> +			ndiv = ndiv - 1024;
> +		else if (ndiv < 6143)
> +			ndiv = ndiv + 1024;
> +		else
> +			ndiv = ndiv + 3072;	
> +		
> +		m88ds3103_tuner_writereg(state, 0x01, (ndiv & 0x3f00) >> 8);											
> +	}else{
> +		m88ds3103_tuner_writereg(state, 0x10, 0x00);			
> +		if (realFreq < 1146000){
> +			m88ds3103_tuner_writereg(state, 0x10, 0x11);
> +			div4 = 1;
> +			ndiv = (realFreq * (6 + 8) * 4) / MT_FE_CRYSTAL_KHZ;
> +		}else{
> +			m88ds3103_tuner_writereg(state, 0x10, 0x01);
> +			ndiv = (realFreq * (6 + 8) * 2) / MT_FE_CRYSTAL_KHZ;
> +		}
> +		ndiv = ndiv + ndiv%2;
> +		ndiv = ndiv - 1024;
> +		m88ds3103_tuner_writereg(state, 0x01, (ndiv>>8)&0x0f);
> +	}
> +	/* set pll */
> +	m88ds3103_tuner_writereg(state, 0x02, ndiv & 0x00ff);
> +	m88ds3103_tuner_writereg(state, 0x03, 0x06);
> +	m88ds3103_tuner_writereg(state, 0x51, 0x0f);
> +	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +	m88ds3103_tuner_writereg(state, 0x50, 0x10);
> +	m88ds3103_tuner_writereg(state, 0x50, 0x00);	
> +
> +	if(state->tuner_id == TS2022_ID){
> +		if(( realFreq >= 1650000 ) && (realFreq <= 1850000)){
> +			msleep(5);
> +			value = m88ds3103_tuner_readreg(state, 0x14);
> +			value &= 0x7f;
> +			if(value < 64){
> +				m88ds3103_tuner_writereg(state, 0x10, 0x82);
> +				m88ds3103_tuner_writereg(state, 0x11, 0x6f);
> +
> +				m88ds3103_tuner_writereg(state, 0x51, 0x0f);
> +				m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +				m88ds3103_tuner_writereg(state, 0x50, 0x10);
> +				m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +			}
> +		}
> +		msleep(5);
> +		value = m88ds3103_tuner_readreg(state, 0x14);
> +		value &= 0x1f;
> +
> +		if(value > 19){
> +			value = m88ds3103_tuner_readreg(state, 0x10);
> +			value &= 0x1d;
> +			m88ds3103_tuner_writereg(state, 0x10, value);
> +		}				
> +	}else{
> +		msleep(5);
> +		value = m88ds3103_tuner_readreg(state, 0x66);
> +		changePLL = (((value & 0x80) >> 7) != div4);
> +
> +		if(changePLL){
> +			m88ds3103_tuner_writereg(state, 0x10, 0x11);
> +			div4 = 1;
> +			ndiv = (realFreq * (6 + 8) * 4)/MT_FE_CRYSTAL_KHZ;
> +			ndiv = ndiv + ndiv%2;
> +			ndiv = ndiv - 1024;
> +					
> +			m88ds3103_tuner_writereg(state, 0x01, (ndiv>>8) & 0x0f);
> +			m88ds3103_tuner_writereg(state, 0x02, ndiv & 0xff);
> +			
> +			m88ds3103_tuner_writereg(state, 0x51, 0x0f);
> +			m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +			m88ds3103_tuner_writereg(state, 0x50, 0x10);
> +			m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +		}		
> +	}
> +	/*set the RF gain*/
> +	if(state->tuner_id == TS2020_ID)
> +		m88ds3103_tuner_writereg(state, 0x60, 0x79);
> +			
> +	m88ds3103_tuner_writereg(state, 0x51, 0x17);
> +	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +	m88ds3103_tuner_writereg(state, 0x50, 0x08);
> +	m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +	msleep(5);
> +
> +	if(state->tuner_id == TS2020_ID){
> +		RFgain = m88ds3103_tuner_readreg(state, 0x3d);
> +		RFgain &= 0x0f;
> +		if(RFgain < 15){
> +			if(RFgain < 4) 
> +				RFgain = 0;
> +			else
> +				RFgain = RFgain -3;
> +			value = ((RFgain << 3) | 0x01) & 0x79;
> +			m88ds3103_tuner_writereg(state, 0x60, value);
> +			m88ds3103_tuner_writereg(state, 0x51, 0x17);
> +			m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +			m88ds3103_tuner_writereg(state, 0x50, 0x08);
> +			m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +		}
> +	}
> +	
> +	/* set the LPF */
> +	if(state->tuner_id == TS2022_ID){
> +		m88ds3103_tuner_writereg(state, 0x25, 0x00);
> +		m88ds3103_tuner_writereg(state, 0x27, 0x70);
> +		m88ds3103_tuner_writereg(state, 0x41, 0x09);
> +		m88ds3103_tuner_writereg(state, 0x08, 0x0b);
> +	}
> +
> +	f3db = ((c->symbol_rate / 1000) *135) / 200 + 2000;
> +	f3db += lpf_offset_KHz;
> +	if (f3db < 7000)
> +		f3db = 7000;
> +	if (f3db > 40000)
> +		f3db = 40000;
> +			
> +	gdiv28 = (MT_FE_CRYSTAL_KHZ / 1000 * 1694 + 500) / 1000;
> +	m88ds3103_tuner_writereg(state, 0x04, gdiv28 & 0xff);
> +	m88ds3103_tuner_writereg(state, 0x51, 0x1b);
> +	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +	m88ds3103_tuner_writereg(state, 0x50, 0x04);
> +	m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +	msleep(5);
> +
> +	value = m88ds3103_tuner_readreg(state, 0x26);
> +	capCode = value & 0x3f;
> +	if(state->tuner_id == TS2022_ID){
> +		m88ds3103_tuner_writereg(state, 0x41, 0x0d);
> +
> +		m88ds3103_tuner_writereg(state, 0x51, 0x1b);
> +		m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +		m88ds3103_tuner_writereg(state, 0x50, 0x04);
> +		m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +
> +		msleep(2);
> +
> +		value = m88ds3103_tuner_readreg(state, 0x26);
> +		value &= 0x3f;
> +		value = (capCode + value) / 2;		
> +	}
> +	else
> +		value = capCode;
> +		
> +	gdiv28 = gdiv28 * 207 / (value * 2 + 151);	
> +	mlpf_max = gdiv28 * 135 / 100;
> +	mlpf_min = gdiv28 * 78 / 100;
> +	if (mlpf_max > 63)
> +		mlpf_max = 63;
> +
> +	if(state->tuner_id == TS2022_ID)
> +		lpf_coeff = 3200;
> +	else
> +		lpf_coeff = 2766;
> +		
> +	nlpf = (f3db * gdiv28 * 2 / lpf_coeff / (MT_FE_CRYSTAL_KHZ / 1000)  + 1) / 2 ;	
> +	if (nlpf > 23) nlpf = 23;
> +	if (nlpf < 1) nlpf = 1;
> +
> +	lpf_mxdiv = (nlpf * (MT_FE_CRYSTAL_KHZ / 1000) * lpf_coeff * 2 / f3db + 1) / 2;
> +
> +	if (lpf_mxdiv < mlpf_min){
> +		nlpf++;
> +		lpf_mxdiv = (nlpf * (MT_FE_CRYSTAL_KHZ / 1000) * lpf_coeff * 2  / f3db + 1) / 2;
> +	}
> +
> +	if (lpf_mxdiv > mlpf_max)
> +		lpf_mxdiv = mlpf_max;
> +
> +	m88ds3103_tuner_writereg(state, 0x04, lpf_mxdiv);
> +	m88ds3103_tuner_writereg(state, 0x06, nlpf);
> +	m88ds3103_tuner_writereg(state, 0x51, 0x1b);
> +	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +	m88ds3103_tuner_writereg(state, 0x50, 0x04);
> +	m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +	msleep(5);
> +	
> +	if(state->tuner_id == TS2022_ID){
> +		msleep(2);
> +		value = m88ds3103_tuner_readreg(state, 0x26);
> +		capCode = value & 0x3f;
> +
> +		m88ds3103_tuner_writereg(state, 0x41, 0x09);
> +
> +		m88ds3103_tuner_writereg(state, 0x51, 0x1b);
> +		m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +		m88ds3103_tuner_writereg(state, 0x50, 0x04);
> +		m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +
> +		msleep(2);
> +		value = m88ds3103_tuner_readreg(state, 0x26);
> +		value &= 0x3f;
> +		value = (capCode + value) / 2;
> +
> +		value = value | 0x80;
> +		m88ds3103_tuner_writereg(state, 0x25, value);
> +		m88ds3103_tuner_writereg(state, 0x27, 0x30);
> +
> +		m88ds3103_tuner_writereg(state, 0x08, 0x09);		
> +	}
> +
> +	/* Set the BB gain */
> +	m88ds3103_tuner_writereg(state, 0x51, 0x1e);
> +	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +	m88ds3103_tuner_writereg(state, 0x50, 0x01);
> +	m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +	if(state->tuner_id == TS2020_ID){
> +		if(RFgain == 15){
> +			msleep(40);
> +			value = m88ds3103_tuner_readreg(state, 0x21);
> +			value &= 0x0f;
> +			if(value < 3){
> +				m88ds3103_tuner_writereg(state, 0x60, 0x61);
> +				m88ds3103_tuner_writereg(state, 0x51, 0x17);
> +				m88ds3103_tuner_writereg(state, 0x51, 0x1f);
> +				m88ds3103_tuner_writereg(state, 0x50, 0x08);
> +				m88ds3103_tuner_writereg(state, 0x50, 0x00);
> +			}			
> +		}
> +	}
> +	msleep(60);
> +	
> +	offset_khz = (ndiv - ndiv % 2 + 1024) * MT_FE_CRYSTAL_KHZ
> +		/ (6 + 8) / (div4 + 1) / 2 - realFreq;
> +
> +	m88ds3103_demod_connect(fe, offset_khz+lpf_offset_KHz);
> +
> +	for (i = 0; i < 30 ; i++) {
> +		m88ds3103_read_status(fe, &status);
> +		if (status & FE_HAS_LOCK){
> +			break;
> +                }
> +		msleep(20);
> +	}
> +	
> +	if((status & FE_HAS_LOCK) == 0){
> +		state->delivery_system = (state->delivery_system == SYS_DVBS) ? SYS_DVBS2 : SYS_DVBS;
> +		m88ds3103_demod_connect(fe, offset_khz);
> +	
> +		for (i = 0; i < 30 ; i++) {
> +			m88ds3103_read_status(fe, &status);
> +			if (status & FE_HAS_LOCK){
> +				break;
> +                	}
> +			msleep(20);
> +		}
> +	}
> +	
> +	if (status & FE_HAS_LOCK){
> +		if(state->config->start_ctrl){
> +			if(state->first_lock == 0){
> +				state->config->start_ctrl(fe);
> +				state->first_lock = 1;	
> +			}
> +		}		
> +	}
> +		
> +	return 0;
> +}
> +
> +static int m88ds3103_tune(struct dvb_frontend *fe,
> +			bool re_tune,
> +			unsigned int mode_flags,
> +			unsigned int *delay,
> +			fe_status_t *status)
> +{	
> +	*delay = HZ / 5;
> +	
> +	dprintk("%s() ", __func__);
> +	dprintk("re_tune = %d\n", re_tune);
> +	
> +	if (re_tune) {
> +		int ret = m88ds3103_set_frontend(fe);
> +		if (ret)
> +			return ret;
> +	}
> +	
> +	return m88ds3103_read_status(fe, status);
> +}
> +
> +static enum dvbfe_algo m88ds3103_get_algo(struct dvb_frontend *fe)
> +{
> +	return DVBFE_ALGO_HW;
> +}
> + 
> + /*
> + * Power config will reset and load initial firmware if required
> + */
> +static int m88ds3103_initilaze(struct dvb_frontend *fe)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	int ret;
> +
> +	dprintk("%s()\n", __func__);
> +	/* hard reset */
> +	m88ds3103_writereg(state, 0x07, 0x80);
> +	m88ds3103_writereg(state, 0x07, 0x00);
> +	msleep(1);
> +	
> +	m88ds3103_writereg(state, 0x08, 0x01 | m88ds3103_readreg(state, 0x08));
> +	msleep(1);
> +
> +	if(state->tuner_id == TS2020_ID){
> +		/* TS2020 init */
> +		m88ds3103_tuner_writereg(state, 0x42, 0x73);
> +		msleep(2);
> +		m88ds3103_tuner_writereg(state, 0x05, 0x01);
> +		m88ds3103_tuner_writereg(state, 0x62, 0xb5);
> +		m88ds3103_tuner_writereg(state, 0x07, 0x02);
> +		m88ds3103_tuner_writereg(state, 0x08, 0x01);
> +	}
> +	else if(state->tuner_id == TS2022_ID){
> +		/* TS2022 init */
> +		m88ds3103_tuner_writereg(state, 0x62, 0x6c);
> +		msleep(2);
> +		m88ds3103_tuner_writereg(state, 0x42, 0x6c);
> +		msleep(2);
> +		m88ds3103_tuner_writereg(state, 0x7d, 0x9d);
> +		m88ds3103_tuner_writereg(state, 0x7c, 0x9a);
> +		m88ds3103_tuner_writereg(state, 0x7a, 0x76);
> +
> +		m88ds3103_tuner_writereg(state, 0x3b, 0x01);
> +		m88ds3103_tuner_writereg(state, 0x63, 0x88);
> +
> +		m88ds3103_tuner_writereg(state, 0x61, 0x85);
> +		m88ds3103_tuner_writereg(state, 0x22, 0x30);
> +		m88ds3103_tuner_writereg(state, 0x30, 0x40);
> +		m88ds3103_tuner_writereg(state, 0x20, 0x23);
> +		m88ds3103_tuner_writereg(state, 0x24, 0x02);
> +		m88ds3103_tuner_writereg(state, 0x12, 0xa0);	
> +	}
> +		
> +	if(state->demod_id == DS3103_ID){
> +		m88ds3103_writereg(state, 0x07, 0xe0);
> +		m88ds3103_writereg(state, 0x07, 0x00);
> +		msleep(1);		
> +	}
> +	m88ds3103_writereg(state, 0xb2, 0x01);
> +	
> +	/* Load the firmware if required */
> +	ret = m88ds3103_load_firmware(fe);
> +	if (ret != 0){
> +		printk(KERN_ERR "%s: Unable initialize firmware\n", __func__);
> +		return ret;
> +	}
> +	if(state->demod_id == DS3103_ID){
> +		m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d));
> +		m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30));		
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * Initialise or wake up device
> + */
> +static int m88ds3103_initfe(struct dvb_frontend *fe)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +	u8 val;
> +
> +	dprintk("%s()\n", __func__);
> +
> +	/* 1st step to wake up demod */
> +	m88ds3103_writereg(state, 0x08, 0x01 | m88ds3103_readreg(state, 0x08));
> +	m88ds3103_writereg(state, 0x04, 0xfe & m88ds3103_readreg(state, 0x04));
> +	m88ds3103_writereg(state, 0x23, 0xef & m88ds3103_readreg(state, 0x23));
> +	
> +	/* 2nd step to wake up tuner */
> +	val = m88ds3103_tuner_readreg(state, 0x00) & 0xff;
> +	if((val & 0x01) == 0){
> +		m88ds3103_tuner_writereg(state, 0x00, 0x01);
> +		msleep(50);
> +	}
> +	m88ds3103_tuner_writereg(state, 0x00, 0x03);
> +	msleep(50);
> +	
> +	return 0;	
> +}
> +
> +/* Put device to sleep */
> +static int m88ds3103_sleep(struct dvb_frontend *fe)
> +{
> +	struct m88ds3103_state *state = fe->demodulator_priv;
> +
> +	dprintk("%s()\n", __func__);
> +	
> +	/* 1st step to sleep tuner */
> +	m88ds3103_tuner_writereg(state, 0x00, 0x00);
> +	
> +	/* 2nd step to sleep demod */
> +	m88ds3103_writereg(state, 0x08, 0xfe & m88ds3103_readreg(state, 0x08));
> +	m88ds3103_writereg(state, 0x04, 0x01 | m88ds3103_readreg(state, 0x04));
> +	m88ds3103_writereg(state, 0x23, 0x10 | m88ds3103_readreg(state, 0x23));
> +	
> +
> +	return 0;
> +}
> +
> +static struct dvb_frontend_ops m88ds3103_ops = {
> +	.delsys = { SYS_DVBS, SYS_DVBS2},
> +	.info = {
> +		.name = "Montage DS3103/TS2022",
> +		.type = FE_QPSK,
> +		.frequency_min = 950000,
> +		.frequency_max = 2150000,
> +		.frequency_stepsize = 1011, /* kHz for QPSK frontends */
> +		.frequency_tolerance = 5000,
> +		.symbol_rate_min = 1000000,
> +		.symbol_rate_max = 45000000,
> +		.caps = FE_CAN_INVERSION_AUTO |
> +			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
> +			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
> +			FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
> +			FE_CAN_2G_MODULATION |
> +			FE_CAN_QPSK | FE_CAN_RECOVER
> +	},
> +
> +	.release = m88ds3103_release,
> +
> +	.init = m88ds3103_initfe,
> +	.sleep = m88ds3103_sleep,
> +	.read_status = m88ds3103_read_status,
> +	.read_ber = m88ds3103_read_ber,
> +	.read_signal_strength = m88ds3103_read_signal_strength,
> +	.read_snr = m88ds3103_read_snr,
> +	.read_ucblocks = m88ds3103_read_ucblocks,
> +	.set_tone = m88ds3103_set_tone,
> +	.set_voltage = m88ds3103_set_voltage,
> +	.diseqc_send_master_cmd = m88ds3103_send_diseqc_msg,
> +	.diseqc_send_burst = m88ds3103_diseqc_send_burst,
> +	.get_frontend_algo = m88ds3103_get_algo,
> +	.tune = m88ds3103_tune,
> +	.set_frontend = m88ds3103_set_frontend,
> +};
> +
> +MODULE_DESCRIPTION("DVB Frontend module for Montage DS3103/TS2022 hardware");
> +MODULE_AUTHOR("Max nibble");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/media/dvb/frontends/m88ds3103.h b/drivers/media/dvb/frontends/m88ds3103.h
> new file mode 100644
> index 0000000..c7b690e
> --- /dev/null
> +++ b/drivers/media/dvb/frontends/m88ds3103.h
> @@ -0,0 +1,53 @@
> +/*
> +    Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner driver
> +
> +    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 M88DS3103_H
> +#define M88DS3103_H
> +
> +#include <linux/dvb/frontend.h>
> +
> +struct m88ds3103_config {
> +	/* the demodulator's i2c address */
> +	u8 demod_address;
> +	u8 ci_mode;
> +	u8 pin_ctrl;
> +	u8 ts_mode; /* 0: Parallel, 1: Serial */
> +
> +	/* Set device param to start dma */
> +	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
> +    /* Start to transfer data */
> +    int (*start_ctrl)(struct dvb_frontend *fe);
> +    /* Set LNB voltage */
> +    int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
> +};
> +
> +#if defined(CONFIG_DVB_M88DS3103) || \
> +	(defined(CONFIG_DVB_M88DS3103_MODULE) && defined(MODULE))
> +extern struct dvb_frontend *m88ds3103_attach(
> +       const struct m88ds3103_config *config,
> +       struct i2c_adapter *i2c);
> +#else
> +static inline struct dvb_frontend *m88ds3103_attach(
> +       const struct m88ds3103_config *config,
> +       struct i2c_adapter *i2c)
> +{
> +	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
> +	return NULL;
> +}
> +#endif /* CONFIG_DVB_M88DS3103 */
> +#endif /* M88DS3103_H */


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-15 15:53   ` [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver nibble.max
  2012-04-19 18:06     ` Mauro Carvalho Chehab
  2012-04-19 20:08     ` Mauro Carvalho Chehab
@ 2012-04-20  8:01     ` nibble.max
  2012-04-20  9:47       ` Antti Palosaari
  2012-04-20 17:10       ` [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver Mauro Carvalho Chehab
  2 siblings, 2 replies; 56+ messages in thread
From: nibble.max @ 2012-04-20  8:01 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

2012-04-20 15:56:27 nibble.max@gmail.com
At first time, I check it exist so try to patch it.
But with new m88ds3103 features to add and ts2022 tuner include, find it is hard to do simply patch.
It is better to create a new driver for maintain.
>Hi Max,
>
>Em 15-04-2012 12:53, nibble.max escreveu:
>> Montage m88ds3103 demodulator and ts2022 tuner driver.
>
>It was pointed to me that this device were already discussed on:
>
>   http://www.mail-archive.com/linux-media@vger.kernel.org/msg43109.html
>
>If m88ds3103 demod is similar enough to ds3000, it should just add the needed
>bits at the existing driver, and not creating a new driver. 
>
>Thanks,
>Mauro
>
>> 
>> Signed-off-by: Max nibble <nibble.max@gmail.com>
>> ---
>>  drivers/media/dvb/frontends/Kconfig     |    7 +
>>  drivers/media/dvb/frontends/Makefile    |    2 +
>>  drivers/media/dvb/frontends/m88ds3103.c | 1851 +++++++++++++++++++++++++++++++
>>  drivers/media/dvb/frontends/m88ds3103.h |   53 +
>>  4 files changed, 1913 insertions(+)
>>  create mode 100644 drivers/media/dvb/frontends/m88ds3103.c
>>  create mode 100644 drivers/media/dvb/frontends/m88ds3103.h
>> 
>> diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
>> index e11adb6..d2bb312 100644
>> --- a/drivers/media/dvb/frontends/Kconfig
>> +++ b/drivers/media/dvb/frontends/Kconfig
>> @@ -214,6 +214,13 @@ config DVB_CX24116
>>  	help
>>  	  A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
>>  
>> +config DVB_M88DS3103
>> +	tristate "Montage DS3103 based"
>> +	depends on DVB_CORE && I2C
>> +	default m if DVB_FE_CUSTOMISE
>> +	help
>> +	  A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
>> +	  
>>  config DVB_SI21XX
>>  	tristate "Silicon Labs SI21XX based"
>>  	depends on DVB_CORE && I2C
>> diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
>> index 6ca7557..84ddf41 100644
>> --- a/drivers/media/dvb/frontends/Makefile
>> +++ b/drivers/media/dvb/frontends/Makefile
>> @@ -98,5 +98,7 @@ obj-$(CONFIG_DVB_A8293) += a8293.o
>>  obj-$(CONFIG_DVB_TDA10071) += tda10071.o
>>  obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
>>  obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
>> +obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o
>>  obj-$(CONFIG_DVB_AF9033) += af9033.o
>>  
>> +
>> diff --git a/drivers/media/dvb/frontends/m88ds3103.c b/drivers/media/dvb/frontends/m88ds3103.c
>> new file mode 100644
>> index 0000000..a186ba0
>> --- /dev/null
>> +++ b/drivers/media/dvb/frontends/m88ds3103.c
>> @@ -0,0 +1,1851 @@
>> +/*
>> +    Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner driver
>> +
>> +    Copyright (C) 2011 Max nibble<nibble.max@gmail.com>
>> +    Copyright (C) 2010 Montage Technology<www.montage-tech.com>
>> +    Copyright (C) 2009 Konstantin Dimitrov.
>> +
>> +    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/slab.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/moduleparam.h>
>> +#include <linux/init.h>
>> +#include <linux/firmware.h>
>> +
>> +#include "dvb_frontend.h"
>> +#include "m88ds3103.h"
>> +
>> +static int debug;
>> +module_param(debug, int, 0644);
>> +MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
>> +
>> +#define dprintk(args...) \
>> +	do { \
>> +		if (debug) \
>> +			printk(KERN_INFO "m88ds3103: " args); \
>> +	} while (0)
>> +
>> +#define FW_DOWN_SIZE 32
>> +#define FW_DOWN_LOOP (8192/FW_DOWN_SIZE)
>> +#define DS3103_DEFAULT_FIRMWARE "dvb-fe-ds3103.fw"
>> +#define DS3000_DEFAULT_FIRMWARE "dvb-fe-ds300x.fw"
>> +#define MT_FE_MCLK_KHZ 96000 /* in kHz */
>> +#define MT_FE_CRYSTAL_KHZ   27000 /* in kHz */
>> +#define FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz 3000
>> +#define DS3000_ID	0x3000
>> +#define DS3103_ID	0x3103
>> +#define TS2020_ID	0x2020
>> +#define TS2022_ID	0x2022
>> +#define UNKNOW_ID	0x0000
>> +
>> +/* For M88DS3103 demod dvbs mode.*/
>> +static u8 ds3103_dvbs_init_tab[] = {
>> +	0x23, 0x07,
>> +	0x08, 0x03,
>> +	0x0c, 0x02,
>> +	0x21, 0x54,
>> +	0x25, 0x82,
>> +	0x27, 0x31,
>> +	0x30, 0x08,
>> +	0x31, 0x40,
>> +	0x32, 0x32,
>> +	0x33, 0x35,
>> +	0x35, 0xff,
>> +	0x3a, 0x00,
>> +	0x37, 0x10,
>> +	0x38, 0x10,
>> +	0x39, 0x02,
>> +	0x42, 0x60,
>> +	0x4a, 0x80,
>> +	0x4b, 0x04,
>> +	0x4d, 0x91,
>> +	0x5d, 0xc8,
>> +	0x50, 0x36,
>> +	0x51, 0x36,
>> +	0x52, 0x36,
>> +	0x53, 0x36,
>> +	0x63, 0x0f,
>> +	0x64, 0x30,
>> +	0x65, 0x40,
>> +	0x68, 0x26,
>> +	0x69, 0x4c,
>> +	0x70, 0x20,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x40,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x60,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x80,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0xa0,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x1f,
>> +	0x76, 0x38,
>> +	0x77, 0xa6,
>> +	0x78, 0x0c,
>> +	0x79, 0x80,
>> +	0x7f, 0x14,
>> +	0x7c, 0x00,
>> +	0xae, 0x82,
>> +	0x80, 0x64,
>> +	0x81, 0x66,
>> +	0x82, 0x44,
>> +	0x85, 0x04,
>> +	0xcd, 0xf4,
>> +	0x90, 0x33,
>> +	0xa0, 0x44,
>> +	0xc0, 0x08,
>> +	0xc3, 0x10,
>> +	0xc4, 0x08,
>> +	0xc5, 0xf0,
>> +	0xc6, 0xff,
>> +	0xc7, 0x00,
>> +	0xc8, 0x1a,
>> +	0xc9, 0x80,
>> +	0xe0, 0xf8,
>> +	0xe6, 0x8b,
>> +	0xd0, 0x40,
>> +	0xf8, 0x20,
>> +	0xfa, 0x0f,
>> +	0x00, 0x00,
>> +	0xbd, 0x01,
>> +	0xb8, 0x00,
>> +};
>> +/* For M88DS3103 demod dvbs2 mode.*/
>> +static u8 ds3103_dvbs2_init_tab[] = {
>> +	0x23, 0x07,
>> +	0x08, 0x07,
>> +	0x0c, 0x02,
>> +	0x21, 0x54,
>> +	0x25, 0x82,
>> +	0x27, 0x31,
>> +	0x30, 0x08,
>> +	0x32, 0x32,
>> +	0x33, 0x35,
>> +	0x35, 0xff,
>> +	0x3a, 0x00,
>> +	0x37, 0x10,
>> +	0x38, 0x10,
>> +	0x39, 0x02,
>> +	0x42, 0x60,
>> +	0x4a, 0x80,
>> +	0x4b, 0x04,
>> +	0x4d, 0x91,
>> +	0x5d, 0xc8,
>> +	0x50, 0x36,
>> +	0x51, 0x36,
>> +	0x52, 0x36,
>> +	0x53, 0x36,
>> +	0x63, 0x0f,
>> +	0x64, 0x10,
>> +	0x65, 0x20,
>> +	0x68, 0x46,
>> +	0x69, 0xcd,
>> +	0x70, 0x20,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x40,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x60,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x80,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0xa0,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x1f,
>> +	0x76, 0x38,
>> +	0x77, 0xa6,
>> +	0x78, 0x0c,
>> +	0x79, 0x80,
>> +	0x7f, 0x14,
>> +	0x85, 0x08,
>> +	0xcd, 0xf4,
>> +	0x90, 0x33,
>> +	0x86, 0x00,
>> +	0x87, 0x0f,
>> +	0x89, 0x00,
>> +	0x8b, 0x44,
>> +	0x8c, 0x66,
>> +	0x9d, 0xc1,
>> +	0x8a, 0x10,
>> +	0xad, 0x40,
>> +	0xa0, 0x44,
>> +	0xc0, 0x08,
>> +	0xc1, 0x10,
>> +	0xc2, 0x08,
>> +	0xc3, 0x10,
>> +	0xc4, 0x08,
>> +	0xc5, 0xf0,
>> +	0xc6, 0xff,
>> +	0xc7, 0x00,
>> +	0xc8, 0x1a,
>> +	0xc9, 0x80,
>> +	0xca, 0x23,
>> +	0xcb, 0x24,
>> +	0xcc, 0xf4,
>> +	0xce, 0x74,
>> +	0x00, 0x00,
>> +	0xbd, 0x01,
>> +	0xb8, 0x00,
>> +};
>> +
>> +/* For M88DS3000 demod dvbs mode.*/
>> +static u8 ds3000_dvbs_init_tab[] = {
>> +	0x23, 0x05,
>> +	0x08, 0x03,
>> +	0x0c, 0x02,
>> +	0x21, 0x54,
>> +	0x25, 0x82,
>> +	0x27, 0x31,
>> +	0x30, 0x08,
>> +	0x31, 0x40,
>> +	0x32, 0x32,
>> +	0x33, 0x35,
>> +	0x35, 0xff,
>> +	0x3a, 0x00,
>> +	0x37, 0x10,
>> +	0x38, 0x10,
>> +	0x39, 0x02,
>> +	0x42, 0x60,
>> +	0x4a, 0x40,
>> +	0x4b, 0x04,
>> +	0x4d, 0x91,
>> +	0x5d, 0xc8,
>> +	0x50, 0x77,
>> +	0x51, 0x77,
>> +	0x52, 0x36,
>> +	0x53, 0x36,
>> +	0x56, 0x01,
>> +	0x63, 0x47,
>> +	0x64, 0x30,
>> +	0x65, 0x40,
>> +	0x68, 0x26,
>> +	0x69, 0x4c,
>> +	0x70, 0x20,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x40,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x60,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x80,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0xa0,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x1f,
>> +	0x76, 0x00,
>> +	0x77, 0xd1,
>> +	0x78, 0x0c,
>> +	0x79, 0x80,
>> +	0x7f, 0x04,
>> +	0x7c, 0x00,
>> +	0x80, 0x86,
>> +	0x81, 0xa6,
>> +	0x85, 0x04,
>> +	0xcd, 0xf4,
>> +	0x90, 0x33,
>> +	0xa0, 0x44,
>> +	0xc0, 0x18,
>> +	0xc3, 0x10,
>> +	0xc4, 0x08,
>> +	0xc5, 0x80,
>> +	0xc6, 0x80,
>> +	0xc7, 0x0a,
>> +	0xc8, 0x1a,
>> +	0xc9, 0x80,
>> +	0xfe, 0xb6,
>> +	0xe0, 0xf8,
>> +	0xe6, 0x8b,
>> +	0xd0, 0x40,
>> +	0xf8, 0x20,
>> +	0xfa, 0x0f,
>> +	0xad, 0x20,
>> +	0xae, 0x07,
>> +	0xb8, 0x00,
>> +};
>> +
>> +/* For M88DS3000 demod dvbs2 mode.*/
>> +static u8 ds3000_dvbs2_init_tab[] = {
>> +	0x23, 0x0f,
>> +	0x08, 0x07,
>> +	0x0c, 0x02,
>> +	0x21, 0x54,
>> +	0x25, 0x82,
>> +	0x27, 0x31,
>> +	0x30, 0x08,
>> +	0x31, 0x32,
>> +	0x32, 0x32,
>> +	0x33, 0x35,
>> +	0x35, 0xff,
>> +	0x3a, 0x00,
>> +	0x37, 0x10,
>> +	0x38, 0x10,
>> +	0x39, 0x02,
>> +	0x42, 0x60,
>> +	0x4a, 0x80,
>> +	0x4b, 0x04,
>> +	0x4d, 0x91,
>> +	0x5d, 0x88,
>> +	0x50, 0x36,
>> +	0x51, 0x36,
>> +	0x52, 0x36,
>> +	0x53, 0x36,
>> +	0x63, 0x60,
>> +	0x64, 0x10,
>> +	0x65, 0x10,
>> +	0x68, 0x04,
>> +	0x69, 0x29,
>> +	0x70, 0x20,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x40,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x60,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x80,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0xa0,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x1f,
>> +	0xa0, 0x44,
>> +	0xc0, 0x08,
>> +	0xc1, 0x10,
>> +	0xc2, 0x08,
>> +	0xc3, 0x10,
>> +	0xc4, 0x08,
>> +	0xc5, 0xf0,
>> +	0xc6, 0xf0,
>> +	0xc7, 0x0a,
>> +	0xc8, 0x1a,
>> +	0xc9, 0x80,
>> +	0xca, 0x23,
>> +	0xcb, 0x24,
>> +	0xce, 0x74,
>> +	0x56, 0x01,
>> +	0x90, 0x03,
>> +	0x76, 0x80,
>> +	0x77, 0x42,
>> +	0x78, 0x0a,
>> +	0x79, 0x80,
>> +	0xad, 0x40,
>> +	0xae, 0x07,
>> +	0x7f, 0xd4,
>> +	0x7c, 0x00,
>> +	0x80, 0xa8,
>> +	0x81, 0xda,
>> +	0x7c, 0x01,
>> +	0x80, 0xda,
>> +	0x81, 0xec,
>> +	0x7c, 0x02,
>> +	0x80, 0xca,
>> +	0x81, 0xeb,
>> +	0x7c, 0x03,
>> +	0x80, 0xba,
>> +	0x81, 0xdb,
>> +	0x85, 0x08,
>> +	0x86, 0x00,
>> +	0x87, 0x02,
>> +	0x89, 0x80,
>> +	0x8b, 0x44,
>> +	0x8c, 0xaa,
>> +	0x8a, 0x10,
>> +	0xba, 0x00,
>> +	0xf5, 0x04,
>> +	0xd2, 0x32,
>> +	0xb8, 0x00,
>> +};
>> +
>> +struct m88ds3103_state {
>> +	struct i2c_adapter *i2c;
>> +	const struct m88ds3103_config *config;
>> +	
>> +	struct dvb_frontend frontend;
>> +	
>> +	u32 preBer;
>> +	u8 skip_fw_load;	
>> +	u8 first_lock; /* The first time of signal lock */
>> +	u16 demod_id; /* demod chip type */
>> +	u16 tuner_id; /* tuner chip type */
>> +	fe_delivery_system_t delivery_system;
>> +};
>> +
>> +/*demod register operations.*/
>> +static int m88ds3103_writereg(struct m88ds3103_state *state, int reg, int data)
>> +{
>> +	u8 buf[] = { reg, data };
>> +	struct i2c_msg msg = { .addr = state->config->demod_address,
>> +		.flags = 0, .buf = buf, .len = 2 };
>> +	int err;
>> +
>> +	if (debug > 1)
>> +		printk("m88ds3103: %s: write reg 0x%02x, value 0x%02x\n",
>> +			__func__, reg, data);
>> +
>> +	err = i2c_transfer(state->i2c, &msg, 1);
>> +	if (err != 1) {
>> +		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x,"
>> +			 " value == 0x%02x)\n", __func__, err, reg, data);
>> +		return -EREMOTEIO;
>> +	}
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_readreg(struct m88ds3103_state *state, u8 reg)
>> +{
>> +	int ret;
>> +	u8 b0[] = { reg };
>> +	u8 b1[] = { 0 };
>> +	struct i2c_msg msg[] = {
>> +		{ .addr = state->config->demod_address, .flags = 0,
>> +			.buf = b0, .len = 1 },
>> +		{ .addr = state->config->demod_address, .flags = I2C_M_RD,
>> +			.buf = b1, .len = 1 }
>> +	};
>> +	ret = i2c_transfer(state->i2c, msg, 2);
>> +
>> +	if (ret != 2) {
>> +		printk(KERN_ERR "%s: reg=0x%x (error=%d)\n",
>> +			__func__, reg, ret);
>> +		return ret;
>> +	}
>> +
>> +	if (debug > 1)
>> +		printk(KERN_INFO "m88ds3103: read reg 0x%02x, value 0x%02x\n",
>> +			reg, b1[0]);
>> +
>> +	return b1[0];
>> +}
>> +
>> +/*tuner register operations.*/
>> +static int m88ds3103_tuner_writereg(struct m88ds3103_state *state, int reg, int data)
>> +{
>> +	u8 buf[] = { reg, data };
>> +	struct i2c_msg msg = { .addr = 0x60,
>> +		.flags = 0, .buf = buf, .len = 2 };
>> +	int err;
>> +
>> +	m88ds3103_writereg(state, 0x03, 0x11);
>> +	err = i2c_transfer(state->i2c, &msg, 1);
>> +	
>> +	if (err != 1) {
>> +		printk("%s: writereg error(err == %i, reg == 0x%02x,"
>> +			 " value == 0x%02x)\n", __func__, err, reg, data);
>> +		return -EREMOTEIO;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_tuner_readreg(struct m88ds3103_state *state, u8 reg)
>> +{
>> +	int ret;
>> +	u8 b0[] = { reg };
>> +	u8 b1[] = { 0 };
>> +	struct i2c_msg msg[] = {
>> +		{ .addr = 0x60, .flags = 0,
>> +			.buf = b0, .len = 1 },
>> +		{ .addr = 0x60, .flags = I2C_M_RD,
>> +			.buf = b1, .len = 1 }
>> +	};
>> +
>> +	m88ds3103_writereg(state, 0x03, 0x11);	
>> +	ret = i2c_transfer(state->i2c, msg, 2);
>> +
>> +	if (ret != 2) {
>> +		printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);
>> +		return ret;
>> +	}
>> +
>> +	return b1[0];
>> +}
>> +
>> +/* Bulk demod I2C write, for firmware download. */
>> +static int m88ds3103_writeregN(struct m88ds3103_state *state, int reg,
>> +				const u8 *data, u16 len)
>> +{
>> +	int ret = -EREMOTEIO;
>> +	struct i2c_msg msg;
>> +	u8 *buf;
>> +
>> +	buf = kmalloc(len + 1, GFP_KERNEL);
>> +	if (buf == NULL) {
>> +		printk("Unable to kmalloc\n");
>> +		ret = -ENOMEM;
>> +		goto error;
>> +	}
>> +
>> +	*(buf) = reg;
>> +	memcpy(buf + 1, data, len);
>> +
>> +	msg.addr = state->config->demod_address;
>> +	msg.flags = 0;
>> +	msg.buf = buf;
>> +	msg.len = len + 1;
>> +
>> +	if (debug > 1)
>> +		printk(KERN_INFO "m88ds3103: %s:  write regN 0x%02x, len = %d\n",
>> +			__func__, reg, len);
>> +
>> +	ret = i2c_transfer(state->i2c, &msg, 1);
>> +	if (ret != 1) {
>> +		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n",
>> +			 __func__, ret, reg);
>> +		ret = -EREMOTEIO;
>> +	}
>> +	
>> +error:
>> +	kfree(buf);
>> +
>> +	return ret;
>> +}
>> +
>> +static int m88ds3103_load_firmware(struct dvb_frontend *fe)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	const struct firmware *fw;
>> +	int i, ret = 0;
>> +
>> +	dprintk("%s()\n", __func__);
>> +		
>> +	if (state->skip_fw_load)
>> +		return 0;
>> +	/* Load firmware */
>> +	/* request the firmware, this will block until someone uploads it */	
>> +	if(state->demod_id == DS3000_ID){
>> +		printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__,
>> +				DS3000_DEFAULT_FIRMWARE);		
>> +		ret = request_firmware(&fw, DS3000_DEFAULT_FIRMWARE,
>> +					state->i2c->dev.parent);
>> +	}else if(state->demod_id == DS3103_ID){
>> +		printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__,
>> +				DS3103_DEFAULT_FIRMWARE);
>> +		ret = request_firmware(&fw, DS3103_DEFAULT_FIRMWARE,
>> +					state->i2c->dev.parent);
>> +	}
>> +	
>> +	printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__);
>> +	if (ret) {
>> +		printk(KERN_ERR "%s: No firmware uploaded (timeout or file not "
>> +				"found?)\n", __func__);
>> +		return ret;
>> +	}
>> +
>> +	/* Make sure we don't recurse back through here during loading */
>> +	state->skip_fw_load = 1;
>> +
>> +	dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
>> +			fw->size,
>> +			fw->data[0],
>> +			fw->data[1],
>> +			fw->data[fw->size - 2],
>> +			fw->data[fw->size - 1]);
>> +			
>> +	/* stop internal mcu. */
>> +	m88ds3103_writereg(state, 0xb2, 0x01);
>> +	/* split firmware to download.*/
>> +	for(i = 0; i < FW_DOWN_LOOP; i++){
>> +		ret = m88ds3103_writeregN(state, 0xb0, &(fw->data[FW_DOWN_SIZE*i]), FW_DOWN_SIZE);
>> +		if(ret != 1) break;		
>> +	}
>> +	/* start internal mcu. */
>> +	if(ret == 1)
>> +		m88ds3103_writereg(state, 0xb2, 0x00);
>> +		
>> +	release_firmware(fw);
>> +
>> +	dprintk("%s: Firmware upload %s\n", __func__,
>> +			ret == 1 ? "complete" : "failed");
>> +
>> +	if(ret == 1) ret = 0;
>> +	
>> +	/* Ensure firmware is always loaded if required */
>> +	state->skip_fw_load = 0;
>> +
>> +	return ret;
>> +}
>> +
>> +
>> +static int m88ds3103_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	u8 data;
>> +
>> +	dprintk("%s(%d)\n", __func__, voltage);
>> +
>> +	dprintk("m88ds3103:pin_ctrl = (%02x)\n", state->config->pin_ctrl);
>> +	
>> +	if(state->config->set_voltage)
>> +		state->config->set_voltage(fe, voltage);
>> +	
>> +	data = m88ds3103_readreg(state, 0xa2);
>> +	
>> +        if(state->config->pin_ctrl & 0x80){ /*If control pin is assigned.*/
>> +	        data &= ~0x03; /* bit0 V/H, bit1 off/on */
>> +	        if(state->config->pin_ctrl & 0x02)
>> +		     data |= 0x02;
>> +
>> +	        switch (voltage) {
>> +	        case SEC_VOLTAGE_18:
>> +		     if((state->config->pin_ctrl & 0x01) == 0)
>> +			  data |= 0x01;
>> +		     break;
>> +	        case SEC_VOLTAGE_13:
>> +		     if(state->config->pin_ctrl & 0x01)
>> +			  data |= 0x01;
>> +		     break;
>> +	        case SEC_VOLTAGE_OFF:
>> +		     if(state->config->pin_ctrl & 0x02)
>> +			   data &= ~0x02;			
>> +		     else
>> +			   data |= 0x02;
>> +		     break;
>> +	         }
>> +        }
>> +
>> +	m88ds3103_writereg(state, 0xa2, data);
>> +
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_read_status(struct dvb_frontend *fe, fe_status_t* status)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	int lock = 0;
>> +	
>> +	*status = 0;
>> +	
>> +	switch (state->delivery_system){
>> +	case SYS_DVBS:
>> +		lock = m88ds3103_readreg(state, 0xd1);
>> +		dprintk("%s: SYS_DVBS status=%x.\n", __func__, lock);
>> +		
>> +		if ((lock & 0x07) == 0x07){
>> +			/*if((m88ds3103_readreg(state, 0x0d) & 0x07) == 0x07)*/
>> +				*status = FE_HAS_SIGNAL | FE_HAS_CARRIER 
>> +					| FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
>> +			
>> +		}
>> +		break;
>> +	case SYS_DVBS2:
>> +		lock = m88ds3103_readreg(state, 0x0d);
>> +		dprintk("%s: SYS_DVBS2 status=%x.\n", __func__, lock);
>> +
>> +		if ((lock & 0x8f) == 0x8f)
>> +			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER 
>> +				| FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
>> +			
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_read_ber(struct dvb_frontend *fe, u32* ber)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	u8 tmp1, tmp2, tmp3;
>> +	u32 ldpc_frame_cnt, pre_err_packags, code_rate_fac = 0;
>> +
>> +	dprintk("%s()\n", __func__);
>> +
>> +	switch (state->delivery_system) {
>> +	case SYS_DVBS:
>> +		m88ds3103_writereg(state, 0xf9, 0x04);
>> +		tmp3 = m88ds3103_readreg(state, 0xf8);
>> +		if ((tmp3&0x10) == 0){
>> +			tmp1 = m88ds3103_readreg(state, 0xf7);
>> +			tmp2 = m88ds3103_readreg(state, 0xf6);
>> +			tmp3 |= 0x10;
>> +			m88ds3103_writereg(state, 0xf8, tmp3);
>> +			state->preBer = (tmp1<<8) | tmp2;
>> +		}
>> +		break;
>> +	case SYS_DVBS2:
>> +		tmp1 = m88ds3103_readreg(state, 0x7e) & 0x0f;
>> +		switch(tmp1){
>> +		case 0:	code_rate_fac = 16008 - 80; break;
>> +		case 1:	code_rate_fac = 21408 - 80; break;
>> +		case 2:	code_rate_fac = 25728 - 80; break;
>> +		case 3:	code_rate_fac = 32208 - 80; break;
>> +		case 4:	code_rate_fac = 38688 - 80; break;
>> +		case 5:	code_rate_fac = 43040 - 80; break;
>> +		case 6:	code_rate_fac = 48408 - 80; break;
>> +		case 7:	code_rate_fac = 51648 - 80; break;
>> +		case 8:	code_rate_fac = 53840 - 80; break;
>> +		case 9:	code_rate_fac = 57472 - 80; break;
>> +		case 10: code_rate_fac = 58192 - 80; break;
>> +		}
>> +		
>> +		tmp1 = m88ds3103_readreg(state, 0xd7) & 0xff;
>> +		tmp2 = m88ds3103_readreg(state, 0xd6) & 0xff;
>> +		tmp3 = m88ds3103_readreg(state, 0xd5) & 0xff;		
>> +		ldpc_frame_cnt = (tmp1 << 16) | (tmp2 << 8) | tmp3;
>> +
>> +		tmp1 = m88ds3103_readreg(state, 0xf8) & 0xff;
>> +		tmp2 = m88ds3103_readreg(state, 0xf7) & 0xff;
>> +		pre_err_packags = tmp1<<8 | tmp2;
>> +		
>> +		if (ldpc_frame_cnt > 1000){
>> +			m88ds3103_writereg(state, 0xd1, 0x01);
>> +			m88ds3103_writereg(state, 0xf9, 0x01);
>> +			m88ds3103_writereg(state, 0xf9, 0x00);
>> +			m88ds3103_writereg(state, 0xd1, 0x00);
>> +			state->preBer = pre_err_packags;
>> +		} 				
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +	*ber = state->preBer;
>> +	
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_read_signal_strength(struct dvb_frontend *fe,
>> +						u16 *signal_strength)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	u16 gain;
>> +	u8 gain1, gain2, gain3 = 0;
>> +
>> +	dprintk("%s()\n", __func__);
>> +
>> +	gain1 = m88ds3103_tuner_readreg(state, 0x3d) & 0x1f;
>> +	dprintk("%s: gain1 = 0x%02x \n", __func__, gain1);
>> +	
>> +	if (gain1 > 15) gain1 = 15;
>> +	gain2 = m88ds3103_tuner_readreg(state, 0x21) & 0x1f;
>> +	dprintk("%s: gain2 = 0x%02x \n", __func__, gain2);
>> +	
>> +	if(state->tuner_id == TS2022_ID){
>> +		gain3 = (m88ds3103_tuner_readreg(state, 0x66)>>3) & 0x07;
>> +		dprintk("%s: gain3 = 0x%02x \n", __func__, gain3);
>> +		
>> +		if (gain2 > 16) gain2 = 16;
>> +		if (gain2 < 2) gain2 = 2;			
>> +		if (gain3 > 6) gain3 = 6;
>> +	}else{
>> +		if (gain2 > 13) gain2 = 13;
>> +		gain3 = 0;
>> +	}
>> +
>> +	gain = gain1*23 + gain2*35 + gain3*29;
>> +	*signal_strength = 60000 - gain*55;
>> +
>> +	return 0;
>> +}
>> +
>> +
>> +static int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *p_snr)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	u8 val, npow1, npow2, spow1, cnt;
>> +	u16 tmp, snr;
>> +	u32 npow, spow, snr_total;	
>> +	static const u16 mes_log10[] ={
>> +		0,	3010,	4771,	6021, 	6990,	7781,	8451,	9031,	9542,	10000,
>> +		10414,	10792,	11139,	11461,	11761,	12041,	12304,	12553,	12788,	13010,
>> +		13222,	13424,	13617,	13802,	13979,	14150,	14314,	14472,	14624,	14771,
>> +		14914,	15052,	15185,	15315,	15441,	15563,	15682,	15798,	15911,	16021,
>> +		16128,	16232,	16335,	16435,	16532,	16628,	16721,	16812,	16902,	16990,
>> +		17076,	17160,	17243,	17324,	17404,	17482,	17559,	17634,	17709,	17782,
>> +		17853,	17924,	17993,	18062,	18129,	18195,	18261,	18325,	18388,	18451,
>> +		18513,	18573,	18633,	18692,	18751,	18808,	18865,	18921,	18976,	19031
>> +	};
>> +	static const u16 mes_loge[] ={
>> +		0,	6931,	10986,	13863, 	16094,	17918,	19459,	20794,	21972,	23026,
>> +		23979,	24849,	25649,	26391,	27081,	27726,	28332,	28904,	29444,	29957,
>> +		30445,	30910,	31355,	31781,	32189,	32581,	32958,	33322,	33673,	34012,
>> +		34340,	34657,
>> +	};
>> +
>> +	dprintk("%s()\n", __func__);
>> +
>> +	snr = 0;
>> +	
>> +	switch (state->delivery_system){
>> +	case SYS_DVBS:
>> +		cnt = 10; snr_total = 0;
>> +		while(cnt > 0){
>> +			val = m88ds3103_readreg(state, 0xff);
>> +			snr_total += val;
>> +			cnt--;
>> +		}
>> +		tmp = (u16)(snr_total/80);
>> +		if(tmp > 0){
>> +			if (tmp > 32) tmp = 32;
>> +			snr = (mes_loge[tmp - 1] * 100) / 45;
>> +		}else{
>> +			snr = 0;
>> +		}
>> +		break;
>> +	case SYS_DVBS2:
>> +		cnt  = 10; npow = 0; spow = 0;
>> +		while(cnt >0){
>> +			npow1 = m88ds3103_readreg(state, 0x8c) & 0xff;
>> +			npow2 = m88ds3103_readreg(state, 0x8d) & 0xff;
>> +			npow += (((npow1 & 0x3f) + (u16)(npow2 << 6)) >> 2);
>> +
>> +			spow1 = m88ds3103_readreg(state, 0x8e) & 0xff;
>> +			spow += ((spow1 * spow1) >> 1);
>> +			cnt--;
>> +		}
>> +		npow /= 10; spow /= 10;
>> +		if(spow == 0){
>> +			snr = 0;
>> +		}else if(npow == 0){
>> +			snr = 19;
>> +		}else{
>> +			if(spow > npow){
>> +				tmp = (u16)(spow / npow);
>> +				if (tmp > 80) tmp = 80;
>> +				snr = mes_log10[tmp - 1]*3;
>> +			}else{
>> +				tmp = (u16)(npow / spow);
>> +				if (tmp > 80) tmp = 80;
>> +				snr = -(mes_log10[tmp - 1] / 1000);
>> +			}
>> +		}			
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +	*p_snr = snr;
>> +
>> +	return 0;
>> +}
>> +
>> +
>> +static int m88ds3103_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	u8 tmp1, tmp2, tmp3, data;
>> +
>> +	dprintk("%s()\n", __func__);
>> +
>> +	switch (state->delivery_system) {
>> +	case SYS_DVBS:
>> +		data = m88ds3103_readreg(state, 0xf8);
>> +		data |= 0x40;
>> +		m88ds3103_writereg(state, 0xf8, data);		
>> +		tmp1 = m88ds3103_readreg(state, 0xf5);
>> +		tmp2 = m88ds3103_readreg(state, 0xf4);
>> +		*ucblocks = (tmp1 <<8) | tmp2;		
>> +		data &= ~0x20;
>> +		m88ds3103_writereg(state, 0xf8, data);
>> +		data |= 0x20;
>> +		m88ds3103_writereg(state, 0xf8, data);
>> +		data &= ~0x40;
>> +		m88ds3103_writereg(state, 0xf8, data);
>> +		break;
>> +	case SYS_DVBS2:
>> +		tmp1 = m88ds3103_readreg(state, 0xda);
>> +		tmp2 = m88ds3103_readreg(state, 0xd9);
>> +		tmp3 = m88ds3103_readreg(state, 0xd8);
>> +		*ucblocks = (tmp1 <<16)|(tmp2 <<8)|tmp3;
>> +		data = m88ds3103_readreg(state, 0xd1);
>> +		data |= 0x01;
>> +		m88ds3103_writereg(state, 0xd1, data);
>> +		data &= ~0x01;
>> +		m88ds3103_writereg(state, 0xd1, data);
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	u8 data_a1, data_a2;
>> +
>> +	dprintk("%s(%d)\n", __func__, tone);
>> +	if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
>> +		printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
>> +		return -EINVAL;
>> +	}
>> +
>> +	data_a1 = m88ds3103_readreg(state, 0xa1);
>> +	data_a2 = m88ds3103_readreg(state, 0xa2);
>> +	if(state->demod_id == DS3103_ID)
>> +		data_a2 &= 0xdf; /* Normal mode */
>> +	switch (tone) {
>> +	case SEC_TONE_ON:
>> +		dprintk("%s: SEC_TONE_ON\n", __func__);
>> +		data_a1 |= 0x04;
>> +		data_a1 &= ~0x03;
>> +		data_a1 &= ~0x40;
>> +		data_a2 &= ~0xc0;
>> +		break;
>> +	case SEC_TONE_OFF:
>> +		dprintk("%s: SEC_TONE_OFF\n", __func__);
>> +		data_a2 &= ~0xc0;
>> +		data_a2 |= 0x80;
>> +		break;
>> +	}
>> +	m88ds3103_writereg(state, 0xa2, data_a2);
>> +	m88ds3103_writereg(state, 0xa1, data_a1);
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_send_diseqc_msg(struct dvb_frontend *fe,
>> +				struct dvb_diseqc_master_cmd *d)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	int i, ret = 0;
>> +	u8 tmp, time_out;
>> +
>> +	/* Dump DiSEqC message */
>> +	if (debug) {
>> +		printk(KERN_INFO "m88ds3103: %s(", __func__);
>> +		for (i = 0 ; i < d->msg_len ;) {
>> +			printk(KERN_INFO "0x%02x", d->msg[i]);
>> +			if (++i < d->msg_len)
>> +				printk(KERN_INFO ", ");
>> +		}
>> +	}
>> +
>> +	tmp = m88ds3103_readreg(state, 0xa2);
>> +	tmp &= ~0xc0;
>> +	if(state->demod_id == DS3103_ID)
>> +		tmp &= ~0x20;
>> +	m88ds3103_writereg(state, 0xa2, tmp);
>> +	
>> +	for (i = 0; i < d->msg_len; i ++)
>> +		m88ds3103_writereg(state, (0xa3+i), d->msg[i]);
>> +
>> +	tmp = m88ds3103_readreg(state, 0xa1);	
>> +	tmp &= ~0x38;
>> +	tmp &= ~0x40;
>> +	tmp |= ((d->msg_len-1) << 3) | 0x07;
>> +	tmp &= ~0x80;
>> +	m88ds3103_writereg(state, 0xa1, tmp);
>> +	/*	1.5 * 9 * 8	= 108ms	*/
>> +	time_out = 150;
>> +	while (time_out > 0){
>> +		msleep(10);
>> +		time_out -= 10;
>> +		tmp = m88ds3103_readreg(state, 0xa1);		
>> +		if ((tmp & 0x40) == 0)
>> +			break;
>> +	}
>> +	if (time_out == 0){
>> +		tmp = m88ds3103_readreg(state, 0xa1);
>> +		tmp &= ~0x80;
>> +		tmp |= 0x40;
>> +		m88ds3103_writereg(state, 0xa1, tmp);
>> +		ret = 1;
>> +	}
>> +	tmp = m88ds3103_readreg(state, 0xa2);
>> +	tmp &= ~0xc0;
>> +	tmp |= 0x80;
>> +	m88ds3103_writereg(state, 0xa2, tmp);	
>> +	return ret;
>> +}
>> +
>> +
>> +static int m88ds3103_diseqc_send_burst(struct dvb_frontend *fe,
>> +					fe_sec_mini_cmd_t burst)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	u8	val, time_out;
>> +	
>> +	dprintk("%s()\n", __func__);
>> +
>> +	val = m88ds3103_readreg(state, 0xa2);
>> +	val &= ~0xc0;
>> +	if(state->demod_id == DS3103_ID)
>> +		val &= 0xdf; /* Normal mode */
>> +	m88ds3103_writereg(state, 0xa2, val);
>> +	/* DiSEqC burst */
>> +	if (burst == SEC_MINI_B)
>> +		m88ds3103_writereg(state, 0xa1, 0x01);
>> +	else
>> +		m88ds3103_writereg(state, 0xa1, 0x02);
>> +
>> +	msleep(13);
>> +
>> +	time_out = 5;
>> +	do{
>> +		val = m88ds3103_readreg(state, 0xa1);
>> +		if ((val & 0x40) == 0)
>> +			break;
>> +		msleep(1);
>> +		time_out --;
>> +	} while (time_out > 0);
>> +
>> +	val = m88ds3103_readreg(state, 0xa2);
>> +	val &= ~0xc0;
>> +	val |= 0x80;
>> +	m88ds3103_writereg(state, 0xa2, val);
>> +	
>> +	return 0;
>> +}
>> +
>> +static void m88ds3103_release(struct dvb_frontend *fe)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +
>> +	dprintk("%s\n", __func__);
>> +	kfree(state);
>> +}
>> +
>> +static int m88ds3103_check_id(struct m88ds3103_state *state)
>> +{
>> +	int val_00, val_01;
>> +	
>> +	/*check demod id*/
>> +	val_01 = m88ds3103_readreg(state, 0x01);
>> +	printk(KERN_INFO "DS3000 chip version: %x attached.\n", val_01);
>> +			
>> +	if(val_01 == 0xD0)
>> +		state->demod_id = DS3103_ID;
>> +	else if(val_01 == 0xC0)
>> +		state->demod_id = DS3000_ID;
>> +	else
>> +		state->demod_id = UNKNOW_ID;
>> +		
>> +	/*check tuner id*/
>> +	val_00 = m88ds3103_tuner_readreg(state, 0x00);
>> +	printk(KERN_INFO "TS202x chip version[1]: %x attached.\n", val_00);
>> +	val_00 &= 0x03;
>> +	if(val_00 == 0)
>> +	{
>> +		m88ds3103_tuner_writereg(state, 0x00, 0x01);
>> +		msleep(3);		
>> +	}
>> +	m88ds3103_tuner_writereg(state, 0x00, 0x03);
>> +	msleep(5);
>> +	
>> +	val_00 = m88ds3103_tuner_readreg(state, 0x00);
>> +	printk(KERN_INFO "TS202x chip version[2]: %x attached.\n", val_00);
>> +	val_00 &= 0xff;
>> +	if((val_00 == 0x01) || (val_00 == 0x41) || (val_00 == 0x81))
>> +		state->tuner_id = TS2020_ID;
>> +	else if(((val_00 & 0xc0)== 0xc0) || (val_00 == 0x83))
>> +		state->tuner_id = TS2022_ID;
>> +	else
>> +		state->tuner_id = UNKNOW_ID;
>> +			
>> +	return state->demod_id;	
>> +}
>> +
>> +static struct dvb_frontend_ops m88ds3103_ops;
>> +static int m88ds3103_initilaze(struct dvb_frontend *fe);
>> +
>> +struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *config,
>> +				    struct i2c_adapter *i2c)
>> +{
>> +	struct m88ds3103_state *state = NULL;
>> +
>> +	dprintk("%s\n", __func__);
>> +
>> +	/* allocate memory for the internal state */
>> +	state = kzalloc(sizeof(struct m88ds3103_state), GFP_KERNEL);
>> +	if (state == NULL) {
>> +		printk(KERN_ERR "Unable to kmalloc\n");
>> +		goto error2;
>> +	}
>> +
>> +	state->config = config;
>> +	state->i2c = i2c;
>> +	state->preBer = 0xffff;
>> +	state->delivery_system = SYS_DVBS; /*Default to DVB-S.*/
>> +	
>> +	/* check demod id */
>> +	if(m88ds3103_check_id(state) == UNKNOW_ID){
>> +		printk(KERN_ERR "Unable to find Montage chip\n");
>> +		goto error3;
>> +	}
>> +
>> +	memcpy(&state->frontend.ops, &m88ds3103_ops,
>> +			sizeof(struct dvb_frontend_ops));
>> +	state->frontend.demodulator_priv = state;
>> +	
>> +	m88ds3103_initilaze(&state->frontend);
>> +	
>> +	return &state->frontend;
>> +
>> +error3:
>> +	kfree(state);
>> +error2:
>> +	return NULL;
>> +}
>> +EXPORT_SYMBOL(m88ds3103_attach);
>> +
>> +static int m88ds3103_set_carrier_offset(struct dvb_frontend *fe,
>> +					s32 carrier_offset_khz)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	s32 tmp;
>> +
>> +	tmp = carrier_offset_khz;
>> +	tmp *= 65536;
>> +	
>> +	tmp = (2*tmp + MT_FE_MCLK_KHZ) / (2*MT_FE_MCLK_KHZ);
>> +
>> +	if (tmp < 0)
>> +		tmp += 65536;
>> +
>> +	m88ds3103_writereg(state, 0x5f, tmp >> 8);
>> +	m88ds3103_writereg(state, 0x5e, tmp & 0xff);
>> +
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_set_symrate(struct dvb_frontend *fe)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
>> +	u16 value;
>> +	
>> +	value = (((c->symbol_rate / 1000) << 15) + (MT_FE_MCLK_KHZ / 4)) / (MT_FE_MCLK_KHZ / 2);
>> +	m88ds3103_writereg(state, 0x61, value & 0x00ff);
>> +	m88ds3103_writereg(state, 0x62, (value & 0xff00) >> 8);
>> +
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_set_CCI(struct dvb_frontend *fe)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	u8 tmp;
>> +
>> +	tmp = m88ds3103_readreg(state, 0x56);
>> +	tmp &= ~0x01;
>> +	m88ds3103_writereg(state, 0x56, tmp);
>> +
>> +	tmp = m88ds3103_readreg(state, 0x76);
>> +	tmp &= ~0x80;
>> +	m88ds3103_writereg(state, 0x76, tmp);
>> +
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_init_reg(struct m88ds3103_state *state, const u8 *p_reg_tab, u32 size)
>> +{
>> +	u32 i;
>> +	
>> +	for(i = 0; i < size; i+=2)
>> +		m88ds3103_writereg(state, p_reg_tab[i], p_reg_tab[i+1]);
>> +		
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_demod_connect(struct dvb_frontend *fe, s32 carrier_offset_khz) 
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
>> +	u16 value;
>> +	u8 val1,val2,data;
>> +	
>> +	dprintk("connect delivery system = %d\n", state->delivery_system);
>> +	
>> +	/* ds3000 global reset */
>> +	m88ds3103_writereg(state, 0x07, 0x80);
>> +	m88ds3103_writereg(state, 0x07, 0x00);
>> +	/* ds3000 build-in uC reset */
>> +	m88ds3103_writereg(state, 0xb2, 0x01);
>> +	/* ds3000 software reset */
>> +	m88ds3103_writereg(state, 0x00, 0x01);
>> +
>> +	switch (state->delivery_system) {
>> +	case SYS_DVBS:
>> +		/* initialise the demod in DVB-S mode */
>> +		if(state->demod_id == DS3000_ID){
>> +			m88ds3103_init_reg(state, ds3000_dvbs_init_tab, sizeof(ds3000_dvbs_init_tab));
>> +			
>> +			value = m88ds3103_readreg(state, 0xfe);
>> +			value &= 0xc0;
>> +			value |= 0x1b;
>> +			m88ds3103_writereg(state, 0xfe, value);
>> +			
>> +			if(state->config->ci_mode)
>> +				val1 = 0x80;
>> +			else if(state->config->ts_mode)
>> +				val1 = 0x60;
>> +			else
>> +				val1 = 0x20;
>> +			m88ds3103_writereg(state, 0xfd, val1);
>> +			
>> +		}else if(state->demod_id == DS3103_ID){
>> +			m88ds3103_init_reg(state, ds3103_dvbs_init_tab, sizeof(ds3103_dvbs_init_tab));
>> +			
>> +			/* set ts clock */
>> +			if(state->config->ts_mode == 0)	{
>> +				val1 = 3; val2 = 3;
>> +			}else{
>> +				val1 = 0; val2 = 0;
>> +			}
>> +			val1 -= 1; val2 -= 1;
>> +			val1 &= 0x3f; val2 &= 0x3f;
>> +			data = m88ds3103_readreg(state, 0xfe);
>> +			data &= 0xf0;
>> +			data |= (val2 >> 2) & 0x0f;
>> +			m88ds3103_writereg(state, 0xfe, data);
>> +			data = (val2 & 0x03) << 6;
>> +			data |= val1;
>> +			m88ds3103_writereg(state, 0xea, data);
>> +			
>> +			m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d));
>> +			m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30));
>> +			
>> +			/* set master clock */
>> +			val1 = m88ds3103_readreg(state, 0x22);
>> +			val2 = m88ds3103_readreg(state, 0x24);
>> +			
>> +			val1 &= 0x3f;
>> +			val2 &= 0x3f;
>> +			val1 |= 0x80;
>> +			val2 |= 0x40;
>> +
>> +			m88ds3103_writereg(state, 0x22, val1);
>> +			m88ds3103_writereg(state, 0x24, val2);	
>> +			
>> +			if(state->config->ci_mode)
>> +				val1 = 0x03;
>> +			else if(state->config->ts_mode)
>> +				val1 = 0x06;
>> +			else
>> +				val1 = 0x42;
>> +			m88ds3103_writereg(state, 0xfd, val1);		
>> +		}
>> +		break;
>> +	case SYS_DVBS2:
>> +		/* initialise the demod in DVB-S2 mode */
>> +		if(state->demod_id == DS3000_ID){
>> +			m88ds3103_init_reg(state, ds3000_dvbs2_init_tab, sizeof(ds3000_dvbs2_init_tab));
>> +		
>> +			if (c->symbol_rate >= 30000000)
>> +				m88ds3103_writereg(state, 0xfe, 0x54);
>> +			else
>> +				m88ds3103_writereg(state, 0xfe, 0x98);
>> +								
>> +		}else if(state->demod_id == DS3103_ID){
>> +			m88ds3103_init_reg(state, ds3103_dvbs2_init_tab, sizeof(ds3103_dvbs2_init_tab));
>> +
>> +			/* set ts clock */
>> +			if(state->config->ts_mode == 0){
>> +				val1 = 5; val2 = 4;
>> +			}else{
>> +				val1 = 0; val2 = 0;
>> +			}
>> +			val1 -= 1; val2 -= 1;
>> +			val1 &= 0x3f; val2 &= 0x3f;
>> +			data = m88ds3103_readreg(state, 0xfe);
>> +			data &= 0xf0;
>> +			data |= (val2 >> 2) & 0x0f;
>> +			m88ds3103_writereg(state, 0xfe, data);
>> +			data = (val2 & 0x03) << 6;
>> +			data |= val1;
>> +			m88ds3103_writereg(state, 0xea, data);
>> +			
>> +			m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d));
>> +			m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30));
>> +			
>> +			/* set master clock */
>> +			val1 = m88ds3103_readreg(state, 0x22);
>> +			val2 = m88ds3103_readreg(state, 0x24);
>> +			
>> +			val1 &= 0x3f;
>> +			val2 &= 0x3f;
>> +			if(state->config->ts_mode == 1){
>> +				val1 |= 0x80;
>> +				val2 |= 0x40;
>> +			}else{
>> +				if (c->symbol_rate >= 28000000){
>> +					val1 |= 0xc0;
>> +				}else if (c->symbol_rate >= 18000000){
>> +					val2 |= 0x40;
>> +				}else{
>> +					val1 |= 0x80;
>> +					val2 |= 0x40;
>> +				}				
>> +			}
>> +			m88ds3103_writereg(state, 0x22, val1);
>> +			m88ds3103_writereg(state, 0x24, val2);					
>> +		}
>> +		
>> +		if(state->config->ci_mode)
>> +			val1 = 0x03;
>> +		else if(state->config->ts_mode)
>> +			val1 = 0x06;
>> +		else
>> +			val1 = 0x42;
>> +		m88ds3103_writereg(state, 0xfd, val1);
>> +		
>> +		break;
>> +	default:
>> +		return 1;
>> +	}
>> +	/* disable 27MHz clock output */
>> +	m88ds3103_writereg(state, 0x29, 0x80);
>> +	/* enable ac coupling */
>> +	m88ds3103_writereg(state, 0x25, 0x8a);
>> +
>> +	if ((c->symbol_rate / 1000) <= 3000){
>> +		m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 32 * 100 / 64 = 400*/
>> +		m88ds3103_writereg(state, 0xc8, 0x20);
>> +		m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/
>> +		m88ds3103_writereg(state, 0xc7, 0x00);
>> +	}else if((c->symbol_rate / 1000) <= 10000){
>> +		m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 16 * 100 / 64 = 200*/
>> +		m88ds3103_writereg(state, 0xc8, 0x10);
>> +		m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/
>> +		m88ds3103_writereg(state, 0xc7, 0x00);
>> +	}else{
>> +		m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 6 * 100 / 64 = 75*/
>> +		m88ds3103_writereg(state, 0xc8, 0x06);
>> +		m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/
>> +		m88ds3103_writereg(state, 0xc7, 0x00);
>> +	}
>> +
>> +	m88ds3103_set_symrate(fe);
>> +	
>> +	m88ds3103_set_CCI(fe);
>> +
>> +	m88ds3103_set_carrier_offset(fe, carrier_offset_khz);
>> +		
>> +	/* ds3000 out of software reset */
>> +	m88ds3103_writereg(state, 0x00, 0x00);
>> +	/* start ds3000 build-in uC */
>> +	m88ds3103_writereg(state, 0xb2, 0x00);	
>> +	
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_set_frontend(struct dvb_frontend *fe)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
>> +
>> +	int i;
>> +	fe_status_t status;
>> +	u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf, div4, capCode, changePLL;
>> +	s32 offset_khz, lpf_offset_KHz;
>> +	u16 value, ndiv, lpf_coeff;
>> +	u32 f3db, gdiv28, realFreq;
>> +	u8 RFgain;
>> +
>> +	dprintk("%s() ", __func__);
>> +	dprintk("c frequency = %d\n", c->frequency);
>> +	dprintk("symbol rate = %d\n", c->symbol_rate);
>> +	dprintk("delivery system = %d\n", c->delivery_system);
>> +	
>> +	realFreq = c->frequency;
>> +	lpf_offset_KHz = 0;
>> +	if(c->symbol_rate < 5000000){
>> +		lpf_offset_KHz = FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz;
>> +		realFreq += FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz;
>> +	}
>> +	
>> +	if (state->config->set_ts_params)
>> +		state->config->set_ts_params(fe, 0);
>> +
>> +	div4 = 0;
>> +	RFgain = 0;
>> +	if(state->tuner_id == TS2022_ID){
>> +		m88ds3103_tuner_writereg(state, 0x10, 0x0a);
>> +		m88ds3103_tuner_writereg(state, 0x11, 0x40);
>> +		if (realFreq < 1103000) {
>> +			m88ds3103_tuner_writereg(state, 0x10, 0x1b);
>> +			div4 = 1;
>> +			ndiv = (realFreq * (6 + 8) * 4)/MT_FE_CRYSTAL_KHZ;				
>> +		}else {
>> +			ndiv = (realFreq * (6 + 8) * 2)/MT_FE_CRYSTAL_KHZ;
>> +		}
>> +		ndiv = ndiv + ndiv%2;
>> +		if(ndiv < 4095)
>> +			ndiv = ndiv - 1024;
>> +		else if (ndiv < 6143)
>> +			ndiv = ndiv + 1024;
>> +		else
>> +			ndiv = ndiv + 3072;	
>> +		
>> +		m88ds3103_tuner_writereg(state, 0x01, (ndiv & 0x3f00) >> 8);											
>> +	}else{
>> +		m88ds3103_tuner_writereg(state, 0x10, 0x00);			
>> +		if (realFreq < 1146000){
>> +			m88ds3103_tuner_writereg(state, 0x10, 0x11);
>> +			div4 = 1;
>> +			ndiv = (realFreq * (6 + 8) * 4) / MT_FE_CRYSTAL_KHZ;
>> +		}else{
>> +			m88ds3103_tuner_writereg(state, 0x10, 0x01);
>> +			ndiv = (realFreq * (6 + 8) * 2) / MT_FE_CRYSTAL_KHZ;
>> +		}
>> +		ndiv = ndiv + ndiv%2;
>> +		ndiv = ndiv - 1024;
>> +		m88ds3103_tuner_writereg(state, 0x01, (ndiv>>8)&0x0f);
>> +	}
>> +	/* set pll */
>> +	m88ds3103_tuner_writereg(state, 0x02, ndiv & 0x00ff);
>> +	m88ds3103_tuner_writereg(state, 0x03, 0x06);
>> +	m88ds3103_tuner_writereg(state, 0x51, 0x0f);
>> +	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
>> +	m88ds3103_tuner_writereg(state, 0x50, 0x10);
>> +	m88ds3103_tuner_writereg(state, 0x50, 0x00);	
>> +
>> +	if(state->tuner_id == TS2022_ID){
>> +		if(( realFreq >= 1650000 ) && (realFreq <= 1850000)){
>> +			msleep(5);
>> +			value = m88ds3103_tuner_readreg(state, 0x14);
>> +			value &= 0x7f;
>> +			if(value < 64){
>> +				m88ds3103_tuner_writereg(state, 0x10, 0x82);
>> +				m88ds3103_tuner_writereg(state, 0x11, 0x6f);
>> +
>> +				m88ds3103_tuner_writereg(state, 0x51, 0x0f);
>> +				m88ds3103_tuner_writereg(state, 0x51, 0x1f);
>> +				m88ds3103_tuner_writereg(state, 0x50, 0x10);
>> +				m88ds3103_tuner_writereg(state, 0x50, 0x00);
>> +			}
>> +		}
>> +		msleep(5);
>> +		value = m88ds3103_tuner_readreg(state, 0x14);
>> +		value &= 0x1f;
>> +
>> +		if(value > 19){
>> +			value = m88ds3103_tuner_readreg(state, 0x10);
>> +			value &= 0x1d;
>> +			m88ds3103_tuner_writereg(state, 0x10, value);
>> +		}				
>> +	}else{
>> +		msleep(5);
>> +		value = m88ds3103_tuner_readreg(state, 0x66);
>> +		changePLL = (((value & 0x80) >> 7) != div4);
>> +
>> +		if(changePLL){
>> +			m88ds3103_tuner_writereg(state, 0x10, 0x11);
>> +			div4 = 1;
>> +			ndiv = (realFreq * (6 + 8) * 4)/MT_FE_CRYSTAL_KHZ;
>> +			ndiv = ndiv + ndiv%2;
>> +			ndiv = ndiv - 1024;
>> +					
>> +			m88ds3103_tuner_writereg(state, 0x01, (ndiv>>8) & 0x0f);
>> +			m88ds3103_tuner_writereg(state, 0x02, ndiv & 0xff);
>> +			
>> +			m88ds3103_tuner_writereg(state, 0x51, 0x0f);
>> +			m88ds3103_tuner_writereg(state, 0x51, 0x1f);
>> +			m88ds3103_tuner_writereg(state, 0x50, 0x10);
>> +			m88ds3103_tuner_writereg(state, 0x50, 0x00);
>> +		}		
>> +	}
>> +	/*set the RF gain*/
>> +	if(state->tuner_id == TS2020_ID)
>> +		m88ds3103_tuner_writereg(state, 0x60, 0x79);
>> +			
>> +	m88ds3103_tuner_writereg(state, 0x51, 0x17);
>> +	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
>> +	m88ds3103_tuner_writereg(state, 0x50, 0x08);
>> +	m88ds3103_tuner_writereg(state, 0x50, 0x00);
>> +	msleep(5);
>> +
>> +	if(state->tuner_id == TS2020_ID){
>> +		RFgain = m88ds3103_tuner_readreg(state, 0x3d);
>> +		RFgain &= 0x0f;
>> +		if(RFgain < 15){
>> +			if(RFgain < 4) 
>> +				RFgain = 0;
>> +			else
>> +				RFgain = RFgain -3;
>> +			value = ((RFgain << 3) | 0x01) & 0x79;
>> +			m88ds3103_tuner_writereg(state, 0x60, value);
>> +			m88ds3103_tuner_writereg(state, 0x51, 0x17);
>> +			m88ds3103_tuner_writereg(state, 0x51, 0x1f);
>> +			m88ds3103_tuner_writereg(state, 0x50, 0x08);
>> +			m88ds3103_tuner_writereg(state, 0x50, 0x00);
>> +		}
>> +	}
>> +	
>> +	/* set the LPF */
>> +	if(state->tuner_id == TS2022_ID){
>> +		m88ds3103_tuner_writereg(state, 0x25, 0x00);
>> +		m88ds3103_tuner_writereg(state, 0x27, 0x70);
>> +		m88ds3103_tuner_writereg(state, 0x41, 0x09);
>> +		m88ds3103_tuner_writereg(state, 0x08, 0x0b);
>> +	}
>> +
>> +	f3db = ((c->symbol_rate / 1000) *135) / 200 + 2000;
>> +	f3db += lpf_offset_KHz;
>> +	if (f3db < 7000)
>> +		f3db = 7000;
>> +	if (f3db > 40000)
>> +		f3db = 40000;
>> +			
>> +	gdiv28 = (MT_FE_CRYSTAL_KHZ / 1000 * 1694 + 500) / 1000;
>> +	m88ds3103_tuner_writereg(state, 0x04, gdiv28 & 0xff);
>> +	m88ds3103_tuner_writereg(state, 0x51, 0x1b);
>> +	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
>> +	m88ds3103_tuner_writereg(state, 0x50, 0x04);
>> +	m88ds3103_tuner_writereg(state, 0x50, 0x00);
>> +	msleep(5);
>> +
>> +	value = m88ds3103_tuner_readreg(state, 0x26);
>> +	capCode = value & 0x3f;
>> +	if(state->tuner_id == TS2022_ID){
>> +		m88ds3103_tuner_writereg(state, 0x41, 0x0d);
>> +
>> +		m88ds3103_tuner_writereg(state, 0x51, 0x1b);
>> +		m88ds3103_tuner_writereg(state, 0x51, 0x1f);
>> +		m88ds3103_tuner_writereg(state, 0x50, 0x04);
>> +		m88ds3103_tuner_writereg(state, 0x50, 0x00);
>> +
>> +		msleep(2);
>> +
>> +		value = m88ds3103_tuner_readreg(state, 0x26);
>> +		value &= 0x3f;
>> +		value = (capCode + value) / 2;		
>> +	}
>> +	else
>> +		value = capCode;
>> +		
>> +	gdiv28 = gdiv28 * 207 / (value * 2 + 151);	
>> +	mlpf_max = gdiv28 * 135 / 100;
>> +	mlpf_min = gdiv28 * 78 / 100;
>> +	if (mlpf_max > 63)
>> +		mlpf_max = 63;
>> +
>> +	if(state->tuner_id == TS2022_ID)
>> +		lpf_coeff = 3200;
>> +	else
>> +		lpf_coeff = 2766;
>> +		
>> +	nlpf = (f3db * gdiv28 * 2 / lpf_coeff / (MT_FE_CRYSTAL_KHZ / 1000)  + 1) / 2 ;	
>> +	if (nlpf > 23) nlpf = 23;
>> +	if (nlpf < 1) nlpf = 1;
>> +
>> +	lpf_mxdiv = (nlpf * (MT_FE_CRYSTAL_KHZ / 1000) * lpf_coeff * 2 / f3db + 1) / 2;
>> +
>> +	if (lpf_mxdiv < mlpf_min){
>> +		nlpf++;
>> +		lpf_mxdiv = (nlpf * (MT_FE_CRYSTAL_KHZ / 1000) * lpf_coeff * 2  / f3db + 1) / 2;
>> +	}
>> +
>> +	if (lpf_mxdiv > mlpf_max)
>> +		lpf_mxdiv = mlpf_max;
>> +
>> +	m88ds3103_tuner_writereg(state, 0x04, lpf_mxdiv);
>> +	m88ds3103_tuner_writereg(state, 0x06, nlpf);
>> +	m88ds3103_tuner_writereg(state, 0x51, 0x1b);
>> +	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
>> +	m88ds3103_tuner_writereg(state, 0x50, 0x04);
>> +	m88ds3103_tuner_writereg(state, 0x50, 0x00);
>> +	msleep(5);
>> +	
>> +	if(state->tuner_id == TS2022_ID){
>> +		msleep(2);
>> +		value = m88ds3103_tuner_readreg(state, 0x26);
>> +		capCode = value & 0x3f;
>> +
>> +		m88ds3103_tuner_writereg(state, 0x41, 0x09);
>> +
>> +		m88ds3103_tuner_writereg(state, 0x51, 0x1b);
>> +		m88ds3103_tuner_writereg(state, 0x51, 0x1f);
>> +		m88ds3103_tuner_writereg(state, 0x50, 0x04);
>> +		m88ds3103_tuner_writereg(state, 0x50, 0x00);
>> +
>> +		msleep(2);
>> +		value = m88ds3103_tuner_readreg(state, 0x26);
>> +		value &= 0x3f;
>> +		value = (capCode + value) / 2;
>> +
>> +		value = value | 0x80;
>> +		m88ds3103_tuner_writereg(state, 0x25, value);
>> +		m88ds3103_tuner_writereg(state, 0x27, 0x30);
>> +
>> +		m88ds3103_tuner_writereg(state, 0x08, 0x09);		
>> +	}
>> +
>> +	/* Set the BB gain */
>> +	m88ds3103_tuner_writereg(state, 0x51, 0x1e);
>> +	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
>> +	m88ds3103_tuner_writereg(state, 0x50, 0x01);
>> +	m88ds3103_tuner_writereg(state, 0x50, 0x00);
>> +	if(state->tuner_id == TS2020_ID){
>> +		if(RFgain == 15){
>> +			msleep(40);
>> +			value = m88ds3103_tuner_readreg(state, 0x21);
>> +			value &= 0x0f;
>> +			if(value < 3){
>> +				m88ds3103_tuner_writereg(state, 0x60, 0x61);
>> +				m88ds3103_tuner_writereg(state, 0x51, 0x17);
>> +				m88ds3103_tuner_writereg(state, 0x51, 0x1f);
>> +				m88ds3103_tuner_writereg(state, 0x50, 0x08);
>> +				m88ds3103_tuner_writereg(state, 0x50, 0x00);
>> +			}			
>> +		}
>> +	}
>> +	msleep(60);
>> +	
>> +	offset_khz = (ndiv - ndiv % 2 + 1024) * MT_FE_CRYSTAL_KHZ
>> +		/ (6 + 8) / (div4 + 1) / 2 - realFreq;
>> +
>> +	m88ds3103_demod_connect(fe, offset_khz+lpf_offset_KHz);
>> +
>> +	for (i = 0; i < 30 ; i++) {
>> +		m88ds3103_read_status(fe, &status);
>> +		if (status & FE_HAS_LOCK){
>> +			break;
>> +                }
>> +		msleep(20);
>> +	}
>> +	
>> +	if((status & FE_HAS_LOCK) == 0){
>> +		state->delivery_system = (state->delivery_system == SYS_DVBS) ? SYS_DVBS2 : SYS_DVBS;
>> +		m88ds3103_demod_connect(fe, offset_khz);
>> +	
>> +		for (i = 0; i < 30 ; i++) {
>> +			m88ds3103_read_status(fe, &status);
>> +			if (status & FE_HAS_LOCK){
>> +				break;
>> +                	}
>> +			msleep(20);
>> +		}
>> +	}
>> +	
>> +	if (status & FE_HAS_LOCK){
>> +		if(state->config->start_ctrl){
>> +			if(state->first_lock == 0){
>> +				state->config->start_ctrl(fe);
>> +				state->first_lock = 1;	
>> +			}
>> +		}		
>> +	}
>> +		
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_tune(struct dvb_frontend *fe,
>> +			bool re_tune,
>> +			unsigned int mode_flags,
>> +			unsigned int *delay,
>> +			fe_status_t *status)
>> +{	
>> +	*delay = HZ / 5;
>> +	
>> +	dprintk("%s() ", __func__);
>> +	dprintk("re_tune = %d\n", re_tune);
>> +	
>> +	if (re_tune) {
>> +		int ret = m88ds3103_set_frontend(fe);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +	
>> +	return m88ds3103_read_status(fe, status);
>> +}
>> +
>> +static enum dvbfe_algo m88ds3103_get_algo(struct dvb_frontend *fe)
>> +{
>> +	return DVBFE_ALGO_HW;
>> +}
>> + 
>> + /*
>> + * Power config will reset and load initial firmware if required
>> + */
>> +static int m88ds3103_initilaze(struct dvb_frontend *fe)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	int ret;
>> +
>> +	dprintk("%s()\n", __func__);
>> +	/* hard reset */
>> +	m88ds3103_writereg(state, 0x07, 0x80);
>> +	m88ds3103_writereg(state, 0x07, 0x00);
>> +	msleep(1);
>> +	
>> +	m88ds3103_writereg(state, 0x08, 0x01 | m88ds3103_readreg(state, 0x08));
>> +	msleep(1);
>> +
>> +	if(state->tuner_id == TS2020_ID){
>> +		/* TS2020 init */
>> +		m88ds3103_tuner_writereg(state, 0x42, 0x73);
>> +		msleep(2);
>> +		m88ds3103_tuner_writereg(state, 0x05, 0x01);
>> +		m88ds3103_tuner_writereg(state, 0x62, 0xb5);
>> +		m88ds3103_tuner_writereg(state, 0x07, 0x02);
>> +		m88ds3103_tuner_writereg(state, 0x08, 0x01);
>> +	}
>> +	else if(state->tuner_id == TS2022_ID){
>> +		/* TS2022 init */
>> +		m88ds3103_tuner_writereg(state, 0x62, 0x6c);
>> +		msleep(2);
>> +		m88ds3103_tuner_writereg(state, 0x42, 0x6c);
>> +		msleep(2);
>> +		m88ds3103_tuner_writereg(state, 0x7d, 0x9d);
>> +		m88ds3103_tuner_writereg(state, 0x7c, 0x9a);
>> +		m88ds3103_tuner_writereg(state, 0x7a, 0x76);
>> +
>> +		m88ds3103_tuner_writereg(state, 0x3b, 0x01);
>> +		m88ds3103_tuner_writereg(state, 0x63, 0x88);
>> +
>> +		m88ds3103_tuner_writereg(state, 0x61, 0x85);
>> +		m88ds3103_tuner_writereg(state, 0x22, 0x30);
>> +		m88ds3103_tuner_writereg(state, 0x30, 0x40);
>> +		m88ds3103_tuner_writereg(state, 0x20, 0x23);
>> +		m88ds3103_tuner_writereg(state, 0x24, 0x02);
>> +		m88ds3103_tuner_writereg(state, 0x12, 0xa0);	
>> +	}
>> +		
>> +	if(state->demod_id == DS3103_ID){
>> +		m88ds3103_writereg(state, 0x07, 0xe0);
>> +		m88ds3103_writereg(state, 0x07, 0x00);
>> +		msleep(1);		
>> +	}
>> +	m88ds3103_writereg(state, 0xb2, 0x01);
>> +	
>> +	/* Load the firmware if required */
>> +	ret = m88ds3103_load_firmware(fe);
>> +	if (ret != 0){
>> +		printk(KERN_ERR "%s: Unable initialize firmware\n", __func__);
>> +		return ret;
>> +	}
>> +	if(state->demod_id == DS3103_ID){
>> +		m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d));
>> +		m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30));		
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +/*
>> + * Initialise or wake up device
>> + */
>> +static int m88ds3103_initfe(struct dvb_frontend *fe)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	u8 val;
>> +
>> +	dprintk("%s()\n", __func__);
>> +
>> +	/* 1st step to wake up demod */
>> +	m88ds3103_writereg(state, 0x08, 0x01 | m88ds3103_readreg(state, 0x08));
>> +	m88ds3103_writereg(state, 0x04, 0xfe & m88ds3103_readreg(state, 0x04));
>> +	m88ds3103_writereg(state, 0x23, 0xef & m88ds3103_readreg(state, 0x23));
>> +	
>> +	/* 2nd step to wake up tuner */
>> +	val = m88ds3103_tuner_readreg(state, 0x00) & 0xff;
>> +	if((val & 0x01) == 0){
>> +		m88ds3103_tuner_writereg(state, 0x00, 0x01);
>> +		msleep(50);
>> +	}
>> +	m88ds3103_tuner_writereg(state, 0x00, 0x03);
>> +	msleep(50);
>> +	
>> +	return 0;	
>> +}
>> +
>> +/* Put device to sleep */
>> +static int m88ds3103_sleep(struct dvb_frontend *fe)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +
>> +	dprintk("%s()\n", __func__);
>> +	
>> +	/* 1st step to sleep tuner */
>> +	m88ds3103_tuner_writereg(state, 0x00, 0x00);
>> +	
>> +	/* 2nd step to sleep demod */
>> +	m88ds3103_writereg(state, 0x08, 0xfe & m88ds3103_readreg(state, 0x08));
>> +	m88ds3103_writereg(state, 0x04, 0x01 | m88ds3103_readreg(state, 0x04));
>> +	m88ds3103_writereg(state, 0x23, 0x10 | m88ds3103_readreg(state, 0x23));
>> +	
>> +
>> +	return 0;
>> +}
>> +
>> +static struct dvb_frontend_ops m88ds3103_ops = {
>> +	.delsys = { SYS_DVBS, SYS_DVBS2},
>> +	.info = {
>> +		.name = "Montage DS3103/TS2022",
>> +		.type = FE_QPSK,
>> +		.frequency_min = 950000,
>> +		.frequency_max = 2150000,
>> +		.frequency_stepsize = 1011, /* kHz for QPSK frontends */
>> +		.frequency_tolerance = 5000,
>> +		.symbol_rate_min = 1000000,
>> +		.symbol_rate_max = 45000000,
>> +		.caps = FE_CAN_INVERSION_AUTO |
>> +			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
>> +			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
>> +			FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
>> +			FE_CAN_2G_MODULATION |
>> +			FE_CAN_QPSK | FE_CAN_RECOVER
>> +	},
>> +
>> +	.release = m88ds3103_release,
>> +
>> +	.init = m88ds3103_initfe,
>> +	.sleep = m88ds3103_sleep,
>> +	.read_status = m88ds3103_read_status,
>> +	.read_ber = m88ds3103_read_ber,
>> +	.read_signal_strength = m88ds3103_read_signal_strength,
>> +	.read_snr = m88ds3103_read_snr,
>> +	.read_ucblocks = m88ds3103_read_ucblocks,
>> +	.set_tone = m88ds3103_set_tone,
>> +	.set_voltage = m88ds3103_set_voltage,
>> +	.diseqc_send_master_cmd = m88ds3103_send_diseqc_msg,
>> +	.diseqc_send_burst = m88ds3103_diseqc_send_burst,
>> +	.get_frontend_algo = m88ds3103_get_algo,
>> +	.tune = m88ds3103_tune,
>> +	.set_frontend = m88ds3103_set_frontend,
>> +};
>> +
>> +MODULE_DESCRIPTION("DVB Frontend module for Montage DS3103/TS2022 hardware");
>> +MODULE_AUTHOR("Max nibble");
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/media/dvb/frontends/m88ds3103.h b/drivers/media/dvb/frontends/m88ds3103.h
>> new file mode 100644
>> index 0000000..c7b690e
>> --- /dev/null
>> +++ b/drivers/media/dvb/frontends/m88ds3103.h
>> @@ -0,0 +1,53 @@
>> +/*
>> +    Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner driver
>> +
>> +    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 M88DS3103_H
>> +#define M88DS3103_H
>> +
>> +#include <linux/dvb/frontend.h>
>> +
>> +struct m88ds3103_config {
>> +	/* the demodulator's i2c address */
>> +	u8 demod_address;
>> +	u8 ci_mode;
>> +	u8 pin_ctrl;
>> +	u8 ts_mode; /* 0: Parallel, 1: Serial */
>> +
>> +	/* Set device param to start dma */
>> +	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
>> +    /* Start to transfer data */
>> +    int (*start_ctrl)(struct dvb_frontend *fe);
>> +    /* Set LNB voltage */
>> +    int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
>> +};
>> +
>> +#if defined(CONFIG_DVB_M88DS3103) || \
>> +	(defined(CONFIG_DVB_M88DS3103_MODULE) && defined(MODULE))
>> +extern struct dvb_frontend *m88ds3103_attach(
>> +       const struct m88ds3103_config *config,
>> +       struct i2c_adapter *i2c);
>> +#else
>> +static inline struct dvb_frontend *m88ds3103_attach(
>> +       const struct m88ds3103_config *config,
>> +       struct i2c_adapter *i2c)
>> +{
>> +	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
>> +	return NULL;
>> +}
>> +#endif /* CONFIG_DVB_M88DS3103 */
>> +#endif /* M88DS3103_H */
>


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Re: [PATCH 5/6] m88ds3103, dvbsky remote control key map.
  2012-04-19 18:16     ` Mauro Carvalho Chehab
@ 2012-04-20  8:01       ` nibble.max
  0 siblings, 0 replies; 56+ messages in thread
From: nibble.max @ 2012-04-20  8:01 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

2012-04-20 15:53:20 nibble.max@gmail.com
>Em 15-04-2012 12:53, nibble.max escreveu:
>> dvbsky remote control key map for pci/pcie card.
>> 
>> Signed-off-by: Max nibble <nibble.max@gmail.com>
>> ---
>>  drivers/media/rc/keymaps/Makefile    |    1 +
>>  drivers/media/rc/keymaps/rc-dvbsky.c |   78 ++++++++++++++++++++++++++++++++++
>>  2 files changed, 79 insertions(+)
>>  create mode 100644 drivers/media/rc/keymaps/rc-dvbsky.c
>> 
>> diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
>> index 49ce266..e6a882b 100644
>> --- a/drivers/media/rc/keymaps/Makefile
>> +++ b/drivers/media/rc/keymaps/Makefile
>> @@ -26,6 +26,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
>>  			rc-dm1105-nec.o \
>>  			rc-dntv-live-dvb-t.o \
>>  			rc-dntv-live-dvbt-pro.o \
>> +			rc-dvbsky.o \
>>  			rc-em-terratec.o \
>>  			rc-encore-enltv2.o \
>>  			rc-encore-enltv.o \
>> diff --git a/drivers/media/rc/keymaps/rc-dvbsky.c b/drivers/media/rc/keymaps/rc-dvbsky.c
>> new file mode 100644
>> index 0000000..2bd9977
>> --- /dev/null
>> +++ b/drivers/media/rc/keymaps/rc-dvbsky.c
>> @@ -0,0 +1,78 @@
>> +/* rc-dvbsky.c - Keytable for Dvbsky Remote Controllers
>> + *
>> + * keymap imported from ir-keymaps.c
>
>No, you didn't import it from ir-keymaps.c ;) This is the old file where several
>keymaps used to be stored.
>
>> + *
>> + *
>> + * Copyright (c) 2010-2011 by Mauro Carvalho Chehab <mchehab@redhat.com>
>
>Huh? I didn't wrote this keymap.
>
>> + *
>> + * 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.
>> + */
>> +
>> +#include <media/rc-map.h>
>> +#include <linux/module.h>
>> +/*
>> + * This table contains the complete RC5 code, instead of just the data part
>> + */
>> +
>> +static struct rc_map_table rc5_dvbsky[] = {
>> +	{ 0x0000, KEY_0 },
>> +	{ 0x0001, KEY_1 },
>> +	{ 0x0002, KEY_2 },
>> +	{ 0x0003, KEY_3 },
>> +	{ 0x0004, KEY_4 },
>> +	{ 0x0005, KEY_5 },
>> +	{ 0x0006, KEY_6 },
>> +	{ 0x0007, KEY_7 },
>> +	{ 0x0008, KEY_8 },
>> +	{ 0x0009, KEY_9 },	
>> +	{ 0x000a, KEY_MUTE },
>> +	{ 0x000d, KEY_OK },
>> +	{ 0x000b, KEY_STOP },
>> +	{ 0x000c, KEY_EXIT },	
>> +	{ 0x000e, KEY_CAMERA }, /*Snap shot*/
>> +	{ 0x000f, KEY_SUBTITLE }, /*PIP*/
>> +	{ 0x0010, KEY_VOLUMEUP },
>> +	{ 0x0011, KEY_VOLUMEDOWN },
>> +	{ 0x0012, KEY_FAVORITES },
>> +	{ 0x0013, KEY_LIST }, /*Info*/
>> +	{ 0x0016, KEY_PAUSE },
>> +	{ 0x0017, KEY_PLAY },
>> +	{ 0x001f, KEY_RECORD },
>> +	{ 0x0020, KEY_CHANNELDOWN },
>> +	{ 0x0021, KEY_CHANNELUP },
>> +	{ 0x0025, KEY_POWER2 },
>> +	{ 0x0026, KEY_REWIND },
>> +	{ 0x0027, KEY_FASTFORWARD },
>> +	{ 0x0029, KEY_LAST },
>> +	{ 0x002b, KEY_MENU },	
>> +	{ 0x002c, KEY_EPG },
>> +	{ 0x002d, KEY_ZOOM },	
>
>Hmm... are you sure that your IR getkey function is right? 
>There are a few RC-5 IR's that uses only 6 bits, but this is not
>common. I suspect that your code is missing the higher bits.
>
>It would be nice if you could test it with another RC5 IR, or
>to test your RC-5 with some other IR receiver, in order to double
>check it.
I check the remote controller from dvbsky supply.
It's 5 address bits are all zero. It works.
>
>> +};
>> +
>> +static struct rc_map_list rc5_dvbsky_map = {
>> +	.map = {
>> +		.scan    = rc5_dvbsky,
>> +		.size    = ARRAY_SIZE(rc5_dvbsky),
>> +		.rc_type = RC_TYPE_RC5,
>> +		.name    = RC_MAP_DVBSKY,
>> +	}
>> +};
>> +
>> +static int __init init_rc_map_rc5_dvbsky(void)
>> +{
>> +	return rc_map_register(&rc5_dvbsky_map);
>> +}
>> +
>> +static void __exit exit_rc_map_rc5_dvbsky(void)
>> +{
>> +	rc_map_unregister(&rc5_dvbsky_map);
>> +}
>> +
>> +module_init(init_rc_map_rc5_dvbsky)
>> +module_exit(exit_rc_map_rc5_dvbsky)
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
>
>Again, I didn't write it. You did ;)
>
>Regards,
>Mauro
>
>


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-19 18:06     ` Mauro Carvalho Chehab
@ 2012-04-20  8:01       ` nibble.max
  0 siblings, 0 replies; 56+ messages in thread
From: nibble.max @ 2012-04-20  8:01 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

2012-04-20 15:48:53 nibble.max@gmail.com
Mauro, thank you.
>
>Hi Max,
>
>Em 15-04-2012 12:53, nibble.max escreveu:
>> Montage m88ds3103 demodulator and ts2022 tuner driver.
>> 
>> Signed-off-by: Max nibble <nibble.max@gmail.com>
>
>Please always test any patch you send upstream with ./scripts/checkpatch.pl.
>
>It analyses the code and checks if it is following the Linux Coding Style
>(Documentation/CodingStyle).
>
>From what I've seen, there are several small CodingStyle issues on this patch.
>
>There's also another problem here: this driver is mixing an I2C tuner driver
>with the demod one. Please split. If the tuner is simple enough, you an add
>it to:
>	drivers/media/common/tuners/tuner-simple.c
>or at:
>	drivers/media/dvb/frontends/dvb-pll.c
>
>But please don't mix tuners with demods. Mixing it causes code duplication and
>more time lost when debugging it (as two different version of the same driver
>can have different bugs).
I check the tuner-simple.c and dvb-pll.c is not fit for m88ts202x tuner.
Should we create a new tuner file like "stv6110x"?
>
>I'll analyze it deeper after you fix those two issues.
>
>Thanks,
>Mauro
>
>
>> ---
>>  drivers/media/dvb/frontends/Kconfig     |    7 +
>>  drivers/media/dvb/frontends/Makefile    |    2 +
>>  drivers/media/dvb/frontends/m88ds3103.c | 1851 +++++++++++++++++++++++++++++++
>>  drivers/media/dvb/frontends/m88ds3103.h |   53 +
>>  4 files changed, 1913 insertions(+)
>>  create mode 100644 drivers/media/dvb/frontends/m88ds3103.c
>>  create mode 100644 drivers/media/dvb/frontends/m88ds3103.h
>> 
>> diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
>> index e11adb6..d2bb312 100644
>> --- a/drivers/media/dvb/frontends/Kconfig
>> +++ b/drivers/media/dvb/frontends/Kconfig
>> @@ -214,6 +214,13 @@ config DVB_CX24116
>>  	help
>>  	  A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
>>  
>> +config DVB_M88DS3103
>> +	tristate "Montage DS3103 based"
>> +	depends on DVB_CORE && I2C
>> +	default m if DVB_FE_CUSTOMISE
>> +	help
>> +	  A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
>> +	  
>>  config DVB_SI21XX
>>  	tristate "Silicon Labs SI21XX based"
>>  	depends on DVB_CORE && I2C
>> diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
>> index 6ca7557..84ddf41 100644
>> --- a/drivers/media/dvb/frontends/Makefile
>> +++ b/drivers/media/dvb/frontends/Makefile
>> @@ -98,5 +98,7 @@ obj-$(CONFIG_DVB_A8293) += a8293.o
>>  obj-$(CONFIG_DVB_TDA10071) += tda10071.o
>>  obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
>>  obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
>> +obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o
>>  obj-$(CONFIG_DVB_AF9033) += af9033.o
>>  
>> +
>> diff --git a/drivers/media/dvb/frontends/m88ds3103.c b/drivers/media/dvb/frontends/m88ds3103.c
>> new file mode 100644
>> index 0000000..a186ba0
>> --- /dev/null
>> +++ b/drivers/media/dvb/frontends/m88ds3103.c
>> @@ -0,0 +1,1851 @@
>> +/*
>> +    Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner driver
>> +
>> +    Copyright (C) 2011 Max nibble<nibble.max@gmail.com>
>> +    Copyright (C) 2010 Montage Technology<www.montage-tech.com>
>> +    Copyright (C) 2009 Konstantin Dimitrov.
>> +
>> +    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/slab.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/moduleparam.h>
>> +#include <linux/init.h>
>> +#include <linux/firmware.h>
>> +
>> +#include "dvb_frontend.h"
>> +#include "m88ds3103.h"
>> +
>> +static int debug;
>> +module_param(debug, int, 0644);
>> +MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
>> +
>> +#define dprintk(args...) \
>> +	do { \
>> +		if (debug) \
>> +			printk(KERN_INFO "m88ds3103: " args); \
>> +	} while (0)
>> +
>> +#define FW_DOWN_SIZE 32
>> +#define FW_DOWN_LOOP (8192/FW_DOWN_SIZE)
>> +#define DS3103_DEFAULT_FIRMWARE "dvb-fe-ds3103.fw"
>> +#define DS3000_DEFAULT_FIRMWARE "dvb-fe-ds300x.fw"
>> +#define MT_FE_MCLK_KHZ 96000 /* in kHz */
>> +#define MT_FE_CRYSTAL_KHZ   27000 /* in kHz */
>> +#define FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz 3000
>> +#define DS3000_ID	0x3000
>> +#define DS3103_ID	0x3103
>> +#define TS2020_ID	0x2020
>> +#define TS2022_ID	0x2022
>> +#define UNKNOW_ID	0x0000
>> +
>> +/* For M88DS3103 demod dvbs mode.*/
>> +static u8 ds3103_dvbs_init_tab[] = {
>> +	0x23, 0x07,
>> +	0x08, 0x03,
>> +	0x0c, 0x02,
>> +	0x21, 0x54,
>> +	0x25, 0x82,
>> +	0x27, 0x31,
>> +	0x30, 0x08,
>> +	0x31, 0x40,
>> +	0x32, 0x32,
>> +	0x33, 0x35,
>> +	0x35, 0xff,
>> +	0x3a, 0x00,
>> +	0x37, 0x10,
>> +	0x38, 0x10,
>> +	0x39, 0x02,
>> +	0x42, 0x60,
>> +	0x4a, 0x80,
>> +	0x4b, 0x04,
>> +	0x4d, 0x91,
>> +	0x5d, 0xc8,
>> +	0x50, 0x36,
>> +	0x51, 0x36,
>> +	0x52, 0x36,
>> +	0x53, 0x36,
>> +	0x63, 0x0f,
>> +	0x64, 0x30,
>> +	0x65, 0x40,
>> +	0x68, 0x26,
>> +	0x69, 0x4c,
>> +	0x70, 0x20,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x40,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x60,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x80,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0xa0,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x1f,
>> +	0x76, 0x38,
>> +	0x77, 0xa6,
>> +	0x78, 0x0c,
>> +	0x79, 0x80,
>> +	0x7f, 0x14,
>> +	0x7c, 0x00,
>> +	0xae, 0x82,
>> +	0x80, 0x64,
>> +	0x81, 0x66,
>> +	0x82, 0x44,
>> +	0x85, 0x04,
>> +	0xcd, 0xf4,
>> +	0x90, 0x33,
>> +	0xa0, 0x44,
>> +	0xc0, 0x08,
>> +	0xc3, 0x10,
>> +	0xc4, 0x08,
>> +	0xc5, 0xf0,
>> +	0xc6, 0xff,
>> +	0xc7, 0x00,
>> +	0xc8, 0x1a,
>> +	0xc9, 0x80,
>> +	0xe0, 0xf8,
>> +	0xe6, 0x8b,
>> +	0xd0, 0x40,
>> +	0xf8, 0x20,
>> +	0xfa, 0x0f,
>> +	0x00, 0x00,
>> +	0xbd, 0x01,
>> +	0xb8, 0x00,
>> +};
>> +/* For M88DS3103 demod dvbs2 mode.*/
>> +static u8 ds3103_dvbs2_init_tab[] = {
>> +	0x23, 0x07,
>> +	0x08, 0x07,
>> +	0x0c, 0x02,
>> +	0x21, 0x54,
>> +	0x25, 0x82,
>> +	0x27, 0x31,
>> +	0x30, 0x08,
>> +	0x32, 0x32,
>> +	0x33, 0x35,
>> +	0x35, 0xff,
>> +	0x3a, 0x00,
>> +	0x37, 0x10,
>> +	0x38, 0x10,
>> +	0x39, 0x02,
>> +	0x42, 0x60,
>> +	0x4a, 0x80,
>> +	0x4b, 0x04,
>> +	0x4d, 0x91,
>> +	0x5d, 0xc8,
>> +	0x50, 0x36,
>> +	0x51, 0x36,
>> +	0x52, 0x36,
>> +	0x53, 0x36,
>> +	0x63, 0x0f,
>> +	0x64, 0x10,
>> +	0x65, 0x20,
>> +	0x68, 0x46,
>> +	0x69, 0xcd,
>> +	0x70, 0x20,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x40,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x60,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x80,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0xa0,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x1f,
>> +	0x76, 0x38,
>> +	0x77, 0xa6,
>> +	0x78, 0x0c,
>> +	0x79, 0x80,
>> +	0x7f, 0x14,
>> +	0x85, 0x08,
>> +	0xcd, 0xf4,
>> +	0x90, 0x33,
>> +	0x86, 0x00,
>> +	0x87, 0x0f,
>> +	0x89, 0x00,
>> +	0x8b, 0x44,
>> +	0x8c, 0x66,
>> +	0x9d, 0xc1,
>> +	0x8a, 0x10,
>> +	0xad, 0x40,
>> +	0xa0, 0x44,
>> +	0xc0, 0x08,
>> +	0xc1, 0x10,
>> +	0xc2, 0x08,
>> +	0xc3, 0x10,
>> +	0xc4, 0x08,
>> +	0xc5, 0xf0,
>> +	0xc6, 0xff,
>> +	0xc7, 0x00,
>> +	0xc8, 0x1a,
>> +	0xc9, 0x80,
>> +	0xca, 0x23,
>> +	0xcb, 0x24,
>> +	0xcc, 0xf4,
>> +	0xce, 0x74,
>> +	0x00, 0x00,
>> +	0xbd, 0x01,
>> +	0xb8, 0x00,
>> +};
>> +
>> +/* For M88DS3000 demod dvbs mode.*/
>> +static u8 ds3000_dvbs_init_tab[] = {
>> +	0x23, 0x05,
>> +	0x08, 0x03,
>> +	0x0c, 0x02,
>> +	0x21, 0x54,
>> +	0x25, 0x82,
>> +	0x27, 0x31,
>> +	0x30, 0x08,
>> +	0x31, 0x40,
>> +	0x32, 0x32,
>> +	0x33, 0x35,
>> +	0x35, 0xff,
>> +	0x3a, 0x00,
>> +	0x37, 0x10,
>> +	0x38, 0x10,
>> +	0x39, 0x02,
>> +	0x42, 0x60,
>> +	0x4a, 0x40,
>> +	0x4b, 0x04,
>> +	0x4d, 0x91,
>> +	0x5d, 0xc8,
>> +	0x50, 0x77,
>> +	0x51, 0x77,
>> +	0x52, 0x36,
>> +	0x53, 0x36,
>> +	0x56, 0x01,
>> +	0x63, 0x47,
>> +	0x64, 0x30,
>> +	0x65, 0x40,
>> +	0x68, 0x26,
>> +	0x69, 0x4c,
>> +	0x70, 0x20,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x40,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x60,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x80,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0xa0,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x1f,
>> +	0x76, 0x00,
>> +	0x77, 0xd1,
>> +	0x78, 0x0c,
>> +	0x79, 0x80,
>> +	0x7f, 0x04,
>> +	0x7c, 0x00,
>> +	0x80, 0x86,
>> +	0x81, 0xa6,
>> +	0x85, 0x04,
>> +	0xcd, 0xf4,
>> +	0x90, 0x33,
>> +	0xa0, 0x44,
>> +	0xc0, 0x18,
>> +	0xc3, 0x10,
>> +	0xc4, 0x08,
>> +	0xc5, 0x80,
>> +	0xc6, 0x80,
>> +	0xc7, 0x0a,
>> +	0xc8, 0x1a,
>> +	0xc9, 0x80,
>> +	0xfe, 0xb6,
>> +	0xe0, 0xf8,
>> +	0xe6, 0x8b,
>> +	0xd0, 0x40,
>> +	0xf8, 0x20,
>> +	0xfa, 0x0f,
>> +	0xad, 0x20,
>> +	0xae, 0x07,
>> +	0xb8, 0x00,
>> +};
>> +
>> +/* For M88DS3000 demod dvbs2 mode.*/
>> +static u8 ds3000_dvbs2_init_tab[] = {
>> +	0x23, 0x0f,
>> +	0x08, 0x07,
>> +	0x0c, 0x02,
>> +	0x21, 0x54,
>> +	0x25, 0x82,
>> +	0x27, 0x31,
>> +	0x30, 0x08,
>> +	0x31, 0x32,
>> +	0x32, 0x32,
>> +	0x33, 0x35,
>> +	0x35, 0xff,
>> +	0x3a, 0x00,
>> +	0x37, 0x10,
>> +	0x38, 0x10,
>> +	0x39, 0x02,
>> +	0x42, 0x60,
>> +	0x4a, 0x80,
>> +	0x4b, 0x04,
>> +	0x4d, 0x91,
>> +	0x5d, 0x88,
>> +	0x50, 0x36,
>> +	0x51, 0x36,
>> +	0x52, 0x36,
>> +	0x53, 0x36,
>> +	0x63, 0x60,
>> +	0x64, 0x10,
>> +	0x65, 0x10,
>> +	0x68, 0x04,
>> +	0x69, 0x29,
>> +	0x70, 0x20,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x40,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x60,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x80,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0xa0,
>> +	0x71, 0x70,
>> +	0x72, 0x04,
>> +	0x73, 0x00,
>> +	0x70, 0x1f,
>> +	0xa0, 0x44,
>> +	0xc0, 0x08,
>> +	0xc1, 0x10,
>> +	0xc2, 0x08,
>> +	0xc3, 0x10,
>> +	0xc4, 0x08,
>> +	0xc5, 0xf0,
>> +	0xc6, 0xf0,
>> +	0xc7, 0x0a,
>> +	0xc8, 0x1a,
>> +	0xc9, 0x80,
>> +	0xca, 0x23,
>> +	0xcb, 0x24,
>> +	0xce, 0x74,
>> +	0x56, 0x01,
>> +	0x90, 0x03,
>> +	0x76, 0x80,
>> +	0x77, 0x42,
>> +	0x78, 0x0a,
>> +	0x79, 0x80,
>> +	0xad, 0x40,
>> +	0xae, 0x07,
>> +	0x7f, 0xd4,
>> +	0x7c, 0x00,
>> +	0x80, 0xa8,
>> +	0x81, 0xda,
>> +	0x7c, 0x01,
>> +	0x80, 0xda,
>> +	0x81, 0xec,
>> +	0x7c, 0x02,
>> +	0x80, 0xca,
>> +	0x81, 0xeb,
>> +	0x7c, 0x03,
>> +	0x80, 0xba,
>> +	0x81, 0xdb,
>> +	0x85, 0x08,
>> +	0x86, 0x00,
>> +	0x87, 0x02,
>> +	0x89, 0x80,
>> +	0x8b, 0x44,
>> +	0x8c, 0xaa,
>> +	0x8a, 0x10,
>> +	0xba, 0x00,
>> +	0xf5, 0x04,
>> +	0xd2, 0x32,
>> +	0xb8, 0x00,
>> +};
>> +
>> +struct m88ds3103_state {
>> +	struct i2c_adapter *i2c;
>> +	const struct m88ds3103_config *config;
>> +	
>> +	struct dvb_frontend frontend;
>> +	
>> +	u32 preBer;
>> +	u8 skip_fw_load;	
>> +	u8 first_lock; /* The first time of signal lock */
>> +	u16 demod_id; /* demod chip type */
>> +	u16 tuner_id; /* tuner chip type */
>> +	fe_delivery_system_t delivery_system;
>> +};
>> +
>> +/*demod register operations.*/
>> +static int m88ds3103_writereg(struct m88ds3103_state *state, int reg, int data)
>> +{
>> +	u8 buf[] = { reg, data };
>> +	struct i2c_msg msg = { .addr = state->config->demod_address,
>> +		.flags = 0, .buf = buf, .len = 2 };
>> +	int err;
>> +
>> +	if (debug > 1)
>> +		printk("m88ds3103: %s: write reg 0x%02x, value 0x%02x\n",
>> +			__func__, reg, data);
>> +
>> +	err = i2c_transfer(state->i2c, &msg, 1);
>> +	if (err != 1) {
>> +		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x,"
>> +			 " value == 0x%02x)\n", __func__, err, reg, data);
>> +		return -EREMOTEIO;
>> +	}
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_readreg(struct m88ds3103_state *state, u8 reg)
>> +{
>> +	int ret;
>> +	u8 b0[] = { reg };
>> +	u8 b1[] = { 0 };
>> +	struct i2c_msg msg[] = {
>> +		{ .addr = state->config->demod_address, .flags = 0,
>> +			.buf = b0, .len = 1 },
>> +		{ .addr = state->config->demod_address, .flags = I2C_M_RD,
>> +			.buf = b1, .len = 1 }
>> +	};
>> +	ret = i2c_transfer(state->i2c, msg, 2);
>> +
>> +	if (ret != 2) {
>> +		printk(KERN_ERR "%s: reg=0x%x (error=%d)\n",
>> +			__func__, reg, ret);
>> +		return ret;
>> +	}
>> +
>> +	if (debug > 1)
>> +		printk(KERN_INFO "m88ds3103: read reg 0x%02x, value 0x%02x\n",
>> +			reg, b1[0]);
>> +
>> +	return b1[0];
>> +}
>> +
>> +/*tuner register operations.*/
>> +static int m88ds3103_tuner_writereg(struct m88ds3103_state *state, int reg, int data)
>> +{
>> +	u8 buf[] = { reg, data };
>> +	struct i2c_msg msg = { .addr = 0x60,
>> +		.flags = 0, .buf = buf, .len = 2 };
>> +	int err;
>> +
>> +	m88ds3103_writereg(state, 0x03, 0x11);
>> +	err = i2c_transfer(state->i2c, &msg, 1);
>> +	
>> +	if (err != 1) {
>> +		printk("%s: writereg error(err == %i, reg == 0x%02x,"
>> +			 " value == 0x%02x)\n", __func__, err, reg, data);
>> +		return -EREMOTEIO;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_tuner_readreg(struct m88ds3103_state *state, u8 reg)
>> +{
>> +	int ret;
>> +	u8 b0[] = { reg };
>> +	u8 b1[] = { 0 };
>> +	struct i2c_msg msg[] = {
>> +		{ .addr = 0x60, .flags = 0,
>> +			.buf = b0, .len = 1 },
>> +		{ .addr = 0x60, .flags = I2C_M_RD,
>> +			.buf = b1, .len = 1 }
>> +	};
>> +
>> +	m88ds3103_writereg(state, 0x03, 0x11);	
>> +	ret = i2c_transfer(state->i2c, msg, 2);
>> +
>> +	if (ret != 2) {
>> +		printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);
>> +		return ret;
>> +	}
>> +
>> +	return b1[0];
>> +}
>> +
>> +/* Bulk demod I2C write, for firmware download. */
>> +static int m88ds3103_writeregN(struct m88ds3103_state *state, int reg,
>> +				const u8 *data, u16 len)
>> +{
>> +	int ret = -EREMOTEIO;
>> +	struct i2c_msg msg;
>> +	u8 *buf;
>> +
>> +	buf = kmalloc(len + 1, GFP_KERNEL);
>> +	if (buf == NULL) {
>> +		printk("Unable to kmalloc\n");
>> +		ret = -ENOMEM;
>> +		goto error;
>> +	}
>> +
>> +	*(buf) = reg;
>> +	memcpy(buf + 1, data, len);
>> +
>> +	msg.addr = state->config->demod_address;
>> +	msg.flags = 0;
>> +	msg.buf = buf;
>> +	msg.len = len + 1;
>> +
>> +	if (debug > 1)
>> +		printk(KERN_INFO "m88ds3103: %s:  write regN 0x%02x, len = %d\n",
>> +			__func__, reg, len);
>> +
>> +	ret = i2c_transfer(state->i2c, &msg, 1);
>> +	if (ret != 1) {
>> +		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n",
>> +			 __func__, ret, reg);
>> +		ret = -EREMOTEIO;
>> +	}
>> +	
>> +error:
>> +	kfree(buf);
>> +
>> +	return ret;
>> +}
>> +
>> +static int m88ds3103_load_firmware(struct dvb_frontend *fe)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	const struct firmware *fw;
>> +	int i, ret = 0;
>> +
>> +	dprintk("%s()\n", __func__);
>> +		
>> +	if (state->skip_fw_load)
>> +		return 0;
>> +	/* Load firmware */
>> +	/* request the firmware, this will block until someone uploads it */	
>> +	if(state->demod_id == DS3000_ID){
>> +		printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__,
>> +				DS3000_DEFAULT_FIRMWARE);		
>> +		ret = request_firmware(&fw, DS3000_DEFAULT_FIRMWARE,
>> +					state->i2c->dev.parent);
>> +	}else if(state->demod_id == DS3103_ID){
>> +		printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__,
>> +				DS3103_DEFAULT_FIRMWARE);
>> +		ret = request_firmware(&fw, DS3103_DEFAULT_FIRMWARE,
>> +					state->i2c->dev.parent);
>> +	}
>> +	
>> +	printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__);
>> +	if (ret) {
>> +		printk(KERN_ERR "%s: No firmware uploaded (timeout or file not "
>> +				"found?)\n", __func__);
>> +		return ret;
>> +	}
>> +
>> +	/* Make sure we don't recurse back through here during loading */
>> +	state->skip_fw_load = 1;
>> +
>> +	dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
>> +			fw->size,
>> +			fw->data[0],
>> +			fw->data[1],
>> +			fw->data[fw->size - 2],
>> +			fw->data[fw->size - 1]);
>> +			
>> +	/* stop internal mcu. */
>> +	m88ds3103_writereg(state, 0xb2, 0x01);
>> +	/* split firmware to download.*/
>> +	for(i = 0; i < FW_DOWN_LOOP; i++){
>> +		ret = m88ds3103_writeregN(state, 0xb0, &(fw->data[FW_DOWN_SIZE*i]), FW_DOWN_SIZE);
>> +		if(ret != 1) break;		
>> +	}
>> +	/* start internal mcu. */
>> +	if(ret == 1)
>> +		m88ds3103_writereg(state, 0xb2, 0x00);
>> +		
>> +	release_firmware(fw);
>> +
>> +	dprintk("%s: Firmware upload %s\n", __func__,
>> +			ret == 1 ? "complete" : "failed");
>> +
>> +	if(ret == 1) ret = 0;
>> +	
>> +	/* Ensure firmware is always loaded if required */
>> +	state->skip_fw_load = 0;
>> +
>> +	return ret;
>> +}
>> +
>> +
>> +static int m88ds3103_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	u8 data;
>> +
>> +	dprintk("%s(%d)\n", __func__, voltage);
>> +
>> +	dprintk("m88ds3103:pin_ctrl = (%02x)\n", state->config->pin_ctrl);
>> +	
>> +	if(state->config->set_voltage)
>> +		state->config->set_voltage(fe, voltage);
>> +	
>> +	data = m88ds3103_readreg(state, 0xa2);
>> +	
>> +        if(state->config->pin_ctrl & 0x80){ /*If control pin is assigned.*/
>> +	        data &= ~0x03; /* bit0 V/H, bit1 off/on */
>> +	        if(state->config->pin_ctrl & 0x02)
>> +		     data |= 0x02;
>> +
>> +	        switch (voltage) {
>> +	        case SEC_VOLTAGE_18:
>> +		     if((state->config->pin_ctrl & 0x01) == 0)
>> +			  data |= 0x01;
>> +		     break;
>> +	        case SEC_VOLTAGE_13:
>> +		     if(state->config->pin_ctrl & 0x01)
>> +			  data |= 0x01;
>> +		     break;
>> +	        case SEC_VOLTAGE_OFF:
>> +		     if(state->config->pin_ctrl & 0x02)
>> +			   data &= ~0x02;			
>> +		     else
>> +			   data |= 0x02;
>> +		     break;
>> +	         }
>> +        }
>> +
>> +	m88ds3103_writereg(state, 0xa2, data);
>> +
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_read_status(struct dvb_frontend *fe, fe_status_t* status)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	int lock = 0;
>> +	
>> +	*status = 0;
>> +	
>> +	switch (state->delivery_system){
>> +	case SYS_DVBS:
>> +		lock = m88ds3103_readreg(state, 0xd1);
>> +		dprintk("%s: SYS_DVBS status=%x.\n", __func__, lock);
>> +		
>> +		if ((lock & 0x07) == 0x07){
>> +			/*if((m88ds3103_readreg(state, 0x0d) & 0x07) == 0x07)*/
>> +				*status = FE_HAS_SIGNAL | FE_HAS_CARRIER 
>> +					| FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
>> +			
>> +		}
>> +		break;
>> +	case SYS_DVBS2:
>> +		lock = m88ds3103_readreg(state, 0x0d);
>> +		dprintk("%s: SYS_DVBS2 status=%x.\n", __func__, lock);
>> +
>> +		if ((lock & 0x8f) == 0x8f)
>> +			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER 
>> +				| FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
>> +			
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_read_ber(struct dvb_frontend *fe, u32* ber)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	u8 tmp1, tmp2, tmp3;
>> +	u32 ldpc_frame_cnt, pre_err_packags, code_rate_fac = 0;
>> +
>> +	dprintk("%s()\n", __func__);
>> +
>> +	switch (state->delivery_system) {
>> +	case SYS_DVBS:
>> +		m88ds3103_writereg(state, 0xf9, 0x04);
>> +		tmp3 = m88ds3103_readreg(state, 0xf8);
>> +		if ((tmp3&0x10) == 0){
>> +			tmp1 = m88ds3103_readreg(state, 0xf7);
>> +			tmp2 = m88ds3103_readreg(state, 0xf6);
>> +			tmp3 |= 0x10;
>> +			m88ds3103_writereg(state, 0xf8, tmp3);
>> +			state->preBer = (tmp1<<8) | tmp2;
>> +		}
>> +		break;
>> +	case SYS_DVBS2:
>> +		tmp1 = m88ds3103_readreg(state, 0x7e) & 0x0f;
>> +		switch(tmp1){
>> +		case 0:	code_rate_fac = 16008 - 80; break;
>> +		case 1:	code_rate_fac = 21408 - 80; break;
>> +		case 2:	code_rate_fac = 25728 - 80; break;
>> +		case 3:	code_rate_fac = 32208 - 80; break;
>> +		case 4:	code_rate_fac = 38688 - 80; break;
>> +		case 5:	code_rate_fac = 43040 - 80; break;
>> +		case 6:	code_rate_fac = 48408 - 80; break;
>> +		case 7:	code_rate_fac = 51648 - 80; break;
>> +		case 8:	code_rate_fac = 53840 - 80; break;
>> +		case 9:	code_rate_fac = 57472 - 80; break;
>> +		case 10: code_rate_fac = 58192 - 80; break;
>> +		}
>> +		
>> +		tmp1 = m88ds3103_readreg(state, 0xd7) & 0xff;
>> +		tmp2 = m88ds3103_readreg(state, 0xd6) & 0xff;
>> +		tmp3 = m88ds3103_readreg(state, 0xd5) & 0xff;		
>> +		ldpc_frame_cnt = (tmp1 << 16) | (tmp2 << 8) | tmp3;
>> +
>> +		tmp1 = m88ds3103_readreg(state, 0xf8) & 0xff;
>> +		tmp2 = m88ds3103_readreg(state, 0xf7) & 0xff;
>> +		pre_err_packags = tmp1<<8 | tmp2;
>> +		
>> +		if (ldpc_frame_cnt > 1000){
>> +			m88ds3103_writereg(state, 0xd1, 0x01);
>> +			m88ds3103_writereg(state, 0xf9, 0x01);
>> +			m88ds3103_writereg(state, 0xf9, 0x00);
>> +			m88ds3103_writereg(state, 0xd1, 0x00);
>> +			state->preBer = pre_err_packags;
>> +		} 				
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +	*ber = state->preBer;
>> +	
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_read_signal_strength(struct dvb_frontend *fe,
>> +						u16 *signal_strength)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	u16 gain;
>> +	u8 gain1, gain2, gain3 = 0;
>> +
>> +	dprintk("%s()\n", __func__);
>> +
>> +	gain1 = m88ds3103_tuner_readreg(state, 0x3d) & 0x1f;
>> +	dprintk("%s: gain1 = 0x%02x \n", __func__, gain1);
>> +	
>> +	if (gain1 > 15) gain1 = 15;
>> +	gain2 = m88ds3103_tuner_readreg(state, 0x21) & 0x1f;
>> +	dprintk("%s: gain2 = 0x%02x \n", __func__, gain2);
>> +	
>> +	if(state->tuner_id == TS2022_ID){
>> +		gain3 = (m88ds3103_tuner_readreg(state, 0x66)>>3) & 0x07;
>> +		dprintk("%s: gain3 = 0x%02x \n", __func__, gain3);
>> +		
>> +		if (gain2 > 16) gain2 = 16;
>> +		if (gain2 < 2) gain2 = 2;			
>> +		if (gain3 > 6) gain3 = 6;
>> +	}else{
>> +		if (gain2 > 13) gain2 = 13;
>> +		gain3 = 0;
>> +	}
>> +
>> +	gain = gain1*23 + gain2*35 + gain3*29;
>> +	*signal_strength = 60000 - gain*55;
>> +
>> +	return 0;
>> +}
>> +
>> +
>> +static int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *p_snr)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	u8 val, npow1, npow2, spow1, cnt;
>> +	u16 tmp, snr;
>> +	u32 npow, spow, snr_total;	
>> +	static const u16 mes_log10[] ={
>> +		0,	3010,	4771,	6021, 	6990,	7781,	8451,	9031,	9542,	10000,
>> +		10414,	10792,	11139,	11461,	11761,	12041,	12304,	12553,	12788,	13010,
>> +		13222,	13424,	13617,	13802,	13979,	14150,	14314,	14472,	14624,	14771,
>> +		14914,	15052,	15185,	15315,	15441,	15563,	15682,	15798,	15911,	16021,
>> +		16128,	16232,	16335,	16435,	16532,	16628,	16721,	16812,	16902,	16990,
>> +		17076,	17160,	17243,	17324,	17404,	17482,	17559,	17634,	17709,	17782,
>> +		17853,	17924,	17993,	18062,	18129,	18195,	18261,	18325,	18388,	18451,
>> +		18513,	18573,	18633,	18692,	18751,	18808,	18865,	18921,	18976,	19031
>> +	};
>> +	static const u16 mes_loge[] ={
>> +		0,	6931,	10986,	13863, 	16094,	17918,	19459,	20794,	21972,	23026,
>> +		23979,	24849,	25649,	26391,	27081,	27726,	28332,	28904,	29444,	29957,
>> +		30445,	30910,	31355,	31781,	32189,	32581,	32958,	33322,	33673,	34012,
>> +		34340,	34657,
>> +	};
>> +
>> +	dprintk("%s()\n", __func__);
>> +
>> +	snr = 0;
>> +	
>> +	switch (state->delivery_system){
>> +	case SYS_DVBS:
>> +		cnt = 10; snr_total = 0;
>> +		while(cnt > 0){
>> +			val = m88ds3103_readreg(state, 0xff);
>> +			snr_total += val;
>> +			cnt--;
>> +		}
>> +		tmp = (u16)(snr_total/80);
>> +		if(tmp > 0){
>> +			if (tmp > 32) tmp = 32;
>> +			snr = (mes_loge[tmp - 1] * 100) / 45;
>> +		}else{
>> +			snr = 0;
>> +		}
>> +		break;
>> +	case SYS_DVBS2:
>> +		cnt  = 10; npow = 0; spow = 0;
>> +		while(cnt >0){
>> +			npow1 = m88ds3103_readreg(state, 0x8c) & 0xff;
>> +			npow2 = m88ds3103_readreg(state, 0x8d) & 0xff;
>> +			npow += (((npow1 & 0x3f) + (u16)(npow2 << 6)) >> 2);
>> +
>> +			spow1 = m88ds3103_readreg(state, 0x8e) & 0xff;
>> +			spow += ((spow1 * spow1) >> 1);
>> +			cnt--;
>> +		}
>> +		npow /= 10; spow /= 10;
>> +		if(spow == 0){
>> +			snr = 0;
>> +		}else if(npow == 0){
>> +			snr = 19;
>> +		}else{
>> +			if(spow > npow){
>> +				tmp = (u16)(spow / npow);
>> +				if (tmp > 80) tmp = 80;
>> +				snr = mes_log10[tmp - 1]*3;
>> +			}else{
>> +				tmp = (u16)(npow / spow);
>> +				if (tmp > 80) tmp = 80;
>> +				snr = -(mes_log10[tmp - 1] / 1000);
>> +			}
>> +		}			
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +	*p_snr = snr;
>> +
>> +	return 0;
>> +}
>> +
>> +
>> +static int m88ds3103_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	u8 tmp1, tmp2, tmp3, data;
>> +
>> +	dprintk("%s()\n", __func__);
>> +
>> +	switch (state->delivery_system) {
>> +	case SYS_DVBS:
>> +		data = m88ds3103_readreg(state, 0xf8);
>> +		data |= 0x40;
>> +		m88ds3103_writereg(state, 0xf8, data);		
>> +		tmp1 = m88ds3103_readreg(state, 0xf5);
>> +		tmp2 = m88ds3103_readreg(state, 0xf4);
>> +		*ucblocks = (tmp1 <<8) | tmp2;		
>> +		data &= ~0x20;
>> +		m88ds3103_writereg(state, 0xf8, data);
>> +		data |= 0x20;
>> +		m88ds3103_writereg(state, 0xf8, data);
>> +		data &= ~0x40;
>> +		m88ds3103_writereg(state, 0xf8, data);
>> +		break;
>> +	case SYS_DVBS2:
>> +		tmp1 = m88ds3103_readreg(state, 0xda);
>> +		tmp2 = m88ds3103_readreg(state, 0xd9);
>> +		tmp3 = m88ds3103_readreg(state, 0xd8);
>> +		*ucblocks = (tmp1 <<16)|(tmp2 <<8)|tmp3;
>> +		data = m88ds3103_readreg(state, 0xd1);
>> +		data |= 0x01;
>> +		m88ds3103_writereg(state, 0xd1, data);
>> +		data &= ~0x01;
>> +		m88ds3103_writereg(state, 0xd1, data);
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	u8 data_a1, data_a2;
>> +
>> +	dprintk("%s(%d)\n", __func__, tone);
>> +	if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
>> +		printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
>> +		return -EINVAL;
>> +	}
>> +
>> +	data_a1 = m88ds3103_readreg(state, 0xa1);
>> +	data_a2 = m88ds3103_readreg(state, 0xa2);
>> +	if(state->demod_id == DS3103_ID)
>> +		data_a2 &= 0xdf; /* Normal mode */
>> +	switch (tone) {
>> +	case SEC_TONE_ON:
>> +		dprintk("%s: SEC_TONE_ON\n", __func__);
>> +		data_a1 |= 0x04;
>> +		data_a1 &= ~0x03;
>> +		data_a1 &= ~0x40;
>> +		data_a2 &= ~0xc0;
>> +		break;
>> +	case SEC_TONE_OFF:
>> +		dprintk("%s: SEC_TONE_OFF\n", __func__);
>> +		data_a2 &= ~0xc0;
>> +		data_a2 |= 0x80;
>> +		break;
>> +	}
>> +	m88ds3103_writereg(state, 0xa2, data_a2);
>> +	m88ds3103_writereg(state, 0xa1, data_a1);
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_send_diseqc_msg(struct dvb_frontend *fe,
>> +				struct dvb_diseqc_master_cmd *d)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	int i, ret = 0;
>> +	u8 tmp, time_out;
>> +
>> +	/* Dump DiSEqC message */
>> +	if (debug) {
>> +		printk(KERN_INFO "m88ds3103: %s(", __func__);
>> +		for (i = 0 ; i < d->msg_len ;) {
>> +			printk(KERN_INFO "0x%02x", d->msg[i]);
>> +			if (++i < d->msg_len)
>> +				printk(KERN_INFO ", ");
>> +		}
>> +	}
>> +
>> +	tmp = m88ds3103_readreg(state, 0xa2);
>> +	tmp &= ~0xc0;
>> +	if(state->demod_id == DS3103_ID)
>> +		tmp &= ~0x20;
>> +	m88ds3103_writereg(state, 0xa2, tmp);
>> +	
>> +	for (i = 0; i < d->msg_len; i ++)
>> +		m88ds3103_writereg(state, (0xa3+i), d->msg[i]);
>> +
>> +	tmp = m88ds3103_readreg(state, 0xa1);	
>> +	tmp &= ~0x38;
>> +	tmp &= ~0x40;
>> +	tmp |= ((d->msg_len-1) << 3) | 0x07;
>> +	tmp &= ~0x80;
>> +	m88ds3103_writereg(state, 0xa1, tmp);
>> +	/*	1.5 * 9 * 8	= 108ms	*/
>> +	time_out = 150;
>> +	while (time_out > 0){
>> +		msleep(10);
>> +		time_out -= 10;
>> +		tmp = m88ds3103_readreg(state, 0xa1);		
>> +		if ((tmp & 0x40) == 0)
>> +			break;
>> +	}
>> +	if (time_out == 0){
>> +		tmp = m88ds3103_readreg(state, 0xa1);
>> +		tmp &= ~0x80;
>> +		tmp |= 0x40;
>> +		m88ds3103_writereg(state, 0xa1, tmp);
>> +		ret = 1;
>> +	}
>> +	tmp = m88ds3103_readreg(state, 0xa2);
>> +	tmp &= ~0xc0;
>> +	tmp |= 0x80;
>> +	m88ds3103_writereg(state, 0xa2, tmp);	
>> +	return ret;
>> +}
>> +
>> +
>> +static int m88ds3103_diseqc_send_burst(struct dvb_frontend *fe,
>> +					fe_sec_mini_cmd_t burst)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	u8	val, time_out;
>> +	
>> +	dprintk("%s()\n", __func__);
>> +
>> +	val = m88ds3103_readreg(state, 0xa2);
>> +	val &= ~0xc0;
>> +	if(state->demod_id == DS3103_ID)
>> +		val &= 0xdf; /* Normal mode */
>> +	m88ds3103_writereg(state, 0xa2, val);
>> +	/* DiSEqC burst */
>> +	if (burst == SEC_MINI_B)
>> +		m88ds3103_writereg(state, 0xa1, 0x01);
>> +	else
>> +		m88ds3103_writereg(state, 0xa1, 0x02);
>> +
>> +	msleep(13);
>> +
>> +	time_out = 5;
>> +	do{
>> +		val = m88ds3103_readreg(state, 0xa1);
>> +		if ((val & 0x40) == 0)
>> +			break;
>> +		msleep(1);
>> +		time_out --;
>> +	} while (time_out > 0);
>> +
>> +	val = m88ds3103_readreg(state, 0xa2);
>> +	val &= ~0xc0;
>> +	val |= 0x80;
>> +	m88ds3103_writereg(state, 0xa2, val);
>> +	
>> +	return 0;
>> +}
>> +
>> +static void m88ds3103_release(struct dvb_frontend *fe)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +
>> +	dprintk("%s\n", __func__);
>> +	kfree(state);
>> +}
>> +
>> +static int m88ds3103_check_id(struct m88ds3103_state *state)
>> +{
>> +	int val_00, val_01;
>> +	
>> +	/*check demod id*/
>> +	val_01 = m88ds3103_readreg(state, 0x01);
>> +	printk(KERN_INFO "DS3000 chip version: %x attached.\n", val_01);
>> +			
>> +	if(val_01 == 0xD0)
>> +		state->demod_id = DS3103_ID;
>> +	else if(val_01 == 0xC0)
>> +		state->demod_id = DS3000_ID;
>> +	else
>> +		state->demod_id = UNKNOW_ID;
>> +		
>> +	/*check tuner id*/
>> +	val_00 = m88ds3103_tuner_readreg(state, 0x00);
>> +	printk(KERN_INFO "TS202x chip version[1]: %x attached.\n", val_00);
>> +	val_00 &= 0x03;
>> +	if(val_00 == 0)
>> +	{
>> +		m88ds3103_tuner_writereg(state, 0x00, 0x01);
>> +		msleep(3);		
>> +	}
>> +	m88ds3103_tuner_writereg(state, 0x00, 0x03);
>> +	msleep(5);
>> +	
>> +	val_00 = m88ds3103_tuner_readreg(state, 0x00);
>> +	printk(KERN_INFO "TS202x chip version[2]: %x attached.\n", val_00);
>> +	val_00 &= 0xff;
>> +	if((val_00 == 0x01) || (val_00 == 0x41) || (val_00 == 0x81))
>> +		state->tuner_id = TS2020_ID;
>> +	else if(((val_00 & 0xc0)== 0xc0) || (val_00 == 0x83))
>> +		state->tuner_id = TS2022_ID;
>> +	else
>> +		state->tuner_id = UNKNOW_ID;
>> +			
>> +	return state->demod_id;	
>> +}
>> +
>> +static struct dvb_frontend_ops m88ds3103_ops;
>> +static int m88ds3103_initilaze(struct dvb_frontend *fe);
>> +
>> +struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *config,
>> +				    struct i2c_adapter *i2c)
>> +{
>> +	struct m88ds3103_state *state = NULL;
>> +
>> +	dprintk("%s\n", __func__);
>> +
>> +	/* allocate memory for the internal state */
>> +	state = kzalloc(sizeof(struct m88ds3103_state), GFP_KERNEL);
>> +	if (state == NULL) {
>> +		printk(KERN_ERR "Unable to kmalloc\n");
>> +		goto error2;
>> +	}
>> +
>> +	state->config = config;
>> +	state->i2c = i2c;
>> +	state->preBer = 0xffff;
>> +	state->delivery_system = SYS_DVBS; /*Default to DVB-S.*/
>> +	
>> +	/* check demod id */
>> +	if(m88ds3103_check_id(state) == UNKNOW_ID){
>> +		printk(KERN_ERR "Unable to find Montage chip\n");
>> +		goto error3;
>> +	}
>> +
>> +	memcpy(&state->frontend.ops, &m88ds3103_ops,
>> +			sizeof(struct dvb_frontend_ops));
>> +	state->frontend.demodulator_priv = state;
>> +	
>> +	m88ds3103_initilaze(&state->frontend);
>> +	
>> +	return &state->frontend;
>> +
>> +error3:
>> +	kfree(state);
>> +error2:
>> +	return NULL;
>> +}
>> +EXPORT_SYMBOL(m88ds3103_attach);
>> +
>> +static int m88ds3103_set_carrier_offset(struct dvb_frontend *fe,
>> +					s32 carrier_offset_khz)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	s32 tmp;
>> +
>> +	tmp = carrier_offset_khz;
>> +	tmp *= 65536;
>> +	
>> +	tmp = (2*tmp + MT_FE_MCLK_KHZ) / (2*MT_FE_MCLK_KHZ);
>> +
>> +	if (tmp < 0)
>> +		tmp += 65536;
>> +
>> +	m88ds3103_writereg(state, 0x5f, tmp >> 8);
>> +	m88ds3103_writereg(state, 0x5e, tmp & 0xff);
>> +
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_set_symrate(struct dvb_frontend *fe)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
>> +	u16 value;
>> +	
>> +	value = (((c->symbol_rate / 1000) << 15) + (MT_FE_MCLK_KHZ / 4)) / (MT_FE_MCLK_KHZ / 2);
>> +	m88ds3103_writereg(state, 0x61, value & 0x00ff);
>> +	m88ds3103_writereg(state, 0x62, (value & 0xff00) >> 8);
>> +
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_set_CCI(struct dvb_frontend *fe)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	u8 tmp;
>> +
>> +	tmp = m88ds3103_readreg(state, 0x56);
>> +	tmp &= ~0x01;
>> +	m88ds3103_writereg(state, 0x56, tmp);
>> +
>> +	tmp = m88ds3103_readreg(state, 0x76);
>> +	tmp &= ~0x80;
>> +	m88ds3103_writereg(state, 0x76, tmp);
>> +
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_init_reg(struct m88ds3103_state *state, const u8 *p_reg_tab, u32 size)
>> +{
>> +	u32 i;
>> +	
>> +	for(i = 0; i < size; i+=2)
>> +		m88ds3103_writereg(state, p_reg_tab[i], p_reg_tab[i+1]);
>> +		
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_demod_connect(struct dvb_frontend *fe, s32 carrier_offset_khz) 
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
>> +	u16 value;
>> +	u8 val1,val2,data;
>> +	
>> +	dprintk("connect delivery system = %d\n", state->delivery_system);
>> +	
>> +	/* ds3000 global reset */
>> +	m88ds3103_writereg(state, 0x07, 0x80);
>> +	m88ds3103_writereg(state, 0x07, 0x00);
>> +	/* ds3000 build-in uC reset */
>> +	m88ds3103_writereg(state, 0xb2, 0x01);
>> +	/* ds3000 software reset */
>> +	m88ds3103_writereg(state, 0x00, 0x01);
>> +
>> +	switch (state->delivery_system) {
>> +	case SYS_DVBS:
>> +		/* initialise the demod in DVB-S mode */
>> +		if(state->demod_id == DS3000_ID){
>> +			m88ds3103_init_reg(state, ds3000_dvbs_init_tab, sizeof(ds3000_dvbs_init_tab));
>> +			
>> +			value = m88ds3103_readreg(state, 0xfe);
>> +			value &= 0xc0;
>> +			value |= 0x1b;
>> +			m88ds3103_writereg(state, 0xfe, value);
>> +			
>> +			if(state->config->ci_mode)
>> +				val1 = 0x80;
>> +			else if(state->config->ts_mode)
>> +				val1 = 0x60;
>> +			else
>> +				val1 = 0x20;
>> +			m88ds3103_writereg(state, 0xfd, val1);
>> +			
>> +		}else if(state->demod_id == DS3103_ID){
>> +			m88ds3103_init_reg(state, ds3103_dvbs_init_tab, sizeof(ds3103_dvbs_init_tab));
>> +			
>> +			/* set ts clock */
>> +			if(state->config->ts_mode == 0)	{
>> +				val1 = 3; val2 = 3;
>> +			}else{
>> +				val1 = 0; val2 = 0;
>> +			}
>> +			val1 -= 1; val2 -= 1;
>> +			val1 &= 0x3f; val2 &= 0x3f;
>> +			data = m88ds3103_readreg(state, 0xfe);
>> +			data &= 0xf0;
>> +			data |= (val2 >> 2) & 0x0f;
>> +			m88ds3103_writereg(state, 0xfe, data);
>> +			data = (val2 & 0x03) << 6;
>> +			data |= val1;
>> +			m88ds3103_writereg(state, 0xea, data);
>> +			
>> +			m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d));
>> +			m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30));
>> +			
>> +			/* set master clock */
>> +			val1 = m88ds3103_readreg(state, 0x22);
>> +			val2 = m88ds3103_readreg(state, 0x24);
>> +			
>> +			val1 &= 0x3f;
>> +			val2 &= 0x3f;
>> +			val1 |= 0x80;
>> +			val2 |= 0x40;
>> +
>> +			m88ds3103_writereg(state, 0x22, val1);
>> +			m88ds3103_writereg(state, 0x24, val2);	
>> +			
>> +			if(state->config->ci_mode)
>> +				val1 = 0x03;
>> +			else if(state->config->ts_mode)
>> +				val1 = 0x06;
>> +			else
>> +				val1 = 0x42;
>> +			m88ds3103_writereg(state, 0xfd, val1);		
>> +		}
>> +		break;
>> +	case SYS_DVBS2:
>> +		/* initialise the demod in DVB-S2 mode */
>> +		if(state->demod_id == DS3000_ID){
>> +			m88ds3103_init_reg(state, ds3000_dvbs2_init_tab, sizeof(ds3000_dvbs2_init_tab));
>> +		
>> +			if (c->symbol_rate >= 30000000)
>> +				m88ds3103_writereg(state, 0xfe, 0x54);
>> +			else
>> +				m88ds3103_writereg(state, 0xfe, 0x98);
>> +								
>> +		}else if(state->demod_id == DS3103_ID){
>> +			m88ds3103_init_reg(state, ds3103_dvbs2_init_tab, sizeof(ds3103_dvbs2_init_tab));
>> +
>> +			/* set ts clock */
>> +			if(state->config->ts_mode == 0){
>> +				val1 = 5; val2 = 4;
>> +			}else{
>> +				val1 = 0; val2 = 0;
>> +			}
>> +			val1 -= 1; val2 -= 1;
>> +			val1 &= 0x3f; val2 &= 0x3f;
>> +			data = m88ds3103_readreg(state, 0xfe);
>> +			data &= 0xf0;
>> +			data |= (val2 >> 2) & 0x0f;
>> +			m88ds3103_writereg(state, 0xfe, data);
>> +			data = (val2 & 0x03) << 6;
>> +			data |= val1;
>> +			m88ds3103_writereg(state, 0xea, data);
>> +			
>> +			m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d));
>> +			m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30));
>> +			
>> +			/* set master clock */
>> +			val1 = m88ds3103_readreg(state, 0x22);
>> +			val2 = m88ds3103_readreg(state, 0x24);
>> +			
>> +			val1 &= 0x3f;
>> +			val2 &= 0x3f;
>> +			if(state->config->ts_mode == 1){
>> +				val1 |= 0x80;
>> +				val2 |= 0x40;
>> +			}else{
>> +				if (c->symbol_rate >= 28000000){
>> +					val1 |= 0xc0;
>> +				}else if (c->symbol_rate >= 18000000){
>> +					val2 |= 0x40;
>> +				}else{
>> +					val1 |= 0x80;
>> +					val2 |= 0x40;
>> +				}				
>> +			}
>> +			m88ds3103_writereg(state, 0x22, val1);
>> +			m88ds3103_writereg(state, 0x24, val2);					
>> +		}
>> +		
>> +		if(state->config->ci_mode)
>> +			val1 = 0x03;
>> +		else if(state->config->ts_mode)
>> +			val1 = 0x06;
>> +		else
>> +			val1 = 0x42;
>> +		m88ds3103_writereg(state, 0xfd, val1);
>> +		
>> +		break;
>> +	default:
>> +		return 1;
>> +	}
>> +	/* disable 27MHz clock output */
>> +	m88ds3103_writereg(state, 0x29, 0x80);
>> +	/* enable ac coupling */
>> +	m88ds3103_writereg(state, 0x25, 0x8a);
>> +
>> +	if ((c->symbol_rate / 1000) <= 3000){
>> +		m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 32 * 100 / 64 = 400*/
>> +		m88ds3103_writereg(state, 0xc8, 0x20);
>> +		m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/
>> +		m88ds3103_writereg(state, 0xc7, 0x00);
>> +	}else if((c->symbol_rate / 1000) <= 10000){
>> +		m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 16 * 100 / 64 = 200*/
>> +		m88ds3103_writereg(state, 0xc8, 0x10);
>> +		m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/
>> +		m88ds3103_writereg(state, 0xc7, 0x00);
>> +	}else{
>> +		m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 6 * 100 / 64 = 75*/
>> +		m88ds3103_writereg(state, 0xc8, 0x06);
>> +		m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/
>> +		m88ds3103_writereg(state, 0xc7, 0x00);
>> +	}
>> +
>> +	m88ds3103_set_symrate(fe);
>> +	
>> +	m88ds3103_set_CCI(fe);
>> +
>> +	m88ds3103_set_carrier_offset(fe, carrier_offset_khz);
>> +		
>> +	/* ds3000 out of software reset */
>> +	m88ds3103_writereg(state, 0x00, 0x00);
>> +	/* start ds3000 build-in uC */
>> +	m88ds3103_writereg(state, 0xb2, 0x00);	
>> +	
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_set_frontend(struct dvb_frontend *fe)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
>> +
>> +	int i;
>> +	fe_status_t status;
>> +	u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf, div4, capCode, changePLL;
>> +	s32 offset_khz, lpf_offset_KHz;
>> +	u16 value, ndiv, lpf_coeff;
>> +	u32 f3db, gdiv28, realFreq;
>> +	u8 RFgain;
>> +
>> +	dprintk("%s() ", __func__);
>> +	dprintk("c frequency = %d\n", c->frequency);
>> +	dprintk("symbol rate = %d\n", c->symbol_rate);
>> +	dprintk("delivery system = %d\n", c->delivery_system);
>> +	
>> +	realFreq = c->frequency;
>> +	lpf_offset_KHz = 0;
>> +	if(c->symbol_rate < 5000000){
>> +		lpf_offset_KHz = FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz;
>> +		realFreq += FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz;
>> +	}
>> +	
>> +	if (state->config->set_ts_params)
>> +		state->config->set_ts_params(fe, 0);
>> +
>> +	div4 = 0;
>> +	RFgain = 0;
>> +	if(state->tuner_id == TS2022_ID){
>> +		m88ds3103_tuner_writereg(state, 0x10, 0x0a);
>> +		m88ds3103_tuner_writereg(state, 0x11, 0x40);
>> +		if (realFreq < 1103000) {
>> +			m88ds3103_tuner_writereg(state, 0x10, 0x1b);
>> +			div4 = 1;
>> +			ndiv = (realFreq * (6 + 8) * 4)/MT_FE_CRYSTAL_KHZ;				
>> +		}else {
>> +			ndiv = (realFreq * (6 + 8) * 2)/MT_FE_CRYSTAL_KHZ;
>> +		}
>> +		ndiv = ndiv + ndiv%2;
>> +		if(ndiv < 4095)
>> +			ndiv = ndiv - 1024;
>> +		else if (ndiv < 6143)
>> +			ndiv = ndiv + 1024;
>> +		else
>> +			ndiv = ndiv + 3072;	
>> +		
>> +		m88ds3103_tuner_writereg(state, 0x01, (ndiv & 0x3f00) >> 8);											
>> +	}else{
>> +		m88ds3103_tuner_writereg(state, 0x10, 0x00);			
>> +		if (realFreq < 1146000){
>> +			m88ds3103_tuner_writereg(state, 0x10, 0x11);
>> +			div4 = 1;
>> +			ndiv = (realFreq * (6 + 8) * 4) / MT_FE_CRYSTAL_KHZ;
>> +		}else{
>> +			m88ds3103_tuner_writereg(state, 0x10, 0x01);
>> +			ndiv = (realFreq * (6 + 8) * 2) / MT_FE_CRYSTAL_KHZ;
>> +		}
>> +		ndiv = ndiv + ndiv%2;
>> +		ndiv = ndiv - 1024;
>> +		m88ds3103_tuner_writereg(state, 0x01, (ndiv>>8)&0x0f);
>> +	}
>> +	/* set pll */
>> +	m88ds3103_tuner_writereg(state, 0x02, ndiv & 0x00ff);
>> +	m88ds3103_tuner_writereg(state, 0x03, 0x06);
>> +	m88ds3103_tuner_writereg(state, 0x51, 0x0f);
>> +	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
>> +	m88ds3103_tuner_writereg(state, 0x50, 0x10);
>> +	m88ds3103_tuner_writereg(state, 0x50, 0x00);	
>> +
>> +	if(state->tuner_id == TS2022_ID){
>> +		if(( realFreq >= 1650000 ) && (realFreq <= 1850000)){
>> +			msleep(5);
>> +			value = m88ds3103_tuner_readreg(state, 0x14);
>> +			value &= 0x7f;
>> +			if(value < 64){
>> +				m88ds3103_tuner_writereg(state, 0x10, 0x82);
>> +				m88ds3103_tuner_writereg(state, 0x11, 0x6f);
>> +
>> +				m88ds3103_tuner_writereg(state, 0x51, 0x0f);
>> +				m88ds3103_tuner_writereg(state, 0x51, 0x1f);
>> +				m88ds3103_tuner_writereg(state, 0x50, 0x10);
>> +				m88ds3103_tuner_writereg(state, 0x50, 0x00);
>> +			}
>> +		}
>> +		msleep(5);
>> +		value = m88ds3103_tuner_readreg(state, 0x14);
>> +		value &= 0x1f;
>> +
>> +		if(value > 19){
>> +			value = m88ds3103_tuner_readreg(state, 0x10);
>> +			value &= 0x1d;
>> +			m88ds3103_tuner_writereg(state, 0x10, value);
>> +		}				
>> +	}else{
>> +		msleep(5);
>> +		value = m88ds3103_tuner_readreg(state, 0x66);
>> +		changePLL = (((value & 0x80) >> 7) != div4);
>> +
>> +		if(changePLL){
>> +			m88ds3103_tuner_writereg(state, 0x10, 0x11);
>> +			div4 = 1;
>> +			ndiv = (realFreq * (6 + 8) * 4)/MT_FE_CRYSTAL_KHZ;
>> +			ndiv = ndiv + ndiv%2;
>> +			ndiv = ndiv - 1024;
>> +					
>> +			m88ds3103_tuner_writereg(state, 0x01, (ndiv>>8) & 0x0f);
>> +			m88ds3103_tuner_writereg(state, 0x02, ndiv & 0xff);
>> +			
>> +			m88ds3103_tuner_writereg(state, 0x51, 0x0f);
>> +			m88ds3103_tuner_writereg(state, 0x51, 0x1f);
>> +			m88ds3103_tuner_writereg(state, 0x50, 0x10);
>> +			m88ds3103_tuner_writereg(state, 0x50, 0x00);
>> +		}		
>> +	}
>> +	/*set the RF gain*/
>> +	if(state->tuner_id == TS2020_ID)
>> +		m88ds3103_tuner_writereg(state, 0x60, 0x79);
>> +			
>> +	m88ds3103_tuner_writereg(state, 0x51, 0x17);
>> +	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
>> +	m88ds3103_tuner_writereg(state, 0x50, 0x08);
>> +	m88ds3103_tuner_writereg(state, 0x50, 0x00);
>> +	msleep(5);
>> +
>> +	if(state->tuner_id == TS2020_ID){
>> +		RFgain = m88ds3103_tuner_readreg(state, 0x3d);
>> +		RFgain &= 0x0f;
>> +		if(RFgain < 15){
>> +			if(RFgain < 4) 
>> +				RFgain = 0;
>> +			else
>> +				RFgain = RFgain -3;
>> +			value = ((RFgain << 3) | 0x01) & 0x79;
>> +			m88ds3103_tuner_writereg(state, 0x60, value);
>> +			m88ds3103_tuner_writereg(state, 0x51, 0x17);
>> +			m88ds3103_tuner_writereg(state, 0x51, 0x1f);
>> +			m88ds3103_tuner_writereg(state, 0x50, 0x08);
>> +			m88ds3103_tuner_writereg(state, 0x50, 0x00);
>> +		}
>> +	}
>> +	
>> +	/* set the LPF */
>> +	if(state->tuner_id == TS2022_ID){
>> +		m88ds3103_tuner_writereg(state, 0x25, 0x00);
>> +		m88ds3103_tuner_writereg(state, 0x27, 0x70);
>> +		m88ds3103_tuner_writereg(state, 0x41, 0x09);
>> +		m88ds3103_tuner_writereg(state, 0x08, 0x0b);
>> +	}
>> +
>> +	f3db = ((c->symbol_rate / 1000) *135) / 200 + 2000;
>> +	f3db += lpf_offset_KHz;
>> +	if (f3db < 7000)
>> +		f3db = 7000;
>> +	if (f3db > 40000)
>> +		f3db = 40000;
>> +			
>> +	gdiv28 = (MT_FE_CRYSTAL_KHZ / 1000 * 1694 + 500) / 1000;
>> +	m88ds3103_tuner_writereg(state, 0x04, gdiv28 & 0xff);
>> +	m88ds3103_tuner_writereg(state, 0x51, 0x1b);
>> +	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
>> +	m88ds3103_tuner_writereg(state, 0x50, 0x04);
>> +	m88ds3103_tuner_writereg(state, 0x50, 0x00);
>> +	msleep(5);
>> +
>> +	value = m88ds3103_tuner_readreg(state, 0x26);
>> +	capCode = value & 0x3f;
>> +	if(state->tuner_id == TS2022_ID){
>> +		m88ds3103_tuner_writereg(state, 0x41, 0x0d);
>> +
>> +		m88ds3103_tuner_writereg(state, 0x51, 0x1b);
>> +		m88ds3103_tuner_writereg(state, 0x51, 0x1f);
>> +		m88ds3103_tuner_writereg(state, 0x50, 0x04);
>> +		m88ds3103_tuner_writereg(state, 0x50, 0x00);
>> +
>> +		msleep(2);
>> +
>> +		value = m88ds3103_tuner_readreg(state, 0x26);
>> +		value &= 0x3f;
>> +		value = (capCode + value) / 2;		
>> +	}
>> +	else
>> +		value = capCode;
>> +		
>> +	gdiv28 = gdiv28 * 207 / (value * 2 + 151);	
>> +	mlpf_max = gdiv28 * 135 / 100;
>> +	mlpf_min = gdiv28 * 78 / 100;
>> +	if (mlpf_max > 63)
>> +		mlpf_max = 63;
>> +
>> +	if(state->tuner_id == TS2022_ID)
>> +		lpf_coeff = 3200;
>> +	else
>> +		lpf_coeff = 2766;
>> +		
>> +	nlpf = (f3db * gdiv28 * 2 / lpf_coeff / (MT_FE_CRYSTAL_KHZ / 1000)  + 1) / 2 ;	
>> +	if (nlpf > 23) nlpf = 23;
>> +	if (nlpf < 1) nlpf = 1;
>> +
>> +	lpf_mxdiv = (nlpf * (MT_FE_CRYSTAL_KHZ / 1000) * lpf_coeff * 2 / f3db + 1) / 2;
>> +
>> +	if (lpf_mxdiv < mlpf_min){
>> +		nlpf++;
>> +		lpf_mxdiv = (nlpf * (MT_FE_CRYSTAL_KHZ / 1000) * lpf_coeff * 2  / f3db + 1) / 2;
>> +	}
>> +
>> +	if (lpf_mxdiv > mlpf_max)
>> +		lpf_mxdiv = mlpf_max;
>> +
>> +	m88ds3103_tuner_writereg(state, 0x04, lpf_mxdiv);
>> +	m88ds3103_tuner_writereg(state, 0x06, nlpf);
>> +	m88ds3103_tuner_writereg(state, 0x51, 0x1b);
>> +	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
>> +	m88ds3103_tuner_writereg(state, 0x50, 0x04);
>> +	m88ds3103_tuner_writereg(state, 0x50, 0x00);
>> +	msleep(5);
>> +	
>> +	if(state->tuner_id == TS2022_ID){
>> +		msleep(2);
>> +		value = m88ds3103_tuner_readreg(state, 0x26);
>> +		capCode = value & 0x3f;
>> +
>> +		m88ds3103_tuner_writereg(state, 0x41, 0x09);
>> +
>> +		m88ds3103_tuner_writereg(state, 0x51, 0x1b);
>> +		m88ds3103_tuner_writereg(state, 0x51, 0x1f);
>> +		m88ds3103_tuner_writereg(state, 0x50, 0x04);
>> +		m88ds3103_tuner_writereg(state, 0x50, 0x00);
>> +
>> +		msleep(2);
>> +		value = m88ds3103_tuner_readreg(state, 0x26);
>> +		value &= 0x3f;
>> +		value = (capCode + value) / 2;
>> +
>> +		value = value | 0x80;
>> +		m88ds3103_tuner_writereg(state, 0x25, value);
>> +		m88ds3103_tuner_writereg(state, 0x27, 0x30);
>> +
>> +		m88ds3103_tuner_writereg(state, 0x08, 0x09);		
>> +	}
>> +
>> +	/* Set the BB gain */
>> +	m88ds3103_tuner_writereg(state, 0x51, 0x1e);
>> +	m88ds3103_tuner_writereg(state, 0x51, 0x1f);
>> +	m88ds3103_tuner_writereg(state, 0x50, 0x01);
>> +	m88ds3103_tuner_writereg(state, 0x50, 0x00);
>> +	if(state->tuner_id == TS2020_ID){
>> +		if(RFgain == 15){
>> +			msleep(40);
>> +			value = m88ds3103_tuner_readreg(state, 0x21);
>> +			value &= 0x0f;
>> +			if(value < 3){
>> +				m88ds3103_tuner_writereg(state, 0x60, 0x61);
>> +				m88ds3103_tuner_writereg(state, 0x51, 0x17);
>> +				m88ds3103_tuner_writereg(state, 0x51, 0x1f);
>> +				m88ds3103_tuner_writereg(state, 0x50, 0x08);
>> +				m88ds3103_tuner_writereg(state, 0x50, 0x00);
>> +			}			
>> +		}
>> +	}
>> +	msleep(60);
>> +	
>> +	offset_khz = (ndiv - ndiv % 2 + 1024) * MT_FE_CRYSTAL_KHZ
>> +		/ (6 + 8) / (div4 + 1) / 2 - realFreq;
>> +
>> +	m88ds3103_demod_connect(fe, offset_khz+lpf_offset_KHz);
>> +
>> +	for (i = 0; i < 30 ; i++) {
>> +		m88ds3103_read_status(fe, &status);
>> +		if (status & FE_HAS_LOCK){
>> +			break;
>> +                }
>> +		msleep(20);
>> +	}
>> +	
>> +	if((status & FE_HAS_LOCK) == 0){
>> +		state->delivery_system = (state->delivery_system == SYS_DVBS) ? SYS_DVBS2 : SYS_DVBS;
>> +		m88ds3103_demod_connect(fe, offset_khz);
>> +	
>> +		for (i = 0; i < 30 ; i++) {
>> +			m88ds3103_read_status(fe, &status);
>> +			if (status & FE_HAS_LOCK){
>> +				break;
>> +                	}
>> +			msleep(20);
>> +		}
>> +	}
>> +	
>> +	if (status & FE_HAS_LOCK){
>> +		if(state->config->start_ctrl){
>> +			if(state->first_lock == 0){
>> +				state->config->start_ctrl(fe);
>> +				state->first_lock = 1;	
>> +			}
>> +		}		
>> +	}
>> +		
>> +	return 0;
>> +}
>> +
>> +static int m88ds3103_tune(struct dvb_frontend *fe,
>> +			bool re_tune,
>> +			unsigned int mode_flags,
>> +			unsigned int *delay,
>> +			fe_status_t *status)
>> +{	
>> +	*delay = HZ / 5;
>> +	
>> +	dprintk("%s() ", __func__);
>> +	dprintk("re_tune = %d\n", re_tune);
>> +	
>> +	if (re_tune) {
>> +		int ret = m88ds3103_set_frontend(fe);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +	
>> +	return m88ds3103_read_status(fe, status);
>> +}
>> +
>> +static enum dvbfe_algo m88ds3103_get_algo(struct dvb_frontend *fe)
>> +{
>> +	return DVBFE_ALGO_HW;
>> +}
>> + 
>> + /*
>> + * Power config will reset and load initial firmware if required
>> + */
>> +static int m88ds3103_initilaze(struct dvb_frontend *fe)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	int ret;
>> +
>> +	dprintk("%s()\n", __func__);
>> +	/* hard reset */
>> +	m88ds3103_writereg(state, 0x07, 0x80);
>> +	m88ds3103_writereg(state, 0x07, 0x00);
>> +	msleep(1);
>> +	
>> +	m88ds3103_writereg(state, 0x08, 0x01 | m88ds3103_readreg(state, 0x08));
>> +	msleep(1);
>> +
>> +	if(state->tuner_id == TS2020_ID){
>> +		/* TS2020 init */
>> +		m88ds3103_tuner_writereg(state, 0x42, 0x73);
>> +		msleep(2);
>> +		m88ds3103_tuner_writereg(state, 0x05, 0x01);
>> +		m88ds3103_tuner_writereg(state, 0x62, 0xb5);
>> +		m88ds3103_tuner_writereg(state, 0x07, 0x02);
>> +		m88ds3103_tuner_writereg(state, 0x08, 0x01);
>> +	}
>> +	else if(state->tuner_id == TS2022_ID){
>> +		/* TS2022 init */
>> +		m88ds3103_tuner_writereg(state, 0x62, 0x6c);
>> +		msleep(2);
>> +		m88ds3103_tuner_writereg(state, 0x42, 0x6c);
>> +		msleep(2);
>> +		m88ds3103_tuner_writereg(state, 0x7d, 0x9d);
>> +		m88ds3103_tuner_writereg(state, 0x7c, 0x9a);
>> +		m88ds3103_tuner_writereg(state, 0x7a, 0x76);
>> +
>> +		m88ds3103_tuner_writereg(state, 0x3b, 0x01);
>> +		m88ds3103_tuner_writereg(state, 0x63, 0x88);
>> +
>> +		m88ds3103_tuner_writereg(state, 0x61, 0x85);
>> +		m88ds3103_tuner_writereg(state, 0x22, 0x30);
>> +		m88ds3103_tuner_writereg(state, 0x30, 0x40);
>> +		m88ds3103_tuner_writereg(state, 0x20, 0x23);
>> +		m88ds3103_tuner_writereg(state, 0x24, 0x02);
>> +		m88ds3103_tuner_writereg(state, 0x12, 0xa0);	
>> +	}
>> +		
>> +	if(state->demod_id == DS3103_ID){
>> +		m88ds3103_writereg(state, 0x07, 0xe0);
>> +		m88ds3103_writereg(state, 0x07, 0x00);
>> +		msleep(1);		
>> +	}
>> +	m88ds3103_writereg(state, 0xb2, 0x01);
>> +	
>> +	/* Load the firmware if required */
>> +	ret = m88ds3103_load_firmware(fe);
>> +	if (ret != 0){
>> +		printk(KERN_ERR "%s: Unable initialize firmware\n", __func__);
>> +		return ret;
>> +	}
>> +	if(state->demod_id == DS3103_ID){
>> +		m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d));
>> +		m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30));		
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +/*
>> + * Initialise or wake up device
>> + */
>> +static int m88ds3103_initfe(struct dvb_frontend *fe)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +	u8 val;
>> +
>> +	dprintk("%s()\n", __func__);
>> +
>> +	/* 1st step to wake up demod */
>> +	m88ds3103_writereg(state, 0x08, 0x01 | m88ds3103_readreg(state, 0x08));
>> +	m88ds3103_writereg(state, 0x04, 0xfe & m88ds3103_readreg(state, 0x04));
>> +	m88ds3103_writereg(state, 0x23, 0xef & m88ds3103_readreg(state, 0x23));
>> +	
>> +	/* 2nd step to wake up tuner */
>> +	val = m88ds3103_tuner_readreg(state, 0x00) & 0xff;
>> +	if((val & 0x01) == 0){
>> +		m88ds3103_tuner_writereg(state, 0x00, 0x01);
>> +		msleep(50);
>> +	}
>> +	m88ds3103_tuner_writereg(state, 0x00, 0x03);
>> +	msleep(50);
>> +	
>> +	return 0;	
>> +}
>> +
>> +/* Put device to sleep */
>> +static int m88ds3103_sleep(struct dvb_frontend *fe)
>> +{
>> +	struct m88ds3103_state *state = fe->demodulator_priv;
>> +
>> +	dprintk("%s()\n", __func__);
>> +	
>> +	/* 1st step to sleep tuner */
>> +	m88ds3103_tuner_writereg(state, 0x00, 0x00);
>> +	
>> +	/* 2nd step to sleep demod */
>> +	m88ds3103_writereg(state, 0x08, 0xfe & m88ds3103_readreg(state, 0x08));
>> +	m88ds3103_writereg(state, 0x04, 0x01 | m88ds3103_readreg(state, 0x04));
>> +	m88ds3103_writereg(state, 0x23, 0x10 | m88ds3103_readreg(state, 0x23));
>> +	
>> +
>> +	return 0;
>> +}
>> +
>> +static struct dvb_frontend_ops m88ds3103_ops = {
>> +	.delsys = { SYS_DVBS, SYS_DVBS2},
>> +	.info = {
>> +		.name = "Montage DS3103/TS2022",
>> +		.type = FE_QPSK,
>> +		.frequency_min = 950000,
>> +		.frequency_max = 2150000,
>> +		.frequency_stepsize = 1011, /* kHz for QPSK frontends */
>> +		.frequency_tolerance = 5000,
>> +		.symbol_rate_min = 1000000,
>> +		.symbol_rate_max = 45000000,
>> +		.caps = FE_CAN_INVERSION_AUTO |
>> +			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
>> +			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
>> +			FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
>> +			FE_CAN_2G_MODULATION |
>> +			FE_CAN_QPSK | FE_CAN_RECOVER
>> +	},
>> +
>> +	.release = m88ds3103_release,
>> +
>> +	.init = m88ds3103_initfe,
>> +	.sleep = m88ds3103_sleep,
>> +	.read_status = m88ds3103_read_status,
>> +	.read_ber = m88ds3103_read_ber,
>> +	.read_signal_strength = m88ds3103_read_signal_strength,
>> +	.read_snr = m88ds3103_read_snr,
>> +	.read_ucblocks = m88ds3103_read_ucblocks,
>> +	.set_tone = m88ds3103_set_tone,
>> +	.set_voltage = m88ds3103_set_voltage,
>> +	.diseqc_send_master_cmd = m88ds3103_send_diseqc_msg,
>> +	.diseqc_send_burst = m88ds3103_diseqc_send_burst,
>> +	.get_frontend_algo = m88ds3103_get_algo,
>> +	.tune = m88ds3103_tune,
>> +	.set_frontend = m88ds3103_set_frontend,
>> +};
>> +
>> +MODULE_DESCRIPTION("DVB Frontend module for Montage DS3103/TS2022 hardware");
>> +MODULE_AUTHOR("Max nibble");
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/media/dvb/frontends/m88ds3103.h b/drivers/media/dvb/frontends/m88ds3103.h
>> new file mode 100644
>> index 0000000..c7b690e
>> --- /dev/null
>> +++ b/drivers/media/dvb/frontends/m88ds3103.h
>> @@ -0,0 +1,53 @@
>> +/*
>> +    Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner driver
>> +
>> +    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 M88DS3103_H
>> +#define M88DS3103_H
>> +
>> +#include <linux/dvb/frontend.h>
>> +
>> +struct m88ds3103_config {
>> +	/* the demodulator's i2c address */
>> +	u8 demod_address;
>> +	u8 ci_mode;
>> +	u8 pin_ctrl;
>> +	u8 ts_mode; /* 0: Parallel, 1: Serial */
>> +
>> +	/* Set device param to start dma */
>> +	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
>> +    /* Start to transfer data */
>> +    int (*start_ctrl)(struct dvb_frontend *fe);
>> +    /* Set LNB voltage */
>> +    int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
>> +};
>> +
>> +#if defined(CONFIG_DVB_M88DS3103) || \
>> +	(defined(CONFIG_DVB_M88DS3103_MODULE) && defined(MODULE))
>> +extern struct dvb_frontend *m88ds3103_attach(
>> +       const struct m88ds3103_config *config,
>> +       struct i2c_adapter *i2c);
>> +#else
>> +static inline struct dvb_frontend *m88ds3103_attach(
>> +       const struct m88ds3103_config *config,
>> +       struct i2c_adapter *i2c)
>> +{
>> +	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
>> +	return NULL;
>> +}
>> +#endif /* CONFIG_DVB_M88DS3103 */
>> +#endif /* M88DS3103_H */
>
>.


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Re: [PATCH 2/6] m88ds3103, dvbsky dvb-s2 usb box.
  2012-04-15 15:53   ` [PATCH 2/6] m88ds3103, dvbsky dvb-s2 usb box nibble.max
  2012-04-19 18:09     ` Mauro Carvalho Chehab
@ 2012-04-20  8:08     ` nibble.max
  2012-04-20 17:08       ` Mauro Carvalho Chehab
  1 sibling, 1 reply; 56+ messages in thread
From: nibble.max @ 2012-04-20  8:08 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: linux-media

2012-04-20 16:02:41 nibble.max@gmail.com
>Em 15-04-2012 12:53, nibble.max escreveu:
>> dvbsky dvb-s2 usb box based on montage m88ds3103 demodulator.
>> 
>> Signed-off-by: Max nibble <nibble.max@gmail.com>
>> ---
>>  drivers/media/dvb/dvb-usb/Kconfig  |    1 +
>>  drivers/media/dvb/dvb-usb/dw2102.c |  236 +++++++++++++++++++++++++++++++++++-
>>  2 files changed, 236 insertions(+), 1 deletion(-)
>> 
>> diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
>> index be1db75..bf63f29 100644
>> --- a/drivers/media/dvb/dvb-usb/Kconfig
>> +++ b/drivers/media/dvb/dvb-usb/Kconfig
>> @@ -279,6 +279,7 @@ config DVB_USB_DW2102
>>  	select DVB_STV0288 if !DVB_FE_CUSTOMISE
>>  	select DVB_STB6000 if !DVB_FE_CUSTOMISE
>>  	select DVB_CX24116 if !DVB_FE_CUSTOMISE
>> +	select DVB_M88DS3103 if !DVB_FE_CUSTOMISE
>>  	select DVB_SI21XX if !DVB_FE_CUSTOMISE
>>  	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
>>  	select DVB_MT312 if !DVB_FE_CUSTOMISE
>> diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c
>> index 451c5a7..0b1bbd2 100644
>> --- a/drivers/media/dvb/dvb-usb/dw2102.c
>> +++ b/drivers/media/dvb/dvb-usb/dw2102.c
>> @@ -19,6 +19,7 @@
>>  #include "stb6000.h"
>>  #include "eds1547.h"
>>  #include "cx24116.h"
>> +#include "m88ds3103.h"
>>  #include "tda1002x.h"
>>  #include "mt312.h"
>>  #include "zl10039.h"
>> @@ -882,6 +883,44 @@ static int s660_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
>>  	return 0;
>>  }
>>  
>> +static int bstusb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
>> +{
>> +
>> +	struct dvb_usb_adapter *udev_adap =
>> +		(struct dvb_usb_adapter *)(fe->dvb->priv);
>> +
>> +	u8 obuf[3] = { 0xe, 0x80, 0 };
>> +	u8 ibuf[] = { 0 };
>> +		
>> +	info("US6830: %s!\n", __func__);
>> +				
>> +	if (voltage == SEC_VOLTAGE_OFF)
>> +		obuf[2] = 0;
>> +	else 
>> +		obuf[2] = 1;
>> +		
>> +	if (dvb_usb_generic_rw(udev_adap->dev, obuf, 3, ibuf, 1, 0) < 0)
>> +		err("command 0x0e transfer failed.");
>> +	
>> +	return 0;
>> +}
>> +
>> +static int bstusb_restart(struct dvb_frontend *fe)
>> +{
>> +
>> +	struct dvb_usb_adapter *udev_adap =
>> +		(struct dvb_usb_adapter *)(fe->dvb->priv);
>> +	
>> +	u8 obuf[3] = { 0x36, 3, 0 };
>> +	u8 ibuf[] = { 0 };
>> +			
>> +
>> +	if (dvb_usb_generic_rw(udev_adap->dev, obuf, 3, ibuf, 1, 0) < 0)
>> +		err("command 0x36 transfer failed.");
>> +	
>> +	return 0;
>> +}
>> +
>>  static void dw210x_led_ctrl(struct dvb_frontend *fe, int offon)
>>  {
>>  	static u8 led_off[] = { 0 };
>> @@ -987,6 +1026,24 @@ static struct ds3000_config su3000_ds3000_config = {
>>  	.ci_mode = 1,
>>  };
>>  
>> +static struct m88ds3103_config US6830_ds3103_config = {
>> +	.demod_address = 0x68,
>> +	.ci_mode = 1,
>> +	.pin_ctrl = 0x83,
>> +	.ts_mode = 0,
>> +	.start_ctrl = bstusb_restart,
>> +	.set_voltage = bstusb_set_voltage,
>> +};
>> +
>> +static struct m88ds3103_config US6832_ds3103_config = {
>> +	.demod_address = 0x68,
>> +	.ci_mode = 1,
>> +	.pin_ctrl = 0x80,
>> +	.ts_mode = 0,
>> +	.start_ctrl = bstusb_restart,
>> +	.set_voltage = bstusb_set_voltage,
>> +};
>> +
>>  static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
>>  {
>>  	struct dvb_tuner_ops *tuner_ops = NULL;
>> @@ -1214,6 +1271,72 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *d)
>>  	return 0;
>>  }
>>  
>> +static int US6830_frontend_attach(struct dvb_usb_adapter *d)
>> +{
>> +	u8 obuf[3] = { 0xe, 0x83, 0 };
>> +	u8 ibuf[] = { 0 };
>> +
>> +
>> +	info("US6830: %s!\n", __func__);
>> +	
>> +	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
>> +		err("command 0x0e transfer failed.");
>> +
>> +	obuf[0] = 0xe;
>> +	obuf[1] = 0x83;
>> +	obuf[2] = 1;
>> +
>> +	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
>> +		err("command 0x0e transfer failed.");
>> +
>> +	obuf[0] = 0x51;
>> +
>> +	if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
>> +		err("command 0x51 transfer failed.");
>> +
>> +	d->fe_adap[0].fe = dvb_attach(m88ds3103_attach, &US6830_ds3103_config,
>> +					&d->dev->i2c_adap);
>> +	if (d->fe_adap[0].fe == NULL)
>> +		return -EIO;
>> +
>> +	info("Attached M88DS3103!\n");
>> +
>> +	return 0;
>> +}
>> +
>> +static int US6832_frontend_attach(struct dvb_usb_adapter *d)
>> +{
>> +	u8 obuf[3] = { 0xe, 0x83, 0 };
>> +	u8 ibuf[] = { 0 };
>> +
>> +
>> +	info("US6832: %s!\n", __func__);
>> +	
>> +	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
>> +		err("command 0x0e transfer failed.");
>> +
>> +	obuf[0] = 0xe;
>> +	obuf[1] = 0x83;
>> +	obuf[2] = 1;
>> +
>> +	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
>> +		err("command 0x0e transfer failed.");
>> +
>> +	obuf[0] = 0x51;
>> +
>> +	if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
>> +		err("command 0x51 transfer failed.");
>> +
>> +	d->fe_adap[0].fe = dvb_attach(m88ds3103_attach, &US6832_ds3103_config,
>> +					&d->dev->i2c_adap);
>> +	if (d->fe_adap[0].fe == NULL)
>> +		return -EIO;
>> +
>> +	info("Attached M88DS3103!\n");
>> +
>> +	return 0;
>> +}
>> +
>>  static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
>>  {
>>  	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
>> @@ -1451,6 +1574,9 @@ enum dw2102_table_entry {
>>  	TEVII_S480_1,
>>  	TEVII_S480_2,
>>  	X3M_SPC1400HD,
>> +	BST_US6830HD,
>> +	BST_US6831HD,
>> +	BST_US6832HD,
>>  };
>>  
>>  static struct usb_device_id dw2102_table[] = {
>> @@ -1469,6 +1595,9 @@ static struct usb_device_id dw2102_table[] = {
>>  	[TEVII_S480_1] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)},
>>  	[TEVII_S480_2] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)},
>>  	[X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)},
>> +	[BST_US6830HD] = {USB_DEVICE(0x0572, 0x6830)},
>> +	[BST_US6831HD] = {USB_DEVICE(0x0572, 0x6831)},
>> +	[BST_US6832HD] = {USB_DEVICE(0x0572, 0x6832)},
>>  	{ }
>>  };
>>  
>> @@ -1874,6 +2003,107 @@ static struct dvb_usb_device_properties su3000_properties = {
>>  	}
>>  };
>>  
>> +static struct dvb_usb_device_properties US6830_properties = {
>> +	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
>> +	.usb_ctrl = DEVICE_SPECIFIC,
>> +	.size_of_priv = sizeof(struct su3000_state),
>> +	.power_ctrl = su3000_power_ctrl,
>> +	.num_adapters = 1,
>> +	.identify_state	= su3000_identify_state,
>> +	.i2c_algo = &su3000_i2c_algo,
>> +
>> +	.rc.legacy = {
>> +		.rc_map_table = rc_map_su3000_table,
>> +		.rc_map_size = ARRAY_SIZE(rc_map_su3000_table),
>> +		.rc_interval = 150,
>> +		.rc_query = dw2102_rc_query,
>> +	},
>
>
>New drivers should use .rc.core instead. For a simple example on how to use,
>please take a look at the az6007 driver.
>
It is strange to me that I need write two keymaps for one remote controller, one for USB box, the other for pcie cards.
rc.core will save my time to keep one keymap for all. :)

>> +
>> +	.read_mac_address = su3000_read_mac_address,
>> +
>> +	.generic_bulk_ctrl_endpoint = 0x01,
>> +	
>> +	.adapter = {
>> +		{
>> +		.num_frontends = 1,
>> +		.fe = {{
>> +			.streaming_ctrl   = su3000_streaming_ctrl,
>> +			.frontend_attach  = US6830_frontend_attach,
>> +			.stream = {
>> +				.type = USB_BULK,
>> +				.count = 8,
>> +				.endpoint = 0x82,
>> +				.u = {
>> +					.bulk = {
>> +						.buffersize = 4096,
>> +					}
>> +				}
>> +			}
>> +		}},
>> +		}
>> +	},
>> +	.num_device_descs = 2,
>> +	.devices = {
>> +		{ "Bestunar US6830 HD",
>> +			{ &dw2102_table[BST_US6830HD], NULL },
>> +			{ NULL },
>> +		},
>> +		{ "Bestunar US6831 HD",
>> +			{ &dw2102_table[BST_US6831HD], NULL },
>> +			{ NULL },
>> +		},				
>> +	}
>> +};
>> +
>> +static struct dvb_usb_device_properties US6832_properties = {
>> +	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
>> +	.usb_ctrl = DEVICE_SPECIFIC,
>> +	.size_of_priv = sizeof(struct su3000_state),
>> +	.power_ctrl = su3000_power_ctrl,
>> +	.num_adapters = 1,
>> +	.identify_state	= su3000_identify_state,
>> +	.i2c_algo = &su3000_i2c_algo,
>> +
>> +	.rc.legacy = {
>> +		.rc_map_table = rc_map_su3000_table,
>> +		.rc_map_size = ARRAY_SIZE(rc_map_su3000_table),
>> +		.rc_interval = 150,
>> +		.rc_query = dw2102_rc_query,
>> +	},
>> +
>> +	.read_mac_address = su3000_read_mac_address,
>> +
>> +	.generic_bulk_ctrl_endpoint = 0x01,
>> +
>> +	.adapter = {
>> +		{
>> +		.num_frontends = 1,
>> +		.fe = {{
>> +			.streaming_ctrl   = su3000_streaming_ctrl,
>> +			.frontend_attach  = US6832_frontend_attach,
>> +			.stream = {
>> +				.type = USB_BULK,
>> +				.count = 8,
>> +				.endpoint = 0x82,
>> +				.u = {
>> +					.bulk = {
>> +						.buffersize = 4096,
>> +					}
>> +				}
>> +			}
>> +		}},
>> +		}
>> +	},
>> +	.num_device_descs = 1,
>> +	.devices = {
>> +		{ "Bestunar US6832 HD",
>> +			{ &dw2102_table[BST_US6832HD], NULL },
>> +			{ NULL },
>> +		},
>> +				
>> +	}
>> +};
>> +
>>  static int dw2102_probe(struct usb_interface *intf,
>>  		const struct usb_device_id *id)
>>  {
>> @@ -1930,7 +2160,11 @@ static int dw2102_probe(struct usb_interface *intf,
>>  	    0 == dvb_usb_device_init(intf, p7500,
>>  			THIS_MODULE, NULL, adapter_nr) ||
>>  	    0 == dvb_usb_device_init(intf, &su3000_properties,
>> -				     THIS_MODULE, NULL, adapter_nr))
>> +     			THIS_MODULE, NULL, adapter_nr) ||
>> +	    0 == dvb_usb_device_init(intf, &US6830_properties,
>> +			THIS_MODULE, NULL, adapter_nr) ||
>> +	    0 == dvb_usb_device_init(intf, &US6832_properties,
>> +			THIS_MODULE, NULL, adapter_nr))
>>  		return 0;
>>  
>>  	return -ENODEV;
>
>.


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-20  8:01     ` nibble.max
@ 2012-04-20  9:47       ` Antti Palosaari
  2012-04-20 17:24         ` Mauro Carvalho Chehab
  2012-04-21  2:45         ` nibble.max
  2012-04-20 17:10       ` [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver Mauro Carvalho Chehab
  1 sibling, 2 replies; 56+ messages in thread
From: Antti Palosaari @ 2012-04-20  9:47 UTC (permalink / raw)
  To: nibble.max; +Cc: Mauro Carvalho Chehab, linux-media

On 20.04.2012 11:01, nibble.max wrote:
> 2012-04-20 15:56:27 nibble.max@gmail.com
> At first time, I check it exist so try to patch it.
> But with new m88ds3103 features to add and ts2022 tuner include, find it is hard to do simply patch.
> It is better to create a new driver for maintain.
>> Hi Max,
>>
>> Em 15-04-2012 12:53, nibble.max escreveu:
>>> Montage m88ds3103 demodulator and ts2022 tuner driver.
>>
>> It was pointed to me that this device were already discussed on:
>>
>>    http://www.mail-archive.com/linux-media@vger.kernel.org/msg43109.html
>>
>> If m88ds3103 demod is similar enough to ds3000, it should just add the needed
>> bits at the existing driver, and not creating a new driver.
>>
>> Thanks,
>> Mauro

The main problem of these all existing and upcoming Montage DVB-S/S2 
drivers are those are not split originally correct as a tuner and demod 
and now it causes problems.

I really suspect it should be:
* single demod driver that supports both DS3000 and DS3103
* single tuner driver that supports both TS2020 and TS2022

And now what we have is 2 drivers that contains both tuner and demod. 
And a lot of same code. :-(

But it is almost impossible to split it correctly at that phase if you 
don't have both hardware combinations, DS3000/TS2020 and DS3103/TS2022. 
I think it is best to leave old DS3000 as it is and make new driver for 
DS3103 *and* TS2022. Maybe after that someone could add DS3000 support 
to new DS3103 driver and TS2020 support to new TS2022 driver. After that 
it is possible to remove old DS3000 driver.

And we should really consider make simple rule not to accept any driver 
which is not split as logical parts: USB/PCI-interface + demodulator + 
tuner.

regards
Antti
-- 
http://palosaari.fi/

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 2/6] m88ds3103, dvbsky dvb-s2 usb box.
  2012-04-20  8:08     ` nibble.max
@ 2012-04-20 17:08       ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 56+ messages in thread
From: Mauro Carvalho Chehab @ 2012-04-20 17:08 UTC (permalink / raw)
  To: nibble.max; +Cc: linux-media

Em 20-04-2012 05:08, nibble.max escreveu:
> 2012-04-20 16:02:41 nibble.max@gmail.com
>> Em 15-04-2012 12:53, nibble.max escreveu:
>>> +static struct dvb_usb_device_properties US6830_properties = {
>>> +	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
>>> +	.usb_ctrl = DEVICE_SPECIFIC,
>>> +	.size_of_priv = sizeof(struct su3000_state),
>>> +	.power_ctrl = su3000_power_ctrl,
>>> +	.num_adapters = 1,
>>> +	.identify_state	= su3000_identify_state,
>>> +	.i2c_algo = &su3000_i2c_algo,
>>> +
>>> +	.rc.legacy = {
>>> +		.rc_map_table = rc_map_su3000_table,
>>> +		.rc_map_size = ARRAY_SIZE(rc_map_su3000_table),
>>> +		.rc_interval = 150,
>>> +		.rc_query = dw2102_rc_query,
>>> +	},
>>
>>
>> New drivers should use .rc.core instead. For a simple example on how to use,
>> please take a look at the az6007 driver.
>>
> It is strange to me that I need write two keymaps for one remote controller, one for USB box, the other for pcie cards.
> rc.core will save my time to keep one keymap for all. :)
> 

One remote controller just needs one keymap file. If the same IR requires two different
tables, then something is wrong at the get_key function (or, for drivers where only the
lower 8bits are returned - the IR mask is not properly set).

Regards,
Mauro

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-20  8:01     ` nibble.max
  2012-04-20  9:47       ` Antti Palosaari
@ 2012-04-20 17:10       ` Mauro Carvalho Chehab
  1 sibling, 0 replies; 56+ messages in thread
From: Mauro Carvalho Chehab @ 2012-04-20 17:10 UTC (permalink / raw)
  To: nibble.max; +Cc: linux-media

Em 20-04-2012 05:01, nibble.max escreveu:
> 2012-04-20 15:56:27 nibble.max@gmail.com
> At first time, I check it exist so try to patch it.
> But with new m88ds3103 features to add and ts2022 tuner include, find it is hard to do simply patch.
> It is better to create a new driver for maintain.

The tuner should be split into a separate file. For the new ds3103 features, just add
some logic (or some config) parameter to tell that the device is DS3103 and use the
new features only in this case.

Regards,
Mauro


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-20  9:47       ` Antti Palosaari
@ 2012-04-20 17:24         ` Mauro Carvalho Chehab
  2012-04-21  2:45         ` nibble.max
  1 sibling, 0 replies; 56+ messages in thread
From: Mauro Carvalho Chehab @ 2012-04-20 17:24 UTC (permalink / raw)
  To: Antti Palosaari; +Cc: nibble.max, linux-media, Konstantin Dimitrov

Em 20-04-2012 06:47, Antti Palosaari escreveu:
> On 20.04.2012 11:01, nibble.max wrote:
>> 2012-04-20 15:56:27 nibble.max@gmail.com
>> At first time, I check it exist so try to patch it.
>> But with new m88ds3103 features to add and ts2022 tuner include, find it is hard to do simply patch.
>> It is better to create a new driver for maintain.
>>> Hi Max,
>>>
>>> Em 15-04-2012 12:53, nibble.max escreveu:
>>>> Montage m88ds3103 demodulator and ts2022 tuner driver.
>>>
>>> It was pointed to me that this device were already discussed on:
>>>
>>>    http://www.mail-archive.com/linux-media@vger.kernel.org/msg43109.html
>>>
>>> If m88ds3103 demod is similar enough to ds3000, it should just add the needed
>>> bits at the existing driver, and not creating a new driver.
>>>
>>> Thanks,
>>> Mauro
> 
> The main problem of these all existing and upcoming Montage DVB-S/S2 drivers are those are not split originally correct as a tuner and demod and now it causes problems.
> 
> I really suspect it should be:
> * single demod driver that supports both DS3000 and DS3103
> * single tuner driver that supports both TS2020 and TS2022
> 
> And now what we have is 2 drivers that contains both tuner and demod. And a lot of same code. :-(
> 
> But it is almost impossible to split it correctly at that phase if you don't have both hardware combinations, DS3000/TS2020 and DS3103/TS2022. I think it is best to leave old DS3000 as it is and make new driver for DS3103 *and* TS2022. Maybe after that someone could add DS3000 support to new DS3103 driver and TS2020 support to new TS2022 driver. After that it is possible to remove old DS3000 driver.
> 
> And we should really consider make simple rule not to accept any driver which is not split as logical parts: USB/PCI-interface + demodulator + tuner.

Mixing tuner and demod is not good. Yet, dropping the current ds3000 doesn't
seem to be the best approach.

IMO, Konstantin/Montage should split the ds3000 driver on two drivers, putting
the ts2020 bits on a separate driver.

Then, Max should write a patch for ds3000 in order to add support for ds3103 on
it, and a patch for ts2020 driver, in order to add support for ts2022 on it.

Of course, Konstantin should check if Max changes don't break support for the
DS3000/TS2020 configuration.

Regards,
Mauro

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-20  9:47       ` Antti Palosaari
  2012-04-20 17:24         ` Mauro Carvalho Chehab
@ 2012-04-21  2:45         ` nibble.max
  2012-04-23 16:41           ` Antti Palosaari
  1 sibling, 1 reply; 56+ messages in thread
From: nibble.max @ 2012-04-21  2:45 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Antti Palosaari; +Cc: linux-media, Konstantin Dimitrov

2012-04-21 10:38:02 nibble.max@gmail.com
>Em 20-04-2012 06:47, Antti Palosaari escreveu:
>> On 20.04.2012 11:01, nibble.max wrote:
>>> 2012-04-20 15:56:27 nibble.max@gmail.com
>>> At first time, I check it exist so try to patch it.
>>> But with new m88ds3103 features to add and ts2022 tuner include, find it is hard to do simply patch.
>>> It is better to create a new driver for maintain.
>>>> Hi Max,
>>>>
>>>> Em 15-04-2012 12:53, nibble.max escreveu:
>>>>> Montage m88ds3103 demodulator and ts2022 tuner driver.
>>>>
>>>> It was pointed to me that this device were already discussed on:
>>>>
>>>>    http://www.mail-archive.com/linux-media@vger.kernel.org/msg43109.html
>>>>
>>>> If m88ds3103 demod is similar enough to ds3000, it should just add the needed
>>>> bits at the existing driver, and not creating a new driver.
>>>>
>>>> Thanks,
>>>> Mauro
>> 
>> The main problem of these all existing and upcoming Montage DVB-S/S2 drivers are those are not split originally correct as a tuner and demod and now it causes problems.
>> 
>> I really suspect it should be:
>> * single demod driver that supports both DS3000 and DS3103
>> * single tuner driver that supports both TS2020 and TS2022
>> 
>> And now what we have is 2 drivers that contains both tuner and demod. And a lot of same code. :-(
>> 
>> But it is almost impossible to split it correctly at that phase if you don't have both hardware combinations, DS3000/TS2020 and DS3103/TS2022. I think it is best to leave old DS3000 as it is and make new driver for DS3103 *and* TS2022. Maybe after that someone could add DS3000 support to new DS3103 driver and TS2020 support to new TS2022 driver. After that it is possible to remove old DS3000 driver.
>> 
>> And we should really consider make simple rule not to accept any driver which is not split as logical parts: USB/PCI-interface + demodulator + tuner.
>
>Mixing tuner and demod is not good. Yet, dropping the current ds3000 doesn't
>seem to be the best approach.
>
>IMO, Konstantin/Montage should split the ds3000 driver on two drivers, putting
>the ts2020 bits on a separate driver.
>
>Then, Max should write a patch for ds3000 in order to add support for ds3103 on
>it, and a patch for ts2020 driver, in order to add support for ts2022 on it.
>
>Of course, Konstantin should check if Max changes don't break support for the
>DS3000/TS2020 configuration.
>
>Regards,
>Mauro
Actually, I have the following hardware combinations.
1)DS3000 and TS2020 2)DS3103 and TS2020 3)DS3103 and TS2022
Should I sumbit the driver for DS3103 and TS2022 in the split files?
Or I must wait for Konstantin's work. How long should I wait for?

BR,
Max.


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-21  2:45         ` nibble.max
@ 2012-04-23 16:41           ` Antti Palosaari
  2012-04-23 19:51             ` Konstantin Dimitrov
  0 siblings, 1 reply; 56+ messages in thread
From: Antti Palosaari @ 2012-04-23 16:41 UTC (permalink / raw)
  To: nibble.max; +Cc: Mauro Carvalho Chehab, linux-media, Konstantin Dimitrov

On 21.04.2012 05:45, nibble.max wrote:
> 2012-04-21 10:38:02 nibble.max@gmail.com
>> Em 20-04-2012 06:47, Antti Palosaari escreveu:
>>> On 20.04.2012 11:01, nibble.max wrote:
>>>> 2012-04-20 15:56:27 nibble.max@gmail.com
>>>> At first time, I check it exist so try to patch it.
>>>> But with new m88ds3103 features to add and ts2022 tuner include, find it is hard to do simply patch.
>>>> It is better to create a new driver for maintain.
>>>>> Hi Max,
>>>>>
>>>>> Em 15-04-2012 12:53, nibble.max escreveu:
>>>>>> Montage m88ds3103 demodulator and ts2022 tuner driver.
>>>>>
>>>>> It was pointed to me that this device were already discussed on:
>>>>>
>>>>>     http://www.mail-archive.com/linux-media@vger.kernel.org/msg43109.html
>>>>>
>>>>> If m88ds3103 demod is similar enough to ds3000, it should just add the needed
>>>>> bits at the existing driver, and not creating a new driver.
>>>>>
>>>>> Thanks,
>>>>> Mauro
>>>
>>> The main problem of these all existing and upcoming Montage DVB-S/S2 drivers are those are not split originally correct as a tuner and demod and now it causes problems.
>>>
>>> I really suspect it should be:
>>> * single demod driver that supports both DS3000 and DS3103
>>> * single tuner driver that supports both TS2020 and TS2022
>>>
>>> And now what we have is 2 drivers that contains both tuner and demod. And a lot of same code. :-(
>>>
>>> But it is almost impossible to split it correctly at that phase if you don't have both hardware combinations, DS3000/TS2020 and DS3103/TS2022. I think it is best to leave old DS3000 as it is and make new driver for DS3103 *and* TS2022. Maybe after that someone could add DS3000 support to new DS3103 driver and TS2020 support to new TS2022 driver. After that it is possible to remove old DS3000 driver.
>>>
>>> And we should really consider make simple rule not to accept any driver which is not split as logical parts: USB/PCI-interface + demodulator + tuner.
>>
>> Mixing tuner and demod is not good. Yet, dropping the current ds3000 doesn't
>> seem to be the best approach.
>>
>> IMO, Konstantin/Montage should split the ds3000 driver on two drivers, putting
>> the ts2020 bits on a separate driver.
>>
>> Then, Max should write a patch for ds3000 in order to add support for ds3103 on
>> it, and a patch for ts2020 driver, in order to add support for ts2022 on it.
>>
>> Of course, Konstantin should check if Max changes don't break support for the
>> DS3000/TS2020 configuration.
>>
>> Regards,
>> Mauro
> Actually, I have the following hardware combinations.
> 1)DS3000 and TS2020 2)DS3103 and TS2020 3)DS3103 and TS2022
> Should I sumbit the driver for DS3103 and TS2022 in the split files?
> Or I must wait for Konstantin's work. How long should I wait for?

OK, then you have good change to write driver for the DS3103 and 
TS2020/TS2022.

I don't know how long exactly we should wait Konstantin's reply - this 
issue have open now several weeks and I think he haven't replied. My 
opinion is that lets wait few days and if no any reply just start 
splitting your driver for the DS3103 and TS2020/TS2022.

regards
Antti
-- 
http://palosaari.fi/

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-23 16:41           ` Antti Palosaari
@ 2012-04-23 19:51             ` Konstantin Dimitrov
  2012-04-23 21:04               ` Antti Palosaari
                                 ` (3 more replies)
  0 siblings, 4 replies; 56+ messages in thread
From: Konstantin Dimitrov @ 2012-04-23 19:51 UTC (permalink / raw)
  To: Antti Palosaari; +Cc: nibble.max, Mauro Carvalho Chehab, linux-media

Antti, i already commented about ds3103 drivers months ago:

http://www.mail-archive.com/linux-media@vger.kernel.org/msg41135.html

and from my point of view nothing have changed - ds3103 chip is almost
the same as ds3000 and the driver i made for ds3000 from scratch is
what was used ds3103 drivers to be created. so, what you actually is
suggesting - my driver to be removed from the kernel and driver that
was made based on my hard work to be included and that driver author
even refuses to acknowledge my work?!  such practices are really good
for the open-source community, don't you think? also, we already have
one case for example, where to satisfy someone's interests two drivers
for the same demodulators (STV090x family of chips) were accepted in
the kernel - i doubt anyone actually can tell why there are 2 drivers
for STV090x in the kernel and instead the community to support the
driver for STV090x that was made with more open-source ideas in mind,
i.e. the one that can work with any STV090x design and which relies
less on code copyrighted by ST - anyway, those details about STV090x
drivers are off-topic here, but i'm still giving them as example,
because the fact is that already once such mess was created having
multiple drivers for the same generation of chips in the kernel and
apparently those practices will continue if someone don't raise those
questions out loud.

also, why Montage tuner code should be spitted from the demodulator
code? is there any evidence that any Montage tuner (ts2020 or ts2022)
can work with 3rd party demodulator different than ds3000 or ds3103?
are there such designs in real-life, e.g. either Montage demodulator
with 3rd party tuner or actually more importantly for what you're
suggesting Montage tuner (ts2020 or ts2022) with third party
demodulator? it's more or less the same case as with cx24116 (and
tda10071) demodulator, where the tuner (cx24118a) is controlled by the
firmware and thus it's solely part of the demodulator driver, even
that it's possible to control the cx24118a tuner that is used with
cx24116 (and tda10071) designs directly bypassing the firmware. so,
why we don't change in that way the cx24116 (and tda10071) drivers
too?

i just don't see what's the motivation behind what you're suggesting,
because ds3103 is almost the same as ds3000 from driver point of view
and one driver code can be used for both and Montage tuners in
question can work only with those demodulators (or at least are used
in practice only with them). so, if there are any evidences that's not
true then OK let's split them, but if not then what's the point of
that?

On Mon, Apr 23, 2012 at 7:41 PM, Antti Palosaari <crope@iki.fi> wrote:
> On 21.04.2012 05:45, nibble.max wrote:
>>
>> 2012-04-21 10:38:02 nibble.max@gmail.com
>>>
>>> Em 20-04-2012 06:47, Antti Palosaari escreveu:
>>>>
>>>> On 20.04.2012 11:01, nibble.max wrote:
>>>>>
>>>>> 2012-04-20 15:56:27 nibble.max@gmail.com
>>>>> At first time, I check it exist so try to patch it.
>>>>> But with new m88ds3103 features to add and ts2022 tuner include, find
>>>>> it is hard to do simply patch.
>>>>> It is better to create a new driver for maintain.
>>>>>>
>>>>>> Hi Max,
>>>>>>
>>>>>> Em 15-04-2012 12:53, nibble.max escreveu:
>>>>>>>
>>>>>>> Montage m88ds3103 demodulator and ts2022 tuner driver.
>>>>>>
>>>>>>
>>>>>> It was pointed to me that this device were already discussed on:
>>>>>>
>>>>>>
>>>>>>  http://www.mail-archive.com/linux-media@vger.kernel.org/msg43109.html
>>>>>>
>>>>>> If m88ds3103 demod is similar enough to ds3000, it should just add the
>>>>>> needed
>>>>>> bits at the existing driver, and not creating a new driver.
>>>>>>
>>>>>> Thanks,
>>>>>> Mauro
>>>>
>>>>
>>>> The main problem of these all existing and upcoming Montage DVB-S/S2
>>>> drivers are those are not split originally correct as a tuner and demod and
>>>> now it causes problems.
>>>>
>>>> I really suspect it should be:
>>>> * single demod driver that supports both DS3000 and DS3103
>>>> * single tuner driver that supports both TS2020 and TS2022
>>>>
>>>> And now what we have is 2 drivers that contains both tuner and demod.
>>>> And a lot of same code. :-(
>>>>
>>>> But it is almost impossible to split it correctly at that phase if you
>>>> don't have both hardware combinations, DS3000/TS2020 and DS3103/TS2022. I
>>>> think it is best to leave old DS3000 as it is and make new driver for DS3103
>>>> *and* TS2022. Maybe after that someone could add DS3000 support to new
>>>> DS3103 driver and TS2020 support to new TS2022 driver. After that it is
>>>> possible to remove old DS3000 driver.
>>>>
>>>> And we should really consider make simple rule not to accept any driver
>>>> which is not split as logical parts: USB/PCI-interface + demodulator +
>>>> tuner.
>>>
>>>
>>> Mixing tuner and demod is not good. Yet, dropping the current ds3000
>>> doesn't
>>> seem to be the best approach.
>>>
>>> IMO, Konstantin/Montage should split the ds3000 driver on two drivers,
>>> putting
>>> the ts2020 bits on a separate driver.
>>>
>>> Then, Max should write a patch for ds3000 in order to add support for
>>> ds3103 on
>>> it, and a patch for ts2020 driver, in order to add support for ts2022 on
>>> it.
>>>
>>> Of course, Konstantin should check if Max changes don't break support for
>>> the
>>> DS3000/TS2020 configuration.
>>>
>>> Regards,
>>> Mauro
>>
>> Actually, I have the following hardware combinations.
>> 1)DS3000 and TS2020 2)DS3103 and TS2020 3)DS3103 and TS2022
>> Should I sumbit the driver for DS3103 and TS2022 in the split files?
>> Or I must wait for Konstantin's work. How long should I wait for?
>
>
> OK, then you have good change to write driver for the DS3103 and
> TS2020/TS2022.
>
> I don't know how long exactly we should wait Konstantin's reply - this issue
> have open now several weeks and I think he haven't replied. My opinion is
> that lets wait few days and if no any reply just start splitting your driver
> for the DS3103 and TS2020/TS2022.
>
>
> regards
> Antti
> --
> http://palosaari.fi/

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-23 19:51             ` Konstantin Dimitrov
@ 2012-04-23 21:04               ` Antti Palosaari
  2012-04-27 18:44                 ` Konstantin Dimitrov
  2012-04-23 21:49               ` Mauro Carvalho Chehab
                                 ` (2 subsequent siblings)
  3 siblings, 1 reply; 56+ messages in thread
From: Antti Palosaari @ 2012-04-23 21:04 UTC (permalink / raw)
  To: Konstantin Dimitrov; +Cc: nibble.max, Mauro Carvalho Chehab, linux-media

Hello Konstantin,

Good to heard you and finally got your reply to thread.

On 23.04.2012 22:51, Konstantin Dimitrov wrote:
> Antti, i already commented about ds3103 drivers months ago:
>
> http://www.mail-archive.com/linux-media@vger.kernel.org/msg41135.html
>
> and from my point of view nothing have changed - ds3103 chip is almost
> the same as ds3000 and the driver i made for ds3000 from scratch is
> what was used ds3103 drivers to be created. so, what you actually is
> suggesting - my driver to be removed from the kernel and driver that
> was made based on my hard work to be included and that driver author
> even refuses to acknowledge my work?!  such practices are really good
> for the open-source community, don't you think? also, we already have
> one case for example, where to satisfy someone's interests two drivers
> for the same demodulators (STV090x family of chips) were accepted in
> the kernel - i doubt anyone actually can tell why there are 2 drivers
> for STV090x in the kernel and instead the community to support the
> driver for STV090x that was made with more open-source ideas in mind,
> i.e. the one that can work with any STV090x design and which relies
> less on code copyrighted by ST - anyway, those details about STV090x
> drivers are off-topic here, but i'm still giving them as example,
> because the fact is that already once such mess was created having
> multiple drivers for the same generation of chips in the kernel and
> apparently those practices will continue if someone don't raise those
> questions out loud.
>
> also, why Montage tuner code should be spitted from the demodulator
> code? is there any evidence that any Montage tuner (ts2020 or ts2022)
> can work with 3rd party demodulator different than ds3000 or ds3103?

I don't know what is situation of these Montage chips and what are 
possible combinations. *But* there is many existing cases from the DVB-T 
I am aware. Things are done wrongly and all is implemented as a one big 
blob. After that new device is arrived and we cannot support it since 
existing drivers are not split. And it is not single case...

It may happen or it may not happen. You never known. But still it is 
nice to split drivers correctly to avoid such problems that could be 
possible in some day. And I don't even know how much those tuners and 
demods differs - I only saw that patch and it looked there was some 
differences, even so much that two tuner drivers could be good choice.

> are there such designs in real-life, e.g. either Montage demodulator
> with 3rd party tuner or actually more importantly for what you're
> suggesting Montage tuner (ts2020 or ts2022) with third party
> demodulator? it's more or less the same case as with cx24116 (and
> tda10071) demodulator, where the tuner (cx24118a) is controlled by the
> firmware and thus it's solely part of the demodulator driver, even
> that it's possible to control the cx24118a tuner that is used with
> cx24116 (and tda10071) designs directly bypassing the firmware. so,
> why we don't change in that way the cx24116 (and tda10071) drivers
> too?

CX24116 and TDA10071 (I made TDA10071) are somehow different as tuner is 
driven by demodulator firmware. There is no tuner that needs to be 
driven by driver at least for now. There is also some DVB-T devices that 
has demod and tuner which are both controlled by USB -interface firmware 
and thus no chipset driver needed - only some stuff that implements 
frontend. But for the Montage demod/tuner there is clearly both chips 
driven by the driver.

> i just don't see what's the motivation behind what you're suggesting,
> because ds3103 is almost the same as ds3000 from driver point of view
> and one driver code can be used for both and Montage tuners in
> question can work only with those demodulators (or at least are used
> in practice only with them). so, if there are any evidences that's not
> true then OK let's split them, but if not then what's the point of
> that?

I want to split those correctly as it looked splitting could clear 
driver. Also what I suspect those problems Max had were coming from the 
fact it was not split and it makes driver complex when Max added new 
tuner and demod versions.

And my opinion is still it should be split and as a original driver 
author you are correct person to split it :) But you did not replied so 
I proposed Max should do it in order to go ahead.

And I apologize I proposed removing your driver, I know having own 
driver is something like own baby. But also having own baby it means you 
should care it also.

And what goes the original conflict you linked I am not going to 
comment. I still hope you can say what should be done and review the 
code in order to get support that new demod/tuner combo.

I just want things to done correctly. One driver per one entity. Just 
keep it simple and clean to extend later.

So let it be short, is my interpretation correct if I say you want all 
these 4 chips (ds3000/ds3103/ts2020/ts2022) to be driven by single driver?

regards
Antti
-- 
http://palosaari.fi/

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-23 19:51             ` Konstantin Dimitrov
  2012-04-23 21:04               ` Antti Palosaari
@ 2012-04-23 21:49               ` Mauro Carvalho Chehab
  2012-04-27 19:01                 ` Konstantin Dimitrov
  2012-04-24  2:45               ` Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver nibble.max
  2012-04-26 13:03               ` nibble.max
  3 siblings, 1 reply; 56+ messages in thread
From: Mauro Carvalho Chehab @ 2012-04-23 21:49 UTC (permalink / raw)
  To: Konstantin Dimitrov; +Cc: Antti Palosaari, nibble.max, linux-media

Em 23-04-2012 19:51, Konstantin Dimitrov escreveu:
> Antti, i already commented about ds3103 drivers months ago:
 
> also, why Montage tuner code should be spitted from the demodulator
> code? is there any evidence that any Montage tuner (ts2020 or ts2022)
> can work with 3rd party demodulator different than ds3000 or ds3103?

This has nothing to do with Montage devices, but with the way we write
those drivers in Kernel.

There are _several_ examples where the driver for a single silicon were
turned into more than one driver. The biggest examples are the SoC chips,
that are transformed into a large series of drivers.

Another example is the cx88 driver: due to technical reasons, it was splitted 
into 4 drivers, one for each different PCI ID exported by it. 

The cx2341x driver is also an interesting example: while it used to be for a
separate chip, the cx2341x functions are now part of IP blocks on newer 
Conexant chipsets. Those single chips require two drivers to work (cx2341x
and the associated media PCI bridge driver).

Looking into tuners, there are the tda18271 family of devices, with are
supported by several drivers: tda827x, tda8290 and tda18271-fe, depending
on how the actual device is mounted. Eventually, the actual tuner may
also have a tda9887 inside it.

So, there's nothing wrong on splitting it on separate drivers. In a matter of
fact, we strongly prefer to have tuners separate from demods. Having them
together can only be justified technically, if there are really strong reasons
why they should be at the same driver.

I probably missed this at my review for ds3000 (that's why it ended by being
merged), but, on the review I did on it (accidentally due to m88ds3103 patchset
review), it is clear that the tuner has actually a different I2C address (0x60)
than the demod, and it is indeed a separate device. Sorry for slipping into it.

Anyway, now that this is noticed, tuner and demod drivers should be split,
especially since there are some patches floating around to add support for ds3103.

As I said before, the right thing to do is:

	1) split ds3000 from ts2020 at the existing driver;
	2) add support for the newer chips (ds3103/ts2022) to the ds3000 and ds3103
	   drivers.
	3) test if the patches adding support for the newer chips didn't break the
	   support for existing hardware.

My proposal is that tasks (1) and (3) should be handled by you. As Max wants to
add support for some devices based on ds3103/ts2022, IMO, he can do the patches
for (2) in a way that they would be acceptable by you, as the driver maintainer
for ds3000/ts2020, testing with their devices.

Regards,
Mauro

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-23 19:51             ` Konstantin Dimitrov
  2012-04-23 21:04               ` Antti Palosaari
  2012-04-23 21:49               ` Mauro Carvalho Chehab
@ 2012-04-24  2:45               ` nibble.max
  2012-04-26 13:03               ` nibble.max
  3 siblings, 0 replies; 56+ messages in thread
From: nibble.max @ 2012-04-24  2:45 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Antti Palosaari, linux-media, Konstantin Dimitrov

2012-04-24 09:50:33 nibble.max@gmail.com
>Em 23-04-2012 19:51, Konstantin Dimitrov escreveu:
>> Antti, i already commented about ds3103 drivers months ago:
> 
>> also, why Montage tuner code should be spitted from the demodulator
>> code? is there any evidence that any Montage tuner (ts2020 or ts2022)
>> can work with 3rd party demodulator different than ds3000 or ds3103?
>
>This has nothing to do with Montage devices, but with the way we write
>those drivers in Kernel.
>
>There are _several_ examples where the driver for a single silicon were
>turned into more than one driver. The biggest examples are the SoC chips,
>that are transformed into a large series of drivers.
>
>Another example is the cx88 driver: due to technical reasons, it was splitted 
>into 4 drivers, one for each different PCI ID exported by it. 
>
>The cx2341x driver is also an interesting example: while it used to be for a
>separate chip, the cx2341x functions are now part of IP blocks on newer 
>Conexant chipsets. Those single chips require two drivers to work (cx2341x
>and the associated media PCI bridge driver).
>
>Looking into tuners, there are the tda18271 family of devices, with are
>supported by several drivers: tda827x, tda8290 and tda18271-fe, depending
>on how the actual device is mounted. Eventually, the actual tuner may
>also have a tda9887 inside it.
>
>So, there's nothing wrong on splitting it on separate drivers. In a matter of
>fact, we strongly prefer to have tuners separate from demods. Having them
>together can only be justified technically, if there are really strong reasons
>why they should be at the same driver.
>
>I probably missed this at my review for ds3000 (that's why it ended by being
>merged), but, on the review I did on it (accidentally due to m88ds3103 patchset
>review), it is clear that the tuner has actually a different I2C address (0x60)
>than the demod, and it is indeed a separate device. Sorry for slipping into it.
>
>Anyway, now that this is noticed, tuner and demod drivers should be split,
>especially since there are some patches floating around to add support for ds3103.
>
>As I said before, the right thing to do is:
>
>	1) split ds3000 from ts2020 at the existing driver;
>	2) add support for the newer chips (ds3103/ts2022) to the ds3000 and ds3103
>	   drivers.
>	3) test if the patches adding support for the newer chips didn't break the
>	   support for existing hardware.
>
>My proposal is that tasks (1) and (3) should be handled by you. As Max wants to
>add support for some devices based on ds3103/ts2022, IMO, he can do the patches
>for (2) in a way that they would be acceptable by you, as the driver maintainer
>for ds3000/ts2020, testing with their devices.
>
>Regards,
>Mauro

Montage M88ds3103 is not only working with its own tuners. 
It works with silicon tuner including AV2011, AV2026 and CAN tuner including sharp6306, sharp7803 and sharp7903 etc.
How to add these supports in the single file? It is really headache. 
So I think that spliting the tuner and demod file is only right way.

First I read the source code of DS3000 and show respects to ds3000 work in linux.
But find that it can not read back the tuner register correctly, and not set the right tuner bandwidth filter,etc.
I fix all those bugs and also update ds3000 firmware to the latest one.
The big one is that I start to add m88ds3103 demodulator and m88ts2022 tuner support. It is not just the work as simple as adding some constant. there are much difference as you can see much "switch and if" to apply the especial code for new tuner and demodulator.

But Konstantin tell me that I have no right to put the copyright in the file, even say many bad words to my works.
As I know that Konstantin works for the competitor company, I donot care the fight of his company and dvbsky.
Dvbsky develops its hardware by their own, and write windows driver. some of their technical guys have more than ten years in PC tuner design experience from old analog one based on bt878 chip. ohh, this story is out of this topic, sorry.

As many requirements to run into linux, I become the candidate to do it. 
It is public and open project, everybody can contribute to it. Is it right?
I think it is unfair and is abnormal for open source project. 
even start to read the GNU document carefully to check if the original author deny your work in the wrong way, what can i do?
So I decide to rewrite the code from scratch, and find almost ds3000 code copy from the reference code except the driver framework. 
It is obvious that the code is old one, montage update its ds3000 code after Konstantin' works. So I update to the new one.
I have no hardware of Konstantin's works and patch the original ds3000 because more complex works.
That is why I decide to write the new m88ds3103 file and put copyright of Montage and Konstantin as well to show repects to both.

BR,
Max


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Re: Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-23 19:51             ` Konstantin Dimitrov
                                 ` (2 preceding siblings ...)
  2012-04-24  2:45               ` Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver nibble.max
@ 2012-04-26 13:03               ` nibble.max
  2012-04-26 13:24                 ` Mauro Carvalho Chehab
  3 siblings, 1 reply; 56+ messages in thread
From: nibble.max @ 2012-04-26 13:03 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Antti Palosaari, linux-media, Konstantin Dimitrov

2012-04-26 20:59:28 nibble.max@gmail.com
>2012-04-24 09:50:33 nibble.max@gmail.com
>>Em 23-04-2012 19:51, Konstantin Dimitrov escreveu:
>>> Antti, i already commented about ds3103 drivers months ago:
>> 
>>> also, why Montage tuner code should be spitted from the demodulator
>>> code? is there any evidence that any Montage tuner (ts2020 or ts2022)
>>> can work with 3rd party demodulator different than ds3000 or ds3103?
>>
>>This has nothing to do with Montage devices, but with the way we write
>>those drivers in Kernel.
>>
>>There are _several_ examples where the driver for a single silicon were
>>turned into more than one driver. The biggest examples are the SoC chips,
>>that are transformed into a large series of drivers.
>>
>>Another example is the cx88 driver: due to technical reasons, it was splitted 
>>into 4 drivers, one for each different PCI ID exported by it. 
>>
>>The cx2341x driver is also an interesting example: while it used to be for a
>>separate chip, the cx2341x functions are now part of IP blocks on newer 
>>Conexant chipsets. Those single chips require two drivers to work (cx2341x
>>and the associated media PCI bridge driver).
>>
>>Looking into tuners, there are the tda18271 family of devices, with are
>>supported by several drivers: tda827x, tda8290 and tda18271-fe, depending
>>on how the actual device is mounted. Eventually, the actual tuner may
>>also have a tda9887 inside it.
>>
>>So, there's nothing wrong on splitting it on separate drivers. In a matter of
>>fact, we strongly prefer to have tuners separate from demods. Having them
>>together can only be justified technically, if there are really strong reasons
>>why they should be at the same driver.
>>
>>I probably missed this at my review for ds3000 (that's why it ended by being
>>merged), but, on the review I did on it (accidentally due to m88ds3103 patchset
>>review), it is clear that the tuner has actually a different I2C address (0x60)
>>than the demod, and it is indeed a separate device. Sorry for slipping into it.
>>
>>Anyway, now that this is noticed, tuner and demod drivers should be split,
>>especially since there are some patches floating around to add support for ds3103.
>>
>>As I said before, the right thing to do is:
>>
>>	1) split ds3000 from ts2020 at the existing driver;
>>	2) add support for the newer chips (ds3103/ts2022) to the ds3000 and ds3103
>>	   drivers.
>>	3) test if the patches adding support for the newer chips didn't break the
>>	   support for existing hardware.
>>
>>My proposal is that tasks (1) and (3) should be handled by you. As Max wants to
>>add support for some devices based on ds3103/ts2022, IMO, he can do the patches
>>for (2) in a way that they would be acceptable by you, as the driver maintainer
>>for ds3000/ts2020, testing with their devices.
>>
>>Regards,
>>Mauro
>
>Montage M88ds3103 is not only working with its own tuners. 
>It works with silicon tuner including AV2011, AV2026 and CAN tuner including sharp6306, sharp7803 and sharp7903 etc.
>How to add these supports in the single file? It is really headache. 
>So I think that spliting the tuner and demod file is only right way.
>
>First I read the source code of DS3000 and show respects to ds3000 work in linux.
>But find that it can not read back the tuner register correctly, and not set the right tuner bandwidth filter,etc.
>I fix all those bugs and also update ds3000 firmware to the latest one.
>The big one is that I start to add m88ds3103 demodulator and m88ts2022 tuner support. It is not just the work as simple as adding some constant. there are much difference as you can see much "switch and if" to apply the especial code for new tuner and demodulator.
>
>But Konstantin tell me that I have no right to put the copyright in the file, even say many bad words to my works.
>As I know that Konstantin works for the competitor company, I donot care the fight of his company and dvbsky.
>Dvbsky develops its hardware by their own, and write windows driver. some of their technical guys have more than ten years in PC tuner design experience from old analog one based on bt878 chip. ohh, this story is out of this topic, sorry.
>
>As many requirements to run into linux, I become the candidate to do it. 
>It is public and open project, everybody can contribute to it. Is it right?
>I think it is unfair and is abnormal for open source project. 
>even start to read the GNU document carefully to check if the original author deny your work in the wrong way, what can i do?
>So I decide to rewrite the code from scratch, and find almost ds3000 code copy from the reference code except the driver framework. 
>It is obvious that the code is old one, montage update its ds3000 code after Konstantin' works. So I update to the new one.
>I have no hardware of Konstantin's works and patch the original ds3000 because more complex works.
>That is why I decide to write the new m88ds3103 file and put copyright of Montage and Konstantin as well to show repects to both.
>
>BR,
>Max

Hello,
I finish the following works.
1)split the montage dvb-s2 frontend into tuner and demodulator files.
2)Fix the issues as Mauro addressed before.
3)Pass scripts/checkpatch.pl check.
So what is the next step for me?
Is there any schedule of Konstantin's work?
Br,
Max


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-26 13:03               ` nibble.max
@ 2012-04-26 13:24                 ` Mauro Carvalho Chehab
  2012-04-27  7:06                   ` [PATCH 1/6 v2] dvbsky, montage dvb-s/s2 TS202x tuner and M88DS3103 " nibble.max
                                     ` (5 more replies)
  0 siblings, 6 replies; 56+ messages in thread
From: Mauro Carvalho Chehab @ 2012-04-26 13:24 UTC (permalink / raw)
  To: nibble.max; +Cc: Antti Palosaari, linux-media, Konstantin Dimitrov

Em 26-04-2012 10:03, nibble.max escreveu:

> Hello,
> I finish the following works.
> 1)split the montage dvb-s2 frontend into tuner and demodulator files.

Send this patch first. As both tuner and demod drivers were written by
Konstantin, just make sure to preserve the existing copyrights as-is.

After having this patch approved/merged, we can dig into the next ones.

> 2)Fix the issues as Mauro addressed before.
> 3)Pass scripts/checkpatch.pl check.
> So what is the next step for me?
> Is there any schedule of Konstantin's work?
> Br,
> Max
> 

Thanks!
Mauro

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 1/6 v2] dvbsky, montage dvb-s/s2 TS202x tuner and M88DS3103 demodulator driver
  2012-04-26 13:24                 ` Mauro Carvalho Chehab
@ 2012-04-27  7:06                   ` nibble.max
  2012-04-27 11:06                     ` Mauro Carvalho Chehab
  2012-04-27 14:17                     ` Re: [PATCH 1/6 v2] dvbsky, montage dvb-s/s2 TS202x tuner and M88DS3103demodulator driver nibble.max
  2012-04-27  7:06                   ` [PATCH 2/6 v2] dvbsky, dvb-s/s2 usb box nibble.max
                                     ` (4 subsequent siblings)
  5 siblings, 2 replies; 56+ messages in thread
From: nibble.max @ 2012-04-27  7:06 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Antti Palosaari, linux-media, Konstantin Dimitrov

---
 drivers/media/dvb/frontends/Kconfig          |   14 +
 drivers/media/dvb/frontends/Makefile         |    3 +
 drivers/media/dvb/frontends/m88ds3103.c      | 1153 ++++++++++++++++++++++++++
 drivers/media/dvb/frontends/m88ds3103.h      |   67 ++
 drivers/media/dvb/frontends/m88ds3103_priv.h |  413 +++++++++
 drivers/media/dvb/frontends/m88ts202x.c      |  590 +++++++++++++
 drivers/media/dvb/frontends/m88ts202x.h      |   63 ++
 7 files changed, 2303 insertions(+)
 create mode 100644 drivers/media/dvb/frontends/m88ds3103.c
 create mode 100644 drivers/media/dvb/frontends/m88ds3103.h
 create mode 100644 drivers/media/dvb/frontends/m88ds3103_priv.h
 create mode 100644 drivers/media/dvb/frontends/m88ts202x.c
 create mode 100644 drivers/media/dvb/frontends/m88ts202x.h

diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index e11adb6..8d706f6 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -214,6 +214,20 @@ config DVB_CX24116
 	help
 	  A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
 
+config DVB_M88TS202X
+	tristate "Montage M88TS202X based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
+
+config DVB_M88DS3103
+	tristate "Montage M88DS3103 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
+
 config DVB_SI21XX
 	tristate "Silicon Labs SI21XX based"
 	depends on DVB_CORE && I2C
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 6ca7557..1fdfcb4 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -98,5 +98,8 @@ obj-$(CONFIG_DVB_A8293) += a8293.o
 obj-$(CONFIG_DVB_TDA10071) += tda10071.o
 obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
 obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
+obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o
+obj-$(CONFIG_DVB_M88TS202X) += m88ts202x.o
 obj-$(CONFIG_DVB_AF9033) += af9033.o
 
+
diff --git a/drivers/media/dvb/frontends/m88ds3103.c b/drivers/media/dvb/frontends/m88ds3103.c
new file mode 100644
index 0000000..392cada
--- /dev/null
+++ b/drivers/media/dvb/frontends/m88ds3103.c
@@ -0,0 +1,1153 @@
+/*
+    Montage Technology M88DS3103/3000 - DVBS/S2 Satellite demod driver
+
+    Copyright (C) 2011 Max nibble<nibble.max@gmail.com>
+    Copyright (C) 2010 Montage Technology<www.montage-tech.com>
+    Fix some bug and add M88DS3103 code, M88DS3000 code based on DS3000.c.
+
+    Copyright (C) 2009 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
+
+    Copyright (C) 2009 TurboSight.com
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/firmware.h>
+
+#include "dvb_frontend.h"
+#include "m88ds3103.h"
+#include "m88ds3103_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+
+/*demod register operations.*/
+static int m88ds3103_writereg(struct m88ds3103_state *state, int reg, int data)
+{
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = { .addr = state->config->demod_address,
+		.flags = 0, .buf = buf, .len = 2 };
+	int err;
+
+	if (debug > 1)
+		printk(KERN_INFO "m88ds3103: %s: write reg 0x%02x, value 0x%02x\n",
+			__func__, reg, data);
+
+	err = i2c_transfer(state->i2c, &msg, 1);
+	if (err != 1) {
+		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x,"
+			 " value == 0x%02x)\n", __func__, err, reg, data);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int m88ds3103_readreg(struct m88ds3103_state *state, u8 reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{ .addr = state->config->demod_address, .flags = 0,
+			.buf = b0, .len = 1 },
+		{ .addr = state->config->demod_address, .flags = I2C_M_RD,
+			.buf = b1, .len = 1 }
+	};
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) {
+		printk(KERN_ERR "%s: reg=0x%x (error=%d)\n",
+			__func__, reg, ret);
+		return ret;
+	}
+
+	if (debug > 1)
+		printk(KERN_INFO "m88ds3103: read reg 0x%02x, value 0x%02x\n",
+			reg, b1[0]);
+
+	return b1[0];
+}
+
+/* Bulk demod I2C write, for firmware download. */
+static int m88ds3103_writeregN(struct m88ds3103_state *state, int reg,
+				const u8 *data, u16 len)
+{
+	int ret = -EREMOTEIO;
+	struct i2c_msg msg;
+	u8 *buf;
+
+	buf = kmalloc(len + 1, GFP_KERNEL);
+	if (buf == NULL) {
+		printk(KERN_ERR "Unable to kmalloc\n");
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	*(buf) = reg;
+	memcpy(buf + 1, data, len);
+
+	msg.addr = state->config->demod_address;
+	msg.flags = 0;
+	msg.buf = buf;
+	msg.len = len + 1;
+
+	if (debug > 1)
+		printk(KERN_INFO "m88ds3103: %s:  write regN 0x%02x, len = %d\n",
+			__func__, reg, len);
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+	if (ret != 1) {
+		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n",
+			 __func__, ret, reg);
+		ret = -EREMOTEIO;
+	}
+error:
+	kfree(buf);
+
+	return ret;
+}
+
+static int m88ds3103_load_firmware(struct dvb_frontend *fe)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	const struct firmware *fw;
+	int i, ret = 0;
+
+	dprintk("%s()\n", __func__);
+
+	if (state->skip_fw_load)
+		return 0;
+	/* Load firmware */
+	/* request the firmware, this will block until someone uploads it */
+	if (state->demod_id == DS3000_ID) {
+		printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n",
+				__func__,
+				DS3000_DEFAULT_FIRMWARE);
+		ret = request_firmware(&fw, DS3000_DEFAULT_FIRMWARE,
+					state->i2c->dev.parent);
+	} else if (state->demod_id == DS3103_ID) {
+		printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n",
+				__func__,
+				DS3103_DEFAULT_FIRMWARE);
+		ret = request_firmware(&fw, DS3103_DEFAULT_FIRMWARE,
+					state->i2c->dev.parent);
+	}
+
+	printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__);
+	if (ret) {
+		printk(KERN_ERR "%s: No firmware uploaded (timeout or file not "
+				"found?)\n", __func__);
+		return ret;
+	}
+
+	/* Make sure we don't recurse back through here during loading */
+	state->skip_fw_load = 1;
+
+	dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
+			fw->size,
+			fw->data[0],
+			fw->data[1],
+			fw->data[fw->size - 2],
+			fw->data[fw->size - 1]);
+	/* stop internal mcu. */
+	m88ds3103_writereg(state, 0xb2, 0x01);
+	/* split firmware to download.*/
+	for (i = 0; i < FW_DOWN_LOOP; i++) {
+		ret = m88ds3103_writeregN(state, 0xb0,
+				&(fw->data[FW_DOWN_SIZE*i]), FW_DOWN_SIZE);
+		if (ret != 1)
+			break;
+	}
+	/* start internal mcu. */
+	if (ret == 1)
+		m88ds3103_writereg(state, 0xb2, 0x00);
+
+	release_firmware(fw);
+
+	dprintk("%s: Firmware upload %s\n", __func__,
+			ret == 1 ? "complete" : "failed");
+
+	if (ret == 1)
+		ret = 0;
+	/* Ensure firmware is always loaded if required */
+	state->skip_fw_load = 0;
+
+	return ret;
+}
+
+
+static int m88ds3103_set_voltage(struct dvb_frontend *fe,
+				fe_sec_voltage_t voltage)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	u8 data;
+
+	dprintk("%s(%d)\n", __func__, voltage);
+
+	dprintk("m88ds3103:pin_ctrl = (%02x)\n", state->config->pin_ctrl);
+
+	if (state->config->set_voltage)
+		state->config->set_voltage(fe, voltage);
+
+	data = m88ds3103_readreg(state, 0xa2);
+
+	if (state->config->pin_ctrl & 0x80) { /*If control pin is assigned.*/
+		data &= ~0x03; /* bit0 V/H, bit1 off/on */
+		if (state->config->pin_ctrl & 0x02)
+			data |= 0x02;
+
+		switch (voltage) {
+		case SEC_VOLTAGE_18:
+			if ((state->config->pin_ctrl & 0x01) == 0)
+				data |= 0x01;
+			break;
+		case SEC_VOLTAGE_13:
+			if ((state->config->pin_ctrl) & 0x01)
+				data |= 0x01;
+			break;
+		case SEC_VOLTAGE_OFF:
+			if ((state->config->pin_ctrl) & 0x02)
+				data &= ~0x02;
+			else
+				data |= 0x02;
+			break;
+		}
+	}
+	m88ds3103_writereg(state, 0xa2, data);
+
+	return 0;
+}
+
+static int m88ds3103_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	int lock = 0;
+
+	*status = 0;
+
+	switch (state->delivery_system) {
+	case SYS_DVBS:
+		lock = m88ds3103_readreg(state, 0xd1);
+		dprintk("%s: SYS_DVBS status=%x.\n", __func__, lock);
+
+		if ((lock & 0x07) == 0x07) {
+			/*if((m88ds3103_readreg(state, 0x0d) & 0x07) == 0x07)*/
+				*status = FE_HAS_SIGNAL | FE_HAS_CARRIER
+				| FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+		}
+		break;
+	case SYS_DVBS2:
+		lock = m88ds3103_readreg(state, 0x0d);
+		dprintk("%s: SYS_DVBS2 status=%x.\n", __func__, lock);
+
+		if ((lock & 0x8f) == 0x8f)
+			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER
+				| FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int m88ds3103_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	u8 tmp1, tmp2, tmp3;
+	u32 ldpc_frame_cnt, pre_err_packags, code_rate_fac = 0;
+
+	dprintk("%s()\n", __func__);
+
+	switch (state->delivery_system) {
+	case SYS_DVBS:
+		m88ds3103_writereg(state, 0xf9, 0x04);
+		tmp3 = m88ds3103_readreg(state, 0xf8);
+		if ((tmp3 & 0x10) == 0) {
+			tmp1 = m88ds3103_readreg(state, 0xf7);
+			tmp2 = m88ds3103_readreg(state, 0xf6);
+			tmp3 |= 0x10;
+			m88ds3103_writereg(state, 0xf8, tmp3);
+			state->preBer = (tmp1 << 8) | tmp2;
+		}
+		break;
+	case SYS_DVBS2:
+		tmp1 = m88ds3103_readreg(state, 0x7e) & 0x0f;
+		switch (tmp1) {
+		case 0:
+			code_rate_fac = 16008 - 80;
+			break;
+		case 1:
+			code_rate_fac = 21408 - 80;
+			break;
+		case 2:
+			code_rate_fac = 25728 - 80;
+			break;
+		case 3:
+			code_rate_fac = 32208 - 80;
+			break;
+		case 4:
+			code_rate_fac = 38688 - 80;
+			break;
+		case 5:
+			code_rate_fac = 43040 - 80;
+			break;
+		case 6:
+			code_rate_fac = 48408 - 80;
+			break;
+		case 7:
+			code_rate_fac = 51648 - 80;
+			break;
+		case 8:
+			code_rate_fac = 53840 - 80;
+			break;
+		case 9:
+			code_rate_fac = 57472 - 80;
+			break;
+		case 10:
+			code_rate_fac = 58192 - 80;
+			break;
+		}
+
+		tmp1 = m88ds3103_readreg(state, 0xd7) & 0xff;
+		tmp2 = m88ds3103_readreg(state, 0xd6) & 0xff;
+		tmp3 = m88ds3103_readreg(state, 0xd5) & 0xff;
+		ldpc_frame_cnt = (tmp1 << 16) | (tmp2 << 8) | tmp3;
+
+		tmp1 = m88ds3103_readreg(state, 0xf8) & 0xff;
+		tmp2 = m88ds3103_readreg(state, 0xf7) & 0xff;
+		pre_err_packags = tmp1<<8 | tmp2;
+		if (ldpc_frame_cnt > 1000) {
+			m88ds3103_writereg(state, 0xd1, 0x01);
+			m88ds3103_writereg(state, 0xf9, 0x01);
+			m88ds3103_writereg(state, 0xf9, 0x00);
+			m88ds3103_writereg(state, 0xd1, 0x00);
+			state->preBer = pre_err_packags;
+		}
+		break;
+	default:
+		break;
+	}
+	*ber = state->preBer;
+
+	return 0;
+}
+
+static int m88ds3103_read_signal_strength(struct dvb_frontend *fe,
+						u16 *signal_strength)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	u16 gain = 1000;
+
+	dprintk("%s()\n", __func__);
+
+	if (state->config->tuner_get_rfgain)
+		state->config->tuner_get_rfgain(fe, &gain);
+
+	*signal_strength = 60000 - gain*55;
+
+	return 0;
+}
+
+
+static int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *p_snr)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	u8 val, npow1, npow2, spow1, cnt;
+	u16 tmp, snr;
+	u32 npow, spow, snr_total;
+	static const u16 mes_log10[] = {
+		0,	3010,	4771,	6021,	6990,	7781,	8451,	9031,
+		9542,	10000,	10414,	10792,	11139,	11461,	11761,	12041,
+		12304,	12553,	12788,	13010,	13222,	13424,	13617,	13802,
+		13979,	14150,	14314,	14472,	14624,	14771,	14914,	15052,
+		15185,	15315,	15441,	15563,	15682,	15798,	15911,	16021,
+		16128,	16232,	16335,	16435,	16532,	16628,	16721,	16812,
+		16902,	16990,	17076,	17160,	17243,	17324,	17404,	17482,
+		17559,	17634,	17709,	17782,	17853,	17924,	17993,	18062,
+		18129,	18195,	18261,	18325,	18388,	18451,	18513,	18573,
+		18633,	18692,	18751,	18808,	18865,	18921,	18976,	19031
+	};
+	static const u16 mes_loge[] = {
+		0,	6931,	10986,	13863,	16094,	17918,	19459,	20794,
+		21972,	23026,	23979,	24849,	25649,	26391,	27081,	27726,
+		28332,	28904,	29444,	29957,	30445,	30910,	31355,	31781,
+		32189,	32581,	32958,	33322,	33673,	34012,	34340,	34657,
+	};
+
+	dprintk("%s()\n", __func__);
+
+	snr = 0;
+
+	switch (state->delivery_system) {
+	case SYS_DVBS:
+		cnt = 10; snr_total = 0;
+		while (cnt > 0) {
+			val = m88ds3103_readreg(state, 0xff);
+			snr_total += val;
+			cnt--;
+		}
+		tmp = (u16)(snr_total/80);
+		if (tmp > 0) {
+			if (tmp > 32)
+				tmp = 32;
+			snr = (mes_loge[tmp - 1] * 100) / 45;
+		} else {
+			snr = 0;
+		}
+		break;
+	case SYS_DVBS2:
+		cnt  = 10; npow = 0; spow = 0;
+		while (cnt > 0) {
+			npow1 = m88ds3103_readreg(state, 0x8c) & 0xff;
+			npow2 = m88ds3103_readreg(state, 0x8d) & 0xff;
+			npow += (((npow1 & 0x3f) + (u16)(npow2 << 6)) >> 2);
+
+			spow1 = m88ds3103_readreg(state, 0x8e) & 0xff;
+			spow += ((spow1 * spow1) >> 1);
+			cnt--;
+		}
+		npow /= 10; spow /= 10;
+		if (spow == 0) {
+			snr = 0;
+		} else if (npow == 0) {
+			snr = 19;
+		} else {
+			if (spow > npow) {
+				tmp = (u16)(spow / npow);
+				if (tmp > 80)
+					tmp = 80;
+				snr = mes_log10[tmp - 1]*3;
+			} else {
+				tmp = (u16)(npow / spow);
+				if (tmp > 80)
+					tmp = 80;
+				snr = -(mes_log10[tmp - 1] / 1000);
+			}
+		}
+		break;
+	default:
+		break;
+	}
+	*p_snr = snr;
+
+	return 0;
+}
+
+
+static int m88ds3103_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	u8 tmp1, tmp2, tmp3, data;
+
+	dprintk("%s()\n", __func__);
+
+	switch (state->delivery_system) {
+	case SYS_DVBS:
+		data = m88ds3103_readreg(state, 0xf8);
+		data |= 0x40;
+		m88ds3103_writereg(state, 0xf8, data);
+		tmp1 = m88ds3103_readreg(state, 0xf5);
+		tmp2 = m88ds3103_readreg(state, 0xf4);
+		*ucblocks = (tmp1 << 8) | tmp2;
+		data &= ~0x20;
+		m88ds3103_writereg(state, 0xf8, data);
+		data |= 0x20;
+		m88ds3103_writereg(state, 0xf8, data);
+		data &= ~0x40;
+		m88ds3103_writereg(state, 0xf8, data);
+		break;
+	case SYS_DVBS2:
+		tmp1 = m88ds3103_readreg(state, 0xda);
+		tmp2 = m88ds3103_readreg(state, 0xd9);
+		tmp3 = m88ds3103_readreg(state, 0xd8);
+		*ucblocks = (tmp1 << 16)|(tmp2 << 8)|tmp3;
+		data = m88ds3103_readreg(state, 0xd1);
+		data |= 0x01;
+		m88ds3103_writereg(state, 0xd1, data);
+		data &= ~0x01;
+		m88ds3103_writereg(state, 0xd1, data);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int m88ds3103_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	u8 data_a1, data_a2;
+
+	dprintk("%s(%d)\n", __func__, tone);
+	if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
+		printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
+		return -EINVAL;
+	}
+
+	data_a1 = m88ds3103_readreg(state, 0xa1);
+	data_a2 = m88ds3103_readreg(state, 0xa2);
+	if (state->demod_id == DS3103_ID)
+		data_a2 &= 0xdf; /* Normal mode */
+	switch (tone) {
+	case SEC_TONE_ON:
+		dprintk("%s: SEC_TONE_ON\n", __func__);
+		data_a1 |= 0x04;
+		data_a1 &= ~0x03;
+		data_a1 &= ~0x40;
+		data_a2 &= ~0xc0;
+		break;
+	case SEC_TONE_OFF:
+		dprintk("%s: SEC_TONE_OFF\n", __func__);
+		data_a2 &= ~0xc0;
+		data_a2 |= 0x80;
+		break;
+	}
+	m88ds3103_writereg(state, 0xa2, data_a2);
+	m88ds3103_writereg(state, 0xa1, data_a1);
+	return 0;
+}
+
+static int m88ds3103_send_diseqc_msg(struct dvb_frontend *fe,
+				struct dvb_diseqc_master_cmd *d)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	int i, ret = 0;
+	u8 tmp, time_out;
+
+	/* Dump DiSEqC message */
+	if (debug) {
+		printk(KERN_INFO "m88ds3103: %s(", __func__);
+		for (i = 0 ; i < d->msg_len ;) {
+			printk(KERN_INFO "0x%02x", d->msg[i]);
+			if (++i < d->msg_len)
+				printk(KERN_INFO ", ");
+		}
+	}
+
+	tmp = m88ds3103_readreg(state, 0xa2);
+	tmp &= ~0xc0;
+	if (state->demod_id == DS3103_ID)
+		tmp &= ~0x20;
+	m88ds3103_writereg(state, 0xa2, tmp);
+
+	for (i = 0; i < d->msg_len; i++)
+		m88ds3103_writereg(state, (0xa3+i), d->msg[i]);
+
+	tmp = m88ds3103_readreg(state, 0xa1);
+	tmp &= ~0x38;
+	tmp &= ~0x40;
+	tmp |= ((d->msg_len-1) << 3) | 0x07;
+	tmp &= ~0x80;
+	m88ds3103_writereg(state, 0xa1, tmp);
+	/*	1.5 * 9 * 8	= 108ms	*/
+	time_out = 150;
+	while (time_out > 0) {
+		msleep(10);
+		time_out -= 10;
+		tmp = m88ds3103_readreg(state, 0xa1);
+		if ((tmp & 0x40) == 0)
+			break;
+	}
+	if (time_out == 0) {
+		tmp = m88ds3103_readreg(state, 0xa1);
+		tmp &= ~0x80;
+		tmp |= 0x40;
+		m88ds3103_writereg(state, 0xa1, tmp);
+		ret = 1;
+	}
+	tmp = m88ds3103_readreg(state, 0xa2);
+	tmp &= ~0xc0;
+	tmp |= 0x80;
+	m88ds3103_writereg(state, 0xa2, tmp);
+	return ret;
+}
+
+
+static int m88ds3103_diseqc_send_burst(struct dvb_frontend *fe,
+					fe_sec_mini_cmd_t burst)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	u8	val, time_out;
+
+	dprintk("%s()\n", __func__);
+
+	val = m88ds3103_readreg(state, 0xa2);
+	val &= ~0xc0;
+	if (state->demod_id == DS3103_ID)
+		val &= 0xdf; /* Normal mode */
+	m88ds3103_writereg(state, 0xa2, val);
+	/* DiSEqC burst */
+	if (burst == SEC_MINI_B)
+		m88ds3103_writereg(state, 0xa1, 0x01);
+	else
+		m88ds3103_writereg(state, 0xa1, 0x02);
+
+	msleep(13);
+
+	time_out = 5;
+	do {
+		val = m88ds3103_readreg(state, 0xa1);
+		if ((val & 0x40) == 0)
+			break;
+		msleep(1);
+		time_out--;
+	} while (time_out > 0);
+
+	val = m88ds3103_readreg(state, 0xa2);
+	val &= ~0xc0;
+	val |= 0x80;
+	m88ds3103_writereg(state, 0xa2, val);
+
+	return 0;
+}
+
+static void m88ds3103_release(struct dvb_frontend *fe)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+
+	dprintk("%s\n", __func__);
+	kfree(state);
+}
+
+static int m88ds3103_check_id(struct m88ds3103_state *state)
+{
+	int val_01;
+
+	/*check demod id*/
+	val_01 = m88ds3103_readreg(state, 0x01);
+	printk(KERN_INFO "m88ds3103 chip version: %x found\n", val_01);
+
+	if (val_01 == 0xD0)
+		state->demod_id = DS3103_ID;
+	else if (val_01 == 0xC0)
+		state->demod_id = DS3000_ID;
+	else
+		state->demod_id = UNKNOW_ID;
+
+	return state->demod_id;
+}
+
+static int m88ds3103_set_carrier_offset(struct dvb_frontend *fe,
+					s32 carrier_offset_khz)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	s32 tmp;
+
+	tmp = carrier_offset_khz;
+	tmp *= 65536;
+	tmp = (2*tmp + MT_FE_MCLK_KHZ) / (2*MT_FE_MCLK_KHZ);
+
+	if (tmp < 0)
+		tmp += 65536;
+
+	m88ds3103_writereg(state, 0x5f, tmp >> 8);
+	m88ds3103_writereg(state, 0x5e, tmp & 0xff);
+
+	return 0;
+}
+
+static int m88ds3103_set_symrate(struct dvb_frontend *fe)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u16 value;
+
+	value = (((c->symbol_rate / 1000) << 15)
+		+ (MT_FE_MCLK_KHZ / 4)) / (MT_FE_MCLK_KHZ / 2);
+	m88ds3103_writereg(state, 0x61, value & 0x00ff);
+	m88ds3103_writereg(state, 0x62, (value & 0xff00) >> 8);
+
+	return 0;
+}
+
+static int m88ds3103_set_CCI(struct dvb_frontend *fe)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	u8 tmp;
+
+	tmp = m88ds3103_readreg(state, 0x56);
+	tmp &= ~0x01;
+	m88ds3103_writereg(state, 0x56, tmp);
+
+	tmp = m88ds3103_readreg(state, 0x76);
+	tmp &= ~0x80;
+	m88ds3103_writereg(state, 0x76, tmp);
+
+	return 0;
+}
+
+static int m88ds3103_init_reg(struct m88ds3103_state *state,
+				const u8 *p_reg_tab,
+				u32 size)
+{
+	u32 i;
+
+	for (i = 0; i < size; i += 2)
+		m88ds3103_writereg(state, p_reg_tab[i], p_reg_tab[i+1]);
+
+	return 0;
+}
+
+static int m88ds3103_demod_connect(struct dvb_frontend *fe,
+					s32 carrier_offset_khz)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	u16 value;
+	u8 val1, val2, data;
+
+	dprintk("connect delivery system = %d\n", state->delivery_system);
+
+	/* ds3000 global reset */
+	m88ds3103_writereg(state, 0x07, 0x80);
+	m88ds3103_writereg(state, 0x07, 0x00);
+	/* ds3000 build-in uC reset */
+	m88ds3103_writereg(state, 0xb2, 0x01);
+	/* ds3000 software reset */
+	m88ds3103_writereg(state, 0x00, 0x01);
+
+	switch (state->delivery_system) {
+	case SYS_DVBS:
+		/* initialise the demod in DVB-S mode */
+		if (state->demod_id == DS3000_ID) {
+			m88ds3103_init_reg(state, ds3000_dvbs_init_tab,
+						sizeof(ds3000_dvbs_init_tab));
+
+			value = m88ds3103_readreg(state, 0xfe);
+			value &= 0xc0;
+			value |= 0x1b;
+			m88ds3103_writereg(state, 0xfe, value);
+
+			if (state->config->ci_mode)
+				val1 = 0x80;
+			else if (state->config->ts_mode)
+				val1 = 0x60;
+			else
+				val1 = 0x20;
+			m88ds3103_writereg(state, 0xfd, val1);
+
+		} else if (state->demod_id == DS3103_ID) {
+			m88ds3103_init_reg(state, ds3103_dvbs_init_tab,
+						sizeof(ds3103_dvbs_init_tab));
+
+			/* set ts clock */
+			if (state->config->ts_mode == 0) {
+				val1 = 3; val2 = 3;
+			} else {
+				val1 = 0; val2 = 0;
+			}
+			val1 -= 1; val2 -= 1;
+			val1 &= 0x3f; val2 &= 0x3f;
+			data = m88ds3103_readreg(state, 0xfe);
+			data &= 0xf0;
+			data |= (val2 >> 2) & 0x0f;
+			m88ds3103_writereg(state, 0xfe, data);
+			data = (val2 & 0x03) << 6;
+			data |= val1;
+			m88ds3103_writereg(state, 0xea, data);
+
+			m88ds3103_writereg(state, 0x4d,
+					0xfd & m88ds3103_readreg(state, 0x4d));
+			m88ds3103_writereg(state, 0x30,
+					0xef & m88ds3103_readreg(state, 0x30));
+
+			/* set master clock */
+			val1 = m88ds3103_readreg(state, 0x22);
+			val2 = m88ds3103_readreg(state, 0x24);
+			val1 &= 0x3f;
+			val2 &= 0x3f;
+			val1 |= 0x80;
+			val2 |= 0x40;
+
+			m88ds3103_writereg(state, 0x22, val1);
+			m88ds3103_writereg(state, 0x24, val2);
+
+			if (state->config->ci_mode)
+				val1 = 0x03;
+			else if (state->config->ts_mode)
+				val1 = 0x06;
+			else
+				val1 = 0x42;
+			m88ds3103_writereg(state, 0xfd, val1);
+		}
+		break;
+	case SYS_DVBS2:
+		/* initialise the demod in DVB-S2 mode */
+		if (state->demod_id == DS3000_ID) {
+			m88ds3103_init_reg(state, ds3000_dvbs2_init_tab,
+					sizeof(ds3000_dvbs2_init_tab));
+
+			if (c->symbol_rate >= 30000000)
+				m88ds3103_writereg(state, 0xfe, 0x54);
+			else
+				m88ds3103_writereg(state, 0xfe, 0x98);
+
+		} else if (state->demod_id == DS3103_ID) {
+			m88ds3103_init_reg(state, ds3103_dvbs2_init_tab,
+					sizeof(ds3103_dvbs2_init_tab));
+
+			/* set ts clock */
+			if (state->config->ts_mode == 0) {
+				val1 = 5; val2 = 4;
+			} else {
+				val1 = 0; val2 = 0;
+			}
+			val1 -= 1; val2 -= 1;
+			val1 &= 0x3f; val2 &= 0x3f;
+			data = m88ds3103_readreg(state, 0xfe);
+			data &= 0xf0;
+			data |= (val2 >> 2) & 0x0f;
+			m88ds3103_writereg(state, 0xfe, data);
+			data = (val2 & 0x03) << 6;
+			data |= val1;
+			m88ds3103_writereg(state, 0xea, data);
+
+			m88ds3103_writereg(state, 0x4d,
+					0xfd & m88ds3103_readreg(state, 0x4d));
+			m88ds3103_writereg(state, 0x30,
+					0xef & m88ds3103_readreg(state, 0x30));
+
+			/* set master clock */
+			val1 = m88ds3103_readreg(state, 0x22);
+			val2 = m88ds3103_readreg(state, 0x24);
+			val1 &= 0x3f;
+			val2 &= 0x3f;
+			if (state->config->ts_mode == 1) {
+				val1 |= 0x80;
+				val2 |= 0x40;
+			} else {
+				if (c->symbol_rate >= 28000000) {
+					val1 |= 0xc0;
+				} else if (c->symbol_rate >= 18000000) {
+					val2 |= 0x40;
+				} else {
+					val1 |= 0x80;
+					val2 |= 0x40;
+				}
+			}
+			m88ds3103_writereg(state, 0x22, val1);
+			m88ds3103_writereg(state, 0x24, val2);
+		}
+
+		if (state->config->ci_mode)
+			val1 = 0x03;
+		else if (state->config->ts_mode)
+			val1 = 0x06;
+		else
+			val1 = 0x42;
+		m88ds3103_writereg(state, 0xfd, val1);
+
+		break;
+	default:
+		return 1;
+	}
+	/* disable 27MHz clock output */
+	m88ds3103_writereg(state, 0x29, 0x80);
+	/* enable ac coupling */
+	m88ds3103_writereg(state, 0x25, 0x8a);
+
+	if ((c->symbol_rate / 1000) <= 3000) {
+		/* 8 * 32 * 100 / 64 = 400*/
+		m88ds3103_writereg(state, 0xc3, 0x08);
+		m88ds3103_writereg(state, 0xc8, 0x20);
+		 /* 8 * 0 * 100 / 128 = 0*/
+		m88ds3103_writereg(state, 0xc4, 0x08);
+		m88ds3103_writereg(state, 0xc7, 0x00);
+	} else if ((c->symbol_rate / 1000) <= 10000) {
+		/* 8 * 16 * 100 / 64 = 200*/
+		m88ds3103_writereg(state, 0xc3, 0x08);
+		m88ds3103_writereg(state, 0xc8, 0x10);
+		/* 8 * 0 * 100 / 128 = 0*/
+		m88ds3103_writereg(state, 0xc4, 0x08);
+		m88ds3103_writereg(state, 0xc7, 0x00);
+	} else {
+		/* 8 * 6 * 100 / 64 = 75*/
+		m88ds3103_writereg(state, 0xc3, 0x08);
+		m88ds3103_writereg(state, 0xc8, 0x06);
+		 /* 8 * 0 * 100 / 128 = 0*/
+		m88ds3103_writereg(state, 0xc4, 0x08);
+		m88ds3103_writereg(state, 0xc7, 0x00);
+	}
+
+	m88ds3103_set_symrate(fe);
+	m88ds3103_set_CCI(fe);
+	m88ds3103_set_carrier_offset(fe, carrier_offset_khz);
+
+	/* ds3000 out of software reset */
+	m88ds3103_writereg(state, 0x00, 0x00);
+	/* start ds3000 build-in uC */
+	m88ds3103_writereg(state, 0xb2, 0x00);
+
+	return 0;
+}
+
+static int m88ds3103_set_frontend(struct dvb_frontend *fe)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+	int i;
+	fe_status_t status;
+	s32 offset_khz;
+
+	dprintk("%s() ", __func__);
+	dprintk("c frequency = %d\n", c->frequency);
+	dprintk("symbol rate = %d\n", c->symbol_rate);
+	dprintk("delivery system = %d\n", c->delivery_system);
+
+	if (state->config->set_ts_params)
+		state->config->set_ts_params(fe, 0);
+
+	if (state->config->tuner_set_frequency)
+		state->config->tuner_set_frequency(fe, &offset_khz);
+
+	m88ds3103_demod_connect(fe, offset_khz);
+
+	for (i = 0; i < 30 ; i++) {
+		m88ds3103_read_status(fe, &status);
+		if (status & FE_HAS_LOCK)
+			break;
+		msleep(20);
+	}
+
+	if ((status & FE_HAS_LOCK) == 0) {
+		state->delivery_system = (state->delivery_system == SYS_DVBS)
+						? SYS_DVBS2 : SYS_DVBS;
+		m88ds3103_demod_connect(fe, offset_khz);
+
+		for (i = 0; i < 30 ; i++) {
+			m88ds3103_read_status(fe, &status);
+			if (status & FE_HAS_LOCK)
+				break;
+			msleep(20);
+		}
+	}
+
+	if (status & FE_HAS_LOCK) {
+		if (state->config->start_ctrl) {
+			if (state->first_lock == 0) {
+				state->config->start_ctrl(fe);
+				state->first_lock = 1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int m88ds3103_tune(struct dvb_frontend *fe,
+			bool re_tune,
+			unsigned int mode_flags,
+			unsigned int *delay,
+			fe_status_t *status)
+{
+	*delay = HZ / 5;
+
+	dprintk("%s() ", __func__);
+	dprintk("re_tune = %d\n", re_tune);
+
+	if (re_tune) {
+		int ret = m88ds3103_set_frontend(fe);
+		if (ret)
+			return ret;
+	}
+
+	return m88ds3103_read_status(fe, status);
+}
+
+static enum dvbfe_algo m88ds3103_get_algo(struct dvb_frontend *fe)
+{
+	return DVBFE_ALGO_HW;
+}
+
+ /*
+ * Power config will reset and load initial firmware if required
+ */
+static int m88ds3103_initilaze(struct dvb_frontend *fe)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+	int ret;
+
+	dprintk("%s()\n", __func__);
+	/* hard reset */
+	m88ds3103_writereg(state, 0x07, 0x80);
+	m88ds3103_writereg(state, 0x07, 0x00);
+	msleep(1);
+
+	m88ds3103_writereg(state, 0x08, 0x01 | m88ds3103_readreg(state, 0x08));
+	msleep(1);
+
+	if (state->config->tuner_init)
+		state->config->tuner_init(fe);
+
+	if (state->demod_id == DS3103_ID) {
+		m88ds3103_writereg(state, 0x07, 0xe0);
+		m88ds3103_writereg(state, 0x07, 0x00);
+		msleep(1);
+	}
+	m88ds3103_writereg(state, 0xb2, 0x01);
+
+	/* Load the firmware if required */
+	ret = m88ds3103_load_firmware(fe);
+	if (ret != 0) {
+		printk(KERN_ERR "%s: Unable initialize firmware\n", __func__);
+		return ret;
+	}
+	if (state->demod_id == DS3103_ID) {
+		m88ds3103_writereg(state, 0x4d,
+					0xfd & m88ds3103_readreg(state, 0x4d));
+		m88ds3103_writereg(state, 0x30,
+					0xef & m88ds3103_readreg(state, 0x30));
+	}
+
+	return 0;
+}
+
+/*
+ * Initialise or wake up device
+ */
+static int m88ds3103_initfe(struct dvb_frontend *fe)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+
+	dprintk("%s()\n", __func__);
+
+	/* 1st step to wake up demod */
+	m88ds3103_writereg(state, 0x08, 0x01 | m88ds3103_readreg(state, 0x08));
+	m88ds3103_writereg(state, 0x04, 0xfe & m88ds3103_readreg(state, 0x04));
+	m88ds3103_writereg(state, 0x23, 0xef & m88ds3103_readreg(state, 0x23));
+	/* 2nd step to wake up tuner */
+	if (state->config->tuner_wakeup)
+		state->config->tuner_wakeup(fe);
+
+	return 0;
+}
+
+/* Put device to sleep */
+static int m88ds3103_sleep(struct dvb_frontend *fe)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+
+	dprintk("%s()\n", __func__);
+
+	/* 1st step to sleep tuner */
+	if (state->config->tuner_sleep)
+		state->config->tuner_sleep(fe);
+
+	/* 2nd step to sleep demod */
+	m88ds3103_writereg(state, 0x08, 0xfe & m88ds3103_readreg(state, 0x08));
+	m88ds3103_writereg(state, 0x04, 0x01 | m88ds3103_readreg(state, 0x04));
+	m88ds3103_writereg(state, 0x23, 0x10 | m88ds3103_readreg(state, 0x23));
+	return 0;
+
+}
+
+/* i2c gate control */
+static int m88ds3103_i2c_gate(struct dvb_frontend *fe, int enable)
+{
+	struct m88ds3103_state *state = fe->demodulator_priv;
+
+	m88ds3103_writereg(state, 0x03, 0x11);
+
+	return 0;
+}
+
+static struct dvb_frontend_ops m88ds3103_ops = {
+	.delsys = { SYS_DVBS, SYS_DVBS2},
+	.info = {
+		.name = "Montage M88DS3103",
+		.frequency_min = 950000,
+		.frequency_max = 2150000,
+		.frequency_stepsize = 1011, /* kHz for QPSK frontends */
+		.frequency_tolerance = 5000,
+		.symbol_rate_min = 1000000,
+		.symbol_rate_max = 45000000,
+		.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+			FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_2G_MODULATION |
+			FE_CAN_QPSK | FE_CAN_RECOVER
+	},
+
+	.release = m88ds3103_release,
+
+	.init = m88ds3103_initfe,
+	.sleep = m88ds3103_sleep,
+	.read_status = m88ds3103_read_status,
+	.read_ber = m88ds3103_read_ber,
+	.read_signal_strength = m88ds3103_read_signal_strength,
+	.read_snr = m88ds3103_read_snr,
+	.read_ucblocks = m88ds3103_read_ucblocks,
+	.set_tone = m88ds3103_set_tone,
+	.set_voltage = m88ds3103_set_voltage,
+	.diseqc_send_master_cmd = m88ds3103_send_diseqc_msg,
+	.diseqc_send_burst = m88ds3103_diseqc_send_burst,
+	.get_frontend_algo = m88ds3103_get_algo,
+	.tune = m88ds3103_tune,
+	.set_frontend = m88ds3103_set_frontend,
+	.i2c_gate_ctrl = m88ds3103_i2c_gate,
+};
+
+struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *config,
+				    struct i2c_adapter *i2c)
+{
+	struct m88ds3103_state *state = NULL;
+
+	dprintk("%s\n", __func__);
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct m88ds3103_state), GFP_KERNEL);
+	if (state == NULL) {
+		printk(KERN_ERR "Unable to kmalloc\n");
+		goto error2;
+	}
+
+	state->config = config;
+	state->i2c = i2c;
+	state->preBer = 0xffff;
+	state->delivery_system = SYS_DVBS; /*Default to DVB-S.*/
+
+	/* check demod id */
+	if (m88ds3103_check_id(state) == UNKNOW_ID) {
+		printk(KERN_ERR "Unable to find Montage demod chip\n");
+		goto error3;
+	}
+
+	memcpy(&state->frontend.ops, &m88ds3103_ops,
+			sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	m88ds3103_initilaze(&state->frontend);
+
+	return &state->frontend;
+
+error3:
+	kfree(state);
+error2:
+	return NULL;
+}
+EXPORT_SYMBOL(m88ds3103_attach);
+
+MODULE_DESCRIPTION("DVB demod module for Montage M88DS3103");
+MODULE_AUTHOR("Max nibble");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/m88ds3103.h b/drivers/media/dvb/frontends/m88ds3103.h
new file mode 100644
index 0000000..ba6e637
--- /dev/null
+++ b/drivers/media/dvb/frontends/m88ds3103.h
@@ -0,0 +1,67 @@
+/*
+    Montage Technology M88DS3103/3000 - DVBS/S2 Satellite demod driver
+
+    Copyright (C) 2011 Max nibble<nibble.max@gmail.com>
+    Copyright (C) 2010 Montage Technology<www.montage-tech.com>
+    Fix some bug and add M88DS3103 code, M88DS3000 code based on DS3000.c.
+
+    Copyright (C) 2009 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
+
+    Copyright (C) 2009 TurboSight.com
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+#ifndef _M88DS3103_H
+#define _M88DS3103_H
+
+#include <linux/dvb/frontend.h>
+
+struct m88ds3103_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+	u8 ci_mode;
+	u8 pin_ctrl;
+	u8 ts_mode; /* 0: Parallel, 1: Serial */
+	/* Set device param to start dma */
+	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
+	/* Start to transfer data */
+	int (*start_ctrl)(struct dvb_frontend *fe);
+	/* Set LNB voltage */
+	int (*set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
+	/* tuner control */
+	int (*tuner_init) (struct dvb_frontend *fe);
+	int (*tuner_sleep) (struct dvb_frontend *fe);
+	int (*tuner_wakeup) (struct dvb_frontend *fe);
+	int (*tuner_set_frequency) (struct dvb_frontend *fe, s32 *pfreqOffset);
+	int (*tuner_get_rfgain) (struct dvb_frontend *fe, u16 *prfgain);
+};
+
+#if defined(CONFIG_DVB_M88DS3103) || \
+	(defined(CONFIG_DVB_M88DS3103_MODULE) && defined(MODULE))
+extern struct dvb_frontend *m88ds3103_attach(
+		const struct m88ds3103_config *config,
+		struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *m88ds3103_attach(
+		const struct m88ds3103_config *config,
+		struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_M88DS3103 */
+#endif /* M88DS3103_H */
diff --git a/drivers/media/dvb/frontends/m88ds3103_priv.h b/drivers/media/dvb/frontends/m88ds3103_priv.h
new file mode 100644
index 0000000..416a0a5
--- /dev/null
+++ b/drivers/media/dvb/frontends/m88ds3103_priv.h
@@ -0,0 +1,413 @@
+/*
+    Montage Technology M88DS3103/3000 - DVBS/S2 Satellite demod driver
+
+    Copyright (C) 2011 Max nibble<nibble.max@gmail.com>
+    Copyright (C) 2010 Montage Technology<www.montage-tech.com>
+    Fix some bug and add M88DS3103 code, M88DS3000 code based on DS3000.c.
+
+    Copyright (C) 2009 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
+
+    Copyright (C) 2009 TurboSight.com
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _M88DS3103_PRIV_H
+#define _M88DS3103_PRIV_H
+
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(KERN_INFO "m88ds3103: " args); \
+	} while (0)
+
+#define FW_DOWN_SIZE 32
+#define FW_DOWN_LOOP (8192/FW_DOWN_SIZE)
+#define DS3103_DEFAULT_FIRMWARE "dvb-fe-ds3103.fw"
+#define DS3000_DEFAULT_FIRMWARE "dvb-fe-ds300x.fw"
+#define MT_FE_MCLK_KHZ 96000 /* in kHz */
+#define MT_FE_CRYSTAL_KHZ   27000 /* in kHz */
+#define FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz 3000
+#define DS3000_ID	0x3000
+#define DS3103_ID	0x3103
+#define UNKNOW_ID	0x0000
+
+/* For M88DS3103 demod dvbs mode.*/
+static u8 ds3103_dvbs_init_tab[] = {
+	0x23, 0x07,
+	0x08, 0x03,
+	0x0c, 0x02,
+	0x21, 0x54,
+	0x25, 0x82,
+	0x27, 0x31,
+	0x30, 0x08,
+	0x31, 0x40,
+	0x32, 0x32,
+	0x33, 0x35,
+	0x35, 0xff,
+	0x3a, 0x00,
+	0x37, 0x10,
+	0x38, 0x10,
+	0x39, 0x02,
+	0x42, 0x60,
+	0x4a, 0x80,
+	0x4b, 0x04,
+	0x4d, 0x91,
+	0x5d, 0xc8,
+	0x50, 0x36,
+	0x51, 0x36,
+	0x52, 0x36,
+	0x53, 0x36,
+	0x63, 0x0f,
+	0x64, 0x30,
+	0x65, 0x40,
+	0x68, 0x26,
+	0x69, 0x4c,
+	0x70, 0x20,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x40,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x60,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x80,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0xa0,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x1f,
+	0x76, 0x38,
+	0x77, 0xa6,
+	0x78, 0x0c,
+	0x79, 0x80,
+	0x7f, 0x14,
+	0x7c, 0x00,
+	0xae, 0x82,
+	0x80, 0x64,
+	0x81, 0x66,
+	0x82, 0x44,
+	0x85, 0x04,
+	0xcd, 0xf4,
+	0x90, 0x33,
+	0xa0, 0x44,
+	0xc0, 0x08,
+	0xc3, 0x10,
+	0xc4, 0x08,
+	0xc5, 0xf0,
+	0xc6, 0xff,
+	0xc7, 0x00,
+	0xc8, 0x1a,
+	0xc9, 0x80,
+	0xe0, 0xf8,
+	0xe6, 0x8b,
+	0xd0, 0x40,
+	0xf8, 0x20,
+	0xfa, 0x0f,
+	0x00, 0x00,
+	0xbd, 0x01,
+	0xb8, 0x00,
+};
+/* For M88DS3103 demod dvbs2 mode.*/
+static u8 ds3103_dvbs2_init_tab[] = {
+	0x23, 0x07,
+	0x08, 0x07,
+	0x0c, 0x02,
+	0x21, 0x54,
+	0x25, 0x82,
+	0x27, 0x31,
+	0x30, 0x08,
+	0x32, 0x32,
+	0x33, 0x35,
+	0x35, 0xff,
+	0x3a, 0x00,
+	0x37, 0x10,
+	0x38, 0x10,
+	0x39, 0x02,
+	0x42, 0x60,
+	0x4a, 0x80,
+	0x4b, 0x04,
+	0x4d, 0x91,
+	0x5d, 0xc8,
+	0x50, 0x36,
+	0x51, 0x36,
+	0x52, 0x36,
+	0x53, 0x36,
+	0x63, 0x0f,
+	0x64, 0x10,
+	0x65, 0x20,
+	0x68, 0x46,
+	0x69, 0xcd,
+	0x70, 0x20,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x40,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x60,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x80,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0xa0,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x1f,
+	0x76, 0x38,
+	0x77, 0xa6,
+	0x78, 0x0c,
+	0x79, 0x80,
+	0x7f, 0x14,
+	0x85, 0x08,
+	0xcd, 0xf4,
+	0x90, 0x33,
+	0x86, 0x00,
+	0x87, 0x0f,
+	0x89, 0x00,
+	0x8b, 0x44,
+	0x8c, 0x66,
+	0x9d, 0xc1,
+	0x8a, 0x10,
+	0xad, 0x40,
+	0xa0, 0x44,
+	0xc0, 0x08,
+	0xc1, 0x10,
+	0xc2, 0x08,
+	0xc3, 0x10,
+	0xc4, 0x08,
+	0xc5, 0xf0,
+	0xc6, 0xff,
+	0xc7, 0x00,
+	0xc8, 0x1a,
+	0xc9, 0x80,
+	0xca, 0x23,
+	0xcb, 0x24,
+	0xcc, 0xf4,
+	0xce, 0x74,
+	0x00, 0x00,
+	0xbd, 0x01,
+	0xb8, 0x00,
+};
+
+/* For M88DS3000 demod dvbs mode.*/
+static u8 ds3000_dvbs_init_tab[] = {
+	0x23, 0x05,
+	0x08, 0x03,
+	0x0c, 0x02,
+	0x21, 0x54,
+	0x25, 0x82,
+	0x27, 0x31,
+	0x30, 0x08,
+	0x31, 0x40,
+	0x32, 0x32,
+	0x33, 0x35,
+	0x35, 0xff,
+	0x3a, 0x00,
+	0x37, 0x10,
+	0x38, 0x10,
+	0x39, 0x02,
+	0x42, 0x60,
+	0x4a, 0x40,
+	0x4b, 0x04,
+	0x4d, 0x91,
+	0x5d, 0xc8,
+	0x50, 0x77,
+	0x51, 0x77,
+	0x52, 0x36,
+	0x53, 0x36,
+	0x56, 0x01,
+	0x63, 0x47,
+	0x64, 0x30,
+	0x65, 0x40,
+	0x68, 0x26,
+	0x69, 0x4c,
+	0x70, 0x20,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x40,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x60,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x80,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0xa0,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x1f,
+	0x76, 0x00,
+	0x77, 0xd1,
+	0x78, 0x0c,
+	0x79, 0x80,
+	0x7f, 0x04,
+	0x7c, 0x00,
+	0x80, 0x86,
+	0x81, 0xa6,
+	0x85, 0x04,
+	0xcd, 0xf4,
+	0x90, 0x33,
+	0xa0, 0x44,
+	0xc0, 0x18,
+	0xc3, 0x10,
+	0xc4, 0x08,
+	0xc5, 0x80,
+	0xc6, 0x80,
+	0xc7, 0x0a,
+	0xc8, 0x1a,
+	0xc9, 0x80,
+	0xfe, 0xb6,
+	0xe0, 0xf8,
+	0xe6, 0x8b,
+	0xd0, 0x40,
+	0xf8, 0x20,
+	0xfa, 0x0f,
+	0xad, 0x20,
+	0xae, 0x07,
+	0xb8, 0x00,
+};
+
+/* For M88DS3000 demod dvbs2 mode.*/
+static u8 ds3000_dvbs2_init_tab[] = {
+	0x23, 0x0f,
+	0x08, 0x07,
+	0x0c, 0x02,
+	0x21, 0x54,
+	0x25, 0x82,
+	0x27, 0x31,
+	0x30, 0x08,
+	0x31, 0x32,
+	0x32, 0x32,
+	0x33, 0x35,
+	0x35, 0xff,
+	0x3a, 0x00,
+	0x37, 0x10,
+	0x38, 0x10,
+	0x39, 0x02,
+	0x42, 0x60,
+	0x4a, 0x80,
+	0x4b, 0x04,
+	0x4d, 0x91,
+	0x5d, 0x88,
+	0x50, 0x36,
+	0x51, 0x36,
+	0x52, 0x36,
+	0x53, 0x36,
+	0x63, 0x60,
+	0x64, 0x10,
+	0x65, 0x10,
+	0x68, 0x04,
+	0x69, 0x29,
+	0x70, 0x20,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x40,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x60,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x80,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0xa0,
+	0x71, 0x70,
+	0x72, 0x04,
+	0x73, 0x00,
+	0x70, 0x1f,
+	0xa0, 0x44,
+	0xc0, 0x08,
+	0xc1, 0x10,
+	0xc2, 0x08,
+	0xc3, 0x10,
+	0xc4, 0x08,
+	0xc5, 0xf0,
+	0xc6, 0xf0,
+	0xc7, 0x0a,
+	0xc8, 0x1a,
+	0xc9, 0x80,
+	0xca, 0x23,
+	0xcb, 0x24,
+	0xce, 0x74,
+	0x56, 0x01,
+	0x90, 0x03,
+	0x76, 0x80,
+	0x77, 0x42,
+	0x78, 0x0a,
+	0x79, 0x80,
+	0xad, 0x40,
+	0xae, 0x07,
+	0x7f, 0xd4,
+	0x7c, 0x00,
+	0x80, 0xa8,
+	0x81, 0xda,
+	0x7c, 0x01,
+	0x80, 0xda,
+	0x81, 0xec,
+	0x7c, 0x02,
+	0x80, 0xca,
+	0x81, 0xeb,
+	0x7c, 0x03,
+	0x80, 0xba,
+	0x81, 0xdb,
+	0x85, 0x08,
+	0x86, 0x00,
+	0x87, 0x02,
+	0x89, 0x80,
+	0x8b, 0x44,
+	0x8c, 0xaa,
+	0x8a, 0x10,
+	0xba, 0x00,
+	0xf5, 0x04,
+	0xd2, 0x32,
+	0xb8, 0x00,
+};
+
+struct m88ds3103_state {
+	struct i2c_adapter *i2c;
+	const struct m88ds3103_config *config;
+	struct dvb_frontend frontend;
+	u32 preBer;
+	u8 skip_fw_load;
+	u8 first_lock; /* The first time of signal lock */
+	u16 demod_id; /* demod chip type */
+	fe_delivery_system_t delivery_system;
+};
+
+#endif /* _M88DS3103_PRIV_H */
+
diff --git a/drivers/media/dvb/frontends/m88ts202x.c b/drivers/media/dvb/frontends/m88ts202x.c
new file mode 100644
index 0000000..6528dbc
--- /dev/null
+++ b/drivers/media/dvb/frontends/m88ts202x.c
@@ -0,0 +1,590 @@
+/*
+    Montage Technology M88TS2022/2020 - DVBS/S2 Satellite tuner driver
+
+    Copyright (C) 2011 Max nibble<nibble.max@gmail.com>
+    Copyright (C) 2010 Montage Technology<www.montage-tech.com>
+    Fix some bug and add M88TS2022 code, M88TS2020 code based on DS3000.c.
+
+    Copyright (C) 2009 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
+
+    Copyright (C) 2009 TurboSight.com
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+
+#include "dvb_frontend.h"
+#include "m88ts202x.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates debugging (default:0)");
+
+#define dprintk(args...) \
+	do { \
+		if (debug) \
+			printk(KERN_INFO "m88ts202x: " args); \
+	} while (0)
+
+#define MT_FE_CRYSTAL_KHZ   27000 /* in kHz */
+#define FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz 3000
+#define TS2020_ID	0x2020
+#define TS2022_ID	0x2022
+#define UNKNOW_ID	0x0000
+
+struct m88ts202x_state {
+	struct i2c_adapter *i2c;
+	const struct m88ts202x_config *config;
+	struct dvb_frontend *frontend;
+	struct m88ts202x_devctl	*devctl;
+	u16 tuner_id; /* tuner chip type */
+};
+
+/*register operations.*/
+static int m88ts202x_writereg(struct m88ts202x_state *state, int reg, int data)
+{
+	struct dvb_frontend *fe = state->frontend;
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = { .addr = 0x60,
+		.flags = 0, .buf = buf, .len = 2 };
+	int err;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	err = i2c_transfer(state->i2c, &msg, 1);
+
+	if (err != 1) {
+		printk("%s: writereg error(err == %i, reg == 0x%02x,"
+			 " value == 0x%02x)\n", __func__, err, reg, data);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int m88ts202x_readreg(struct m88ts202x_state *state, u8 reg)
+{
+	int ret;
+	struct dvb_frontend *fe = state->frontend;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{ .addr = 0x60, .flags = 0,
+			.buf = b0, .len = 1 },
+		{ .addr = 0x60, .flags = I2C_M_RD,
+			.buf = b1, .len = 1 }
+	};
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) {
+		printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);
+		return ret;
+	}
+
+	return b1[0];
+}
+
+static int m88ts202x_check_id(struct m88ts202x_state *state)
+{
+	int val_00;
+
+	/*check tuner id*/
+	val_00 = m88ts202x_readreg(state, 0x00);
+	printk(KERN_INFO "TS202x chip version[1]: %x found\n", val_00);
+	val_00 &= 0x03;
+	if (val_00 == 0) {
+		m88ts202x_writereg(state, 0x00, 0x01);
+		msleep(3);
+	}
+	m88ts202x_writereg(state, 0x00, 0x03);
+	msleep(5);
+	val_00 = m88ts202x_readreg(state, 0x00);
+	printk(KERN_INFO "TS202x chip version[2]: %x found\n", val_00);
+	val_00 &= 0xff;
+	if ((val_00 == 0x01) || (val_00 == 0x41) || (val_00 == 0x81))
+		state->tuner_id = TS2020_ID;
+	else if (((val_00 & 0xc0) == 0xc0) || (val_00 == 0x83))
+		state->tuner_id = TS2022_ID;
+	else
+		state->tuner_id = UNKNOW_ID;
+
+	return state->tuner_id;
+}
+
+/* wake up */
+static int m88ts202x_wakeup(struct dvb_frontend *fe)
+{
+	struct m88ts202x_state *state = fe->tuner_priv;
+	u8 val;
+
+	dprintk("%s()\n", __func__);
+
+	/*wake up tuner */
+	val = m88ts202x_readreg(state, 0x00) & 0xff;
+	if ((val & 0x01) == 0) {
+		m88ts202x_writereg(state, 0x00, 0x01);
+		msleep(50);
+	}
+	m88ts202x_writereg(state, 0x00, 0x03);
+	msleep(50);
+	return 0;
+}
+
+/*
+ * Initialise device
+ */
+static int m88ts202x_init(struct dvb_frontend *fe)
+{
+	struct m88ts202x_state *state = fe->tuner_priv;
+
+	dprintk("%s()\n", __func__);
+
+	if (state->tuner_id == TS2020_ID) {
+		/* TS2020 init */
+		m88ts202x_writereg(state, 0x42, 0x73);
+		msleep(2);
+		m88ts202x_writereg(state, 0x05, 0x01);
+		m88ts202x_writereg(state, 0x62, 0xb5);
+		m88ts202x_writereg(state, 0x07, 0x02);
+		m88ts202x_writereg(state, 0x08, 0x01);
+	} else if (state->tuner_id == TS2022_ID) {
+		/* TS2022 init */
+		m88ts202x_writereg(state, 0x62, 0x6c);
+		msleep(2);
+		m88ts202x_writereg(state, 0x42, 0x6c);
+		msleep(2);
+		m88ts202x_writereg(state, 0x7d, 0x9d);
+		m88ts202x_writereg(state, 0x7c, 0x9a);
+		m88ts202x_writereg(state, 0x7a, 0x76);
+
+		m88ts202x_writereg(state, 0x3b, 0x01);
+		m88ts202x_writereg(state, 0x63, 0x88);
+
+		m88ts202x_writereg(state, 0x61, 0x85);
+		m88ts202x_writereg(state, 0x22, 0x30);
+		m88ts202x_writereg(state, 0x30, 0x40);
+		m88ts202x_writereg(state, 0x20, 0x23);
+		m88ts202x_writereg(state, 0x24, 0x02);
+		m88ts202x_writereg(state, 0x12, 0xa0);
+	}
+	return 0;
+}
+
+static int m88ts202x_get_rfgain(struct dvb_frontend *fe, u16 *prfgain)
+{
+	struct m88ts202x_state *state = fe->tuner_priv;
+	u16 gain;
+	u8 gain1, gain2, gain3 = 0;
+
+	dprintk("%s()\n", __func__);
+
+	gain1 = m88ts202x_readreg(state, 0x3d) & 0x1f;
+	dprintk("%s: gain1 = 0x%02x\n", __func__, gain1);
+
+	if (gain1 > 15)
+		gain1 = 15;
+	gain2 = m88ts202x_readreg(state, 0x21) & 0x1f;
+	dprintk("%s: gain2 = 0x%02x\n", __func__, gain2);
+
+	if (state->tuner_id == TS2022_ID) {
+		gain3 = (m88ts202x_readreg(state, 0x66)>>3) & 0x07;
+		dprintk("%s: gain3 = 0x%02x\n", __func__, gain3);
+
+		if (gain2 > 16)
+			gain2 = 16;
+		if (gain2 < 2)
+			gain2 = 2;
+		if (gain3 > 6)
+			gain3 = 6;
+	} else {
+		if (gain2 > 13)
+			gain2 = 13;
+		gain3 = 0;
+	}
+
+	gain = gain1*23 + gain2*35 + gain3*29;
+	if (prfgain)
+		*prfgain = gain;
+
+	return 0;
+}
+
+
+static int m88ts202x_set_frequency(struct dvb_frontend *fe, s32 *pfreqOffset)
+{
+	struct m88ts202x_state *state = fe->tuner_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+	u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf, div4, capCode, changePLL;
+	s32 offset_khz, lpf_offset_KHz;
+	u16 value, ndiv, lpf_coeff;
+	u32 f3db, gdiv28, realFreq;
+	u8 RFgain;
+
+	dprintk("%s() frequency=%d\n", __func__, c->frequency);
+
+	realFreq = c->frequency;
+	lpf_offset_KHz = 0;
+	if (c->symbol_rate < 5000000) {
+		lpf_offset_KHz = FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz;
+		realFreq += FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz;
+	}
+
+	div4 = 0;
+	RFgain = 0;
+	if (state->tuner_id == TS2022_ID) {
+		m88ts202x_writereg(state, 0x10, 0x0a);
+		m88ts202x_writereg(state, 0x11, 0x40);
+		if (realFreq < 1103000) {
+			m88ts202x_writereg(state, 0x10, 0x1b);
+			div4 = 1;
+			ndiv = (realFreq * (6 + 8) * 4)
+				/MT_FE_CRYSTAL_KHZ;
+		} else {
+			ndiv = (realFreq * (6 + 8) * 2)
+				/MT_FE_CRYSTAL_KHZ;
+		}
+		ndiv = ndiv + ndiv%2;
+		if (ndiv < 4095)
+			ndiv = ndiv - 1024;
+		else if (ndiv < 6143)
+			ndiv = ndiv + 1024;
+		else
+			ndiv = ndiv + 3072;
+
+		m88ts202x_writereg(state, 0x01,
+					(ndiv & 0x3f00) >> 8);
+
+	} else {
+		m88ts202x_writereg(state, 0x10, 0x00);
+		if (realFreq < 1146000) {
+			m88ts202x_writereg(state, 0x10, 0x11);
+			div4 = 1;
+			ndiv = (realFreq * (6 + 8) * 4) / MT_FE_CRYSTAL_KHZ;
+		} else {
+			m88ts202x_writereg(state, 0x10, 0x01);
+			ndiv = (realFreq * (6 + 8) * 2) / MT_FE_CRYSTAL_KHZ;
+		}
+		ndiv = ndiv + ndiv%2;
+		ndiv = ndiv - 1024;
+		m88ts202x_writereg(state, 0x01, (ndiv>>8)&0x0f);
+	}
+	/* set pll */
+	m88ts202x_writereg(state, 0x02, ndiv & 0x00ff);
+	m88ts202x_writereg(state, 0x03, 0x06);
+	m88ts202x_writereg(state, 0x51, 0x0f);
+	m88ts202x_writereg(state, 0x51, 0x1f);
+	m88ts202x_writereg(state, 0x50, 0x10);
+	m88ts202x_writereg(state, 0x50, 0x00);
+
+	if (state->tuner_id == TS2022_ID) {
+		if ((realFreq >= 1650000) && (realFreq <= 1850000)) {
+			msleep(5);
+			value = m88ts202x_readreg(state, 0x14);
+			value &= 0x7f;
+			if (value < 64) {
+				m88ts202x_writereg(state, 0x10, 0x82);
+				m88ts202x_writereg(state, 0x11, 0x6f);
+
+				m88ts202x_writereg(state, 0x51, 0x0f);
+				m88ts202x_writereg(state, 0x51, 0x1f);
+				m88ts202x_writereg(state, 0x50, 0x10);
+				m88ts202x_writereg(state, 0x50, 0x00);
+			}
+		}
+		msleep(5);
+		value = m88ts202x_readreg(state, 0x14);
+		value &= 0x1f;
+
+		if (value > 19) {
+			value = m88ts202x_readreg(state, 0x10);
+			value &= 0x1d;
+			m88ts202x_writereg(state, 0x10, value);
+		}
+	} else {
+		msleep(5);
+		value = m88ts202x_readreg(state, 0x66);
+		changePLL = (((value & 0x80) >> 7) != div4);
+
+		if (changePLL) {
+			m88ts202x_writereg(state, 0x10, 0x11);
+			div4 = 1;
+			ndiv = (realFreq * (6 + 8) * 4)/MT_FE_CRYSTAL_KHZ;
+			ndiv = ndiv + ndiv%2;
+			ndiv = ndiv - 1024;
+
+			m88ts202x_writereg(state, 0x01, (ndiv>>8) & 0x0f);
+			m88ts202x_writereg(state, 0x02, ndiv & 0xff);
+			m88ts202x_writereg(state, 0x51, 0x0f);
+			m88ts202x_writereg(state, 0x51, 0x1f);
+			m88ts202x_writereg(state, 0x50, 0x10);
+			m88ts202x_writereg(state, 0x50, 0x00);
+		}
+	}
+	/*set the RF gain*/
+	if (state->tuner_id == TS2020_ID)
+		m88ts202x_writereg(state, 0x60, 0x79);
+
+	m88ts202x_writereg(state, 0x51, 0x17);
+	m88ts202x_writereg(state, 0x51, 0x1f);
+	m88ts202x_writereg(state, 0x50, 0x08);
+	m88ts202x_writereg(state, 0x50, 0x00);
+	msleep(5);
+
+	if (state->tuner_id == TS2020_ID) {
+		RFgain = m88ts202x_readreg(state, 0x3d);
+		RFgain &= 0x0f;
+		if (RFgain < 15) {
+			if (RFgain < 4)
+				RFgain = 0;
+			else
+				RFgain = RFgain - 3;
+			value = ((RFgain << 3) | 0x01) & 0x79;
+			m88ts202x_writereg(state, 0x60, value);
+			m88ts202x_writereg(state, 0x51, 0x17);
+			m88ts202x_writereg(state, 0x51, 0x1f);
+			m88ts202x_writereg(state, 0x50, 0x08);
+			m88ts202x_writereg(state, 0x50, 0x00);
+		}
+	}
+	/* set the LPF */
+	if (state->tuner_id == TS2022_ID) {
+		m88ts202x_writereg(state, 0x25, 0x00);
+		m88ts202x_writereg(state, 0x27, 0x70);
+		m88ts202x_writereg(state, 0x41, 0x09);
+		m88ts202x_writereg(state, 0x08, 0x0b);
+	}
+
+	f3db = ((c->symbol_rate / 1000) * 135) / 200 + 2000;
+	f3db += lpf_offset_KHz;
+	if (f3db < 7000)
+		f3db = 7000;
+	if (f3db > 40000)
+		f3db = 40000;
+
+	gdiv28 = (MT_FE_CRYSTAL_KHZ / 1000 * 1694 + 500) / 1000;
+	m88ts202x_writereg(state, 0x04, gdiv28 & 0xff);
+	m88ts202x_writereg(state, 0x51, 0x1b);
+	m88ts202x_writereg(state, 0x51, 0x1f);
+	m88ts202x_writereg(state, 0x50, 0x04);
+	m88ts202x_writereg(state, 0x50, 0x00);
+	msleep(5);
+
+	value = m88ts202x_readreg(state, 0x26);
+	capCode = value & 0x3f;
+	if (state->tuner_id == TS2022_ID) {
+		m88ts202x_writereg(state, 0x41, 0x0d);
+
+		m88ts202x_writereg(state, 0x51, 0x1b);
+		m88ts202x_writereg(state, 0x51, 0x1f);
+		m88ts202x_writereg(state, 0x50, 0x04);
+		m88ts202x_writereg(state, 0x50, 0x00);
+
+		msleep(2);
+
+		value = m88ts202x_readreg(state, 0x26);
+		value &= 0x3f;
+		value = (capCode + value) / 2;
+	} else
+		value = capCode;
+
+	gdiv28 = gdiv28 * 207 / (value * 2 + 151);
+	mlpf_max = gdiv28 * 135 / 100;
+	mlpf_min = gdiv28 * 78 / 100;
+	if (mlpf_max > 63)
+		mlpf_max = 63;
+
+	if (state->tuner_id == TS2022_ID)
+		lpf_coeff = 3200;
+	else
+		lpf_coeff = 2766;
+
+	nlpf = (f3db * gdiv28 * 2 / lpf_coeff
+		/ (MT_FE_CRYSTAL_KHZ / 1000)  + 1) / 2 ;
+	if (nlpf > 23)
+		nlpf = 23;
+	if (nlpf < 1)
+		nlpf = 1;
+
+	lpf_mxdiv = (nlpf * (MT_FE_CRYSTAL_KHZ / 1000)
+			* lpf_coeff * 2 / f3db + 1) / 2;
+
+	if (lpf_mxdiv < mlpf_min) {
+		nlpf++;
+		lpf_mxdiv = (nlpf * (MT_FE_CRYSTAL_KHZ / 1000)
+				* lpf_coeff * 2  / f3db + 1) / 2;
+	}
+
+	if (lpf_mxdiv > mlpf_max)
+		lpf_mxdiv = mlpf_max;
+
+	m88ts202x_writereg(state, 0x04, lpf_mxdiv);
+	m88ts202x_writereg(state, 0x06, nlpf);
+	m88ts202x_writereg(state, 0x51, 0x1b);
+	m88ts202x_writereg(state, 0x51, 0x1f);
+	m88ts202x_writereg(state, 0x50, 0x04);
+	m88ts202x_writereg(state, 0x50, 0x00);
+	msleep(5);
+
+	if (state->tuner_id == TS2022_ID) {
+		msleep(2);
+		value = m88ts202x_readreg(state, 0x26);
+		capCode = value & 0x3f;
+
+		m88ts202x_writereg(state, 0x41, 0x09);
+
+		m88ts202x_writereg(state, 0x51, 0x1b);
+		m88ts202x_writereg(state, 0x51, 0x1f);
+		m88ts202x_writereg(state, 0x50, 0x04);
+		m88ts202x_writereg(state, 0x50, 0x00);
+
+		msleep(2);
+		value = m88ts202x_readreg(state, 0x26);
+		value &= 0x3f;
+		value = (capCode + value) / 2;
+
+		value = value | 0x80;
+		m88ts202x_writereg(state, 0x25, value);
+		m88ts202x_writereg(state, 0x27, 0x30);
+
+		m88ts202x_writereg(state, 0x08, 0x09);
+	}
+
+	/* Set the BB gain */
+	m88ts202x_writereg(state, 0x51, 0x1e);
+	m88ts202x_writereg(state, 0x51, 0x1f);
+	m88ts202x_writereg(state, 0x50, 0x01);
+	m88ts202x_writereg(state, 0x50, 0x00);
+	if (state->tuner_id == TS2020_ID) {
+		if (RFgain == 15) {
+			msleep(40);
+			value = m88ts202x_readreg(state, 0x21);
+			value &= 0x0f;
+			if (value < 3) {
+				m88ts202x_writereg(state, 0x60, 0x61);
+				m88ts202x_writereg(state, 0x51, 0x17);
+				m88ts202x_writereg(state, 0x51, 0x1f);
+				m88ts202x_writereg(state, 0x50, 0x08);
+				m88ts202x_writereg(state, 0x50, 0x00);
+			}
+		}
+	}
+	msleep(60);
+
+	offset_khz = (ndiv - ndiv % 2 + 1024) * MT_FE_CRYSTAL_KHZ
+			/ (6 + 8) / (div4 + 1) / 2 - realFreq;
+
+	*pfreqOffset = offset_khz + lpf_offset_KHz;
+
+	return 0;
+}
+
+/* Put device to sleep */
+static int m88ts202x_sleep(struct dvb_frontend *fe)
+{
+	struct m88ts202x_state *state = fe->tuner_priv;
+
+	dprintk("%s()\n", __func__);
+
+	m88ts202x_writereg(state, 0x00, 0x00);
+
+	return 0;
+}
+
+static int m88ts202x_release(struct dvb_frontend *fe)
+{
+	struct m88ts202x_state *priv = fe->tuner_priv;
+	dprintk("%s()\n", __func__);
+
+	kfree(priv);
+	fe->tuner_priv = NULL;
+
+	return 0;
+}
+static struct m88ts202x_devctl m88ts202x_ctl = {
+	.tuner_init		= m88ts202x_init,
+	.tuner_sleep		= m88ts202x_sleep,
+	.tuner_wakeup		= m88ts202x_wakeup,
+	.tuner_set_frequency	= m88ts202x_set_frequency,
+	.tuner_get_rfgain	= m88ts202x_get_rfgain,
+};
+
+static const struct dvb_tuner_ops m88ts202x_tuner_ops = {
+	.info = {
+		.name           = "Montage M88TS202x",
+		.frequency_min  = 950000,
+		.frequency_max  = 2150000,
+		.frequency_step = 50000,
+	},
+
+	.release	   = m88ts202x_release,
+};
+
+struct m88ts202x_devctl *m88ts202x_attach(struct dvb_frontend *fe,
+					const struct m88ts202x_config *config,
+				      struct i2c_adapter *i2c)
+{
+	struct m88ts202x_state *state = NULL;
+
+	dprintk("%s\n", __func__);
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct m88ts202x_state), GFP_KERNEL);
+	if (state == NULL) {
+		printk(KERN_ERR "Unable to kmalloc\n");
+		goto error2;
+	}
+
+	state->config = config;
+	state->i2c = i2c;
+	state->frontend = fe;
+	state->devctl = &m88ts202x_ctl;
+
+	/* check chip id */
+	if (m88ts202x_check_id(state) == UNKNOW_ID) {
+		printk(KERN_ERR "Unable to find Montage tuner\n");
+		goto error3;
+	}
+
+	memcpy(&fe->ops.tuner_ops, &m88ts202x_tuner_ops,
+			sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = state;
+
+	m88ts202x_init(fe);
+
+	return state->devctl;
+
+error3:
+	kfree(state);
+error2:
+	return NULL;
+}
+EXPORT_SYMBOL(m88ts202x_attach);
+
+MODULE_DESCRIPTION("DVB tuner module for Montage TS2022");
+MODULE_AUTHOR("Max nibble");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/m88ts202x.h b/drivers/media/dvb/frontends/m88ts202x.h
new file mode 100644
index 0000000..f001a31
--- /dev/null
+++ b/drivers/media/dvb/frontends/m88ts202x.h
@@ -0,0 +1,63 @@
+/*
+    Montage Technology M88TS2022/2020 - DVBS/S2 Satellite tuner driver
+
+    Copyright (C) 2011 Max nibble<nibble.max@gmail.com>
+    Copyright (C) 2010 Montage Technology<www.montage-tech.com>
+    Fix some bug and add M88TS2022 code, M88TS2020 code based on DS3000.c.
+
+    Copyright (C) 2009 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
+
+    Copyright (C) 2009 TurboSight.com
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _M88TS202X_H
+#define _M88TS202X_H
+
+#include <linux/dvb/frontend.h>
+
+struct m88ts202x_config {
+	u8 bypasson; /* 1- Enable bypass loop out */
+	u8 clkout;  /* 1- Enable clk output */
+	u8 clkdiv; /* 0- Output 27MHz, 1-Output 13.5MHz */
+};
+
+struct m88ts202x_devctl {
+
+	int (*tuner_init) (struct dvb_frontend *fe);
+	int (*tuner_sleep) (struct dvb_frontend *fe);
+	int (*tuner_wakeup) (struct dvb_frontend *fe);
+	int (*tuner_set_frequency) (struct dvb_frontend *fe, s32 *pfreqOffset);
+	int (*tuner_get_rfgain) (struct dvb_frontend *fe, u16 *prfgain);
+};
+
+#if defined(CONFIG_DVB_M88TS202X) || \
+	(defined(CONFIG_DVB_M88TS202X_MODULE) && defined(MODULE))
+extern struct m88ts202x_devctl *m88ts202x_attach(
+	struct dvb_frontend *fe,
+	const struct m88ts202x_config *config,
+	struct i2c_adapter *i2c);
+#else
+static inline struct m88ts202x_devctl *m88ts202x_attach(
+	struct dvb_frontend *fe,
+	const struct m88ts202x_config *config,
+	struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_M88TS202X */
+#endif /* _M88TS202X_H */
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 2/6 v2] dvbsky, dvb-s/s2 usb box
  2012-04-26 13:24                 ` Mauro Carvalho Chehab
  2012-04-27  7:06                   ` [PATCH 1/6 v2] dvbsky, montage dvb-s/s2 TS202x tuner and M88DS3103 " nibble.max
@ 2012-04-27  7:06                   ` nibble.max
  2013-06-30  3:07                     ` Fwd: " P. van Gaans
  2012-04-27  7:06                   ` [PATCH 3/6 v2] dvbsky, dvb-s/s2 PCIe card nibble.max
                                     ` (3 subsequent siblings)
  5 siblings, 1 reply; 56+ messages in thread
From: nibble.max @ 2012-04-27  7:06 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Antti Palosaari, linux-media

Also fix some code sytle errors checked by checkpatch.pl.
---
 drivers/media/dvb/dvb-usb/Kconfig  |    2 +
 drivers/media/dvb/dvb-usb/dw2102.c |  337 ++++++++++++++++++++++++++++++++----
 2 files changed, 305 insertions(+), 34 deletions(-)

diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index be1db75..93c9381 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -279,6 +279,8 @@ config DVB_USB_DW2102
 	select DVB_STV0288 if !DVB_FE_CUSTOMISE
 	select DVB_STB6000 if !DVB_FE_CUSTOMISE
 	select DVB_CX24116 if !DVB_FE_CUSTOMISE
+	select DVB_M88TS202X if !DVB_FE_CUSTOMISE
+	select DVB_M88DS3103 if !DVB_FE_CUSTOMISE
 	select DVB_SI21XX if !DVB_FE_CUSTOMISE
 	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
 	select DVB_MT312 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c
index 451c5a7..1cf62fb 100644
--- a/drivers/media/dvb/dvb-usb/dw2102.c
+++ b/drivers/media/dvb/dvb-usb/dw2102.c
@@ -19,6 +19,8 @@
 #include "stb6000.h"
 #include "eds1547.h"
 #include "cx24116.h"
+#include "m88ts202x.h"
+#include "m88ds3103.h"
 #include "tda1002x.h"
 #include "mt312.h"
 #include "zl10039.h"
@@ -118,12 +120,12 @@ MODULE_PARM_DESC(demod, "demod to probe (1=cx24116 2=stv0903+stv6110 "
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
-			u16 index, u8 * data, u16 len, int flags)
+			u16 index, u8 *data, u16 len, int flags)
 {
 	int ret;
 	u8 *u8buf;
 	unsigned int pipe = (flags == DW210X_READ_MSG) ?
-				usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0);
+			usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0);
 	u8 request_type = (flags == DW210X_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
 
 	u8buf = kmalloc(len, GFP_KERNEL);
@@ -133,7 +135,8 @@ static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
 
 	if (flags == DW210X_WRITE_MSG)
 		memcpy(u8buf, data, len);
-	ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR,
+	ret = usb_control_msg(dev, pipe,
+				request, request_type | USB_TYPE_VENDOR,
 				value, index , u8buf, len, 2000);
 
 	if (flags == DW210X_READ_MSG)
@@ -179,7 +182,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 			break;
 		case 0x60:
 			if (msg[0].flags == 0) {
-			/* write to tuner pll */
+				/* write to tuner pll */
 				buf6[0] = 0x2c;
 				buf6[1] = 5;
 				buf6[2] = 0xc0;
@@ -190,7 +193,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 				ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
 						buf6, 7, DW210X_WRITE_MSG);
 			} else {
-			/* read from tuner */
+				/* read from tuner */
 				ret = dw210x_op_rw(d->udev, 0xb5, 0, 0,
 						buf6, 1, DW210X_READ_MSG);
 				msg[0].buf[0] = buf6[0];
@@ -273,7 +276,8 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
 	return num;
 }
 
-static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
+static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap,
+				struct i2c_msg msg[], int num)
 {
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
 	int ret = 0;
@@ -346,7 +350,8 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
 	return num;
 }
 
-static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
+static int dw2104_i2c_transfer(struct i2c_adapter *adap,
+				struct i2c_msg msg[], int num)
 {
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
 	int ret = 0;
@@ -712,7 +717,8 @@ static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
 	u8 eeprom[256], eepromline[16];
 
 	for (i = 0; i < 256; i++) {
-		if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2, DW210X_READ_MSG) < 0) {
+		if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2,
+		DW210X_READ_MSG) < 0) {
 			err("read eeprom failed.");
 			return -1;
 		} else {
@@ -882,6 +888,41 @@ static int s660_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 	return 0;
 }
 
+static int bstusb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+
+	struct dvb_usb_adapter *udev_adap =
+		(struct dvb_usb_adapter *)(fe->dvb->priv);
+
+	u8 obuf[3] = { 0xe, 0x80, 0 };
+	u8 ibuf[] = { 0 };
+
+	info("US6830: %s!\n", __func__);
+
+	if (voltage == SEC_VOLTAGE_OFF)
+		obuf[2] = 0;
+	else
+		obuf[2] = 1;
+
+	if (dvb_usb_generic_rw(udev_adap->dev, obuf, 3, ibuf, 1, 0) < 0)
+		err("command 0x0e transfer failed.");
+	return 0;
+}
+
+static int bstusb_restart(struct dvb_frontend *fe)
+{
+
+	struct dvb_usb_adapter *udev_adap =
+		(struct dvb_usb_adapter *)(fe->dvb->priv);
+
+	u8 obuf[3] = { 0x36, 3, 0 };
+	u8 ibuf[] = { 0 };
+
+	if (dvb_usb_generic_rw(udev_adap->dev, obuf, 3, ibuf, 1, 0) < 0)
+		err("command 0x36 transfer failed.");
+	return 0;
+}
+
 static void dw210x_led_ctrl(struct dvb_frontend *fe, int offon)
 {
 	static u8 led_off[] = { 0 };
@@ -987,12 +1028,37 @@ static struct ds3000_config su3000_ds3000_config = {
 	.ci_mode = 1,
 };
 
+static struct m88ts202x_config dvbsky_ts202x_config = {
+	.bypasson = 0,
+	.clkout = 0,
+	.clkdiv = 0,
+};
+
+static struct m88ds3103_config US6830_ds3103_config = {
+	.demod_address = 0x68,
+	.ci_mode = 1,
+	.pin_ctrl = 0x83,
+	.ts_mode = 0,
+	.start_ctrl = bstusb_restart,
+	.set_voltage = bstusb_set_voltage,
+};
+
+static struct m88ds3103_config US6832_ds3103_config = {
+	.demod_address = 0x68,
+	.ci_mode = 1,
+	.pin_ctrl = 0x80,
+	.ts_mode = 0,
+	.start_ctrl = bstusb_restart,
+	.set_voltage = bstusb_set_voltage,
+};
+
 static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
 {
 	struct dvb_tuner_ops *tuner_ops = NULL;
 
 	if (demod_probe & 4) {
-		d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config,
+		d->fe_adap[0].fe = dvb_attach(stv0900_attach,
+				&dw2104a_stv0900_config,
 				&d->dev->i2c_adap, 0);
 		if (d->fe_adap[0].fe != NULL) {
 			if (dvb_attach(stb6100_attach, d->fe_adap[0].fe,
@@ -1003,7 +1069,8 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
 				tuner_ops->get_frequency = stb6100_get_freq;
 				tuner_ops->set_bandwidth = stb6100_set_bandw;
 				tuner_ops->get_bandwidth = stb6100_get_bandw;
-				d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+				d->fe_adap[0].fe->ops.set_voltage =
+							dw210x_set_voltage;
 				info("Attached STV0900+STB6100!\n");
 				return 0;
 			}
@@ -1011,13 +1078,15 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
 	}
 
 	if (demod_probe & 2) {
-		d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config,
+		d->fe_adap[0].fe = dvb_attach(stv0900_attach,
+				&dw2104_stv0900_config,
 				&d->dev->i2c_adap, 0);
 		if (d->fe_adap[0].fe != NULL) {
 			if (dvb_attach(stv6110_attach, d->fe_adap[0].fe,
 					&dw2104_stv6110_config,
 					&d->dev->i2c_adap)) {
-				d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+				d->fe_adap[0].fe->ops.set_voltage =
+							dw210x_set_voltage;
 				info("Attached STV0900+STV6110A!\n");
 				return 0;
 			}
@@ -1053,7 +1122,8 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
 {
 	if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) {
 		/*dw2102_properties.adapter->tuner_attach = NULL;*/
-		d->fe_adap[0].fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config,
+		d->fe_adap[0].fe = dvb_attach(si21xx_attach,
+					&serit_sp1511lhb_config,
 					&d->dev->i2c_adap);
 		if (d->fe_adap[0].fe != NULL) {
 			d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
@@ -1068,7 +1138,8 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
 		if (d->fe_adap[0].fe != NULL) {
 			if (dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61,
 					&d->dev->i2c_adap)) {
-				d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+				d->fe_adap[0].fe->ops.set_voltage =
+							dw210x_set_voltage;
 				info("Attached stv0288!\n");
 				return 0;
 			}
@@ -1076,8 +1147,10 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
 	}
 
 	if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) {
-		/*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/
-		d->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194a_config,
+		/*dw2102_properties.adapter->tuner_attach =
+						dw2102_tuner_attach;*/
+		d->fe_adap[0].fe = dvb_attach(stv0299_attach,
+					&sharp_z0194a_config,
 					&d->dev->i2c_adap);
 		if (d->fe_adap[0].fe != NULL) {
 			d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
@@ -1125,7 +1198,8 @@ static int stv0288_frontend_attach(struct dvb_usb_adapter *d)
 	if (d->fe_adap[0].fe == NULL)
 		return -EIO;
 
-	if (NULL == dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61, &d->dev->i2c_adap))
+	if (NULL == dvb_attach(stb6000_attach, d->fe_adap[0].fe,
+				0x61, &d->dev->i2c_adap))
 		return -EIO;
 
 	d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
@@ -1213,6 +1287,63 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *d)
 
 	return 0;
 }
+static int dvbsky_usb_frontend_attach(struct dvb_usb_adapter *d,
+					struct m88ds3103_config *pdconf,
+					struct m88ts202x_config *ptconf)
+{
+	struct m88ts202x_devctl *ctrl;
+
+	u8 obuf[3] = { 0xe, 0x83, 0 };
+	u8 ibuf[] = { 0 };
+
+	info("dvbsky: %s!\n", __func__);
+	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+		err("command 0x0e transfer failed.");
+
+	obuf[0] = 0xe;
+	obuf[1] = 0x83;
+	obuf[2] = 1;
+
+	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+		err("command 0x0e transfer failed.");
+
+	obuf[0] = 0x51;
+
+	if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
+		err("command 0x51 transfer failed.");
+
+	d->fe_adap[0].fe = dvb_attach(m88ds3103_attach, pdconf,
+					&d->dev->i2c_adap);
+	if (d->fe_adap[0].fe == NULL)
+		return -EIO;
+	ctrl =	dvb_attach(m88ts202x_attach,
+				d->fe_adap[0].fe, ptconf, &d->dev->i2c_adap);
+	if (!ctrl) {
+		printk(KERN_ERR "No m88ts202x found!\n");
+		return -ENODEV;
+	}
+	pdconf->tuner_init = ctrl->tuner_init;
+	pdconf->tuner_sleep = ctrl->tuner_sleep;
+	pdconf->tuner_wakeup = ctrl->tuner_wakeup;
+	pdconf->tuner_set_frequency = ctrl->tuner_set_frequency;
+	pdconf->tuner_get_rfgain = ctrl->tuner_get_rfgain;
+	info("Attached M88DS3103!\n");
+	return 0;
+}
+
+static int US6830_frontend_attach(struct dvb_usb_adapter *d)
+{
+	return dvbsky_usb_frontend_attach(d,
+					&US6830_ds3103_config,
+					&dvbsky_ts202x_config);
+}
+
+static int US6832_frontend_attach(struct dvb_usb_adapter *d)
+{
+	return dvbsky_usb_frontend_attach(d,
+					&US6832_ds3103_config,
+					&dvbsky_ts202x_config);
+}
 
 static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
 {
@@ -1435,6 +1566,28 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 	return 0;
 }
 
+/* dvbsky remote control */
+static int dvbsky_rc_query(struct dvb_usb_device *d)
+{
+	unsigned code = 0;
+	u8 obuf[0x40], ibuf[0x40], toggle;
+
+	obuf[0] = 0x10;
+	if (dvb_usb_generic_rw(d, obuf, 1, ibuf, 2, 0) < 0)
+		err("rc transfer failed.");
+	code = (ibuf[0] << 8) | ibuf[1];
+	if (code != 0xffff) {
+		info("dvbsky rc code: %x", code);
+
+		toggle = (code & 0x800) ? 1 : 0;
+		code &= 0x3f;
+
+		rc_keydown(d->rc_dev, code, toggle);
+	}
+
+	return 0;
+}
+
 enum dw2102_table_entry {
 	CYPRESS_DW2102,
 	CYPRESS_DW2101,
@@ -1451,6 +1604,9 @@ enum dw2102_table_entry {
 	TEVII_S480_1,
 	TEVII_S480_2,
 	X3M_SPC1400HD,
+	BST_US6830HD,
+	BST_US6831HD,
+	BST_US6832HD,
 };
 
 static struct usb_device_id dw2102_table[] = {
@@ -1458,7 +1614,8 @@ static struct usb_device_id dw2102_table[] = {
 	[CYPRESS_DW2101] = {USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
 	[CYPRESS_DW2104] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)},
 	[TEVII_S650] = {USB_DEVICE(0x9022, USB_PID_TEVII_S650)},
-	[TERRATEC_CINERGY_S] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
+	[TERRATEC_CINERGY_S] = {USB_DEVICE(USB_VID_TERRATEC,
+				USB_PID_CINERGY_S)},
 	[CYPRESS_DW3101] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)},
 	[TEVII_S630] = {USB_DEVICE(0x9022, USB_PID_TEVII_S630)},
 	[PROF_1100] = {USB_DEVICE(0x3011, USB_PID_PROF_1100)},
@@ -1469,6 +1626,9 @@ static struct usb_device_id dw2102_table[] = {
 	[TEVII_S480_1] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)},
 	[TEVII_S480_2] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)},
 	[X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)},
+	[BST_US6830HD] = {USB_DEVICE(0x0572, 0x6830)},
+	[BST_US6831HD] = {USB_DEVICE(0x0572, 0x6831)},
+	[BST_US6832HD] = {USB_DEVICE(0x0572, 0x6832)},
 	{ }
 };
 
@@ -1529,7 +1689,8 @@ static int dw2102_load_firmware(struct usb_device *dev,
 		/* init registers */
 		switch (dev->descriptor.idProduct) {
 		case USB_PID_TEVII_S650:
-			dw2104_properties.rc.legacy.rc_map_table = rc_map_tevii_table;
+			dw2104_properties.rc.legacy.rc_map_table =
+							rc_map_tevii_table;
 			dw2104_properties.rc.legacy.rc_map_size =
 					ARRAY_SIZE(rc_map_tevii_table);
 		case USB_PID_DW2104:
@@ -1553,7 +1714,8 @@ static int dw2102_load_firmware(struct usb_device *dev,
 					DW210X_READ_MSG);
 			if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) {
 				dw2102_properties.i2c_algo = &dw2102_i2c_algo;
-				dw2102_properties.adapter->fe[0].tuner_attach = &dw2102_tuner_attach;
+				dw2102_properties.adapter->fe[0].tuner_attach =
+							&dw2102_tuner_attach;
 				break;
 			} else {
 				/* check STV0288 frontend  */
@@ -1565,7 +1727,8 @@ static int dw2102_load_firmware(struct usb_device *dev,
 				dw210x_op_rw(dev, 0xc3, 0xd1, 0, &reset16[0], 3,
 						DW210X_READ_MSG);
 				if (reset16[2] == 0x11) {
-					dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo;
+					dw2102_properties.i2c_algo =
+							&dw2102_earda_i2c_algo;
 					break;
 				}
 			}
@@ -1622,7 +1785,7 @@ static struct dvb_usb_device_properties dw2102_properties = {
 					}
 				}
 			},
-		}},
+		} },
 		}
 	},
 	.num_device_descs = 3,
@@ -1676,7 +1839,7 @@ static struct dvb_usb_device_properties dw2104_properties = {
 					}
 				}
 			},
-		}},
+		} },
 		}
 	},
 	.num_device_descs = 2,
@@ -1727,7 +1890,7 @@ static struct dvb_usb_device_properties dw3101_properties = {
 					}
 				}
 			},
-		}},
+		} },
 		}
 	},
 	.num_device_descs = 1,
@@ -1773,7 +1936,7 @@ static struct dvb_usb_device_properties s6x0_properties = {
 					}
 				}
 			},
-		}},
+		} },
 		}
 	},
 	.num_device_descs = 1,
@@ -1854,7 +2017,7 @@ static struct dvb_usb_device_properties su3000_properties = {
 					}
 				}
 			}
-		}},
+		} },
 		}
 	},
 	.num_device_descs = 3,
@@ -1874,6 +2037,108 @@ static struct dvb_usb_device_properties su3000_properties = {
 	}
 };
 
+static struct dvb_usb_device_properties US6830_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.size_of_priv = sizeof(struct su3000_state),
+	.power_ctrl = su3000_power_ctrl,
+	.num_adapters = 1,
+	.identify_state	= su3000_identify_state,
+	.i2c_algo = &su3000_i2c_algo,
+
+	.rc.core = {
+		.rc_interval      = 300,
+		.rc_codes         = RC_MAP_DVBSKY,
+		.module_name	  = "dvbskyir",
+		.rc_query         = dvbsky_rc_query,
+		.allowed_protos   = RC_TYPE_RC5,
+	},
+
+	.read_mac_address = su3000_read_mac_address,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = { {
+			.streaming_ctrl   = su3000_streaming_ctrl,
+			.frontend_attach  = US6830_frontend_attach,
+			.stream = {
+				.type = USB_BULK,
+				.count = 8,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			}
+		} },
+		}
+	},
+	.num_device_descs = 2,
+	.devices = {
+		{ "Bestunar US6830 HD",
+			{ &dw2102_table[BST_US6830HD], NULL },
+			{ NULL },
+		},
+		{ "Bestunar US6831 HD",
+			{ &dw2102_table[BST_US6831HD], NULL },
+			{ NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties US6832_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.size_of_priv = sizeof(struct su3000_state),
+	.power_ctrl = su3000_power_ctrl,
+	.num_adapters = 1,
+	.identify_state	= su3000_identify_state,
+	.i2c_algo = &su3000_i2c_algo,
+
+	.rc.core = {
+		.rc_interval      = 300,
+		.rc_codes         = RC_MAP_DVBSKY,
+		.module_name	  = "dvbskyir",
+		.rc_query         = dvbsky_rc_query,
+		.allowed_protos   = RC_TYPE_RC5,
+	},
+
+	.read_mac_address = su3000_read_mac_address,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = { {
+			.streaming_ctrl   = su3000_streaming_ctrl,
+			.frontend_attach  = US6832_frontend_attach,
+			.stream = {
+				.type = USB_BULK,
+				.count = 8,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			}
+		} },
+		}
+	},
+	.num_device_descs = 1,
+	.devices = {
+		{ "Bestunar US6832 HD",
+			{ &dw2102_table[BST_US6832HD], NULL },
+			{ NULL },
+		},
+	}
+};
+
 static int dw2102_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
@@ -1917,20 +2182,24 @@ static int dw2102_probe(struct usb_interface *intf,
 
 	if (0 == dvb_usb_device_init(intf, &dw2102_properties,
 			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &dw2104_properties,
+		0 == dvb_usb_device_init(intf, &dw2104_properties,
+			THIS_MODULE, NULL, adapter_nr) ||
+		0 == dvb_usb_device_init(intf, &dw3101_properties,
+			THIS_MODULE, NULL, adapter_nr) ||
+		0 == dvb_usb_device_init(intf, &s6x0_properties,
 			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &dw3101_properties,
+		0 == dvb_usb_device_init(intf, p1100,
 			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &s6x0_properties,
+		0 == dvb_usb_device_init(intf, s660,
 			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, p1100,
+		0 == dvb_usb_device_init(intf, p7500,
 			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, s660,
+		0 == dvb_usb_device_init(intf, &su3000_properties,
 			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, p7500,
+		0 == dvb_usb_device_init(intf, &US6830_properties,
 			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &su3000_properties,
-				     THIS_MODULE, NULL, adapter_nr))
+		0 == dvb_usb_device_init(intf, &US6832_properties,
+			THIS_MODULE, NULL, adapter_nr))
 		return 0;
 
 	return -ENODEV;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 3/6 v2] dvbsky, dvb-s/s2 PCIe card
  2012-04-26 13:24                 ` Mauro Carvalho Chehab
  2012-04-27  7:06                   ` [PATCH 1/6 v2] dvbsky, montage dvb-s/s2 TS202x tuner and M88DS3103 " nibble.max
  2012-04-27  7:06                   ` [PATCH 2/6 v2] dvbsky, dvb-s/s2 usb box nibble.max
@ 2012-04-27  7:06                   ` nibble.max
  2012-04-27  7:07                   ` [PATCH 4/6 v2] dvbsky, dvb-s/s2 PCI card nibble.max
                                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 56+ messages in thread
From: nibble.max @ 2012-04-27  7:06 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Antti Palosaari, linux-media

Also fix some code sytle errors checked by checkpatch.pl.
---
 drivers/media/video/cx23885/Kconfig         |    2 +
 drivers/media/video/cx23885/cx23885-cards.c |  106 +++++++++++++++++++++++++++
 drivers/media/video/cx23885/cx23885-dvb.c   |   90 ++++++++++++++++++++++-
 drivers/media/video/cx23885/cx23885-f300.c  |   51 +++++++++++++
 drivers/media/video/cx23885/cx23885-f300.h  |    6 ++
 drivers/media/video/cx23885/cx23885-input.c |   15 ++++
 drivers/media/video/cx23885/cx23885.h       |    6 +-
 7 files changed, 273 insertions(+), 3 deletions(-)

diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
index b391e9b..33325f4 100644
--- a/drivers/media/video/cx23885/Kconfig
+++ b/drivers/media/video/cx23885/Kconfig
@@ -20,6 +20,8 @@ config VIDEO_CX23885
 	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
 	select DVB_STV6110 if !DVB_FE_CUSTOMISE
 	select DVB_CX24116 if !DVB_FE_CUSTOMISE
+	select DVB_M88TS202X if !DVB_FE_CUSTOMISE
+	select DVB_M88DS3103 if !DVB_FE_CUSTOMISE
 	select DVB_STV0900 if !DVB_FE_CUSTOMISE
 	select DVB_DS3000 if !DVB_FE_CUSTOMISE
 	select DVB_STV0367 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index 19b5499..8f13990 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -497,7 +497,22 @@ struct cx23885_board cx23885_boards[] = {
 		.name		= "TerraTec Cinergy T PCIe Dual",
 		.portb		= CX23885_MPEG_DVB,
 		.portc		= CX23885_MPEG_DVB,
+	},
+
+	[CX23885_BOARD_BST_PS8512] = {
+		.name		= "Bestunar PS8512",
+		.portb		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_DVBSKY_S950] = {
+		.name		= "DVBSKY S950",
+		.portb		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_DVBSKY_S952] = {
+		.name		= "DVBSKY S952",
+		.portb		= CX23885_MPEG_DVB,
+		.portc		= CX23885_MPEG_DVB,
 	}
+
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -705,6 +720,18 @@ struct cx23885_subid cx23885_subids[] = {
 		.subvendor = 0x153b,
 		.subdevice = 0x117e,
 		.card      = CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL,
+	}, {
+		.subvendor = 0x14f1,
+		.subdevice = 0x8512,
+		.card      = CX23885_BOARD_BST_PS8512,
+	}, {
+		.subvendor = 0x4254,
+		.subdevice = 0x0950,
+		.card      = CX23885_BOARD_DVBSKY_S950,
+	}, {
+		.subvendor = 0x4254,
+		.subdevice = 0x0952,
+		.card      = CX23885_BOARD_DVBSKY_S952,
 	},
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -1216,9 +1243,55 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
 		/* enable irq */
 		cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/
 		break;
+	case CX23885_BOARD_DVBSKY_S950:
+	case CX23885_BOARD_BST_PS8512:
+		cx23885_gpio_enable(dev, GPIO_2, 1);
+		cx23885_gpio_clear(dev, GPIO_2);
+		msleep(100);
+		cx23885_gpio_set(dev, GPIO_2);
+		break;
+	case CX23885_BOARD_DVBSKY_S952:
+		cx_write(MC417_CTL, 0x00000037);/* enable GPIO3-18 pins */
+
+		cx23885_gpio_enable(dev, GPIO_2, 1);
+		cx23885_gpio_enable(dev, GPIO_11, 1);
+		cx23885_gpio_clear(dev, GPIO_2);
+		cx23885_gpio_clear(dev, GPIO_11);
+		msleep(100);
+		cx23885_gpio_set(dev, GPIO_2);
+		cx23885_gpio_set(dev, GPIO_11);
+		break;
 	}
 }
 
+static int cx23885_ir_patch(struct i2c_adapter *i2c, u8 reg, u8 mask)
+{
+	struct i2c_msg msgs[2];
+	u8 tx_buf[2], rx_buf[1];
+	/* Write register address */
+	tx_buf[0] = reg;
+	msgs[0].addr = 0x4c;
+	msgs[0].flags = 0;
+	msgs[0].len = 1;
+	msgs[0].buf = (char *) tx_buf;
+	/* Read data from register */
+	msgs[1].addr = 0x4c;
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].len = 1;
+	msgs[1].buf = (char *) rx_buf;
+
+	i2c_transfer(i2c, msgs, 2);
+
+	tx_buf[0] = reg;
+	tx_buf[1] = rx_buf[0] | mask;
+	msgs[0].addr = 0x4c;
+	msgs[0].flags = 0;
+	msgs[0].len = 2;
+	msgs[0].buf = (char *) tx_buf;
+
+	return i2c_transfer(i2c, msgs, 1);
+}
+
 int cx23885_ir_init(struct cx23885_dev *dev)
 {
 	static struct v4l2_subdev_io_pin_config ir_rxtx_pin_cfg[] = {
@@ -1301,6 +1374,20 @@ int cx23885_ir_init(struct cx23885_dev *dev)
 		v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
 				 ir_rx_pin_cfg_count, ir_rx_pin_cfg);
 		break;
+	case CX23885_BOARD_BST_PS8512:
+	case CX23885_BOARD_DVBSKY_S950:
+	case CX23885_BOARD_DVBSKY_S952:
+		dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE);
+		if (dev->sd_ir == NULL) {
+			ret = -ENODEV;
+			break;
+		}
+		v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
+				 ir_rx_pin_cfg_count, ir_rx_pin_cfg);
+
+		cx23885_ir_patch(&(dev->i2c_bus[2].i2c_adap), 0x1f, 0x80);
+		cx23885_ir_patch(&(dev->i2c_bus[2].i2c_adap), 0x23, 0x80);
+		break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
 		if (!enable_885_ir)
 			break;
@@ -1332,6 +1419,9 @@ void cx23885_ir_fini(struct cx23885_dev *dev)
 		break;
 	case CX23885_BOARD_TEVII_S470:
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+	case CX23885_BOARD_BST_PS8512:
+	case CX23885_BOARD_DVBSKY_S950:
+	case CX23885_BOARD_DVBSKY_S952:
 		cx23885_irq_remove(dev, PCI_MSK_AV_CORE);
 		/* sd_ir is a duplicate pointer to the AV Core, just clear it */
 		dev->sd_ir = NULL;
@@ -1375,6 +1465,9 @@ void cx23885_ir_pci_int_enable(struct cx23885_dev *dev)
 		break;
 	case CX23885_BOARD_TEVII_S470:
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+	case CX23885_BOARD_BST_PS8512:
+	case CX23885_BOARD_DVBSKY_S950:
+	case CX23885_BOARD_DVBSKY_S952:
 		if (dev->sd_ir)
 			cx23885_irq_add_enable(dev, PCI_MSK_AV_CORE);
 		break;
@@ -1459,6 +1552,8 @@ void cx23885_card_setup(struct cx23885_dev *dev)
 		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
 		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
 		break;
+	case CX23885_BOARD_BST_PS8512:
+	case CX23885_BOARD_DVBSKY_S950:
 	case CX23885_BOARD_TEVII_S470:
 	case CX23885_BOARD_DVBWORLD_2005:
 		ts1->gen_ctrl_val  = 0x5; /* Parallel */
@@ -1489,6 +1584,14 @@ void cx23885_card_setup(struct cx23885_dev *dev)
 		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
 		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
 		break;
+	case CX23885_BOARD_DVBSKY_S952:
+		ts1->gen_ctrl_val  = 0x5; /* Parallel */
+		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+		ts2->gen_ctrl_val  = 0xe; /* Serial bus + punctured clock */
+		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+		break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
 	case CX23885_BOARD_HAUPPAUGE_HVR1500:
 	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
@@ -1541,6 +1644,9 @@ void cx23885_card_setup(struct cx23885_dev *dev)
 	case CX23885_BOARD_MPX885:
 	case CX23885_BOARD_MYGICA_X8507:
 	case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
+	case CX23885_BOARD_BST_PS8512:
+	case CX23885_BOARD_DVBSKY_S950:
+	case CX23885_BOARD_DVBSKY_S952:
 		dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
 				&dev->i2c_bus[2].i2c_adap,
 				"cx25840", 0x88 >> 1, NULL);
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index 6835eb1..f544c79 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -51,6 +51,8 @@
 #include "stv6110.h"
 #include "lnbh24.h"
 #include "cx24116.h"
+#include "m88ts202x.h"
+#include "m88ds3103.h"
 #include "cimax2.h"
 #include "lgs8gxx.h"
 #include "netup-eeprom.h"
@@ -489,6 +491,31 @@ static struct xc5000_config mygica_x8506_xc5000_config = {
 	.if_khz = 5380,
 };
 
+/* bestunar single dvb-s2 */
+static struct m88ds3103_config bst_ds3103_config = {
+	.demod_address = 0x68,
+	.ci_mode = 0,
+	.pin_ctrl = 0x82,
+	.ts_mode = 0,
+	.set_voltage = bst_set_voltage,
+};
+/* DVBSKY dual dvb-s2 */
+static struct m88ds3103_config dvbsky_ds3103_config_pri = {
+	.demod_address = 0x68,
+	.ci_mode = 0,
+	.pin_ctrl = 0x82,
+	.ts_mode = 0,
+	.set_voltage = bst_set_voltage,
+};
+
+static struct m88ds3103_config dvbsky_ds3103_config_sec = {
+	.demod_address = 0x68,
+	.ci_mode = 0,
+	.pin_ctrl = 0x82,
+	.ts_mode = 1,
+	.set_voltage = dvbsky_set_voltage_sec,
+};
+
 static int cx23885_dvb_set_frontend(struct dvb_frontend *fe)
 {
 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
@@ -620,6 +647,12 @@ static struct mt2063_config terratec_mt2063_config[] = {
 	},
 };
 
+static struct m88ts202x_config dvbsky_ts202x_config = {
+	.bypasson = 0,
+	.clkout = 0,
+	.clkdiv = 0,
+};
+
 int netup_altera_fpga_rw(void *device, int flag, int data, int read)
 {
 	struct cx23885_dev *dev = (struct cx23885_dev *)device;
@@ -664,6 +697,28 @@ int netup_altera_fpga_rw(void *device, int flag, int data, int read)
 	return 0;
 };
 
+static struct dvb_frontend *dvbsky_pcie_frontend_attach(
+						struct m88ds3103_config *pdconf,
+						struct m88ts202x_config *ptconf,
+						struct i2c_adapter *i2c)
+{
+	struct dvb_frontend *fe;
+	struct m88ts202x_devctl *ctrl;
+
+	fe = dvb_attach(m88ds3103_attach, pdconf, i2c);
+	if (!fe)
+		return NULL;
+	ctrl = dvb_attach(m88ts202x_attach, fe, ptconf, i2c);
+	if (ctrl) {
+		pdconf->tuner_init = ctrl->tuner_init;
+		pdconf->tuner_sleep = ctrl->tuner_sleep;
+		pdconf->tuner_wakeup = ctrl->tuner_wakeup;
+		pdconf->tuner_set_frequency = ctrl->tuner_set_frequency;
+		pdconf->tuner_get_rfgain = ctrl->tuner_get_rfgain;
+	}
+	return	fe;
+}
+
 static int dvb_register(struct cx23885_tsport *port)
 {
 	struct cx23885_dev *dev = port->dev;
@@ -1121,7 +1176,8 @@ static int dvb_register(struct cx23885_tsport *port)
 					&netup_xc5000_config[port->nr - 1]))
 				goto frontend_detach;
 			/* load xc5000 firmware */
-			fe0->dvb.frontend->ops.tuner_ops.init(fe0->dvb.frontend);
+			fe0->dvb.frontend->ops.tuner_ops.init(
+							fe0->dvb.frontend);
 		}
 		/* MFE frontend 2 */
 		fe1 = videobuf_dvb_get_frontend(&port->frontends, 2);
@@ -1173,6 +1229,35 @@ static int dvb_register(struct cx23885_tsport *port)
 			break;
 		}
 		break;
+
+	case CX23885_BOARD_BST_PS8512:
+	case CX23885_BOARD_DVBSKY_S950:
+		i2c_bus = &dev->i2c_bus[1];
+		fe0->dvb.frontend = dvbsky_pcie_frontend_attach(
+							&bst_ds3103_config,
+							&dvbsky_ts202x_config,
+							&i2c_bus->i2c_adap);
+		break;
+	case CX23885_BOARD_DVBSKY_S952:
+		switch (port->nr) {
+		/* port B */
+		case 1:
+			i2c_bus = &dev->i2c_bus[1];
+			fe0->dvb.frontend = dvbsky_pcie_frontend_attach(
+						&dvbsky_ds3103_config_pri,
+						&dvbsky_ts202x_config,
+						&i2c_bus->i2c_adap);
+			break;
+		/* port C */
+		case 2:
+			i2c_bus = &dev->i2c_bus[0];
+			fe0->dvb.frontend = dvbsky_pcie_frontend_attach(
+						&dvbsky_ds3103_config_sec,
+						&dvbsky_ts202x_config,
+						&i2c_bus->i2c_adap);
+			break;
+		}
+		break;
 	default:
 		printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
 			" isn't supported yet\n",
@@ -1243,7 +1328,8 @@ static int dvb_register(struct cx23885_tsport *port)
 
 		/* Read entire EEPROM */
 		dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
-		tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom));
+		tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom,
+				sizeof(eeprom));
 		printk(KERN_INFO "TeVii S470 MAC= %pM\n", eeprom + 0xa0);
 		memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6);
 		break;
diff --git a/drivers/media/video/cx23885/cx23885-f300.c b/drivers/media/video/cx23885/cx23885-f300.c
index 93998f2..fbda25b 100644
--- a/drivers/media/video/cx23885/cx23885-f300.c
+++ b/drivers/media/video/cx23885/cx23885-f300.c
@@ -175,3 +175,54 @@ int f300_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 
 	return f300_xfer(fe, buf);
 }
+
+/* bst control */
+int bst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct cx23885_tsport *port = fe->dvb->priv;
+	struct cx23885_dev *dev = port->dev;
+
+	cx23885_gpio_enable(dev, GPIO_1, 1);
+	cx23885_gpio_enable(dev, GPIO_0, 1);
+
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		cx23885_gpio_set(dev, GPIO_1);
+		cx23885_gpio_clear(dev, GPIO_0);
+		break;
+	case SEC_VOLTAGE_18:
+		cx23885_gpio_set(dev, GPIO_1);
+		cx23885_gpio_set(dev, GPIO_0);
+		break;
+	case SEC_VOLTAGE_OFF:
+		cx23885_gpio_clear(dev, GPIO_1);
+		cx23885_gpio_clear(dev, GPIO_0);
+		break;
+	}
+	return 0;
+}
+
+int dvbsky_set_voltage_sec(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct cx23885_tsport *port = fe->dvb->priv;
+	struct cx23885_dev *dev = port->dev;
+
+	cx23885_gpio_enable(dev, GPIO_12, 1);
+	cx23885_gpio_enable(dev, GPIO_13, 1);
+
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		cx23885_gpio_set(dev, GPIO_13);
+		cx23885_gpio_clear(dev, GPIO_12);
+		break;
+	case SEC_VOLTAGE_18:
+		cx23885_gpio_set(dev, GPIO_13);
+		cx23885_gpio_set(dev, GPIO_12);
+		break;
+	case SEC_VOLTAGE_OFF:
+		cx23885_gpio_clear(dev, GPIO_13);
+		cx23885_gpio_clear(dev, GPIO_12);
+		break;
+	}
+	return 0;
+}
diff --git a/drivers/media/video/cx23885/cx23885-f300.h b/drivers/media/video/cx23885/cx23885-f300.h
index e73344c..7abd9eb 100644
--- a/drivers/media/video/cx23885/cx23885-f300.h
+++ b/drivers/media/video/cx23885/cx23885-f300.h
@@ -1,2 +1,8 @@
+extern int dvbsky_set_voltage_sec(struct dvb_frontend *fe,
+				fe_sec_voltage_t voltage);
+
+extern int bst_set_voltage(struct dvb_frontend *fe,
+				fe_sec_voltage_t voltage);
+
 extern int f300_set_voltage(struct dvb_frontend *fe,
 				fe_sec_voltage_t voltage);
diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c
index ce765e3..69c01f3 100644
--- a/drivers/media/video/cx23885/cx23885-input.c
+++ b/drivers/media/video/cx23885/cx23885-input.c
@@ -87,6 +87,9 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
 	case CX23885_BOARD_HAUPPAUGE_HVR1290:
 	case CX23885_BOARD_TEVII_S470:
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+	case CX23885_BOARD_BST_PS8512:
+	case CX23885_BOARD_DVBSKY_S950:
+	case CX23885_BOARD_DVBSKY_S952:
 		/*
 		 * The only boards we handle right now.  However other boards
 		 * using the CX2388x integrated IR controller should be similar
@@ -138,6 +141,9 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev)
 	case CX23885_BOARD_HAUPPAUGE_HVR1850:
 	case CX23885_BOARD_HAUPPAUGE_HVR1290:
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+	case CX23885_BOARD_BST_PS8512:
+	case CX23885_BOARD_DVBSKY_S950:
+	case CX23885_BOARD_DVBSKY_S952:
 		/*
 		 * The IR controller on this board only returns pulse widths.
 		 * Any other mode setting will fail to set up the device.
@@ -279,6 +285,15 @@ int cx23885_input_init(struct cx23885_dev *dev)
 		/* A guess at the remote */
 		rc_map = RC_MAP_TEVII_NEC;
 		break;
+	case CX23885_BOARD_BST_PS8512:
+	case CX23885_BOARD_DVBSKY_S950:
+	case CX23885_BOARD_DVBSKY_S952:
+		/* Integrated CX2388[58] IR controller */
+		driver_type = RC_DRIVER_IR_RAW;
+		allowed_protos = RC_TYPE_ALL;
+		/* A guess at the remote */
+		rc_map = RC_MAP_DVBSKY;
+		break;
 	default:
 		return -ENODEV;
 	}
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
index f020f05..3f37907 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -89,6 +89,9 @@
 #define CX23885_BOARD_MPX885                   32
 #define CX23885_BOARD_MYGICA_X8507             33
 #define CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL 34
+#define CX23885_BOARD_BST_PS8512               35
+#define CX23885_BOARD_DVBSKY_S952              36
+#define CX23885_BOARD_DVBSKY_S950              37
 
 #define GPIO_0 0x00000001
 #define GPIO_1 0x00000002
@@ -584,7 +587,8 @@ extern void cx23885_video_wakeup(struct cx23885_dev *dev,
 int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i);
 int cx23885_set_input(struct file *file, void *priv, unsigned int i);
 int cx23885_get_input(struct file *file, void *priv, unsigned int *i);
-int cx23885_set_frequency(struct file *file, void *priv, struct v4l2_frequency *f);
+int cx23885_set_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f);
 int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl);
 int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl);
 int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 4/6 v2] dvbsky, dvb-s/s2 PCI card
  2012-04-26 13:24                 ` Mauro Carvalho Chehab
                                     ` (2 preceding siblings ...)
  2012-04-27  7:06                   ` [PATCH 3/6 v2] dvbsky, dvb-s/s2 PCIe card nibble.max
@ 2012-04-27  7:07                   ` nibble.max
  2012-04-27  7:07                   ` [PATCH 5/6 v2] dvbsky, remote control key map nibble.max
  2012-04-27  7:07                   ` [PATCH 6/6 v2] dvbsky, remote control include header file nibble.max
  5 siblings, 0 replies; 56+ messages in thread
From: nibble.max @ 2012-04-27  7:07 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Antti Palosaari, linux-media

Also fix the code style errors checked by checkpatch.pl.
---
 drivers/media/video/cx88/Kconfig      |    2 +
 drivers/media/video/cx88/cx88-cards.c |  682 ++++++++++++++++++---------------
 drivers/media/video/cx88/cx88-dvb.c   |  270 +++++++++----
 drivers/media/video/cx88/cx88-input.c |   12 +-
 drivers/media/video/cx88/cx88.h       |   53 +--
 5 files changed, 604 insertions(+), 415 deletions(-)

diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 3598dc0..ef21a82 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -57,6 +57,8 @@ config VIDEO_CX88_DVB
 	select DVB_ISL6421 if !DVB_FE_CUSTOMISE
 	select DVB_S5H1411 if !DVB_FE_CUSTOMISE
 	select DVB_CX24116 if !DVB_FE_CUSTOMISE
+	select DVB_M88TS202X if !DVB_FE_CUSTOMISE
+	select DVB_M88DS3103 if !DVB_FE_CUSTOMISE
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_STV0288 if !DVB_FE_CUSTOMISE
 	select DVB_STB6000 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index cbd5d11..7a017f0 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -38,13 +38,13 @@ module_param_array(tuner, int, NULL, 0444);
 module_param_array(radio, int, NULL, 0444);
 module_param_array(card,  int, NULL, 0444);
 
-MODULE_PARM_DESC(tuner,"tuner type");
-MODULE_PARM_DESC(radio,"radio tuner type");
-MODULE_PARM_DESC(card,"card type");
+MODULE_PARM_DESC(tuner, "tuner type");
+MODULE_PARM_DESC(radio, "radio tuner type");
+MODULE_PARM_DESC(card, "card type");
 
 static unsigned int latency = UNSET;
-module_param(latency,int,0444);
-MODULE_PARM_DESC(latency,"pci latency timer");
+module_param(latency, int, 0444);
+MODULE_PARM_DESC(latency, "pci latency timer");
 
 static int disable_ir;
 module_param(disable_ir, int, 0444);
@@ -76,16 +76,16 @@ static const struct cx88_board cx88_boards[] = {
 		.input          = {{
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 0,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE2,
 			.vmux   = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE3,
 			.vmux   = 2,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE4,
 			.vmux   = 3,
-		}},
+		} },
 	},
 	[CX88_BOARD_HAUPPAUGE] = {
 		.name		= "Hauppauge WinTV 34xxx models",
@@ -97,20 +97,20 @@ static const struct cx88_board cx88_boards[] = {
 		.input          = {{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
-			.gpio0  = 0xff00,  // internal decoder
-		},{
+			.gpio0  = 0xff00,  /* internal decoder */
+		}, {
 			.type   = CX88_VMUX_DEBUG,
 			.vmux   = 0,
-			.gpio0  = 0xff01,  // mono from tuner chip
-		},{
+			.gpio0  = 0xff01,  /* mono from tuner chip */
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0xff02,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0xff02,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0  = 0xff01,
@@ -125,10 +125,10 @@ static const struct cx88_board cx88_boards[] = {
 		.input          = {{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
-		}},
+		} },
 	},
 	[CX88_BOARD_PIXELVIEW] = {
 		.name           = "PixelView",
@@ -139,14 +139,14 @@ static const struct cx88_board cx88_boards[] = {
 		.input          = {{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
-			.gpio0  = 0xff00,  // internal decoder
-		},{
+			.gpio0  = 0xff00,  /* internal decoder */
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
-		}},
+		} },
 		.radio = {
 			 .type  = CX88_RADIO,
 			 .gpio0 = 0xff10,
@@ -163,15 +163,15 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x03ff,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x03fe,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x03fe,
-		}},
+		} },
 	},
 	[CX88_BOARD_WINFAST2000XP_EXPERT] = {
 		.name           = "Leadtek Winfast 2000XP Expert",
@@ -187,21 +187,21 @@ static const struct cx88_board cx88_boards[] = {
 			.gpio1  = 0x00003004,
 			.gpio2  = 0x00F5e700,
 			.gpio3  = 0x02000000,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0	= 0x00F5c700,
 			.gpio1  = 0x00003004,
 			.gpio2  = 0x00F5c700,
 			.gpio3  = 0x02000000,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0	= 0x00F5c700,
 			.gpio1  = 0x00003004,
 			.gpio2  = 0x00F5c700,
 			.gpio3  = 0x02000000,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0	= 0x00F5d700,
@@ -221,23 +221,23 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio1  = 0xe09f,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio1  = 0xe05f,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio1  = 0xe05f,
-		}},
+		} },
 		.radio = {
 			.gpio1  = 0xe0df,
 			.type   = CX88_RADIO,
 		},
 	},
 	[CX88_BOARD_MSI_TVANYWHERE_MASTER] = {
-		// added gpio values thanks to Michal
-		// values for PAL from DScaler
+		/* added gpio values thanks to Michal */
+		/* values for PAL from DScaler */
 		.name           = "MSI TV-@nywhere Master",
 		.tuner_type     = TUNER_MT2032,
 		.radio_type     = UNSET,
@@ -250,19 +250,19 @@ static const struct cx88_board cx88_boards[] = {
 			.gpio0  = 0x000040bf,
 			.gpio1  = 0x000080c0,
 			.gpio2  = 0x0000ff40,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x000040bf,
 			.gpio1  = 0x000080c0,
 			.gpio2  = 0x0000ff40,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x000040bf,
 			.gpio1  = 0x000080c0,
 			.gpio2  = 0x0000ff40,
-		}},
+		} },
 		.radio = {
 			 .type   = CX88_RADIO,
 			 .vmux   = 3,
@@ -285,7 +285,7 @@ static const struct cx88_board cx88_boards[] = {
 			.gpio1  = 0x00003004,
 			.gpio2  = 0x0035e700,
 			.gpio3  = 0x02000000,
-		},{
+		}, {
 
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
@@ -293,14 +293,14 @@ static const struct cx88_board cx88_boards[] = {
 			.gpio1  = 0x00003004,
 			.gpio2  = 0x0035c700,
 			.gpio3  = 0x02000000,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x0035c700,
 			.gpio1  = 0x0035c700,
 			.gpio2  = 0x02000000,
 			.gpio3  = 0x02000000,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0  = 0x0035d700,
@@ -310,7 +310,7 @@ static const struct cx88_board cx88_boards[] = {
 		},
 	},
 	[CX88_BOARD_LEADTEK_PVR2000] = {
-		// gpio values for PAL version from regspy by DScaler
+		/* gpio values for PAL version from regspy by DScaler */
 		.name           = "Leadtek PVR 2000",
 		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
 		.radio_type     = UNSET,
@@ -322,17 +322,17 @@ static const struct cx88_board cx88_boards[] = {
 			.vmux   = 0,
 			.gpio0  = 0x0000bde2,
 			.audioroute = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x0000bde6,
 			.audioroute = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x0000bde6,
 			.audioroute = 1,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0  = 0x0000bd62,
@@ -349,13 +349,13 @@ static const struct cx88_board cx88_boards[] = {
 		.input          = {{
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 0,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE2,
 			.vmux   = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
-		}},
+		} },
 	},
 	[CX88_BOARD_PROLINK_PLAYTVPVR] = {
 		.name           = "Prolink PlayTV PVR",
@@ -368,15 +368,15 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0xbff0,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0xbff3,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0xbff3,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0  = 0xbff0,
@@ -393,12 +393,12 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x0000fde6,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
-			.gpio0  = 0x0000fde6, // 0x0000fda6 L,R RCA audio in?
+			.gpio0  = 0x0000fde6, /* 0x0000fda6 L,R RCA audio in? */
 			.audioroute = 1,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0  = 0x0000fde2,
@@ -417,17 +417,17 @@ static const struct cx88_board cx88_boards[] = {
 			.vmux   = 0,
 			.gpio0  = 0x00000fbf,
 			.gpio2  = 0x0000fc08,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x00000fbf,
 			.gpio2  = 0x0000fc68,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x00000fbf,
 			.gpio2  = 0x0000fc68,
-		}},
+		} },
 	},
 	[CX88_BOARD_KWORLD_DVB_T] = {
 		.name           = "KWorld/VStream XPert DVB-T",
@@ -440,12 +440,12 @@ static const struct cx88_board cx88_boards[] = {
 			.vmux   = 1,
 			.gpio0  = 0x0700,
 			.gpio2  = 0x0101,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x0700,
 			.gpio2  = 0x0101,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = {
@@ -458,11 +458,11 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x000027df,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x000027df,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_KWORLD_LTV883] = {
@@ -475,19 +475,19 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x07f8,
-		},{
+		}, {
 			.type   = CX88_VMUX_DEBUG,
 			.vmux   = 0,
-			.gpio0  = 0x07f9,  // mono from tuner chip
-		},{
+			.gpio0  = 0x07f9,  /* mono from tuner chip */
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x000007fa,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x000007fa,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0  = 0x000007f8,
@@ -520,19 +520,19 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0	= 0x0f0d,
-		},{
+		}, {
 			.type   = CX88_VMUX_CABLE,
 			.vmux   = 0,
 			.gpio0	= 0x0f05,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0	= 0x0f00,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0	= 0x0f00,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_HAUPPAUGE_DVB_T1] = {
@@ -544,7 +544,7 @@ static const struct cx88_board cx88_boards[] = {
 		.input          = {{
 			.type   = CX88_VMUX_DVB,
 			.vmux   = 0,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_CONEXANT_DVB_T1] = {
@@ -556,7 +556,7 @@ static const struct cx88_board cx88_boards[] = {
 		.input          = {{
 			.type   = CX88_VMUX_DVB,
 			.vmux   = 0,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_PROVIDEO_PV259] = {
@@ -569,7 +569,7 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.audioroute = 1,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_BLACKBIRD,
 	},
 	[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS] = {
@@ -582,11 +582,11 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x000027df,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x000027df,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_DNTV_LIVE_DVB_T] = {
@@ -600,12 +600,12 @@ static const struct cx88_board cx88_boards[] = {
 			.vmux   = 1,
 			.gpio0  = 0x00000700,
 			.gpio2  = 0x00000101,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x00000700,
 			.gpio2  = 0x00000101,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_PCHDTV_HD3000] = {
@@ -631,15 +631,15 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x00008484,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x00008400,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x00008400,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0  = 0x00008404,
@@ -647,8 +647,8 @@ static const struct cx88_board cx88_boards[] = {
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_HAUPPAUGE_ROSLYN] = {
-		// entry added by Kaustubh D. Bhalerao <bhalerao.1@osu.edu>
-		// GPIO values obtained from regspy, courtesy Sean Covel
+		/* entry added by Kaustubh D. Bhalerao <bhalerao.1@osu.edu>*/
+		/* GPIO values obtained from regspy, courtesy Sean Covel*/
 		.name           = "Hauppauge WinTV 28xxx (Roslyn) models",
 		.tuner_type     = UNSET,
 		.radio_type     = UNSET,
@@ -659,20 +659,20 @@ static const struct cx88_board cx88_boards[] = {
 			.vmux   = 0,
 			.gpio0  = 0xed1a,
 			.gpio2  = 0x00ff,
-		},{
+		}, {
 			.type   = CX88_VMUX_DEBUG,
 			.vmux   = 0,
 			.gpio0  = 0xff01,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0xff02,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0xed92,
 			.gpio2  = 0x00ff,
-		}},
+		} },
 		.radio = {
 			 .type   = CX88_RADIO,
 			 .gpio0  = 0xed96,
@@ -681,7 +681,8 @@ static const struct cx88_board cx88_boards[] = {
 		.mpeg           = CX88_MPEG_BLACKBIRD,
 	},
 	[CX88_BOARD_DIGITALLOGIC_MEC] = {
-		.name           = "Digital-Logic MICROSPACE Entertainment Center (MEC)",
+		.name           =
+		"Digital-Logic MICROSPACE Entertainment Center (MEC)",
 		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
@@ -692,17 +693,17 @@ static const struct cx88_board cx88_boards[] = {
 			.vmux   = 0,
 			.gpio0  = 0x00009d80,
 			.audioroute = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x00009d76,
 			.audioroute = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x00009d76,
 			.audioroute = 1,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0  = 0x00009d00,
@@ -721,15 +722,15 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 1,
 			.gpio1  = 0x0000e03f,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 2,
 			.gpio1  = 0x0000e07f,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 3,
 			.gpio1  = 0x0000e07f,
-		}}
+		} }
 	},
 	[CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO] = {
 		.name           = "PixelView PlayTV Ultra Pro (Stereo)",
@@ -738,21 +739,21 @@ static const struct cx88_board cx88_boards[] = {
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		/* Some variants use a tda9874 and so need the tvaudio module. */
+	/* Some variants use a tda9874 and so need the tvaudio module. */
 		.audio_chip     = V4L2_IDENT_TVAUDIO,
 		.input          = {{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0xbf61,  /* internal decoder */
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0	= 0xbf63,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0	= 0xbf63,
-		}},
+		} },
 		.radio = {
 			 .type  = CX88_RADIO,
 			 .gpio0 = 0xbf60,
@@ -769,15 +770,15 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x97ed,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x97e9,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x97e9,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_ADSTECH_DVB_T_PCI] = {
@@ -791,12 +792,12 @@ static const struct cx88_board cx88_boards[] = {
 			.vmux   = 1,
 			.gpio0  = 0x0700,
 			.gpio2  = 0x0101,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x0700,
 			.gpio2  = 0x0101,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1] = {
@@ -805,13 +806,13 @@ static const struct cx88_board cx88_boards[] = {
 		.input          = {{
 			.type   = CX88_VMUX_DVB,
 			.vmux   = 0,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 2,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD] = {
@@ -825,15 +826,15 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x87fd,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x87f9,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x87f9,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_AVERMEDIA_ULTRATV_MC_550] = {
@@ -848,17 +849,17 @@ static const struct cx88_board cx88_boards[] = {
 			.vmux   = 0,
 			.gpio0  = 0x0000cd73,
 			.audioroute = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 1,
 			.gpio0  = 0x0000cd73,
 			.audioroute = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 3,
 			.gpio0  = 0x0000cdb3,
 			.audioroute = 1,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.vmux   = 2,
@@ -878,14 +879,14 @@ static const struct cx88_board cx88_boards[] = {
 			 .gpio1  = 0x01000000,
 			 .gpio2  = 0x02000000,
 			 .gpio3  = 0x00100000,
-		 },{
+		 }, {
 			 .type   = CX88_VMUX_SVIDEO,
 			 .vmux   = 2,
 			 .gpio0  = 0x03000000,
 			 .gpio1  = 0x01000000,
 			 .gpio2  = 0x02000000,
 			 .gpio3  = 0x00100000,
-		 }},
+		 } },
 	},
 	[CX88_BOARD_ATI_HDTVWONDER] = {
 		.name           = "ATI HDTV Wonder",
@@ -900,21 +901,21 @@ static const struct cx88_board cx88_boards[] = {
 			.gpio1  = 0x000000ff,
 			.gpio2  = 0x00000001,
 			.gpio3  = 0x00000000,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x00000ffe,
 			.gpio1  = 0x000000ff,
 			.gpio2  = 0x00000001,
 			.gpio3  = 0x00000000,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x00000ffe,
 			.gpio1  = 0x000000ff,
 			.gpio2  = 0x00000001,
 			.gpio3  = 0x00000000,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_WINFAST_DTV1000] = {
@@ -926,13 +927,13 @@ static const struct cx88_board cx88_boards[] = {
 		.input          = {{
 			.type   = CX88_VMUX_DVB,
 			.vmux   = 0,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_AVERTV_303] = {
@@ -949,21 +950,21 @@ static const struct cx88_board cx88_boards[] = {
 			.gpio1  = 0xe09f,
 			.gpio2  = 0x0010,
 			.gpio3  = 0x0000,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x00ff,
 			.gpio1  = 0xe05f,
 			.gpio2  = 0x0010,
 			.gpio3  = 0x0000,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x00ff,
 			.gpio1  = 0xe05f,
 			.gpio2  = 0x0010,
 			.gpio3  = 0x0000,
-		}},
+		} },
 	},
 	[CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1] = {
 		.name		= "Hauppauge Nova-S-Plus DVB-S",
@@ -978,17 +979,17 @@ static const struct cx88_board cx88_boards[] = {
 			.vmux	= 0,
 			/* 2: Line-In */
 			.audioroute = 2,
-		},{
+		}, {
 			.type	= CX88_VMUX_COMPOSITE1,
 			.vmux	= 1,
 			/* 2: Line-In */
 			.audioroute = 2,
-		},{
+		}, {
 			.type	= CX88_VMUX_SVIDEO,
 			.vmux	= 2,
 			/* 2: Line-In */
 			.audioroute = 2,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_HAUPPAUGE_NOVASE2_S1] = {
@@ -1000,7 +1001,7 @@ static const struct cx88_board cx88_boards[] = {
 		.input		= {{
 			.type	= CX88_VMUX_DVB,
 			.vmux	= 0,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_KWORLD_DVBS_100] = {
@@ -1015,17 +1016,17 @@ static const struct cx88_board cx88_boards[] = {
 			.vmux	= 0,
 			/* 2: Line-In */
 			.audioroute = 2,
-		},{
+		}, {
 			.type	= CX88_VMUX_COMPOSITE1,
 			.vmux	= 1,
 			/* 2: Line-In */
 			.audioroute = 2,
-		},{
+		}, {
 			.type	= CX88_VMUX_SVIDEO,
 			.vmux	= 2,
 			/* 2: Line-In */
 			.audioroute = 2,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_HAUPPAUGE_HVR1100] = {
@@ -1038,18 +1039,19 @@ static const struct cx88_board cx88_boards[] = {
 		.input		= {{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
-		},{
+		}, {
 			.type	= CX88_VMUX_COMPOSITE1,
 			.vmux	= 1,
-		},{
+		}, {
 			.type	= CX88_VMUX_SVIDEO,
 			.vmux	= 2,
-		}},
+		} },
 		/* fixme: Add radio support */
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_HAUPPAUGE_HVR1100LP] = {
-		.name		= "Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile)",
+		.name		=
+		"Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile)",
 		.tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
 		.radio_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
@@ -1058,10 +1060,10 @@ static const struct cx88_board cx88_boards[] = {
 		.input		= {{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
-		},{
+		}, {
 			.type	= CX88_VMUX_COMPOSITE1,
 			.vmux	= 1,
-		}},
+		} },
 		/* fixme: Add radio support */
 		.mpeg           = CX88_MPEG_DVB,
 	},
@@ -1077,15 +1079,15 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0xf80808,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0	= 0xf80808,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0	= 0xf80808,
-		}},
+		} },
 		.radio = {
 			 .type  = CX88_RADIO,
 			 .gpio0 = 0xf80808,
@@ -1106,12 +1108,12 @@ static const struct cx88_board cx88_boards[] = {
 			.vmux   = 1,
 			.gpio0  = 0x0700,
 			.gpio2  = 0x0101,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x0700,
 			.gpio2  = 0x0101,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL] = {
@@ -1124,11 +1126,11 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x000067df,
-		 },{
+		 }, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x000067df,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = {
@@ -1142,17 +1144,17 @@ static const struct cx88_board cx88_boards[] = {
 			.vmux   = 0,
 			.gpio0  = 0x3de2,
 			.gpio2  = 0x00ff,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x3de6,
 			.audioroute = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x3de6,
 			.audioroute = 1,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0  = 0x3de6,
@@ -1170,15 +1172,15 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x0000a75f,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x0000a75b,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x0000a75b,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_PCHDTV_HD5500] = {
@@ -1192,15 +1194,15 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x87fd,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x87f9,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x87f9,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_KWORLD_MCE200_DELUXE] = {
@@ -1216,7 +1218,7 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x0000BDE6
-		}},
+		} },
 		.mpeg           = CX88_MPEG_BLACKBIRD,
 	},
 	[CX88_BOARD_PIXELVIEW_PLAYTV_P7000] = {
@@ -1232,7 +1234,7 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x5da6,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_BLACKBIRD,
 	},
 	[CX88_BOARD_NPGTECH_REALTV_TOP10FM] = {
@@ -1245,15 +1247,15 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0	= 0x0788,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0	= 0x078b,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0	= 0x078b,
-		}},
+		} },
 		.radio = {
 			 .type  = CX88_RADIO,
 			 .gpio0 = 0x074a,
@@ -1294,7 +1296,7 @@ static const struct cx88_board cx88_boards[] = {
 			.gpio1  = 0x0000b207,
 			.gpio2  = 0x0001d701,
 			.gpio3  = 0x02000000,
-		}},
+		} },
 		.radio = {
 			 .type  = CX88_RADIO,
 			 .gpio0 = 0x00015702,
@@ -1318,28 +1320,28 @@ static const struct cx88_board cx88_boards[] = {
 			.gpio1  = 0x00008207,
 			.gpio2	= 0x00000000,
 			.gpio3  = 0x02000000,
-		},{
+		}, {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x00018300,
 			.gpio1  = 0x0000f207,
 			.gpio2	= 0x00017304,
 			.gpio3  = 0x02000000,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x00018301,
 			.gpio1  = 0x0000f207,
 			.gpio2	= 0x00017304,
 			.gpio3  = 0x02000000,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x00018301,
 			.gpio1  = 0x0000f207,
 			.gpio2	= 0x00017304,
 			.gpio3  = 0x02000000,
-		}},
+		} },
 		.radio = {
 			 .type  = CX88_RADIO,
 			 .gpio0 = 0x00015702,
@@ -1358,14 +1360,15 @@ static const struct cx88_board cx88_boards[] = {
 		.input  = {{
 			.type  = CX88_VMUX_DVB,
 			.vmux  = 0,
-		},{
+		}, {
 			.type  = CX88_VMUX_COMPOSITE1,
 			.vmux  = 1,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_HAUPPAUGE_HVR3000] = {
-		.name           = "Hauppauge WinTV-HVR3000 TriMode Analog/DVB-S/DVB-T",
+		.name           =
+			"Hauppauge WinTV-HVR3000 TriMode Analog/DVB-S/DVB-T",
 		.tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
 		.radio_type     = UNSET,
 		.tuner_addr     = ADDR_UNSET,
@@ -1378,19 +1381,19 @@ static const struct cx88_board cx88_boards[] = {
 			.gpio0  = 0x84bf,
 			/* 1: TV Audio / FM Mono */
 			.audioroute = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x84bf,
 			/* 2: Line-In */
 			.audioroute = 2,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x84bf,
 			/* 2: Line-In */
 			.audioroute = 2,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0	= 0x84bf,
@@ -1410,18 +1413,19 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x0709,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x070b,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x070b,
-		}},
+		} },
 	},
 	[CX88_BOARD_TE_DTV_250_OEM_SWANN] = {
-		.name           = "Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM",
+		.name           =
+			"Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM",
 		.tuner_type     = TUNER_LG_PAL_NEW_TAPC,
 		.radio_type     = UNSET,
 		.tuner_addr     = ADDR_UNSET,
@@ -1433,24 +1437,25 @@ static const struct cx88_board cx88_boards[] = {
 			.gpio1  = 0x00e00000,
 			.gpio2  = 0x003fffff,
 			.gpio3  = 0x02000000,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x003fffff,
 			.gpio1  = 0x00e00000,
 			.gpio2  = 0x003fffff,
 			.gpio3  = 0x02000000,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x003fffff,
 			.gpio1  = 0x00e00000,
 			.gpio2  = 0x003fffff,
 			.gpio3  = 0x02000000,
-		}},
+		} },
 	},
 	[CX88_BOARD_HAUPPAUGE_HVR1300] = {
-		.name		= "Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder",
+		.name		=
+			"Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder",
 		.tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
 		.radio_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
@@ -1466,19 +1471,19 @@ static const struct cx88_board cx88_boards[] = {
 			.gpio0	= 0xef88,
 			/* 1: TV Audio / FM Mono */
 			.audioroute = 1,
-		},{
+		}, {
 			.type	= CX88_VMUX_COMPOSITE1,
 			.vmux	= 1,
 			.gpio0	= 0xef88,
 			/* 2: Line-In */
 			.audioroute = 2,
-		},{
+		}, {
 			.type	= CX88_VMUX_SVIDEO,
 			.vmux	= 2,
 			.gpio0	= 0xef88,
 			/* 2: Line-In */
 			.audioroute = 2,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
 		.radio = {
 			.type   = CX88_RADIO,
@@ -1509,15 +1514,15 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_DEBUG,
 			.vmux   = 3,
 			.gpio0  = 0x04ff,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x07fa,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x07fa,
-		}},
+		} },
 	},
 	[CX88_BOARD_PINNACLE_PCTV_HD_800i] = {
 		.name           = "Pinnacle PCTV HD 800i",
@@ -1530,19 +1535,19 @@ static const struct cx88_board cx88_boards[] = {
 			.vmux   = 0,
 			.gpio0  = 0x04fb,
 			.gpio1  = 0x10ff,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x04fb,
 			.gpio1  = 0x10ef,
 			.audioroute = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x04fb,
 			.gpio1  = 0x10ef,
 			.audioroute = 1,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO] = {
@@ -1716,16 +1721,21 @@ static const struct cx88_board cx88_boards[] = {
 		},
 	},
 	[CX88_BOARD_POWERCOLOR_REAL_ANGEL] = {
-		.name           = "PowerColor RA330",	/* Long names may confuse LIRC. */
+		.name           = "PowerColor RA330",
+/* Long names may confuse LIRC. */
 		.tuner_type     = TUNER_XC2028,
 		.tuner_addr     = 0x61,
 		.input          = { {
 			.type   = CX88_VMUX_DEBUG,
-			.vmux   = 3,		/* Due to the way the cx88 driver is written,	*/
-			.gpio0 = 0x00ff,	/* there is no way to deactivate audio pass-	*/
-			.gpio1 = 0xf39d,	/* through without this entry. Furthermore, if	*/
-			.gpio3 = 0x0000,	/* the TV mux entry is first, you get audio	*/
-		}, {				/* from the tuner on boot for a little while.	*/
+			.vmux   = 3,
+/* Due to the way the cx88 driver is written,	*/
+			.gpio0 = 0x00ff,
+/* there is no way to deactivate audio pass-	*/
+			.gpio1 = 0xf39d,
+/* through without this entry. Furthermore, if	*/
+			.gpio3 = 0x0000,
+/* the TV mux entry is first, you get audio	*/
+		}, {	/* from the tuner on boot for a little while.	*/
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0 = 0x00ff,
@@ -1814,15 +1824,15 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x10df,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x16d9,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x16d9,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_PROLINK_PV_8000GT] = {
@@ -2224,7 +2234,7 @@ static const struct cx88_board cx88_boards[] = {
 			.gpio0	= 0x0400,	/* pin 2 = 0 */
 			.gpio1	= 0x6060,	/* pin 13 = 1, pin 14 = 1 */
 			.gpio2	= 0x0000,
-		}},
+		} },
 		.radio = {
 			.type	= CX88_RADIO,
 			.gpio0	= 0x0400,	/* pin 2 = 0 */
@@ -2275,7 +2285,7 @@ static const struct cx88_board cx88_boards[] = {
 			.gpio1	= 0xF0F7,
 			.gpio2	= 0x0101,
 			.gpio3	= 0x0000,
-		}},
+		} },
 		.radio = {
 			.type	= CX88_RADIO,
 			.gpio0	= 0x0403,
@@ -2309,6 +2319,18 @@ static const struct cx88_board cx88_boards[] = {
 		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
+	[CX88_BOARD_BST_PS8312] = {
+		.name           = "Bestunar PS8312 DVB-S/S2",
+		.tuner_type     = UNSET,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DVB,
+			.vmux   = 0,
+		} },
+		.mpeg           = CX88_MPEG_DVB,
+	},
 };
 
 /* ------------------------------------------------------------------ */
@@ -2319,19 +2341,19 @@ static const struct cx88_subid cx88_subids[] = {
 		.subvendor = 0x0070,
 		.subdevice = 0x3400,
 		.card      = CX88_BOARD_HAUPPAUGE,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x3401,
 		.card      = CX88_BOARD_HAUPPAUGE,
-	},{
+	}, {
 		.subvendor = 0x14c7,
 		.subdevice = 0x0106,
 		.card      = CX88_BOARD_GDI,
-	},{
+	}, {
 		.subvendor = 0x14c7,
 		.subdevice = 0x0107, /* with mpeg encoder */
 		.card      = CX88_BOARD_GDI,
-	},{
+	}, {
 		.subvendor = PCI_VENDOR_ID_ATI,
 		.subdevice = 0x00f8,
 		.card      = CX88_BOARD_ATI_WONDER_PRO,
@@ -2343,176 +2365,176 @@ static const struct cx88_subid cx88_subids[] = {
 		.subvendor = 0x107d,
 		.subdevice = 0x6611,
 		.card      = CX88_BOARD_WINFAST2000XP_EXPERT,
-	},{
+	}, {
 		.subvendor = 0x107d,
 		.subdevice = 0x6613,	/* NTSC */
 		.card      = CX88_BOARD_WINFAST2000XP_EXPERT,
-	},{
+	}, {
 		.subvendor = 0x107d,
 		.subdevice = 0x6620,
 		.card      = CX88_BOARD_WINFAST_DV2000,
-	},{
+	}, {
 		.subvendor = 0x107d,
 		.subdevice = 0x663b,
 		.card      = CX88_BOARD_LEADTEK_PVR2000,
-	},{
+	}, {
 		.subvendor = 0x107d,
 		.subdevice = 0x663c,
 		.card      = CX88_BOARD_LEADTEK_PVR2000,
-	},{
+	}, {
 		.subvendor = 0x1461,
 		.subdevice = 0x000b,
 		.card      = CX88_BOARD_AVERTV_STUDIO_303,
-	},{
+	}, {
 		.subvendor = 0x1462,
 		.subdevice = 0x8606,
 		.card      = CX88_BOARD_MSI_TVANYWHERE_MASTER,
-	},{
+	}, {
 		.subvendor = 0x10fc,
 		.subdevice = 0xd003,
 		.card      = CX88_BOARD_IODATA_GVVCP3PCI,
-	},{
+	}, {
 		.subvendor = 0x1043,
 		.subdevice = 0x4823,  /* with mpeg encoder */
 		.card      = CX88_BOARD_ASUS_PVR_416,
-	},{
+	}, {
 		.subvendor = 0x17de,
 		.subdevice = 0x08a6,
 		.card      = CX88_BOARD_KWORLD_DVB_T,
-	},{
+	}, {
 		.subvendor = 0x18ac,
 		.subdevice = 0xd810,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q,
-	},{
+	}, {
 		.subvendor = 0x18ac,
 		.subdevice = 0xd820,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T,
-	},{
+	}, {
 		.subvendor = 0x18ac,
 		.subdevice = 0xdb00,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9002,
 		.card      = CX88_BOARD_HAUPPAUGE_DVB_T1,
-	},{
+	}, {
 		.subvendor = 0x14f1,
 		.subdevice = 0x0187,
 		.card      = CX88_BOARD_CONEXANT_DVB_T1,
-	},{
+	}, {
 		.subvendor = 0x1540,
 		.subdevice = 0x2580,
 		.card      = CX88_BOARD_PROVIDEO_PV259,
-	},{
+	}, {
 		.subvendor = 0x18ac,
 		.subdevice = 0xdb10,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
-	},{
+	}, {
 		.subvendor = 0x1554,
 		.subdevice = 0x4811,
 		.card      = CX88_BOARD_PIXELVIEW,
-	},{
+	}, {
 		.subvendor = 0x7063,
 		.subdevice = 0x3000, /* HD-3000 card */
 		.card      = CX88_BOARD_PCHDTV_HD3000,
-	},{
+	}, {
 		.subvendor = 0x17de,
 		.subdevice = 0xa8a6,
 		.card      = CX88_BOARD_DNTV_LIVE_DVB_T,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x2801,
 		.card      = CX88_BOARD_HAUPPAUGE_ROSLYN,
-	},{
+	}, {
 		.subvendor = 0x14f1,
 		.subdevice = 0x0342,
 		.card      = CX88_BOARD_DIGITALLOGIC_MEC,
-	},{
+	}, {
 		.subvendor = 0x10fc,
 		.subdevice = 0xd035,
 		.card      = CX88_BOARD_IODATA_GVBCTV7E,
-	},{
+	}, {
 		.subvendor = 0x1421,
 		.subdevice = 0x0334,
 		.card      = CX88_BOARD_ADSTECH_DVB_T_PCI,
-	},{
+	}, {
 		.subvendor = 0x153b,
 		.subdevice = 0x1166,
 		.card      = CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1,
-	},{
+	}, {
 		.subvendor = 0x18ac,
 		.subdevice = 0xd500,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD,
-	},{
+	}, {
 		.subvendor = 0x1461,
 		.subdevice = 0x8011,
 		.card      = CX88_BOARD_AVERMEDIA_ULTRATV_MC_550,
-	},{
+	}, {
 		.subvendor = PCI_VENDOR_ID_ATI,
 		.subdevice = 0xa101,
 		.card      = CX88_BOARD_ATI_HDTVWONDER,
-	},{
+	}, {
 		.subvendor = 0x107d,
 		.subdevice = 0x665f,
 		.card      = CX88_BOARD_WINFAST_DTV1000,
-	},{
+	}, {
 		.subvendor = 0x1461,
 		.subdevice = 0x000a,
 		.card      = CX88_BOARD_AVERTV_303,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9200,
 		.card      = CX88_BOARD_HAUPPAUGE_NOVASE2_S1,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9201,
 		.card      = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9202,
 		.card      = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1,
-	},{
+	}, {
 		.subvendor = 0x17de,
 		.subdevice = 0x08b2,
 		.card      = CX88_BOARD_KWORLD_DVBS_100,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9400,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR1100,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9402,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR1100,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9800,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR1100LP,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9802,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR1100LP,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9001,
 		.card      = CX88_BOARD_HAUPPAUGE_DVB_T1,
-	},{
+	}, {
 		.subvendor = 0x1822,
 		.subdevice = 0x0025,
 		.card      = CX88_BOARD_DNTV_LIVE_DVB_T_PRO,
-	},{
+	}, {
 		.subvendor = 0x17de,
 		.subdevice = 0x08a1,
 		.card      = CX88_BOARD_KWORLD_DVB_T_CX22702,
-	},{
+	}, {
 		.subvendor = 0x18ac,
 		.subdevice = 0xdb50,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL,
-	},{
+	}, {
 		.subvendor = 0x18ac,
 		.subdevice = 0xdb54,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL,
 		/* Re-branded DViCO: DigitalNow DVB-T Dual */
-	},{
+	}, {
 		.subvendor = 0x18ac,
 		.subdevice = 0xdb11,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
@@ -2525,55 +2547,55 @@ static const struct cx88_subid cx88_subids[] = {
 		.subvendor = 0x17de,
 		.subdevice = 0x0840,
 		.card      = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
-	},{
+	}, {
 		.subvendor = 0x1421,
 		.subdevice = 0x0305,
 		.card      = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
-	},{
+	}, {
 		.subvendor = 0x18ac,
 		.subdevice = 0xdb40,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
-	},{
+	}, {
 		.subvendor = 0x18ac,
 		.subdevice = 0xdb44,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
-	},{
+	}, {
 		.subvendor = 0x7063,
 		.subdevice = 0x5500,
 		.card      = CX88_BOARD_PCHDTV_HD5500,
-	},{
+	}, {
 		.subvendor = 0x17de,
 		.subdevice = 0x0841,
 		.card      = CX88_BOARD_KWORLD_MCE200_DELUXE,
-	},{
+	}, {
 		.subvendor = 0x1822,
 		.subdevice = 0x0019,
 		.card      = CX88_BOARD_DNTV_LIVE_DVB_T_PRO,
-	},{
+	}, {
 		.subvendor = 0x1554,
 		.subdevice = 0x4813,
 		.card      = CX88_BOARD_PIXELVIEW_PLAYTV_P7000,
-	},{
+	}, {
 		.subvendor = 0x14f1,
 		.subdevice = 0x0842,
 		.card      = CX88_BOARD_NPGTECH_REALTV_TOP10FM,
-	},{
+	}, {
 		.subvendor = 0x107d,
 		.subdevice = 0x665e,
 		.card      = CX88_BOARD_WINFAST_DTV2000H,
-	},{
+	}, {
 		.subvendor = 0x107d,
 		.subdevice = 0x6f2b,
 		.card      = CX88_BOARD_WINFAST_DTV2000H_J,
-	},{
+	}, {
 		.subvendor = 0x18ac,
 		.subdevice = 0xd800, /* FusionHDTV 3 Gold (original revision) */
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q,
-	},{
+	}, {
 		.subvendor = 0x14f1,
 		.subdevice = 0x0084,
 		.card      = CX88_BOARD_GENIATECH_DVBS,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x1404,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR3000,
@@ -2585,60 +2607,60 @@ static const struct cx88_subid cx88_subids[] = {
 		.subvendor = 0x18ac,
 		.subdevice = 0xdccd,
 		.card      = CX88_BOARD_SAMSUNG_SMT_7020,
-	},{
+	}, {
 		.subvendor = 0x1461,
 		.subdevice = 0xc111, /* AverMedia M150-D */
 		/* This board is known to work with the ASUS PVR416 config */
 		.card      = CX88_BOARD_ASUS_PVR_416,
-	},{
+	}, {
 		.subvendor = 0xc180,
 		.subdevice = 0xc980,
 		.card      = CX88_BOARD_TE_DTV_250_OEM_SWANN,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9600,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR1300,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9601,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR1300,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9602,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR1300,
-	},{
+	}, {
 		.subvendor = 0x107d,
 		.subdevice = 0x6632,
 		.card      = CX88_BOARD_LEADTEK_PVR2000,
-	},{
+	}, {
 		.subvendor = 0x12ab,
 		.subdevice = 0x2300, /* Club3D Zap TV2100 */
 		.card      = CX88_BOARD_KWORLD_DVB_T_CX22702,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9000,
 		.card      = CX88_BOARD_HAUPPAUGE_DVB_T1,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x1400,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR3000,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x1401,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR3000,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x1402,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR3000,
-	},{
+	}, {
 		.subvendor = 0x1421,
 		.subdevice = 0x0341, /* ADS Tech InstantTV DVB-S */
 		.card      = CX88_BOARD_KWORLD_DVBS_100,
-	},{
+	}, {
 		.subvendor = 0x1421,
 		.subdevice = 0x0390,
 		.card      = CX88_BOARD_ADSTECH_PTV_390,
-	},{
+	}, {
 		.subvendor = 0x11bd,
 		.subdevice = 0x0051,
 		.card      = CX88_BOARD_PINNACLE_PCTV_HD_800i,
@@ -2801,7 +2823,7 @@ static const struct cx88_subid cx88_subids[] = {
 		.subdevice = 0x6f36,
 		.card      = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36,
 	}, {
-		/* WinFast TV2000 XP Global with XC4000 tuner and different GPIOs */
+	/* WinFast TV2000 XP Global with XC4000 tuner and different GPIOs */
 		.subvendor = 0x107d,
 		.subdevice = 0x6f43,
 		.card      = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43,
@@ -2813,6 +2835,10 @@ static const struct cx88_subid cx88_subids[] = {
 		.subvendor = 0x1822,
 		.subdevice = 0x0023,
 		.card      = CX88_BOARD_TWINHAN_VP1027_DVBS,
+	}, {
+		.subvendor = 0x14f1,
+		.subdevice = 0x8312,
+		.card      = CX88_BOARD_BST_PS8312,
 	},
 };
 
@@ -2857,19 +2883,30 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
 	core->board.radio.type = tv.has_radio ? CX88_RADIO : 0;
 
 	/* Make sure we support the board model */
-	switch (tv.model)
-	{
-	case 14009: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in) */
-	case 14019: /* WinTV-HVR3000 (Retail, IR Blaster, b/panel video, 3.5mm audio in) */
-	case 14029: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - 880 bridge) */
-	case 14109: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - low profile) */
-	case 14129: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - 880 bridge - LP) */
-	case 14559: /* WinTV-HVR3000 (OEM, no IR, b/panel video, 3.5mm audio in) */
-	case 14569: /* WinTV-HVR3000 (OEM, no IR, no back panel video) */
-	case 14659: /* WinTV-HVR3000 (OEM, no IR, b/panel video, RCA audio in - Low profile) */
-	case 14669: /* WinTV-HVR3000 (OEM, no IR, no b/panel video - Low profile) */
-	case 28552: /* WinTV-PVR 'Roslyn' (No IR) */
-	case 34519: /* WinTV-PCI-FM */
+	switch (tv.model) {
+	case 14009:
+/* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in) */
+	case 14019:
+/* WinTV-HVR3000 (Retail, IR Blaster, b/panel video, 3.5mm audio in) */
+	case 14029:
+/* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - 880 bridge) */
+	case 14109:
+/* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - low profile) */
+	case 14129:
+/* WinTV-HVR3000 (Retail, IR, b/panel video,
+3.5mm audio in - 880 bridge - LP) */
+	case 14559:
+/* WinTV-HVR3000 (OEM, no IR, b/panel video, 3.5mm audio in) */
+	case 14569:
+/* WinTV-HVR3000 (OEM, no IR, no back panel video) */
+	case 14659:
+/* WinTV-HVR3000 (OEM, no IR, b/panel video, RCA audio in - Low profile) */
+	case 14669:
+/* WinTV-HVR3000 (OEM, no IR, no b/panel video - Low profile) */
+	case 28552:
+/* WinTV-PVR 'Roslyn' (No IR) */
+	case 34519:
+/* WinTV-PCI-FM */
 	case 69009:
 		/* WinTV-HVR4000 (DVBS/S2/T, Video and IR, back panel inputs) */
 	case 69100: /* WinTV-HVR4000LITE (DVBS/S2, IR) */
@@ -2915,33 +2952,33 @@ static const struct {
 	int  fm;
 	const char *name;
 } gdi_tuner[] = {
-	[ 0x01 ] = { .id   = TUNER_ABSENT,
+	[0x01] = { .id   = TUNER_ABSENT,
 		     .name = "NTSC_M" },
-	[ 0x02 ] = { .id   = TUNER_ABSENT,
+	[0x02] = { .id   = TUNER_ABSENT,
 		     .name = "PAL_B" },
-	[ 0x03 ] = { .id   = TUNER_ABSENT,
+	[0x03] = { .id   = TUNER_ABSENT,
 		     .name = "PAL_I" },
-	[ 0x04 ] = { .id   = TUNER_ABSENT,
+	[0x04] = { .id   = TUNER_ABSENT,
 		     .name = "PAL_D" },
-	[ 0x05 ] = { .id   = TUNER_ABSENT,
+	[0x05] = { .id   = TUNER_ABSENT,
 		     .name = "SECAM" },
 
-	[ 0x10 ] = { .id   = TUNER_ABSENT,
+	[0x10] = { .id   = TUNER_ABSENT,
 		     .fm   = 1,
 		     .name = "TEMIC_4049" },
-	[ 0x11 ] = { .id   = TUNER_TEMIC_4136FY5,
+	[0x11] = { .id   = TUNER_TEMIC_4136FY5,
 		     .name = "TEMIC_4136" },
-	[ 0x12 ] = { .id   = TUNER_ABSENT,
+	[0x12] = { .id   = TUNER_ABSENT,
 		     .name = "TEMIC_4146" },
 
-	[ 0x20 ] = { .id   = TUNER_PHILIPS_FQ1216ME,
+	[0x20] = { .id   = TUNER_PHILIPS_FQ1216ME,
 		     .fm   = 1,
 		     .name = "PHILIPS_FQ1216_MK3" },
-	[ 0x21 ] = { .id   = TUNER_ABSENT, .fm = 1,
+	[0x21] = { .id   = TUNER_ABSENT, .fm = 1,
 		     .name = "PHILIPS_FQ1236_MK3" },
-	[ 0x22 ] = { .id   = TUNER_ABSENT,
+	[0x22] = { .id   = TUNER_ABSENT,
 		     .name = "PHILIPS_FI1236_MK3" },
-	[ 0x23 ] = { .id   = TUNER_ABSENT,
+	[0x23] = { .id   = TUNER_ABSENT,
 		     .name = "PHILIPS_FI1216_MK3" },
 };
 
@@ -3241,15 +3278,15 @@ int cx88_tuner_callback(void *priv, int component, int command, int arg)
 		return -EINVAL;
 
 	switch (core->board.tuner_type) {
-		case TUNER_XC2028:
-			info_printk(core, "Calling XC2028/3028 callback\n");
-			return cx88_xc2028_tuner_callback(core, command, arg);
-		case TUNER_XC4000:
-			info_printk(core, "Calling XC4000 callback\n");
-			return cx88_xc4000_tuner_callback(core, command, arg);
-		case TUNER_XC5000:
-			info_printk(core, "Calling XC5000 callback\n");
-			return cx88_xc5000_tuner_callback(core, command, arg);
+	case TUNER_XC2028:
+		info_printk(core, "Calling XC2028/3028 callback\n");
+		return cx88_xc2028_tuner_callback(core, command, arg);
+	case TUNER_XC4000:
+		info_printk(core, "Calling XC4000 callback\n");
+		return cx88_xc4000_tuner_callback(core, command, arg);
+	case TUNER_XC5000:
+		info_printk(core, "Calling XC5000 callback\n");
+		return cx88_xc5000_tuner_callback(core, command, arg);
 	}
 	err_printk(core, "Error: Calling callback for tuner %d\n",
 		   core->board.tuner_type);
@@ -3266,19 +3303,20 @@ static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
 	if (0 == pci->subsystem_vendor &&
 	    0 == pci->subsystem_device) {
 		printk(KERN_ERR
-		       "%s: Your board has no valid PCI Subsystem ID and thus can't\n"
-		       "%s: be autodetected.  Please pass card=<n> insmod option to\n"
-		       "%s: workaround that.  Redirect complaints to the vendor of\n"
+		"%s: Your board has no valid PCI Subsystem ID and thus can't\n"
+		"%s: be autodetected.  Please pass card=<n> insmod option to\n"
+		"%s: workaround that.  Redirect complaints to the vendor of\n"
 		       "%s: the TV card.  Best regards,\n"
 		       "%s:         -- tux\n",
-		       core->name,core->name,core->name,core->name,core->name);
+		       core->name, core->name, core->name,
+			core->name, core->name);
 	} else {
 		printk(KERN_ERR
-		       "%s: Your board isn't known (yet) to the driver.  You can\n"
+		"%s: Your board isn't known (yet) to the driver.  You can\n"
 		       "%s: try to pick one of the existing card configs via\n"
 		       "%s: card=<n> insmod option.  Updating to the latest\n"
 		       "%s: version might help as well.\n",
-		       core->name,core->name,core->name,core->name);
+		       core->name, core->name, core->name, core->name);
 	}
 	err_printk(core, "Here is a list of valid choices for the card=<n> "
 		   "insmod option:\n");
@@ -3292,7 +3330,8 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core)
 	switch (core->boardnr) {
 	case CX88_BOARD_HAUPPAUGE_HVR1300:
 		/*
-		 * Bring the 702 demod up before i2c scanning/attach or devices are hidden
+		 * Bring the 702 demod up
+		* before i2c scanning/attach or devices are hidden
 		 * We leave here with the 702 on the bus
 		 *
 		 * "reset the IR receiver on GPIO[3]"
@@ -3494,18 +3533,18 @@ static void cx88_card_setup(struct cx88_core *core)
 		if (0 == core->i2c_rc) {
 			/* enable tuner */
 			int i;
-			static const u8 buffer [][2] = {
-				{0x10,0x12},
-				{0x13,0x04},
-				{0x16,0x00},
-				{0x14,0x04},
-				{0x17,0x00}
+			static const u8 buffer[][2] = {
+				{0x10, 0x12},
+				{0x13, 0x04},
+				{0x16, 0x00},
+				{0x14, 0x04},
+				{0x17, 0x00}
 			};
 			core->i2c_client.addr = 0x0a;
 
 			for (i = 0; i < ARRAY_SIZE(buffer); i++)
 				if (2 != i2c_master_send(&core->i2c_client,
-							buffer[i],2))
+							buffer[i], 2))
 					warn_printk(core, "Unable to enable "
 						    "tuner(%i).\n", i);
 		}
@@ -3547,6 +3586,12 @@ static void cx88_card_setup(struct cx88_core *core)
 		cx_write(MO_SRST_IO, 1);
 		msleep(100);
 		break;
+	case  CX88_BOARD_BST_PS8312:
+		cx_write(MO_GP1_IO, 0x808000);
+		msleep(100);
+		cx_write(MO_GP1_IO, 0x808080);
+		msleep(100);
+		break;
 	} /*end switch() */
 
 
@@ -3653,8 +3698,8 @@ static int cx88_pci_quirks(const char *name, struct pci_dev *pci)
 
 int cx88_get_resources(const struct cx88_core *core, struct pci_dev *pci)
 {
-	if (request_mem_region(pci_resource_start(pci,0),
-			       pci_resource_len(pci,0),
+	if (request_mem_region(pci_resource_start(pci, 0),
+			       pci_resource_len(pci, 0),
 			       core->name))
 		return 0;
 	printk(KERN_ERR
@@ -3728,7 +3773,8 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
 	if (!core->board.num_frontends && (core->board.mpeg & CX88_MPEG_DVB))
 		core->board.num_frontends = 1;
 
-	info_printk(core, "subsystem: %04x:%04x, board: %s [card=%d,%s], frontend(s): %d\n",
+	info_printk(core, "subsystem: %04x:%04x, \
+		board: %s [card=%d,%s], frontend(s): %d\n",
 		pci->subsystem_vendor, pci->subsystem_device, core->board.name,
 		core->boardnr, card[core->nr] == core->boardnr ?
 		"insmod option" : "autodetected",
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 003937c..47cfa7e 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -54,6 +54,8 @@
 #include "stv0288.h"
 #include "stb6000.h"
 #include "cx24116.h"
+#include "m88ts202x.h"
+#include "m88ds3103.h"
 #include "stv0900.h"
 #include "stb6100.h"
 #include "stb6100_proc.h"
@@ -68,7 +70,7 @@ MODULE_VERSION(CX88_VERSION);
 
 static unsigned int debug;
 module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug,"enable debug messages [dvb]");
+MODULE_PARM_DESC(debug, "enable debug messages [dvb]");
 
 static unsigned int dvb_buf_tscnt = 32;
 module_param(dvb_buf_tscnt, int, 0644);
@@ -76,8 +78,8 @@ MODULE_PARM_DESC(dvb_buf_tscnt, "DVB Buffer TS count [dvb]");
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
-#define dprintk(level,fmt, arg...)	if (debug >= level) \
-	printk(KERN_DEBUG "%s/2-dvb: " fmt, core->name, ## arg)
+#define dprintk(level, fmt, arg...)	{if (debug >= level) \
+	printk(KERN_DEBUG "%s/2-dvb: " fmt, core->name, ## arg)}
 
 /* ------------------------------------------------------------------ */
 
@@ -98,19 +100,19 @@ static int dvb_buf_prepare(struct videobuf_queue *q,
 			   struct videobuf_buffer *vb, enum v4l2_field field)
 {
 	struct cx8802_dev *dev = q->priv_data;
-	return cx8802_buf_prepare(q, dev, (struct cx88_buffer*)vb,field);
+	return cx8802_buf_prepare(q, dev, (struct cx88_buffer *)vb, field);
 }
 
 static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
 	struct cx8802_dev *dev = q->priv_data;
-	cx8802_buf_queue(dev, (struct cx88_buffer*)vb);
+	cx8802_buf_queue(dev, (struct cx88_buffer *)vb);
 }
 
 static void dvb_buf_release(struct videobuf_queue *q,
 			    struct videobuf_buffer *vb)
 {
-	cx88_free_buffer(q, (struct cx88_buffer*)vb);
+	cx88_free_buffer(q, (struct cx88_buffer *)vb);
 }
 
 static const struct videobuf_queue_ops dvb_qops = {
@@ -122,9 +124,9 @@ static const struct videobuf_queue_ops dvb_qops = {
 
 /* ------------------------------------------------------------------ */
 
-static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire)
+static int cx88_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
 {
-	struct cx8802_dev *dev= fe->dvb->priv;
+	struct cx8802_dev *dev = fe->dvb->priv;
 	struct cx8802_driver *drv = NULL;
 	int ret = 0;
 	int fe_id;
@@ -138,7 +140,7 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire)
 	mutex_lock(&dev->core->lock);
 	drv = cx8802_get_driver(dev, CX88_MPEG_DVB);
 	if (drv) {
-		if (acquire){
+		if (acquire) {
 			dev->frontends.active_fe_id = fe_id;
 			ret = drv->request_acquire(drv);
 		} else {
@@ -175,13 +177,13 @@ static void cx88_dvb_gate_ctrl(struct cx88_core  *core, int open)
 
 /* ------------------------------------------------------------------ */
 
-static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
+static int dvico_fusionhdtv_demod_init(struct dvb_frontend *fe)
 {
-	static const u8 clock_config []  = { CLOCK_CTL,  0x38, 0x39 };
-	static const u8 reset []         = { RESET,      0x80 };
-	static const u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
-	static const u8 agc_cfg []       = { AGC_TARGET, 0x24, 0x20 };
-	static const u8 gpp_ctl_cfg []   = { GPP_CTL,    0x33 };
+	static const u8 clock_config[]  = { CLOCK_CTL,  0x38, 0x39 };
+	static const u8 reset[]         = { RESET,      0x80 };
+	static const u8 adc_ctl_1_cfg[] = { ADC_CTL_1,  0x40 };
+	static const u8 agc_cfg[]       = { AGC_TARGET, 0x24, 0x20 };
+	static const u8 gpp_ctl_cfg[]   = { GPP_CTL,    0x33 };
 	static const u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
 
 	mt352_write(fe, clock_config,   sizeof(clock_config));
@@ -197,11 +199,11 @@ static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
 
 static int dvico_dual_demod_init(struct dvb_frontend *fe)
 {
-	static const u8 clock_config []  = { CLOCK_CTL,  0x38, 0x38 };
-	static const u8 reset []         = { RESET,      0x80 };
-	static const u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
-	static const u8 agc_cfg []       = { AGC_TARGET, 0x28, 0x20 };
-	static const u8 gpp_ctl_cfg []   = { GPP_CTL,    0x33 };
+	static const u8 clock_config[]  = { CLOCK_CTL,  0x38, 0x38 };
+	static const u8 reset[]         = { RESET,      0x80 };
+	static const u8 adc_ctl_1_cfg[] = { ADC_CTL_1,  0x40 };
+	static const u8 agc_cfg[]       = { AGC_TARGET, 0x28, 0x20 };
+	static const u8 gpp_ctl_cfg[]   = { GPP_CTL,    0x33 };
 	static const u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
 
 	mt352_write(fe, clock_config,   sizeof(clock_config));
@@ -216,12 +218,12 @@ static int dvico_dual_demod_init(struct dvb_frontend *fe)
 	return 0;
 }
 
-static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe)
+static int dntv_live_dvbt_demod_init(struct dvb_frontend *fe)
 {
-	static const u8 clock_config []  = { 0x89, 0x38, 0x39 };
-	static const u8 reset []         = { 0x50, 0x80 };
-	static const u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
-	static const u8 agc_cfg []       = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
+	static const u8 clock_config[]  = { 0x89, 0x38, 0x39 };
+	static const u8 reset[]         = { 0x50, 0x80 };
+	static const u8 adc_ctl_1_cfg[] = { 0x8E, 0x40 };
+	static const u8 agc_cfg[]       = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
 				       0x00, 0xFF, 0x00, 0x40, 0x40 };
 	static const u8 dntv_extra[]     = { 0xB5, 0x7A };
 	static const u8 capt_range_cfg[] = { 0x75, 0x32 };
@@ -264,13 +266,14 @@ static struct mb86a16_config twinhan_vp1027 = {
 	.demod_address  = 0x08,
 };
 
-#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
-static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
+#if defined(CONFIG_VIDEO_CX88_VP3054) || \
+(defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
+static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend *fe)
 {
-	static const u8 clock_config []  = { 0x89, 0x38, 0x38 };
-	static const u8 reset []         = { 0x50, 0x80 };
-	static const u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
-	static const u8 agc_cfg []       = { 0x67, 0x10, 0x20, 0x00, 0xFF, 0xFF,
+	static const u8 clock_config[]  = { 0x89, 0x38, 0x38 };
+	static const u8 reset[]         = { 0x50, 0x80 };
+	static const u8 adc_ctl_1_cfg[] = { 0x8E, 0x40 };
+	static const u8 agc_cfg[]       = { 0x67, 0x10, 0x20, 0x00, 0xFF, 0xFF,
 				       0x00, 0xFF, 0x00, 0x40, 0x40 };
 	static const u8 dntv_extra[]     = { 0xB5, 0x7A };
 	static const u8 capt_range_cfg[] = { 0x75, 0x32 };
@@ -327,9 +330,9 @@ static const struct cx22702_config hauppauge_hvr_config = {
 	.output_mode   = CX22702_SERIAL_OUTPUT,
 };
 
-static int or51132_set_ts_param(struct dvb_frontend* fe, int is_punctured)
+static int or51132_set_ts_param(struct dvb_frontend *fe, int is_punctured)
 {
-	struct cx8802_dev *dev= fe->dvb->priv;
+	struct cx8802_dev *dev = fe->dvb->priv;
 	dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00;
 	return 0;
 }
@@ -339,9 +342,9 @@ static const struct or51132_config pchdtv_hd3000 = {
 	.set_ts_params = or51132_set_ts_param,
 };
 
-static int lgdt330x_pll_rf_set(struct dvb_frontend* fe, int index)
+static int lgdt330x_pll_rf_set(struct dvb_frontend *fe, int index)
 {
-	struct cx8802_dev *dev= fe->dvb->priv;
+	struct cx8802_dev *dev = fe->dvb->priv;
 	struct cx88_core *core = dev->core;
 
 	dprintk(1, "%s: index = %d\n", __func__, index);
@@ -352,9 +355,9 @@ static int lgdt330x_pll_rf_set(struct dvb_frontend* fe, int index)
 	return 0;
 }
 
-static int lgdt330x_set_ts_param(struct dvb_frontend* fe, int is_punctured)
+static int lgdt330x_set_ts_param(struct dvb_frontend *fe, int is_punctured)
 {
-	struct cx8802_dev *dev= fe->dvb->priv;
+	struct cx8802_dev *dev = fe->dvb->priv;
 	if (is_punctured)
 		dev->ts_gen_cntrl |= 0x04;
 	else
@@ -383,9 +386,9 @@ static const struct lgdt330x_config pchdtv_hd5500 = {
 	.set_ts_params = lgdt330x_set_ts_param,
 };
 
-static int nxt200x_set_ts_param(struct dvb_frontend* fe, int is_punctured)
+static int nxt200x_set_ts_param(struct dvb_frontend *fe, int is_punctured)
 {
-	struct cx8802_dev *dev= fe->dvb->priv;
+	struct cx8802_dev *dev = fe->dvb->priv;
 	dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00;
 	return 0;
 }
@@ -395,18 +398,18 @@ static const struct nxt200x_config ati_hdtvwonder = {
 	.set_ts_params = nxt200x_set_ts_param,
 };
 
-static int cx24123_set_ts_param(struct dvb_frontend* fe,
+static int cx24123_set_ts_param(struct dvb_frontend *fe,
 	int is_punctured)
 {
-	struct cx8802_dev *dev= fe->dvb->priv;
+	struct cx8802_dev *dev = fe->dvb->priv;
 	dev->ts_gen_cntrl = 0x02;
 	return 0;
 }
 
-static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe,
+static int kworld_dvbs_100_set_voltage(struct dvb_frontend *fe,
 				       fe_sec_voltage_t voltage)
 {
-	struct cx8802_dev *dev= fe->dvb->priv;
+	struct cx8802_dev *dev = fe->dvb->priv;
 	struct cx88_core *core = dev->core;
 
 	if (voltage == SEC_VOLTAGE_OFF)
@@ -422,11 +425,11 @@ static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe,
 static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe,
 				      fe_sec_voltage_t voltage)
 {
-	struct cx8802_dev *dev= fe->dvb->priv;
+	struct cx8802_dev *dev = fe->dvb->priv;
 	struct cx88_core *core = dev->core;
 
 	if (voltage == SEC_VOLTAGE_OFF) {
-		dprintk(1,"LNB Voltage OFF\n");
+		dprintk(1, "LNB Voltage OFF\n");
 		cx_write(MO_GP0_IO, 0x0000efff);
 	}
 
@@ -438,7 +441,7 @@ static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe,
 static int tevii_dvbs_set_voltage(struct dvb_frontend *fe,
 				      fe_sec_voltage_t voltage)
 {
-	struct cx8802_dev *dev= fe->dvb->priv;
+	struct cx8802_dev *dev = fe->dvb->priv;
 	struct cx88_core *core = dev->core;
 
 	cx_set(MO_GP0_IO, 0x6040);
@@ -458,6 +461,55 @@ static int tevii_dvbs_set_voltage(struct dvb_frontend *fe,
 		return core->prev_set_voltage(fe, voltage);
 	return 0;
 }
+/*CX88_BOARD_BST_PS8312*/
+static int bst_dvbs_set_voltage(struct dvb_frontend *fe,
+				      fe_sec_voltage_t voltage)
+{
+	struct cx8802_dev *dev = fe->dvb->priv;
+	struct cx88_core *core = dev->core;
+
+	cx_write(MO_GP1_IO, 0x111111);
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		cx_write(MO_GP1_IO, 0x020200);
+		break;
+	case SEC_VOLTAGE_18:
+		cx_write(MO_GP1_IO, 0x020202);
+		break;
+	case SEC_VOLTAGE_OFF:
+		cx_write(MO_GP1_IO, 0x111100);
+		break;
+	}
+
+	if (core->prev_set_voltage)
+		return core->prev_set_voltage(fe, voltage);
+	return 0;
+}
+
+static int bst_dvbs_set_voltage_v2(struct dvb_frontend *fe,
+				      fe_sec_voltage_t voltage)
+{
+	struct cx8802_dev *dev = fe->dvb->priv;
+	struct cx88_core *core = dev->core;
+
+	cx_write(MO_GP1_IO, 0x111101);
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		cx_write(MO_GP1_IO, 0x020200);
+		break;
+	case SEC_VOLTAGE_18:
+
+		cx_write(MO_GP1_IO, 0x020202);
+		break;
+	case SEC_VOLTAGE_OFF:
+		cx_write(MO_GP1_IO, 0x111110);
+		break;
+	}
+
+	if (core->prev_set_voltage)
+		return core->prev_set_voltage(fe, voltage);
+	return 0;
+}
 
 static int vp1027_set_voltage(struct dvb_frontend *fe,
 				    fe_sec_voltage_t voltage)
@@ -700,6 +752,17 @@ static struct ds3000_config tevii_ds3000_config = {
 	.set_ts_params = ds3000_set_ts_param,
 };
 
+static struct m88ts202x_config dvbsky_ts202x_config = {
+	.bypasson = 0,
+	.clkout = 0,
+	.clkdiv = 0,
+};
+
+static struct m88ds3103_config dvbsky_ds3103_config = {
+	.demod_address = 0x68,
+	.set_ts_params = ds3000_set_ts_param,
+};
+
 static const struct stv0900_config prof_7301_stv0900_config = {
 	.demod_address = 0x6a,
 /*	demod_mode = 0,*/
@@ -949,6 +1012,51 @@ static const struct stv0299_config samsung_stv0299_config = {
 	.set_symbol_rate = samsung_smt_7020_stv0299_set_symbol_rate,
 };
 
+static struct dvb_frontend *dvbsky_pci_frontend_attach(
+					struct m88ds3103_config *pdconf,
+					struct m88ts202x_config *ptconf,
+					struct i2c_adapter *i2c)
+{
+	struct dvb_frontend *fe;
+	struct m88ts202x_devctl *ctrl;
+	int ret;
+	u8 b0[] = { 0x60 };
+	u8 b1[2] = { 0 };
+	struct i2c_msg msg[] = {
+			{
+			.addr = 0x50,
+			.flags = 0,
+			.buf = b0,
+			.len = 1
+			}, {
+			.addr = 0x50,
+			.flags = I2C_M_RD,
+			.buf = b1,
+			.len = 2
+			}
+		};
+	fe = dvb_attach(m88ds3103_attach, pdconf, i2c);
+	if (!fe)
+		return NULL;
+	ctrl = dvb_attach(m88ts202x_attach, fe, ptconf, i2c);
+	if (ctrl) {
+		pdconf->tuner_init = ctrl->tuner_init;
+		pdconf->tuner_sleep = ctrl->tuner_sleep;
+		pdconf->tuner_wakeup = ctrl->tuner_wakeup;
+		pdconf->tuner_set_frequency = ctrl->tuner_set_frequency;
+		pdconf->tuner_get_rfgain = ctrl->tuner_get_rfgain;
+	}
+
+	ret = i2c_transfer(i2c, msg, 2);
+	printk(KERN_INFO "PS8312: config = %02x, %02x", b1[0], b1[1]);
+	if (b1[0] == 0xaa)
+		fe->ops.set_voltage = bst_dvbs_set_voltage_v2;
+	else
+		fe->ops.set_voltage = bst_dvbs_set_voltage;
+
+	return	fe;
+}
+
 static int dvb_register(struct cx8802_dev *dev)
 {
 	struct cx88_core *core = dev->core;
@@ -957,7 +1065,8 @@ static int dvb_register(struct cx8802_dev *dev)
 	int res = -EINVAL;
 
 	if (0 != core->i2c_rc) {
-		printk(KERN_ERR "%s/2: no i2c-bus available, cannot attach dvb drivers\n", core->name);
+		printk(KERN_ERR "%s/2: no i2c-bus available,"
+				" cannot attach dvb drivers\n", core->name);
 		goto frontend_detach;
 	}
 
@@ -1121,10 +1230,12 @@ static int dvb_register(struct cx8802_dev *dev)
 		}
 		break;
 	case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
-#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
+#if defined(CONFIG_VIDEO_CX88_VP3054) || \
+(defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
 		/* MT352 is on a secondary I2C bus made from some GPIO lines */
-		fe0->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
-					       &dev->vp3054->adap);
+		fe0->dvb.frontend = dvb_attach(mt352_attach,
+						&dntv_live_dvbt_pro_config,
+						&dev->vp3054->adap);
 		if (fe0->dvb.frontend != NULL) {
 			if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
 					&core->i2c_adap, 0x61,
@@ -1274,7 +1385,7 @@ static int dvb_register(struct cx8802_dev *dev)
 					       &core->i2c_adap);
 		if (fe0->dvb.frontend) {
 			if (!dvb_attach(isl6421_attach, fe0->dvb.frontend,
-					&core->i2c_adap, 0x08, ISL6421_DCL, 0x00))
+				&core->i2c_adap, 0x08, ISL6421_DCL, 0x00))
 				goto frontend_detach;
 		}
 		break;
@@ -1283,8 +1394,10 @@ static int dvb_register(struct cx8802_dev *dev)
 					       &kworld_dvbs_100_config,
 					       &core->i2c_adap);
 		if (fe0->dvb.frontend) {
-			core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
-			fe0->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
+			core->prev_set_voltage =
+					fe0->dvb.frontend->ops.set_voltage;
+			fe0->dvb.frontend->ops.set_voltage =
+						kworld_dvbs_100_set_voltage;
 		}
 		break;
 	case CX88_BOARD_GENIATECH_DVBS:
@@ -1292,8 +1405,10 @@ static int dvb_register(struct cx8802_dev *dev)
 					       &geniatech_dvbs_config,
 					       &core->i2c_adap);
 		if (fe0->dvb.frontend) {
-			core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
-			fe0->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
+			core->prev_set_voltage =
+				fe0->dvb.frontend->ops.set_voltage;
+			fe0->dvb.frontend->ops.set_voltage =
+						geniatech_dvbs_set_voltage;
 		}
 		break;
 	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
@@ -1439,19 +1554,24 @@ static int dvb_register(struct cx8802_dev *dev)
 			if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60,
 					&core->i2c_adap, DVB_PLL_OPERA1))
 				goto frontend_detach;
-			core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
-			fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+			core->prev_set_voltage =
+					fe0->dvb.frontend->ops.set_voltage;
+			fe0->dvb.frontend->ops.set_voltage =
+							tevii_dvbs_set_voltage;
 
 		} else {
 			fe0->dvb.frontend = dvb_attach(stv0288_attach,
-							    &tevii_tuner_earda_config,
+						&tevii_tuner_earda_config,
 							    &core->i2c_adap);
 				if (fe0->dvb.frontend != NULL) {
-					if (!dvb_attach(stb6000_attach, fe0->dvb.frontend, 0x61,
+					if (!dvb_attach(stb6000_attach,
+						fe0->dvb.frontend, 0x61,
 						&core->i2c_adap))
-					goto frontend_detach;
-				core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
-				fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+						goto frontend_detach;
+				core->prev_set_voltage =
+					fe0->dvb.frontend->ops.set_voltage;
+				fe0->dvb.frontend->ops.set_voltage =
+							tevii_dvbs_set_voltage;
 			}
 		}
 		break;
@@ -1460,7 +1580,8 @@ static int dvb_register(struct cx8802_dev *dev)
 					       &tevii_s460_config,
 					       &core->i2c_adap);
 		if (fe0->dvb.frontend != NULL)
-			fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+			fe0->dvb.frontend->ops.set_voltage =
+						tevii_dvbs_set_voltage;
 		break;
 	case CX88_BOARD_TEVII_S464:
 		fe0->dvb.frontend = dvb_attach(ds3000_attach,
@@ -1470,6 +1591,12 @@ static int dvb_register(struct cx8802_dev *dev)
 			fe0->dvb.frontend->ops.set_voltage =
 							tevii_dvbs_set_voltage;
 		break;
+	case CX88_BOARD_BST_PS8312:
+		fe0->dvb.frontend = dvbsky_pci_frontend_attach(
+						&dvbsky_ds3103_config,
+						&dvbsky_ts202x_config,
+						&core->i2c_adap);
+		break;
 	case CX88_BOARD_OMICOM_SS4_PCI:
 	case CX88_BOARD_TBS_8920:
 	case CX88_BOARD_PROF_7300:
@@ -1478,11 +1605,12 @@ static int dvb_register(struct cx8802_dev *dev)
 					       &hauppauge_hvr4000_config,
 					       &core->i2c_adap);
 		if (fe0->dvb.frontend != NULL)
-			fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+			fe0->dvb.frontend->ops.set_voltage =
+						tevii_dvbs_set_voltage;
 		break;
 	case CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII:
 		fe0->dvb.frontend = dvb_attach(zl10353_attach,
-					       &cx88_terratec_cinergy_ht_pci_mkii_config,
+				&cx88_terratec_cinergy_ht_pci_mkii_config,
 					       &core->i2c_adap);
 		if (fe0->dvb.frontend) {
 			fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
@@ -1559,7 +1687,7 @@ static int dvb_register(struct cx8802_dev *dev)
 		break;
 	}
 
-	if ( (NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend) ) {
+	if ((NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend)) {
 		printk(KERN_ERR
 		       "%s/2: frontend initialization failed\n",
 		       core->name);
@@ -1596,7 +1724,7 @@ static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv)
 {
 	struct cx88_core *core = drv->core;
 	int err = 0;
-	dprintk( 1, "%s\n", __func__);
+	dprintk(1, "%s\n", __func__);
 
 	switch (core->boardnr) {
 	case CX88_BOARD_HAUPPAUGE_HVR1300:
@@ -1660,7 +1788,7 @@ static int cx8802_dvb_advise_release(struct cx8802_driver *drv)
 {
 	struct cx88_core *core = drv->core;
 	int err = 0;
-	dprintk( 1, "%s\n", __func__);
+	dprintk(1, "%s\n", __func__);
 
 	switch (core->boardnr) {
 	case CX88_BOARD_HAUPPAUGE_HVR1300:
@@ -1683,8 +1811,8 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
 	struct videobuf_dvb_frontend *fe;
 	int i;
 
-	dprintk( 1, "%s\n", __func__);
-	dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
+	dprintk(1, "%s\n", __func__);
+	dprintk(1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
 		core->boardnr,
 		core->name,
 		core->pci_bus,
@@ -1742,7 +1870,7 @@ static int cx8802_dvb_remove(struct cx8802_driver *drv)
 	struct cx88_core *core = drv->core;
 	struct cx8802_dev *dev = drv->core->dvbdev;
 
-	dprintk( 1, "%s\n", __func__);
+	dprintk(1, "%s\n", __func__);
 
 	videobuf_dvb_unregister_bus(&dev->frontends);
 
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index ebf448c..9b0559b 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -96,7 +96,7 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
 
 		auxgpio = cx_read(MO_GP1_IO);
 		/* Take out the parity part */
-		gpio=(gpio & 0x7fd) + (auxgpio & 0xef);
+		gpio = (gpio & 0x7fd) + (auxgpio & 0xef);
 		break;
 	case CX88_BOARD_WINFAST_DTV1000:
 	case CX88_BOARD_WINFAST_DTV1800H:
@@ -332,7 +332,8 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
 		ir->gpio_addr = MO_GP1_IO;
 		ir->mask_keyup = 0x80;
 		ir->polling = 10; /* ms */
-		hardware_mask = 0x3f;	/* Hardware returns only 6 bits from command part */
+		hardware_mask = 0x3f;
+		/* Hardware returns only 6 bits from command part */
 		break;
 	case CX88_BOARD_PROLINK_PV_8000GT:
 	case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME:
@@ -419,6 +420,10 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
 		rc_type          = RC_TYPE_NEC;
 		ir->sampling     = 0xff00; /* address */
 		break;
+	case CX88_BOARD_BST_PS8312:
+		ir_codes         = RC_MAP_DVBSKY;
+		ir->sampling     = 0xff00; /* address */
+		break;
 	}
 
 	if (!ir_codes) {
@@ -614,7 +619,8 @@ void cx88_i2c_init_ir(struct cx88_core *core)
 			core->init_data.name = "cx88 Hauppauge XVR remote";
 			core->init_data.ir_codes = RC_MAP_HAUPPAUGE;
 			core->init_data.type = RC_TYPE_RC5;
-			core->init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
+			core->init_data.internal_get_key_func =
+							IR_KBD_GET_KEY_HAUP_XVR;
 
 			info.platform_data = &core->init_data;
 		}
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index c9659de..c423b16 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -93,13 +93,13 @@ enum cx8802_board_access {
 /* ----------------------------------------------------------- */
 /* tv norms                                                    */
 
-static unsigned int inline norm_maxw(v4l2_std_id norm)
+static inline unsigned int norm_maxw(v4l2_std_id norm)
 {
 	return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
 }
 
 
-static unsigned int inline norm_maxh(v4l2_std_id norm)
+static inline unsigned int norm_maxh(v4l2_std_id norm)
 {
 	return (norm & V4L2_STD_625_50) ? 576 : 480;
 }
@@ -246,6 +246,7 @@ extern const struct sram_channel const cx88_sram_channels[];
 #define CX88_BOARD_WINFAST_DTV1800H_XC4000 88
 #define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36 89
 #define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43 90
+#define CX88_BOARD_BST_PS8312              91
 
 enum cx88_itype {
 	CX88_VMUX_COMPOSITE1 = 1,
@@ -368,9 +369,11 @@ struct cx88_core {
 
 	/* config info -- dvb */
 #if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
-	int 			   (*prev_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
+	int			(*prev_set_voltage)(struct dvb_frontend *fe,
+						fe_sec_voltage_t voltage);
 #endif
-	void			   (*gate_ctrl)(struct cx88_core  *core, int open);
+	void			(*gate_ctrl)(struct cx88_core  *core,
+						int open);
 
 	/* state info */
 	struct task_struct         *kthread;
@@ -416,7 +419,8 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev)
 		if (!core->i2c_rc) {				\
 			if (core->gate_ctrl)			\
 				core->gate_ctrl(core, 1);	\
-			v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \
+			v4l2_device_call_all(&core->v4l2_dev, \
+					grpid, o, f, ##args); \
 			if (core->gate_ctrl)			\
 				core->gate_ctrl(core, 0);	\
 		}						\
@@ -443,7 +447,7 @@ struct cx8800_fh {
 
 	/* video capture */
 	const struct cx8800_fmt    *fmt;
-	unsigned int               width,height;
+	unsigned int               width, height;
 	struct videobuf_queue      vidq;
 
 	/* vbi capture */
@@ -466,7 +470,7 @@ struct cx8800_dev {
 
 	/* pci i/o */
 	struct pci_dev             *pci;
-	unsigned char              pci_rev,pci_lat;
+	unsigned char              pci_rev, pci_lat;
 
 
 	/* capture queues */
@@ -531,7 +535,7 @@ struct cx8802_dev {
 
 	/* pci i/o */
 	struct pci_dev             *pci;
-	unsigned char              pci_rev,pci_lat;
+	unsigned char              pci_rev, pci_lat;
 
 	/* dma queues */
 	struct cx88_dmaqueue       mpegq;
@@ -549,7 +553,8 @@ struct cx8802_dev {
 	u32                        mailbox;
 	int                        width;
 	int                        height;
-	unsigned char              mpeg_active; /* nonzero if mpeg encoder is active */
+	unsigned char              mpeg_active;
+		/* nonzero if mpeg encoder is active */
 
 	/* mpeg params */
 	struct cx2341x_mpeg_params params;
@@ -577,30 +582,31 @@ struct cx8802_dev {
 /* ----------------------------------------------------------- */
 
 #define cx_read(reg)             readl(core->lmmio + ((reg)>>2))
-#define cx_write(reg,value)      writel((value), core->lmmio + ((reg)>>2))
-#define cx_writeb(reg,value)     writeb((value), core->bmmio + (reg))
+#define cx_write(reg, value)      writel((value), core->lmmio + ((reg)>>2))
+#define cx_writeb(reg, value)     writeb((value), core->bmmio + (reg))
 
-#define cx_andor(reg,mask,value) \
+#define cx_andor(reg, mask, value) \
   writel((readl(core->lmmio+((reg)>>2)) & ~(mask)) |\
   ((value) & (mask)), core->lmmio+((reg)>>2))
-#define cx_set(reg,bit)          cx_andor((reg),(bit),(bit))
-#define cx_clear(reg,bit)        cx_andor((reg),(bit),0)
+#define cx_set(reg, bit)          cx_andor((reg), (bit), (bit))
+#define cx_clear(reg, bit)        cx_andor((reg), (bit), 0)
 
 #define cx_wait(d) { if (need_resched()) schedule(); else udelay(d); }
 
 /* shadow registers */
 #define cx_sread(sreg)		    (core->shadow[sreg])
-#define cx_swrite(sreg,reg,value) \
+#define cx_swrite(sreg, reg, value) \
   (core->shadow[sreg] = value, \
    writel(core->shadow[sreg], core->lmmio + ((reg)>>2)))
-#define cx_sandor(sreg,reg,mask,value) \
+#define cx_sandor(sreg, reg, mask, value) \
   (core->shadow[sreg] = (core->shadow[sreg] & ~(mask)) | ((value) & (mask)), \
    writel(core->shadow[sreg], core->lmmio + ((reg)>>2)))
 
 /* ----------------------------------------------------------- */
 /* cx88-core.c                                                 */
 
-extern void cx88_print_irqbits(const char *name, const char *tag, const char *strings[],
+extern void cx88_print_irqbits(const char *name, const char *tag,
+				const char *strings[],
 			       int len, u32 bits, u32 mask);
 
 extern int cx88_core_irq(struct cx88_core *core, u32 status);
@@ -640,7 +646,7 @@ extern struct video_device *cx88_vdev_init(struct cx88_core *core,
 					   struct pci_dev *pci,
 					   const struct video_device *template_,
 					   const char *type);
-extern struct cx88_core* cx88_core_get(struct pci_dev *pci);
+extern struct cx88_core *cx88_core_get(struct pci_dev *pci);
 extern void cx88_core_put(struct cx88_core *core,
 			  struct pci_dev *pci);
 
@@ -652,7 +658,7 @@ extern int cx88_stop_audio_dma(struct cx88_core *core);
 /* cx88-vbi.c                                                  */
 
 /* Can be used as g_vbi_fmt, try_vbi_fmt and s_vbi_fmt */
-int cx8800_vbi_fmt (struct file *file, void *priv,
+int cx8800_vbi_fmt(struct file *file, void *priv,
 					struct v4l2_format *f);
 
 /*
@@ -695,7 +701,8 @@ int cx8802_register_driver(struct cx8802_driver *drv);
 int cx8802_unregister_driver(struct cx8802_driver *drv);
 
 /* Caller must hold core->lock */
-struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype);
+struct cx8802_driver *cx8802_get_driver(struct cx8802_dev *dev,
+					enum cx88_board_type btype);
 
 /* ----------------------------------------------------------- */
 /* cx88-dsp.c                                                  */
@@ -715,7 +722,7 @@ extern void cx88_i2c_init_ir(struct cx88_core *core);
 /* ----------------------------------------------------------- */
 /* cx88-mpeg.c                                                 */
 
-int cx8802_buf_prepare(struct videobuf_queue *q,struct cx8802_dev *dev,
+int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev,
 			struct cx88_buffer *buf, enum v4l2_field field);
 void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf);
 void cx8802_cancel_buffers(struct cx8802_dev *dev);
@@ -725,8 +732,8 @@ void cx8802_cancel_buffers(struct cx8802_dev *dev);
 extern const u32 cx88_user_ctrls[];
 extern int cx8800_ctrl_query(struct cx88_core *core,
 			     struct v4l2_queryctrl *qctrl);
-int cx88_enum_input (struct cx88_core  *core,struct v4l2_input *i);
-int cx88_set_freq (struct cx88_core  *core,struct v4l2_frequency *f);
+int cx88_enum_input(struct cx88_core  *core, struct v4l2_input *i);
+int cx88_set_freq(struct cx88_core  *core, struct v4l2_frequency *f);
 int cx88_get_control(struct cx88_core *core, struct v4l2_control *ctl);
 int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl);
 int cx88_video_mux(struct cx88_core *core, unsigned int input);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 5/6 v2] dvbsky, remote control key map
  2012-04-26 13:24                 ` Mauro Carvalho Chehab
                                     ` (3 preceding siblings ...)
  2012-04-27  7:07                   ` [PATCH 4/6 v2] dvbsky, dvb-s/s2 PCI card nibble.max
@ 2012-04-27  7:07                   ` nibble.max
  2012-04-27  7:07                   ` [PATCH 6/6 v2] dvbsky, remote control include header file nibble.max
  5 siblings, 0 replies; 56+ messages in thread
From: nibble.max @ 2012-04-27  7:07 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Antti Palosaari, linux-media

---
 drivers/media/rc/keymaps/Makefile    |    1 +
 drivers/media/rc/keymaps/rc-dvbsky.c |   77 ++++++++++++++++++++++++++++++++++
 2 files changed, 78 insertions(+)
 create mode 100644 drivers/media/rc/keymaps/rc-dvbsky.c

diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index 49ce266..e6a882b 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
 			rc-dm1105-nec.o \
 			rc-dntv-live-dvb-t.o \
 			rc-dntv-live-dvbt-pro.o \
+			rc-dvbsky.o \
 			rc-em-terratec.o \
 			rc-encore-enltv2.o \
 			rc-encore-enltv.o \
diff --git a/drivers/media/rc/keymaps/rc-dvbsky.c b/drivers/media/rc/keymaps/rc-dvbsky.c
new file mode 100644
index 0000000..25a531c
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-dvbsky.c
@@ -0,0 +1,77 @@
+/* rc-dvbsky.c - Keytable for Dvbsky Remote Controllers
+ *
+ *
+ *
+ *   Copyright (C) 2011 Max nibble<nibble.max@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+/*
+ * This table contains the complete RC5 code, instead of just the data part
+ */
+
+static struct rc_map_table rc5_dvbsky[] = {
+	{ 0x0000, KEY_0 },
+	{ 0x0001, KEY_1 },
+	{ 0x0002, KEY_2 },
+	{ 0x0003, KEY_3 },
+	{ 0x0004, KEY_4 },
+	{ 0x0005, KEY_5 },
+	{ 0x0006, KEY_6 },
+	{ 0x0007, KEY_7 },
+	{ 0x0008, KEY_8 },
+	{ 0x0009, KEY_9 },
+	{ 0x000a, KEY_MUTE },
+	{ 0x000d, KEY_OK },
+	{ 0x000b, KEY_STOP },
+	{ 0x000c, KEY_EXIT },
+	{ 0x000e, KEY_CAMERA }, /*Snap shot*/
+	{ 0x000f, KEY_SUBTITLE }, /*PIP*/
+	{ 0x0010, KEY_VOLUMEUP },
+	{ 0x0011, KEY_VOLUMEDOWN },
+	{ 0x0012, KEY_FAVORITES },
+	{ 0x0013, KEY_LIST }, /*Info*/
+	{ 0x0016, KEY_PAUSE },
+	{ 0x0017, KEY_PLAY },
+	{ 0x001f, KEY_RECORD },
+	{ 0x0020, KEY_CHANNELDOWN },
+	{ 0x0021, KEY_CHANNELUP },
+	{ 0x0025, KEY_POWER2 },
+	{ 0x0026, KEY_REWIND },
+	{ 0x0027, KEY_FASTFORWARD },
+	{ 0x0029, KEY_LAST },
+	{ 0x002b, KEY_MENU },
+	{ 0x002c, KEY_EPG },
+	{ 0x002d, KEY_ZOOM },
+};
+
+static struct rc_map_list rc5_dvbsky_map = {
+	.map = {
+		.scan    = rc5_dvbsky,
+		.size    = ARRAY_SIZE(rc5_dvbsky),
+		.rc_type = RC_TYPE_RC5,
+		.name    = RC_MAP_DVBSKY,
+	}
+};
+
+static int __init init_rc_map_rc5_dvbsky(void)
+{
+	return rc_map_register(&rc5_dvbsky_map);
+}
+
+static void __exit exit_rc_map_rc5_dvbsky(void)
+{
+	rc_map_unregister(&rc5_dvbsky_map);
+}
+
+module_init(init_rc_map_rc5_dvbsky)
+module_exit(exit_rc_map_rc5_dvbsky)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Max nibble <nibble.max@gmail.com>");
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 6/6 v2] dvbsky, remote control include header file
  2012-04-26 13:24                 ` Mauro Carvalho Chehab
                                     ` (4 preceding siblings ...)
  2012-04-27  7:07                   ` [PATCH 5/6 v2] dvbsky, remote control key map nibble.max
@ 2012-04-27  7:07                   ` nibble.max
  5 siblings, 0 replies; 56+ messages in thread
From: nibble.max @ 2012-04-27  7:07 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Antti Palosaari, linux-media

---
 include/media/rc-map.h |    1 +
 1 file changed, 1 insertion(+)

diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 8db6741..7176dac 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -85,6 +85,7 @@ void rc_map_init(void);
 #define RC_MAP_DM1105_NEC                "rc-dm1105-nec"
 #define RC_MAP_DNTV_LIVE_DVBT_PRO        "rc-dntv-live-dvbt-pro"
 #define RC_MAP_DNTV_LIVE_DVB_T           "rc-dntv-live-dvb-t"
+#define RC_MAP_DVBSKY                    "rc-dvbsky"
 #define RC_MAP_EMPTY                     "rc-empty"
 #define RC_MAP_EM_TERRATEC               "rc-em-terratec"
 #define RC_MAP_ENCORE_ENLTV2             "rc-encore-enltv2"
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6 v2] dvbsky, montage dvb-s/s2 TS202x tuner and M88DS3103 demodulator driver
  2012-04-27  7:06                   ` [PATCH 1/6 v2] dvbsky, montage dvb-s/s2 TS202x tuner and M88DS3103 " nibble.max
@ 2012-04-27 11:06                     ` Mauro Carvalho Chehab
  2012-04-27 14:17                     ` Re: [PATCH 1/6 v2] dvbsky, montage dvb-s/s2 TS202x tuner and M88DS3103demodulator driver nibble.max
  1 sibling, 0 replies; 56+ messages in thread
From: Mauro Carvalho Chehab @ 2012-04-27 11:06 UTC (permalink / raw)
  To: nibble.max; +Cc: Antti Palosaari, linux-media, Konstantin Dimitrov

Em 27-04-2012 04:06, nibble.max escreveu:
> ---
>  drivers/media/dvb/frontends/Kconfig          |   14 +
>  drivers/media/dvb/frontends/Makefile         |    3 +
>  drivers/media/dvb/frontends/m88ds3103.c      | 1153 ++++++++++++++++++++++++++
>  drivers/media/dvb/frontends/m88ds3103.h      |   67 ++
>  drivers/media/dvb/frontends/m88ds3103_priv.h |  413 +++++++++
>  drivers/media/dvb/frontends/m88ts202x.c      |  590 +++++++++++++
>  drivers/media/dvb/frontends/m88ts202x.h      |   63 ++
>  7 files changed, 2303 insertions(+)
>  create mode 100644 drivers/media/dvb/frontends/m88ds3103.c
>  create mode 100644 drivers/media/dvb/frontends/m88ds3103.h
>  create mode 100644 drivers/media/dvb/frontends/m88ds3103_priv.h
>  create mode 100644 drivers/media/dvb/frontends/m88ts202x.c
>  create mode 100644 drivers/media/dvb/frontends/m88ts202x.h

No, this is not what we've agreed. You should, instead, take Konstantin's driver, 
breaking it into two separate ones, without touching the copyrights. Then, apply
what else is needed for ds3103/ts2123.

> diff --git a/drivers/media/dvb/frontends/m88ds3103.c b/drivers/media/dvb/frontends/m88ds3103.c
> new file mode 100644
> index 0000000..392cada
> --- /dev/null
> +++ b/drivers/media/dvb/frontends/m88ds3103.c
> @@ -0,0 +1,1153 @@
> +/*
> +    Montage Technology M88DS3103/3000 - DVBS/S2 Satellite demod driver
> +
> +    Copyright (C) 2011 Max nibble<nibble.max@gmail.com>

Adding your copyright like that only justifies if you make significant contributions
to the code. Adding support for a new card or a new chip within the same chip family
in general don't fit on that. 

If Konstantin is ok, you may, instead, add, at the bottom of the copyright list, something like:

    Copyright (C) 2011 Max nibble<nibble.max@gmail.com>
		- Add support for ds3103

> +    Copyright (C) 2010 Montage Technology<www.montage-tech.com>
> +    Fix some bug and add M88DS3103 code, M88DS3000 code based on DS3000.c.
> +
> +    Copyright (C) 2009 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
> +
> +    Copyright (C) 2009 TurboSight.com

Regards,
Mauro

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Re: [PATCH 1/6 v2] dvbsky, montage dvb-s/s2 TS202x tuner and M88DS3103demodulator driver
  2012-04-27  7:06                   ` [PATCH 1/6 v2] dvbsky, montage dvb-s/s2 TS202x tuner and M88DS3103 " nibble.max
  2012-04-27 11:06                     ` Mauro Carvalho Chehab
@ 2012-04-27 14:17                     ` nibble.max
  2012-04-27 14:35                       ` Mauro Carvalho Chehab
  1 sibling, 1 reply; 56+ messages in thread
From: nibble.max @ 2012-04-27 14:17 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Antti Palosaari, linux-media, Konstantin Dimitrov

2012-04-27 22:03:20 nibble.max@gmail.com
>Em 27-04-2012 04:06, nibble.max escreveu:
>> ---
>>  drivers/media/dvb/frontends/Kconfig          |   14 +
>>  drivers/media/dvb/frontends/Makefile         |    3 +
>>  drivers/media/dvb/frontends/m88ds3103.c      | 1153 ++++++++++++++++++++++++++
>>  drivers/media/dvb/frontends/m88ds3103.h      |   67 ++
>>  drivers/media/dvb/frontends/m88ds3103_priv.h |  413 +++++++++
>>  drivers/media/dvb/frontends/m88ts202x.c      |  590 +++++++++++++
>>  drivers/media/dvb/frontends/m88ts202x.h      |   63 ++
>>  7 files changed, 2303 insertions(+)
>>  create mode 100644 drivers/media/dvb/frontends/m88ds3103.c
>>  create mode 100644 drivers/media/dvb/frontends/m88ds3103.h
>>  create mode 100644 drivers/media/dvb/frontends/m88ds3103_priv.h
>>  create mode 100644 drivers/media/dvb/frontends/m88ts202x.c
>>  create mode 100644 drivers/media/dvb/frontends/m88ts202x.h
>
>No, this is not what we've agreed. You should, instead, take Konstantin's driver, 
>breaking it into two separate ones, without touching the copyrights. Then, apply
>what else is needed for ds3103/ts2123.
Hello Mauro,

Should I need Konstantin's agreement to do that?
Using the seperate tuner and demod, I need to change the codes which use the ds3000 frontend.
How can I test the code to confirm that these codes are right without these hardwards?

If I can not do this work, the new m88ds3103 and m88ts2022 code can not be patched in the upstream.
It seems i go to a dead lock, doesn't it?

Br,
Max
>
>> diff --git a/drivers/media/dvb/frontends/m88ds3103.c b/drivers/media/dvb/frontends/m88ds3103.c
>> new file mode 100644
>> index 0000000..392cada
>> --- /dev/null
>> +++ b/drivers/media/dvb/frontends/m88ds3103.c
>> @@ -0,0 +1,1153 @@
>> +/*
>> +    Montage Technology M88DS3103/3000 - DVBS/S2 Satellite demod driver
>> +
>> +    Copyright (C) 2011 Max nibble<nibble.max@gmail.com>
>
>Adding your copyright like that only justifies if you make significant contributions
>to the code. Adding support for a new card or a new chip within the same chip family
>in general don't fit on that. 
>
>If Konstantin is ok, you may, instead, add, at the bottom of the copyright list, something like:
>
>    Copyright (C) 2011 Max nibble<nibble.max@gmail.com>
>		- Add support for ds3103
>
>> +    Copyright (C) 2010 Montage Technology<www.montage-tech.com>
>> +    Fix some bug and add M88DS3103 code, M88DS3000 code based on DS3000.c.
>> +
>> +    Copyright (C) 2009 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
>> +
>> +    Copyright (C) 2009 TurboSight.com
>
>Regards,
>Mauro


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6 v2] dvbsky, montage dvb-s/s2 TS202x tuner and M88DS3103demodulator driver
  2012-04-27 14:17                     ` Re: [PATCH 1/6 v2] dvbsky, montage dvb-s/s2 TS202x tuner and M88DS3103demodulator driver nibble.max
@ 2012-04-27 14:35                       ` Mauro Carvalho Chehab
  2012-04-27 18:03                         ` Konstantin Dimitrov
  0 siblings, 1 reply; 56+ messages in thread
From: Mauro Carvalho Chehab @ 2012-04-27 14:35 UTC (permalink / raw)
  To: nibble.max; +Cc: Antti Palosaari, linux-media, Konstantin Dimitrov

Em 27-04-2012 11:17, nibble.max escreveu:
> 2012-04-27 22:03:20 nibble.max@gmail.com
>> Em 27-04-2012 04:06, nibble.max escreveu:
>>> ---
>>>  drivers/media/dvb/frontends/Kconfig          |   14 +
>>>  drivers/media/dvb/frontends/Makefile         |    3 +
>>>  drivers/media/dvb/frontends/m88ds3103.c      | 1153 ++++++++++++++++++++++++++
>>>  drivers/media/dvb/frontends/m88ds3103.h      |   67 ++
>>>  drivers/media/dvb/frontends/m88ds3103_priv.h |  413 +++++++++
>>>  drivers/media/dvb/frontends/m88ts202x.c      |  590 +++++++++++++
>>>  drivers/media/dvb/frontends/m88ts202x.h      |   63 ++
>>>  7 files changed, 2303 insertions(+)
>>>  create mode 100644 drivers/media/dvb/frontends/m88ds3103.c
>>>  create mode 100644 drivers/media/dvb/frontends/m88ds3103.h
>>>  create mode 100644 drivers/media/dvb/frontends/m88ds3103_priv.h
>>>  create mode 100644 drivers/media/dvb/frontends/m88ts202x.c
>>>  create mode 100644 drivers/media/dvb/frontends/m88ts202x.h
>>
>> No, this is not what we've agreed. You should, instead, take Konstantin's driver, 
>> breaking it into two separate ones, without touching the copyrights. Then, apply
>> what else is needed for ds3103/ts2123.
> Hello Mauro,
> 
> Should I need Konstantin's agreement to do that?

While the driver is GPLv2, he is the author of the driver. GPL is not copyleft. You can't simply
decide to change the copyrights.

> Using the seperate tuner and demod, I need to change the codes which use the ds3000 frontend.
> How can I test the code to confirm that these codes are right without these hardwards?

Well, at the split patch, you shouldn't do anything but to split tuner and demod. This will
make easier for others to test, if you don't have the hardware for testing.

Regards,
Mauro

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6 v2] dvbsky, montage dvb-s/s2 TS202x tuner and M88DS3103demodulator driver
  2012-04-27 14:35                       ` Mauro Carvalho Chehab
@ 2012-04-27 18:03                         ` Konstantin Dimitrov
  0 siblings, 0 replies; 56+ messages in thread
From: Konstantin Dimitrov @ 2012-04-27 18:03 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: nibble.max, Antti Palosaari, linux-media

On Fri, Apr 27, 2012 at 5:35 PM, Mauro Carvalho Chehab
<mchehab@redhat.com> wrote:
> Em 27-04-2012 11:17, nibble.max escreveu:
>> 2012-04-27 22:03:20 nibble.max@gmail.com
>>> Em 27-04-2012 04:06, nibble.max escreveu:
>>>> ---
>>>>  drivers/media/dvb/frontends/Kconfig          |   14 +
>>>>  drivers/media/dvb/frontends/Makefile         |    3 +
>>>>  drivers/media/dvb/frontends/m88ds3103.c      | 1153 ++++++++++++++++++++++++++
>>>>  drivers/media/dvb/frontends/m88ds3103.h      |   67 ++
>>>>  drivers/media/dvb/frontends/m88ds3103_priv.h |  413 +++++++++
>>>>  drivers/media/dvb/frontends/m88ts202x.c      |  590 +++++++++++++
>>>>  drivers/media/dvb/frontends/m88ts202x.h      |   63 ++
>>>>  7 files changed, 2303 insertions(+)
>>>>  create mode 100644 drivers/media/dvb/frontends/m88ds3103.c
>>>>  create mode 100644 drivers/media/dvb/frontends/m88ds3103.h
>>>>  create mode 100644 drivers/media/dvb/frontends/m88ds3103_priv.h
>>>>  create mode 100644 drivers/media/dvb/frontends/m88ts202x.c
>>>>  create mode 100644 drivers/media/dvb/frontends/m88ts202x.h
>>>
>>> No, this is not what we've agreed. You should, instead, take Konstantin's driver,
>>> breaking it into two separate ones, without touching the copyrights. Then, apply
>>> what else is needed for ds3103/ts2123.
>> Hello Mauro,
>>
>> Should I need Konstantin's agreement to do that?
>
> While the driver is GPLv2, he is the author of the driver. GPL is not copyleft. You can't simply
> decide to change the copyrights.
>

Mauro, well said and thanks for standing up and defending the open-source.

so, "m88ds3103" in it's current version is just combination of using
shuffling of my "ds3000" code plus using copyrighted code by Montage
Technologies - the last is even another reason why "m88ds3103" can't
be accepted, because then actually Montage Technologies should be
listed in the copyright and wait for their approval.

let me give example what i mean - let's take ToneBurst function as
example -  m88ds3103_diseqc_send_burst() - at the current version of
"m88ds3103" it's exactly the same code as the one from the reference
code copyrighted by Montage Technologies and provided by them under
NDA (i have access to that code), in the previous versions of
"m88ds3103" it was the same function as mine in
ds3000_diseqc_send_burs() in ds3000.c - in both cases "m88ds3103"
can't be accepted. also, if you look at mine  ToneBurst function
ds3000_diseqc_send_burs() in ds3000.c you will see it's quite
different than the one copyrighted by Montage Technologies, e.g. some
of the register settings are different, etc, because i made it really
from scratch - it could be even it's not better than the original
settings used by the code copyrighted by Montage Technologies, but
it's at least something genuine to which i came up - of course, the
chip limits you in the ways how you can control it. last, but not
least, just changing the condition of if-else statements (swapping it)
and using do-while-loop instead for-loop is nothing more then
shuffling the code.

so, what i would accept:

- patch against "ds3000.c" that adds ds3103 support: copyright is
unchanged and instead credit for the ds3103 support is get by
"history" note, example what i mean and how is the right way to be
done in my opinion:

===
Montage Technology DS3000/TS2020 - DVBS/S2 Demodulator/Tuner driver
Copyright (C) 2009 Konstantin Dimitrov <kosio.dimitrov@gmail.com>

Copyright (C) 2009 TurboSight.com

History:

April 2012:
   Add support for the new silicone revision ds3103
   Max nibble<nibble.max@gmail.com>
===

- any changes that don't involved ds3103 support are subject to review
and argumentation why they are done, i.e. they are bug, the setting is
wrong, etc.

>> Using the seperate tuner and demod, I need to change the codes which use the ds3000 frontend.
>> How can I test the code to confirm that these codes are right without these hardwards?
>
> Well, at the split patch, you shouldn't do anything but to split tuner and demod. This will
> make easier for others to test, if you don't have the hardware for testing.

i haven't had time to read the emails and i'm still not sure what is
the motivation to split them, because Montage tuner and demodulator
are like "married couple". however, if there is really motivation
about that then let's do it - i will help as far as my spare time
allows and even with the testing, i.e. that nothing got broken as
result of that.

>
> Regards,
> Mauro

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-23 21:04               ` Antti Palosaari
@ 2012-04-27 18:44                 ` Konstantin Dimitrov
  0 siblings, 0 replies; 56+ messages in thread
From: Konstantin Dimitrov @ 2012-04-27 18:44 UTC (permalink / raw)
  To: Antti Palosaari; +Cc: nibble.max, Mauro Carvalho Chehab, linux-media

hello Antti,

sorry that i wasn't able to get back to you earlier.

On Tue, Apr 24, 2012 at 12:04 AM, Antti Palosaari <crope@iki.fi> wrote:
> Hello Konstantin,
>
> Good to heard you and finally got your reply to thread.
>
>
> On 23.04.2012 22:51, Konstantin Dimitrov wrote:
>>
>> Antti, i already commented about ds3103 drivers months ago:
>>
>> http://www.mail-archive.com/linux-media@vger.kernel.org/msg41135.html
>>
>> and from my point of view nothing have changed - ds3103 chip is almost
>> the same as ds3000 and the driver i made for ds3000 from scratch is
>> what was used ds3103 drivers to be created. so, what you actually is
>> suggesting - my driver to be removed from the kernel and driver that
>> was made based on my hard work to be included and that driver author
>> even refuses to acknowledge my work?!  such practices are really good
>> for the open-source community, don't you think? also, we already have
>> one case for example, where to satisfy someone's interests two drivers
>> for the same demodulators (STV090x family of chips) were accepted in
>> the kernel - i doubt anyone actually can tell why there are 2 drivers
>> for STV090x in the kernel and instead the community to support the
>> driver for STV090x that was made with more open-source ideas in mind,
>> i.e. the one that can work with any STV090x design and which relies
>> less on code copyrighted by ST - anyway, those details about STV090x
>> drivers are off-topic here, but i'm still giving them as example,
>> because the fact is that already once such mess was created having
>> multiple drivers for the same generation of chips in the kernel and
>> apparently those practices will continue if someone don't raise those
>> questions out loud.
>>
>> also, why Montage tuner code should be spitted from the demodulator
>> code? is there any evidence that any Montage tuner (ts2020 or ts2022)
>> can work with 3rd party demodulator different than ds3000 or ds3103?
>
>
> I don't know what is situation of these Montage chips and what are possible
> combinations. *But* there is many existing cases from the DVB-T I am aware.
> Things are done wrongly and all is implemented as a one big blob. After that
> new device is arrived and we cannot support it since existing drivers are
> not split. And it is not single case...
>

i understand your point, but i believe with DVB-T is quite different
than with DVB-S2, i.e. it's very rare to mix DVB-S2 tuners and
demodulators in such way how it's done with DVB-T. in fact, i'm not
aware of any such mixes in real-life. also, below i will give a lot of
technical details, i.e. facts about CX24116 or TDA10071 and CX24118A
and then i'm sure you will understand my point why the same discussion
can be made for CX24116 and TDA10071 drivers.

> It may happen or it may not happen. You never known. But still it is nice to
> split drivers correctly to avoid such problems that could be possible in
> some day. And I don't even know how much those tuners and demods differs - I
> only saw that patch and it looked there was some differences, even so much
> that two tuner drivers could be good choice.
>
>
>> are there such designs in real-life, e.g. either Montage demodulator
>> with 3rd party tuner or actually more importantly for what you're
>> suggesting Montage tuner (ts2020 or ts2022) with third party
>> demodulator? it's more or less the same case as with cx24116 (and
>> tda10071) demodulator, where the tuner (cx24118a) is controlled by the
>> firmware and thus it's solely part of the demodulator driver, even
>> that it's possible to control the cx24118a tuner that is used with
>> cx24116 (and tda10071) designs directly bypassing the firmware. so,
>> why we don't change in that way the cx24116 (and tda10071) drivers
>> too?
>
>
> CX24116 and TDA10071 (I made TDA10071) are somehow different as tuner is
> driven by demodulator firmware. There is no tuner that needs to be driven by
> driver at least for now.

it's off-topic, but anyway i think it would be useful information to
you and most of it is in the public domains anyway and thus i won't
break any rules. so, you can google for:

* "s2TDQR-C005F" and get the datasheet of LG NIM that consists of
CX24118A + CX24116, read page 14 of it, there is figure diagram about
it : in short it gives you all the details how CX24118A is connected
to the CX24116 and explains that when there is no support for the
tuner in CX24116 firmware then "tuner pass-through" can be used and
that CX24118A also can be used with "tuner pass-through", i.e. direct
control no matter that it's supported tuner in the CX24116 firmware

* now google for BS2F7HZ0165 datasheet in PDF (not the product brief,
the datasheet is scanned and ugly looking), which is SHARP NIM that
consists of CX24118A + CX24116 and on page 6 you can get even more
information and even how to program the "tuner pass-through" mode

* further more you can google for MDVBS2-24116, which is NIM made by
Comtech with CX24118A + CX24116  and get all CX24118A control
registers and their meaning

so, the above 3 PDFs that are in the public domain gives you enough to
develop CX24118A driver and bypass CX24116 or TDA10071 firmware using
"tuner pass-through" and control CX24118A directly not using the
demodulator firmware. why no one do it that way - i guess for the
reason i don't split Montage demodulator and tuner code - no CX24118A
is used only together with CX24116 or TDA10071, they are "married
couple" and both CX24116 or TDA10071 firmware are capable to control
CX24118A tuner. yet as even first datasheet mentions another tuner
CX24128 can be used and then "tuner pass-through" mode and splitting
the CX24116 or TDA10071 driver and their firmware from the tuner
control is necessary. so, if nothing else that supports with real
facts what i meant with my question - that if we start splitting tuner
from demodulator for DVB-S2 drivers then CX24116 or TDA10071 should
also be re-worked, i.e. support for tuner pass-through" be added, etc
in case in future for example someone will use CX24116 or TDA10071
with another compatible tuner than is not supported by the firmware. i
hope you better get my point now and even that i add some excitement
to it, because the above information will make you know much more
about CX24116 or TDA10071 from someone like me that made drivers for
them a long time ago, but unfortunately i'm not allowed to make them
public, but hopefully one day i at least be in position where i can
submit patches to the current open-source drivers adding some things
that are currently missing from them.

> There is also some DVB-T devices that has demod and
> tuner which are both controlled by USB -interface firmware and thus no
> chipset driver needed - only some stuff that implements frontend. But for
> the Montage demod/tuner there is clearly both chips driven by the driver.
>

actually, not that clear, because we don't know what Montage firmware
is doing (it's micro-controller core and it can do anything) and
Montage tuner and demodulator are connected to each other in the same
fashion as CX24116 or TDA10071 with CX24118A for which i gave enough
details above.

>
>> i just don't see what's the motivation behind what you're suggesting,
>> because ds3103 is almost the same as ds3000 from driver point of view
>> and one driver code can be used for both and Montage tuners in
>> question can work only with those demodulators (or at least are used
>> in practice only with them). so, if there are any evidences that's not
>> true then OK let's split them, but if not then what's the point of
>> that?
>
>
> I want to split those correctly as it looked splitting could clear driver.
> Also what I suspect those problems Max had were coming from the fact it was
> not split and it makes driver complex when Max added new tuner and demod
> versions.
>
> And my opinion is still it should be split and as a original driver author
> you are correct person to split it :) But you did not replied so I proposed
> Max should do it in order to go ahead.
>
> And I apologize I proposed removing your driver, I know having own driver is
> something like own baby. But also having own baby it means you should care
> it also.
>

yes, but when someone want to use it for something it was not
originally intended to be used, i think that person should contribute
the necessary changes.

> And what goes the original conflict you linked I am not going to comment. I
> still hope you can say what should be done and review the code in order to
> get support that new demod/tuner combo.
>

from my point of view the discussion about splitting Montage tuner and
demodulator code, which i have some reservations to do, because of all
arguments i explained above, is just shifting the discussion from the
real issue in question - copyright of "m88ds3103" driver.

> I just want things to done correctly. One driver per one entity. Just keep
> it simple and clean to extend later.
>
> So let it be short, is my interpretation correct if I say you want all these
> 4 chips (ds3000/ds3103/ts2020/ts2022) to be driven by single driver?
>

i don't know if ts2022 is as close to ts2020 as ds3000 to ds3103, but
if yes then they should be controlled by the same driver, i.e. driver
for "Montage ds3k" generation of demodulators and if my argument about
CX24116 or TDA10071 with CX24118A are ignored then and Montage tuner
and demodulator code is split by 2 drivers: driver for "Montage ds3k"
generation of demodulators and driver for "Montage ts202x" generation
of tuners.

>
> regards
> Antti
> --
> http://palosaari.fi/

best regards,
konstantin

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-23 21:49               ` Mauro Carvalho Chehab
@ 2012-04-27 19:01                 ` Konstantin Dimitrov
  2012-04-27 19:36                   ` Mauro Carvalho Chehab
                                     ` (2 more replies)
  0 siblings, 3 replies; 56+ messages in thread
From: Konstantin Dimitrov @ 2012-04-27 19:01 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Antti Palosaari, nibble.max, linux-media

Mauro, your reasoning makes sense to me. so, let's split them and at
least settle this part of the discussion - i will do as far as my
spare time allows, as well make sure there are no some problems
introduced after the split.

also, in one email i've just sent in answer to Antti there is enough
argument why such split, i.e. tuner-pass-through-mode is subject to
discussion about CX24116 and TDA10071 drivers too. currently, majority
of DVB-S2 demodulator drivers in the kernel are married to particular
tuners and there is no split.

On Tue, Apr 24, 2012 at 12:49 AM, Mauro Carvalho Chehab
<mchehab@redhat.com> wrote:
> Em 23-04-2012 19:51, Konstantin Dimitrov escreveu:
>> Antti, i already commented about ds3103 drivers months ago:
>
>> also, why Montage tuner code should be spitted from the demodulator
>> code? is there any evidence that any Montage tuner (ts2020 or ts2022)
>> can work with 3rd party demodulator different than ds3000 or ds3103?
>
> This has nothing to do with Montage devices, but with the way we write
> those drivers in Kernel.
>
> There are _several_ examples where the driver for a single silicon were
> turned into more than one driver. The biggest examples are the SoC chips,
> that are transformed into a large series of drivers.
>
> Another example is the cx88 driver: due to technical reasons, it was splitted
> into 4 drivers, one for each different PCI ID exported by it.
>
> The cx2341x driver is also an interesting example: while it used to be for a
> separate chip, the cx2341x functions are now part of IP blocks on newer
> Conexant chipsets. Those single chips require two drivers to work (cx2341x
> and the associated media PCI bridge driver).
>
> Looking into tuners, there are the tda18271 family of devices, with are
> supported by several drivers: tda827x, tda8290 and tda18271-fe, depending
> on how the actual device is mounted. Eventually, the actual tuner may
> also have a tda9887 inside it.
>
> So, there's nothing wrong on splitting it on separate drivers. In a matter of
> fact, we strongly prefer to have tuners separate from demods. Having them
> together can only be justified technically, if there are really strong reasons
> why they should be at the same driver.
>
> I probably missed this at my review for ds3000 (that's why it ended by being
> merged), but, on the review I did on it (accidentally due to m88ds3103 patchset
> review), it is clear that the tuner has actually a different I2C address (0x60)
> than the demod, and it is indeed a separate device. Sorry for slipping into it.
>
> Anyway, now that this is noticed, tuner and demod drivers should be split,
> especially since there are some patches floating around to add support for ds3103.
>
> As I said before, the right thing to do is:
>
>        1) split ds3000 from ts2020 at the existing driver;
>        2) add support for the newer chips (ds3103/ts2022) to the ds3000 and ds3103
>           drivers.
>        3) test if the patches adding support for the newer chips didn't break the
>           support for existing hardware.
>
> My proposal is that tasks (1) and (3) should be handled by you. As Max wants to
> add support for some devices based on ds3103/ts2022, IMO, he can do the patches
> for (2) in a way that they would be acceptable by you, as the driver maintainer
> for ds3000/ts2020, testing with their devices.
>
> Regards,
> Mauro

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-27 19:01                 ` Konstantin Dimitrov
@ 2012-04-27 19:36                   ` Mauro Carvalho Chehab
  2012-04-27 20:37                     ` Konstantin Dimitrov
  2012-04-27 19:55                   ` Antti Palosaari
  2012-04-28  9:17                   ` Demod hardware pid filter implement nibble.max
  2 siblings, 1 reply; 56+ messages in thread
From: Mauro Carvalho Chehab @ 2012-04-27 19:36 UTC (permalink / raw)
  To: Konstantin Dimitrov; +Cc: Antti Palosaari, nibble.max, linux-media

Hi Konstantin,

Em 27-04-2012 16:01, Konstantin Dimitrov escreveu:
> Mauro, your reasoning makes sense to me. so, let's split them and at
> least settle this part of the discussion - i will do as far as my
> spare time allows, as well make sure there are no some problems
> introduced after the split.

Thank you!

> also, in one email i've just sent in answer to Antti there is enough
> argument why such split, i.e. tuner-pass-through-mode is subject to
> discussion about CX24116 and TDA10071 drivers too. currently, majority
> of DVB-S2 demodulator drivers in the kernel are married to particular
> tuners and there is no split.

Besides the reasoning I gave you, having the tuner and the demod on separate
drivers help a lot code reviewers to check what's happening inside the code,
because the code on each driver becomes more coincide and the two different
functions become more decoupled, with reduces the code complexity. So, bugs
tend to be reduced and they're easier to fix, especially when someone need
to fix bad things at the dvb core.

Also, as almost all drivers are like that, it is easier to identify driver
patterns, especially when newer patches are adding extra functionality there.

Thanks!
Mauro


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-27 19:01                 ` Konstantin Dimitrov
  2012-04-27 19:36                   ` Mauro Carvalho Chehab
@ 2012-04-27 19:55                   ` Antti Palosaari
  2012-04-27 20:21                     ` Konstantin Dimitrov
  2012-04-28  9:17                   ` Demod hardware pid filter implement nibble.max
  2 siblings, 1 reply; 56+ messages in thread
From: Antti Palosaari @ 2012-04-27 19:55 UTC (permalink / raw)
  To: Konstantin Dimitrov; +Cc: Mauro Carvalho Chehab, nibble.max, linux-media

On 27.04.2012 22:01, Konstantin Dimitrov wrote:
> Mauro, your reasoning makes sense to me. so, let's split them and at
> least settle this part of the discussion - i will do as far as my
> spare time allows, as well make sure there are no some problems
> introduced after the split.
>
> also, in one email i've just sent in answer to Antti there is enough
> argument why such split, i.e. tuner-pass-through-mode is subject to
> discussion about CX24116 and TDA10071 drivers too. currently, majority
> of DVB-S2 demodulator drivers in the kernel are married to particular
> tuners and there is no split.

I read the mail and as it was long study, I comment only that 
CX24116+CX24118A and TDA10071+CX24118A demod+tuner combos versus Montage 
demod+tuner combos. As you may see, CX24116 and TDA10071 are so much 
different than both needs own driver. But as you said those are married 
always as a demod+tuner.

So if I use your logic, what happens if CX24118A tuner is not driven by 
CX24116 or TDA10071 firmware? ==> it happens we have two drivers, 
CX24116 and TDA10071 *both* having similar CX24118A tuner driver code 
inside! Same tuner driver code inside two demods drivers. Could you now 
understand why we want it split?
The reason which saves us having CX24118A tuner driver is that it is 
inside both CX24116 and TDA10071 firmware.

There is mainly two different controlling situation. Most commonly 
driver controls chip but in some cases it is firmware which is 
controlling. And I don't see it very important trying always to by-pass 
firmware control and use driver for that.

Patrick explained those few days back in the mailing list:
http://www.mail-archive.com/linux-media@vger.kernel.org/msg44814.html

You said also we cannot know if Montage demod does some tweaking for the 
tuner too. Yes true, at that point we don't know. But I think it is 
rather small probability whilst driver clearly controls it.

regards
Antti
-- 
http://palosaari.fi/

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-27 19:55                   ` Antti Palosaari
@ 2012-04-27 20:21                     ` Konstantin Dimitrov
  2012-04-27 20:42                       ` Antti Palosaari
  0 siblings, 1 reply; 56+ messages in thread
From: Konstantin Dimitrov @ 2012-04-27 20:21 UTC (permalink / raw)
  To: Antti Palosaari; +Cc: Mauro Carvalho Chehab, nibble.max, linux-media

On Fri, Apr 27, 2012 at 10:55 PM, Antti Palosaari <crope@iki.fi> wrote:
> On 27.04.2012 22:01, Konstantin Dimitrov wrote:
>>
>> Mauro, your reasoning makes sense to me. so, let's split them and at
>> least settle this part of the discussion - i will do as far as my
>> spare time allows, as well make sure there are no some problems
>> introduced after the split.
>>
>> also, in one email i've just sent in answer to Antti there is enough
>> argument why such split, i.e. tuner-pass-through-mode is subject to
>> discussion about CX24116 and TDA10071 drivers too. currently, majority
>> of DVB-S2 demodulator drivers in the kernel are married to particular
>> tuners and there is no split.
>
>
> I read the mail and as it was long study, I comment only that
> CX24116+CX24118A and TDA10071+CX24118A demod+tuner combos versus Montage
> demod+tuner combos. As you may see, CX24116 and TDA10071 are so much
> different than both needs own driver. But as you said those are married
> always as a demod+tuner.
>
> So if I use your logic, what happens if CX24118A tuner is not driven by
> CX24116 or TDA10071 firmware? ==> it happens we have two drivers, CX24116
> and TDA10071 *both* having similar CX24118A tuner driver code inside! Same
> tuner driver code inside two demods drivers. Could you now understand why we
> want it split?
> The reason which saves us having CX24118A tuner driver is that it is inside
> both CX24116 and TDA10071 firmware.
>
> There is mainly two different controlling situation. Most commonly driver
> controls chip but in some cases it is firmware which is controlling. And I
> don't see it very important trying always to by-pass firmware control and
> use driver for that.
>

i got that point, but what happens if tomorrow their is CX24116 or
TDA10071 design with tuner different than CX14118A? in fact the LG
datasheet i pointed out to you clearly states that for example there
is actually such design - case when CX24116 is used with CX24128 tuner
instead CX24118A in which case the only way is to bypass the firmware
and control the tuner directly. also, isn't it even double bad the
current state of CX24116 or TDA10071 drivers - from one side they use
2 firmwares, part of which is doing the same, i.e control the CX24118A
and from the other side they depend on proprietary firmware to do
something that can be done in open-source code? i don't know, but at
least from my point of view if that's not worse than the current
status of ds3000 driver, it's at least as wrong as it, i.e. there
isn't not only separation of tuner and demodulator code in CX24116 or
TDA10071 drivers, but there is not even a code that can allow they to
be separated easily, because making CX14118A driver from scratch is
task that will need some effort. anyway, maybe, it's just me, but i
prefer to depend as less as possible on proprietary firmwares done is
such way. however, there is no any doubt current CX24116 or TDA10071
drivers don't allow any other tuner that is not supported by the
proprietary firmware to be used and thus they break the rule of tuner
and demodulator code separation. so, i really don't understand what
makes CX24116 or TDA10071 drivers different than the others, i.e. why
they are developed in such way and there is no discussion about them
to be changed in way that allow use of other tuner like CX24128, which
is not supported by the proprietary firmwares. so, the only
explanation from my perspective is lack of such need in real-life, but
it's the same for ds3000.

> Patrick explained those few days back in the mailing list:
> http://www.mail-archive.com/linux-media@vger.kernel.org/msg44814.html
>
> You said also we cannot know if Montage demod does some tweaking for the
> tuner too. Yes true, at that point we don't know. But I think it is rather
> small probability whilst driver clearly controls it.
>
>
> regards
> Antti
> --
> http://palosaari.fi/

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-27 19:36                   ` Mauro Carvalho Chehab
@ 2012-04-27 20:37                     ` Konstantin Dimitrov
  2012-04-27 20:40                       ` Konstantin Dimitrov
  0 siblings, 1 reply; 56+ messages in thread
From: Konstantin Dimitrov @ 2012-04-27 20:37 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Antti Palosaari, nibble.max, linux-media

hi Mauro,

in the mean time i was actually pointed out that there is 3rd party
tuner that is proved to work in practice with both Montage ds3k
demodulator family, as well ST STV090x demods, i.e. there are such
reference designs. so, the split further makes sense and in fact that
should be make in way that both drivers for STV090x and Montage ds3k
demodulator family can share tuners with each other. so, that's just
note for the upcoming review of the patches i will submit - in short
the split of  Montage tuner and demodulator code i will make it in the
same fashion as how the driver code for ST 6100/6110 tuner are split
from STV090x driver, because that now, as i've just mentioned, makes
sense from practical point of view since of the 3rd party tuner for
which there is reference designs with both STV090x and Montage
demodulator. also, that way STB0899, STV090x and Montage demodulator
drivers can be used together with any other of the DVB-S2 tuners
available in the kernel - ST 6100 and 6110 and soon TS2020.

however, i want to pointed out few other problems - they are off-topic
as not related to drivers for Montage chips, but related as far as
we're putting some order and making things in a proper way and those
those things are out of that order:

- there are 2 drivers for the same DVB-S2 tuner: ST 6110, respectively
"stv6110.c" and "stv6110x.c"

- there are 2 drivers for the same DVB-S2 demodulator family:
respectively stv090x* and stv0900*

the above couldn't be more wrong - in fact i can submit patches to
make all drivers that relies on stv090x* and "stv6110.c" to use
stv090x* and "stv6110x.c" instead except the NetUP board, for which in
my opinion someone should submit patches using stv090x* and
"stv6110x.c" and subsequently stv090x* and "stv6110.c" be removed -
unless someone have some real argument why stv090x* and "stv6110.c"
should stay or even if for why they should replace stv090x* and
"stv6110x.c" and subsequently  stv090x* and "stv6110x.c" be removed
instead. so, the case with ST 6110 and STV090x support is the most
frustrating and out of order thing that i can indicate regarding the
support of DVB-S2 chips in the kernel and i hope you will take care as
maintainer to be resolved or at least someone to explain why the
current state is like that - or point me out to explanation if such
was already made to the mailing list. so, what i'm suggesting is
"spring cleaning" of all DVB-S2 tuner/demodulator drivers in the
kernel - if it's not done now in the future the mess will only
increase.

thank you,
konstantin

On Fri, Apr 27, 2012 at 10:36 PM, Mauro Carvalho Chehab
<mchehab@redhat.com> wrote:
> Hi Konstantin,
>
> Em 27-04-2012 16:01, Konstantin Dimitrov escreveu:
>> Mauro, your reasoning makes sense to me. so, let's split them and at
>> least settle this part of the discussion - i will do as far as my
>> spare time allows, as well make sure there are no some problems
>> introduced after the split.
>
> Thank you!
>
>> also, in one email i've just sent in answer to Antti there is enough
>> argument why such split, i.e. tuner-pass-through-mode is subject to
>> discussion about CX24116 and TDA10071 drivers too. currently, majority
>> of DVB-S2 demodulator drivers in the kernel are married to particular
>> tuners and there is no split.
>
> Besides the reasoning I gave you, having the tuner and the demod on separate
> drivers help a lot code reviewers to check what's happening inside the code,
> because the code on each driver becomes more coincide and the two different
> functions become more decoupled, with reduces the code complexity. So, bugs
> tend to be reduced and they're easier to fix, especially when someone need
> to fix bad things at the dvb core.
>
> Also, as almost all drivers are like that, it is easier to identify driver
> patterns, especially when newer patches are adding extra functionality there.
>
> Thanks!
> Mauro
>

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-27 20:37                     ` Konstantin Dimitrov
@ 2012-04-27 20:40                       ` Konstantin Dimitrov
  2012-04-27 20:54                         ` Antti Palosaari
  0 siblings, 1 reply; 56+ messages in thread
From: Konstantin Dimitrov @ 2012-04-27 20:40 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Antti Palosaari, nibble.max, linux-media

On Fri, Apr 27, 2012 at 11:37 PM, Konstantin Dimitrov
<kosio.dimitrov@gmail.com> wrote:
> hi Mauro,
>
> in the mean time i was actually pointed out that there is 3rd party
> tuner that is proved to work in practice with both Montage ds3k
> demodulator family, as well ST STV090x demods, i.e. there are such
> reference designs. so, the split further makes sense and in fact that
> should be make in way that both drivers for STV090x and Montage ds3k
> demodulator family can share tuners with each other. so, that's just
> note for the upcoming review of the patches i will submit - in short
> the split of  Montage tuner and demodulator code i will make it in the
> same fashion as how the driver code for ST 6100/6110 tuner are split
> from STV090x driver, because that now, as i've just mentioned, makes
> sense from practical point of view since of the 3rd party tuner for
> which there is reference designs with both STV090x and Montage
> demodulator. also, that way STB0899, STV090x and Montage demodulator
> drivers can be used together with any other of the DVB-S2 tuners
> available in the kernel - ST 6100 and 6110 and soon TS2020.
>
> however, i want to pointed out few other problems - they are off-topic
> as not related to drivers for Montage chips, but related as far as
> we're putting some order and making things in a proper way and those
> those things are out of that order:
>
> - there are 2 drivers for the same DVB-S2 tuner: ST 6110, respectively
> "stv6110.c" and "stv6110x.c"
>
> - there are 2 drivers for the same DVB-S2 demodulator family:
> respectively stv090x* and stv0900*
>
> the above couldn't be more wrong - in fact i can submit patches to
> make all drivers that relies on stv090x* and "stv6110.c" to use
> stv090x* and "stv6110x.c" instead except the NetUP board, for which in

> my opinion someone should submit patches using stv090x* and
> "stv6110x.c" and subsequently stv090x* and "stv6110.c" be removed -

to correct a typo: and subsequently stv0900* and "stv6110.c" be removed

> unless someone have some real argument why stv090x* and "stv6110.c"

the same: unless someone have some real argument why stv0900* and "stv6110.c"

> should stay or even if for why they should replace stv090x* and
> "stv6110x.c" and subsequently  stv090x* and "stv6110x.c" be removed
> instead. so, the case with ST 6110 and STV090x support is the most
> frustrating and out of order thing that i can indicate regarding the
> support of DVB-S2 chips in the kernel and i hope you will take care as
> maintainer to be resolved or at least someone to explain why the
> current state is like that - or point me out to explanation if such
> was already made to the mailing list. so, what i'm suggesting is
> "spring cleaning" of all DVB-S2 tuner/demodulator drivers in the
> kernel - if it's not done now in the future the mess will only
> increase.
>
> thank you,
> konstantin
>
> On Fri, Apr 27, 2012 at 10:36 PM, Mauro Carvalho Chehab
> <mchehab@redhat.com> wrote:
>> Hi Konstantin,
>>
>> Em 27-04-2012 16:01, Konstantin Dimitrov escreveu:
>>> Mauro, your reasoning makes sense to me. so, let's split them and at
>>> least settle this part of the discussion - i will do as far as my
>>> spare time allows, as well make sure there are no some problems
>>> introduced after the split.
>>
>> Thank you!
>>
>>> also, in one email i've just sent in answer to Antti there is enough
>>> argument why such split, i.e. tuner-pass-through-mode is subject to
>>> discussion about CX24116 and TDA10071 drivers too. currently, majority
>>> of DVB-S2 demodulator drivers in the kernel are married to particular
>>> tuners and there is no split.
>>
>> Besides the reasoning I gave you, having the tuner and the demod on separate
>> drivers help a lot code reviewers to check what's happening inside the code,
>> because the code on each driver becomes more coincide and the two different
>> functions become more decoupled, with reduces the code complexity. So, bugs
>> tend to be reduced and they're easier to fix, especially when someone need
>> to fix bad things at the dvb core.
>>
>> Also, as almost all drivers are like that, it is easier to identify driver
>> patterns, especially when newer patches are adding extra functionality there.
>>
>> Thanks!
>> Mauro
>>

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-27 20:21                     ` Konstantin Dimitrov
@ 2012-04-27 20:42                       ` Antti Palosaari
  2012-04-27 21:13                         ` Konstantin Dimitrov
  2012-04-28  3:54                         ` nibble.max
  0 siblings, 2 replies; 56+ messages in thread
From: Antti Palosaari @ 2012-04-27 20:42 UTC (permalink / raw)
  To: Konstantin Dimitrov; +Cc: Mauro Carvalho Chehab, nibble.max, linux-media

On 27.04.2012 23:21, Konstantin Dimitrov wrote:
> On Fri, Apr 27, 2012 at 10:55 PM, Antti Palosaari<crope@iki.fi>  wrote:
>> On 27.04.2012 22:01, Konstantin Dimitrov wrote:
>>>
>>> Mauro, your reasoning makes sense to me. so, let's split them and at
>>> least settle this part of the discussion - i will do as far as my
>>> spare time allows, as well make sure there are no some problems
>>> introduced after the split.
>>>
>>> also, in one email i've just sent in answer to Antti there is enough
>>> argument why such split, i.e. tuner-pass-through-mode is subject to
>>> discussion about CX24116 and TDA10071 drivers too. currently, majority
>>> of DVB-S2 demodulator drivers in the kernel are married to particular
>>> tuners and there is no split.
>>
>>
>> I read the mail and as it was long study, I comment only that
>> CX24116+CX24118A and TDA10071+CX24118A demod+tuner combos versus Montage
>> demod+tuner combos. As you may see, CX24116 and TDA10071 are so much
>> different than both needs own driver. But as you said those are married
>> always as a demod+tuner.
>>
>> So if I use your logic, what happens if CX24118A tuner is not driven by
>> CX24116 or TDA10071 firmware? ==>  it happens we have two drivers, CX24116
>> and TDA10071 *both* having similar CX24118A tuner driver code inside! Same
>> tuner driver code inside two demods drivers. Could you now understand why we
>> want it split?
>> The reason which saves us having CX24118A tuner driver is that it is inside
>> both CX24116 and TDA10071 firmware.
>>
>> There is mainly two different controlling situation. Most commonly driver
>> controls chip but in some cases it is firmware which is controlling. And I
>> don't see it very important trying always to by-pass firmware control and
>> use driver for that.
>>
>
> i got that point, but what happens if tomorrow their is CX24116 or
> TDA10071 design with tuner different than CX14118A? in fact the LG
> datasheet i pointed out to you clearly states that for example there
> is actually such design - case when CX24116 is used with CX24128 tuner
> instead CX24118A in which case the only way is to bypass the firmware
> and control the tuner directly. also, isn't it even double bad the
> current state of CX24116 or TDA10071 drivers - from one side they use
> 2 firmwares, part of which is doing the same, i.e control the CX24118A
> and from the other side they depend on proprietary firmware to do
> something that can be done in open-source code? i don't know, but at
> least from my point of view if that's not worse than the current
> status of ds3000 driver, it's at least as wrong as it, i.e. there
> isn't not only separation of tuner and demodulator code in CX24116 or
> TDA10071 drivers, but there is not even a code that can allow they to
> be separated easily, because making CX14118A driver from scratch is
> task that will need some effort. anyway, maybe, it's just me, but i
> prefer to depend as less as possible on proprietary firmwares done is
> such way. however, there is no any doubt current CX24116 or TDA10071
> drivers don't allow any other tuner that is not supported by the
> proprietary firmware to be used and thus they break the rule of tuner
> and demodulator code separation. so, i really don't understand what
> makes CX24116 or TDA10071 drivers different than the others, i.e. why
> they are developed in such way and there is no discussion about them
> to be changed in way that allow use of other tuner like CX24128, which
> is not supported by the proprietary firmwares. so, the only
> explanation from my perspective is lack of such need in real-life, but
> it's the same for ds3000.

In case of new device having CX24116 or TDA10071, but different tuner 
than firmware controlled CX14118A, driver must be changed to support new 
configuration. Or even make new driver if differences are too big. I 
suspect implementing new .set_frontend() callback is almost everything 
what is needed. Then add configuration option 
.tuner_controlled_by_firmware or something like that. There is likely 
rather similar existing cases.

IIRC someone mentioned AF9035/AF9033 firmwares have different versions 
for different tuners. Also AF9015 uploads firmware to AF9013 demod, 
external or internal. Still AF9013 driver could upload firmware 
independently. There is many kind of cases chip/firmware can control 
other chips. And if you look AF9015/AF9013 and AF9035/AF9033 drivers you 
can see some examples of splitting drivers even those are many times 
integrated together. OK, that AF90xx stuff goes to DVB-T side but it is 
good example of splitting drivers and supporting very wide set of 
demod/tuner combinations.

And it is nice you found CX24116 is sold by two different tuners :) If 
those tuners are controlled by the driver we can see similar mess than 
ds3000 + ts2020 or ts2022. At the some point handling different tuner 
drivers inside one demod driver goes difficult - errors can be done 
easily and maintaining goes hard.

regards
Antti
-- 
http://palosaari.fi/

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-27 20:40                       ` Konstantin Dimitrov
@ 2012-04-27 20:54                         ` Antti Palosaari
  2012-04-27 21:01                           ` Konstantin Dimitrov
  0 siblings, 1 reply; 56+ messages in thread
From: Antti Palosaari @ 2012-04-27 20:54 UTC (permalink / raw)
  To: Konstantin Dimitrov; +Cc: Mauro Carvalho Chehab, nibble.max, linux-media

On 27.04.2012 23:40, Konstantin Dimitrov wrote:
> On Fri, Apr 27, 2012 at 11:37 PM, Konstantin Dimitrov
>> however, i want to pointed out few other problems - they are off-topic
>> as not related to drivers for Montage chips, but related as far as
>> we're putting some order and making things in a proper way and those
>> those things are out of that order:
>>
>> - there are 2 drivers for the same DVB-S2 tuner: ST 6110, respectively
>> "stv6110.c" and "stv6110x.c"
>>
>> - there are 2 drivers for the same DVB-S2 demodulator family:
>> respectively stv090x* and stv0900*
>>
>> the above couldn't be more wrong - in fact i can submit patches to
>> make all drivers that relies on stv090x* and "stv6110.c" to use
>> stv090x* and "stv6110x.c" instead except the NetUP board, for which in
>
>> my opinion someone should submit patches using stv090x* and
>> "stv6110x.c" and subsequently stv090x* and "stv6110.c" be removed -
>
> to correct a typo: and subsequently stv0900* and "stv6110.c" be removed
>
>> unless someone have some real argument why stv090x* and "stv6110.c"
>
> the same: unless someone have some real argument why stv0900* and "stv6110.c"
>
>> should stay or even if for why they should replace stv090x* and
>> "stv6110x.c" and subsequently  stv090x* and "stv6110x.c" be removed
>> instead. so, the case with ST 6110 and STV090x support is the most
>> frustrating and out of order thing that i can indicate regarding the
>> support of DVB-S2 chips in the kernel and i hope you will take care as
>> maintainer to be resolved or at least someone to explain why the
>> current state is like that - or point me out to explanation if such
>> was already made to the mailing list. so, what i'm suggesting is
>> "spring cleaning" of all DVB-S2 tuner/demodulator drivers in the
>> kernel - if it's not done now in the future the mess will only
>> increase.

That stv090x stuff is discussed many times earlier too. It is mistake 
done for the some reasons. In theory there should be only one driver per 
chip/logical entity but for the non-technical reason it was failed. And 
as it is failed at the very first try it is hard to correct later.

regards
Antti
-- 
http://palosaari.fi/

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-27 20:54                         ` Antti Palosaari
@ 2012-04-27 21:01                           ` Konstantin Dimitrov
  0 siblings, 0 replies; 56+ messages in thread
From: Konstantin Dimitrov @ 2012-04-27 21:01 UTC (permalink / raw)
  To: Antti Palosaari; +Cc: Mauro Carvalho Chehab, nibble.max, linux-media

On Fri, Apr 27, 2012 at 11:54 PM, Antti Palosaari <crope@iki.fi> wrote:
> On 27.04.2012 23:40, Konstantin Dimitrov wrote:
>>
>> On Fri, Apr 27, 2012 at 11:37 PM, Konstantin Dimitrov
>>>
>>> however, i want to pointed out few other problems - they are off-topic
>>>
>>> as not related to drivers for Montage chips, but related as far as
>>> we're putting some order and making things in a proper way and those
>>> those things are out of that order:
>>>
>>> - there are 2 drivers for the same DVB-S2 tuner: ST 6110, respectively
>>> "stv6110.c" and "stv6110x.c"
>>>
>>> - there are 2 drivers for the same DVB-S2 demodulator family:
>>> respectively stv090x* and stv0900*
>>>
>>> the above couldn't be more wrong - in fact i can submit patches to
>>> make all drivers that relies on stv090x* and "stv6110.c" to use
>>> stv090x* and "stv6110x.c" instead except the NetUP board, for which in
>>
>>
>>> my opinion someone should submit patches using stv090x* and
>>> "stv6110x.c" and subsequently stv090x* and "stv6110.c" be removed -
>>
>>
>> to correct a typo: and subsequently stv0900* and "stv6110.c" be removed
>>
>>> unless someone have some real argument why stv090x* and "stv6110.c"
>>
>>
>> the same: unless someone have some real argument why stv0900* and
>> "stv6110.c"
>>
>>> should stay or even if for why they should replace stv090x* and
>>> "stv6110x.c" and subsequently  stv090x* and "stv6110x.c" be removed
>>> instead. so, the case with ST 6110 and STV090x support is the most
>>> frustrating and out of order thing that i can indicate regarding the
>>> support of DVB-S2 chips in the kernel and i hope you will take care as
>>> maintainer to be resolved or at least someone to explain why the
>>> current state is like that - or point me out to explanation if such
>>> was already made to the mailing list. so, what i'm suggesting is
>>> "spring cleaning" of all DVB-S2 tuner/demodulator drivers in the
>>> kernel - if it's not done now in the future the mess will only
>>> increase.
>
>
> That stv090x stuff is discussed many times earlier too. It is mistake done
> for the some reasons. In theory there should be only one driver per
> chip/logical entity but for the non-technical reason it was failed. And as
> it is failed at the very first try it is hard to correct later.
>

OK, what about i commit to correct it to the degree i can? that degree
is : patch all bridge drivers to use stv090x* and stv6110x* except the
driver for the NetUP card since i don't have any similar hardware,
which i can use for testing and remove the less mature and less
versatile drivers involved in the mess, i.e. stv6110.* and stv0900*.
until the NetUP don't submit patch to utilize stv090x* and stv6110x*
their card will be left in unsupported stage - at least that way 99%
of the mess will be cleaned and subsequently the whole mess, because i
guess someone with NetUP hardware will contribute what i can't do.

>
> regards
> Antti
> --
> http://palosaari.fi/

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-27 20:42                       ` Antti Palosaari
@ 2012-04-27 21:13                         ` Konstantin Dimitrov
  2012-04-28  3:54                         ` nibble.max
  1 sibling, 0 replies; 56+ messages in thread
From: Konstantin Dimitrov @ 2012-04-27 21:13 UTC (permalink / raw)
  To: Antti Palosaari, Mauro Carvalho Chehab; +Cc: nibble.max, linux-media

Antti, Mauro,

i believe we're all on the same page here and i just want to summarize
based on all the discussion so far and if we all agree:

1) ds3000 and ts2020 code split, there are already several strong
arguments about it and most of all that it turned out there is
reference design with 3rd party tuner that works both with ds3000 and
stv090x demodulators. i will take care of this task

2) the result of 1) would be that the following DVB-S2 tuner and
demodulator drivers will be able to work in any combination of each
other (assuming there is such hardware design available): stb0899*,
stv090x*, ds3000, stv6110x*, stb6100* and ts2020. that's good, because
it starts to put order, because those are significant part of the
DVB-S2 drivers in the kernel

3) not only, because of 2), but in general it's not clear why there is
stv6110.* driver, which is for the exact same silicone as stv6110x*,
as well stv0900*, which is for the same family of chips as stv090x*. i
can help a little here to the degree that i can make all bridge
drivers depend on stv6110x* and stv090x* except the driver for one
card made by NetUP - there i can just do it in theory, but i can't
test and probably break support for it

4) after 1), 2) and if 3) is resolved the only DVB-S2 drivers that
will continue to be married to one particular tuner (CX24118A) that
will left are cx24116 and tda10071, which for the time being will be
left that way until basically there is someone that volunteers to make
separate CX24118A driver based on the LG, SHARP and Comtech datasheets
that are available in the public domain, for which i gave details in a
previous email, and which in my opinion contain sufficient information
that task to be made

5) ds3103 and ts2022 support, done in form of a patch respectively to
ds3000 driver and ts2020 driver or if ts2022 happens to be very
different than ts2020 then ts2022 support be made as separate driver,
i guess Max will take this

6) if it's necessary bug fixes, improvements, etc to the shared code
between ds3000 and ds3103, but only after review, discussion and
argumentation why those changes are actually needed

On Fri, Apr 27, 2012 at 11:42 PM, Antti Palosaari <crope@iki.fi> wrote:
> On 27.04.2012 23:21, Konstantin Dimitrov wrote:
>>
>> On Fri, Apr 27, 2012 at 10:55 PM, Antti Palosaari<crope@iki.fi>  wrote:
>>>
>>> On 27.04.2012 22:01, Konstantin Dimitrov wrote:
>>>>
>>>>
>>>> Mauro, your reasoning makes sense to me. so, let's split them and at
>>>> least settle this part of the discussion - i will do as far as my
>>>> spare time allows, as well make sure there are no some problems
>>>> introduced after the split.
>>>>
>>>> also, in one email i've just sent in answer to Antti there is enough
>>>> argument why such split, i.e. tuner-pass-through-mode is subject to
>>>> discussion about CX24116 and TDA10071 drivers too. currently, majority
>>>> of DVB-S2 demodulator drivers in the kernel are married to particular
>>>> tuners and there is no split.
>>>
>>>
>>>
>>> I read the mail and as it was long study, I comment only that
>>> CX24116+CX24118A and TDA10071+CX24118A demod+tuner combos versus Montage
>>> demod+tuner combos. As you may see, CX24116 and TDA10071 are so much
>>> different than both needs own driver. But as you said those are married
>>> always as a demod+tuner.
>>>
>>> So if I use your logic, what happens if CX24118A tuner is not driven by
>>> CX24116 or TDA10071 firmware? ==>  it happens we have two drivers,
>>> CX24116
>>> and TDA10071 *both* having similar CX24118A tuner driver code inside!
>>> Same
>>> tuner driver code inside two demods drivers. Could you now understand why
>>> we
>>> want it split?
>>> The reason which saves us having CX24118A tuner driver is that it is
>>> inside
>>> both CX24116 and TDA10071 firmware.
>>>
>>> There is mainly two different controlling situation. Most commonly driver
>>> controls chip but in some cases it is firmware which is controlling. And
>>> I
>>> don't see it very important trying always to by-pass firmware control and
>>> use driver for that.
>>>
>>
>> i got that point, but what happens if tomorrow their is CX24116 or
>> TDA10071 design with tuner different than CX14118A? in fact the LG
>> datasheet i pointed out to you clearly states that for example there
>> is actually such design - case when CX24116 is used with CX24128 tuner
>> instead CX24118A in which case the only way is to bypass the firmware
>> and control the tuner directly. also, isn't it even double bad the
>> current state of CX24116 or TDA10071 drivers - from one side they use
>> 2 firmwares, part of which is doing the same, i.e control the CX24118A
>> and from the other side they depend on proprietary firmware to do
>> something that can be done in open-source code? i don't know, but at
>> least from my point of view if that's not worse than the current
>> status of ds3000 driver, it's at least as wrong as it, i.e. there
>> isn't not only separation of tuner and demodulator code in CX24116 or
>> TDA10071 drivers, but there is not even a code that can allow they to
>> be separated easily, because making CX14118A driver from scratch is
>> task that will need some effort. anyway, maybe, it's just me, but i
>> prefer to depend as less as possible on proprietary firmwares done is
>> such way. however, there is no any doubt current CX24116 or TDA10071
>> drivers don't allow any other tuner that is not supported by the
>> proprietary firmware to be used and thus they break the rule of tuner
>> and demodulator code separation. so, i really don't understand what
>> makes CX24116 or TDA10071 drivers different than the others, i.e. why
>> they are developed in such way and there is no discussion about them
>> to be changed in way that allow use of other tuner like CX24128, which
>> is not supported by the proprietary firmwares. so, the only
>> explanation from my perspective is lack of such need in real-life, but
>> it's the same for ds3000.
>
>
> In case of new device having CX24116 or TDA10071, but different tuner than
> firmware controlled CX14118A, driver must be changed to support new
> configuration. Or even make new driver if differences are too big. I suspect
> implementing new .set_frontend() callback is almost everything what is
> needed. Then add configuration option .tuner_controlled_by_firmware or
> something like that. There is likely rather similar existing cases.
>
> IIRC someone mentioned AF9035/AF9033 firmwares have different versions for
> different tuners. Also AF9015 uploads firmware to AF9013 demod, external or
> internal. Still AF9013 driver could upload firmware independently. There is
> many kind of cases chip/firmware can control other chips. And if you look
> AF9015/AF9013 and AF9035/AF9033 drivers you can see some examples of
> splitting drivers even those are many times integrated together. OK, that
> AF90xx stuff goes to DVB-T side but it is good example of splitting drivers
> and supporting very wide set of demod/tuner combinations.
>
> And it is nice you found CX24116 is sold by two different tuners :) If those
> tuners are controlled by the driver we can see similar mess than ds3000 +
> ts2020 or ts2022. At the some point handling different tuner drivers inside
> one demod driver goes difficult - errors can be done easily and maintaining
> goes hard.
>
>
> regards
> Antti
> --
> http://palosaari.fi/

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver
  2012-04-27 20:42                       ` Antti Palosaari
  2012-04-27 21:13                         ` Konstantin Dimitrov
@ 2012-04-28  3:54                         ` nibble.max
  1 sibling, 0 replies; 56+ messages in thread
From: nibble.max @ 2012-04-28  3:54 UTC (permalink / raw)
  To: Konstantin Dimitrov, Antti Palosaari, Mauro Carvalho Chehab; +Cc: linux-media

2012-04-28 10:57:19 nibble.max@gmail.com
>Antti, Mauro,
>
>i believe we're all on the same page here and i just want to summarize
>based on all the discussion so far and if we all agree:
>
>1) ds3000 and ts2020 code split, there are already several strong
>arguments about it and most of all that it turned out there is
>reference design with 3rd party tuner that works both with ds3000 and
>stv090x demodulators. i will take care of this task
>

Montage demodulator has worked with Sharp 6306 CAN tuner for several years.
I suggest to put the dvb-s/s2 initialize constant data of ds3000 to the seperate files.
As i patch ds3103, it has also dvb-s/s2 initialize datas. 
It will make ds3000 file too long and ugly to review.
As i do in the try patch placing them into ds3000_priv.h.

>2) the result of 1) would be that the following DVB-S2 tuner and
>demodulator drivers will be able to work in any combination of each
>other (assuming there is such hardware design available): stb0899*,
>stv090x*, ds3000, stv6110x*, stb6100* and ts2020. that's good, because
>it starts to put order, because those are significant part of the
>DVB-S2 drivers in the kernel
>
>3) not only, because of 2), but in general it's not clear why there is
>stv6110.* driver, which is for the exact same silicone as stv6110x*,
>as well stv0900*, which is for the same family of chips as stv090x*. i
>can help a little here to the degree that i can make all bridge
>drivers depend on stv6110x* and stv090x* except the driver for one
>card made by NetUP - there i can just do it in theory, but i can't
>test and probably break support for it
>
>4) after 1), 2) and if 3) is resolved the only DVB-S2 drivers that
>will continue to be married to one particular tuner (CX24118A) that
>will left are cx24116 and tda10071, which for the time being will be
>left that way until basically there is someone that volunteers to make
>separate CX24118A driver based on the LG, SHARP and Comtech datasheets
>that are available in the public domain, for which i gave details in a
>previous email, and which in my opinion contain sufficient information
>that task to be made
>
>5) ds3103 and ts2022 support, done in form of a patch respectively to
>ds3000 driver and ts2020 driver or if ts2022 happens to be very
>different than ts2020 then ts2022 support be made as separate driver,
>i guess Max will take this
>

FYI,We have approval from Montage to let us use its reference code under GPLv2 lincense.

But to their surprise, they review ds3000.c and find the tuner and demod config part almost same as their reference code.
They have not agree anybody to public their code under GPLv2 before.
They doubt that ds3000.c public is breaking their NDA without their permission.

>6) if it's necessary bug fixes, improvements, etc to the shared code
>between ds3000 and ds3103, but only after review, discussion and
>argumentation why those changes are actually needed
>

>On Fri, Apr 27, 2012 at 11:42 PM, Antti Palosaari <crope@iki.fi> wrote:
>> On 27.04.2012 23:21, Konstantin Dimitrov wrote:
>>>
>>> On Fri, Apr 27, 2012 at 10:55 PM, Antti Palosaari<crope@iki.fi>  wrote:
>>>>
>>>> On 27.04.2012 22:01, Konstantin Dimitrov wrote:
>>>>>
>>>>>
>>>>> Mauro, your reasoning makes sense to me. so, let's split them and at
>>>>> least settle this part of the discussion - i will do as far as my
>>>>> spare time allows, as well make sure there are no some problems
>>>>> introduced after the split.
>>>>>
>>>>> also, in one email i've just sent in answer to Antti there is enough
>>>>> argument why such split, i.e. tuner-pass-through-mode is subject to
>>>>> discussion about CX24116 and TDA10071 drivers too. currently, majority
>>>>> of DVB-S2 demodulator drivers in the kernel are married to particular
>>>>> tuners and there is no split.
>>>>
>>>>
>>>>
>>>> I read the mail and as it was long study, I comment only that
>>>> CX24116+CX24118A and TDA10071+CX24118A demod+tuner combos versus Montage
>>>> demod+tuner combos. As you may see, CX24116 and TDA10071 are so much
>>>> different than both needs own driver. But as you said those are married
>>>> always as a demod+tuner.
>>>>
>>>> So if I use your logic, what happens if CX24118A tuner is not driven by
>>>> CX24116 or TDA10071 firmware? ==>  it happens we have two drivers,
>>>> CX24116
>>>> and TDA10071 *both* having similar CX24118A tuner driver code inside!
>>>> Same
>>>> tuner driver code inside two demods drivers. Could you now understand why
>>>> we
>>>> want it split?
>>>> The reason which saves us having CX24118A tuner driver is that it is
>>>> inside
>>>> both CX24116 and TDA10071 firmware.
>>>>
>>>> There is mainly two different controlling situation. Most commonly driver
>>>> controls chip but in some cases it is firmware which is controlling. And
>>>> I
>>>> don't see it very important trying always to by-pass firmware control and
>>>> use driver for that.
>>>>
>>>
>>> i got that point, but what happens if tomorrow their is CX24116 or
>>> TDA10071 design with tuner different than CX14118A? in fact the LG
>>> datasheet i pointed out to you clearly states that for example there
>>> is actually such design - case when CX24116 is used with CX24128 tuner
>>> instead CX24118A in which case the only way is to bypass the firmware
>>> and control the tuner directly. also, isn't it even double bad the
>>> current state of CX24116 or TDA10071 drivers - from one side they use
>>> 2 firmwares, part of which is doing the same, i.e control the CX24118A
>>> and from the other side they depend on proprietary firmware to do
>>> something that can be done in open-source code? i don't know, but at
>>> least from my point of view if that's not worse than the current
>>> status of ds3000 driver, it's at least as wrong as it, i.e. there
>>> isn't not only separation of tuner and demodulator code in CX24116 or
>>> TDA10071 drivers, but there is not even a code that can allow they to
>>> be separated easily, because making CX14118A driver from scratch is
>>> task that will need some effort. anyway, maybe, it's just me, but i
>>> prefer to depend as less as possible on proprietary firmwares done is
>>> such way. however, there is no any doubt current CX24116 or TDA10071
>>> drivers don't allow any other tuner that is not supported by the
>>> proprietary firmware to be used and thus they break the rule of tuner
>>> and demodulator code separation. so, i really don't understand what
>>> makes CX24116 or TDA10071 drivers different than the others, i.e. why
>>> they are developed in such way and there is no discussion about them
>>> to be changed in way that allow use of other tuner like CX24128, which
>>> is not supported by the proprietary firmwares. so, the only
>>> explanation from my perspective is lack of such need in real-life, but
>>> it's the same for ds3000.
>>
>>
>> In case of new device having CX24116 or TDA10071, but different tuner than
>> firmware controlled CX14118A, driver must be changed to support new
>> configuration. Or even make new driver if differences are too big. I suspect
>> implementing new .set_frontend() callback is almost everything what is
>> needed. Then add configuration option .tuner_controlled_by_firmware or
>> something like that. There is likely rather similar existing cases.
>>
>> IIRC someone mentioned AF9035/AF9033 firmwares have different versions for
>> different tuners. Also AF9015 uploads firmware to AF9013 demod, external or
>> internal. Still AF9013 driver could upload firmware independently. There is
>> many kind of cases chip/firmware can control other chips. And if you look
>> AF9015/AF9013 and AF9035/AF9033 drivers you can see some examples of
>> splitting drivers even those are many times integrated together. OK, that
>> AF90xx stuff goes to DVB-T side but it is good example of splitting drivers
>> and supporting very wide set of demod/tuner combinations.
>>
>> And it is nice you found CX24116 is sold by two different tuners :) If those
>> tuners are controlled by the driver we can see similar mess than ds3000 +
>> ts2020 or ts2022. At the some point handling different tuner drivers inside
>> one demod driver goes difficult - errors can be done easily and maintaining
>> goes hard.
>>
>>
>> regards
>> Antti
>> --
>> http://palosaari.fi/
>.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Demod hardware pid filter implement
  2012-04-27 19:01                 ` Konstantin Dimitrov
  2012-04-27 19:36                   ` Mauro Carvalho Chehab
  2012-04-27 19:55                   ` Antti Palosaari
@ 2012-04-28  9:17                   ` nibble.max
  2012-04-28 10:15                     ` Antti Palosaari
  2 siblings, 1 reply; 56+ messages in thread
From: nibble.max @ 2012-04-28  9:17 UTC (permalink / raw)
  To: Antti Palosaari; +Cc: linux-media

Hello Antti,
As we known that AF9013 has the hardware pid filter capability.
How to implement the hardware pid filter, which the demodulator has this capability?

For usb, i find 
struct dvb_usb_adapter_fe_properties {
int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int);
int (*pid_filter)      (struct dvb_usb_adapter *, int, u16, int);
.......
It can implement the hardware filter if the demodulator has.

But on the other interface, i do not find similar solution.
For example, we have a hardware of AF9013 and CX23885 pcie chip and want to use the hardware pid filter in AF9013.
i find some codes to hook the dvb.demux to do that pid filtering.
I think it is demod property, but the current "dvb_frontend_ops" has no definition for this.
It is better that adding a function pointer of pid filtering in "dvb_frontend_ops" to do in general way.
What is your idea?

BR,
Max


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Demod hardware pid filter implement
  2012-04-28  9:17                   ` Demod hardware pid filter implement nibble.max
@ 2012-04-28 10:15                     ` Antti Palosaari
  0 siblings, 0 replies; 56+ messages in thread
From: Antti Palosaari @ 2012-04-28 10:15 UTC (permalink / raw)
  To: nibble.max; +Cc: linux-media

On 28.04.2012 12:17, nibble.max wrote:
> Hello Antti,
> As we known that AF9013 has the hardware pid filter capability.
> How to implement the hardware pid filter, which the demodulator has this capability?
>
> For usb, i find
> struct dvb_usb_adapter_fe_properties {
> int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int);
> int (*pid_filter)      (struct dvb_usb_adapter *, int, u16, int);
> .......
> It can implement the hardware filter if the demodulator has.
>
> But on the other interface, i do not find similar solution.
> For example, we have a hardware of AF9013 and CX23885 pcie chip and want to use the hardware pid filter in AF9013.
> i find some codes to hook the dvb.demux to do that pid filtering.
> I think it is demod property, but the current "dvb_frontend_ops" has no definition for this.
> It is better that adding a function pointer of pid filtering in "dvb_frontend_ops" to do in general way.
> What is your idea?

It is not supported currently - only DVB USB supports it.

In order to PID filter for the demodulator you will need to change DVB 
fronted code. Copy some PID -filtering stuff from the DVB USB to the 
frondend handling.

regards
Antti
-- 
http://palosaari.fi/

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Fwd: [PATCH 2/6 v2] dvbsky, dvb-s/s2 usb box
  2012-04-27  7:06                   ` [PATCH 2/6 v2] dvbsky, dvb-s/s2 usb box nibble.max
@ 2013-06-30  3:07                     ` P. van Gaans
  2014-01-15 19:30                       ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 56+ messages in thread
From: P. van Gaans @ 2013-06-30  3:07 UTC (permalink / raw)
  To: linux-media

Trying to figure out if a Mystique SaTiX-S2 Sky V2 USB device (USB ID 
0572:6831, looks like it is a DVBSKY S960 clone) would be supported 
before I buy, I came along this message.

Looking at 
http://git.linuxtv.org/media_tree.git/blob/HEAD:/drivers/media/usb/dvb-usb/dw2102.c 
it seems as if this patch never made it, so these USB S2 boxes would be 
unsupported.

Would it still be possible to include this patch?

Best regards,

P. van Gaans


-------- Original Message --------
Subject: [PATCH 2/6 v2] dvbsky, dvb-s/s2 usb box
Date: Fri, 27 Apr 2012 15:06:29 +0800
From: nibble.max <nibble.max@gmail.com>
To: Mauro Carvalho Chehab <mchehab@redhat.com>
CC: Antti Palosaari <crope@iki.fi>, linux-media 
<linux-media@vger.kernel.org>

Also fix some code sytle errors checked by checkpatch.pl.
---
  drivers/media/dvb/dvb-usb/Kconfig  |    2 +
  drivers/media/dvb/dvb-usb/dw2102.c |  337 
++++++++++++++++++++++++++++++++----
  2 files changed, 305 insertions(+), 34 deletions(-)

diff --git a/drivers/media/dvb/dvb-usb/Kconfig 
b/drivers/media/dvb/dvb-usb/Kconfig
index be1db75..93c9381 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -279,6 +279,8 @@ config DVB_USB_DW2102
  	select DVB_STV0288 if !DVB_FE_CUSTOMISE
  	select DVB_STB6000 if !DVB_FE_CUSTOMISE
  	select DVB_CX24116 if !DVB_FE_CUSTOMISE
+	select DVB_M88TS202X if !DVB_FE_CUSTOMISE
+	select DVB_M88DS3103 if !DVB_FE_CUSTOMISE
  	select DVB_SI21XX if !DVB_FE_CUSTOMISE
  	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
  	select DVB_MT312 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c 
b/drivers/media/dvb/dvb-usb/dw2102.c
index 451c5a7..1cf62fb 100644
--- a/drivers/media/dvb/dvb-usb/dw2102.c
+++ b/drivers/media/dvb/dvb-usb/dw2102.c
@@ -19,6 +19,8 @@
  #include "stb6000.h"
  #include "eds1547.h"
  #include "cx24116.h"
+#include "m88ts202x.h"
+#include "m88ds3103.h"
  #include "tda1002x.h"
  #include "mt312.h"
  #include "zl10039.h"
@@ -118,12 +120,12 @@ MODULE_PARM_DESC(demod, "demod to probe (1=cx24116 
2=stv0903+stv6110 "
  DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);

  static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
-			u16 index, u8 * data, u16 len, int flags)
+			u16 index, u8 *data, u16 len, int flags)
  {
  	int ret;
  	u8 *u8buf;
  	unsigned int pipe = (flags == DW210X_READ_MSG) ?
-				usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0);
+			usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0);
  	u8 request_type = (flags == DW210X_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;

  	u8buf = kmalloc(len, GFP_KERNEL);
@@ -133,7 +135,8 @@ static int dw210x_op_rw(struct usb_device *dev, u8 
request, u16 value,

  	if (flags == DW210X_WRITE_MSG)
  		memcpy(u8buf, data, len);
-	ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR,
+	ret = usb_control_msg(dev, pipe,
+				request, request_type | USB_TYPE_VENDOR,
  				value, index , u8buf, len, 2000);

  	if (flags == DW210X_READ_MSG)
@@ -179,7 +182,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter 
*adap, struct i2c_msg msg[],
  			break;
  		case 0x60:
  			if (msg[0].flags == 0) {
-			/* write to tuner pll */
+				/* write to tuner pll */
  				buf6[0] = 0x2c;
  				buf6[1] = 5;
  				buf6[2] = 0xc0;
@@ -190,7 +193,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter 
*adap, struct i2c_msg msg[],
  				ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
  						buf6, 7, DW210X_WRITE_MSG);
  			} else {
-			/* read from tuner */
+				/* read from tuner */
  				ret = dw210x_op_rw(d->udev, 0xb5, 0, 0,
  						buf6, 1, DW210X_READ_MSG);
  				msg[0].buf[0] = buf6[0];
@@ -273,7 +276,8 @@ static int dw2102_serit_i2c_transfer(struct 
i2c_adapter *adap,
  	return num;
  }

-static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct 
i2c_msg msg[], int num)
+static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap,
+				struct i2c_msg msg[], int num)
  {
  	struct dvb_usb_device *d = i2c_get_adapdata(adap);
  	int ret = 0;
@@ -346,7 +350,8 @@ static int dw2102_earda_i2c_transfer(struct 
i2c_adapter *adap, struct i2c_msg ms
  	return num;
  }

-static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg 
msg[], int num)
+static int dw2104_i2c_transfer(struct i2c_adapter *adap,
+				struct i2c_msg msg[], int num)
  {
  	struct dvb_usb_device *d = i2c_get_adapdata(adap);
  	int ret = 0;
@@ -712,7 +717,8 @@ static int dw210x_read_mac_address(struct 
dvb_usb_device *d, u8 mac[6])
  	u8 eeprom[256], eepromline[16];

  	for (i = 0; i < 256; i++) {
-		if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2, DW210X_READ_MSG) < 
0) {
+		if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2,
+		DW210X_READ_MSG) < 0) {
  			err("read eeprom failed.");
  			return -1;
  		} else {
@@ -882,6 +888,41 @@ static int s660_set_voltage(struct dvb_frontend 
*fe, fe_sec_voltage_t voltage)
  	return 0;
  }

+static int bstusb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t 
voltage)
+{
+
+	struct dvb_usb_adapter *udev_adap =
+		(struct dvb_usb_adapter *)(fe->dvb->priv);
+
+	u8 obuf[3] = { 0xe, 0x80, 0 };
+	u8 ibuf[] = { 0 };
+
+	info("US6830: %s!\n", __func__);
+
+	if (voltage == SEC_VOLTAGE_OFF)
+		obuf[2] = 0;
+	else
+		obuf[2] = 1;
+
+	if (dvb_usb_generic_rw(udev_adap->dev, obuf, 3, ibuf, 1, 0) < 0)
+		err("command 0x0e transfer failed.");
+	return 0;
+}
+
+static int bstusb_restart(struct dvb_frontend *fe)
+{
+
+	struct dvb_usb_adapter *udev_adap =
+		(struct dvb_usb_adapter *)(fe->dvb->priv);
+
+	u8 obuf[3] = { 0x36, 3, 0 };
+	u8 ibuf[] = { 0 };
+
+	if (dvb_usb_generic_rw(udev_adap->dev, obuf, 3, ibuf, 1, 0) < 0)
+		err("command 0x36 transfer failed.");
+	return 0;
+}
+
  static void dw210x_led_ctrl(struct dvb_frontend *fe, int offon)
  {
  	static u8 led_off[] = { 0 };
@@ -987,12 +1028,37 @@ static struct ds3000_config su3000_ds3000_config = {
  	.ci_mode = 1,
  };

+static struct m88ts202x_config dvbsky_ts202x_config = {
+	.bypasson = 0,
+	.clkout = 0,
+	.clkdiv = 0,
+};
+
+static struct m88ds3103_config US6830_ds3103_config = {
+	.demod_address = 0x68,
+	.ci_mode = 1,
+	.pin_ctrl = 0x83,
+	.ts_mode = 0,
+	.start_ctrl = bstusb_restart,
+	.set_voltage = bstusb_set_voltage,
+};
+
+static struct m88ds3103_config US6832_ds3103_config = {
+	.demod_address = 0x68,
+	.ci_mode = 1,
+	.pin_ctrl = 0x80,
+	.ts_mode = 0,
+	.start_ctrl = bstusb_restart,
+	.set_voltage = bstusb_set_voltage,
+};
+
  static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
  {
  	struct dvb_tuner_ops *tuner_ops = NULL;

  	if (demod_probe & 4) {
-		d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config,
+		d->fe_adap[0].fe = dvb_attach(stv0900_attach,
+				&dw2104a_stv0900_config,
  				&d->dev->i2c_adap, 0);
  		if (d->fe_adap[0].fe != NULL) {
  			if (dvb_attach(stb6100_attach, d->fe_adap[0].fe,
@@ -1003,7 +1069,8 @@ static int dw2104_frontend_attach(struct 
dvb_usb_adapter *d)
  				tuner_ops->get_frequency = stb6100_get_freq;
  				tuner_ops->set_bandwidth = stb6100_set_bandw;
  				tuner_ops->get_bandwidth = stb6100_get_bandw;
-				d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+				d->fe_adap[0].fe->ops.set_voltage =
+							dw210x_set_voltage;
  				info("Attached STV0900+STB6100!\n");
  				return 0;
  			}
@@ -1011,13 +1078,15 @@ static int dw2104_frontend_attach(struct 
dvb_usb_adapter *d)
  	}

  	if (demod_probe & 2) {
-		d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config,
+		d->fe_adap[0].fe = dvb_attach(stv0900_attach,
+				&dw2104_stv0900_config,
  				&d->dev->i2c_adap, 0);
  		if (d->fe_adap[0].fe != NULL) {
  			if (dvb_attach(stv6110_attach, d->fe_adap[0].fe,
  					&dw2104_stv6110_config,
  					&d->dev->i2c_adap)) {
-				d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+				d->fe_adap[0].fe->ops.set_voltage =
+							dw210x_set_voltage;
  				info("Attached STV0900+STV6110A!\n");
  				return 0;
  			}
@@ -1053,7 +1122,8 @@ static int dw2102_frontend_attach(struct 
dvb_usb_adapter *d)
  {
  	if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) {
  		/*dw2102_properties.adapter->tuner_attach = NULL;*/
-		d->fe_adap[0].fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config,
+		d->fe_adap[0].fe = dvb_attach(si21xx_attach,
+					&serit_sp1511lhb_config,
  					&d->dev->i2c_adap);
  		if (d->fe_adap[0].fe != NULL) {
  			d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
@@ -1068,7 +1138,8 @@ static int dw2102_frontend_attach(struct 
dvb_usb_adapter *d)
  		if (d->fe_adap[0].fe != NULL) {
  			if (dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61,
  					&d->dev->i2c_adap)) {
-				d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
+				d->fe_adap[0].fe->ops.set_voltage =
+							dw210x_set_voltage;
  				info("Attached stv0288!\n");
  				return 0;
  			}
@@ -1076,8 +1147,10 @@ static int dw2102_frontend_attach(struct 
dvb_usb_adapter *d)
  	}

  	if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) {
-		/*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/
-		d->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194a_config,
+		/*dw2102_properties.adapter->tuner_attach =
+						dw2102_tuner_attach;*/
+		d->fe_adap[0].fe = dvb_attach(stv0299_attach,
+					&sharp_z0194a_config,
  					&d->dev->i2c_adap);
  		if (d->fe_adap[0].fe != NULL) {
  			d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
@@ -1125,7 +1198,8 @@ static int stv0288_frontend_attach(struct 
dvb_usb_adapter *d)
  	if (d->fe_adap[0].fe == NULL)
  		return -EIO;

-	if (NULL == dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61, 
&d->dev->i2c_adap))
+	if (NULL == dvb_attach(stb6000_attach, d->fe_adap[0].fe,
+				0x61, &d->dev->i2c_adap))
  		return -EIO;

  	d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
@@ -1213,6 +1287,63 @@ static int su3000_frontend_attach(struct 
dvb_usb_adapter *d)

  	return 0;
  }
+static int dvbsky_usb_frontend_attach(struct dvb_usb_adapter *d,
+					struct m88ds3103_config *pdconf,
+					struct m88ts202x_config *ptconf)
+{
+	struct m88ts202x_devctl *ctrl;
+
+	u8 obuf[3] = { 0xe, 0x83, 0 };
+	u8 ibuf[] = { 0 };
+
+	info("dvbsky: %s!\n", __func__);
+	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+		err("command 0x0e transfer failed.");
+
+	obuf[0] = 0xe;
+	obuf[1] = 0x83;
+	obuf[2] = 1;
+
+	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+		err("command 0x0e transfer failed.");
+
+	obuf[0] = 0x51;
+
+	if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
+		err("command 0x51 transfer failed.");
+
+	d->fe_adap[0].fe = dvb_attach(m88ds3103_attach, pdconf,
+					&d->dev->i2c_adap);
+	if (d->fe_adap[0].fe == NULL)
+		return -EIO;
+	ctrl =	dvb_attach(m88ts202x_attach,
+				d->fe_adap[0].fe, ptconf, &d->dev->i2c_adap);
+	if (!ctrl) {
+		printk(KERN_ERR "No m88ts202x found!\n");
+		return -ENODEV;
+	}
+	pdconf->tuner_init = ctrl->tuner_init;
+	pdconf->tuner_sleep = ctrl->tuner_sleep;
+	pdconf->tuner_wakeup = ctrl->tuner_wakeup;
+	pdconf->tuner_set_frequency = ctrl->tuner_set_frequency;
+	pdconf->tuner_get_rfgain = ctrl->tuner_get_rfgain;
+	info("Attached M88DS3103!\n");
+	return 0;
+}
+
+static int US6830_frontend_attach(struct dvb_usb_adapter *d)
+{
+	return dvbsky_usb_frontend_attach(d,
+					&US6830_ds3103_config,
+					&dvbsky_ts202x_config);
+}
+
+static int US6832_frontend_attach(struct dvb_usb_adapter *d)
+{
+	return dvbsky_usb_frontend_attach(d,
+					&US6832_ds3103_config,
+					&dvbsky_ts202x_config);
+}

  static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
  {
@@ -1435,6 +1566,28 @@ static int dw2102_rc_query(struct dvb_usb_device 
*d, u32 *event, int *state)
  	return 0;
  }

+/* dvbsky remote control */
+static int dvbsky_rc_query(struct dvb_usb_device *d)
+{
+	unsigned code = 0;
+	u8 obuf[0x40], ibuf[0x40], toggle;
+
+	obuf[0] = 0x10;
+	if (dvb_usb_generic_rw(d, obuf, 1, ibuf, 2, 0) < 0)
+		err("rc transfer failed.");
+	code = (ibuf[0] << 8) | ibuf[1];
+	if (code != 0xffff) {
+		info("dvbsky rc code: %x", code);
+
+		toggle = (code & 0x800) ? 1 : 0;
+		code &= 0x3f;
+
+		rc_keydown(d->rc_dev, code, toggle);
+	}
+
+	return 0;
+}
+
  enum dw2102_table_entry {
  	CYPRESS_DW2102,
  	CYPRESS_DW2101,
@@ -1451,6 +1604,9 @@ enum dw2102_table_entry {
  	TEVII_S480_1,
  	TEVII_S480_2,
  	X3M_SPC1400HD,
+	BST_US6830HD,
+	BST_US6831HD,
+	BST_US6832HD,
  };

  static struct usb_device_id dw2102_table[] = {
@@ -1458,7 +1614,8 @@ static struct usb_device_id dw2102_table[] = {
  	[CYPRESS_DW2101] = {USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
  	[CYPRESS_DW2104] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)},
  	[TEVII_S650] = {USB_DEVICE(0x9022, USB_PID_TEVII_S650)},
-	[TERRATEC_CINERGY_S] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
+	[TERRATEC_CINERGY_S] = {USB_DEVICE(USB_VID_TERRATEC,
+				USB_PID_CINERGY_S)},
  	[CYPRESS_DW3101] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)},
  	[TEVII_S630] = {USB_DEVICE(0x9022, USB_PID_TEVII_S630)},
  	[PROF_1100] = {USB_DEVICE(0x3011, USB_PID_PROF_1100)},
@@ -1469,6 +1626,9 @@ static struct usb_device_id dw2102_table[] = {
  	[TEVII_S480_1] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)},
  	[TEVII_S480_2] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)},
  	[X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)},
+	[BST_US6830HD] = {USB_DEVICE(0x0572, 0x6830)},
+	[BST_US6831HD] = {USB_DEVICE(0x0572, 0x6831)},
+	[BST_US6832HD] = {USB_DEVICE(0x0572, 0x6832)},
  	{ }
  };

@@ -1529,7 +1689,8 @@ static int dw2102_load_firmware(struct usb_device 
*dev,
  		/* init registers */
  		switch (dev->descriptor.idProduct) {
  		case USB_PID_TEVII_S650:
-			dw2104_properties.rc.legacy.rc_map_table = rc_map_tevii_table;
+			dw2104_properties.rc.legacy.rc_map_table =
+							rc_map_tevii_table;
  			dw2104_properties.rc.legacy.rc_map_size =
  					ARRAY_SIZE(rc_map_tevii_table);
  		case USB_PID_DW2104:
@@ -1553,7 +1714,8 @@ static int dw2102_load_firmware(struct usb_device 
*dev,
  					DW210X_READ_MSG);
  			if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) {
  				dw2102_properties.i2c_algo = &dw2102_i2c_algo;
-				dw2102_properties.adapter->fe[0].tuner_attach = &dw2102_tuner_attach;
+				dw2102_properties.adapter->fe[0].tuner_attach =
+							&dw2102_tuner_attach;
  				break;
  			} else {
  				/* check STV0288 frontend  */
@@ -1565,7 +1727,8 @@ static int dw2102_load_firmware(struct usb_device 
*dev,
  				dw210x_op_rw(dev, 0xc3, 0xd1, 0, &reset16[0], 3,
  						DW210X_READ_MSG);
  				if (reset16[2] == 0x11) {
-					dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo;
+					dw2102_properties.i2c_algo =
+							&dw2102_earda_i2c_algo;
  					break;
  				}
  			}
@@ -1622,7 +1785,7 @@ static struct dvb_usb_device_properties 
dw2102_properties = {
  					}
  				}
  			},
-		}},
+		} },
  		}
  	},
  	.num_device_descs = 3,
@@ -1676,7 +1839,7 @@ static struct dvb_usb_device_properties 
dw2104_properties = {
  					}
  				}
  			},
-		}},
+		} },
  		}
  	},
  	.num_device_descs = 2,
@@ -1727,7 +1890,7 @@ static struct dvb_usb_device_properties 
dw3101_properties = {
  					}
  				}
  			},
-		}},
+		} },
  		}
  	},
  	.num_device_descs = 1,
@@ -1773,7 +1936,7 @@ static struct dvb_usb_device_properties 
s6x0_properties = {
  					}
  				}
  			},
-		}},
+		} },
  		}
  	},
  	.num_device_descs = 1,
@@ -1854,7 +2017,7 @@ static struct dvb_usb_device_properties 
su3000_properties = {
  					}
  				}
  			}
-		}},
+		} },
  		}
  	},
  	.num_device_descs = 3,
@@ -1874,6 +2037,108 @@ static struct dvb_usb_device_properties 
su3000_properties = {
  	}
  };

+static struct dvb_usb_device_properties US6830_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.size_of_priv = sizeof(struct su3000_state),
+	.power_ctrl = su3000_power_ctrl,
+	.num_adapters = 1,
+	.identify_state	= su3000_identify_state,
+	.i2c_algo = &su3000_i2c_algo,
+
+	.rc.core = {
+		.rc_interval      = 300,
+		.rc_codes         = RC_MAP_DVBSKY,
+		.module_name	  = "dvbskyir",
+		.rc_query         = dvbsky_rc_query,
+		.allowed_protos   = RC_TYPE_RC5,
+	},
+
+	.read_mac_address = su3000_read_mac_address,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = { {
+			.streaming_ctrl   = su3000_streaming_ctrl,
+			.frontend_attach  = US6830_frontend_attach,
+			.stream = {
+				.type = USB_BULK,
+				.count = 8,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			}
+		} },
+		}
+	},
+	.num_device_descs = 2,
+	.devices = {
+		{ "Bestunar US6830 HD",
+			{ &dw2102_table[BST_US6830HD], NULL },
+			{ NULL },
+		},
+		{ "Bestunar US6831 HD",
+			{ &dw2102_table[BST_US6831HD], NULL },
+			{ NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties US6832_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.size_of_priv = sizeof(struct su3000_state),
+	.power_ctrl = su3000_power_ctrl,
+	.num_adapters = 1,
+	.identify_state	= su3000_identify_state,
+	.i2c_algo = &su3000_i2c_algo,
+
+	.rc.core = {
+		.rc_interval      = 300,
+		.rc_codes         = RC_MAP_DVBSKY,
+		.module_name	  = "dvbskyir",
+		.rc_query         = dvbsky_rc_query,
+		.allowed_protos   = RC_TYPE_RC5,
+	},
+
+	.read_mac_address = su3000_read_mac_address,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.adapter = {
+		{
+		.num_frontends = 1,
+		.fe = { {
+			.streaming_ctrl   = su3000_streaming_ctrl,
+			.frontend_attach  = US6832_frontend_attach,
+			.stream = {
+				.type = USB_BULK,
+				.count = 8,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			}
+		} },
+		}
+	},
+	.num_device_descs = 1,
+	.devices = {
+		{ "Bestunar US6832 HD",
+			{ &dw2102_table[BST_US6832HD], NULL },
+			{ NULL },
+		},
+	}
+};
+
  static int dw2102_probe(struct usb_interface *intf,
  		const struct usb_device_id *id)
  {
@@ -1917,20 +2182,24 @@ static int dw2102_probe(struct usb_interface *intf,

  	if (0 == dvb_usb_device_init(intf, &dw2102_properties,
  			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &dw2104_properties,
+		0 == dvb_usb_device_init(intf, &dw2104_properties,
+			THIS_MODULE, NULL, adapter_nr) ||
+		0 == dvb_usb_device_init(intf, &dw3101_properties,
+			THIS_MODULE, NULL, adapter_nr) ||
+		0 == dvb_usb_device_init(intf, &s6x0_properties,
  			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &dw3101_properties,
+		0 == dvb_usb_device_init(intf, p1100,
  			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &s6x0_properties,
+		0 == dvb_usb_device_init(intf, s660,
  			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, p1100,
+		0 == dvb_usb_device_init(intf, p7500,
  			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, s660,
+		0 == dvb_usb_device_init(intf, &su3000_properties,
  			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, p7500,
+		0 == dvb_usb_device_init(intf, &US6830_properties,
  			THIS_MODULE, NULL, adapter_nr) ||
-	    0 == dvb_usb_device_init(intf, &su3000_properties,
-				     THIS_MODULE, NULL, adapter_nr))
+		0 == dvb_usb_device_init(intf, &US6832_properties,
+			THIS_MODULE, NULL, adapter_nr))
  		return 0;

  	return -ENODEV;
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html




^ permalink raw reply related	[flat|nested] 56+ messages in thread

* Re: [PATCH 2/6 v2] dvbsky, dvb-s/s2 usb box
  2013-06-30  3:07                     ` Fwd: " P. van Gaans
@ 2014-01-15 19:30                       ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 56+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-15 19:30 UTC (permalink / raw)
  To: P. van Gaans; +Cc: linux-media

Em Sun, 30 Jun 2013 05:07:09 +0200
"P. van Gaans" <w3ird_n3rd@gmx.net> escreveu:

> Trying to figure out if a Mystique SaTiX-S2 Sky V2 USB device (USB ID 
> 0572:6831, looks like it is a DVBSKY S960 clone) would be supported 
> before I buy, I came along this message.
> 
> Looking at 
> http://git.linuxtv.org/media_tree.git/blob/HEAD:/drivers/media/usb/dvb-usb/dw2102.c 
> it seems as if this patch never made it, so these USB S2 boxes would be 
> unsupported.
> 
> Would it still be possible to include this patch?

There were some issues with this patch that were never solved. However,
support for those new chips were added as another driver. Some bits may
still be needed to support your specific board, though.

Regards,
Mauro

> 
> Best regards,
> 
> P. van Gaans
> 
> 
> -------- Original Message --------
> Subject: [PATCH 2/6 v2] dvbsky, dvb-s/s2 usb box
> Date: Fri, 27 Apr 2012 15:06:29 +0800
> From: nibble.max <nibble.max@gmail.com>
> To: Mauro Carvalho Chehab <mchehab@redhat.com>
> CC: Antti Palosaari <crope@iki.fi>, linux-media 
> <linux-media@vger.kernel.org>
> 
> Also fix some code sytle errors checked by checkpatch.pl.
> ---
>   drivers/media/dvb/dvb-usb/Kconfig  |    2 +
>   drivers/media/dvb/dvb-usb/dw2102.c |  337 
> ++++++++++++++++++++++++++++++++----
>   2 files changed, 305 insertions(+), 34 deletions(-)
> 
> diff --git a/drivers/media/dvb/dvb-usb/Kconfig 
> b/drivers/media/dvb/dvb-usb/Kconfig
> index be1db75..93c9381 100644
> --- a/drivers/media/dvb/dvb-usb/Kconfig
> +++ b/drivers/media/dvb/dvb-usb/Kconfig
> @@ -279,6 +279,8 @@ config DVB_USB_DW2102
>   	select DVB_STV0288 if !DVB_FE_CUSTOMISE
>   	select DVB_STB6000 if !DVB_FE_CUSTOMISE
>   	select DVB_CX24116 if !DVB_FE_CUSTOMISE
> +	select DVB_M88TS202X if !DVB_FE_CUSTOMISE
> +	select DVB_M88DS3103 if !DVB_FE_CUSTOMISE
>   	select DVB_SI21XX if !DVB_FE_CUSTOMISE
>   	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
>   	select DVB_MT312 if !DVB_FE_CUSTOMISE
> diff --git a/drivers/media/dvb/dvb-usb/dw2102.c 
> b/drivers/media/dvb/dvb-usb/dw2102.c
> index 451c5a7..1cf62fb 100644
> --- a/drivers/media/dvb/dvb-usb/dw2102.c
> +++ b/drivers/media/dvb/dvb-usb/dw2102.c
> @@ -19,6 +19,8 @@
>   #include "stb6000.h"
>   #include "eds1547.h"
>   #include "cx24116.h"
> +#include "m88ts202x.h"
> +#include "m88ds3103.h"
>   #include "tda1002x.h"
>   #include "mt312.h"
>   #include "zl10039.h"
> @@ -118,12 +120,12 @@ MODULE_PARM_DESC(demod, "demod to probe (1=cx24116 
> 2=stv0903+stv6110 "
>   DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
> 
>   static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
> -			u16 index, u8 * data, u16 len, int flags)
> +			u16 index, u8 *data, u16 len, int flags)
>   {
>   	int ret;
>   	u8 *u8buf;
>   	unsigned int pipe = (flags == DW210X_READ_MSG) ?
> -				usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0);
> +			usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0);
>   	u8 request_type = (flags == DW210X_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
> 
>   	u8buf = kmalloc(len, GFP_KERNEL);
> @@ -133,7 +135,8 @@ static int dw210x_op_rw(struct usb_device *dev, u8 
> request, u16 value,
> 
>   	if (flags == DW210X_WRITE_MSG)
>   		memcpy(u8buf, data, len);
> -	ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR,
> +	ret = usb_control_msg(dev, pipe,
> +				request, request_type | USB_TYPE_VENDOR,
>   				value, index , u8buf, len, 2000);
> 
>   	if (flags == DW210X_READ_MSG)
> @@ -179,7 +182,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter 
> *adap, struct i2c_msg msg[],
>   			break;
>   		case 0x60:
>   			if (msg[0].flags == 0) {
> -			/* write to tuner pll */
> +				/* write to tuner pll */
>   				buf6[0] = 0x2c;
>   				buf6[1] = 5;
>   				buf6[2] = 0xc0;
> @@ -190,7 +193,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter 
> *adap, struct i2c_msg msg[],
>   				ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
>   						buf6, 7, DW210X_WRITE_MSG);
>   			} else {
> -			/* read from tuner */
> +				/* read from tuner */
>   				ret = dw210x_op_rw(d->udev, 0xb5, 0, 0,
>   						buf6, 1, DW210X_READ_MSG);
>   				msg[0].buf[0] = buf6[0];
> @@ -273,7 +276,8 @@ static int dw2102_serit_i2c_transfer(struct 
> i2c_adapter *adap,
>   	return num;
>   }
> 
> -static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct 
> i2c_msg msg[], int num)
> +static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap,
> +				struct i2c_msg msg[], int num)
>   {
>   	struct dvb_usb_device *d = i2c_get_adapdata(adap);
>   	int ret = 0;
> @@ -346,7 +350,8 @@ static int dw2102_earda_i2c_transfer(struct 
> i2c_adapter *adap, struct i2c_msg ms
>   	return num;
>   }
> 
> -static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg 
> msg[], int num)
> +static int dw2104_i2c_transfer(struct i2c_adapter *adap,
> +				struct i2c_msg msg[], int num)
>   {
>   	struct dvb_usb_device *d = i2c_get_adapdata(adap);
>   	int ret = 0;
> @@ -712,7 +717,8 @@ static int dw210x_read_mac_address(struct 
> dvb_usb_device *d, u8 mac[6])
>   	u8 eeprom[256], eepromline[16];
> 
>   	for (i = 0; i < 256; i++) {
> -		if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2, DW210X_READ_MSG) < 
> 0) {
> +		if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2,
> +		DW210X_READ_MSG) < 0) {
>   			err("read eeprom failed.");
>   			return -1;
>   		} else {
> @@ -882,6 +888,41 @@ static int s660_set_voltage(struct dvb_frontend 
> *fe, fe_sec_voltage_t voltage)
>   	return 0;
>   }
> 
> +static int bstusb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t 
> voltage)
> +{
> +
> +	struct dvb_usb_adapter *udev_adap =
> +		(struct dvb_usb_adapter *)(fe->dvb->priv);
> +
> +	u8 obuf[3] = { 0xe, 0x80, 0 };
> +	u8 ibuf[] = { 0 };
> +
> +	info("US6830: %s!\n", __func__);
> +
> +	if (voltage == SEC_VOLTAGE_OFF)
> +		obuf[2] = 0;
> +	else
> +		obuf[2] = 1;
> +
> +	if (dvb_usb_generic_rw(udev_adap->dev, obuf, 3, ibuf, 1, 0) < 0)
> +		err("command 0x0e transfer failed.");
> +	return 0;
> +}
> +
> +static int bstusb_restart(struct dvb_frontend *fe)
> +{
> +
> +	struct dvb_usb_adapter *udev_adap =
> +		(struct dvb_usb_adapter *)(fe->dvb->priv);
> +
> +	u8 obuf[3] = { 0x36, 3, 0 };
> +	u8 ibuf[] = { 0 };
> +
> +	if (dvb_usb_generic_rw(udev_adap->dev, obuf, 3, ibuf, 1, 0) < 0)
> +		err("command 0x36 transfer failed.");
> +	return 0;
> +}
> +
>   static void dw210x_led_ctrl(struct dvb_frontend *fe, int offon)
>   {
>   	static u8 led_off[] = { 0 };
> @@ -987,12 +1028,37 @@ static struct ds3000_config su3000_ds3000_config = {
>   	.ci_mode = 1,
>   };
> 
> +static struct m88ts202x_config dvbsky_ts202x_config = {
> +	.bypasson = 0,
> +	.clkout = 0,
> +	.clkdiv = 0,
> +};
> +
> +static struct m88ds3103_config US6830_ds3103_config = {
> +	.demod_address = 0x68,
> +	.ci_mode = 1,
> +	.pin_ctrl = 0x83,
> +	.ts_mode = 0,
> +	.start_ctrl = bstusb_restart,
> +	.set_voltage = bstusb_set_voltage,
> +};
> +
> +static struct m88ds3103_config US6832_ds3103_config = {
> +	.demod_address = 0x68,
> +	.ci_mode = 1,
> +	.pin_ctrl = 0x80,
> +	.ts_mode = 0,
> +	.start_ctrl = bstusb_restart,
> +	.set_voltage = bstusb_set_voltage,
> +};
> +
>   static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
>   {
>   	struct dvb_tuner_ops *tuner_ops = NULL;
> 
>   	if (demod_probe & 4) {
> -		d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config,
> +		d->fe_adap[0].fe = dvb_attach(stv0900_attach,
> +				&dw2104a_stv0900_config,
>   				&d->dev->i2c_adap, 0);
>   		if (d->fe_adap[0].fe != NULL) {
>   			if (dvb_attach(stb6100_attach, d->fe_adap[0].fe,
> @@ -1003,7 +1069,8 @@ static int dw2104_frontend_attach(struct 
> dvb_usb_adapter *d)
>   				tuner_ops->get_frequency = stb6100_get_freq;
>   				tuner_ops->set_bandwidth = stb6100_set_bandw;
>   				tuner_ops->get_bandwidth = stb6100_get_bandw;
> -				d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
> +				d->fe_adap[0].fe->ops.set_voltage =
> +							dw210x_set_voltage;
>   				info("Attached STV0900+STB6100!\n");
>   				return 0;
>   			}
> @@ -1011,13 +1078,15 @@ static int dw2104_frontend_attach(struct 
> dvb_usb_adapter *d)
>   	}
> 
>   	if (demod_probe & 2) {
> -		d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config,
> +		d->fe_adap[0].fe = dvb_attach(stv0900_attach,
> +				&dw2104_stv0900_config,
>   				&d->dev->i2c_adap, 0);
>   		if (d->fe_adap[0].fe != NULL) {
>   			if (dvb_attach(stv6110_attach, d->fe_adap[0].fe,
>   					&dw2104_stv6110_config,
>   					&d->dev->i2c_adap)) {
> -				d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
> +				d->fe_adap[0].fe->ops.set_voltage =
> +							dw210x_set_voltage;
>   				info("Attached STV0900+STV6110A!\n");
>   				return 0;
>   			}
> @@ -1053,7 +1122,8 @@ static int dw2102_frontend_attach(struct 
> dvb_usb_adapter *d)
>   {
>   	if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) {
>   		/*dw2102_properties.adapter->tuner_attach = NULL;*/
> -		d->fe_adap[0].fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config,
> +		d->fe_adap[0].fe = dvb_attach(si21xx_attach,
> +					&serit_sp1511lhb_config,
>   					&d->dev->i2c_adap);
>   		if (d->fe_adap[0].fe != NULL) {
>   			d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
> @@ -1068,7 +1138,8 @@ static int dw2102_frontend_attach(struct 
> dvb_usb_adapter *d)
>   		if (d->fe_adap[0].fe != NULL) {
>   			if (dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61,
>   					&d->dev->i2c_adap)) {
> -				d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
> +				d->fe_adap[0].fe->ops.set_voltage =
> +							dw210x_set_voltage;
>   				info("Attached stv0288!\n");
>   				return 0;
>   			}
> @@ -1076,8 +1147,10 @@ static int dw2102_frontend_attach(struct 
> dvb_usb_adapter *d)
>   	}
> 
>   	if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) {
> -		/*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/
> -		d->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194a_config,
> +		/*dw2102_properties.adapter->tuner_attach =
> +						dw2102_tuner_attach;*/
> +		d->fe_adap[0].fe = dvb_attach(stv0299_attach,
> +					&sharp_z0194a_config,
>   					&d->dev->i2c_adap);
>   		if (d->fe_adap[0].fe != NULL) {
>   			d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
> @@ -1125,7 +1198,8 @@ static int stv0288_frontend_attach(struct 
> dvb_usb_adapter *d)
>   	if (d->fe_adap[0].fe == NULL)
>   		return -EIO;
> 
> -	if (NULL == dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61, 
> &d->dev->i2c_adap))
> +	if (NULL == dvb_attach(stb6000_attach, d->fe_adap[0].fe,
> +				0x61, &d->dev->i2c_adap))
>   		return -EIO;
> 
>   	d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
> @@ -1213,6 +1287,63 @@ static int su3000_frontend_attach(struct 
> dvb_usb_adapter *d)
> 
>   	return 0;
>   }
> +static int dvbsky_usb_frontend_attach(struct dvb_usb_adapter *d,
> +					struct m88ds3103_config *pdconf,
> +					struct m88ts202x_config *ptconf)
> +{
> +	struct m88ts202x_devctl *ctrl;
> +
> +	u8 obuf[3] = { 0xe, 0x83, 0 };
> +	u8 ibuf[] = { 0 };
> +
> +	info("dvbsky: %s!\n", __func__);
> +	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
> +		err("command 0x0e transfer failed.");
> +
> +	obuf[0] = 0xe;
> +	obuf[1] = 0x83;
> +	obuf[2] = 1;
> +
> +	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
> +		err("command 0x0e transfer failed.");
> +
> +	obuf[0] = 0x51;
> +
> +	if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
> +		err("command 0x51 transfer failed.");
> +
> +	d->fe_adap[0].fe = dvb_attach(m88ds3103_attach, pdconf,
> +					&d->dev->i2c_adap);
> +	if (d->fe_adap[0].fe == NULL)
> +		return -EIO;
> +	ctrl =	dvb_attach(m88ts202x_attach,
> +				d->fe_adap[0].fe, ptconf, &d->dev->i2c_adap);
> +	if (!ctrl) {
> +		printk(KERN_ERR "No m88ts202x found!\n");
> +		return -ENODEV;
> +	}
> +	pdconf->tuner_init = ctrl->tuner_init;
> +	pdconf->tuner_sleep = ctrl->tuner_sleep;
> +	pdconf->tuner_wakeup = ctrl->tuner_wakeup;
> +	pdconf->tuner_set_frequency = ctrl->tuner_set_frequency;
> +	pdconf->tuner_get_rfgain = ctrl->tuner_get_rfgain;
> +	info("Attached M88DS3103!\n");
> +	return 0;
> +}
> +
> +static int US6830_frontend_attach(struct dvb_usb_adapter *d)
> +{
> +	return dvbsky_usb_frontend_attach(d,
> +					&US6830_ds3103_config,
> +					&dvbsky_ts202x_config);
> +}
> +
> +static int US6832_frontend_attach(struct dvb_usb_adapter *d)
> +{
> +	return dvbsky_usb_frontend_attach(d,
> +					&US6832_ds3103_config,
> +					&dvbsky_ts202x_config);
> +}
> 
>   static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
>   {
> @@ -1435,6 +1566,28 @@ static int dw2102_rc_query(struct dvb_usb_device 
> *d, u32 *event, int *state)
>   	return 0;
>   }
> 
> +/* dvbsky remote control */
> +static int dvbsky_rc_query(struct dvb_usb_device *d)
> +{
> +	unsigned code = 0;
> +	u8 obuf[0x40], ibuf[0x40], toggle;
> +
> +	obuf[0] = 0x10;
> +	if (dvb_usb_generic_rw(d, obuf, 1, ibuf, 2, 0) < 0)
> +		err("rc transfer failed.");
> +	code = (ibuf[0] << 8) | ibuf[1];
> +	if (code != 0xffff) {
> +		info("dvbsky rc code: %x", code);
> +
> +		toggle = (code & 0x800) ? 1 : 0;
> +		code &= 0x3f;
> +
> +		rc_keydown(d->rc_dev, code, toggle);
> +	}
> +
> +	return 0;
> +}
> +
>   enum dw2102_table_entry {
>   	CYPRESS_DW2102,
>   	CYPRESS_DW2101,
> @@ -1451,6 +1604,9 @@ enum dw2102_table_entry {
>   	TEVII_S480_1,
>   	TEVII_S480_2,
>   	X3M_SPC1400HD,
> +	BST_US6830HD,
> +	BST_US6831HD,
> +	BST_US6832HD,
>   };
> 
>   static struct usb_device_id dw2102_table[] = {
> @@ -1458,7 +1614,8 @@ static struct usb_device_id dw2102_table[] = {
>   	[CYPRESS_DW2101] = {USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
>   	[CYPRESS_DW2104] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)},
>   	[TEVII_S650] = {USB_DEVICE(0x9022, USB_PID_TEVII_S650)},
> -	[TERRATEC_CINERGY_S] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
> +	[TERRATEC_CINERGY_S] = {USB_DEVICE(USB_VID_TERRATEC,
> +				USB_PID_CINERGY_S)},
>   	[CYPRESS_DW3101] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)},
>   	[TEVII_S630] = {USB_DEVICE(0x9022, USB_PID_TEVII_S630)},
>   	[PROF_1100] = {USB_DEVICE(0x3011, USB_PID_PROF_1100)},
> @@ -1469,6 +1626,9 @@ static struct usb_device_id dw2102_table[] = {
>   	[TEVII_S480_1] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)},
>   	[TEVII_S480_2] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)},
>   	[X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)},
> +	[BST_US6830HD] = {USB_DEVICE(0x0572, 0x6830)},
> +	[BST_US6831HD] = {USB_DEVICE(0x0572, 0x6831)},
> +	[BST_US6832HD] = {USB_DEVICE(0x0572, 0x6832)},
>   	{ }
>   };
> 
> @@ -1529,7 +1689,8 @@ static int dw2102_load_firmware(struct usb_device 
> *dev,
>   		/* init registers */
>   		switch (dev->descriptor.idProduct) {
>   		case USB_PID_TEVII_S650:
> -			dw2104_properties.rc.legacy.rc_map_table = rc_map_tevii_table;
> +			dw2104_properties.rc.legacy.rc_map_table =
> +							rc_map_tevii_table;
>   			dw2104_properties.rc.legacy.rc_map_size =
>   					ARRAY_SIZE(rc_map_tevii_table);
>   		case USB_PID_DW2104:
> @@ -1553,7 +1714,8 @@ static int dw2102_load_firmware(struct usb_device 
> *dev,
>   					DW210X_READ_MSG);
>   			if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) {
>   				dw2102_properties.i2c_algo = &dw2102_i2c_algo;
> -				dw2102_properties.adapter->fe[0].tuner_attach = &dw2102_tuner_attach;
> +				dw2102_properties.adapter->fe[0].tuner_attach =
> +							&dw2102_tuner_attach;
>   				break;
>   			} else {
>   				/* check STV0288 frontend  */
> @@ -1565,7 +1727,8 @@ static int dw2102_load_firmware(struct usb_device 
> *dev,
>   				dw210x_op_rw(dev, 0xc3, 0xd1, 0, &reset16[0], 3,
>   						DW210X_READ_MSG);
>   				if (reset16[2] == 0x11) {
> -					dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo;
> +					dw2102_properties.i2c_algo =
> +							&dw2102_earda_i2c_algo;
>   					break;
>   				}
>   			}
> @@ -1622,7 +1785,7 @@ static struct dvb_usb_device_properties 
> dw2102_properties = {
>   					}
>   				}
>   			},
> -		}},
> +		} },
>   		}
>   	},
>   	.num_device_descs = 3,
> @@ -1676,7 +1839,7 @@ static struct dvb_usb_device_properties 
> dw2104_properties = {
>   					}
>   				}
>   			},
> -		}},
> +		} },
>   		}
>   	},
>   	.num_device_descs = 2,
> @@ -1727,7 +1890,7 @@ static struct dvb_usb_device_properties 
> dw3101_properties = {
>   					}
>   				}
>   			},
> -		}},
> +		} },
>   		}
>   	},
>   	.num_device_descs = 1,
> @@ -1773,7 +1936,7 @@ static struct dvb_usb_device_properties 
> s6x0_properties = {
>   					}
>   				}
>   			},
> -		}},
> +		} },
>   		}
>   	},
>   	.num_device_descs = 1,
> @@ -1854,7 +2017,7 @@ static struct dvb_usb_device_properties 
> su3000_properties = {
>   					}
>   				}
>   			}
> -		}},
> +		} },
>   		}
>   	},
>   	.num_device_descs = 3,
> @@ -1874,6 +2037,108 @@ static struct dvb_usb_device_properties 
> su3000_properties = {
>   	}
>   };
> 
> +static struct dvb_usb_device_properties US6830_properties = {
> +	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
> +	.usb_ctrl = DEVICE_SPECIFIC,
> +	.size_of_priv = sizeof(struct su3000_state),
> +	.power_ctrl = su3000_power_ctrl,
> +	.num_adapters = 1,
> +	.identify_state	= su3000_identify_state,
> +	.i2c_algo = &su3000_i2c_algo,
> +
> +	.rc.core = {
> +		.rc_interval      = 300,
> +		.rc_codes         = RC_MAP_DVBSKY,
> +		.module_name	  = "dvbskyir",
> +		.rc_query         = dvbsky_rc_query,
> +		.allowed_protos   = RC_TYPE_RC5,
> +	},
> +
> +	.read_mac_address = su3000_read_mac_address,
> +
> +	.generic_bulk_ctrl_endpoint = 0x01,
> +
> +	.adapter = {
> +		{
> +		.num_frontends = 1,
> +		.fe = { {
> +			.streaming_ctrl   = su3000_streaming_ctrl,
> +			.frontend_attach  = US6830_frontend_attach,
> +			.stream = {
> +				.type = USB_BULK,
> +				.count = 8,
> +				.endpoint = 0x82,
> +				.u = {
> +					.bulk = {
> +						.buffersize = 4096,
> +					}
> +				}
> +			}
> +		} },
> +		}
> +	},
> +	.num_device_descs = 2,
> +	.devices = {
> +		{ "Bestunar US6830 HD",
> +			{ &dw2102_table[BST_US6830HD], NULL },
> +			{ NULL },
> +		},
> +		{ "Bestunar US6831 HD",
> +			{ &dw2102_table[BST_US6831HD], NULL },
> +			{ NULL },
> +		},
> +	}
> +};
> +
> +static struct dvb_usb_device_properties US6832_properties = {
> +	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
> +	.usb_ctrl = DEVICE_SPECIFIC,
> +	.size_of_priv = sizeof(struct su3000_state),
> +	.power_ctrl = su3000_power_ctrl,
> +	.num_adapters = 1,
> +	.identify_state	= su3000_identify_state,
> +	.i2c_algo = &su3000_i2c_algo,
> +
> +	.rc.core = {
> +		.rc_interval      = 300,
> +		.rc_codes         = RC_MAP_DVBSKY,
> +		.module_name	  = "dvbskyir",
> +		.rc_query         = dvbsky_rc_query,
> +		.allowed_protos   = RC_TYPE_RC5,
> +	},
> +
> +	.read_mac_address = su3000_read_mac_address,
> +
> +	.generic_bulk_ctrl_endpoint = 0x01,
> +
> +	.adapter = {
> +		{
> +		.num_frontends = 1,
> +		.fe = { {
> +			.streaming_ctrl   = su3000_streaming_ctrl,
> +			.frontend_attach  = US6832_frontend_attach,
> +			.stream = {
> +				.type = USB_BULK,
> +				.count = 8,
> +				.endpoint = 0x82,
> +				.u = {
> +					.bulk = {
> +						.buffersize = 4096,
> +					}
> +				}
> +			}
> +		} },
> +		}
> +	},
> +	.num_device_descs = 1,
> +	.devices = {
> +		{ "Bestunar US6832 HD",
> +			{ &dw2102_table[BST_US6832HD], NULL },
> +			{ NULL },
> +		},
> +	}
> +};
> +
>   static int dw2102_probe(struct usb_interface *intf,
>   		const struct usb_device_id *id)
>   {
> @@ -1917,20 +2182,24 @@ static int dw2102_probe(struct usb_interface *intf,
> 
>   	if (0 == dvb_usb_device_init(intf, &dw2102_properties,
>   			THIS_MODULE, NULL, adapter_nr) ||
> -	    0 == dvb_usb_device_init(intf, &dw2104_properties,
> +		0 == dvb_usb_device_init(intf, &dw2104_properties,
> +			THIS_MODULE, NULL, adapter_nr) ||
> +		0 == dvb_usb_device_init(intf, &dw3101_properties,
> +			THIS_MODULE, NULL, adapter_nr) ||
> +		0 == dvb_usb_device_init(intf, &s6x0_properties,
>   			THIS_MODULE, NULL, adapter_nr) ||
> -	    0 == dvb_usb_device_init(intf, &dw3101_properties,
> +		0 == dvb_usb_device_init(intf, p1100,
>   			THIS_MODULE, NULL, adapter_nr) ||
> -	    0 == dvb_usb_device_init(intf, &s6x0_properties,
> +		0 == dvb_usb_device_init(intf, s660,
>   			THIS_MODULE, NULL, adapter_nr) ||
> -	    0 == dvb_usb_device_init(intf, p1100,
> +		0 == dvb_usb_device_init(intf, p7500,
>   			THIS_MODULE, NULL, adapter_nr) ||
> -	    0 == dvb_usb_device_init(intf, s660,
> +		0 == dvb_usb_device_init(intf, &su3000_properties,
>   			THIS_MODULE, NULL, adapter_nr) ||
> -	    0 == dvb_usb_device_init(intf, p7500,
> +		0 == dvb_usb_device_init(intf, &US6830_properties,
>   			THIS_MODULE, NULL, adapter_nr) ||
> -	    0 == dvb_usb_device_init(intf, &su3000_properties,
> -				     THIS_MODULE, NULL, adapter_nr))
> +		0 == dvb_usb_device_init(intf, &US6832_properties,
> +			THIS_MODULE, NULL, adapter_nr))
>   		return 0;
> 
>   	return -ENODEV;


-- 

Cheers,
Mauro

^ permalink raw reply	[flat|nested] 56+ messages in thread

end of thread, other threads:[~2014-01-15 19:30 UTC | newest]

Thread overview: 56+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-01-22 10:38 [PATCH 1/3] m88brs2000 DVB-S frontend and tuner module Malcolm Priestley
2012-01-26 16:56 ` Mauro Carvalho Chehab
2012-01-27 22:26   ` Malcolm Priestley
2012-04-15 15:53   ` [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver nibble.max
2012-04-19 18:06     ` Mauro Carvalho Chehab
2012-04-20  8:01       ` nibble.max
2012-04-19 20:08     ` Mauro Carvalho Chehab
2012-04-20  8:01     ` nibble.max
2012-04-20  9:47       ` Antti Palosaari
2012-04-20 17:24         ` Mauro Carvalho Chehab
2012-04-21  2:45         ` nibble.max
2012-04-23 16:41           ` Antti Palosaari
2012-04-23 19:51             ` Konstantin Dimitrov
2012-04-23 21:04               ` Antti Palosaari
2012-04-27 18:44                 ` Konstantin Dimitrov
2012-04-23 21:49               ` Mauro Carvalho Chehab
2012-04-27 19:01                 ` Konstantin Dimitrov
2012-04-27 19:36                   ` Mauro Carvalho Chehab
2012-04-27 20:37                     ` Konstantin Dimitrov
2012-04-27 20:40                       ` Konstantin Dimitrov
2012-04-27 20:54                         ` Antti Palosaari
2012-04-27 21:01                           ` Konstantin Dimitrov
2012-04-27 19:55                   ` Antti Palosaari
2012-04-27 20:21                     ` Konstantin Dimitrov
2012-04-27 20:42                       ` Antti Palosaari
2012-04-27 21:13                         ` Konstantin Dimitrov
2012-04-28  3:54                         ` nibble.max
2012-04-28  9:17                   ` Demod hardware pid filter implement nibble.max
2012-04-28 10:15                     ` Antti Palosaari
2012-04-24  2:45               ` Re: [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver nibble.max
2012-04-26 13:03               ` nibble.max
2012-04-26 13:24                 ` Mauro Carvalho Chehab
2012-04-27  7:06                   ` [PATCH 1/6 v2] dvbsky, montage dvb-s/s2 TS202x tuner and M88DS3103 " nibble.max
2012-04-27 11:06                     ` Mauro Carvalho Chehab
2012-04-27 14:17                     ` Re: [PATCH 1/6 v2] dvbsky, montage dvb-s/s2 TS202x tuner and M88DS3103demodulator driver nibble.max
2012-04-27 14:35                       ` Mauro Carvalho Chehab
2012-04-27 18:03                         ` Konstantin Dimitrov
2012-04-27  7:06                   ` [PATCH 2/6 v2] dvbsky, dvb-s/s2 usb box nibble.max
2013-06-30  3:07                     ` Fwd: " P. van Gaans
2014-01-15 19:30                       ` Mauro Carvalho Chehab
2012-04-27  7:06                   ` [PATCH 3/6 v2] dvbsky, dvb-s/s2 PCIe card nibble.max
2012-04-27  7:07                   ` [PATCH 4/6 v2] dvbsky, dvb-s/s2 PCI card nibble.max
2012-04-27  7:07                   ` [PATCH 5/6 v2] dvbsky, remote control key map nibble.max
2012-04-27  7:07                   ` [PATCH 6/6 v2] dvbsky, remote control include header file nibble.max
2012-04-20 17:10       ` [PATCH 1/6] m88ds3103, montage dvb-s/s2 demodulator driver Mauro Carvalho Chehab
2012-04-15 15:53   ` [PATCH 2/6] m88ds3103, dvbsky dvb-s2 usb box nibble.max
2012-04-19 18:09     ` Mauro Carvalho Chehab
2012-04-20  8:08     ` nibble.max
2012-04-20 17:08       ` Mauro Carvalho Chehab
2012-04-15 15:53   ` [PATCH 3/6] m88ds3103, dvbsky dvb-s2 cx23883 pci card nibble.max
2012-04-15 15:53   ` [PATCH 4/6] m88ds3103, dvbsky dvb-s2 cx23885 pcie card nibble.max
2012-04-19 18:11     ` Mauro Carvalho Chehab
2012-04-15 15:53   ` [PATCH 5/6] m88ds3103, dvbsky remote control key map nibble.max
2012-04-19 18:16     ` Mauro Carvalho Chehab
2012-04-20  8:01       ` nibble.max
2012-04-15 15:53   ` [PATCH 6/6] m88ds3103, dvbsky remote control include header file nibble.max

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.