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