From 9507901ef329b2dd3417372c7c9b2abcfd5c1885 Mon Sep 17 00:00:00 2001
From: Mauro Carvalho Chehab <mchehab@infradead.org>
Date: Tue, 22 Apr 2008 14:45:15 -0300
Subject: V4L/DVB (7257): cx88: Add xc2028/3028 boards

This patch ports a patch from Markus Rechberger to work with tuner-xc2028.
It adds entries for several cx88 boards with xc2038/3028 tuners.

Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
---
 drivers/media/video/cx88/cx88-cards.c | 188 +++++++++++++++++++++++++++++++++-
 drivers/media/video/cx88/cx88-dvb.c   |  44 +++++++-
 drivers/media/video/cx88/cx88.h       |   4 +
 3 files changed, 234 insertions(+), 2 deletions(-)

(limited to 'drivers/media')

diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 3e07fbe4c84..d07286fa21f 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -1426,6 +1426,124 @@ static const struct cx88_board cx88_boards[] = {
 		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
+	[CX88_BOARD_PINNACLE_HYBRID_PCTV] = {
+	       .name           = "Pinnacle Hybrid PCTV",
+	       .tuner_type     = TUNER_XC2028,
+	       .tuner_addr     = 0x61,
+	       .input          = { {
+		       .type   = CX88_VMUX_TELEVISION,
+		       .vmux   = 0,
+	       }, {
+		       .type   = CX88_VMUX_COMPOSITE1,
+		       .vmux   = 1,
+	       }, {
+		       .type   = CX88_VMUX_SVIDEO,
+		       .vmux   = 2,
+	       } },
+	       .radio = {
+		       .type   = CX88_RADIO,
+		       .gpio0  = 0x004ff,
+		       .gpio1  = 0x010ff,
+		       .gpio2  = 0x0ff,
+	       },
+       },
+       [CX88_BOARD_WINFAST_TV2000_XP_GLOBAL] = {
+	       .name           = "Winfast TV2000 XP Global",
+	       .tuner_type     = TUNER_XC2028,
+	       .tuner_addr     = 0x61,
+	       .input          = { {
+		       .type   = CX88_VMUX_TELEVISION,
+		       .vmux   = 0,
+		       .gpio0  = 0x0400, /* pin 2:mute = 0 (off?) */
+		       .gpio1  = 0x0000,
+		       .gpio2  = 0x0800, /* pin 19:audio = 0 (tv) */
+
+	       }, {
+		       .type   = CX88_VMUX_COMPOSITE1,
+		       .vmux   = 1,
+		       .gpio0  = 0x0400, /* probably?  or 0x0404 to turn mute on */
+		       .gpio1  = 0x0000,
+		       .gpio2  = 0x0808, /* pin 19:audio = 1 (line) */
+
+	       }, {
+		       .type   = CX88_VMUX_SVIDEO,
+		       .vmux   = 2,
+	       } },
+	       .radio = {
+		       .type   = CX88_RADIO,
+		       .gpio0  = 0x004ff,
+		       .gpio1  = 0x010ff,
+		       .gpio2  = 0x0ff,
+	       },
+       },
+       [CX88_BOARD_POWERCOLOR_REAL_ANGEL] = {
+	       .name           = "PowerColor Real Angel 330",
+	       .tuner_type     = TUNER_XC2028,
+	       .tuner_addr     = 0x61,
+	       .input          = { {
+		       .type   = CX88_VMUX_TELEVISION,
+		       .vmux   = 0,
+		       .gpio0 = 0x0400, /* pin 2:mute = 0 (off?) */
+		       .gpio1 = 0x0000,
+		       .gpio2 = 0x0800, /* pin 19:audio = 0 (tv) */
+	       }, {
+		       .type   = CX88_VMUX_COMPOSITE1,
+		       .vmux   = 1,
+		       .gpio0 = 0x0400, /* probably?  or 0x0404 to turn mute on */
+		       .gpio1 = 0x0000,
+		       .gpio2 = 0x0808, /* pin 19:audio = 1 (line) */
+	       }, {
+		       .type   = CX88_VMUX_SVIDEO,
+		       .vmux   = 2,
+		       .gpio0  = 0x000ff,
+		       .gpio1  = 0x0f37d,
+		       .gpio2  = 0x00019,
+		       .gpio3  = 0x00000,
+	       } },
+	       .radio = {
+		       .type   = CX88_RADIO,
+		       .gpio0  = 0x000ff,
+		       .gpio1  = 0x0f35d,
+		       .gpio2  = 0x00019,
+		       .gpio3  = 0x00000,
+	       },
+       },
+       [CX88_BOARD_GENIATECH_X8000_MT] = {
+		/* Also PowerColor Real Angel 330 and Geniatech X800 OEM */
+	       .name           = "Geniatech X8000-MT DVBT",
+	       .tuner_type     = TUNER_XC2028,
+	       .tuner_addr     = 0x61,
+	       .input          = { {
+		       .type   = CX88_VMUX_TELEVISION,
+		       .vmux   = 0,
+		       .gpio0  = 0x00000000,
+		       .gpio1  = 0x00e3e341,
+		       .gpio2  = 0x00000000,
+		       .gpio3  = 0x00000000,
+	       }, {
+		       .type   = CX88_VMUX_COMPOSITE1,
+		       .vmux   = 1,
+		       .gpio0  = 0x00000000,
+		       .gpio1  = 0x00e3e361,
+		       .gpio2  = 0x00000000,
+		       .gpio3  = 0x00000000,
+	       }, {
+		       .type   = CX88_VMUX_SVIDEO,
+		       .vmux   = 2,
+		       .gpio0  = 0x00000000,
+		       .gpio1  = 0x00e3e361,
+		       .gpio2  = 0x00000000,
+		       .gpio3  = 0x00000000,
+	       } },
+	       .radio = {
+		       .type   = CX88_RADIO,
+		       .gpio0  = 0x00000000,
+		       .gpio1  = 0x00e3e341,
+		       .gpio2  = 0x00000000,
+		       .gpio3  = 0x00000000,
+	       },
+	       .mpeg           = CX88_MPEG_DVB,
+       }
 };
 
 /* ------------------------------------------------------------------ */
@@ -1743,7 +1861,23 @@ static const struct cx88_subid cx88_subids[] = {
 		.subvendor = 0x18ac,
 		.subdevice = 0xd530,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO,
-	},
+	}, {
+		.subvendor = 0x12ab,
+		.subdevice = 0x1788,
+		.card      = CX88_BOARD_PINNACLE_HYBRID_PCTV,
+	}, {
+		.subvendor = 0x14f1,
+		.subdevice = 0xea3d,
+		.card      = CX88_BOARD_POWERCOLOR_REAL_ANGEL,
+	}, {
+		.subvendor = 0x107d,
+		.subdevice = 0x6f18,
+		.card      = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL,
+	}, {
+		.subvendor = 0x14f1,
+		.subdevice = 0x8852,
+		.card      = CX88_BOARD_GENIATECH_X8000_MT,
+	}
 };
 
 /* ----------------------------------------------------------------------- */
@@ -1875,6 +2009,50 @@ static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data)
 		CX88_RADIO : 0;
 }
 
+/* ----------------------------------------------------------------------- */
+/* some Geniatech specific stuff                                           */
+
+static int cx88_xc3028_geniatech_tuner_callback(void *priv, int command, int mode)
+{
+	struct i2c_algo_bit_data *i2c_algo = priv;
+	struct cx88_core *core = i2c_algo->data;
+
+	switch (command) {
+	case XC2028_TUNER_RESET:
+		switch (INPUT(core->input).type) {
+		case CX88_RADIO:
+			cx_write(MO_GP1_IO, 0x101010);
+			mdelay(50);
+			cx_write(MO_GP1_IO, 0x101000);
+			mdelay(50);
+			cx_write(MO_GP1_IO, 0x101010);
+			mdelay(50);
+			return 0;
+		case CX88_VMUX_DVB:
+			cx_write(MO_GP1_IO, 0x030302);
+			mdelay(50);
+			cx_write(MO_GP1_IO, 0x101010);
+			mdelay(50);
+			cx_write(MO_GP1_IO, 0x101000);
+			mdelay(50);
+			cx_write(MO_GP1_IO, 0x101010);
+			mdelay(50);
+			return 0;
+		default:
+			cx_write(MO_GP1_IO, 0x030301);
+			mdelay(50);
+			cx_write(MO_GP1_IO, 0x101010);
+			mdelay(50);
+			cx_write(MO_GP1_IO, 0x101000);
+			mdelay(50);
+			cx_write(MO_GP1_IO, 0x101010);
+			mdelay(50);
+			return 0;
+		 }
+	}
+	return -EINVAL;
+}
+
 /* ----------------------------------------------------------------------- */
 /* some DViCO specific stuff                                               */
 
@@ -1914,6 +2092,14 @@ static int cx88_xc2028_tuner_callback(void *priv, int command, int arg)
 	struct i2c_algo_bit_data *i2c_algo = priv;
 	struct cx88_core *core = i2c_algo->data;
 
+	/* Board-specific callbacks */
+	switch (core->boardnr) {
+	case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
+	case CX88_BOARD_POWERCOLOR_REAL_ANGEL:
+	case CX88_BOARD_GENIATECH_X8000_MT:
+		return cx88_xc3028_geniatech_tuner_callback(priv, command, arg);
+	}
+
 	switch (command) {
 	case XC2028_TUNER_RESET:
 	{
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 735376060df..c786d951a04 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -434,8 +434,16 @@ static struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = {
 	.tuner_callback	= cx88_tuner_callback,
 };
 
+static struct zl10353_config cx88_geniatech_x8000_mt = {
+       .demod_address = (0x1e >> 1),
+       .no_tuner = 1,
+};
+
+
 static int dvb_register(struct cx8802_dev *dev)
 {
+	int attach_xc3028 = 0;
+
 	/* init struct videobuf_dvb */
 	dev->dvb.name = dev->core->name;
 	dev->ts_gen_cntrl = 0x0c;
@@ -727,16 +735,50 @@ static int dvb_register(struct cx8802_dev *dev)
 				fe->ops.tuner_ops.set_config(fe, &ctl);
 		}
 		break;
+	 case CX88_BOARD_PINNACLE_HYBRID_PCTV:
+		dev->dvb.frontend = dvb_attach(zl10353_attach,
+					       &cx88_geniatech_x8000_mt,
+					       &dev->core->i2c_adap);
+		attach_xc3028 = 1;
+		break;
+	 case CX88_BOARD_GENIATECH_X8000_MT:
+	       dev->ts_gen_cntrl = 0x00;
+
+		dev->dvb.frontend = dvb_attach(zl10353_attach,
+					       &cx88_geniatech_x8000_mt,
+					       &dev->core->i2c_adap);
+		attach_xc3028 = 1;
+		break;
 	default:
 		printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
 		       dev->core->name);
 		break;
 	}
 	if (NULL == dev->dvb.frontend) {
-		printk(KERN_ERR "%s/2: frontend initialization failed\n", dev->core->name);
+		printk(KERN_ERR
+		       "%s/2: frontend initialization failed\n",
+		       dev->core->name);
 		return -1;
 	}
 
+	if (attach_xc3028) {
+		struct dvb_frontend *fe;
+		struct xc2028_config cfg = {
+			.i2c_adap  = &dev->core->i2c_adap,
+			.i2c_addr  = 0x61,
+			.video_dev = dev->core,
+		};
+		fe = dvb_attach(xc2028_attach, dev->dvb.frontend, &cfg);
+		if (!fe) {
+			printk(KERN_ERR "%s/2: xc3028 attach failed\n",
+			       dev->core->name);
+			dvb_frontend_detach(dev->dvb.frontend);
+			dvb_unregister_frontend(dev->dvb.frontend);
+			dev->dvb.frontend = NULL;
+			return -1;
+		}
+	}
+
 	/* Ensure all frontends negotiate bus access */
 	dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
 
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 8121bd07a88..5145bf2f555 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -212,6 +212,10 @@ extern struct sram_channel cx88_sram_channels[];
 #define CX88_BOARD_ADSTECH_PTV_390         57
 #define CX88_BOARD_PINNACLE_PCTV_HD_800i   58
 #define CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO 59
+#define CX88_BOARD_PINNACLE_HYBRID_PCTV    60
+#define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL 61
+#define CX88_BOARD_POWERCOLOR_REAL_ANGEL   62
+#define CX88_BOARD_GENIATECH_X8000_MT      63
 
 enum cx88_itype {
 	CX88_VMUX_COMPOSITE1 = 1,
-- 
cgit v1.2.3