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