Mailing List archive

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

[linux-dvb] Re: [patches] cx22702 + mt352 updates



  Hi,

> > But I don't want to start over from scratch with a code base where I
> > don't even know whenever it works or not, which I would have to to
> > create a minimal patch.
> 
> I got that already, but it is still what I'm asking you to do,
> whether you see the point or not. If you can convince someone else
> (Andrew, Michael, ...) to commit your patch, fine. But I won't do it.

How about this one?  Switched over to using a config struct like the
current linuxtv version, also reordered the functions to match the
linuxtv version's ordering so diff produces a smaller and more readable
patch ...

  Gerd

diff -pu --ignore-all-space --minimal /work/bk/2.6/Linux/drivers/media/dvb/frontends/cx22702.h ./cx22702.h
--- /work/bk/2.6/Linux/drivers/media/dvb/frontends/cx22702.h	2004-12-08 16:43:38.000000000 +0100
+++ ./cx22702.h	2005-02-04 10:37:46.000000000 +0100
@@ -36,8 +36,14 @@ struct cx22702_config
 	u8 demod_address;
 
 	/* PLL maintenance */
+	u8 pll_address;
+	struct dvb_pll_desc *pll_desc;
+
+#if 0 /* disabled for now, but maybe we'll need it again for plls
+       * which don't fit into the dvb_pll_desc model ... */
 	int (*pll_init)(struct dvb_frontend* fe);
 	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+#endif
 };
 
 extern struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
diff -pu --ignore-all-space --minimal /work/bk/2.6/Linux/drivers/media/dvb/frontends/cx22702.c ./cx22702.c
--- /work/bk/2.6/Linux/drivers/media/dvb/frontends/cx22702.c	2004-12-08 16:37:00.000000000 +0100
+++ ./cx22702.c	2005-02-04 13:34:55.000000000 +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,27 +31,32 @@
 #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 {
+#define dprintk	if (debug) printk
 
-	struct i2c_adapter* i2c;
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
 
-	struct dvb_frontend_ops ops;
+/* ------------------------------------------------------------------ */
 
-	/* configuration settings */
+struct cx22702_state {
 	const struct cx22702_config* config;
-
-	struct dvb_frontend frontend;
-
-	/* previous uncorrected block counter */
+	struct i2c_client               demod;
+	struct i2c_client               pll;
+	struct dvb_frontend             fe;
+	struct dvb_frontend_ops         ops;
 	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 [] = {
@@ -83,37 +88,71 @@ 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)
 {
-	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);
+	int ret;
 
-	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 -1;
+	}
+	return 0;
+}
 
-	return (ret != 1) ? -1 : 0;
+static int readreg(struct i2c_client *c, u8 reg)
+{
+	u8 wr [] = { reg };
+	u8 rd [] = { 0 };
+	struct i2c_msg msg [] = {
+		{ .addr = c->addr, .flags = 0,        .buf = wr, .len = 1 },
+		{ .addr = c->addr, .flags = I2C_M_RD, .buf = rd, .len = 1 },
+	};
+	int ret;
+
+	ret = i2c_transfer(c->adapter, msg, 2);
+	if (ret != 2) {
+		printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+		return -1;
+	}
+	return rd[0];
 }
 
-static u8 cx22702_readreg (struct cx22702_state* state, u8 reg)
+/* ------------------------------------------------------------------ */
+
+#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;
-	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_master_send(c, data, 4);
+	if (ret != 4) {
+		printk("%s: i/o error (addr == 0x%02x, ret == %i)\n",
+		       __FUNCTION__, c->addr, ret);
+		return -EIO;
+	}
+	return 0;
+}
 
-	ret = i2c_transfer(state->i2c, msg, 2);
+/* ------------------------------------------------------------------ */
 
-	if (ret != 2)
-		printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+static int cx22702_reset(struct cx22702_state *state)
+{
+	int i;
 
-	return b1[0];
+	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)
@@ -121,35 +160,33 @@ static int cx22702_set_inversion (struct
 	u8 val;
 
 	switch (inversion) {
-
 		case INVERSION_AUTO:
 			return -EOPNOTSUPP;
 
 		case INVERSION_ON:
-			val = cx22702_readreg (state, 0x0C);
-			return cx22702_writereg (state, 0x0C, val | 0x01);
+		val = readreg(&state->demod, 0x0C);
+		return writereg(&state->demod, 0x0C, val | 0x01);
 
 		case INVERSION_OFF:
-			val = cx22702_readreg (state, 0x0C);
-			return cx22702_writereg (state, 0x0C, val & 0xfe);
+		val = readreg(&state->demod, 0x0C);
+		return writereg(&state->demod, 0x0C, val & 0xfe);
 
 		default:
 			return -EINVAL;
-
 	}
-
 }
 
 /* Retrieve the demod settings */
-static int cx22702_get_tps (struct cx22702_state *state, struct dvb_ofdm_parameters *p)
+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))
+	if (!(readreg(&state->demod, 0x0A) & 0x20))
 		return -EAGAIN;
 
-	val = cx22702_readreg (state, 0x01);
+	val = readreg(&state->demod, 0x01);
 	switch( (val&0x18)>>3) {
 		case 0: p->constellation =   QPSK; break;
 		case 1: p->constellation = QAM_16; break;
@@ -162,8 +199,7 @@ static int cx22702_get_tps (struct cx227
 		case 3: p->hierarchy_information =    HIERARCHY_4; break;
 	}
 
-
-	val = cx22702_readreg (state, 0x02);
+	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;
@@ -179,8 +215,7 @@ static int cx22702_get_tps (struct cx227
 		case 4: p->code_rate_LP = FEC_7_8; break;
 	}
 
-
-	val = cx22702_readreg (state, 0x03);
+	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;
@@ -195,28 +230,22 @@ static int cx22702_get_tps (struct cx227
 	return 0;
 }
 
-
-
-
-
-
-
-
-
-
-
-
-
 /* 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,
+			   struct dvb_frontend_parameters *p)
 {
 	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->config->pll_desc, pllbuf,
+			  p->frequency,
+			  p->u.ofdm.bandwidth);
+	PLL_ENABLE(state);
+	pll_write4(&state->pll,pllbuf);
+	PLL_DISABLE(state);
 
 	/* set inversion */
 	cx22702_set_inversion (state, p->inversion);
@@ -224,13 +253,13 @@ static int cx22702_set_tps (struct dvb_f
 	/* set bandwidth */
 	switch(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__);
@@ -249,13 +278,13 @@ static int cx22702_set_tps (struct dvb_f
 	   (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;
 	}
 
@@ -278,7 +307,7 @@ 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) {
@@ -303,7 +332,7 @@ 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) {
@@ -322,211 +351,298 @@ static int cx22702_set_tps (struct dvb_f
 			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)
 {
-	int i;
-	struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
-
-	cx22702_writereg (state, 0x00, 0x02);
-
-	msleep(10);
-
-	for (i=0; i<sizeof(init_tab); i+=2)
-		cx22702_writereg (state, init_tab[i], init_tab[i+1]);
-
-
-	/* 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);
-	}
+	struct cx22702_state *state = fe->demodulator_priv;
 
+	cx22702_reset(state);
 	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;
+	struct cx22702_state *state = fe->demodulator_priv;
+	u8 reg0A = readreg(&state->demod, 0x0A);
+	u8 reg23 = readreg(&state->demod, 0x23);
 
 			*status = 0;
-
-	reg0A = cx22702_readreg (state, 0x0A);
-	reg23 = cx22702_readreg (state, 0x23);
-
-			dprintk ("%s: status demod=0x%02x agc=0x%02x\n"
-				,__FUNCTION__,reg0A,reg23);
-
-			if(reg0A & 0x10) {
-				*status |= FE_HAS_LOCK;
-				*status |= FE_HAS_VITERBI;
-				*status |= FE_HAS_SYNC;
-			}
-
+	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_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);
-		}
+	struct cx22702_state *state = fe->demodulator_priv;
 
+	*ber = (readreg(&state->demod, 0xDE) & 0x7F) << 7;
+	*ber |= readreg(&state->demod, 0xDF) & 0x7F;
 	return 0;
 		}
 
-static int cx22702_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+static int cx22702_read_signal_strength(struct dvb_frontend* fe, u16* strength)
 		{
-	struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
-
-	*signal_strength = cx22702_readreg (state, 0x23);
+	struct cx22702_state *state = fe->demodulator_priv;
 
+	*strength = readreg(&state->demod, 0x23);
 	return 0;
 }
 
 static int cx22702_read_snr(struct dvb_frontend* fe, u16* snr)
 {
-	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;
+	u32 ber;
 
+	/* 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;
 }
 
 static int cx22702_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
 {
-	struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
-
-	u8 _ucblocks;
+	struct cx22702_state *state = fe->demodulator_priv;
+	u8 ucb;
 
 	/* 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;
-
+	ucb = readreg(&state->demod, 0xE3);
+	if (state->prevUCBlocks < ucb)
+		*ucblocks = (ucb - state->prevUCBlocks);
+	else
+		*ucblocks = 256 + ucb - state->prevUCBlocks;
+	state->prevUCBlocks = ucb;
 	return 0;
 }
 
-static int cx22702_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+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 reg0C = cx22702_readreg (state, 0x0C);
+static int cx22702_set_frontend(struct dvb_frontend* fe,
+				struct dvb_frontend_parameters* params)
+{
+	struct cx22702_state *state = fe->demodulator_priv;
+	int ret;
 
-	p->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF;
-	return cx22702_get_tps (state, &p->u.ofdm);
+	ret=cx22702_set_tps(state, params);
+	if (debug && ret < 0)
+		printk("%s: set_tps failed ret=%d\n",__FUNCTION__,ret);
+	return ret;
 }
 
 static void cx22702_release(struct dvb_frontend* fe)
 {
-	struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+	struct cx22702_state *state = fe->demodulator_priv;
+
+	i2c_detach_client(&state->demod);
+	i2c_detach_client(&state->pll);
 		kfree(state);
 	}
 
-static struct dvb_frontend_ops cx22702_ops;
-
-struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
-				    struct i2c_adapter* i2c)
+static int cx22702_sleep(struct dvb_frontend* fe)
 {
-	struct cx22702_state* state = NULL;
-
-	/* allocate memory for the internal state */
-	state = (struct cx22702_state*) kmalloc(sizeof(struct cx22702_state), GFP_KERNEL);
-	if (state == NULL) goto error;
-
-	/* setup the state */
-	state->config = config;
-	state->i2c = i2c;
-	memcpy(&state->ops, &cx22702_ops, sizeof(struct dvb_frontend_ops));
-	state->prevUCBlocks = 0;
-
-	/* check if the demod is there */
-	if (cx22702_readreg(state, 0x1f) != 0x3) goto error;
+	struct cx22702_state *state = fe->demodulator_priv;
+	u8 pllbuf[4];
 
-	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
-	state->frontend.demodulator_priv = state;
-	return &state->frontend;
+	dprintk("%s\n",__FUNCTION__);
 
-error:
-	if (state) kfree(state);
-	return NULL;
+	dvb_pll_configure(state->config->pll_desc, pllbuf, 0, 0);
+	PLL_ENABLE(state);
+	pll_write4(&state->pll,pllbuf);
+	PLL_DISABLE(state);
+	return 0;
 }
 
-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,
 	},
-
-	.release = cx22702_release,
-
 	.init = cx22702_init,
-
-	.set_frontend = cx22702_set_tps,
+	.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,
 };
 
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+/* ------------------------------------------------------------------ */
 
-MODULE_DESCRIPTION("Conexant CX22702 DVB-T Demodulator driver");
+/* Validate the demod, make sure we understand the hardware */
+static int cx22702_validate_demod(struct i2c_client *c)
+{
+	int type = readreg(c, 0x1f);
+
+	if (0x03 != type) {
+		printk ("%s i2c demod type 0x%02x not known\n",
+			__FUNCTION__, type);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+/* Validate the tuner PLL, make sure we understand the hardware */
+static int cx22702_validate_pll(struct cx22702_state *state)
+{
+	int result=0;
+
+	PLL_ENABLE(state);
+	result = readreg(&state->pll,0xc2);
+	PLL_DISABLE(state);
+	return result;
+}
+
+struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
+				    struct i2c_adapter* i2c)
+{
+	struct cx22702_state *state;
+	int ret;
+
+	state = kmalloc(sizeof(*state), GFP_KERNEL);
+	if (NULL == state)
+		return NULL;
+	memset(state, 0, sizeof(*state));
+
+	state->config              = config;
+	state->ops                 = cx22702_fe_ops;
+	state->fe.demodulator_priv = state;
+	state->fe.ops              = &state->ops;
+
+	state->demod         = demod_template;
+	state->demod.adapter = i2c;
+	state->demod.addr    = config->demod_address;
+	state->pll           = pll_template;
+	strlcpy(state->pll.name, config->pll_desc->name, sizeof(state->pll.name));
+	state->pll.adapter   = i2c;
+	state->pll.addr      = config->pll_address;
+	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_attach);
+
+/* ------------------------------------------------------------------ */
+
+static struct i2c_driver demod_driver = {
+	.owner = THIS_MODULE,
+	.name  = __stringify(KBUILD_MODNAME) " demod",
+	.id    = I2C_DRIVERID_DVBFE_CX22702,
+};
+static struct i2c_client demod_template = {
+	.name   = "cx22702",
+	.flags  = I2C_CLIENT_ALLOW_USE,
+	.driver = &demod_driver,
+};
+
+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,
+};
+
+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:
+ */




Home | Main Index | Thread Index