Re: patch, which supports some new DVB-C budget cards

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Monday 12 February 2007 23:54:28 e9hack wrote:
> Hi,
>
> it exist some new DVB-C budget cards, which are based on the KNC ONE
> (Terratec, Setalco) design. They are using a new tuner with the
> TDA10023 as demodulator. The main work to support this chip was done
> by Georg Auer. He has implemented the frontend (tda10023.c) for the
> ReelBox.

> The attached archive contains the following files: - 
> tda1002x.diff, diff against the current hg-tree
> - tda10023.c, the frontend which should go to ./linux/drivers/media/dvb/frontends
> - tda1002x.h, which should replace ./linux/drivers/media/dvb/frontend/tda10021.h 

You can use hg add and hg remove to add and remove files. hg diff will
display the changes. I hope you don't mind if I a attach the whole patch.

> I would like it, if the owners of such new cards do test the patch.
> The patch may also affect all cards which are supported by the
> modules budget-av and budget.

The patched hg version works with following two cards:

saa7146: found saa7146 @ mem ffffc20000058000 (revision 1, irq 17) (0x1894,0x0020).
DVB: registering new adapter (KNC1 DVB-C).
TDA10021: i2c-addr = 0x0d, id = 0x7c
saa7146: found saa7146 @ mem ffffc20000078000 (revision 1, irq 19) (0x153b,0x1156).
DVB: registering new adapter (Terratec Cinergy 1200 DVB-C).
TDA10021: i2c-addr = 0x0c, id = 0x7c
diff -r 667e84e2e762 linux/drivers/media/dvb/frontends/Kconfig
--- a/linux/drivers/media/dvb/frontends/Kconfig	Tue Feb 13 07:00:55 2007 -0200
+++ b/linux/drivers/media/dvb/frontends/Kconfig	Tue Feb 13 13:51:09 2007 +0100
@@ -200,6 +200,13 @@ config DVB_VES1820
 
 config DVB_TDA10021
 	tristate "Philips TDA10021 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-C tuner module. Say Y when you want to support this frontend.
+
+config DVB_TDA10023
+	tristate "Philips TDA10023 based"
 	depends on DVB_CORE && I2C
 	default m if DVB_FE_CUSTOMISE
 	help
diff -r 667e84e2e762 linux/drivers/media/dvb/frontends/Makefile
--- a/linux/drivers/media/dvb/frontends/Makefile	Tue Feb 13 07:00:55 2007 -0200
+++ b/linux/drivers/media/dvb/frontends/Makefile	Tue Feb 13 13:51:09 2007 +0100
@@ -25,6 +25,7 @@ obj-$(CONFIG_DVB_ZL10353) += zl10353.o
 obj-$(CONFIG_DVB_ZL10353) += zl10353.o
 obj-$(CONFIG_DVB_CX22702) += cx22702.o
 obj-$(CONFIG_DVB_TDA10021) += tda10021.o
+obj-$(CONFIG_DVB_TDA10023) += tda10023.o
 obj-$(CONFIG_DVB_STV0297) += stv0297.o
 obj-$(CONFIG_DVB_NXT200X) += nxt200x.o
 obj-$(CONFIG_DVB_OR51211) += or51211.o
diff -r 667e84e2e762 linux/drivers/media/dvb/frontends/tda10021.c
--- a/linux/drivers/media/dvb/frontends/tda10021.c	Tue Feb 13 07:00:55 2007 -0200
+++ b/linux/drivers/media/dvb/frontends/tda10021.c	Tue Feb 13 13:51:09 2007 +0100
@@ -30,13 +30,13 @@
 #include <linux/slab.h>
 
 #include "dvb_frontend.h"
-#include "tda10021.h"
+#include "tda1002x.h"
 
 
 struct tda10021_state {
 	struct i2c_adapter* i2c;
 	/* configuration settings */
-	const struct tda10021_config* config;
+	const struct tda1002x_config* config;
 	struct dvb_frontend frontend;
 
 	u8 pwm;
@@ -64,7 +64,7 @@ static u8 tda10021_inittab[0x40]=
 {
 	0x73, 0x6a, 0x23, 0x0a, 0x02, 0x37, 0x77, 0x1a,
 	0x37, 0x6a, 0x17, 0x8a, 0x1e, 0x86, 0x43, 0x40,
-	0xb8, 0x3f, 0xa0, 0x00, 0xcd, 0x01, 0x00, 0xff,
+	0xb8, 0x3f, 0xa1, 0x00, 0xcd, 0x01, 0x00, 0xff,
 	0x11, 0x00, 0x7c, 0x31, 0x30, 0x20, 0x00, 0x00,
 	0x02, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00,
 	0x07, 0x00, 0x33, 0x11, 0x0d, 0x95, 0x08, 0x58,
@@ -97,9 +97,12 @@ static u8 tda10021_readreg (struct tda10
 	int ret;
 
 	ret = i2c_transfer (state->i2c, msg, 2);
-	if (ret != 2)
+	
+	// Don't print an error message if the id is read.
+	if (ret != 2 && reg != 0x1a)
 		printk("DVB: TDA10021: %s: readreg error (ret == %i)\n",
 				__FUNCTION__, ret);
+
 	return b1[0];
 }
 
@@ -199,16 +202,6 @@ static int tda10021_set_symbolrate (stru
 	_tda10021_writereg (state, 0x0e, SFIL);
 
 	return 0;
-}
-
-static int tda10021_write(struct dvb_frontend* fe, u8 *buf, int len)
-{
-	struct tda10021_state* state = fe->demodulator_priv;
-
-	if (len != 2)
-		return -EINVAL;
-
-	return _tda10021_writereg(state, buf[0], buf[1]);
 }
 
 static int tda10021_init (struct dvb_frontend *fe)
@@ -408,11 +401,12 @@ static void tda10021_release(struct dvb_
 
 static struct dvb_frontend_ops tda10021_ops;
 
-struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
+struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
 				     struct i2c_adapter* i2c,
 				     u8 pwm)
 {
 	struct tda10021_state* state = NULL;
+	u8 id;
 
 	/* allocate memory for the internal state */
 	state = kmalloc(sizeof(struct tda10021_state), GFP_KERNEL);
@@ -425,7 +419,10 @@ struct dvb_frontend* tda10021_attach(con
 	state->reg0 = tda10021_inittab[0];
 
 	/* check if the demod is there */
-	if ((tda10021_readreg(state, 0x1a) & 0xf0) != 0x70) goto error;
+	id = tda10021_readreg(state, 0x1a);
+	if ((id & 0xf0) != 0x70) goto error;
+	
+	printk("TDA10021: i2c-addr = 0x%02x, id = 0x%02x\n", state->config->demod_address, id);
 
 	/* create dvb_frontend */
 	memcpy(&state->frontend.ops, &tda10021_ops, sizeof(struct dvb_frontend_ops));
@@ -461,7 +458,6 @@ static struct dvb_frontend_ops tda10021_
 
 	.init = tda10021_init,
 	.sleep = tda10021_sleep,
-	.write = tda10021_write,
 	.i2c_gate_ctrl = tda10021_i2c_gate_ctrl,
 
 	.set_frontend = tda10021_set_parameters,
diff -r 667e84e2e762 linux/drivers/media/dvb/frontends/tda10021.h
--- a/linux/drivers/media/dvb/frontends/tda10021.h	Tue Feb 13 07:00:55 2007 -0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
-    TDA10021  - Single Chip Cable Channel Receiver driver module
-	       used on the the Siemens DVB-C cards
-
-    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@xxxxxxxxxxxxxx>
-    Copyright (C) 2004 Markus Schulz <msc@xxxxxxxxxxxxx>
-		   Support for TDA10021
-
-    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 TDA10021_H
-#define TDA10021_H
-
-#include <linux/dvb/frontend.h>
-
-struct tda10021_config
-{
-	/* the demodulator's i2c address */
-	u8 demod_address;
-};
-
-#if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE))
-extern struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
-					    struct i2c_adapter* i2c, u8 pwm);
-#else
-static inline struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
-					    struct i2c_adapter* i2c, u8 pwm)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
-	return NULL;
-}
-#endif // CONFIG_DVB_TDA10021
-
-static inline int tda10021_writereg(struct dvb_frontend *fe, u8 reg, u8 val) {
-	int r = 0;
-	u8 buf[] = {reg, val};
-	if (fe->ops.write)
-		r = fe->ops.write(fe, buf, 2);
-	return r;
-}
-
-#endif // TDA10021_H
diff -r 667e84e2e762 linux/drivers/media/dvb/frontends/tda10023.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/frontends/tda10023.c	Tue Feb 13 18:20:54 2007 +0100
@@ -0,0 +1,548 @@
+/*
+    TDA10023  - DVB-C decoder 
+    (as used in Philips CU1216-3 NIM and the Reelbox DVB-C tuner card)
+    
+    Copyright (C) 2005 Georg Acher, BayCom GmbH (acher at baycom dot de)
+    Copyright (c) 2006 Hartmut Birr (e9hack at gmail dot com)
+
+    Remotely based on tda10021.c
+    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@xxxxxxxxxxxxxx>
+    Copyright (C) 2004 Markus Schulz <msc@xxxxxxxxxxxxx>
+                   Support for TDA10021
+
+    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/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "tda1002x.h"
+
+
+struct tda10023_state {
+	struct i2c_adapter* i2c;
+	/* configuration settings */
+	const struct tda1002x_config* config;
+	struct dvb_frontend frontend;
+
+	u8 pwm;
+	u8 reg0;
+};
+
+
+#if 0
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...)
+#endif
+
+static int verbose;
+
+#define XTAL   28920000UL
+#define PLL_M  8UL
+#define PLL_P  4UL
+#define PLL_N  1UL
+#define SYSCLK (XTAL*PLL_M/(PLL_N*PLL_P))  // -> 57840000
+
+static u8 tda10023_inittab[]={
+	// reg mask val
+	0x2a,0xff,0x02,  // PLL3, Bypass, Power Down
+	0xff,0x64,0x00,  // Sleep 100ms
+	0x2a,0xff,0x03,  // PLL3, Bypass, Power Down
+	0xff,0x64,0x00,  // Sleep 100ms
+	0x28,0xff,PLL_M-1,  // PLL1 M=8
+	0x29,0xff,((PLL_P-1)<<6)|(PLL_N-1),  // PLL2
+	0x00,0xff,0x23,  // GPR FSAMPLING=1
+	0x2a,0xff,0x08,  // PLL3 PSACLK=1
+	0xff,0x64,0x00,  // Sleep 100ms
+	0x1f,0xff,0x00,  // RESET
+	0xff,0x64,0x00,  // Sleep 100ms
+	0xe6,0x0c,0x04,  // RSCFG_IND
+	0x10,0xc0,0x80,  // DECDVBCFG1 PBER=1
+
+	0x0e,0xff,0x82,  // GAIN1
+	0x03,0x08,0x08,  // CLKCONF DYN=1
+	0x2e,0xbf,0x30,  // AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1 PPWMTUN=0 PPWMIF=0
+	0x01,0xff,0x30,  // AGCREF
+	0x1e,0x84,0x84,  // CONTROL SACLK_ON=1
+	0x1b,0xff,0xc8,  // ADC TWOS=1
+	0x3b,0xff,0xff,  // IFMAX
+	0x3c,0xff,0x00,  // IFMIN
+	0x34,0xff,0x00,  // PWMREF
+	0x35,0xff,0xff,  // TUNMAX
+	0x36,0xff,0x00,  // TUNMIN
+	0x06,0xff,0x7f,  // EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1    // 0x77
+	0x1c,0x30,0x30,  // EQCONF2 STEPALGO=SGNALGO=1
+	0x37,0xff,0xf6,  // DELTAF_LSB
+	0x38,0xff,0xff,  // DELTAF_MSB
+	0x02,0xff,0x93,  // AGCCONF1  IFS=1 KAGCIF=2 KAGCTUN=3
+	0x2d,0xff,0xf6,  // SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2
+	0x04,0x10,0x00,   // SWRAMP=1
+	0x12,0xff,0xa1,  // INTP1 POCLKP=1 FEL=1 MFS=0
+	0x2b,0x01,0xa1,  // INTS1
+	0x20,0xff,0x04,  // INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=?
+	0x2c,0xff,0x0d,  // INTP/S TRIP=0 TRIS=0
+	0xc4,0xff,0x00,
+	0xc3,0x30,0x00,
+	0xb5,0xff,0x19,  // ERAGC_THD
+	0x00,0x03,0x01,  // GPR, CLBS soft reset
+	0x00,0x03,0x03,  // GPR, CLBS soft reset
+	0xff,0x64,0x00,  // Sleep 100ms
+	0xff,0xff,0xff
+};
+
+static u8 tda10023_readreg (struct tda10023_state* state, u8 reg)
+{
+	u8 b0 [] = { reg };
+	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 } };
+	int ret;
+
+	ret = i2c_transfer (state->i2c, msg, 2);
+	if (ret != 2)
+		printk("DVB: TDA10023: %s: readreg error (ret == %i)\n",
+				 __FUNCTION__, ret);
+	return b1[0];
+}
+
+static int tda10023_writereg (struct tda10023_state* state, u8 reg, u8 data)
+{
+        u8 buf[] = { reg, data };
+	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+        int ret;
+
+	ret = i2c_transfer (state->i2c, &msg, 1);
+	if (ret != 1)
+		printk("DVB: TDA10023(%d): %s, writereg error "
+			"(reg == 0x%02x, val == 0x%02x, ret == %i)\n",
+			state->frontend.dvb->num, __FUNCTION__, reg, data, ret);
+
+	return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+
+static int tda10023_writebit (struct tda10023_state* state, u8 reg, u8 mask,u8 data)
+{
+	if (mask==0xff) 
+		return tda10023_writereg(state, reg, data);
+	else {
+		u8 val;
+		val=tda10023_readreg(state,reg);
+		val&=~mask;
+		val|=(data&mask);
+		return tda10023_writereg(state, reg, val);
+	}
+}
+
+static void tda10023_writetab(struct tda10023_state* state, u8* tab)
+{
+	u8 r,m,v;
+	while (1) {
+		r=*tab++;
+		m=*tab++;
+		v=*tab++;
+		if (r==0xff) {
+			if (m==0xff)
+				break;
+			else
+				msleep(m);
+		}
+		else 
+			tda10023_writebit(state,r,m,v);
+	}
+}
+
+//get access to tuner
+static int lock_tuner(struct tda10023_state* state)
+{
+	u8 buf[2] = { 0x0f, 0xc0 };
+	struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
+
+	if(i2c_transfer(state->i2c, &msg, 1) != 1)
+	{
+		printk("tda10023: lock tuner fails\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+//release access from tuner
+static int unlock_tuner(struct tda10023_state* state)
+{
+	u8 buf[2] = { 0x0f, 0x40 };
+	struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
+
+	if(i2c_transfer(state->i2c, &msg_post, 1) != 1)
+	{
+		printk("tda10023: unlock tuner fails\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int tda10023_setup_reg0 (struct tda10023_state* state, u8 reg0)
+{
+	reg0 |= state->reg0 & 0x63;
+
+	tda10023_writereg (state, 0x00, reg0 & 0xfe);
+	tda10023_writereg (state, 0x00, reg0 | 0x01);
+
+	state->reg0 = reg0;
+	return 0;
+}
+
+static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr)
+{
+	s32 BDR;
+	s32 BDRI;
+	s16 SFIL=0;
+	u16 NDEC = 0;
+
+	if (sr > (SYSCLK/(2*4)))
+		sr=SYSCLK/(2*4);
+	
+	if (sr<870000)
+		sr=870000;
+
+	if (sr < (u32)(SYSCLK/98.40)) {
+		NDEC=3;
+		SFIL=1;
+	} else if (sr<(u32)(SYSCLK/64.0)) {
+		NDEC=3;
+		SFIL=0;
+	} else if (sr<(u32)(SYSCLK/49.2)) {
+		NDEC=2;
+		SFIL=1;
+	} else if (sr<(u32)(SYSCLK/32.0)) {
+		NDEC=2;
+		SFIL=0;
+	} else if (sr<(u32)(SYSCLK/24.6)) {
+		NDEC=1;
+		SFIL=1;
+	} else if (sr<(u32)(SYSCLK/16.0)) {
+		NDEC=1;
+		SFIL=0;
+	} else if (sr<(u32)(SYSCLK/12.3)) {
+		NDEC=0;
+		SFIL=1;
+	} 
+
+	BDRI=SYSCLK*16;
+	BDRI>>=NDEC;
+	BDRI +=sr/2;
+	BDRI /=sr;
+
+	if (BDRI>255)
+		BDRI=255;
+
+	{
+		u64 BDRX;
+
+		BDRX=1<<(24+NDEC);
+		BDRX*=sr;
+		do_div(BDRX,SYSCLK); 	// BDRX/=SYSCLK;
+
+		BDR=(s32)BDRX;
+	}
+//	printk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n",sr,BDR,BDRI,NDEC);
+	tda10023_writebit (state, 0x03, 0xc0, NDEC<<6);
+	tda10023_writereg (state, 0x0a, BDR&255);
+	tda10023_writereg (state, 0x0b, (BDR>>8)&255);
+	tda10023_writereg (state, 0x0c, (BDR>>16)&31);
+	tda10023_writereg (state, 0x0d, BDRI);
+	tda10023_writereg (state, 0x3d, (SFIL<<7));
+	return 0;
+}
+
+static int tda10023_init (struct dvb_frontend *fe)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+
+	dprintk("DVB: TDA10023(%d): init chip\n", fe->adapter->num);
+
+	tda10023_writetab(state, tda10023_inittab);
+	
+	return 0;
+}
+
+static int tda10023_set_parameters (struct dvb_frontend *fe,
+			    struct dvb_frontend_parameters *p)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+
+	static int qamvals[6][6] = {
+		//  QAM   LOCKTHR  MSETH   AREF AGCREFNYQ  ERAGCNYQ_THD
+		{ (5<<2),  0x78,    0x8c,   0x96,   0x78,   0x4c  },  // 4 QAM 
+		{ (0<<2),  0x87,    0xa2,   0x91,   0x8c,   0x57  },  // 16 QAM
+		{ (1<<2),  0x64,    0x74,   0x96,   0x8c,   0x57  },  // 32 QAM
+		{ (2<<2),  0x46,    0x43,   0x6a,   0x6a,   0x44  },  // 64 QAM
+		{ (3<<2),  0x36,    0x34,   0x7e,   0x78,   0x4c  },  // 128 QAM 
+		{ (4<<2),  0x26,    0x23,   0x6c,   0x5c,   0x3c  },  // 256 QAM 
+	};
+
+        int qam = p->u.qam.modulation;
+
+        if (qam < 0 || qam > 5)
+                return -EINVAL;
+
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	tda10023_set_symbolrate (state, p->u.qam.symbol_rate);
+	tda10023_writereg (state, 0x05, qamvals[qam][1]);
+        tda10023_writereg (state, 0x08, qamvals[qam][2]);
+        tda10023_writereg (state, 0x09, qamvals[qam][3]);
+        tda10023_writereg (state, 0xb4, qamvals[qam][4]);
+        tda10023_writereg (state, 0xb6, qamvals[qam][5]);
+
+//	tda10023_writereg (state, 0x04, (p->inversion?0x12:0x32));
+//	tda10023_writebit (state, 0x04, 0x60, (p->inversion?0:0x20));
+	tda10023_writebit (state, 0x04, 0x40, 0x40);
+        tda10023_setup_reg0 (state, qamvals[qam][0]);
+
+	return 0;
+}
+
+static int tda10023_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+	int sync;
+
+	*status = 0;
+
+	//0x11[1] == CARLOCK -> Carrier locked
+	//0x11[2] == FSYNC -> Frame synchronisation
+	//0x11[3] == FEL -> Front End locked
+	//0x11[6] == NODVB -> DVB Mode Information
+	sync = tda10023_readreg (state, 0x11);
+
+	if (sync & 2)
+		*status |= FE_HAS_SIGNAL|FE_HAS_CARRIER;
+
+	if (sync & 4)
+		*status |= FE_HAS_SYNC|FE_HAS_VITERBI;
+
+	if (sync & 8)
+		*status |= FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int tda10023_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+	u8 a,b,c;
+	a=tda10023_readreg(state, 0x14);
+	b=tda10023_readreg(state, 0x15);
+	c=tda10023_readreg(state, 0x16)&0xf;
+	tda10023_writebit (state, 0x10, 0xc0, 0x00);
+
+	*ber = a | (b<<8)| (c<<16);		
+	return 0;
+}
+
+static int tda10023_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+	u8 ifgain=tda10023_readreg(state, 0x2f);
+
+	u16 gain = ((255-tda10023_readreg(state, 0x17))) + (255-ifgain)/16;
+	// Max raw value is about 0xb0 -> Normalize to >0xf0 after 0x90
+	if (gain>0x90)
+		gain=gain+2*(gain-0x90);
+	if (gain>255)
+		gain=255;
+	
+	*strength = (gain<<8)|gain;
+	return 0;
+}
+
+static int tda10023_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+
+	u8 quality = ~tda10023_readreg(state, 0x18);
+	*snr = (quality << 8) | quality;
+	return 0;
+}
+
+static int tda10023_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+	u8 a,b,c,d;
+	a= tda10023_readreg (state, 0x74);
+	b= tda10023_readreg (state, 0x75);
+	c= tda10023_readreg (state, 0x76);
+	d= tda10023_readreg (state, 0x77);
+	*ucblocks = a | (b<<8)|(c<<16)|(d<<24);
+
+	tda10023_writebit (state, 0x10, 0x20,0x00);
+	tda10023_writebit (state, 0x10, 0x20,0x20);
+	tda10023_writebit (state, 0x13, 0x01, 0x00);
+
+	return 0;
+}
+
+static int tda10023_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+	int sync,inv;
+	s8 afc = 0;
+
+	sync = tda10023_readreg(state, 0x11);
+	afc = tda10023_readreg(state, 0x19);
+	inv = tda10023_readreg(state, 0x04);
+	
+	if (verbose) {
+		/* AFC only valid when carrier has been recovered */
+		printk(sync & 2 ? "DVB: TDA10023(%d): AFC (%d) %dHz\n" :
+				  "DVB: TDA10023(%d): [AFC (%d) %dHz]\n",
+			state->frontend.dvb->num, afc,
+		       -((s32)p->u.qam.symbol_rate * afc) >> 10);
+	}
+
+	p->inversion = (inv&0x20?0:1);
+	p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16;
+
+	p->u.qam.fec_inner = FEC_NONE;
+	p->frequency = ((p->frequency + 31250) / 62500) * 62500;
+
+	if (sync & 2)
+		p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10;
+
+	return 0;
+}
+
+static int tda10023_sleep(struct dvb_frontend* fe)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+
+	tda10023_writereg (state, 0x1b, 0x02);  /* pdown ADC */
+	tda10023_writereg (state, 0x00, 0x80);  /* standby */
+
+	return 0;
+}
+
+static int tda10023_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		lock_tuner(state);
+	} else {
+		unlock_tuner(state);
+	}
+	return 0;
+}
+
+static void tda10023_release(struct dvb_frontend* fe)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops tda10023_ops;
+
+struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
+				     struct i2c_adapter* i2c,
+				     u8 pwm)
+{
+	struct tda10023_state* state = NULL;
+	int i;
+
+	/* allocate memory for the internal state */
+	state = kmalloc(sizeof(struct tda10023_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
+	state->pwm = pwm;
+	for (i=0; i < sizeof(tda10023_inittab)/sizeof(*tda10023_inittab);i+=3) {
+		if (tda10023_inittab[i] == 0x00) {
+			state->reg0 = tda10023_inittab[i+2];
+			break;
+		}
+	}
+
+	// Wakeup if in standby
+	tda10023_writereg (state, 0x00, 0x33);
+	/* check if the demod is there */
+	if ((tda10023_readreg(state, 0x1a) & 0xf0) != 0x70) goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops tda10023_ops = {
+
+	.info = {
+		.name = "Philips TDA10023 DVB-C",
+		.type = FE_QAM,
+		.frequency_stepsize = 62500,
+		.frequency_min = 51000000,
+		.frequency_max = 858000000,
+		.symbol_rate_min = (SYSCLK/2)/64,     /* SACLK/64 == (SYSCLK/2)/64 */
+		.symbol_rate_max = (SYSCLK/2)/4,      /* SACLK/4 */
+	#if 0
+		.frequency_tolerance = ???,
+		.symbol_rate_tolerance = ???,  /* ppm */  /* == 8% (spec p. 5) */
+	#endif
+		.caps = 0x400 | //FE_CAN_QAM_4
+			FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
+			FE_CAN_QAM_128 | FE_CAN_QAM_256 |
+			FE_CAN_FEC_AUTO
+	},
+
+	.release = tda10023_release,
+
+	.init = tda10023_init,
+	.sleep = tda10023_sleep,
+	.i2c_gate_ctrl = tda10023_i2c_gate_ctrl,
+
+	.set_frontend = tda10023_set_parameters,
+	.get_frontend = tda10023_get_frontend,
+
+	.read_status = tda10023_read_status,
+	.read_ber = tda10023_read_ber,
+	.read_signal_strength = tda10023_read_signal_strength,
+	.read_snr = tda10023_read_snr,
+	.read_ucblocks = tda10023_read_ucblocks,
+};
+
+
+MODULE_DESCRIPTION("Philips TDA10023 DVB-C demodulator driver");
+MODULE_AUTHOR("Georg Acher, Hartmut Birr");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(tda10023_attach);
diff -r 667e84e2e762 linux/drivers/media/dvb/frontends/tda1002x.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/frontends/tda1002x.h	Tue Feb 13 18:20:54 2007 +0100
@@ -0,0 +1,59 @@
+/*
+    TDA10021/TDA10023  - Single Chip Cable Channel Receiver driver module
+	                 used on the the Siemens DVB-C cards
+
+    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@xxxxxxxxxxxxxx>
+    Copyright (C) 2004 Markus Schulz <msc@xxxxxxxxxxxxx>
+		   Support for TDA10021
+
+    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 TDA1002x_H
+#define TDA1002x_H
+
+#include <linux/dvb/frontend.h>
+
+struct tda1002x_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+};
+
+#if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE))
+extern struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
+					    struct i2c_adapter* i2c, u8 pwm);
+#else
+static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
+					    struct i2c_adapter* i2c, u8 pwm)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_TDA10021
+
+#if defined(CONFIG_DVB_TDA10023) || (defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE))
+extern struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
+					    struct i2c_adapter* i2c, u8 pwm);
+#else
+static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
+					    struct i2c_adapter* i2c, u8 pwm)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_TDA10023
+
+#endif // TDA1002x_H
diff -r 667e84e2e762 linux/drivers/media/dvb/ttpci/Kconfig
--- a/linux/drivers/media/dvb/ttpci/Kconfig	Tue Feb 13 07:00:55 2007 -0200
+++ b/linux/drivers/media/dvb/ttpci/Kconfig	Tue Feb 13 13:51:09 2007 +0100
@@ -69,6 +69,7 @@ config DVB_BUDGET
 	select DVB_L64781 if !DVB_FE_CUSTOMISE
 	select DVB_TDA8083 if !DVB_FE_CUSTOMISE
 	select DVB_TDA10021 if !DVB_FE_CUSTOMISE
+	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
 	select DVB_S5H1420 if !DVB_FE_CUSTOMISE
 	select DVB_TDA10086 if !DVB_FE_CUSTOMISE
 	select DVB_TDA826X if !DVB_FE_CUSTOMISE
@@ -114,6 +115,7 @@ config DVB_BUDGET_AV
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
 	select DVB_TDA10021 if !DVB_FE_CUSTOMISE
+	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
 	select DVB_TUA6100 if !DVB_FE_CUSTOMISE
 	select FW_LOADER
 	help
diff -r 667e84e2e762 linux/drivers/media/dvb/ttpci/budget-av.c
--- a/linux/drivers/media/dvb/ttpci/budget-av.c	Tue Feb 13 07:00:55 2007 -0200
+++ b/linux/drivers/media/dvb/ttpci/budget-av.c	Tue Feb 13 13:51:09 2007 +0100
@@ -35,7 +35,7 @@
 
 #include "budget.h"
 #include "stv0299.h"
-#include "tda10021.h"
+#include "tda1002x.h"
 #include "tda1004x.h"
 #include "tua6100.h"
 #include "dvb-pll.h"
@@ -66,9 +66,7 @@ struct budget_av {
 	int slot_status;
 	struct dvb_ca_en50221 ca;
 	u8 reinitialise_demod:1;
-	u8 tda10021_poclkp:1;
-	u8 tda10021_ts_enabled;
-	int (*tda10021_set_frontend)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
+	int (*tda1002x_set_frontend)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
 };
 
 static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot);
@@ -234,12 +232,6 @@ static int ciintf_slot_reset(struct dvb_
 	if (budget_av->reinitialise_demod)
 		dvb_frontend_reinitialise(budget_av->budget.dvb_frontend);
 
-	/* set tda10021 back to original clock configuration on reset */
-	if (budget_av->tda10021_poclkp) {
-		tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0);
-		budget_av->tda10021_ts_enabled = 0;
-	}
-
 	return 0;
 }
 
@@ -256,11 +248,6 @@ static int ciintf_slot_shutdown(struct d
 	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
 	budget_av->slot_status = SLOTSTATUS_NONE;
 
-	/* set tda10021 back to original clock configuration when cam removed */
-	if (budget_av->tda10021_poclkp) {
-		tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0);
-		budget_av->tda10021_ts_enabled = 0;
-	}
 	return 0;
 }
 
@@ -275,12 +262,6 @@ static int ciintf_slot_ts_enable(struct 
 	dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status);
 
 	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
-
-	/* tda10021 seems to need a different TS clock config when data is routed to the CAM */
-	if (budget_av->tda10021_poclkp) {
-		tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa1);
-		budget_av->tda10021_ts_enabled = 1;
-	}
 
 	return 0;
 }
@@ -631,18 +612,22 @@ static int philips_cu1216_tuner_set_para
 static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	struct budget *budget = (struct budget *) fe->dvb->priv;
-	u8 buf[4];
+	u8 buf[6];
 	struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
 
+#define CU1216_IF 36125000
 #define TUNER_MUL 62500
 
-	u32 div = (params->frequency + 36125000 + TUNER_MUL / 2) / TUNER_MUL;
+	u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
 
 	buf[0] = (div >> 8) & 0x7f;
 	buf[1] = div & 0xff;
-	buf[2] = 0x86;
-	buf[3] = (params->frequency < 150000000 ? 0x01 :
-		  params->frequency < 445000000 ? 0x02 : 0x04);
+	buf[2] = 0xce;
+	buf[3] = (params->frequency < 160000000 + CU1216_IF ? 0x01 :
+		  params->frequency < 445000000 + CU1216_IF ? 0x02 : 0x04);
+		  
+	buf[4] = 0xde;
+	buf[5] = 0x20;
 
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
@@ -651,11 +636,11 @@ static int philips_cu1216_tuner_set_para
 	return 0;
 }
 
-static struct tda10021_config philips_cu1216_config = {
+static struct tda1002x_config philips_cu1216_config = {
 	.demod_address = 0x0c,
 };
 
-static struct tda10021_config philips_cu1216_config_altaddress = {
+static struct tda1002x_config philips_cu1216_config_altaddress = {
 	.demod_address = 0x0d,
 };
 
@@ -883,7 +868,7 @@ static int philips_sd1878_ci_set_symbol_
 
 static struct stv0299_config philips_sd1878_config = {
 	.demod_address = 0x68,
-     .inittab = philips_sd1878_inittab,
+	.inittab = philips_sd1878_inittab,
 	.mclk = 88000000UL,
 	.invert = 0,
 	.skip_reinit = 0,
@@ -908,38 +893,36 @@ static u8 read_pwm(struct budget_av *bud
 	return pwm;
 }
 
-#define SUBID_DVBS_KNC1		0x0010
-#define SUBID_DVBS_KNC1_PLUS	0x0011
-#define SUBID_DVBS_TYPHOON	0x4f56
-#define SUBID_DVBS_CINERGY1200	0x1154
-#define SUBID_DVBS_CYNERGY1200N 0x1155
-
-#define SUBID_DVBS_TV_STAR	0x0014
-#define SUBID_DVBS_TV_STAR_CI	0x0016
-#define SUBID_DVBS_EASYWATCH_1  0x001a
-#define SUBID_DVBS_EASYWATCH	0x001e
-#define SUBID_DVBC_EASYWATCH	0x002a
-#define SUBID_DVBC_KNC1		0x0020
-#define SUBID_DVBC_KNC1_PLUS	0x0021
-#define SUBID_DVBC_CINERGY1200	0x1156
-
-#define SUBID_DVBT_KNC1_PLUS	0x0031
-#define SUBID_DVBT_KNC1		0x0030
-#define SUBID_DVBT_CINERGY1200	0x1157
-
-
-static int tda10021_set_frontend(struct dvb_frontend *fe,
+#define SUBID_DVBS_KNC1			0x0010
+#define SUBID_DVBS_KNC1_PLUS		0x0011
+#define SUBID_DVBS_TYPHOON		0x4f56
+#define SUBID_DVBS_CINERGY1200		0x1154
+#define SUBID_DVBS_CYNERGY1200N 	0x1155
+
+#define SUBID_DVBS_TV_STAR		0x0014
+#define SUBID_DVBS_TV_STAR_CI		0x0016
+#define SUBID_DVBS_EASYWATCH_1  	0x001a
+#define SUBID_DVBS_EASYWATCH		0x001e
+#define SUBID_DVBC_EASYWATCH		0x002a
+#define SUBID_DVBC_EASYWATCH_MK3	0x002c
+#define SUBID_DVBC_KNC1			0x0020
+#define SUBID_DVBC_KNC1_PLUS		0x0021
+#define SUBID_DVBC_KNC1_PLUS_MK3	0x0022
+#define SUBID_DVBC_CINERGY1200		0x1156
+#define SUBID_DVBC_CINERGY1200_MK3	0x1176	
+
+#define SUBID_DVBT_KNC1_PLUS		0x0031
+#define SUBID_DVBT_KNC1			0x0030
+#define SUBID_DVBT_CINERGY1200		0x1157
+
+
+static int tda1002x_set_frontend(struct dvb_frontend *fe,
 				 struct dvb_frontend_parameters *p)
 {
 	struct budget_av* budget_av = fe->dvb->priv;
 	int result;
 
-	result = budget_av->tda10021_set_frontend(fe, p);
-	if (budget_av->tda10021_ts_enabled) {
-		tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa1);
-	} else {
-		tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0);
-	}
+	result = budget_av->tda1002x_set_frontend(fe, p);
 
 	return result;
 }
@@ -961,6 +944,7 @@ static void frontend_init(struct budget_
 		case SUBID_DVBC_KNC1_PLUS:
 		case SUBID_DVBT_KNC1_PLUS:
 		case SUBID_DVBC_EASYWATCH:
+		case SUBID_DVBC_KNC1_PLUS_MK3:
 			saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI);
 			break;
 	}
@@ -1017,6 +1001,7 @@ static void frontend_init(struct budget_
 	case SUBID_DVBC_CINERGY1200:
 	case SUBID_DVBC_EASYWATCH:
 		budget_av->reinitialise_demod = 1;
+		budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;
 		fe = dvb_attach(tda10021_attach, &philips_cu1216_config,
 				     &budget_av->budget.i2c_adap,
 				     read_pwm(budget_av));
@@ -1025,9 +1010,23 @@ static void frontend_init(struct budget_
 					     &budget_av->budget.i2c_adap,
 					     read_pwm(budget_av));
 		if (fe) {
-			budget_av->tda10021_poclkp = 1;
-			budget_av->tda10021_set_frontend = fe->ops.set_frontend;
-			fe->ops.set_frontend = tda10021_set_frontend;
+			budget_av->tda1002x_set_frontend = fe->ops.set_frontend;
+			fe->ops.set_frontend = tda1002x_set_frontend;
+			fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
+		}
+		break;
+
+	case SUBID_DVBC_EASYWATCH_MK3:
+	case SUBID_DVBC_CINERGY1200_MK3:
+	case SUBID_DVBC_KNC1_PLUS_MK3:
+		budget_av->reinitialise_demod = 1;
+		budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;
+		fe = dvb_attach(tda10023_attach, &philips_cu1216_config,
+				     &budget_av->budget.i2c_adap,
+				     read_pwm(budget_av));
+		if (fe) {
+			budget_av->tda1002x_set_frontend = fe->ops.set_frontend;
+			fe->ops.set_frontend = tda1002x_set_frontend;
 			fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
 		}
 		break;
@@ -1260,12 +1259,15 @@ MAKE_BUDGET_INFO(satewpls, "Satelco Easy
 MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
 MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S);
 MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP);
+MAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3);
 MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
 MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);
+MAKE_BUDGET_INFO(knc1cpmk3, "KNC1 DVB-C MK3", BUDGET_KNC1C_MK3);
 MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP);
 MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);
 MAKE_BUDGET_INFO(cin1200sn, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);
 MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C);
+MAKE_BUDGET_INFO(cin1200cmk3, "Terratec Cinergy 1200 DVB-C MK3", BUDGET_CIN1200C_MK3);
 MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T);
 
 static struct pci_device_id pci_tbl[] = {
@@ -1279,13 +1281,16 @@ static struct pci_device_id pci_tbl[] = 
 	MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
 	MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
 	MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a),
+	MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c),
 	MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
 	MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
+	MAKE_EXTENSION_PCI(knc1cpmk3, 0x1894, 0x0022),
 	MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
 	MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031),
 	MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154),
 	MAKE_EXTENSION_PCI(cin1200sn, 0x153b, 0x1155),
 	MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156),
+	MAKE_EXTENSION_PCI(cin1200cmk3, 0x153b, 0x1176),
 	MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157),
 	{
 	 .vendor = 0,
diff -r 667e84e2e762 linux/drivers/media/dvb/ttpci/budget-core.c
--- a/linux/drivers/media/dvb/ttpci/budget-core.c	Tue Feb 13 07:00:55 2007 -0200
+++ b/linux/drivers/media/dvb/ttpci/budget-core.c	Tue Feb 13 13:51:09 2007 +0100
@@ -41,11 +41,14 @@
 
 #define TS_WIDTH		(2 * TS_SIZE)
 #define TS_WIDTH_ACTIVY		TS_SIZE
+#define TS_WIDTH_DVBC		TS_SIZE
 #define TS_HEIGHT_MASK		0xf00
 #define TS_HEIGHT_MASK_ACTIVY	0xc00
+#define TS_HEIGHT_MASK_DVBC	0xe00
 #define TS_MIN_BUFSIZE_K	188
 #define TS_MAX_BUFSIZE_K	1410
 #define TS_MAX_BUFSIZE_K_ACTIVY	564
+#define TS_MAX_BUFSIZE_K_DVBC	1316
 #define BUFFER_WARNING_WAIT	(30*HZ)
 
 int budget_debug;
@@ -106,6 +109,32 @@ static int start_ts_capture(struct budge
 		saa7146_write(dev, MC2, (MASK_10 | MASK_26));
 		saa7146_write(dev, BRS_CTRL, 0x60000000);
 		break;
+	case BUDGET_KNC1C:
+	case BUDGET_KNC1CP:
+	case BUDGET_CIN1200C:
+		if (budget->video_port == BUDGET_VIDEO_PORTA) {
+			saa7146_write(dev, DD1_INIT, 0x06000200);
+			saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+			saa7146_write(dev, BRS_CTRL, 0x00000000);
+		} else {
+			saa7146_write(dev, DD1_INIT, 0x02000600);
+			saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+			saa7146_write(dev, BRS_CTRL, 0x60000000);
+		}
+		break;	
+	case BUDGET_CIN1200C_MK3:
+	case BUDGET_KNC1C_MK3:
+	case BUDGET_KNC1CP_MK3:
+		if (budget->video_port == BUDGET_VIDEO_PORTA) {
+			saa7146_write(dev, DD1_INIT, 0x06000200);
+			saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+			saa7146_write(dev, BRS_CTRL, 0x00000000);
+		} else {
+			saa7146_write(dev, DD1_INIT, 0x000006c0);
+			saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+			saa7146_write(dev, BRS_CTRL, 0x60000000);
+		}
+		break;
 	default:
 		if (budget->video_port == BUDGET_VIDEO_PORTA) {
 			saa7146_write(dev, DD1_INIT, 0x06000200);
@@ -122,7 +151,13 @@ static int start_ts_capture(struct budge
 	mdelay(10);
 
 	saa7146_write(dev, BASE_ODD3, 0);
-	saa7146_write(dev, BASE_EVEN3, 0);
+	if (budget->buffer_size > budget->buffer_height * budget->buffer_width) {
+		// using odd/even buffers
+		saa7146_write(dev, BASE_EVEN3, budget->buffer_height * budget->buffer_width);
+	} else {
+		// using a single buffer
+		saa7146_write(dev, BASE_EVEN3, 0);
+	}
 	saa7146_write(dev, PROT_ADDR3, budget->buffer_size);
 	saa7146_write(dev, BASE_PAGE3, budget->pt.dma | ME1 | 0x90);
 
@@ -135,7 +170,7 @@ static int start_ts_capture(struct budge
 	SAA7146_ISR_CLEAR(budget->dev, MASK_10);	/* VPE */
 	SAA7146_IER_ENABLE(budget->dev, MASK_10);	/* VPE */
 	saa7146_write(dev, MC1, (MASK_04 | MASK_20));	/* DMA3 on */
-
+	
 	return 0;
 }
 
@@ -398,12 +433,24 @@ int ttpci_budget_init(struct budget *bud
 
 	budget->card = bi;
 	budget->dev = (struct saa7146_dev *) dev;
-
-	if (budget->card->type == BUDGET_FS_ACTIVY) {
+	
+	switch(budget->card->type) {
+	case BUDGET_FS_ACTIVY:
 		budget->buffer_width = TS_WIDTH_ACTIVY;
 		max_bufsize = TS_MAX_BUFSIZE_K_ACTIVY;
 		height_mask = TS_HEIGHT_MASK_ACTIVY;
-	} else {
+		break;
+	case BUDGET_KNC1C:
+	case BUDGET_KNC1CP:
+	case BUDGET_CIN1200C:
+	case BUDGET_KNC1C_MK3:
+	case BUDGET_KNC1CP_MK3:
+	case BUDGET_CIN1200C_MK3:
+		budget->buffer_width = TS_WIDTH_DVBC;
+		max_bufsize = TS_MAX_BUFSIZE_K_DVBC;
+		height_mask = TS_HEIGHT_MASK_DVBC;
+		break;
+	default:
 		budget->buffer_width = TS_WIDTH;
 		max_bufsize = TS_MAX_BUFSIZE_K;
 		height_mask = TS_HEIGHT_MASK;
@@ -415,14 +462,22 @@ int ttpci_budget_init(struct budget *bud
 		dma_buffer_size = max_bufsize;
 
 	budget->buffer_height = dma_buffer_size * 1024 / budget->buffer_width;
-	budget->buffer_height &= height_mask;
-	budget->buffer_size = budget->buffer_height * budget->buffer_width;
+	if (budget->buffer_height > 0xfff) {
+		budget->buffer_height /= 2;
+		budget->buffer_height &= height_mask;
+		budget->buffer_size = 2 * budget->buffer_height * budget->buffer_width;
+	} else {
+		budget->buffer_height &= height_mask;
+		budget->buffer_size = budget->buffer_height * budget->buffer_width;
+	}
 	budget->buffer_warning_threshold = budget->buffer_size * 80/100;
 	budget->buffer_warnings = 0;
 	budget->buffer_warning_time = jiffies;
 
-	dprintk(2, "%s: width = %d, height = %d\n",
-		budget->dev->name, budget->buffer_width, budget->buffer_height);
+	dprintk(2, "%s: buffer type = %s, width = %d, height = %d\n",
+		budget->dev->name,
+		budget->buffer_size > budget->buffer_width * budget->buffer_height ? "odd/even" : "single",
+		budget->buffer_width, budget->buffer_height);
 	printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size);
 
 	if ((ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner, &budget->dev->pci->dev)) < 0) {
diff -r 667e84e2e762 linux/drivers/media/dvb/ttpci/budget.h
--- a/linux/drivers/media/dvb/ttpci/budget.h	Tue Feb 13 07:00:55 2007 -0200
+++ b/linux/drivers/media/dvb/ttpci/budget.h	Tue Feb 13 13:51:09 2007 +0100
@@ -107,6 +107,9 @@ static struct saa7146_pci_extension_data
 #define BUDGET_KNC1CP		   12
 #define BUDGET_KNC1TP		   13
 #define BUDGET_TVSTAR		   14
+#define BUDGET_CIN1200C_MK3	   15
+#define BUDGET_KNC1C_MK3	   16
+#define BUDGET_KNC1CP_MK3	   17	   	
 
 #define BUDGET_VIDEO_PORTA         0
 #define BUDGET_VIDEO_PORTB         1
_______________________________________________
linux-dvb mailing list
linux-dvb@xxxxxxxxxxx
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

[Index of Archives]     [Linux Media]     [Video 4 Linux]     [Asterisk]     [Samba]     [Xorg]     [Xfree86]     [Linux USB]

  Powered by Linux