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