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 */
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. */
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 
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 
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 
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 
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 */
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 
359 	DEB_EE("\n");
360 
361 	saa7146_vv_init(dev, &vv_data);
362 	vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
363 	vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
364 	vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
365 	if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_VIDEO)) {
366 		pr_err("cannot register capture v4l2 device. skipping.\n");
367 		return -1;
368 	}
369 
370 	pr_err("found 'hexium orion' frame grabber-%d\n", hexium_num);
371 	hexium_num++;
372 
373 	/* the rest */
374 	hexium->cur_input = 0;
375 	hexium_init_done(dev);
376 
377 	return 0;
378 }
379 
380 static int hexium_detach(struct saa7146_dev *dev)
381 {
382 	struct hexium *hexium = (struct hexium *) dev->ext_priv;
383 
384 	DEB_EE("dev:%p\n", dev);
385 
386 	saa7146_unregister_device(&hexium->video_dev, dev);
387 	saa7146_vv_release(dev);
388 
389 	hexium_num--;
390 
391 	i2c_del_adapter(&hexium->i2c_adapter);
392 	kfree(hexium);
393 	return 0;
394 }
395 
396 static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
397 {
398 	return 0;
399 }
400 
401 static struct saa7146_extension extension;
402 
403 static struct saa7146_pci_extension_data hexium_hv_pci6 = {
404 	.ext_priv = "Hexium HV-PCI6 / Orion",
405 	.ext = &extension,
406 };
407 
408 static struct saa7146_pci_extension_data hexium_orion_1svhs_3bnc = {
409 	.ext_priv = "Hexium HV-PCI6 / Orion (1 SVHS/3 BNC)",
410 	.ext = &extension,
411 };
412 
413 static struct saa7146_pci_extension_data hexium_orion_4bnc = {
414 	.ext_priv = "Hexium HV-PCI6 / Orion (4 BNC)",
415 	.ext = &extension,
416 };
417 
418 static const struct pci_device_id pci_tbl[] = {
419 	{
420 	 .vendor = PCI_VENDOR_ID_PHILIPS,
421 	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
422 	 .subvendor = 0x0000,
423 	 .subdevice = 0x0000,
424 	 .driver_data = (unsigned long) &hexium_hv_pci6,
425 	 },
426 	{
427 	 .vendor = PCI_VENDOR_ID_PHILIPS,
428 	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
429 	 .subvendor = 0x17c8,
430 	 .subdevice = 0x0101,
431 	 .driver_data = (unsigned long) &hexium_orion_1svhs_3bnc,
432 	 },
433 	{
434 	 .vendor = PCI_VENDOR_ID_PHILIPS,
435 	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
436 	 .subvendor = 0x17c8,
437 	 .subdevice = 0x2101,
438 	 .driver_data = (unsigned long) &hexium_orion_4bnc,
439 	 },
440 	{
441 	 .vendor = 0,
442 	 }
443 };
444 
445 MODULE_DEVICE_TABLE(pci, pci_tbl);
446 
447 static struct saa7146_ext_vv vv_data = {
448 	.inputs = HEXIUM_INPUTS,
449 	.capabilities = 0,
450 	.stds = &hexium_standards[0],
451 	.num_stds = ARRAY_SIZE(hexium_standards),
452 	.std_callback = &std_callback,
453 };
454 
455 static struct saa7146_extension extension = {
456 	.name = "hexium HV-PCI6 Orion",
457 	.flags = 0,		// SAA7146_USE_I2C_IRQ,
458 
459 	.pci_tbl = &pci_tbl[0],
460 	.module = THIS_MODULE,
461 
462 	.probe = hexium_probe,
463 	.attach = hexium_attach,
464 	.detach = hexium_detach,
465 
466 	.irq_mask = 0,
467 	.irq_func = NULL,
468 };
469 
470 static int __init hexium_init_module(void)
471 {
472 	if (0 != saa7146_register_extension(&extension)) {
473 		DEB_S("failed to register extension\n");
474 		return -ENODEV;
475 	}
476 
477 	return 0;
478 }
479 
480 static void __exit hexium_cleanup_module(void)
481 {
482 	saa7146_unregister_extension(&extension);
483 }
484 
485 module_init(hexium_init_module);
486 module_exit(hexium_cleanup_module);
487 
488 MODULE_DESCRIPTION("video4linux-2 driver for Hexium Orion frame grabber cards");
489 MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
490 MODULE_LICENSE("GPL");
491