1/*
2    hexium_orion.c - v4l2 driver for the Hexium Orion frame grabber cards
3
4    Visit http://www.mihu.de/linux/saa7146/ and follow the link
5    to "hexium" for further details about this card.
6
7    Copyright (C) 2003 Michael Hunold <michael@mihu.de>
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*/
23
24#define DEBUG_VARIABLE debug
25
26#include <media/saa7146_vv.h>
27
28static int debug = 0;
29module_param(debug, int, 0);
30MODULE_PARM_DESC(debug, "debug verbosity");
31
32/* global variables */
33static int hexium_num = 0;
34
35#define HEXIUM_HV_PCI6_ORION		1
36#define HEXIUM_ORION_1SVHS_3BNC		2
37#define HEXIUM_ORION_4BNC		3
38
39#define HEXIUM_INPUTS	9
40static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
41	{ 0, "CVBS 1",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
42	{ 1, "CVBS 2",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
43	{ 2, "CVBS 3",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
44	{ 3, "CVBS 4",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
45	{ 4, "CVBS 5",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
46	{ 5, "CVBS 6",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
47	{ 6, "Y/C 1",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
48	{ 7, "Y/C 2",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
49	{ 8, "Y/C 3",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
50};
51
52#define HEXIUM_AUDIOS	0
53
54struct hexium_data
55{
56	s8 adr;
57	u8 byte;
58};
59
60static struct saa7146_extension_ioctls ioctls[] = {
61	{ VIDIOC_G_INPUT,	SAA7146_EXCLUSIVE },
62	{ VIDIOC_S_INPUT,	SAA7146_EXCLUSIVE },
63	{ VIDIOC_ENUMINPUT, 	SAA7146_EXCLUSIVE },
64	{ VIDIOC_S_STD,		SAA7146_AFTER },
65	{ 0,			0 }
66};
67
68struct hexium
69{
70	int type;
71	struct video_device	*video_dev;
72	struct i2c_adapter	i2c_adapter;
73
74	int cur_input;	/* current input */
75};
76
77/* Philips SAA7110 decoder default registers */
78static u8 hexium_saa7110[53]={
79/*00*/ 0x4C,0x3C,0x0D,0xEF,0xBD,0xF0,0x00,0x00,
80/*08*/ 0xF8,0xF8,0x60,0x60,0x40,0x86,0x18,0x90,
81/*10*/ 0x00,0x2C,0x40,0x46,0x42,0x1A,0xFF,0xDA,
82/*18*/ 0xF0,0x8B,0x00,0x00,0x00,0x00,0x00,0x00,
83/*20*/ 0xD9,0x17,0x40,0x41,0x80,0x41,0x80,0x4F,
84/*28*/ 0xFE,0x01,0x0F,0x0F,0x03,0x01,0x81,0x03,
85/*30*/ 0x44,0x75,0x01,0x8C,0x03
86};
87
88static struct {
89	struct hexium_data data[8];
90} hexium_input_select[] = {
91{
92	{ /* cvbs 1 */
93		{ 0x06, 0x00 },
94		{ 0x20, 0xD9 },
95		{ 0x21, 0x17 }, // 0x16,
96		{ 0x22, 0x40 },
97		{ 0x2C, 0x03 },
98		{ 0x30, 0x44 },
99		{ 0x31, 0x75 }, // ??
100		{ 0x21, 0x16 }, // 0x03,
101	}
102}, {
103	{ /* cvbs 2 */
104		{ 0x06, 0x00 },
105		{ 0x20, 0x78 },
106		{ 0x21, 0x07 }, // 0x03,
107		{ 0x22, 0xD2 },
108		{ 0x2C, 0x83 },
109		{ 0x30, 0x60 },
110		{ 0x31, 0xB5 }, // ?
111		{ 0x21, 0x03 },
112	}
113}, {
114	{ /* cvbs 3 */
115		{ 0x06, 0x00 },
116		{ 0x20, 0xBA },
117		{ 0x21, 0x07 }, // 0x05,
118		{ 0x22, 0x91 },
119		{ 0x2C, 0x03 },
120		{ 0x30, 0x60 },
121		{ 0x31, 0xB5 }, // ??
122		{ 0x21, 0x05 }, // 0x03,
123	}
124}, {
125	{ /* cvbs 4 */
126		{ 0x06, 0x00 },
127		{ 0x20, 0xD8 },
128		{ 0x21, 0x17 }, // 0x16,
129		{ 0x22, 0x40 },
130		{ 0x2C, 0x03 },
131		{ 0x30, 0x44 },
132		{ 0x31, 0x75 }, // ??
133		{ 0x21, 0x16 }, // 0x03,
134	}
135}, {
136	{ /* cvbs 5 */
137		{ 0x06, 0x00 },
138		{ 0x20, 0xB8 },
139		{ 0x21, 0x07 }, // 0x05,
140		{ 0x22, 0x91 },
141		{ 0x2C, 0x03 },
142		{ 0x30, 0x60 },
143		{ 0x31, 0xB5 }, // ??
144		{ 0x21, 0x05 }, // 0x03,
145	}
146}, {
147	{ /* cvbs 6 */
148		{ 0x06, 0x00 },
149		{ 0x20, 0x7C },
150		{ 0x21, 0x07 }, // 0x03
151		{ 0x22, 0xD2 },
152		{ 0x2C, 0x83 },
153		{ 0x30, 0x60 },
154		{ 0x31, 0xB5 }, // ??
155		{ 0x21, 0x03 },
156	}
157}, {
158	{ /* y/c 1 */
159		{ 0x06, 0x80 },
160		{ 0x20, 0x59 },
161		{ 0x21, 0x17 },
162		{ 0x22, 0x42 },
163		{ 0x2C, 0xA3 },
164		{ 0x30, 0x44 },
165		{ 0x31, 0x75 },
166		{ 0x21, 0x12 },
167	}
168}, {
169	{ /* y/c 2 */
170		{ 0x06, 0x80 },
171		{ 0x20, 0x9A },
172		{ 0x21, 0x17 },
173		{ 0x22, 0xB1 },
174		{ 0x2C, 0x13 },
175		{ 0x30, 0x60 },
176		{ 0x31, 0xB5 },
177		{ 0x21, 0x14 },
178	}
179}, {
180	{ /* y/c 3 */
181		{ 0x06, 0x80 },
182		{ 0x20, 0x3C },
183		{ 0x21, 0x27 },
184		{ 0x22, 0xC1 },
185		{ 0x2C, 0x23 },
186		{ 0x30, 0x44 },
187		{ 0x31, 0x75 },
188		{ 0x21, 0x21 },
189	}
190}
191};
192
193static struct saa7146_standard hexium_standards[] = {
194	{
195		.name	= "PAL", 	.id	= V4L2_STD_PAL,
196		.v_offset	= 16,	.v_field 	= 288,
197		.h_offset	= 1,	.h_pixels 	= 680,
198		.v_max_out	= 576,	.h_max_out	= 768,
199	}, {
200		.name	= "NTSC", 	.id	= V4L2_STD_NTSC,
201		.v_offset	= 16,	.v_field 	= 240,
202		.h_offset	= 1,	.h_pixels 	= 640,
203		.v_max_out	= 480,	.h_max_out	= 640,
204	}, {
205		.name	= "SECAM", 	.id	= V4L2_STD_SECAM,
206		.v_offset	= 16,	.v_field 	= 288,
207		.h_offset	= 1,	.h_pixels 	= 720,
208		.v_max_out	= 576,	.h_max_out	= 768,
209	}
210};
211
212/* this is only called for old HV-PCI6/Orion cards
213   without eeprom */
214static int hexium_probe(struct saa7146_dev *dev)
215{
216	struct hexium *hexium = NULL;
217	union i2c_smbus_data data;
218	int err = 0;
219
220	DEB_EE((".\n"));
221
222	/* there are no hexium orion cards with revision 0 saa7146s */
223	if (0 == dev->revision) {
224		return -EFAULT;
225	}
226
227	hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
228	if (NULL == hexium) {
229		printk("hexium_orion: hexium_probe: not enough kernel memory.\n");
230		return -ENOMEM;
231	}
232
233	/* enable i2c-port pins */
234	saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
235
236	saa7146_write(dev, DD1_INIT, 0x01000100);
237	saa7146_write(dev, DD1_STREAM_B, 0x00000000);
238	saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
239
240	hexium->i2c_adapter = (struct i2c_adapter) {
241		.class = I2C_CLASS_TV_ANALOG,
242		.name = "hexium orion",
243	};
244	saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
245	if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
246		DEB_S(("cannot register i2c-device. skipping.\n"));
247		kfree(hexium);
248		return -EFAULT;
249	}
250
251	/* set SAA7110 control GPIO 0 */
252	saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI);
253	/*  set HWControl GPIO number 2 */
254	saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
255
256	mdelay(10);
257
258	/* detect newer Hexium Orion cards by subsystem ids */
259	if (0x17c8 == dev->pci->subsystem_vendor && 0x0101 == dev->pci->subsystem_device) {
260		printk("hexium_orion: device is a Hexium Orion w/ 1 SVHS + 3 BNC inputs.\n");
261		/* we store the pointer in our private data field */
262		dev->ext_priv = hexium;
263		hexium->type = HEXIUM_ORION_1SVHS_3BNC;
264		return 0;
265	}
266
267	if (0x17c8 == dev->pci->subsystem_vendor && 0x2101 == dev->pci->subsystem_device) {
268		printk("hexium_orion: device is a Hexium Orion w/ 4 BNC inputs.\n");
269		/* we store the pointer in our private data field */
270		dev->ext_priv = hexium;
271		hexium->type = HEXIUM_ORION_4BNC;
272		return 0;
273	}
274
275	/* check if this is an old hexium Orion card by looking at
276	   a saa7110 at address 0x4e */
277	if (0 == (err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) {
278		printk("hexium_orion: device is a Hexium HV-PCI6/Orion (old).\n");
279		/* we store the pointer in our private data field */
280		dev->ext_priv = hexium;
281		hexium->type = HEXIUM_HV_PCI6_ORION;
282		return 0;
283	}
284
285	i2c_del_adapter(&hexium->i2c_adapter);
286	kfree(hexium);
287	return -EFAULT;
288}
289
290/* bring hardware to a sane state. this has to be done, just in case someone
291   wants to capture from this device before it has been properly initialized.
292   the capture engine would badly fail, because no valid signal arrives on the
293   saa7146, thus leading to timeouts and stuff. */
294static int hexium_init_done(struct saa7146_dev *dev)
295{
296	struct hexium *hexium = (struct hexium *) dev->ext_priv;
297	union i2c_smbus_data data;
298	int i = 0;
299
300	DEB_D(("hexium_init_done called.\n"));
301
302	/* initialize the helper ics to useful values */
303	for (i = 0; i < sizeof(hexium_saa7110); i++) {
304		data.byte = hexium_saa7110[i];
305		if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
306			printk("hexium_orion: failed for address 0x%02x\n", i);
307		}
308	}
309
310	return 0;
311}
312
313static int hexium_set_input(struct hexium *hexium, int input)
314{
315	union i2c_smbus_data data;
316	int i = 0;
317
318	DEB_D((".\n"));
319
320	for (i = 0; i < 8; i++) {
321		int adr = hexium_input_select[input].data[i].adr;
322		data.byte = hexium_input_select[input].data[i].byte;
323		if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, adr, I2C_SMBUS_BYTE_DATA, &data)) {
324			return -1;
325		}
326		printk("%d: 0x%02x => 0x%02x\n",input, adr,data.byte);
327	}
328
329	return 0;
330}
331
332static struct saa7146_ext_vv vv_data;
333
334/* this function only gets called when the probing was successful */
335static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
336{
337	struct hexium *hexium = (struct hexium *) dev->ext_priv;
338
339	DEB_EE((".\n"));
340
341	saa7146_vv_init(dev, &vv_data);
342	if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) {
343		printk("hexium_orion: cannot register capture v4l2 device. skipping.\n");
344		return -1;
345	}
346
347	printk("hexium_orion: found 'hexium orion' frame grabber-%d.\n", hexium_num);
348	hexium_num++;
349
350	/* the rest */
351	hexium->cur_input = 0;
352	hexium_init_done(dev);
353
354	return 0;
355}
356
357static int hexium_detach(struct saa7146_dev *dev)
358{
359	struct hexium *hexium = (struct hexium *) dev->ext_priv;
360
361	DEB_EE(("dev:%p\n", dev));
362
363	saa7146_unregister_device(&hexium->video_dev, dev);
364	saa7146_vv_release(dev);
365
366	hexium_num--;
367
368	i2c_del_adapter(&hexium->i2c_adapter);
369	kfree(hexium);
370	return 0;
371}
372
373static int hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
374{
375	struct saa7146_dev *dev = fh->dev;
376	struct hexium *hexium = (struct hexium *) dev->ext_priv;
377/*
378	struct saa7146_vv *vv = dev->vv_data;
379*/
380	switch (cmd) {
381	case VIDIOC_ENUMINPUT:
382		{
383			struct v4l2_input *i = arg;
384			DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
385
386			if (i->index < 0 || i->index >= HEXIUM_INPUTS) {
387				return -EINVAL;
388			}
389
390			memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
391
392			DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
393			return 0;
394		}
395	case VIDIOC_G_INPUT:
396		{
397			int *input = (int *) arg;
398			*input = hexium->cur_input;
399
400			DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
401			return 0;
402		}
403	case VIDIOC_S_INPUT:
404		{
405			int input = *(int *) arg;
406
407			if (input < 0 || input >= HEXIUM_INPUTS) {
408				return -EINVAL;
409			}
410
411			hexium->cur_input = input;
412			hexium_set_input(hexium, input);
413
414			return 0;
415		}
416	default:
417/*
418		DEB_D(("hexium_ioctl() does not handle this ioctl.\n"));
419*/
420		return -ENOIOCTLCMD;
421	}
422	return 0;
423}
424
425static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
426{
427	return 0;
428}
429
430static struct saa7146_extension extension;
431
432static struct saa7146_pci_extension_data hexium_hv_pci6 = {
433	.ext_priv = "Hexium HV-PCI6 / Orion",
434	.ext = &extension,
435};
436
437static struct saa7146_pci_extension_data hexium_orion_1svhs_3bnc = {
438	.ext_priv = "Hexium HV-PCI6 / Orion (1 SVHS/3 BNC)",
439	.ext = &extension,
440};
441
442static struct saa7146_pci_extension_data hexium_orion_4bnc = {
443	.ext_priv = "Hexium HV-PCI6 / Orion (4 BNC)",
444	.ext = &extension,
445};
446
447static struct pci_device_id pci_tbl[] = {
448	{
449	 .vendor = PCI_VENDOR_ID_PHILIPS,
450	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
451	 .subvendor = 0x0000,
452	 .subdevice = 0x0000,
453	 .driver_data = (unsigned long) &hexium_hv_pci6,
454	 },
455	{
456	 .vendor = PCI_VENDOR_ID_PHILIPS,
457	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
458	 .subvendor = 0x17c8,
459	 .subdevice = 0x0101,
460	 .driver_data = (unsigned long) &hexium_orion_1svhs_3bnc,
461	 },
462	{
463	 .vendor = PCI_VENDOR_ID_PHILIPS,
464	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
465	 .subvendor = 0x17c8,
466	 .subdevice = 0x2101,
467	 .driver_data = (unsigned long) &hexium_orion_4bnc,
468	 },
469	{
470	 .vendor = 0,
471	 }
472};
473
474MODULE_DEVICE_TABLE(pci, pci_tbl);
475
476static struct saa7146_ext_vv vv_data = {
477	.inputs = HEXIUM_INPUTS,
478	.capabilities = 0,
479	.stds = &hexium_standards[0],
480	.num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
481	.std_callback = &std_callback,
482	.ioctls = &ioctls[0],
483	.ioctl = hexium_ioctl,
484};
485
486static struct saa7146_extension extension = {
487	.name = "hexium HV-PCI6 Orion",
488	.flags = 0,		// SAA7146_USE_I2C_IRQ,
489
490	.pci_tbl = &pci_tbl[0],
491	.module = THIS_MODULE,
492
493	.probe = hexium_probe,
494	.attach = hexium_attach,
495	.detach = hexium_detach,
496
497	.irq_mask = 0,
498	.irq_func = NULL,
499};
500
501static int __init hexium_init_module(void)
502{
503	if (0 != saa7146_register_extension(&extension)) {
504		DEB_S(("failed to register extension.\n"));
505		return -ENODEV;
506	}
507
508	return 0;
509}
510
511static void __exit hexium_cleanup_module(void)
512{
513	saa7146_unregister_extension(&extension);
514}
515
516module_init(hexium_init_module);
517module_exit(hexium_cleanup_module);
518
519MODULE_DESCRIPTION("video4linux-2 driver for Hexium Orion frame grabber cards");
520MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
521MODULE_LICENSE("GPL");
522