• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/drv-intf/saa7146_vv.h>
29 #include <linux/module.h>
30 
31 static int debug;
32 module_param(debug, int, 0);
33 MODULE_PARM_DESC(debug, "debug verbosity");
34 
35 /* global variables */
36 static 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
43 static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
44 	{ 0, "CVBS 1",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
45 	{ 1, "CVBS 2",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
46 	{ 2, "CVBS 3",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
47 	{ 3, "CVBS 4",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
48 	{ 4, "CVBS 5",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
49 	{ 5, "CVBS 6",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
50 	{ 6, "Y/C 1",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
51 	{ 7, "Y/C 2",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
52 	{ 8, "Y/C 3",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
53 };
54 
55 #define HEXIUM_AUDIOS	0
56 
57 struct hexium_data
58 {
59 	s8 adr;
60 	u8 byte;
61 };
62 
63 struct 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 */
73 static 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 
83 static 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 
188 static 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 */
hexium_probe(struct saa7146_dev * dev)209 static 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 	strscpy(hexium->i2c_adapter.name, "hexium orion",
236 		sizeof(hexium->i2c_adapter.name));
237 	saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
238 	if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
239 		DEB_S("cannot register i2c-device. skipping.\n");
240 		kfree(hexium);
241 		return -EFAULT;
242 	}
243 
244 	/* set SAA7110 control GPIO 0 */
245 	saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI);
246 	/*  set HWControl GPIO number 2 */
247 	saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
248 
249 	mdelay(10);
250 
251 	/* detect newer Hexium Orion cards by subsystem ids */
252 	if (0x17c8 == dev->pci->subsystem_vendor && 0x0101 == dev->pci->subsystem_device) {
253 		pr_info("device is a Hexium Orion w/ 1 SVHS + 3 BNC inputs\n");
254 		/* we store the pointer in our private data field */
255 		dev->ext_priv = hexium;
256 		hexium->type = HEXIUM_ORION_1SVHS_3BNC;
257 		return 0;
258 	}
259 
260 	if (0x17c8 == dev->pci->subsystem_vendor && 0x2101 == dev->pci->subsystem_device) {
261 		pr_info("device is a Hexium Orion w/ 4 BNC inputs\n");
262 		/* we store the pointer in our private data field */
263 		dev->ext_priv = hexium;
264 		hexium->type = HEXIUM_ORION_4BNC;
265 		return 0;
266 	}
267 
268 	/* check if this is an old hexium Orion card by looking at
269 	   a saa7110 at address 0x4e */
270 	if (0 == (err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) {
271 		pr_info("device is a Hexium HV-PCI6/Orion (old)\n");
272 		/* we store the pointer in our private data field */
273 		dev->ext_priv = hexium;
274 		hexium->type = HEXIUM_HV_PCI6_ORION;
275 		return 0;
276 	}
277 
278 	i2c_del_adapter(&hexium->i2c_adapter);
279 	kfree(hexium);
280 	return -EFAULT;
281 }
282 
283 /* bring hardware to a sane state. this has to be done, just in case someone
284    wants to capture from this device before it has been properly initialized.
285    the capture engine would badly fail, because no valid signal arrives on the
286    saa7146, thus leading to timeouts and stuff. */
hexium_init_done(struct saa7146_dev * dev)287 static int hexium_init_done(struct saa7146_dev *dev)
288 {
289 	struct hexium *hexium = (struct hexium *) dev->ext_priv;
290 	union i2c_smbus_data data;
291 	int i = 0;
292 
293 	DEB_D("hexium_init_done called\n");
294 
295 	/* initialize the helper ics to useful values */
296 	for (i = 0; i < sizeof(hexium_saa7110); i++) {
297 		data.byte = hexium_saa7110[i];
298 		if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
299 			pr_err("failed for address 0x%02x\n", i);
300 		}
301 	}
302 
303 	return 0;
304 }
305 
hexium_set_input(struct hexium * hexium,int input)306 static int hexium_set_input(struct hexium *hexium, int input)
307 {
308 	union i2c_smbus_data data;
309 	int i = 0;
310 
311 	DEB_D("\n");
312 
313 	for (i = 0; i < 8; i++) {
314 		int adr = hexium_input_select[input].data[i].adr;
315 		data.byte = hexium_input_select[input].data[i].byte;
316 		if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, adr, I2C_SMBUS_BYTE_DATA, &data)) {
317 			return -1;
318 		}
319 		pr_debug("%d: 0x%02x => 0x%02x\n", input, adr, data.byte);
320 	}
321 
322 	return 0;
323 }
324 
vidioc_enum_input(struct file * file,void * fh,struct v4l2_input * i)325 static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
326 {
327 	DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index);
328 
329 	if (i->index >= HEXIUM_INPUTS)
330 		return -EINVAL;
331 
332 	memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
333 
334 	DEB_D("v4l2_ioctl: VIDIOC_ENUMINPUT %d\n", i->index);
335 	return 0;
336 }
337 
vidioc_g_input(struct file * file,void * fh,unsigned int * input)338 static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
339 {
340 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
341 	struct hexium *hexium = (struct hexium *) dev->ext_priv;
342 
343 	*input = hexium->cur_input;
344 
345 	DEB_D("VIDIOC_G_INPUT: %d\n", *input);
346 	return 0;
347 }
348 
vidioc_s_input(struct file * file,void * fh,unsigned int input)349 static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
350 {
351 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
352 	struct hexium *hexium = (struct hexium *) dev->ext_priv;
353 
354 	if (input >= HEXIUM_INPUTS)
355 		return -EINVAL;
356 
357 	hexium->cur_input = input;
358 	hexium_set_input(hexium, input);
359 
360 	return 0;
361 }
362 
363 static struct saa7146_ext_vv vv_data;
364 
365 /* this function only gets called when the probing was successful */
hexium_attach(struct saa7146_dev * dev,struct saa7146_pci_extension_data * info)366 static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
367 {
368 	struct hexium *hexium = (struct hexium *) dev->ext_priv;
369 
370 	DEB_EE("\n");
371 
372 	saa7146_vv_init(dev, &vv_data);
373 	vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
374 	vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
375 	vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
376 	if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) {
377 		pr_err("cannot register capture v4l2 device. skipping.\n");
378 		return -1;
379 	}
380 
381 	pr_err("found 'hexium orion' frame grabber-%d\n", hexium_num);
382 	hexium_num++;
383 
384 	/* the rest */
385 	hexium->cur_input = 0;
386 	hexium_init_done(dev);
387 
388 	return 0;
389 }
390 
hexium_detach(struct saa7146_dev * dev)391 static int hexium_detach(struct saa7146_dev *dev)
392 {
393 	struct hexium *hexium = (struct hexium *) dev->ext_priv;
394 
395 	DEB_EE("dev:%p\n", dev);
396 
397 	saa7146_unregister_device(&hexium->video_dev, dev);
398 	saa7146_vv_release(dev);
399 
400 	hexium_num--;
401 
402 	i2c_del_adapter(&hexium->i2c_adapter);
403 	kfree(hexium);
404 	return 0;
405 }
406 
std_callback(struct saa7146_dev * dev,struct saa7146_standard * std)407 static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
408 {
409 	return 0;
410 }
411 
412 static struct saa7146_extension extension;
413 
414 static struct saa7146_pci_extension_data hexium_hv_pci6 = {
415 	.ext_priv = "Hexium HV-PCI6 / Orion",
416 	.ext = &extension,
417 };
418 
419 static struct saa7146_pci_extension_data hexium_orion_1svhs_3bnc = {
420 	.ext_priv = "Hexium HV-PCI6 / Orion (1 SVHS/3 BNC)",
421 	.ext = &extension,
422 };
423 
424 static struct saa7146_pci_extension_data hexium_orion_4bnc = {
425 	.ext_priv = "Hexium HV-PCI6 / Orion (4 BNC)",
426 	.ext = &extension,
427 };
428 
429 static const struct pci_device_id pci_tbl[] = {
430 	{
431 	 .vendor = PCI_VENDOR_ID_PHILIPS,
432 	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
433 	 .subvendor = 0x0000,
434 	 .subdevice = 0x0000,
435 	 .driver_data = (unsigned long) &hexium_hv_pci6,
436 	 },
437 	{
438 	 .vendor = PCI_VENDOR_ID_PHILIPS,
439 	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
440 	 .subvendor = 0x17c8,
441 	 .subdevice = 0x0101,
442 	 .driver_data = (unsigned long) &hexium_orion_1svhs_3bnc,
443 	 },
444 	{
445 	 .vendor = PCI_VENDOR_ID_PHILIPS,
446 	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
447 	 .subvendor = 0x17c8,
448 	 .subdevice = 0x2101,
449 	 .driver_data = (unsigned long) &hexium_orion_4bnc,
450 	 },
451 	{
452 	 .vendor = 0,
453 	 }
454 };
455 
456 MODULE_DEVICE_TABLE(pci, pci_tbl);
457 
458 static struct saa7146_ext_vv vv_data = {
459 	.inputs = HEXIUM_INPUTS,
460 	.capabilities = 0,
461 	.stds = &hexium_standards[0],
462 	.num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
463 	.std_callback = &std_callback,
464 };
465 
466 static struct saa7146_extension extension = {
467 	.name = "hexium HV-PCI6 Orion",
468 	.flags = 0,		// SAA7146_USE_I2C_IRQ,
469 
470 	.pci_tbl = &pci_tbl[0],
471 	.module = THIS_MODULE,
472 
473 	.probe = hexium_probe,
474 	.attach = hexium_attach,
475 	.detach = hexium_detach,
476 
477 	.irq_mask = 0,
478 	.irq_func = NULL,
479 };
480 
hexium_init_module(void)481 static int __init hexium_init_module(void)
482 {
483 	if (0 != saa7146_register_extension(&extension)) {
484 		DEB_S("failed to register extension\n");
485 		return -ENODEV;
486 	}
487 
488 	return 0;
489 }
490 
hexium_cleanup_module(void)491 static void __exit hexium_cleanup_module(void)
492 {
493 	saa7146_unregister_extension(&extension);
494 }
495 
496 module_init(hexium_init_module);
497 module_exit(hexium_cleanup_module);
498 
499 MODULE_DESCRIPTION("video4linux-2 driver for Hexium Orion frame grabber cards");
500 MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
501 MODULE_LICENSE("GPL");
502