1/*
2    hexium_gemini.c - v4l2 driver for Hexium Gemini frame grabber cards
3
4    Visit http://www.mihu.de/linux/saa7146/ and follow the link
5    to "hexium" for further details about this card.
6
7    Copyright (C) 2003 Michael Hunold <michael@mihu.de>
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*/
23
24#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
25
26#define DEBUG_VARIABLE debug
27
28#include <media/saa7146_vv.h>
29#include <linux/module.h>
30
31static int debug;
32module_param(debug, int, 0);
33MODULE_PARM_DESC(debug, "debug verbosity");
34
35/* global variables */
36static int hexium_num;
37
38#define HEXIUM_GEMINI			4
39#define HEXIUM_GEMINI_DUAL		5
40
41#define HEXIUM_INPUTS	9
42static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
43	{ 0, "CVBS 1",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
44	{ 1, "CVBS 2",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
45	{ 2, "CVBS 3",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
46	{ 3, "CVBS 4",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
47	{ 4, "CVBS 5",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
48	{ 5, "CVBS 6",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
49	{ 6, "Y/C 1",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
50	{ 7, "Y/C 2",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
51	{ 8, "Y/C 3",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
52};
53
54#define HEXIUM_AUDIOS	0
55
56struct hexium_data
57{
58	s8 adr;
59	u8 byte;
60};
61
62#define HEXIUM_CONTROLS	1
63static struct v4l2_queryctrl hexium_controls[] = {
64	{ V4L2_CID_PRIVATE_BASE, V4L2_CTRL_TYPE_BOOLEAN, "B/W", 0, 1, 1, 0, 0 },
65};
66
67#define HEXIUM_GEMINI_V_1_0		1
68#define HEXIUM_GEMINI_DUAL_V_1_0	2
69
70struct hexium
71{
72	int type;
73
74	struct video_device	*video_dev;
75	struct i2c_adapter	i2c_adapter;
76
77	int 		cur_input;	/* current input */
78	v4l2_std_id 	cur_std;	/* current standard */
79	int		cur_bw;		/* current black/white status */
80};
81
82/* Samsung KS0127B decoder default registers */
83static u8 hexium_ks0127b[0x100]={
84/*00*/ 0x00,0x52,0x30,0x40,0x01,0x0C,0x2A,0x10,
85/*08*/ 0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x06,
86/*10*/ 0x00,0x00,0xE4,0xC0,0x00,0x00,0x00,0x00,
87/*18*/ 0x14,0x9B,0xFE,0xFF,0xFC,0xFF,0x03,0x22,
88/*20*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
89/*28*/ 0x00,0x00,0x00,0x00,0x00,0x2C,0x9B,0x00,
90/*30*/ 0x00,0x00,0x10,0x80,0x80,0x10,0x80,0x80,
91/*38*/ 0x01,0x04,0x00,0x00,0x00,0x29,0xC0,0x00,
92/*40*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
93/*48*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
94/*50*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
95/*58*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
96/*60*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
97/*68*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
98/*70*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
99/*78*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
100/*80*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
101/*88*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
102/*90*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
103/*98*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
104/*A0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
105/*A8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
106/*B0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
107/*B8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
108/*C0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
109/*C8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
110/*D0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
111/*D8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
112/*E0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
113/*E8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
114/*F0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
115/*F8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
116};
117
118static struct hexium_data hexium_pal[] = {
119	{ 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
120};
121
122static struct hexium_data hexium_pal_bw[] = {
123	{ 0x01, 0x52 },	{ 0x12, 0x64 },	{ 0x2D, 0x2C },	{ 0x2E, 0x9B },	{ -1 , 0xFF }
124};
125
126static struct hexium_data hexium_ntsc[] = {
127	{ 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
128};
129
130static struct hexium_data hexium_ntsc_bw[] = {
131	{ 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
132};
133
134static struct hexium_data hexium_secam[] = {
135	{ 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
136};
137
138static struct hexium_data hexium_input_select[] = {
139	{ 0x02, 0x60 },
140	{ 0x02, 0x64 },
141	{ 0x02, 0x61 },
142	{ 0x02, 0x65 },
143	{ 0x02, 0x62 },
144	{ 0x02, 0x66 },
145	{ 0x02, 0x68 },
146	{ 0x02, 0x69 },
147	{ 0x02, 0x6A },
148};
149
150/* fixme: h_offset = 0 for Hexium Gemini *Dual*, which
151   are currently *not* supported*/
152static struct saa7146_standard hexium_standards[] = {
153	{
154		.name	= "PAL", 	.id	= V4L2_STD_PAL,
155		.v_offset	= 28,	.v_field 	= 288,
156		.h_offset	= 1,	.h_pixels 	= 680,
157		.v_max_out	= 576,	.h_max_out	= 768,
158	}, {
159		.name	= "NTSC", 	.id	= V4L2_STD_NTSC,
160		.v_offset	= 28,	.v_field 	= 240,
161		.h_offset	= 1,	.h_pixels 	= 640,
162		.v_max_out	= 480,	.h_max_out	= 640,
163	}, {
164		.name	= "SECAM", 	.id	= V4L2_STD_SECAM,
165		.v_offset	= 28,	.v_field 	= 288,
166		.h_offset	= 1,	.h_pixels 	= 720,
167		.v_max_out	= 576,	.h_max_out	= 768,
168	}
169};
170
171/* bring hardware to a sane state. this has to be done, just in case someone
172   wants to capture from this device before it has been properly initialized.
173   the capture engine would badly fail, because no valid signal arrives on the
174   saa7146, thus leading to timeouts and stuff. */
175static int hexium_init_done(struct saa7146_dev *dev)
176{
177	struct hexium *hexium = (struct hexium *) dev->ext_priv;
178	union i2c_smbus_data data;
179	int i = 0;
180
181	DEB_D("hexium_init_done called\n");
182
183	/* initialize the helper ics to useful values */
184	for (i = 0; i < sizeof(hexium_ks0127b); i++) {
185		data.byte = hexium_ks0127b[i];
186		if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
187			pr_err("hexium_init_done() failed for address 0x%02x\n",
188			       i);
189		}
190	}
191
192	return 0;
193}
194
195static int hexium_set_input(struct hexium *hexium, int input)
196{
197	union i2c_smbus_data data;
198
199	DEB_D("\n");
200
201	data.byte = hexium_input_select[input].byte;
202	if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, hexium_input_select[input].adr, I2C_SMBUS_BYTE_DATA, &data)) {
203		return -1;
204	}
205
206	return 0;
207}
208
209static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec)
210{
211	union i2c_smbus_data data;
212	int i = 0;
213
214	DEB_D("\n");
215
216	while (vdec[i].adr != -1) {
217		data.byte = vdec[i].byte;
218		if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, vdec[i].adr, I2C_SMBUS_BYTE_DATA, &data)) {
219			pr_err("hexium_init_done: hexium_set_standard() failed for address 0x%02x\n",
220			       i);
221			return -1;
222		}
223		i++;
224	}
225	return 0;
226}
227
228static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
229{
230	DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index);
231
232	if (i->index >= HEXIUM_INPUTS)
233		return -EINVAL;
234
235	memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
236
237	DEB_D("v4l2_ioctl: VIDIOC_ENUMINPUT %d\n", i->index);
238	return 0;
239}
240
241static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
242{
243	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
244	struct hexium *hexium = (struct hexium *) dev->ext_priv;
245
246	*input = hexium->cur_input;
247
248	DEB_D("VIDIOC_G_INPUT: %d\n", *input);
249	return 0;
250}
251
252static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
253{
254	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
255	struct hexium *hexium = (struct hexium *) dev->ext_priv;
256
257	DEB_EE("VIDIOC_S_INPUT %d\n", input);
258
259	if (input >= HEXIUM_INPUTS)
260		return -EINVAL;
261
262	hexium->cur_input = input;
263	hexium_set_input(hexium, input);
264	return 0;
265}
266
267/* the saa7146 provides some controls (brightness, contrast, saturation)
268   which gets registered *after* this function. because of this we have
269   to return with a value != 0 even if the function succeeded.. */
270static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc)
271{
272	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
273	int i;
274
275	for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
276		if (hexium_controls[i].id == qc->id) {
277			*qc = hexium_controls[i];
278			DEB_D("VIDIOC_QUERYCTRL %d\n", qc->id);
279			return 0;
280		}
281	}
282	return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc);
283}
284
285static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
286{
287	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
288	struct hexium *hexium = (struct hexium *) dev->ext_priv;
289	int i;
290
291	for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
292		if (hexium_controls[i].id == vc->id)
293			break;
294	}
295
296	if (i < 0)
297		return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc);
298
299	if (vc->id == V4L2_CID_PRIVATE_BASE) {
300		vc->value = hexium->cur_bw;
301		DEB_D("VIDIOC_G_CTRL BW:%d\n", vc->value);
302		return 0;
303	}
304	return -EINVAL;
305}
306
307static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
308{
309	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
310	struct hexium *hexium = (struct hexium *) dev->ext_priv;
311	int i = 0;
312
313	for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
314		if (hexium_controls[i].id == vc->id)
315			break;
316	}
317
318	if (i < 0)
319		return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc);
320
321	if (vc->id == V4L2_CID_PRIVATE_BASE)
322		hexium->cur_bw = vc->value;
323
324	DEB_D("VIDIOC_S_CTRL BW:%d\n", hexium->cur_bw);
325
326	if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
327		hexium_set_standard(hexium, hexium_pal);
328		return 0;
329	}
330	if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
331		hexium_set_standard(hexium, hexium_ntsc);
332		return 0;
333	}
334	if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
335		hexium_set_standard(hexium, hexium_secam);
336		return 0;
337	}
338	if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
339		hexium_set_standard(hexium, hexium_pal_bw);
340		return 0;
341	}
342	if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
343		hexium_set_standard(hexium, hexium_ntsc_bw);
344		return 0;
345	}
346	if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std)
347		/* fixme: is there no bw secam mode? */
348		return -EINVAL;
349
350	return -EINVAL;
351}
352
353
354static struct saa7146_ext_vv vv_data;
355
356/* this function only gets called when the probing was successful */
357static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
358{
359	struct hexium *hexium;
360	int ret;
361
362	DEB_EE("\n");
363
364	hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
365	if (NULL == hexium) {
366		pr_err("not enough kernel memory in hexium_attach()\n");
367		return -ENOMEM;
368	}
369	dev->ext_priv = hexium;
370
371	/* enable i2c-port pins */
372	saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
373
374	hexium->i2c_adapter = (struct i2c_adapter) {
375		.name = "hexium gemini",
376	};
377	saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
378	if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
379		DEB_S("cannot register i2c-device. skipping.\n");
380		kfree(hexium);
381		return -EFAULT;
382	}
383
384	/*  set HWControl GPIO number 2 */
385	saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
386
387	saa7146_write(dev, DD1_INIT, 0x07000700);
388	saa7146_write(dev, DD1_STREAM_B, 0x00000000);
389	saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
390
391	/* the rest */
392	hexium->cur_input = 0;
393	hexium_init_done(dev);
394
395	hexium_set_standard(hexium, hexium_pal);
396	hexium->cur_std = V4L2_STD_PAL;
397
398	hexium_set_input(hexium, 0);
399	hexium->cur_input = 0;
400
401	saa7146_vv_init(dev, &vv_data);
402	vv_data.ops.vidioc_queryctrl = vidioc_queryctrl;
403	vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl;
404	vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl;
405	vv_data.ops.vidioc_enum_input = vidioc_enum_input;
406	vv_data.ops.vidioc_g_input = vidioc_g_input;
407	vv_data.ops.vidioc_s_input = vidioc_s_input;
408	ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER);
409	if (ret < 0) {
410		pr_err("cannot register capture v4l2 device. skipping.\n");
411		return ret;
412	}
413
414	pr_info("found 'hexium gemini' frame grabber-%d\n", hexium_num);
415	hexium_num++;
416
417	return 0;
418}
419
420static int hexium_detach(struct saa7146_dev *dev)
421{
422	struct hexium *hexium = (struct hexium *) dev->ext_priv;
423
424	DEB_EE("dev:%p\n", dev);
425
426	saa7146_unregister_device(&hexium->video_dev, dev);
427	saa7146_vv_release(dev);
428
429	hexium_num--;
430
431	i2c_del_adapter(&hexium->i2c_adapter);
432	kfree(hexium);
433	return 0;
434}
435
436static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
437{
438	struct hexium *hexium = (struct hexium *) dev->ext_priv;
439
440	if (V4L2_STD_PAL == std->id) {
441		hexium_set_standard(hexium, hexium_pal);
442		hexium->cur_std = V4L2_STD_PAL;
443		return 0;
444	} else if (V4L2_STD_NTSC == std->id) {
445		hexium_set_standard(hexium, hexium_ntsc);
446		hexium->cur_std = V4L2_STD_NTSC;
447		return 0;
448	} else if (V4L2_STD_SECAM == std->id) {
449		hexium_set_standard(hexium, hexium_secam);
450		hexium->cur_std = V4L2_STD_SECAM;
451		return 0;
452	}
453
454	return -1;
455}
456
457static struct saa7146_extension hexium_extension;
458
459static struct saa7146_pci_extension_data hexium_gemini_4bnc = {
460	.ext_priv = "Hexium Gemini (4 BNC)",
461	.ext = &hexium_extension,
462};
463
464static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = {
465	.ext_priv = "Hexium Gemini Dual (4 BNC)",
466	.ext = &hexium_extension,
467};
468
469static struct pci_device_id pci_tbl[] = {
470	{
471	 .vendor = PCI_VENDOR_ID_PHILIPS,
472	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
473	 .subvendor = 0x17c8,
474	 .subdevice = 0x2401,
475	 .driver_data = (unsigned long) &hexium_gemini_4bnc,
476	 },
477	{
478	 .vendor = PCI_VENDOR_ID_PHILIPS,
479	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
480	 .subvendor = 0x17c8,
481	 .subdevice = 0x2402,
482	 .driver_data = (unsigned long) &hexium_gemini_dual_4bnc,
483	 },
484	{
485	 .vendor = 0,
486	 }
487};
488
489MODULE_DEVICE_TABLE(pci, pci_tbl);
490
491static struct saa7146_ext_vv vv_data = {
492	.inputs = HEXIUM_INPUTS,
493	.capabilities = 0,
494	.stds = &hexium_standards[0],
495	.num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
496	.std_callback = &std_callback,
497};
498
499static struct saa7146_extension hexium_extension = {
500	.name = "hexium gemini",
501	.flags = SAA7146_USE_I2C_IRQ,
502
503	.pci_tbl = &pci_tbl[0],
504	.module = THIS_MODULE,
505
506	.attach = hexium_attach,
507	.detach = hexium_detach,
508
509	.irq_mask = 0,
510	.irq_func = NULL,
511};
512
513static int __init hexium_init_module(void)
514{
515	if (0 != saa7146_register_extension(&hexium_extension)) {
516		DEB_S("failed to register extension\n");
517		return -ENODEV;
518	}
519
520	return 0;
521}
522
523static void __exit hexium_cleanup_module(void)
524{
525	saa7146_unregister_extension(&hexium_extension);
526}
527
528module_init(hexium_init_module);
529module_exit(hexium_cleanup_module);
530
531MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards");
532MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
533MODULE_LICENSE("GPL");
534