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