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
20static int debug;
21module_param(debug, int, 0);
22MODULE_PARM_DESC(debug, "debug verbosity");
23
24/* global variables */
25static 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
32static 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
46struct 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
55struct 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 */
67static 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
102static struct hexium_data hexium_pal[] = {
103	{ 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
104};
105
106static struct hexium_data hexium_ntsc[] = {
107	{ 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
108};
109
110static struct hexium_data hexium_secam[] = {
111	{ 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
112};
113
114static 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*/
128static 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. */
151static 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
171static 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
185static 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
204static 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
217static 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
228static 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
243static struct saa7146_ext_vv vv_data;
244
245/* this function only gets called when the probing was successful */
246static 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
313static 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
329static 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
350static struct saa7146_extension hexium_extension;
351
352static struct saa7146_pci_extension_data hexium_gemini_4bnc = {
353	.ext_priv = "Hexium Gemini (4 BNC)",
354	.ext = &hexium_extension,
355};
356
357static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = {
358	.ext_priv = "Hexium Gemini Dual (4 BNC)",
359	.ext = &hexium_extension,
360};
361
362static 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
382MODULE_DEVICE_TABLE(pci, pci_tbl);
383
384static 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
392static 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
406static 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
416static void __exit hexium_cleanup_module(void)
417{
418	saa7146_unregister_extension(&hexium_extension);
419}
420
421module_init(hexium_init_module);
422module_exit(hexium_cleanup_module);
423
424MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards");
425MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
426MODULE_LICENSE("GPL");
427