1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3     hexium_gemini.c - v4l2 driver for Hexium Gemini 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_GEMINI			4
28 #define HEXIUM_GEMINI_DUAL		5
29 
30 #define HEXIUM_INPUTS	9
31 static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
32 	{ 0, "CVBS 1",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
33 	{ 1, "CVBS 2",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
34 	{ 2, "CVBS 3",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
35 	{ 3, "CVBS 4",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
36 	{ 4, "CVBS 5",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
37 	{ 5, "CVBS 6",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
38 	{ 6, "Y/C 1",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
39 	{ 7, "Y/C 2",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
40 	{ 8, "Y/C 3",	V4L2_INPUT_TYPE_CAMERA,	0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
41 };
42 
43 #define HEXIUM_AUDIOS	0
44 
45 struct hexium_data
46 {
47 	s8 adr;
48 	u8 byte;
49 };
50 
51 #define HEXIUM_GEMINI_V_1_0		1
52 #define HEXIUM_GEMINI_DUAL_V_1_0	2
53 
54 struct hexium
55 {
56 	int type;
57 
58 	struct video_device	video_dev;
59 	struct i2c_adapter	i2c_adapter;
60 
61 	int		cur_input;	/* current input */
62 	v4l2_std_id	cur_std;	/* current standard */
63 };
64 
65 /* Samsung KS0127B decoder default registers */
66 static u8 hexium_ks0127b[0x100]={
67 /*00*/ 0x00,0x52,0x30,0x40,0x01,0x0C,0x2A,0x10,
68 /*08*/ 0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x06,
69 /*10*/ 0x00,0x00,0xE4,0xC0,0x00,0x00,0x00,0x00,
70 /*18*/ 0x14,0x9B,0xFE,0xFF,0xFC,0xFF,0x03,0x22,
71 /*20*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
72 /*28*/ 0x00,0x00,0x00,0x00,0x00,0x2C,0x9B,0x00,
73 /*30*/ 0x00,0x00,0x10,0x80,0x80,0x10,0x80,0x80,
74 /*38*/ 0x01,0x04,0x00,0x00,0x00,0x29,0xC0,0x00,
75 /*40*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
76 /*48*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
77 /*50*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
78 /*58*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
79 /*60*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
80 /*68*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
81 /*70*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
82 /*78*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
83 /*80*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
84 /*88*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
85 /*90*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
86 /*98*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
87 /*A0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
88 /*A8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
89 /*B0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
90 /*B8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
91 /*C0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
92 /*C8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
93 /*D0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
94 /*D8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
95 /*E0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
96 /*E8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
97 /*F0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
98 /*F8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
99 };
100 
101 static struct hexium_data hexium_pal[] = {
102 	{ 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
103 };
104 
105 static struct hexium_data hexium_ntsc[] = {
106 	{ 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
107 };
108 
109 static struct hexium_data hexium_secam[] = {
110 	{ 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
111 };
112 
113 static struct hexium_data hexium_input_select[] = {
114 	{ 0x02, 0x60 },
115 	{ 0x02, 0x64 },
116 	{ 0x02, 0x61 },
117 	{ 0x02, 0x65 },
118 	{ 0x02, 0x62 },
119 	{ 0x02, 0x66 },
120 	{ 0x02, 0x68 },
121 	{ 0x02, 0x69 },
122 	{ 0x02, 0x6A },
123 };
124 
125 /* fixme: h_offset = 0 for Hexium Gemini *Dual*, which
126    are currently *not* supported*/
127 static struct saa7146_standard hexium_standards[] = {
128 	{
129 		.name	= "PAL",	.id	= V4L2_STD_PAL,
130 		.v_offset	= 28,	.v_field	= 288,
131 		.h_offset	= 1,	.h_pixels	= 680,
132 		.v_max_out	= 576,	.h_max_out	= 768,
133 	}, {
134 		.name	= "NTSC",	.id	= V4L2_STD_NTSC,
135 		.v_offset	= 28,	.v_field	= 240,
136 		.h_offset	= 1,	.h_pixels	= 640,
137 		.v_max_out	= 480,	.h_max_out	= 640,
138 	}, {
139 		.name	= "SECAM",	.id	= V4L2_STD_SECAM,
140 		.v_offset	= 28,	.v_field	= 288,
141 		.h_offset	= 1,	.h_pixels	= 720,
142 		.v_max_out	= 576,	.h_max_out	= 768,
143 	}
144 };
145 
146 /* bring hardware to a sane state. this has to be done, just in case someone
147    wants to capture from this device before it has been properly initialized.
148    the capture engine would badly fail, because no valid signal arrives on the
149    saa7146, thus leading to timeouts and stuff. */
150 static int hexium_init_done(struct saa7146_dev *dev)
151 {
152 	struct hexium *hexium = (struct hexium *) dev->ext_priv;
153 	union i2c_smbus_data data;
154 	int i = 0;
155 
156 	DEB_D("hexium_init_done called\n");
157 
158 	/* initialize the helper ics to useful values */
159 	for (i = 0; i < sizeof(hexium_ks0127b); i++) {
160 		data.byte = hexium_ks0127b[i];
161 		if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
162 			pr_err("hexium_init_done() failed for address 0x%02x\n",
163 			       i);
164 		}
165 	}
166 
167 	return 0;
168 }
169 
170 static int hexium_set_input(struct hexium *hexium, int input)
171 {
172 	union i2c_smbus_data data;
173 
174 	DEB_D("\n");
175 
176 	data.byte = hexium_input_select[input].byte;
177 	if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, hexium_input_select[input].adr, I2C_SMBUS_BYTE_DATA, &data)) {
178 		return -1;
179 	}
180 
181 	return 0;
182 }
183 
184 static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec)
185 {
186 	union i2c_smbus_data data;
187 	int i = 0;
188 
189 	DEB_D("\n");
190 
191 	while (vdec[i].adr != -1) {
192 		data.byte = vdec[i].byte;
193 		if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, vdec[i].adr, I2C_SMBUS_BYTE_DATA, &data)) {
194 			pr_err("hexium_init_done: hexium_set_standard() failed for address 0x%02x\n",
195 			       i);
196 			return -1;
197 		}
198 		i++;
199 	}
200 	return 0;
201 }
202 
203 static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
204 {
205 	DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index);
206 
207 	if (i->index >= HEXIUM_INPUTS)
208 		return -EINVAL;
209 
210 	memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
211 
212 	DEB_D("v4l2_ioctl: VIDIOC_ENUMINPUT %d\n", i->index);
213 	return 0;
214 }
215 
216 static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
217 {
218 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
219 	struct hexium *hexium = (struct hexium *) dev->ext_priv;
220 
221 	*input = hexium->cur_input;
222 
223 	DEB_D("VIDIOC_G_INPUT: %d\n", *input);
224 	return 0;
225 }
226 
227 static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
228 {
229 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
230 	struct hexium *hexium = (struct hexium *) dev->ext_priv;
231 
232 	DEB_EE("VIDIOC_S_INPUT %d\n", input);
233 
234 	if (input >= HEXIUM_INPUTS)
235 		return -EINVAL;
236 
237 	hexium->cur_input = input;
238 	hexium_set_input(hexium, input);
239 	return 0;
240 }
241 
242 static struct saa7146_ext_vv vv_data;
243 
244 /* this function only gets called when the probing was successful */
245 static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
246 {
247 	struct hexium *hexium;
248 	int ret;
249 
250 	DEB_EE("\n");
251 
252 	hexium = kzalloc(sizeof(*hexium), GFP_KERNEL);
253 	if (!hexium)
254 		return -ENOMEM;
255 
256 	dev->ext_priv = hexium;
257 
258 	/* enable i2c-port pins */
259 	saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
260 
261 	strscpy(hexium->i2c_adapter.name, "hexium gemini",
262 		sizeof(hexium->i2c_adapter.name));
263 	saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
264 	if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
265 		DEB_S("cannot register i2c-device. skipping.\n");
266 		kfree(hexium);
267 		return -EFAULT;
268 	}
269 
270 	/*  set HWControl GPIO number 2 */
271 	saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
272 
273 	saa7146_write(dev, DD1_INIT, 0x07000700);
274 	saa7146_write(dev, DD1_STREAM_B, 0x00000000);
275 	saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
276 
277 	/* the rest */
278 	hexium->cur_input = 0;
279 	hexium_init_done(dev);
280 
281 	hexium_set_standard(hexium, hexium_pal);
282 	hexium->cur_std = V4L2_STD_PAL;
283 
284 	hexium_set_input(hexium, 0);
285 	hexium->cur_input = 0;
286 
287 	saa7146_vv_init(dev, &vv_data);
288 
289 	vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
290 	vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
291 	vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
292 	ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER);
293 	if (ret < 0) {
294 		pr_err("cannot register capture v4l2 device. skipping.\n");
295 		saa7146_vv_release(dev);
296 		i2c_del_adapter(&hexium->i2c_adapter);
297 		kfree(hexium);
298 		return ret;
299 	}
300 
301 	pr_info("found 'hexium gemini' frame grabber-%d\n", hexium_num);
302 	hexium_num++;
303 
304 	return 0;
305 }
306 
307 static int hexium_detach(struct saa7146_dev *dev)
308 {
309 	struct hexium *hexium = (struct hexium *) dev->ext_priv;
310 
311 	DEB_EE("dev:%p\n", dev);
312 
313 	saa7146_unregister_device(&hexium->video_dev, dev);
314 	saa7146_vv_release(dev);
315 
316 	hexium_num--;
317 
318 	i2c_del_adapter(&hexium->i2c_adapter);
319 	kfree(hexium);
320 	return 0;
321 }
322 
323 static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
324 {
325 	struct hexium *hexium = (struct hexium *) dev->ext_priv;
326 
327 	if (V4L2_STD_PAL == std->id) {
328 		hexium_set_standard(hexium, hexium_pal);
329 		hexium->cur_std = V4L2_STD_PAL;
330 		return 0;
331 	} else if (V4L2_STD_NTSC == std->id) {
332 		hexium_set_standard(hexium, hexium_ntsc);
333 		hexium->cur_std = V4L2_STD_NTSC;
334 		return 0;
335 	} else if (V4L2_STD_SECAM == std->id) {
336 		hexium_set_standard(hexium, hexium_secam);
337 		hexium->cur_std = V4L2_STD_SECAM;
338 		return 0;
339 	}
340 
341 	return -1;
342 }
343 
344 static struct saa7146_extension hexium_extension;
345 
346 static struct saa7146_pci_extension_data hexium_gemini_4bnc = {
347 	.ext_priv = "Hexium Gemini (4 BNC)",
348 	.ext = &hexium_extension,
349 };
350 
351 static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = {
352 	.ext_priv = "Hexium Gemini Dual (4 BNC)",
353 	.ext = &hexium_extension,
354 };
355 
356 static const struct pci_device_id pci_tbl[] = {
357 	{
358 	 .vendor = PCI_VENDOR_ID_PHILIPS,
359 	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
360 	 .subvendor = 0x17c8,
361 	 .subdevice = 0x2401,
362 	 .driver_data = (unsigned long) &hexium_gemini_4bnc,
363 	 },
364 	{
365 	 .vendor = PCI_VENDOR_ID_PHILIPS,
366 	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
367 	 .subvendor = 0x17c8,
368 	 .subdevice = 0x2402,
369 	 .driver_data = (unsigned long) &hexium_gemini_dual_4bnc,
370 	 },
371 	{
372 	 .vendor = 0,
373 	 }
374 };
375 
376 MODULE_DEVICE_TABLE(pci, pci_tbl);
377 
378 static struct saa7146_ext_vv vv_data = {
379 	.inputs = HEXIUM_INPUTS,
380 	.capabilities = 0,
381 	.stds = &hexium_standards[0],
382 	.num_stds = ARRAY_SIZE(hexium_standards),
383 	.std_callback = &std_callback,
384 };
385 
386 static struct saa7146_extension hexium_extension = {
387 	.name = "hexium gemini",
388 	.flags = SAA7146_USE_I2C_IRQ,
389 
390 	.pci_tbl = &pci_tbl[0],
391 	.module = THIS_MODULE,
392 
393 	.attach = hexium_attach,
394 	.detach = hexium_detach,
395 
396 	.irq_mask = 0,
397 	.irq_func = NULL,
398 };
399 
400 static int __init hexium_init_module(void)
401 {
402 	if (0 != saa7146_register_extension(&hexium_extension)) {
403 		DEB_S("failed to register extension\n");
404 		return -ENODEV;
405 	}
406 
407 	return 0;
408 }
409 
410 static void __exit hexium_cleanup_module(void)
411 {
412 	saa7146_unregister_extension(&hexium_extension);
413 }
414 
415 module_init(hexium_init_module);
416 module_exit(hexium_cleanup_module);
417 
418 MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards");
419 MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
420 MODULE_LICENSE("GPL");
421