Mailing List archive

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

[linux-dvb] Re: [patch-rfc] frontend firmware



Hi Michael!

On Monday 21 June 2004 20:44, Michael Hunold wrote:
> It's inevitable to switch over to kernel-i2c for the saa7146 based cards
> and let dvb-i2c vanish.
>
> For the stv0299 and the tda1004x drivers, I already did these changes,
> ie. they use the kernel-i2c interface and the kernel-i2c adapters
> registered by av7110 and budget.
>
> The big plus is, that kernel-i2c automatically does all the sysfs and
> kobject foo. In addition, it's very easy to use the firmware-loading
> facilities in conjunction with kernel-i2c.
>
> Please have a look at the tda1004x driver, where firmware loading is
> implemented through the device member of the i2c client object.

Ahh, I see clearly now. Didn't notice what was what earlier, but...

> In the short term, we should at least convert all drivers that need
> firmware to kernel-i2c.

Please check the attached patch very thoroughly, as I most certainly broke 
something :) It's only the sp887x, but at least it's something. I belive you 
asked kindly for patches like this a couple of months ago..

> Michael.

Regards,
Kenneth
Index: linux/drivers/media/dvb/frontends/sp887x.c
===================================================================
RCS file: /cvs/linuxtv/dvb-kernel/linux/drivers/media/dvb/frontends/sp887x.c,v
retrieving revision 1.11
diff -u -r1.11 sp887x.c
--- linux/drivers/media/dvb/frontends/sp887x.c	11 Mar 2004 18:40:44 -0000	1.11
+++ linux/drivers/media/dvb/frontends/sp887x.c	21 Jun 2004 20:35:47 -0000
@@ -22,18 +22,13 @@
 #include <linux/fs.h>
 #include <linux/unistd.h>
 #include <linux/fcntl.h>
-#include <linux/errno.h>
 #include <linux/i2c.h>
-
+#include <linux/firmware.h>
 
 #include "dvb_frontend.h"
 #include "dvb_functions.h"
 
-#ifndef DVB_SP887X_FIRMWARE_FILE
-#define DVB_SP887X_FIRMWARE_FILE "/usr/lib/hotplug/firmware/sc_main.mc"
-#endif
-
-static char *sp887x_firmware = DVB_SP887X_FIRMWARE_FILE;
+#define I2C_DRIVERID_SP887X I2C_DRIVERID_EXP2
 
 #if 0
 #define dprintk(x...) printk(x)
@@ -68,18 +63,21 @@
                 FE_CAN_RECOVER
 };
 
-static int errno;
+struct sp887x_state {
+	u8			initialized;
+	struct i2c_adapter	*i2c;
+	struct dvb_adapter	*dvb;
+};
 
 static
-int i2c_writebytes (struct dvb_frontend *fe, u8 addr, u8 *buf, u8 len)
+int i2c_writebytes (struct i2c_adapter *i2c, u8 addr, u8 *buf, u8 len)
 {
-	struct dvb_i2c_bus *i2c = fe->i2c;
 	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = len };
 	int err;
 
 	LOG("i2c_writebytes", msg.addr, msg.buf, msg.len);
 
-	if ((err = i2c->xfer (i2c, &msg, 1)) != 1) {
+	if ((err = i2c_transfer(i2c, &msg, 1)) != 1) {
 		printk ("%s: i2c write error (addr %02x, err == %i)\n",
 			__FUNCTION__, addr, err);
 		return -EREMOTEIO;
@@ -91,16 +89,15 @@
 
 
 static
-int sp887x_writereg (struct dvb_frontend *fe, u16 reg, u16 data)
+int sp887x_writereg (struct i2c_adapter *i2c, u16 reg, u16 data)
 {
-	struct dvb_i2c_bus *i2c = fe->i2c;
 	u8 b0 [] = { reg >> 8 , reg & 0xff, data >> 8, data & 0xff };
 	struct i2c_msg msg = { .addr = 0x70, .flags = 0, .buf = b0, .len = 4 };
 	int ret;
 
 	LOG("sp887x_writereg", msg.addr, msg.buf, msg.len);
 
-	if ((ret = i2c->xfer(i2c, &msg, 1)) != 1) {
+	if ((ret = i2c_transfer(i2c, &msg, 1)) != 1) {
 		/**
 		 *  in case of soft reset we ignore ACK errors...
 		 */
@@ -119,9 +116,8 @@
 
 
 static
-u16 sp887x_readreg (struct dvb_frontend *fe, u16 reg)
+u16 sp887x_readreg (struct i2c_adapter *i2c, u16 reg)
 {
-	struct dvb_i2c_bus *i2c = fe->i2c;
 	u8 b0 [] = { reg >> 8 , reg & 0xff };
 	u8 b1 [2];
 	int ret;
@@ -131,7 +127,7 @@
 	LOG("sp887x_readreg (w)", msg[0].addr, msg[0].buf, msg[0].len);
 	LOG("sp887x_readreg (r)", msg[1].addr, msg[1].buf, msg[1].len);
 
-	if ((ret = i2c->xfer(i2c, msg, 2)) != 2)
+	if ((ret = i2c_transfer(i2c, msg, 2)) != 2)
 		printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
 
 	return (((b1[0] << 8) | b1[1]) & 0xfff);
@@ -139,182 +135,56 @@
 
 
 static
-void sp887x_microcontroller_stop (struct dvb_frontend *fe)
+void sp887x_microcontroller_stop (struct i2c_adapter *i2c)
 {
 	dprintk("%s\n", __FUNCTION__);
-	sp887x_writereg(fe, 0xf08, 0x000);
-	sp887x_writereg(fe, 0xf09, 0x000);
+	sp887x_writereg(i2c, 0xf08, 0x000);
+	sp887x_writereg(i2c, 0xf09, 0x000);
 
 	/* microcontroller STOP */
-	sp887x_writereg(fe, 0xf00, 0x000);
+	sp887x_writereg(i2c, 0xf00, 0x000);
 }
 
 
 static
-void sp887x_microcontroller_start (struct dvb_frontend *fe)
+void sp887x_microcontroller_start (struct i2c_adapter *i2c)
 {
 	dprintk("%s\n", __FUNCTION__);
-	sp887x_writereg(fe, 0xf08, 0x000);
-	sp887x_writereg(fe, 0xf09, 0x000);
+	sp887x_writereg(i2c, 0xf08, 0x000);
+	sp887x_writereg(i2c, 0xf09, 0x000);
 
 	/* microcontroller START */
-	sp887x_writereg(fe, 0xf00, 0x001);
+	sp887x_writereg(i2c, 0xf00, 0x001);
 }
 
 
 static
-void sp887x_setup_agc (struct dvb_frontend *fe)
+void sp887x_setup_agc (struct i2c_adapter *i2c)
 {
 	/* setup AGC parameters */
 	dprintk("%s\n", __FUNCTION__);
-	sp887x_writereg(fe, 0x33c, 0x054);
-	sp887x_writereg(fe, 0x33b, 0x04c);
-	sp887x_writereg(fe, 0x328, 0x000);
-	sp887x_writereg(fe, 0x327, 0x005);
-	sp887x_writereg(fe, 0x326, 0x001);
-	sp887x_writereg(fe, 0x325, 0x001);
-	sp887x_writereg(fe, 0x324, 0x001);
-	sp887x_writereg(fe, 0x318, 0x050);
-	sp887x_writereg(fe, 0x317, 0x3fe);
-	sp887x_writereg(fe, 0x316, 0x001);
-	sp887x_writereg(fe, 0x313, 0x005);
-	sp887x_writereg(fe, 0x312, 0x002);
-	sp887x_writereg(fe, 0x306, 0x000);
-	sp887x_writereg(fe, 0x303, 0x000);
+	sp887x_writereg(i2c, 0x33c, 0x054);
+	sp887x_writereg(i2c, 0x33b, 0x04c);
+	sp887x_writereg(i2c, 0x328, 0x000);
+	sp887x_writereg(i2c, 0x327, 0x005);
+	sp887x_writereg(i2c, 0x326, 0x001);
+	sp887x_writereg(i2c, 0x325, 0x001);
+	sp887x_writereg(i2c, 0x324, 0x001);
+	sp887x_writereg(i2c, 0x318, 0x050);
+	sp887x_writereg(i2c, 0x317, 0x3fe);
+	sp887x_writereg(i2c, 0x316, 0x001);
+	sp887x_writereg(i2c, 0x313, 0x005);
+	sp887x_writereg(i2c, 0x312, 0x002);
+	sp887x_writereg(i2c, 0x306, 0x000);
+	sp887x_writereg(i2c, 0x303, 0x000);
 }
 
-
-#define BLOCKSIZE 30
-
-/**
- *  load firmware and setup MPEG interface...
- */
-static
-int sp887x_initial_setup (struct dvb_frontend *fe)
-{
-	u8 buf [BLOCKSIZE+2];
-	unsigned char *firmware = NULL;
-	int i;
-	int fd;
-	int filesize;
-	int fw_size;
-	mm_segment_t fs;
-
-	dprintk("%s\n", __FUNCTION__);
-
-	/* soft reset */
-	sp887x_writereg(fe, 0xf1a, 0x000);
-
-	sp887x_microcontroller_stop (fe);
-
-	fs = get_fs();
-
-	// Load the firmware
-	set_fs(get_ds());
-	fd = open(sp887x_firmware, 0, 0);
-	if (fd < 0) {
-		printk(KERN_WARNING "%s: Unable to open firmware %s\n", __FUNCTION__,
-		       sp887x_firmware);
-		return -EIO;
-	}
-	filesize = lseek(fd, 0L, 2);
-	if (filesize <= 0) {
-		printk(KERN_WARNING "%s: Firmware %s is empty\n", __FUNCTION__,
-		       sp887x_firmware);
-		sys_close(fd);
-		return -EIO;
-	}
-
-	fw_size = 0x4000;
-
-	// allocate buffer for it
-	firmware = vmalloc(fw_size);
-	if (firmware == NULL) {
-		printk(KERN_WARNING "%s: Out of memory loading firmware\n",
-		       __FUNCTION__);
-		sys_close(fd);
-		return -EIO;
-	}
-
-	// read it!
-	// read the first 16384 bytes from the file
-	// ignore the first 10 bytes
-	lseek(fd, 10, 0);
-	if (read(fd, firmware, fw_size) != fw_size) {
-		printk(KERN_WARNING "%s: Failed to read firmware\n", __FUNCTION__);
-		vfree(firmware);
-		sys_close(fd);
-		return -EIO;
-	}
-	sys_close(fd);
-	set_fs(fs);
-
-	printk ("%s: firmware upload... ", __FUNCTION__);
-
-	/* setup write pointer to -1 (end of memory) */
-	/* bit 0x8000 in address is set to enable 13bit mode */
-	sp887x_writereg(fe, 0x8f08, 0x1fff);
-
-	/* dummy write (wrap around to start of memory) */
-	sp887x_writereg(fe, 0x8f0a, 0x0000);
-
-	for (i=0; i<fw_size; i+=BLOCKSIZE) {
-		int c = BLOCKSIZE;
-		int err;
-
-		if (i+c > fw_size)
-			c = fw_size - i;
-
-		/* bit 0x8000 in address is set to enable 13bit mode */
-		/* bit 0x4000 enables multibyte read/write transfers */
-		/* write register is 0xf0a */
-		buf[0] = 0xcf;
-		buf[1] = 0x0a;
-
-		memcpy(&buf[2], firmware + i, c);
-
-		if ((err = i2c_writebytes (fe, 0x70, buf, c+2)) < 0) {
-			printk ("failed.\n");
-			printk ("%s: i2c error (err == %i)\n", __FUNCTION__, err);
-			vfree(firmware);
-			return err;
-		}
-	}
-
-	vfree(firmware);
-
-	/* don't write RS bytes between packets */
-	sp887x_writereg(fe, 0xc13, 0x001);
-
-	/* suppress clock if (!data_valid) */
-	sp887x_writereg(fe, 0xc14, 0x000);
-
-	/* setup MPEG interface... */
-	sp887x_writereg(fe, 0xc1a, 0x872);
-	sp887x_writereg(fe, 0xc1b, 0x001);
-	sp887x_writereg(fe, 0xc1c, 0x000); /* parallel mode (serial mode == 1) */
-	sp887x_writereg(fe, 0xc1a, 0x871);
-
-	/* ADC mode, 2 for MT8872, 3 for SP8870/SP8871 */
-	sp887x_writereg(fe, 0x301, 0x002);
-
-	sp887x_setup_agc(fe);
-
-	/* bit 0x010: enable data valid signal */
-	sp887x_writereg(fe, 0xd00, 0x010);
-	sp887x_writereg(fe, 0x0d1, 0x000);
-
-	printk ("done.\n");
-	return 0;
-};
-
-
 /**
  *  returns the actual tuned center frequency which can be used
  *  to initialise the AFC registers
  */
 static
-int tsa5060_setup_pll (struct dvb_frontend *fe, int freq)
+int tsa5060_setup_pll (struct i2c_adapter *i2c, int freq)
 {
 	u8 cfg, cpump, band_select;
 	u8 buf [4];
@@ -334,9 +204,9 @@
 	buf [3] = cpump | band_select;
 
 	/* open i2c gate for PLL message transmission... */
-	sp887x_writereg(fe, 0x206, 0x001);
-	i2c_writebytes(fe, 0x60, buf, 4);
-	sp887x_writereg(fe, 0x206, 0x000);
+	sp887x_writereg(i2c, 0x206, 0x001);
+	i2c_writebytes(i2c, 0x60, buf, 4);
+	sp887x_writereg(i2c, 0x206, 0x000);
 
 	return (div * 166666 - 36000000);
 }
@@ -441,7 +311,7 @@
 
 
 static
-void sp887x_correct_offsets (struct dvb_frontend *fe,
+void sp887x_correct_offsets (struct i2c_adapter *i2c,
 			     struct dvb_frontend_parameters *p,
 			     int actual_freq)
 {
@@ -464,17 +334,17 @@
 		frequency_shift = -frequency_shift;
 
 	/* sample rate correction */
-	sp887x_writereg(fe, 0x319, srate_correction[bw_index] >> 12);
-	sp887x_writereg(fe, 0x31a, srate_correction[bw_index] & 0xfff);
+	sp887x_writereg(i2c, 0x319, srate_correction[bw_index] >> 12);
+	sp887x_writereg(i2c, 0x31a, srate_correction[bw_index] & 0xfff);
 
 	/* carrier offset correction */
-	sp887x_writereg(fe, 0x309, frequency_shift >> 12);
-	sp887x_writereg(fe, 0x30a, frequency_shift & 0xfff);
+	sp887x_writereg(i2c, 0x309, frequency_shift >> 12);
+	sp887x_writereg(i2c, 0x30a, frequency_shift & 0xfff);
 }
 
 
 static
-int sp887x_setup_frontend_parameters (struct dvb_frontend *fe,
+int sp887x_setup_frontend_parameters (struct i2c_adapter *i2c,
 				      struct dvb_frontend_parameters *p)
 {
 	int actual_freq, err;
@@ -488,14 +358,14 @@
 	if ((err = configure_reg0xc05(p, &reg0xc05)))
 		return err;
 
-	sp887x_microcontroller_stop(fe);
+	sp887x_microcontroller_stop(i2c);
 
-	actual_freq = tsa5060_setup_pll(fe, p->frequency);
+	actual_freq = tsa5060_setup_pll(i2c, p->frequency);
 
 	/* read status reg in order to clear pending irqs */
-	sp887x_readreg(fe, 0x200);
+	sp887x_readreg(i2c, 0x200);
 
-	sp887x_correct_offsets(fe, p, actual_freq);
+	sp887x_correct_offsets(i2c, p, actual_freq);
 
 	/* filter for 6/7/8 Mhz channel */
 	if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
@@ -505,15 +375,15 @@
 	else
 		val = 0;
 
-	sp887x_writereg(fe, 0x311, val);
+	sp887x_writereg(i2c, 0x311, val);
 
 	/* scan order: 2k first = 0, 8k first = 1 */
 	if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K)
-		sp887x_writereg(fe, 0x338, 0x000);
+		sp887x_writereg(i2c, 0x338, 0x000);
 	else
-		sp887x_writereg(fe, 0x338, 0x001);
+		sp887x_writereg(i2c, 0x338, 0x001);
 
-	sp887x_writereg(fe, 0xc05, reg0xc05);
+	sp887x_writereg(i2c, 0xc05, reg0xc05);
 
 	if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
 		val = 2 << 3;
@@ -525,17 +395,48 @@
 	/* enable OFDM and SAW bits as lock indicators in sync register 0xf17,
 	 * optimize algorithm for given bandwidth...
 	 */
-	sp887x_writereg(fe, 0xf14, 0x160 | val);
-	sp887x_writereg(fe, 0xf15, 0x000);
+	sp887x_writereg(i2c, 0xf14, 0x160 | val);
+	sp887x_writereg(i2c, 0xf15, 0x000);
 
-	sp887x_microcontroller_start(fe);
+	sp887x_microcontroller_start(i2c);
 	return 0;
 }
 
+static int sp887x_init (struct i2c_adapter *i2c)
+{
+	/* don't write RS bytes between packets */
+	sp887x_writereg(i2c, 0xc13, 0x001);
+
+	/* suppress clock if (!data_valid) */
+	sp887x_writereg(i2c, 0xc14, 0x000);
+
+	/* setup MPEG interface... */
+	sp887x_writereg(i2c, 0xc1a, 0x872);
+	sp887x_writereg(i2c, 0xc1b, 0x001);
+	sp887x_writereg(i2c, 0xc1c, 0x000); /* parallel mode (serial mode == 1) */
+	sp887x_writereg(i2c, 0xc1a, 0x871);
+
+	/* ADC mode, 2 for MT8872, 3 for SP8870/SP8871 */
+	sp887x_writereg(i2c, 0x301, 0x002);
+
+	sp887x_setup_agc(i2c);
+
+	/* bit 0x010: enable data valid signal */
+	sp887x_writereg(i2c, 0xd00, 0x010);
+	sp887x_writereg(i2c, 0x0d1, 0x000);
+
+	/* enable TS output and interface pins */
+	sp887x_writereg(i2c, 0xc18, 0x00d);
+
+	return 0;
+};
 
 static
 int sp887x_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
 {
+	struct sp887x_state *state = (struct sp887x_state *) fe->data;
+	struct i2c_adapter *i2c = state->i2c;
+
         switch (cmd) {
         case FE_GET_INFO:
 		memcpy (arg, &sp887x_info, sizeof(struct dvb_frontend_info));
@@ -543,9 +444,9 @@
 
         case FE_READ_STATUS:
 	{
-		u16 snr12 = sp887x_readreg(fe, 0xf16);
-		u16 sync0x200 = sp887x_readreg(fe, 0x200);
-		u16 sync0xf17 = sp887x_readreg(fe, 0xf17);
+		u16 snr12 = sp887x_readreg(i2c, 0xf16);
+		u16 sync0x200 = sp887x_readreg(i2c, 0x200);
+		u16 sync0xf17 = sp887x_readreg(i2c, 0xf17);
 		fe_status_t *status = arg;
 
 		*status = 0;
@@ -579,10 +480,10 @@
         case FE_READ_BER:
 	{
 		u32* ber = arg;
-		*ber = (sp887x_readreg(fe, 0xc08) & 0x3f) |
-		       (sp887x_readreg(fe, 0xc07) << 6);
-		sp887x_writereg(fe, 0xc08, 0x000);
-		sp887x_writereg(fe, 0xc07, 0x000);
+		*ber = (sp887x_readreg(i2c, 0xc08) & 0x3f) |
+		       (sp887x_readreg(i2c, 0xc07) << 6);
+		sp887x_writereg(i2c, 0xc08, 0x000);
+		sp887x_writereg(i2c, 0xc07, 0x000);
 		if (*ber >= 0x3fff0)
 			*ber = ~0;
 		break;
@@ -591,7 +492,7 @@
 
         case FE_READ_SIGNAL_STRENGTH:		// FIXME: correct registers ?
 	{
-		u16 snr12 = sp887x_readreg(fe, 0xf16);
+		u16 snr12 = sp887x_readreg(i2c, 0xf16);
 		u32 signal = 3 * (snr12 << 4);
 		*((u16*) arg) = (signal < 0xffff) ? signal : 0xffff;
 		break;
@@ -599,7 +500,7 @@
 
         case FE_READ_SNR:
 	{
-		u16 snr12 = sp887x_readreg(fe, 0xf16);
+		u16 snr12 = sp887x_readreg(i2c, 0xf16);
 		*(u16*) arg = (snr12 << 4) | (snr12 >> 8);
 		break;
 	}
@@ -607,30 +508,30 @@
 	case FE_READ_UNCORRECTED_BLOCKS:
 	{
 		u32 *ublocks = (u32 *) arg;
-		*ublocks = sp887x_readreg(fe, 0xc0c);
+		*ublocks = sp887x_readreg(i2c, 0xc0c);
 		if (*ublocks == 0xfff)
 			*ublocks = ~0;
 		break;
 	}
 
         case FE_SET_FRONTEND:
-		return sp887x_setup_frontend_parameters(fe, arg);
+		return sp887x_setup_frontend_parameters(i2c, arg);
 
 	case FE_GET_FRONTEND:  // FIXME: read known values back from Hardware...
-		break;
+		return -EOPNOTSUPP;
 
         case FE_SLEEP:
 		/* tristate TS output and disable interface pins */
-		sp887x_writereg(fe, 0xc18, 0x000);
+		sp887x_writereg(i2c, 0xc18, 0x000);
 		break;
 
         case FE_INIT:
-		if (fe->data == NULL) {	  /* first time initialisation... */
-			fe->data = (void*) ~0;
-			sp887x_initial_setup (fe);
-		}
-		/* enable TS output and interface pins */
-		sp887x_writereg(fe, 0xc18, 0x00d);
+		if (state->initialized)
+			return 0;
+		
+		sp887x_init(i2c);
+
+		state->initialized = 1;
 		break;
 
 	case FE_GET_TUNE_SETTINGS:
@@ -649,51 +550,193 @@
         return 0;
 }
 
+#define BLOCKSIZE 30
+int sp887x_load_firmware(struct i2c_adapter *i2c,
+			 struct firmware *fw)
+{
+	u8 buf [BLOCKSIZE+2];
+	int i;
 
+	dprintk("%s\n", __FUNCTION__);
 
-static
-int sp887x_attach (struct dvb_i2c_bus *i2c, void **data)
+	/* soft reset */
+	sp887x_writereg(i2c, 0xf1a, 0x000);
+
+	sp887x_microcontroller_stop (i2c);
+
+	if (fw->size != 0x4000) {
+		printk(KERN_ERR "sp887x: Invalid firmware size.\n");
+		return -EINVAL;
+	}
+
+	printk ("%s: firmware upload... ", __FUNCTION__);
+
+	/* setup write pointer to -1 (end of memory) */
+	/* bit 0x8000 in address is set to enable 13bit mode */
+	sp887x_writereg(i2c, 0x8f08, 0x1fff);
+
+	/* dummy write (wrap around to start of memory) */
+	sp887x_writereg(i2c, 0x8f0a, 0x0000);
+
+	for (i=10; i<fw->size; i+=BLOCKSIZE) {
+		int c = BLOCKSIZE;
+		int err;
+
+		if (i+c > fw->size)
+			c = fw->size - i;
+
+		/* bit 0x8000 in address is set to enable 13bit mode */
+		/* bit 0x4000 enables multibyte read/write transfers */
+		/* write register is 0xf0a */
+		buf[0] = 0xcf;
+		buf[1] = 0x0a;
+
+		memcpy(&buf[2], fw->data + i, c);
+
+		if ((err = i2c_writebytes (i2c, 0x70, buf, c+2)) < 0) {
+			printk ("failed.\n");
+			printk ("%s: i2c error (err == %i)\n", __FUNCTION__, err);
+			release_firmware(fw);
+			return err;
+		}
+	}
+
+	release_firmware(fw);
+	return 0;
+}
+
+static struct i2c_client client_template;
+
+static int attach_adapter (struct i2c_adapter *adapter)
 {
+	struct sp887x_state *state;
+	struct i2c_client *client;
+	const struct firmware *fw;
+	int ret;
+
 	struct i2c_msg msg = {.addr = 0x70, .flags = 0, .buf = NULL, .len = 0 };
 
 	dprintk ("%s\n", __FUNCTION__);
 
-	if (i2c->xfer (i2c, &msg, 1) != 1)
+	if (i2c_transfer(adapter, &msg, 1) != 1)
                 return -ENODEV;
 
-	return dvb_register_frontend (sp887x_ioctl, i2c, NULL, &sp887x_info);
-}
+	if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)))
+		return -ENOMEM;
+
+	if (NULL == (state = kmalloc(sizeof(struct sp887x_state), GFP_KERNEL))) {
+		kfree(client);
+		return -ENOMEM;
+	}
 
+	state->i2c = adapter;
+	state->dvb = NULL;
+	state->initialized = 0;
 
-static
-void sp887x_detach (struct dvb_i2c_bus *i2c, void *data)
+	memcpy(client, &client_template, sizeof(struct i2c_client));
+	client->adapter = adapter;
+	client->addr = 0x70;
+	i2c_set_clientdata(client, state);
+
+	ret = i2c_attach_client(client);
+	if (ret) {
+		kfree(state);
+		kfree(client);
+		return ret;
+	}
+
+	BUG_ON(!state->dvb);
+
+	printk(KERN_INFO "sp887x: waiting for firmware..\n");
+	ret = request_firmware(&fw, "dvb-fe-sp887x.fw", &client->dev);
+	if (ret) {
+		printk(KERN_ERR "sp887x: unable to load firmware.\n");
+		goto out;
+	}
+
+	ret = dvb_register_frontend_new(sp887x_ioctl, state->dvb,
+					state, &sp887x_info);
+	if (ret) {
+		printk(KERN_ERR "sp887x: unable to register frontend.\n");
+		goto out;
+	}
+
+	return 0;
+out:
+	i2c_detach_client(client);
+	kfree(client);
+	kfree(state);
+	return ret;
+}
+
+static int detach_client (struct i2c_client *client)
 {
+	struct sp887x_state *state = i2c_get_clientdata(client);
+
 	dprintk ("%s\n", __FUNCTION__);
-	dvb_unregister_frontend (sp887x_ioctl, i2c);
-}
 
+	
+	dvb_unregister_frontend_new (sp887x_ioctl, state->dvb);
+	i2c_detach_client(client);
+	BUG_ON(state->dvb);
+	kfree(client);
+	kfree(state);
+	return 0;
+}
 
-static
-int __init init_sp887x (void)
+static int command (struct i2c_client *client, unsigned int cmd, void *arg)
 {
+	struct sp887x_state *state = (struct sp887x_state*)i2c_get_clientdata(client);
+
 	dprintk ("%s\n", __FUNCTION__);
-	return dvb_register_i2c_device (NULL, sp887x_attach, sp887x_detach);
+
+	switch (cmd) {
+	case FE_REGISTER:
+		state->dvb = (struct dvb_adapter*)arg;
+		break;
+
+	case FE_UNREGISTER:
+		state->dvb = NULL;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
 }
 
+static struct i2c_driver driver = {
+	.owner		= THIS_MODULE,
+	.name		= "sp887x",
+	.id		= I2C_DRIVERID_SP887X,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter = attach_adapter,
+	.detach_client	= detach_client,
+	.command	= command,
+};
 
-static
-void __exit exit_sp887x (void)
+static struct i2c_client client_template = {
+	I2C_DEVNAME("sp887x"),
+	.flags		= I2C_CLIENT_ALLOW_USE,
+	.driver		= &driver,
+};
+
+static int __init init_sp887x (void)
 {
 	dprintk ("%s\n", __FUNCTION__);
-	dvb_unregister_i2c_device (sp887x_attach);
+	return i2c_add_driver (&driver);
 }
 
+static void __exit exit_sp887x (void)
+{
+	dprintk ("%s\n", __FUNCTION__);
+	if (i2c_del_driver (&driver))
+		printk(KERN_ERR "sp887x: driver deregistration failed.\n");
+}
 
 module_init(init_sp887x);
 module_exit(exit_sp887x);
 
-
 MODULE_DESCRIPTION("sp887x DVB-T demodulator driver");
 MODULE_LICENSE("GPL");
 
-

Home | Main Index | Thread Index