Mailing List archive

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

[linux-dvb] [rfc/patch] pll handling and cx22702 update



  Hi guys,

Here is one more attempt to move to a more sane pll handling.  The
intention is to move pll mostly out of the dvb adapter drivers, allow
sharing it and kill code duplication.  It also moves away from many
little functions which all do basically the same and uses a generic,
configurable function instead.

I use a data structure (struct dvb_pll_desc) which describes how the pll
must be programmed, i.e. which frequency ranges need which config bytes
and so on.  I think that should catch all those common pll's which are
programmed with a 4-byte i2c write sequence, two bytes divisor and two
config bytes.

There is a function which will take such a description + frequency and
calculates the command sequence resulting from that.  Actually sending
that command sequence to the pll remains the job of the frontend and/or
adapter driver, that is too hardware specific to be factored out into
common code.

The patch also contains my latest cx22702 code which actually uses the
new pll handling.  More sample code can be found in the current
video4linux cvs, in cx88-dvb.c (look there to see how this can be used
with a mt352 frontend).

Don't be scared because of yet another redesign, the old and new stuff
can live in parallel, so can have a more smooth switchover than with
the frontend refactoring ;)

Comments?

  Gerd

Signed-off-by: Gerd Knorr <kraxel@bytesex.org>
---
 drivers/media/dvb/frontends/Makefile  |    1 
 drivers/media/dvb/frontends/cx22702.c |  708 +++++++++++++++-----------
 drivers/media/dvb/frontends/cx22702.h |   50 -
 drivers/media/dvb/frontends/dvb-pll.c |  151 +++++
 drivers/media/dvb/frontends/dvb-pll.h |   33 +
 5 files changed, 619 insertions(+), 324 deletions(-)

Index: linux-2004-12-08/drivers/media/dvb/frontends/dvb-pll.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2004-12-08/drivers/media/dvb/frontends/dvb-pll.h	2004-12-09 14:28:52.130425628 +0100
@@ -0,0 +1,33 @@
+/*
+ * $Id: dvb-pll.h,v 1.1 2004/12/09 12:51:35 kraxel Exp $
+ */
+
+struct dvb_pll_desc {
+	char *name;
+	u32  min;
+	u32  max;
+	void (*setbw)(u8 *buf, int bandwidth);
+	int  count;
+	struct {
+		u32 limit;
+		u32 offset;
+		u32 stepsize;
+		u8  cb1;
+		u8  cb2;
+	} entries[];
+};
+
+extern struct dvb_pll_desc dvb_pll_thomson_dtt7579;
+extern struct dvb_pll_desc dvb_pll_thomson_dtt759x;
+extern struct dvb_pll_desc dvb_pll_lg_z201;
+extern struct dvb_pll_desc dvb_pll_unknown_1;
+
+int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
+		      u32 freq, int bandwidth);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * compile-command: "make DVB=1"
+ * End:
+ */
Index: linux-2004-12-08/drivers/media/dvb/frontends/dvb-pll.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2004-12-08/drivers/media/dvb/frontends/dvb-pll.c	2004-12-09 14:28:52.130425628 +0100
@@ -0,0 +1,151 @@
+/*
+ * $Id: dvb-pll.c,v 1.1 2004/12/09 12:51:35 kraxel Exp $
+ *
+ * descriptions + helper functions for simple dvb plls.
+ *
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/dvb/frontend.h>
+#include <asm/types.h>
+
+#include "dvb-pll.h"
+
+/* ----------------------------------------------------------- */
+/* descriptions                                                */
+
+struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
+	.name  = "Thomson ddt7579",
+	.min   = 177000000,
+	.max   = 858000000,
+	.count = 5,
+	.entries = {
+		{          0, 36166667, 166666, 0xb4, 0x03 }, /* go sleep */
+		{  443250000, 36166667, 166666, 0xb4, 0x02 },
+		{  542000000, 36166667, 166666, 0xb4, 0x08 },
+		{  771000000, 36166667, 166666, 0xbc, 0x08 },
+		{  999999999, 36166667, 166666, 0xf4, 0x08 },
+	},
+};
+EXPORT_SYMBOL(dvb_pll_thomson_dtt7579);
+
+static void thomson_dtt759x_bw(u8 *buf, int bandwidth)
+{
+	if (BANDWIDTH_7_MHZ == bandwidth)
+		buf[3] |= 0x10;
+}
+
+struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
+	.name  = "Thomson ddt759x",
+	.min   = 177000000,
+	.max   = 896000000,
+	.setbw = thomson_dtt759x_bw,
+	.count = 6,
+	.entries = {
+		{          0, 36166667, 166666, 0x84, 0x03 },
+		{  264000000, 36166667, 166666, 0xb4, 0x02 },
+		{  470000000, 36166667, 166666, 0xbc, 0x02 },
+		{  735000000, 36166667, 166666, 0xbc, 0x08 },
+		{  835000000, 36166667, 166666, 0xf4, 0x08 },
+		{  999999999, 36166667, 166666, 0xfc, 0x08 },
+	},
+};
+EXPORT_SYMBOL(dvb_pll_thomson_dtt759x);
+
+struct dvb_pll_desc dvb_pll_lg_z201 = {
+	.name  = "LG z201",
+	.min   = 174000000,
+	.max   = 862000000,
+	.count = 5,
+	.entries = {
+		{          0, 36166667, 166666, 0xbc, 0x03 },
+		{  443250000, 36166667, 166666, 0xbc, 0x01 },
+		{  542000000, 36166667, 166666, 0xbc, 0x02 },
+		{  830000000, 36166667, 166666, 0xf4, 0x02 },
+		{  999999999, 36166667, 166666, 0xfc, 0x02 },
+	},
+};
+EXPORT_SYMBOL(dvb_pll_lg_z201);
+
+struct dvb_pll_desc dvb_pll_unknown_1 = {
+	.name  = "unknown 1", /* used by dntv live dvb-t */
+	.min   = 174000000,
+	.max   = 862000000,
+	.count = 9,
+	.entries = {
+		{  150000000, 36166667, 166666, 0xb4, 0x01 },
+		{  173000000, 36166667, 166666, 0xbc, 0x01 },
+		{  250000000, 36166667, 166666, 0xb4, 0x02 },
+		{  400000000, 36166667, 166666, 0xbc, 0x02 },
+		{  420000000, 36166667, 166666, 0xf4, 0x02 },
+		{  470000000, 36166667, 166666, 0xfc, 0x02 },
+		{  600000000, 36166667, 166666, 0xbc, 0x08 },
+		{  730000000, 36166667, 166666, 0xf4, 0x08 },
+		{  999999999, 36166667, 166666, 0xfc, 0x08 },
+	},
+};
+EXPORT_SYMBOL(dvb_pll_unknown_1);
+
+/* ----------------------------------------------------------- */
+/* code                                                        */
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
+		      u32 freq, int bandwidth)
+{
+	u32 div;
+	int i;
+
+	if (freq != 0 && (freq < desc->min || freq > desc->max))
+	    return -EINVAL;
+
+	for (i = 0; i < desc->count; i++) {
+		if (freq > desc->entries[i].limit)
+			continue;
+		break;
+	}
+	BUG_ON(i == desc->count);
+
+	div = (freq + desc->entries[i].offset) / desc->entries[i].stepsize;
+	buf[0] = div >> 8;
+	buf[1] = div & 0xff;
+	buf[2] = desc->entries[i].cb1;
+	buf[3] = desc->entries[i].cb2;
+
+	if (desc->setbw)
+		desc->setbw(buf, bandwidth);
+
+	if (debug)
+		printk("pll: %s: freq=%d bw=%d | i=%d (%d) div=%d | "
+		       "buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
+		       desc->name, freq, bandwidth, i, desc->entries[i].limit,
+		       div, buf[0], buf[1], buf[2], buf[3]);
+	
+	return 0;
+}
+EXPORT_SYMBOL(dvb_pll_configure);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * compile-command: "make DVB=1"
+ * End:
+ */
Index: linux-2004-12-08/drivers/media/dvb/frontends/cx22702.h
===================================================================
--- linux-2004-12-08.orig/drivers/media/dvb/frontends/cx22702.h	2004-12-09 14:17:55.355170649 +0100
+++ linux-2004-12-08/drivers/media/dvb/frontends/cx22702.h	2004-12-09 14:28:52.131425439 +0100
@@ -1,46 +1,4 @@
-/*
-    Conexant 22702 DVB OFDM demodulator driver
-
-    based on:
-        Alps TDMB7 DVB OFDM demodulator driver
-
-    Copyright (C) 2001-2002 Convergence Integrated Media GmbH
-	  Holger Waechtler <holger@convergence.de>
-
-    Copyright (C) 2004 Steven Toth <steve@toth.demon.co.uk>
-
-    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 CX22702_H
-#define CX22702_H
-
-#include <linux/dvb/frontend.h>
-
-struct cx22702_config
-{
-	/* the demodulator's i2c address */
-	u8 demod_address;
-
-	/* PLL maintenance */
-	int (*pll_init)(struct dvb_frontend* fe);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-};
-
-extern struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
-					   struct i2c_adapter* i2c);
-
-#endif // CX22702_H
+void* cx22702_create(struct i2c_adapter *i2c,
+		     int pll_addr, struct dvb_pll_desc *pll,
+		     int demod_addr);
+int cx22702_destroy(void*);
Index: linux-2004-12-08/drivers/media/dvb/frontends/cx22702.c
===================================================================
--- linux-2004-12-08.orig/drivers/media/dvb/frontends/cx22702.c	2004-12-09 14:17:59.839325749 +0100
+++ linux-2004-12-08/drivers/media/dvb/frontends/cx22702.c	2004-12-09 14:28:52.148422237 +0100
@@ -1,8 +1,8 @@
 /*
-    Conexant 22702 DVB OFDM demodulator driver
+    Conexant 22702 DVB OFDM frontend driver
 
     based on:
-        Alps TDMB7 DVB OFDM demodulator driver
+        Alps TDMB7 DVB OFDM frontend driver
 
     Copyright (C) 2001-2002 Convergence Integrated Media GmbH
 	  Holger Waechtler <holger@convergence.de>
@@ -31,30 +31,36 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+
 #include "dvb_frontend.h"
+#include "dvb-pll.h"
 #include "cx22702.h"
 
+#define FRONTEND_NAME "dvbfe_cx22702"
 
-struct cx22702_state {
-
-	struct i2c_adapter* i2c;
-
-	struct dvb_frontend_ops ops;
+#define dprintk	if (debug) printk
 
-	/* configuration settings */
-	const struct cx22702_config* config;
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
 
-	struct dvb_frontend frontend;
+/* ------------------------------------------------------------------ */
 
-	/* previous uncorrected block counter */
+struct cx22702_state {
+	struct i2c_client               demod;
+	struct i2c_client               pll;
+	struct dvb_pll_desc             *pll_desc;
+	struct dvb_frontend             fe;
+	struct dvb_frontend_ops         ops;
+	struct dvb_frontend_parameters  p;
 	u8 prevUCBlocks;
 };
 
-static int debug = 0;
-#define dprintk	if (debug) printk
+static struct i2c_client demod_template;
+static struct i2c_client pll_template;
 
 /* Register values to initialise the demod */
-static u8 init_tab [] = {
+static u8 init_tab[] = {
 	0x00, 0x00, /* Stop aquisition */
 	0x0B, 0x06,
 	0x09, 0x01,
@@ -83,154 +89,123 @@ static u8 init_tab [] = {
 	0xfd, 0x00,
 };
 
-static int cx22702_writereg (struct cx22702_state* state, u8 reg, u8 data)
+/* ------------------------------------------------------------------ */
+
+static int writereg(struct i2c_client *c, u8 reg, u8 data)
 {
+	u8 buf[] = { reg, data };
 	int ret;
-	u8 buf [] = { reg, data };
-	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
-
-	ret = i2c_transfer(state->i2c, &msg, 1);
 
-	if (ret != 1)
+	ret = i2c_master_send(c, buf, 2);
+	if (ret != 2) {
 		printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
-			__FUNCTION__, reg, data, ret);
-
-	return (ret != 1) ? -1 : 0;
+		       __FUNCTION__, reg, data, ret);
+		return -1;
+	}
+	return 0;
 }
 
-static u8 cx22702_readreg (struct cx22702_state* state, u8 reg)
+static u8 readreg(struct i2c_client *c, u8 reg)
 {
-	int ret;
-	u8 b0 [] = { reg };
-	u8 b1 [] = { 0 };
-
+	u8 wr [] = { reg };
+	u8 rd [] = { 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);
+		{ .addr = c->addr, .flags = 0,        .buf = wr, .len = 1 },
+		{ .addr = c->addr, .flags = I2C_M_RD, .buf = rd, .len = 1 },
+	};
+	int ret;
 
-	if (ret != 2)
+	ret = i2c_transfer(c->adapter, msg, 2);
+	if (ret != 2) {
 		printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
-
-	return b1[0];
-}
-
-static int cx22702_set_inversion (struct cx22702_state *state, int inversion)
-{
-	u8 val;
-
-	switch (inversion) {
-
-		case INVERSION_AUTO:
-			return -EOPNOTSUPP;
-
-		case INVERSION_ON:
-			val = cx22702_readreg (state, 0x0C);
-			return cx22702_writereg (state, 0x0C, val | 0x01);
-
-		case INVERSION_OFF:
-			val = cx22702_readreg (state, 0x0C);
-			return cx22702_writereg (state, 0x0C, val & 0xfe);
-
-		default:
-			return -EINVAL;
-
+		return -1;
 	}
-
+	return rd[0];
 }
 
-/* Retrieve the demod settings */
-static int cx22702_get_tps (struct cx22702_state *state, struct dvb_ofdm_parameters *p)
-{
-	u8 val;
+/* ------------------------------------------------------------------ */
 
-	/* Make sure the TPS regs are valid */
-	if (!(cx22702_readreg(state, 0x0A) & 0x20))
-		return -EAGAIN;
-
-	val = cx22702_readreg (state, 0x01);
-	switch( (val&0x18)>>3) {
-		case 0: p->constellation =   QPSK; break;
-		case 1: p->constellation = QAM_16; break;
-		case 2: p->constellation = QAM_64; break;
-	}
-	switch( val&0x07 ) {
-		case 0: p->hierarchy_information = HIERARCHY_NONE; break;
-		case 1: p->hierarchy_information =    HIERARCHY_1; break;
-		case 2: p->hierarchy_information =    HIERARCHY_2; break;
-		case 3: p->hierarchy_information =    HIERARCHY_4; break;
-	}
-
-
-	val = cx22702_readreg (state, 0x02);
-	switch( (val&0x38)>>3 ) {
-		case 0: p->code_rate_HP = FEC_1_2; break;
-		case 1: p->code_rate_HP = FEC_2_3; break;
-		case 2: p->code_rate_HP = FEC_3_4; break;
-		case 3: p->code_rate_HP = FEC_5_6; break;
-		case 4: p->code_rate_HP = FEC_7_8; break;
-	}
-	switch( val&0x07 ) {
-		case 0: p->code_rate_LP = FEC_1_2; break;
-		case 1: p->code_rate_LP = FEC_2_3; break;
-		case 2: p->code_rate_LP = FEC_3_4; break;
-		case 3: p->code_rate_LP = FEC_5_6; break;
-		case 4: p->code_rate_LP = FEC_7_8; break;
-	}
+#define PLL_ENABLE(cx)  writereg(&cx->demod, 0x0D, readreg(&cx->demod, 0x0D) & 0xfe)
+#define PLL_DISABLE(cx) writereg(&cx->demod, 0x0D, readreg(&cx->demod, 0x0D) | 0x01)
 
+static int pll_write4(struct i2c_client *c, u8 *data)
+{
+	int ret;
 
-	val = cx22702_readreg (state, 0x03);
-	switch( (val&0x0c)>>2 ) {
-		case 0: p->guard_interval = GUARD_INTERVAL_1_32; break;
-		case 1: p->guard_interval = GUARD_INTERVAL_1_16; break;
-		case 2: p->guard_interval =  GUARD_INTERVAL_1_8; break;
-		case 3: p->guard_interval =  GUARD_INTERVAL_1_4; break;
-}
-	switch( val&0x03 ) {
-		case 0: p->transmission_mode = TRANSMISSION_MODE_2K; break;
-		case 1: p->transmission_mode = TRANSMISSION_MODE_8K; break;
+	ret = i2c_master_send(c, data, 4);
+	if (ret != 4) {
+		printk("%s: i/o error (addr == 0x%02x, ret == %i)\n",
+		       __FUNCTION__, c->addr, ret);
+		return -1;
 	}
-
 	return 0;
 }
 
+/* ------------------------------------------------------------------ */
 
+static int cx22702_reset(struct cx22702_state *state)
+{
+	int i;
 
+	dprintk("%s\n",__FUNCTION__);
+	writereg(&state->demod, 0x00, 0x02);
+	msleep(10);
 
+	for (i=0; i<ARRAY_SIZE(init_tab); i+=2)
+		writereg(&state->demod, init_tab[i], init_tab[i+1]);
+	return 0;
+}
 
+static int cx22702_set_inversion(struct cx22702_state *state, int inversion)
+{
+	u8 val;
 
+	switch (inversion) {
+	case INVERSION_AUTO:
+		return -EOPNOTSUPP;
 
+	case INVERSION_ON:
+		val = readreg(&state->demod, 0x0C);
+		return writereg(&state->demod, 0x0C, val | 0x01);
+
+	case INVERSION_OFF:
+		val = readreg(&state->demod, 0x0C);
+		return writereg(&state->demod, 0x0C, val & 0xfe);
 
-
-
-
-
+	default:
+		return -EINVAL;
+	}
+}
 
 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx22702_set_tps(struct cx22702_state *state)
 {
 	u8 val;
-	struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+	u8 pllbuf[4];
+
+	dprintk("%s\n",__FUNCTION__);
 
 	/* set PLL */
-        cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe);
-	state->config->pll_set(fe, p);
-        cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
+	dvb_pll_configure(state->pll_desc, pllbuf,
+			  state->p.frequency,
+			  state->p.u.ofdm.bandwidth);
+	PLL_ENABLE(state);
+	pll_write4(&state->pll,pllbuf);
+	PLL_DISABLE(state);
 
 	/* set inversion */
-	cx22702_set_inversion (state, p->inversion);
+	cx22702_set_inversion(state, state->p.inversion);
 
 	/* set bandwidth */
-	switch(p->u.ofdm.bandwidth) {
+	switch(state->p.u.ofdm.bandwidth) {
 	case BANDWIDTH_6_MHZ:
-		cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xcf) | 0x20 );
+		writereg(&state->demod, 0x0C, (readreg(&state->demod, 0x0C) & 0xcf) | 0x20 );
 		break;
 	case BANDWIDTH_7_MHZ:
-		cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xcf) | 0x10 );
+		writereg(&state->demod, 0x0C, (readreg(&state->demod, 0x0C) & 0xcf) | 0x10 );
 		break;
 	case BANDWIDTH_8_MHZ:
-		cx22702_writereg(state, 0x0C, cx22702_readreg(state, 0x0C) &0xcf );
+		writereg(&state->demod, 0x0C, readreg(&state->demod, 0x0C) &0xcf );
 		break;
 	default:
 		dprintk ("%s: invalid bandwidth\n",__FUNCTION__);
@@ -238,30 +213,30 @@ static int cx22702_set_tps (struct dvb_f
 	}
 
 
-	p->u.ofdm.code_rate_LP = FEC_AUTO; //temp hack as manual not working
+	state->p.u.ofdm.code_rate_LP = FEC_AUTO; //temp hack as manual not working
 
 	/* use auto configuration? */
-	if((p->u.ofdm.hierarchy_information==HIERARCHY_AUTO) ||
-	   (p->u.ofdm.constellation==QAM_AUTO) ||
-	   (p->u.ofdm.code_rate_HP==FEC_AUTO) ||
-	   (p->u.ofdm.code_rate_LP==FEC_AUTO) ||
-	   (p->u.ofdm.guard_interval==GUARD_INTERVAL_AUTO) ||
-	   (p->u.ofdm.transmission_mode==TRANSMISSION_MODE_AUTO) ) {
+	if((state->p.u.ofdm.hierarchy_information==HIERARCHY_AUTO) ||
+	   (state->p.u.ofdm.constellation==QAM_AUTO) ||
+	   (state->p.u.ofdm.code_rate_HP==FEC_AUTO) ||
+	   (state->p.u.ofdm.code_rate_LP==FEC_AUTO) ||
+	   (state->p.u.ofdm.guard_interval==GUARD_INTERVAL_AUTO) ||
+	   (state->p.u.ofdm.transmission_mode==TRANSMISSION_MODE_AUTO) ) {
 
 		/* TPS Source - use hardware driven values */
-		cx22702_writereg(state, 0x06, 0x10);
-		cx22702_writereg(state, 0x07, 0x9);
-		cx22702_writereg(state, 0x08, 0xC1);
-		cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B) & 0xfc );
-		cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 );
-		cx22702_writereg(state, 0x00, 0x01); /* Begin aquisition */
-		printk("%s: Autodetecting\n",__FUNCTION__);
+		writereg(&state->demod, 0x06, 0x10);
+		writereg(&state->demod, 0x07, 0x9);
+		writereg(&state->demod, 0x08, 0xC1);
+		writereg(&state->demod, 0x0B, readreg(&state->demod, 0x0B) & 0xfc );
+		writereg(&state->demod, 0x0C, (readreg(&state->demod, 0x0C) & 0xBF) | 0x40 );
+		writereg(&state->demod, 0x00, 0x01); /* Begin aquisition */
+		dprintk("%s: Autodetecting\n",__FUNCTION__);
 		return 0;
 	}
 
    	/* manually programmed values */
 	val=0;
-	switch(p->u.ofdm.constellation) {
+	switch(state->p.u.ofdm.constellation) {
 		case   QPSK: val = (val&0xe7); break;
 		case QAM_16: val = (val&0xe7)|0x08; break;
 		case QAM_64: val = (val&0xe7)|0x10; break;
@@ -269,7 +244,7 @@ static int cx22702_set_tps (struct dvb_f
 			dprintk ("%s: invalid constellation\n",__FUNCTION__);
 			return -EINVAL;
 	}
-	switch(p->u.ofdm.hierarchy_information) {
+	switch(state->p.u.ofdm.hierarchy_information) {
 		case HIERARCHY_NONE: val = (val&0xf8); break;
 		case    HIERARCHY_1: val = (val&0xf8)|1; break;
 		case    HIERARCHY_2: val = (val&0xf8)|2; break;
@@ -278,10 +253,10 @@ static int cx22702_set_tps (struct dvb_f
 			dprintk ("%s: invalid hierarchy\n",__FUNCTION__);
 			return -EINVAL;
 	}
-	cx22702_writereg (state, 0x06, val);
+	writereg(&state->demod, 0x06, val);
 
 	val=0;
-	switch(p->u.ofdm.code_rate_HP) {
+	switch(state->p.u.ofdm.code_rate_HP) {
 		case FEC_NONE:
 		case FEC_1_2: val = (val&0xc7); break;
 		case FEC_2_3: val = (val&0xc7)|0x08; break;
@@ -292,7 +267,7 @@ static int cx22702_set_tps (struct dvb_f
 			dprintk ("%s: invalid code_rate_HP\n",__FUNCTION__);
 			return -EINVAL;
 	}
-	switch(p->u.ofdm.code_rate_LP) {
+	switch(state->p.u.ofdm.code_rate_LP) {
 		case FEC_NONE:
 		case FEC_1_2: val = (val&0xf8); break;
 		case FEC_2_3: val = (val&0xf8)|1; break;
@@ -303,10 +278,10 @@ static int cx22702_set_tps (struct dvb_f
 			dprintk ("%s: invalid code_rate_LP\n",__FUNCTION__);
 			return -EINVAL;
 	}
-	cx22702_writereg (state, 0x07, val);
+	writereg(&state->demod, 0x07, val);
 
 	val=0;
-	switch(p->u.ofdm.guard_interval) {
+	switch(state->p.u.ofdm.guard_interval) {
 		case GUARD_INTERVAL_1_32: val = (val&0xf3); break;
 		case GUARD_INTERVAL_1_16: val = (val&0xf3)|0x04; break;
 		case  GUARD_INTERVAL_1_8: val = (val&0xf3)|0x08; break;
@@ -315,218 +290,395 @@ static int cx22702_set_tps (struct dvb_f
 			dprintk ("%s: invalid guard_interval\n",__FUNCTION__);
 			return -EINVAL;
 	}
-	switch(p->u.ofdm.transmission_mode) {
+	switch(state->p.u.ofdm.transmission_mode) {
 		case TRANSMISSION_MODE_2K: val = (val&0xfc); break;
 		case TRANSMISSION_MODE_8K: val = (val&0xfc)|1; break;
 		default:
 			dprintk ("%s: invalid transmission_mode\n",__FUNCTION__);
 			return -EINVAL;
 	}
-	cx22702_writereg(state, 0x08, val);
-	cx22702_writereg(state, 0x0B, (cx22702_readreg(state, 0x0B) & 0xfc) | 0x02 );
-	cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 );
+	writereg(&state->demod, 0x08, val);
+	writereg(&state->demod, 0x0B, (readreg(&state->demod, 0x0B) & 0xfc) | 0x02 );
+	writereg(&state->demod, 0x0C, (readreg(&state->demod, 0x0C) & 0xBF) | 0x40 );
 
 	/* Begin channel aquisition */
-	cx22702_writereg(state, 0x00, 0x01);
+	writereg(&state->demod, 0x00, 0x01);
 
 	return 0;
 }
 
-
-/* Reset the demod hardware and reset all of the configuration registers
-   to a default state. */
-static int cx22702_init (struct dvb_frontend* fe)
+/* Retrieve the demod settings */
+static int cx22702_get_tps(struct cx22702_state *state,
+			   struct dvb_ofdm_parameters *p)
 {
-	int i;
-	struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
-
-	cx22702_writereg (state, 0x00, 0x02);
+	u8 val;
 
-	msleep(10);
+	/* Make sure the TPS regs are valid */
+	if (!(readreg(&state->demod, 0x0A) & 0x20))
+		return -EAGAIN;
 
-	for (i=0; i<sizeof(init_tab); i+=2)
-		cx22702_writereg (state, init_tab[i], init_tab[i+1]);
+	val = readreg(&state->demod, 0x01);
+	switch( (val&0x18)>>3) {
+		case 0: p->constellation =   QPSK; break;
+		case 1: p->constellation = QAM_16; break;
+		case 2: p->constellation = QAM_64; break;
+	}
+	switch( val&0x07 ) {
+		case 0: p->hierarchy_information = HIERARCHY_NONE; break;
+		case 1: p->hierarchy_information =    HIERARCHY_1; break;
+		case 2: p->hierarchy_information =    HIERARCHY_2; break;
+		case 3: p->hierarchy_information =    HIERARCHY_4; break;
+	}
 
+	val = readreg(&state->demod, 0x02);
+	switch( (val&0x38)>>3 ) {
+		case 0: p->code_rate_HP = FEC_1_2; break;
+		case 1: p->code_rate_HP = FEC_2_3; break;
+		case 2: p->code_rate_HP = FEC_3_4; break;
+		case 3: p->code_rate_HP = FEC_5_6; break;
+		case 4: p->code_rate_HP = FEC_7_8; break;
+	}
+	switch( val&0x07 ) {
+		case 0: p->code_rate_LP = FEC_1_2; break;
+		case 1: p->code_rate_LP = FEC_2_3; break;
+		case 2: p->code_rate_LP = FEC_3_4; break;
+		case 3: p->code_rate_LP = FEC_5_6; break;
+		case 4: p->code_rate_LP = FEC_7_8; break;
+	}
 
-	/* init PLL */
-	if (state->config->pll_init) {
-	        cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe);
-		state->config->pll_init(fe);
-		cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
+	val = readreg(&state->demod, 0x03);
+	switch( (val&0x0c)>>2 ) {
+		case 0: p->guard_interval = GUARD_INTERVAL_1_32; break;
+		case 1: p->guard_interval = GUARD_INTERVAL_1_16; break;
+		case 2: p->guard_interval =  GUARD_INTERVAL_1_8; break;
+		case 3: p->guard_interval =  GUARD_INTERVAL_1_4; break;
+	}
+	switch( val&0x03 ) {
+		case 0: p->transmission_mode = TRANSMISSION_MODE_2K; break;
+		case 1: p->transmission_mode = TRANSMISSION_MODE_8K; break;
 	}
 
 	return 0;
 }
 
-static int cx22702_read_status(struct dvb_frontend* fe, fe_status_t* status)
-{
-	struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
-	u8 reg0A;
-	u8 reg23;
+/* ------------------------------------------------------------------ */
 
-			*status = 0;
+/* Validate the demod, make sure we understand the hardware */
+static int cx22702_validate_demod(struct i2c_client *c)
+{
+	int type = readreg(c, 0x1f);
 
-	reg0A = cx22702_readreg (state, 0x0A);
-	reg23 = cx22702_readreg (state, 0x23);
+	if (0x03 != type) {
+		printk ("%s i2c demod type 0x%02x not known\n",
+			__FUNCTION__, type);
+		return -ENODEV;
+	}
+	return 0;
+}
 
-			dprintk ("%s: status demod=0x%02x agc=0x%02x\n"
-				,__FUNCTION__,reg0A,reg23);
+/* Validate the tuner PLL, make sure we understand the hardware */
+static int cx22702_validate_pll(struct cx22702_state *state)
+{
+	int result=0;
 
-			if(reg0A & 0x10) {
-				*status |= FE_HAS_LOCK;
-				*status |= FE_HAS_VITERBI;
-				*status |= FE_HAS_SYNC;
-			}
+	PLL_ENABLE(state);
+	result = readreg(&state->pll,0xc2);
+	PLL_DISABLE(state);
+	return result;
+}
 
-			if(reg0A & 0x20)
-				*status |= FE_HAS_CARRIER;
+/* ------------------------------------------------------------------ */
 
-			if(reg23 < 0xf0)
-				*status |= FE_HAS_SIGNAL;
+static int cx22702_init(struct dvb_frontend* fe)
+{
+	struct cx22702_state *state = fe->demodulator_priv;
 
+	cx22702_reset(state);
 	return 0;
-			}
-
-static int cx22702_read_ber(struct dvb_frontend* fe, u32* ber)
-		{
-	struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+}
 
-	if(cx22702_readreg (state, 0xE4) & 0x02) {
-				/* Realtime statistics */
-		*ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7
-			| (cx22702_readreg (state, 0xDF)&0x7F);
-			} else {
-		/* Averagtine statistics */
-		*ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7
-			| cx22702_readreg (state, 0xDF);
-		}
-
-	return 0;
-		}
-
-static int cx22702_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
-		{
-	struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+static int cx22702_sleep(struct dvb_frontend* fe)
+{
+	struct cx22702_state *state = fe->demodulator_priv;
+	u8 pllbuf[4];
 
-	*signal_strength = cx22702_readreg (state, 0x23);
+	dprintk("%s\n",__FUNCTION__);
 
+	dvb_pll_configure(state->pll_desc, pllbuf, 0, 0);
+	PLL_ENABLE(state);
+	pll_write4(&state->pll,pllbuf);
+	PLL_DISABLE(state);
 	return 0;
 }
 
-static int cx22702_read_snr(struct dvb_frontend* fe, u16* snr)
+static int cx22702_set_frontend(struct dvb_frontend* fe,
+				struct dvb_frontend_parameters* params)
 {
-	struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
-
-	u16 rs_ber=0;
-	if(cx22702_readreg (state, 0xE4) & 0x02) {
-		/* Realtime statistics */
-		rs_ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7
-			| (cx22702_readreg (state, 0xDF)& 0x7F);
-	} else {
-		/* Averagine statistics */
-		rs_ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 8
-			| cx22702_readreg (state, 0xDF);
-	}
-	*snr = ~rs_ber;
+	struct cx22702_state *state = fe->demodulator_priv;
+	int ret;
 
-	return 0;
+	state->p = *params;
+	ret=cx22702_set_tps(state);
+	if (debug && ret < 0)
+		printk("%s: set_tps failed ret=%d\n",__FUNCTION__,ret);
+	return ret;
 }
 
-static int cx22702_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+static int cx22702_get_frontend(struct dvb_frontend* fe,
+				struct dvb_frontend_parameters* params)
 {
-	struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+	struct cx22702_state *state = fe->demodulator_priv;
+	u8 reg0C = readreg(&state->demod, 0x0C);
+	params->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF;
+	return cx22702_get_tps(state, &params->u.ofdm);
+}
 
-	u8 _ucblocks;
+#if 0
+static int cx22702_get_tune_settings(struct dvb_frontend* fe,
+				     struct dvb_frontend_tune_settings* settings)
+{
+	struct cx22702_state *state = fe->demodulator_priv;
+}
+#endif
 
-	/* RS Uncorrectable Packet Count then reset */
-	_ucblocks = cx22702_readreg (state, 0xE3);
-	if (state->prevUCBlocks < _ucblocks) *ucblocks = (_ucblocks - state->prevUCBlocks);
-	else *ucblocks = state->prevUCBlocks - _ucblocks;
-	state->prevUCBlocks = _ucblocks;
+static int cx22702_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct cx22702_state *state = fe->demodulator_priv;
+	u8 reg0A = readreg(&state->demod, 0x0A);
+	u8 reg23 = readreg(&state->demod, 0x23);
+
+	*status = 0;
+	if(reg0A & 0x10)
+		*status |= FE_HAS_LOCK| FE_HAS_VITERBI | FE_HAS_SYNC;
+	if(reg0A & 0x20)
+		*status |= FE_HAS_CARRIER;
+	if(reg23 < 0xf0)
+		*status |= FE_HAS_SIGNAL;
 
+	dprintk ("%s: status demod=0x%02x agc=0x%02x status=0x%x\n",
+		 __FUNCTION__,reg0A,reg23,*status);
 	return 0;
 }
 
-static int cx22702_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx22702_read_ber(struct dvb_frontend* fe, u32* ber)
 {
-	struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
-
-	u8 reg0C = cx22702_readreg (state, 0x0C);
+	struct cx22702_state *state = fe->demodulator_priv;
 
-	p->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF;
-	return cx22702_get_tps (state, &p->u.ofdm);
+	*ber = (readreg(&state->demod, 0xDE) & 0x7F) << 7;
+	*ber |= readreg(&state->demod, 0xDF) & 0x7F;
+	return 0;
 }
 
-static void cx22702_release(struct dvb_frontend* fe)
+static int cx22702_read_signal_strength(struct dvb_frontend* fe, u16* strength)
 {
-	struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
-		kfree(state);
-	}
+	struct cx22702_state *state = fe->demodulator_priv;
 
-static struct dvb_frontend_ops cx22702_ops;
+	*strength = readreg(&state->demod, 0x23);
+	return 0;
+}
 
-struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
-				    struct i2c_adapter* i2c)
+static int cx22702_read_snr(struct dvb_frontend* fe, u16* snr)
 {
-	struct cx22702_state* state = NULL;
+	u32 ber;
 
-	/* allocate memory for the internal state */
-	state = (struct cx22702_state*) kmalloc(sizeof(struct cx22702_state), GFP_KERNEL);
-	if (state == NULL) goto error;
+	/* We don't have an register for this         */
+	/* We'll take the inverse of the BER register */
+	cx22702_read_ber(fe, &ber);
+	*snr = ~ber;
+	return 0;
+}
 
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	memcpy(&state->ops, &cx22702_ops, sizeof(struct dvb_frontend_ops));
-	state->prevUCBlocks = 0;
+static int cx22702_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct cx22702_state *state = fe->demodulator_priv;
+	u8 ucb;
 
-	/* check if the demod is there */
-	if (cx22702_readreg(state, 0x1f) != 0x3) goto error;
+	/* RS Uncorrectable Packet Count then reset */
+	ucb = readreg(&state->demod, 0xE3);
+	if (state->prevUCBlocks < ucb)
+		*ucblocks = (ucb - state->prevUCBlocks);
+	else
+		*ucblocks = 256 + ucb - state->prevUCBlocks;
+	state->prevUCBlocks = ucb;
+	return 0;
+}
 
-	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
+static void cx22702_release(struct dvb_frontend* fe)
+{
+	struct cx22702_state *state = fe->demodulator_priv;
 
-error:
-	if (state) kfree(state);
-	return NULL;
+	i2c_detach_client(&state->demod);
+	i2c_detach_client(&state->pll);
+	kfree(state);
 }
 
-static struct dvb_frontend_ops cx22702_ops = {
-
+static struct dvb_frontend_ops cx22702_fe_ops = {
 	.info = {
-		.name			= "Conexant CX22702 DVB-T",
+		.name			= "cx22702 demod",
 		.type			= FE_OFDM,
 		.frequency_min		= 177000000,
 		.frequency_max		= 858000000,
 		.frequency_stepsize	= 166666,
-		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-		FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-		FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-		FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
-		FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER
+		.caps =
+		FE_CAN_FEC_1_2 |
+		FE_CAN_FEC_2_3 |
+		FE_CAN_FEC_3_4 |
+		FE_CAN_FEC_5_6 |
+		FE_CAN_FEC_7_8 |
+		FE_CAN_FEC_AUTO |
+		FE_CAN_QPSK |
+		FE_CAN_QAM_16 |
+		FE_CAN_QAM_64 |
+		FE_CAN_QAM_AUTO |
+		FE_CAN_HIERARCHY_AUTO |
+		FE_CAN_GUARD_INTERVAL_AUTO |
+		FE_CAN_TRANSMISSION_MODE_AUTO |
+		FE_CAN_RECOVER,
 	},
+	.init                 = cx22702_init,
+	.sleep                = cx22702_sleep,
+	.set_frontend         = cx22702_set_frontend,
+	.get_frontend         = cx22702_get_frontend,
+	.read_status          = cx22702_read_status,
+	.read_ber             = cx22702_read_ber,
+	.read_signal_strength = cx22702_read_signal_strength,
+	.read_snr             = cx22702_read_snr,
+	.read_ucblocks        = cx22702_read_ucblocks,
+	.release              = cx22702_release,
+};
 
-	.release = cx22702_release,
+void* cx22702_create(struct i2c_adapter *i2c,
+		     int pll_addr, struct dvb_pll_desc *pll_desc,
+		     int demod_addr)
+{
+	struct cx22702_state *state;
+	int ret;
 
-	.init = cx22702_init,
+	state = kmalloc(sizeof(*state), GFP_KERNEL);
+	if (NULL == state)
+		return NULL;
+	memset(state, 0, sizeof(*state));
+
+	state->ops                 = cx22702_fe_ops;
+	state->pll_desc            = pll_desc;
+	state->fe.demodulator_priv = state;
+	state->fe.ops              = &state->ops;
+
+	state->demod         = demod_template;
+	state->demod.adapter = i2c;
+	state->demod.addr    = demod_addr;
+	state->pll           = pll_template;
+	strlcpy(state->pll.name, pll_desc->name, sizeof(state->pll.name));
+	state->pll.adapter   = i2c;
+	state->pll.addr      = pll_addr;
+	i2c_set_clientdata(&state->demod, state);
+	i2c_set_clientdata(&state->pll, state);
+
+	/* verify devices */
+	ret=cx22702_validate_demod(&state->demod);
+	if (ret < 0)
+		goto fail_free;
+	ret=cx22702_validate_pll(state);
+	if(ret < 0)
+		goto fail_free;
+
+	/* register i2c */
+	ret = i2c_attach_client(&state->demod);
+	if (0 != ret) {
+		printk("cx22702: i2c demod register failed (%d)\n", ret);
+		goto fail_free;
+	}
+	ret = i2c_attach_client(&state->pll);
+	if (0 != ret) {
+		printk("cx22702: i2c pll register failed (%d)\n", ret);
+		goto fail_unreg1;
+	}
+
+	/* all fine ;) */
+	return &state->fe;
+
+fail_unreg1:
+	i2c_detach_client(&state->demod);
+fail_free:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(cx22702_create);
 
-	.set_frontend = cx22702_set_tps,
-	.get_frontend = cx22702_get_frontend,
+static int cx22702_suspend(struct device * dev, u32 state, u32 level)
+{
+	struct i2c_client *c = container_of(dev, struct i2c_client, dev);
+	struct cx22702_state *st = i2c_get_clientdata(c);
 
-	.read_status = cx22702_read_status,
-	.read_ber = cx22702_read_ber,
-	.read_signal_strength = cx22702_read_signal_strength,
-	.read_snr = cx22702_read_snr,
-	.read_ucblocks = cx22702_read_ucblocks,
+	dprintk("cx22702: suspend\n");
+	cx22702_sleep(&st->fe);
+	return 0;
+}
+
+static int cx22702_resume(struct device * dev, u32 level)
+{
+	struct i2c_client *c = container_of(dev, struct i2c_client, dev);
+	struct cx22702_state *st = i2c_get_clientdata(c);
+
+	dprintk("cx22702: resume\n");
+	cx22702_reset(st);
+	if (st->p.frequency != 0)
+		cx22702_set_tps(st);
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static struct i2c_driver demod_driver = {
+	.owner = THIS_MODULE,
+	.name  = __stringify(KBUILD_MODNAME) " demod",
+	.id    = I2C_DRIVERID_DVBFE_CX22702,
+	.driver {
+		.suspend = cx22702_suspend,
+		.resume  = cx22702_resume,
+	},
+};
+static struct i2c_client demod_template = {
+	.name   = "cx22702",
+	.flags  = I2C_CLIENT_ALLOW_USE,
+	.driver = &demod_driver,
 };
 
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+static struct i2c_driver pll_driver = {
+	.owner = THIS_MODULE,
+	.name  = __stringify(KBUILD_MODNAME) " pll",
+	.id    = I2C_DRIVERID_DVBFE_CX22702,
+};
+static struct i2c_client pll_template = {
+	.name   = "unset",
+	.flags  = I2C_CLIENT_ALLOW_USE,
+	.driver = &pll_driver,
+};
 
-MODULE_DESCRIPTION("Conexant CX22702 DVB-T Demodulator driver");
+static int __init init_cx22702 (void)
+{
+	i2c_add_driver(&demod_driver);
+	i2c_add_driver(&pll_driver);
+	return 0;
+}
+
+static void __exit exit_cx22702 (void)
+{
+	i2c_del_driver(&pll_driver);
+	i2c_del_driver(&demod_driver);
+}
+
+module_init (init_cx22702);
+module_exit (exit_cx22702);
+
+MODULE_DESCRIPTION("CX22702 DVB Frontend driver");
 MODULE_AUTHOR("Steven Toth");
+MODULE_AUTHOR("Gerd Knorr");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(cx22702_attach);
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * compile-command: "make DVB=1"
+ * End:
+ */
Index: linux-2004-12-08/drivers/media/dvb/frontends/Makefile
===================================================================
--- linux-2004-12-08.orig/drivers/media/dvb/frontends/Makefile	2004-12-09 14:15:21.000000000 +0100
+++ linux-2004-12-08/drivers/media/dvb/frontends/Makefile	2004-12-09 14:30:01.191414058 +0100
@@ -4,6 +4,7 @@
 
 EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
 
+obj-$(CONFIG_DVB) += dvb-pll.o
 obj-$(CONFIG_DVB_STV0299) += stv0299.o
 obj-$(CONFIG_DVB_SP8870) += sp8870.o
 obj-$(CONFIG_DVB_CX22700) += cx22700.o




Home | Main Index | Thread Index