xref: /linux/drivers/media/pci/saa7146/hexium_gemini.c (revision a544684b790f3e9f75173b3b42d7dad1c89dd237)
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 	ret = saa7146_vv_init(dev, &vv_data);
288 	if (ret) {
289 		i2c_del_adapter(&hexium->i2c_adapter);
290 		kfree(hexium);
291 		return ret;
292 	}
293 
294 	vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
295 	vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
296 	vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
297 	ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_VIDEO);
298 	if (ret < 0) {
299 		pr_err("cannot register capture v4l2 device. skipping.\n");
300 		saa7146_vv_release(dev);
301 		i2c_del_adapter(&hexium->i2c_adapter);
302 		kfree(hexium);
303 		return ret;
304 	}
305 
306 	pr_info("found 'hexium gemini' frame grabber-%d\n", hexium_num);
307 	hexium_num++;
308 
309 	return 0;
310 }
311 
312 static int hexium_detach(struct saa7146_dev *dev)
313 {
314 	struct hexium *hexium = (struct hexium *) dev->ext_priv;
315 
316 	DEB_EE("dev:%p\n", dev);
317 
318 	saa7146_unregister_device(&hexium->video_dev, dev);
319 	saa7146_vv_release(dev);
320 
321 	hexium_num--;
322 
323 	i2c_del_adapter(&hexium->i2c_adapter);
324 	kfree(hexium);
325 	return 0;
326 }
327 
328 static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
329 {
330 	struct hexium *hexium = (struct hexium *) dev->ext_priv;
331 
332 	if (V4L2_STD_PAL == std->id) {
333 		hexium_set_standard(hexium, hexium_pal);
334 		hexium->cur_std = V4L2_STD_PAL;
335 		return 0;
336 	} else if (V4L2_STD_NTSC == std->id) {
337 		hexium_set_standard(hexium, hexium_ntsc);
338 		hexium->cur_std = V4L2_STD_NTSC;
339 		return 0;
340 	} else if (V4L2_STD_SECAM == std->id) {
341 		hexium_set_standard(hexium, hexium_secam);
342 		hexium->cur_std = V4L2_STD_SECAM;
343 		return 0;
344 	}
345 
346 	return -1;
347 }
348 
349 static struct saa7146_extension hexium_extension;
350 
351 static struct saa7146_pci_extension_data hexium_gemini_4bnc = {
352 	.ext_priv = "Hexium Gemini (4 BNC)",
353 	.ext = &hexium_extension,
354 };
355 
356 static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = {
357 	.ext_priv = "Hexium Gemini Dual (4 BNC)",
358 	.ext = &hexium_extension,
359 };
360 
361 static const struct pci_device_id pci_tbl[] = {
362 	{
363 	 .vendor = PCI_VENDOR_ID_PHILIPS,
364 	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
365 	 .subvendor = 0x17c8,
366 	 .subdevice = 0x2401,
367 	 .driver_data = (unsigned long) &hexium_gemini_4bnc,
368 	 },
369 	{
370 	 .vendor = PCI_VENDOR_ID_PHILIPS,
371 	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
372 	 .subvendor = 0x17c8,
373 	 .subdevice = 0x2402,
374 	 .driver_data = (unsigned long) &hexium_gemini_dual_4bnc,
375 	 },
376 	{
377 	 .vendor = 0,
378 	 }
379 };
380 
381 MODULE_DEVICE_TABLE(pci, pci_tbl);
382 
383 static struct saa7146_ext_vv vv_data = {
384 	.inputs = HEXIUM_INPUTS,
385 	.capabilities = 0,
386 	.stds = &hexium_standards[0],
387 	.num_stds = ARRAY_SIZE(hexium_standards),
388 	.std_callback = &std_callback,
389 };
390 
391 static struct saa7146_extension hexium_extension = {
392 	.name = "hexium gemini",
393 	.flags = SAA7146_USE_I2C_IRQ,
394 
395 	.pci_tbl = &pci_tbl[0],
396 	.module = THIS_MODULE,
397 
398 	.attach = hexium_attach,
399 	.detach = hexium_detach,
400 
401 	.irq_mask = 0,
402 	.irq_func = NULL,
403 };
404 
405 static int __init hexium_init_module(void)
406 {
407 	if (0 != saa7146_register_extension(&hexium_extension)) {
408 		DEB_S("failed to register extension\n");
409 		return -ENODEV;
410 	}
411 
412 	return 0;
413 }
414 
415 static void __exit hexium_cleanup_module(void)
416 {
417 	saa7146_unregister_extension(&hexium_extension);
418 }
419 
420 module_init(hexium_init_module);
421 module_exit(hexium_cleanup_module);
422 
423 MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards");
424 MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
425 MODULE_LICENSE("GPL");
426