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