diff mbox

Add support for GeoVision GV-800(S)

Message ID f917d4dd0902281213n592f8166m97f8e205bc255b93@mail.gmail.com (mailing list archive)
State Superseded
Headers show

Commit Message

Bruno Christo Feb. 28, 2009, 8:13 p.m. UTC
I forgot to run make checkpatch before submitting the previous patch,
here is the fixed patch:

diff -r c770b20d15c6 linux/Documentation/video4linux/CARDLIST.bttv
--- a/linux/Documentation/video4linux/CARDLIST.bttv	Fri Feb 27
21:29:59 2009 -0300
+++ b/linux/Documentation/video4linux/CARDLIST.bttv	Sat Feb 28
17:09:23 2009 -0300
@@ -155,3 +155,5 @@
 154 -> PHYTEC VD-012-X1 (bt878)
 155 -> PHYTEC VD-012-X2 (bt878)
 156 -> IVCE-8784
[0000:f050,0001:f050,0002:f050,0003:f050]
+157 -> Geovision GV-800(S) (master)                        [800a:763d]
+158 -> Geovision GV-800(S) (slave)
[800b:763d,800c:763d,800d:763d]
diff -r c770b20d15c6 linux/drivers/media/video/bt8xx/bttv-cards.c
--- a/linux/drivers/media/video/bt8xx/bttv-cards.c	Fri Feb 27 21:29:59
2009 -0300
+++ b/linux/drivers/media/video/bt8xx/bttv-cards.c	Sat Feb 28 17:09:23
2009 -0300
@@ -75,6 +75,9 @@
 static void geovision_muxsel(struct bttv *btv, unsigned int input);

 static void phytec_muxsel(struct bttv *btv, unsigned int input);
+
+static void gv800s_muxsel(struct bttv *btv, unsigned int input);
+static void gv800s_init(struct bttv *btv);

 static int terratec_active_radio_upgrade(struct bttv *btv);
 static int tea5757_read(struct bttv *btv);
@@ -312,6 +315,10 @@
 	{ 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2,	"DViCO FusionHDTV 2" },
 	{ 0x763c008a, BTTV_BOARD_GEOVISION_GV600,	"GeoVision GV-600" },
 	{ 0x18011000, BTTV_BOARD_ENLTV_FM_2,	"Encore ENL TV-FM-2" },
+	{ 0x763d800a, BTTV_BOARD_GEOVISION_GV800S, "GeoVision GV-800(S) (master)" },
+	{ 0x763d800b, BTTV_BOARD_GEOVISION_GV800S_SL,	"GeoVision GV-800(S) (slave)" },
+	{ 0x763d800c, BTTV_BOARD_GEOVISION_GV800S_SL,	"GeoVision GV-800(S) (slave)" },
+	{ 0x763d800d, BTTV_BOARD_GEOVISION_GV800S_SL,	"GeoVision GV-800(S) (slave)" },
 	{ 0, -1, NULL }
 };

@@ -2847,7 +2854,60 @@
 		.pll            = PLL_28,
 		.tuner_type     = TUNER_ABSENT,
 		.tuner_addr	= ADDR_UNSET,
-	}
+	},
+		[BTTV_BOARD_GEOVISION_GV800S] = {
+		/* Bruno Christo <bchristo@inf.ufsm.br>
+		 *
+		 * GeoVision GV-800(S) has 4 Conexant Fusion 878A:
+		 * 	1 audio input  per BT878A = 4 audio inputs
+		 * 	4 video inputs per BT878A = 16 video inputs
+		 * This is the first BT878A chip of the GV-800(S). It's the
+		 * "master" chip and it controls the video inputs through an
+		 * analog multiplexer (a CD22M3494) via some GPIO pins. The
+		 * slaves should use card type 0x9e (following this one).
+		 * There is a EEPROM on the card which is currently not handled.
+		 * The audio input is not working yet.
+		 */
+		.name           = "Geovision GV-800(S) (master)",
+		.video_inputs   = 4,
+		/* .audio_inputs= 1, */
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.svhs           = NO_SVHS,
+		.gpiomask	= 0xf107f,
+		.no_gpioirq     = 1,
+		.muxsel		= MUXSEL(2, 2, 2, 2),
+		.pll		= PLL_28,
+		.no_msp34xx	= 1,
+		.no_tda7432	= 1,
+		.no_tda9875	= 1,
+		.muxsel_hook    = gv800s_muxsel,
+	},
+		[BTTV_BOARD_GEOVISION_GV800S_SL] = {
+		/* Bruno Christo <bchristo@inf.ufsm.br>
+		 *
+		 * GeoVision GV-800(S) has 4 Conexant Fusion 878A:
+		 * 	1 audio input  per BT878A = 4 audio inputs
+		 * 	4 video inputs per BT878A = 16 video inputs
+		 * The 3 other BT878A chips are "slave" chips of the GV-800(S)
+		 * and should use this card type.
+		 * The audio input is not working yet.
+		 */
+		.name           = "Geovision GV-800(S) (slave)",
+		.video_inputs   = 4,
+		/* .audio_inputs= 1, */
+		.tuner_type	= TUNER_ABSENT,
+		.tuner_addr	= ADDR_UNSET,
+		.svhs           = NO_SVHS,
+		.gpiomask	= 0x00,
+		.no_gpioirq     = 1,
+		.muxsel		= MUXSEL(2, 2, 2, 2),
+		.pll		= PLL_28,
+		.no_msp34xx	= 1,
+		.no_tda7432	= 1,
+		.no_tda9875	= 1,
+		.muxsel_hook    = gv800s_muxsel,
+	},
 };

 static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -3376,6 +3436,9 @@
 	case BTTV_BOARD_KODICOM_4400R:
 		kodicom4400r_init(btv);
 		break;
+	case BTTV_BOARD_GEOVISION_GV800S:
+		gv800s_init(btv);
+		break;
 	}

 	/* pll configuration */
@@ -4595,6 +4658,122 @@
 	gpio_bits(0x3, mux);
 }

+/*
+ * GeoVision GV-800(S) functions
+ * Bruno Christo <bchristo@inf.ufsm.br>
+*/
+
+/* This is a function to control the analog switch, which determines which
+ * camera is routed to which controller.  The switch comprises an X-address
+ * (gpio bits 0-3, representing the camera, ranging from 0-15), and a
+ * Y-address (gpio bits 4-6, representing the controller, ranging from 0-3).
+ * A data value (gpio bit 18) of '1' enables the switch, and '0' disables
+ * the switch.  A STROBE bit (gpio bit 17) latches the data value into the
+ * specified address. There is also a chip select (gpio bit 16).
+ * The idea is to set the address and chip select together, bring
+ * STROBE high, write the data, and finally bring STROBE back to low.
+ */
+static void gv800s_write(struct bttv *btv,
+			 unsigned char xaddr,
+			 unsigned char yaddr,
+			 unsigned char data) {
+	/* On the "master" 878A:
+	* GPIO bits 0-9 are used for the analog switch:
+	*   00 - 03:	camera selector
+	*   04 - 06:	878A (controller) selector
+	*   16: 	cselect
+	*   17:		strobe
+	*   18: 	data (1->on, 0->off)
+	*   19:		reset
+	*/
+	const u32 ADDR = ((xaddr&0xf) | (yaddr&3)<<4);
+	const u32 CSELECT = 1<<16;
+	const u32 STROBE = 1<<17;
+	const u32 DATA = data<<18;
+
+	gpio_bits(0x1007f, ADDR | CSELECT);	/* write ADDR and CSELECT */
+	gpio_bits(0x20000, STROBE);		/* STROBE high */
+	gpio_bits(0x40000, DATA);		/* write DATA */
+	gpio_bits(0x20000, ~STROBE);		/* STROBE low */
+}
+
+/*
+ * GeoVision GV-800(S) muxsel
+ *
+ * Each of the 4 cards (controllers) use this function.
+ * The controller using this function selects the input through the GPIO pins
+ * of the "master" card. A pointer to this card is stored in master[btv->c.nr].
+ *
+ * The parameter 'input' is the requested camera number (0-4) on the
controller.
+ * The map array has the address of each input. Note that the addresses in the
+ * array are in the sequence the original GeoVision driver uses, that is, set
+ * every controller to input 0, then to input 1, 2, 3, repeat. This means that
+ * the physical "camera 1" connector corresponds to controller 0 input 0,
+ * "camera 2" corresponds to controller 1 input 0, and so on.
+ *
+ * After getting the input address, the function then writes the appropriate
+ * data to the analog switch, and housekeeps the local copy of the switch
+ * information.
+ */
+static void gv800s_muxsel(struct bttv *btv, unsigned int input)
+{
+	struct bttv *mctlr;
+	char *sw_status;
+	int xaddr, yaddr;
+	static unsigned int map[4][4] = { { 0x0, 0x4, 0xa, 0x6 },
+					  { 0x1, 0x5, 0xb, 0x7 },
+					  { 0x2, 0x8, 0xc, 0xe },
+					  { 0x3, 0x9, 0xd, 0xf } };
+	input = input%4;
+	mctlr = master[btv->c.nr];
+	if (mctlr == NULL) {
+		/* do nothing until the "master" is detected */
+		return;
+	}
+	yaddr = (btv->c.nr - mctlr->c.nr) & 3;
+	sw_status = (char *)(&mctlr->mbox_we);
+	xaddr = map[yaddr][input] & 0xf;
+
+	/* Check if the controller/camera pair has changed, ignore otherwise */
+	if (sw_status[yaddr] != xaddr) {
+		/* disable the old switch, enable the new one and save status */
+		gv800s_write(mctlr, sw_status[yaddr], yaddr, 0);
+		sw_status[yaddr] = xaddr;
+		gv800s_write(mctlr, xaddr, yaddr, 1);
+	}
+}
+
+/* GeoVision GV-800(S) "master" chip init */
+static void gv800s_init(struct bttv *btv)
+{
+	char *sw_status = (char *)(&btv->mbox_we);
+	int ix;
+
+	gpio_inout(0xf107f, 0xf107f);
+	gpio_write(1<<19); /* reset the analog MUX */
+	gpio_write(0);
+
+	/* Preset camera 0 to the 4 controllers */
+	for (ix = 0; ix < 4; ix++) {
+		sw_status[ix] = ix;
+		gv800s_write(btv, ix, ix, 1);
+	}
+
+	/* Inputs on the "master" controller need this brightness fix */
+	bttv_I2CWrite(btv, 0x18, 0x5, 0x90, 1);
+
+	if (btv->c.nr > BTTV_MAX-4)
+	   return;
+	/*
+	 * Store the "master" controller pointer in the master
+	 * array for later use in the muxsel function.
+	 */
+	master[btv->c.nr]   = btv;
+	master[btv->c.nr+1] = btv;
+	master[btv->c.nr+2] = btv;
+	master[btv->c.nr+3] = btv;
+}
+
 /* ----------------------------------------------------------------------- */
 /* motherboard chipset specific stuff                                      */


2009/2/28 Bruno Christo <brunochristo@gmail.com>:
> Hello all,
>
> I have a GeoVision GV-800(S) card, it has 4 CONEXANT BT878A chips.
> It has 16 video inputs and 4 audio inputs, and it is almost identical
> to the GV-800, as seen on http://bttv-gallery.de .
> The only difference appears to be the analog mux, it has a CD22M3494
> in place of the MT8816AP. The card has a blue PCB, as seen in this
> picture: http://www.gsbr.com.br/imagem/kits/GeoVision%20GV%20800.jpg .
>
> This card wasn't originally supported, and it was detected as
> UNKNOWN/GENERIC. The video inputs weren't working, so I tried
> "forcing" a few cards like the GeoVision GV-600, but there was still
> no video. So I made a patch to support this card, based on the Kodicom
> 4400r.
>
> The GV-800(S) is identified as follows:
>
> # lspci
> ...
> 02:00.0 Multimedia video controller: Brooktree Corporation Bt878 Video
> Capture (rev 11)
> 02:00.1 Multimedia controller: Brooktree Corporation Bt878 Audio
> Capture (rev 11)
> 02:04.0 Multimedia video controller: Brooktree Corporation Bt878 Video
> Capture (rev 11)
> 02:04.1 Multimedia controller: Brooktree Corporation Bt878 Audio
> Capture (rev 11)
> 02:08.0 Multimedia video controller: Brooktree Corporation Bt878 Video
> Capture (rev 11)
> 02:08.1 Multimedia controller: Brooktree Corporation Bt878 Audio
> Capture (rev 11)
> 02:0c.0 Multimedia video controller: Brooktree Corporation Bt878 Video
> Capture (rev 11)
> 02:0c.1 Multimedia controller: Brooktree Corporation Bt878 Audio
> Capture (rev 11)
>
> # lspci -nv
> ...
> 02:00.0 0400: 109e:036e (rev 11)
>        Subsystem: 800a:763d
>        Flags: bus master, medium devsel, latency 32, IRQ 10
>        Memory at cdfff000 (32-bit, prefetchable) [size=4K]
>        Capabilities: [44] Vital Product Data <?>
>        Capabilities: [4c] Power Management version 2
>        Kernel modules: bttv
>
> 02:00.1 0480: 109e:0878 (rev 11)
>        Subsystem: 800a:763d
>        Flags: bus master, medium devsel, latency 32, IRQ 10
>        Memory at cdffe000 (32-bit, prefetchable) [size=4K]
>        Capabilities: [44] Vital Product Data <?>
>        Capabilities: [4c] Power Management version 2
>
> 02:04.0 0400: 109e:036e (rev 11)
>        Subsystem: 800b:763d
>        Flags: bus master, medium devsel, latency 32, IRQ 10
>        Memory at cdffd000 (32-bit, prefetchable) [size=4K]
>        Capabilities: [44] Vital Product Data <?>
>        Capabilities: [4c] Power Management version 2
>        Kernel modules: bttv
>
> 02:04.1 0480: 109e:0878 (rev 11)
>        Subsystem: 800b:763d
>        Flags: bus master, medium devsel, latency 32, IRQ 10
>        Memory at cdffc000 (32-bit, prefetchable) [size=4K]
>        Capabilities: [44] Vital Product Data <?>
>        Capabilities: [4c] Power Management version 2
>
> 02:08.0 0400: 109e:036e (rev 11)
>        Subsystem: 800c:763d
>        Flags: bus master, medium devsel, latency 32, IRQ 10
>        Memory at cdffb000 (32-bit, prefetchable) [size=4K]
>        Capabilities: [44] Vital Product Data <?>
>        Capabilities: [4c] Power Management version 2
>        Kernel modules: bttv
>
> 02:08.1 0480: 109e:0878 (rev 11)
>        Subsystem: 800c:763d
>        Flags: bus master, medium devsel, latency 32, IRQ 10
>        Memory at cdffa000 (32-bit, prefetchable) [size=4K]
>        Capabilities: [44] Vital Product Data <?>
>        Capabilities: [4c] Power Management version 2
>
> 02:0c.0 0400: 109e:036e (rev 11)
>        Subsystem: 800d:763d
>        Flags: bus master, medium devsel, latency 32, IRQ 10
>        Memory at cdff9000 (32-bit, prefetchable) [size=4K]
>        Capabilities: [44] Vital Product Data <?>
>        Capabilities: [4c] Power Management version 2
>        Kernel modules: bttv
>
> 02:0c.1 0480: 109e:0878 (rev 11)
>        Subsystem: 800d:763d
>        Flags: bus master, medium devsel, latency 32, IRQ 10
>        Memory at cdff8000 (32-bit, prefetchable) [size=4K]
>        Capabilities: [44] Vital Product Data <?>
>        Capabilities: [4c] Power Management version 2
>
> As you can see, the GV-800(S) card is almost identical to the GV-800
> on bttv-gallery, so this patch might also work for that card. If not,
> only a few changes should be required on the gv800s_write() function.
>
> After this patch, the video inputs work correctly. The input order may
> seem a little odd, but it's the order the original software/driver
> uses, and I decided to keep that order to get the most out of the
> card.
>
> I tried to get the audio working with the snd-bt87x module, but I only
> get noise from every audio input, even after selecting a different mux
> with alsamixer. Also, after trying to play sound from those sources, I
> randomly get a RISC error about an invalid RISC opcode, and then that
> output stops working. I also can't change the sampling rate when
> recording. Any pointers to adding audio support are welcome.
>
> Signed-off-by: Bruno Christo <bchristo@inf.ufsm.br>
>
> diff -r c770b20d15c6 linux/Documentation/video4linux/CARDLIST.bttv
> --- a/linux/Documentation/video4linux/CARDLIST.bttv     Fri Feb 27
> 21:29:59 2009 -0300
> +++ b/linux/Documentation/video4linux/CARDLIST.bttv     Fri Feb 27
> 22:12:29 2009 -0300
> @@ -155,3 +155,5 @@
>  154 -> PHYTEC VD-012-X1 (bt878)
>  155 -> PHYTEC VD-012-X2 (bt878)
>  156 -> IVCE-8784
> [0000:f050,0001:f050,0002:f050,0003:f050]
> +157 -> Geovision GV-800(S) (master)                        [800a:763d]
> +158 -> Geovision GV-800(S) (slave)
> [800b:763d,800c:763d,800d:763d]
> diff -r c770b20d15c6 linux/drivers/media/video/bt8xx/bttv-cards.c
> --- a/linux/drivers/media/video/bt8xx/bttv-cards.c      Fri Feb 27 21:29:59
> 2009 -0300
> +++ b/linux/drivers/media/video/bt8xx/bttv-cards.c      Fri Feb 27 22:12:29
> 2009 -0300
> @@ -75,6 +75,9 @@
>  static void geovision_muxsel(struct bttv *btv, unsigned int input);
>
>  static void phytec_muxsel(struct bttv *btv, unsigned int input);
> +
> +static void gv800s_muxsel(struct bttv *btv, unsigned int input);
> +static void gv800s_init(struct bttv *btv);
>
>  static int terratec_active_radio_upgrade(struct bttv *btv);
>  static int tea5757_read(struct bttv *btv);
> @@ -312,6 +315,10 @@
>        { 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2,    "DViCO FusionHDTV 2" },
>        { 0x763c008a, BTTV_BOARD_GEOVISION_GV600,       "GeoVision GV-600" },
>        { 0x18011000, BTTV_BOARD_ENLTV_FM_2,    "Encore ENL TV-FM-2" },
> +       { 0x763d800a, BTTV_BOARD_GEOVISION_GV800S, "GeoVision GV-800(S) (master)" },
> +       { 0x763d800b, BTTV_BOARD_GEOVISION_GV800S_SL,   "GeoVision GV-800(S) (slave)" },
> +       { 0x763d800c, BTTV_BOARD_GEOVISION_GV800S_SL,   "GeoVision GV-800(S) (slave)" },
> +       { 0x763d800d, BTTV_BOARD_GEOVISION_GV800S_SL,   "GeoVision GV-800(S) (slave)" },
>        { 0, -1, NULL }
>  };
>
> @@ -2847,7 +2854,60 @@
>                .pll            = PLL_28,
>                .tuner_type     = TUNER_ABSENT,
>                .tuner_addr     = ADDR_UNSET,
> -       }
> +       },
> +               [BTTV_BOARD_GEOVISION_GV800S] = {
> +               /* Bruno Christo <bchristo@inf.ufsm.br>
> +                *
> +                * GeoVision GV-800(S) has 4 Conexant Fusion 878A:
> +                *      1 audio input  per BT878A = 4 audio inputs
> +                *      4 video inputs per BT878A = 16 video inputs
> +                * This is the first BT878A chip of the GV-800(S). It's the
> +                * "master" chip and it controls the video inputs through an
> +                * analog multiplexer (a CD22M3494) via some GPIO pins. The
> +                * slaves should use card type 0x9e (following this one).
> +                * There is a EEPROM on the card which is currently not handled.
> +                * The audio input is not working yet.
> +                */
> +               .name           = "Geovision GV-800(S) (master)",
> +               .video_inputs   = 4,
> +               /* .audio_inputs= 1, */
> +               .tuner_type     = TUNER_ABSENT,
> +               .tuner_addr     = ADDR_UNSET,
> +               .svhs           = NO_SVHS,
> +               .gpiomask       = 0xf107f,
> +               .no_gpioirq     = 1,
> +               .muxsel         = MUXSEL(2, 2, 2, 2),
> +               .pll            = PLL_28,
> +               .no_msp34xx     = 1,
> +               .no_tda7432     = 1,
> +               .no_tda9875     = 1,
> +               .muxsel_hook    = gv800s_muxsel,
> +       },
> +               [BTTV_BOARD_GEOVISION_GV800S_SL] = {
> +               /* Bruno Christo <bchristo@inf.ufsm.br>
> +                *
> +                * GeoVision GV-800(S) has 4 Conexant Fusion 878A:
> +                *      1 audio input  per BT878A = 4 audio inputs
> +                *      4 video inputs per BT878A = 16 video inputs
> +                * The 3 other BT878A chips are "slave" chips of the GV-800(S)
> +                * and should use this card type.
> +                * The audio input is not working yet.
> +                */
> +               .name           = "Geovision GV-800(S) (slave)",
> +               .video_inputs   = 4,
> +               /* .audio_inputs= 1, */
> +               .tuner_type     = TUNER_ABSENT,
> +               .tuner_addr     = ADDR_UNSET,
> +               .svhs           = NO_SVHS,
> +               .gpiomask       = 0x00,
> +               .no_gpioirq     = 1,
> +               .muxsel         = MUXSEL(2, 2, 2, 2),
> +               .pll            = PLL_28,
> +               .no_msp34xx     = 1,
> +               .no_tda7432     = 1,
> +               .no_tda9875     = 1,
> +               .muxsel_hook    = gv800s_muxsel,
> +       },
>  };
>
>  static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
> @@ -3376,6 +3436,9 @@
>        case BTTV_BOARD_KODICOM_4400R:
>                kodicom4400r_init(btv);
>                break;
> +       case BTTV_BOARD_GEOVISION_GV800S:
> +               gv800s_init(btv);
> +               break;
>        }
>
>        /* pll configuration */
> @@ -4595,6 +4658,123 @@
>        gpio_bits(0x3, mux);
>  }
>
> +/*
> + * GeoVision GV-800(S) functions
> + * Bruno Christo <bchristo@inf.ufsm.br>
> +*/
> +
> +/* This is a function to control the analog switch, which determines which
> + * camera is routed to which controller.  The switch comprises an X-address
> + * (gpio bits 0-3, representing the camera, ranging from 0-15), and a
> + * Y-address (gpio bits 4-6, representing the controller, ranging from 0-3).
> + * A data value (gpio bit 18) of '1' enables the switch, and '0' disables
> + * the switch.  A STROBE bit (gpio bit 17) latches the data value into the
> + * specified address. There is also a chip select (gpio bit 16).
> + * The idea is to set the address and chip select together, bring
> + * STROBE high, write the data, and finally bring STROBE back to low.
> + */
> +static void gv800s_write(struct bttv *btv,
> +                        unsigned char xaddr,
> +                        unsigned char yaddr,
> +                        unsigned char data) {
> +       /* On the "master" 878A:
> +       * GPIO bits 0-9 are used for the analog switch:
> +       *   00 - 03:    camera selector
> +       *   04 - 06:    878A (controller) selector
> +       *   16:         cselect
> +       *   17:         strobe
> +       *   18:         data (1->on, 0->off)
> +       *   19:         reset
> +       */
> +       const u32 ADDR = ((xaddr&0xf) | (yaddr&3)<<4);
> +       const u32 CSELECT = 1<<16;
> +       const u32 STROBE = 1<<17;
> +       const u32 DATA = data<<18;
> +
> +       gpio_bits(0x1007f, ADDR | CSELECT);     /* write ADDR and CSELECT */
> +       gpio_bits(0x20000, STROBE);             /* STROBE high */
> +       gpio_bits(0x40000, DATA);               /* write DATA */
> +       gpio_bits(0x20000, ~STROBE);            /* STROBE low */
> +}
> +
> +/*
> + * GeoVision GV-800(S) muxsel
> + *
> + * Each of the 4 cards (controllers) use this function.
> + * The controller using this function selects the input through the GPIO pins
> + * of the "master" card. A pointer to this card is stored in master[btv->c.nr].
> + *
> + * The parameter 'input' is the requested camera number (0-4) on the
> controller.
> + * The map array has the address of each input. Note that the addresses in the
> + * array are in the sequence the original GeoVision driver uses, that is, set
> + * every controller to input 0, then to input 1, 2, 3, repeat. This means that
> + * the physical "camera 1" connector corresponds to controller 0 input 0,
> + * "camera 2" corresponds to controller 1 input 0, and so on.
> + *
> + * After getting the input address, the function then writes the appropriate
> + * data to the analog switch, and housekeeps the local copy of the switch
> + * information.
> + */
> +static void gv800s_muxsel(struct bttv *btv, unsigned int input)
> +{
> +       struct bttv *mctlr;
> +       char *sw_status;
> +       int xaddr, yaddr;
> +       static unsigned int map[4][4] = {{ 0x0, 0x4, 0xa, 0x6 },
> +                                        { 0x1, 0x5, 0xb, 0x7 },
> +                                        { 0x2, 0x8, 0xc, 0xe },
> +                                        { 0x3, 0x9, 0xd, 0xf }};
> +       input = input%4;
> +       mctlr = master[btv->c.nr];
> +       if (mctlr == NULL) {
> +               // do nothing until the "master" is detected
> +               return;
> +       }
> +       yaddr = (btv->c.nr - mctlr->c.nr) & 3;
> +       sw_status = (char *)(&mctlr->mbox_we);
> +       xaddr = map[yaddr][input] & 0xf;
> +
> +       // Check if the controller/camera pair has changed, ignore otherwise
> +       if (sw_status[yaddr] != xaddr)
> +       {
> +               // disable the old switch, enable the new one and save status
> +               gv800s_write(mctlr, sw_status[yaddr], yaddr, 0);
> +               sw_status[yaddr] = xaddr;
> +               gv800s_write(mctlr, xaddr, yaddr, 1);
> +       }
> +}
> +
> +/* GeoVision GV-800(S) "master" chip init */
> +static void gv800s_init(struct bttv *btv)
> +{
> +       char *sw_status = (char *)(&btv->mbox_we);
> +       int ix;
> +
> +       gpio_inout(0xf107f, 0xf107f);
> +       gpio_write(1<<19); /* reset the analog MUX */
> +       gpio_write(0);
> +
> +       /* Preset camera 0 to the 4 controllers */
> +       for (ix = 0; ix < 4; ix++) {
> +               sw_status[ix] = ix;
> +               gv800s_write(btv, ix, ix, 1);
> +       }
> +
> +       /* Inputs on the "master" controller need this brightness fix */
> +       bttv_I2CWrite(btv, 0x18, 0x5, 0x90, 1);
> +
> +       if (btv->c.nr>BTTV_MAX-4)
> +           return;
> +       /*
> +        * Store the "master" controller pointer in the master
> +        * array for later use in the muxsel function.
> +        */
> +       master[btv->c.nr]   = btv;
> +       master[btv->c.nr+1] = btv;
> +       master[btv->c.nr+2] = btv;
> +       master[btv->c.nr+3] = btv;
> +}
> +
>  /* ----------------------------------------------------------------------- */
>  /* motherboard chipset specific stuff                                      */
>
> diff -r c770b20d15c6 linux/drivers/media/video/bt8xx/bttv.h
> --- a/linux/drivers/media/video/bt8xx/bttv.h    Fri Feb 27 21:29:59 2009 -0300
> +++ b/linux/drivers/media/video/bt8xx/bttv.h    Fri Feb 27 22:12:29 2009 -0300
> @@ -182,6 +182,8 @@
>  #define BTTV_BOARD_VD012_X1               0x9a
>  #define BTTV_BOARD_VD012_X2               0x9b
>  #define BTTV_BOARD_IVCE8784               0x9c
> +#define BTTV_BOARD_GEOVISION_GV800S       0x9d
> +#define BTTV_BOARD_GEOVISION_GV800S_SL    0x9e
>
>
>  /* more card-specific defines */
> --
> Bruno Christo
> Bacharel em Ciência da Computação - UFSM
>

Comments

Nicola Soranzo March 2, 2009, 1:59 p.m. UTC | #1
Hi Bruno,
it look like that your e-mail program is line wrapping your patch.
Please read email-clients.txt in Linux Documentation and resubmit the patch, 
otherwise it cannot be correctly handled by patchwork.kernel.org .
Thanks,
Nicola

Alle sabato 28 febbraio 2009, Bruno Christo ha scritto:
> I forgot to run make checkpatch before submitting the previous patch,
> here is the fixed patch:
>
> diff -r c770b20d15c6 linux/Documentation/video4linux/CARDLIST.bttv
> --- a/linux/Documentation/video4linux/CARDLIST.bttv	Fri Feb 27
> 21:29:59 2009 -0300
> +++ b/linux/Documentation/video4linux/CARDLIST.bttv	Sat Feb 28
> 17:09:23 2009 -0300
> @@ -155,3 +155,5 @@
>  154 -> PHYTEC VD-012-X1 (bt878)
>  155 -> PHYTEC VD-012-X2 (bt878)
>  156 -> IVCE-8784
> [0000:f050,0001:f050,0002:f050,0003:f050]
> +157 -> Geovision GV-800(S) (master)                        [800a:763d]
> +158 -> Geovision GV-800(S) (slave)
> [800b:763d,800c:763d,800d:763d]
> diff -r c770b20d15c6 linux/drivers/media/video/bt8xx/bttv-cards.c
> --- a/linux/drivers/media/video/bt8xx/bttv-cards.c	Fri Feb 27 21:29:59
> 2009 -0300
> +++ b/linux/drivers/media/video/bt8xx/bttv-cards.c	Sat Feb 28 17:09:23
> 2009 -0300
> @@ -75,6 +75,9 @@
>  static void geovision_muxsel(struct bttv *btv, unsigned int input);
>
>  static void phytec_muxsel(struct bttv *btv, unsigned int input);
> +
> +static void gv800s_muxsel(struct bttv *btv, unsigned int input);
> +static void gv800s_init(struct bttv *btv);
>
>  static int terratec_active_radio_upgrade(struct bttv *btv);
>  static int tea5757_read(struct bttv *btv);
> @@ -312,6 +315,10 @@
>  	{ 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2,	"DViCO FusionHDTV 2" },
>  	{ 0x763c008a, BTTV_BOARD_GEOVISION_GV600,	"GeoVision GV-600" },
>  	{ 0x18011000, BTTV_BOARD_ENLTV_FM_2,	"Encore ENL TV-FM-2" },
> +	{ 0x763d800a, BTTV_BOARD_GEOVISION_GV800S, "GeoVision GV-800(S) (master)"
> }, +	{ 0x763d800b, BTTV_BOARD_GEOVISION_GV800S_SL,	"GeoVision GV-800(S)
> (slave)" }, +	{ 0x763d800c, BTTV_BOARD_GEOVISION_GV800S_SL,	"GeoVision
> GV-800(S) (slave)" }, +	{ 0x763d800d,
> BTTV_BOARD_GEOVISION_GV800S_SL,	"GeoVision GV-800(S) (slave)" }, { 0, -1,
> NULL }
>  };
>
> @@ -2847,7 +2854,60 @@
>  		.pll            = PLL_28,
>  		.tuner_type     = TUNER_ABSENT,
>  		.tuner_addr	= ADDR_UNSET,
> -	}
> +	},
> +		[BTTV_BOARD_GEOVISION_GV800S] = {
> +		/* Bruno Christo <bchristo@inf.ufsm.br>
> +		 *
> +		 * GeoVision GV-800(S) has 4 Conexant Fusion 878A:
> +		 * 	1 audio input  per BT878A = 4 audio inputs
> +		 * 	4 video inputs per BT878A = 16 video inputs
> +		 * This is the first BT878A chip of the GV-800(S). It's the
> +		 * "master" chip and it controls the video inputs through an
> +		 * analog multiplexer (a CD22M3494) via some GPIO pins. The
> +		 * slaves should use card type 0x9e (following this one).
> +		 * There is a EEPROM on the card which is currently not handled.
> +		 * The audio input is not working yet.
> +		 */
> +		.name           = "Geovision GV-800(S) (master)",
> +		.video_inputs   = 4,
> +		/* .audio_inputs= 1, */
> +		.tuner_type	= TUNER_ABSENT,
> +		.tuner_addr	= ADDR_UNSET,
> +		.svhs           = NO_SVHS,
> +		.gpiomask	= 0xf107f,
> +		.no_gpioirq     = 1,
> +		.muxsel		= MUXSEL(2, 2, 2, 2),
> +		.pll		= PLL_28,
> +		.no_msp34xx	= 1,
> +		.no_tda7432	= 1,
> +		.no_tda9875	= 1,
> +		.muxsel_hook    = gv800s_muxsel,
> +	},
> +		[BTTV_BOARD_GEOVISION_GV800S_SL] = {
> +		/* Bruno Christo <bchristo@inf.ufsm.br>
> +		 *
> +		 * GeoVision GV-800(S) has 4 Conexant Fusion 878A:
> +		 * 	1 audio input  per BT878A = 4 audio inputs
> +		 * 	4 video inputs per BT878A = 16 video inputs
> +		 * The 3 other BT878A chips are "slave" chips of the GV-800(S)
> +		 * and should use this card type.
> +		 * The audio input is not working yet.
> +		 */
> +		.name           = "Geovision GV-800(S) (slave)",
> +		.video_inputs   = 4,
> +		/* .audio_inputs= 1, */
> +		.tuner_type	= TUNER_ABSENT,
> +		.tuner_addr	= ADDR_UNSET,
> +		.svhs           = NO_SVHS,
> +		.gpiomask	= 0x00,
> +		.no_gpioirq     = 1,
> +		.muxsel		= MUXSEL(2, 2, 2, 2),
> +		.pll		= PLL_28,
> +		.no_msp34xx	= 1,
> +		.no_tda7432	= 1,
> +		.no_tda9875	= 1,
> +		.muxsel_hook    = gv800s_muxsel,
> +	},
>  };
>
>  static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
> @@ -3376,6 +3436,9 @@
>  	case BTTV_BOARD_KODICOM_4400R:
>  		kodicom4400r_init(btv);
>  		break;
> +	case BTTV_BOARD_GEOVISION_GV800S:
> +		gv800s_init(btv);
> +		break;
>  	}
>
>  	/* pll configuration */
> @@ -4595,6 +4658,122 @@
>  	gpio_bits(0x3, mux);
>  }
>
> +/*
> + * GeoVision GV-800(S) functions
> + * Bruno Christo <bchristo@inf.ufsm.br>
> +*/
> +
> +/* This is a function to control the analog switch, which determines which
> + * camera is routed to which controller.  The switch comprises an
> X-address + * (gpio bits 0-3, representing the camera, ranging from 0-15),
> and a + * Y-address (gpio bits 4-6, representing the controller, ranging
> from 0-3). + * A data value (gpio bit 18) of '1' enables the switch, and
> '0' disables + * the switch.  A STROBE bit (gpio bit 17) latches the data
> value into the + * specified address. There is also a chip select (gpio bit
> 16).
> + * The idea is to set the address and chip select together, bring
> + * STROBE high, write the data, and finally bring STROBE back to low.
> + */
> +static void gv800s_write(struct bttv *btv,
> +			 unsigned char xaddr,
> +			 unsigned char yaddr,
> +			 unsigned char data) {
> +	/* On the "master" 878A:
> +	* GPIO bits 0-9 are used for the analog switch:
> +	*   00 - 03:	camera selector
> +	*   04 - 06:	878A (controller) selector
> +	*   16: 	cselect
> +	*   17:		strobe
> +	*   18: 	data (1->on, 0->off)
> +	*   19:		reset
> +	*/
> +	const u32 ADDR = ((xaddr&0xf) | (yaddr&3)<<4);
> +	const u32 CSELECT = 1<<16;
> +	const u32 STROBE = 1<<17;
> +	const u32 DATA = data<<18;
> +
> +	gpio_bits(0x1007f, ADDR | CSELECT);	/* write ADDR and CSELECT */
> +	gpio_bits(0x20000, STROBE);		/* STROBE high */
> +	gpio_bits(0x40000, DATA);		/* write DATA */
> +	gpio_bits(0x20000, ~STROBE);		/* STROBE low */
> +}
> +
> +/*
> + * GeoVision GV-800(S) muxsel
> + *
> + * Each of the 4 cards (controllers) use this function.
> + * The controller using this function selects the input through the GPIO
> pins + * of the "master" card. A pointer to this card is stored in
> master[btv->c.nr]. + *
> + * The parameter 'input' is the requested camera number (0-4) on the
> controller.
> + * The map array has the address of each input. Note that the addresses in
> the + * array are in the sequence the original GeoVision driver uses, that
> is, set + * every controller to input 0, then to input 1, 2, 3, repeat.
> This means that + * the physical "camera 1" connector corresponds to
> controller 0 input 0, + * "camera 2" corresponds to controller 1 input 0,
> and so on.
> + *
> + * After getting the input address, the function then writes the
> appropriate + * data to the analog switch, and housekeeps the local copy of
> the switch + * information.
> + */
> +static void gv800s_muxsel(struct bttv *btv, unsigned int input)
> +{
> +	struct bttv *mctlr;
> +	char *sw_status;
> +	int xaddr, yaddr;
> +	static unsigned int map[4][4] = { { 0x0, 0x4, 0xa, 0x6 },
> +					  { 0x1, 0x5, 0xb, 0x7 },
> +					  { 0x2, 0x8, 0xc, 0xe },
> +					  { 0x3, 0x9, 0xd, 0xf } };
> +	input = input%4;
> +	mctlr = master[btv->c.nr];
> +	if (mctlr == NULL) {
> +		/* do nothing until the "master" is detected */
> +		return;
> +	}
> +	yaddr = (btv->c.nr - mctlr->c.nr) & 3;
> +	sw_status = (char *)(&mctlr->mbox_we);
> +	xaddr = map[yaddr][input] & 0xf;
> +
> +	/* Check if the controller/camera pair has changed, ignore otherwise */
> +	if (sw_status[yaddr] != xaddr) {
> +		/* disable the old switch, enable the new one and save status */
> +		gv800s_write(mctlr, sw_status[yaddr], yaddr, 0);
> +		sw_status[yaddr] = xaddr;
> +		gv800s_write(mctlr, xaddr, yaddr, 1);
> +	}
> +}
> +
> +/* GeoVision GV-800(S) "master" chip init */
> +static void gv800s_init(struct bttv *btv)
> +{
> +	char *sw_status = (char *)(&btv->mbox_we);
> +	int ix;
> +
> +	gpio_inout(0xf107f, 0xf107f);
> +	gpio_write(1<<19); /* reset the analog MUX */
> +	gpio_write(0);
> +
> +	/* Preset camera 0 to the 4 controllers */
> +	for (ix = 0; ix < 4; ix++) {
> +		sw_status[ix] = ix;
> +		gv800s_write(btv, ix, ix, 1);
> +	}
> +
> +	/* Inputs on the "master" controller need this brightness fix */
> +	bttv_I2CWrite(btv, 0x18, 0x5, 0x90, 1);
> +
> +	if (btv->c.nr > BTTV_MAX-4)
> +	   return;
> +	/*
> +	 * Store the "master" controller pointer in the master
> +	 * array for later use in the muxsel function.
> +	 */
> +	master[btv->c.nr]   = btv;
> +	master[btv->c.nr+1] = btv;
> +	master[btv->c.nr+2] = btv;
> +	master[btv->c.nr+3] = btv;
> +}
> +
>  /* -----------------------------------------------------------------------
> */ /* motherboard chipset specific stuff                                   
>   */
>
> diff -r c770b20d15c6 linux/drivers/media/video/bt8xx/bttv.h
> --- a/linux/drivers/media/video/bt8xx/bttv.h	Fri Feb 27 21:29:59 2009 -0300
> +++ b/linux/drivers/media/video/bt8xx/bttv.h	Sat Feb 28 17:09:23 2009 -0300
> @@ -182,6 +182,8 @@
>  #define BTTV_BOARD_VD012_X1		   0x9a
>  #define BTTV_BOARD_VD012_X2		   0x9b
>  #define BTTV_BOARD_IVCE8784		   0x9c
> +#define BTTV_BOARD_GEOVISION_GV800S	   0x9d
> +#define BTTV_BOARD_GEOVISION_GV800S_SL	   0x9e
>
>
>  /* more card-specific defines */
>
> 2009/2/28 Bruno Christo <brunochristo@gmail.com>:
> > Hello all,
> >
> > I have a GeoVision GV-800(S) card, it has 4 CONEXANT BT878A chips.
> > It has 16 video inputs and 4 audio inputs, and it is almost identical
> > to the GV-800, as seen on http://bttv-gallery.de .
> > The only difference appears to be the analog mux, it has a CD22M3494
> > in place of the MT8816AP. The card has a blue PCB, as seen in this
> > picture: http://www.gsbr.com.br/imagem/kits/GeoVision%20GV%20800.jpg .
> >
> > This card wasn't originally supported, and it was detected as
> > UNKNOWN/GENERIC. The video inputs weren't working, so I tried
> > "forcing" a few cards like the GeoVision GV-600, but there was still
> > no video. So I made a patch to support this card, based on the Kodicom
> > 4400r.
> >
> > The GV-800(S) is identified as follows:
> >
> > # lspci
> > ...
> > 02:00.0 Multimedia video controller: Brooktree Corporation Bt878 Video
> > Capture (rev 11)
> > 02:00.1 Multimedia controller: Brooktree Corporation Bt878 Audio
> > Capture (rev 11)
> > 02:04.0 Multimedia video controller: Brooktree Corporation Bt878 Video
> > Capture (rev 11)
> > 02:04.1 Multimedia controller: Brooktree Corporation Bt878 Audio
> > Capture (rev 11)
> > 02:08.0 Multimedia video controller: Brooktree Corporation Bt878 Video
> > Capture (rev 11)
> > 02:08.1 Multimedia controller: Brooktree Corporation Bt878 Audio
> > Capture (rev 11)
> > 02:0c.0 Multimedia video controller: Brooktree Corporation Bt878 Video
> > Capture (rev 11)
> > 02:0c.1 Multimedia controller: Brooktree Corporation Bt878 Audio
> > Capture (rev 11)
> >
> > # lspci -nv
> > ...
> > 02:00.0 0400: 109e:036e (rev 11)
> >        Subsystem: 800a:763d
> >        Flags: bus master, medium devsel, latency 32, IRQ 10
> >        Memory at cdfff000 (32-bit, prefetchable) [size=4K]
> >        Capabilities: [44] Vital Product Data <?>
> >        Capabilities: [4c] Power Management version 2
> >        Kernel modules: bttv
> >
> > 02:00.1 0480: 109e:0878 (rev 11)
> >        Subsystem: 800a:763d
> >        Flags: bus master, medium devsel, latency 32, IRQ 10
> >        Memory at cdffe000 (32-bit, prefetchable) [size=4K]
> >        Capabilities: [44] Vital Product Data <?>
> >        Capabilities: [4c] Power Management version 2
> >
> > 02:04.0 0400: 109e:036e (rev 11)
> >        Subsystem: 800b:763d
> >        Flags: bus master, medium devsel, latency 32, IRQ 10
> >        Memory at cdffd000 (32-bit, prefetchable) [size=4K]
> >        Capabilities: [44] Vital Product Data <?>
> >        Capabilities: [4c] Power Management version 2
> >        Kernel modules: bttv
> >
> > 02:04.1 0480: 109e:0878 (rev 11)
> >        Subsystem: 800b:763d
> >        Flags: bus master, medium devsel, latency 32, IRQ 10
> >        Memory at cdffc000 (32-bit, prefetchable) [size=4K]
> >        Capabilities: [44] Vital Product Data <?>
> >        Capabilities: [4c] Power Management version 2
> >
> > 02:08.0 0400: 109e:036e (rev 11)
> >        Subsystem: 800c:763d
> >        Flags: bus master, medium devsel, latency 32, IRQ 10
> >        Memory at cdffb000 (32-bit, prefetchable) [size=4K]
> >        Capabilities: [44] Vital Product Data <?>
> >        Capabilities: [4c] Power Management version 2
> >        Kernel modules: bttv
> >
> > 02:08.1 0480: 109e:0878 (rev 11)
> >        Subsystem: 800c:763d
> >        Flags: bus master, medium devsel, latency 32, IRQ 10
> >        Memory at cdffa000 (32-bit, prefetchable) [size=4K]
> >        Capabilities: [44] Vital Product Data <?>
> >        Capabilities: [4c] Power Management version 2
> >
> > 02:0c.0 0400: 109e:036e (rev 11)
> >        Subsystem: 800d:763d
> >        Flags: bus master, medium devsel, latency 32, IRQ 10
> >        Memory at cdff9000 (32-bit, prefetchable) [size=4K]
> >        Capabilities: [44] Vital Product Data <?>
> >        Capabilities: [4c] Power Management version 2
> >        Kernel modules: bttv
> >
> > 02:0c.1 0480: 109e:0878 (rev 11)
> >        Subsystem: 800d:763d
> >        Flags: bus master, medium devsel, latency 32, IRQ 10
> >        Memory at cdff8000 (32-bit, prefetchable) [size=4K]
> >        Capabilities: [44] Vital Product Data <?>
> >        Capabilities: [4c] Power Management version 2
> >
> > As you can see, the GV-800(S) card is almost identical to the GV-800
> > on bttv-gallery, so this patch might also work for that card. If not,
> > only a few changes should be required on the gv800s_write() function.
> >
> > After this patch, the video inputs work correctly. The input order may
> > seem a little odd, but it's the order the original software/driver
> > uses, and I decided to keep that order to get the most out of the
> > card.
> >
> > I tried to get the audio working with the snd-bt87x module, but I only
> > get noise from every audio input, even after selecting a different mux
> > with alsamixer. Also, after trying to play sound from those sources, I
> > randomly get a RISC error about an invalid RISC opcode, and then that
> > output stops working. I also can't change the sampling rate when
> > recording. Any pointers to adding audio support are welcome.
> >
> > Signed-off-by: Bruno Christo <bchristo@inf.ufsm.br>
> >
> > diff -r c770b20d15c6 linux/Documentation/video4linux/CARDLIST.bttv
> > --- a/linux/Documentation/video4linux/CARDLIST.bttv     Fri Feb 27
> > 21:29:59 2009 -0300
> > +++ b/linux/Documentation/video4linux/CARDLIST.bttv     Fri Feb 27
> > 22:12:29 2009 -0300
> > @@ -155,3 +155,5 @@
> >  154 -> PHYTEC VD-012-X1 (bt878)
> >  155 -> PHYTEC VD-012-X2 (bt878)
> >  156 -> IVCE-8784
> > [0000:f050,0001:f050,0002:f050,0003:f050]
> > +157 -> Geovision GV-800(S) (master)                        [800a:763d]
> > +158 -> Geovision GV-800(S) (slave)
> > [800b:763d,800c:763d,800d:763d]
> > diff -r c770b20d15c6 linux/drivers/media/video/bt8xx/bttv-cards.c
> > --- a/linux/drivers/media/video/bt8xx/bttv-cards.c      Fri Feb 27
> > 21:29:59 2009 -0300
> > +++ b/linux/drivers/media/video/bt8xx/bttv-cards.c      Fri Feb 27
> > 22:12:29 2009 -0300
> > @@ -75,6 +75,9 @@
> >  static void geovision_muxsel(struct bttv *btv, unsigned int input);
> >
> >  static void phytec_muxsel(struct bttv *btv, unsigned int input);
> > +
> > +static void gv800s_muxsel(struct bttv *btv, unsigned int input);
> > +static void gv800s_init(struct bttv *btv);
> >
> >  static int terratec_active_radio_upgrade(struct bttv *btv);
> >  static int tea5757_read(struct bttv *btv);
> > @@ -312,6 +315,10 @@
> >        { 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2,    "DViCO FusionHDTV
> > 2" }, { 0x763c008a, BTTV_BOARD_GEOVISION_GV600,       "GeoVision GV-600"
> > }, { 0x18011000, BTTV_BOARD_ENLTV_FM_2,    "Encore ENL TV-FM-2" }, +    
> >   { 0x763d800a, BTTV_BOARD_GEOVISION_GV800S, "GeoVision GV-800(S)
> > (master)" }, +       { 0x763d800b, BTTV_BOARD_GEOVISION_GV800S_SL,  
> > "GeoVision GV-800(S) (slave)" }, +       { 0x763d800c,
> > BTTV_BOARD_GEOVISION_GV800S_SL,   "GeoVision GV-800(S) (slave)" }, +    
> >   { 0x763d800d, BTTV_BOARD_GEOVISION_GV800S_SL,   "GeoVision GV-800(S)
> > (slave)" }, { 0, -1, NULL }
> >  };
> >
> > @@ -2847,7 +2854,60 @@
> >                .pll            = PLL_28,
> >                .tuner_type     = TUNER_ABSENT,
> >                .tuner_addr     = ADDR_UNSET,
> > -       }
> > +       },
> > +               [BTTV_BOARD_GEOVISION_GV800S] = {
> > +               /* Bruno Christo <bchristo@inf.ufsm.br>
> > +                *
> > +                * GeoVision GV-800(S) has 4 Conexant Fusion 878A:
> > +                *      1 audio input  per BT878A = 4 audio inputs
> > +                *      4 video inputs per BT878A = 16 video inputs
> > +                * This is the first BT878A chip of the GV-800(S). It's
> > the +                * "master" chip and it controls the video inputs
> > through an +                * analog multiplexer (a CD22M3494) via some
> > GPIO pins. The +                * slaves should use card type 0x9e
> > (following this one). +                * There is a EEPROM on the card
> > which is currently not handled. +                * The audio input is not
> > working yet.
> > +                */
> > +               .name           = "Geovision GV-800(S) (master)",
> > +               .video_inputs   = 4,
> > +               /* .audio_inputs= 1, */
> > +               .tuner_type     = TUNER_ABSENT,
> > +               .tuner_addr     = ADDR_UNSET,
> > +               .svhs           = NO_SVHS,
> > +               .gpiomask       = 0xf107f,
> > +               .no_gpioirq     = 1,
> > +               .muxsel         = MUXSEL(2, 2, 2, 2),
> > +               .pll            = PLL_28,
> > +               .no_msp34xx     = 1,
> > +               .no_tda7432     = 1,
> > +               .no_tda9875     = 1,
> > +               .muxsel_hook    = gv800s_muxsel,
> > +       },
> > +               [BTTV_BOARD_GEOVISION_GV800S_SL] = {
> > +               /* Bruno Christo <bchristo@inf.ufsm.br>
> > +                *
> > +                * GeoVision GV-800(S) has 4 Conexant Fusion 878A:
> > +                *      1 audio input  per BT878A = 4 audio inputs
> > +                *      4 video inputs per BT878A = 16 video inputs
> > +                * The 3 other BT878A chips are "slave" chips of the
> > GV-800(S) +                * and should use this card type.
> > +                * The audio input is not working yet.
> > +                */
> > +               .name           = "Geovision GV-800(S) (slave)",
> > +               .video_inputs   = 4,
> > +               /* .audio_inputs= 1, */
> > +               .tuner_type     = TUNER_ABSENT,
> > +               .tuner_addr     = ADDR_UNSET,
> > +               .svhs           = NO_SVHS,
> > +               .gpiomask       = 0x00,
> > +               .no_gpioirq     = 1,
> > +               .muxsel         = MUXSEL(2, 2, 2, 2),
> > +               .pll            = PLL_28,
> > +               .no_msp34xx     = 1,
> > +               .no_tda7432     = 1,
> > +               .no_tda9875     = 1,
> > +               .muxsel_hook    = gv800s_muxsel,
> > +       },
> >  };
> >
> >  static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
> > @@ -3376,6 +3436,9 @@
> >        case BTTV_BOARD_KODICOM_4400R:
> >                kodicom4400r_init(btv);
> >                break;
> > +       case BTTV_BOARD_GEOVISION_GV800S:
> > +               gv800s_init(btv);
> > +               break;
> >        }
> >
> >        /* pll configuration */
> > @@ -4595,6 +4658,123 @@
> >        gpio_bits(0x3, mux);
> >  }
> >
> > +/*
> > + * GeoVision GV-800(S) functions
> > + * Bruno Christo <bchristo@inf.ufsm.br>
> > +*/
> > +
> > +/* This is a function to control the analog switch, which determines
> > which + * camera is routed to which controller.  The switch comprises an
> > X-address + * (gpio bits 0-3, representing the camera, ranging from
> > 0-15), and a + * Y-address (gpio bits 4-6, representing the controller,
> > ranging from 0-3). + * A data value (gpio bit 18) of '1' enables the
> > switch, and '0' disables + * the switch.  A STROBE bit (gpio bit 17)
> > latches the data value into the + * specified address. There is also a
> > chip select (gpio bit 16). + * The idea is to set the address and chip
> > select together, bring + * STROBE high, write the data, and finally bring
> > STROBE back to low. + */
> > +static void gv800s_write(struct bttv *btv,
> > +                        unsigned char xaddr,
> > +                        unsigned char yaddr,
> > +                        unsigned char data) {
> > +       /* On the "master" 878A:
> > +       * GPIO bits 0-9 are used for the analog switch:
> > +       *   00 - 03:    camera selector
> > +       *   04 - 06:    878A (controller) selector
> > +       *   16:         cselect
> > +       *   17:         strobe
> > +       *   18:         data (1->on, 0->off)
> > +       *   19:         reset
> > +       */
> > +       const u32 ADDR = ((xaddr&0xf) | (yaddr&3)<<4);
> > +       const u32 CSELECT = 1<<16;
> > +       const u32 STROBE = 1<<17;
> > +       const u32 DATA = data<<18;
> > +
> > +       gpio_bits(0x1007f, ADDR | CSELECT);     /* write ADDR and CSELECT
> > */ +       gpio_bits(0x20000, STROBE);             /* STROBE high */ +  
> >     gpio_bits(0x40000, DATA);               /* write DATA */ +      
> > gpio_bits(0x20000, ~STROBE);            /* STROBE low */ +}
> > +
> > +/*
> > + * GeoVision GV-800(S) muxsel
> > + *
> > + * Each of the 4 cards (controllers) use this function.
> > + * The controller using this function selects the input through the GPIO
> > pins + * of the "master" card. A pointer to this card is stored in
> > master[btv->c.nr]. + *
> > + * The parameter 'input' is the requested camera number (0-4) on the
> > controller.
> > + * The map array has the address of each input. Note that the addresses
> > in the + * array are in the sequence the original GeoVision driver uses,
> > that is, set + * every controller to input 0, then to input 1, 2, 3,
> > repeat. This means that + * the physical "camera 1" connector corresponds
> > to controller 0 input 0, + * "camera 2" corresponds to controller 1 input
> > 0, and so on.
> > + *
> > + * After getting the input address, the function then writes the
> > appropriate + * data to the analog switch, and housekeeps the local copy
> > of the switch + * information.
> > + */
> > +static void gv800s_muxsel(struct bttv *btv, unsigned int input)
> > +{
> > +       struct bttv *mctlr;
> > +       char *sw_status;
> > +       int xaddr, yaddr;
> > +       static unsigned int map[4][4] = {{ 0x0, 0x4, 0xa, 0x6 },
> > +                                        { 0x1, 0x5, 0xb, 0x7 },
> > +                                        { 0x2, 0x8, 0xc, 0xe },
> > +                                        { 0x3, 0x9, 0xd, 0xf }};
> > +       input = input%4;
> > +       mctlr = master[btv->c.nr];
> > +       if (mctlr == NULL) {
> > +               // do nothing until the "master" is detected
> > +               return;
> > +       }
> > +       yaddr = (btv->c.nr - mctlr->c.nr) & 3;
> > +       sw_status = (char *)(&mctlr->mbox_we);
> > +       xaddr = map[yaddr][input] & 0xf;
> > +
> > +       // Check if the controller/camera pair has changed, ignore
> > otherwise +       if (sw_status[yaddr] != xaddr)
> > +       {
> > +               // disable the old switch, enable the new one and save
> > status +               gv800s_write(mctlr, sw_status[yaddr], yaddr, 0); +
> >               sw_status[yaddr] = xaddr;
> > +               gv800s_write(mctlr, xaddr, yaddr, 1);
> > +       }
> > +}
> > +
> > +/* GeoVision GV-800(S) "master" chip init */
> > +static void gv800s_init(struct bttv *btv)
> > +{
> > +       char *sw_status = (char *)(&btv->mbox_we);
> > +       int ix;
> > +
> > +       gpio_inout(0xf107f, 0xf107f);
> > +       gpio_write(1<<19); /* reset the analog MUX */
> > +       gpio_write(0);
> > +
> > +       /* Preset camera 0 to the 4 controllers */
> > +       for (ix = 0; ix < 4; ix++) {
> > +               sw_status[ix] = ix;
> > +               gv800s_write(btv, ix, ix, 1);
> > +       }
> > +
> > +       /* Inputs on the "master" controller need this brightness fix */
> > +       bttv_I2CWrite(btv, 0x18, 0x5, 0x90, 1);
> > +
> > +       if (btv->c.nr>BTTV_MAX-4)
> > +           return;
> > +       /*
> > +        * Store the "master" controller pointer in the master
> > +        * array for later use in the muxsel function.
> > +        */
> > +       master[btv->c.nr]   = btv;
> > +       master[btv->c.nr+1] = btv;
> > +       master[btv->c.nr+2] = btv;
> > +       master[btv->c.nr+3] = btv;
> > +}
> > +
> >  /*
> > -----------------------------------------------------------------------
> > */ /* motherboard chipset specific stuff                                
> >      */
> >
> > diff -r c770b20d15c6 linux/drivers/media/video/bt8xx/bttv.h
> > --- a/linux/drivers/media/video/bt8xx/bttv.h    Fri Feb 27 21:29:59 2009
> > -0300 +++ b/linux/drivers/media/video/bt8xx/bttv.h    Fri Feb 27 22:12:29
> > 2009 -0300 @@ -182,6 +182,8 @@
> >  #define BTTV_BOARD_VD012_X1               0x9a
> >  #define BTTV_BOARD_VD012_X2               0x9b
> >  #define BTTV_BOARD_IVCE8784               0x9c
> > +#define BTTV_BOARD_GEOVISION_GV800S       0x9d
> > +#define BTTV_BOARD_GEOVISION_GV800S_SL    0x9e
> >
> >
> >  /* more card-specific defines */
> > --
> > Bruno Christo
> > Bacharel em Ciência da Computação - UFSM
diff mbox

Patch

diff -r c770b20d15c6 linux/drivers/media/video/bt8xx/bttv.h
--- a/linux/drivers/media/video/bt8xx/bttv.h	Fri Feb 27 21:29:59 2009 -0300
+++ b/linux/drivers/media/video/bt8xx/bttv.h	Sat Feb 28 17:09:23 2009 -0300
@@ -182,6 +182,8 @@ 
 #define BTTV_BOARD_VD012_X1		   0x9a
 #define BTTV_BOARD_VD012_X2		   0x9b
 #define BTTV_BOARD_IVCE8784		   0x9c
+#define BTTV_BOARD_GEOVISION_GV800S	   0x9d
+#define BTTV_BOARD_GEOVISION_GV800S_SL	   0x9e


 /* more card-specific defines */