blob: fe596a1c12a81a7a71b15559dfd6747f7ae993ce [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 hexium_orion.c - v4l2 driver for the Hexium Orion 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.
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -03006
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 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 DEBUG_VARIABLE debug
25
26#include <media/saa7146_vv.h>
27
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030028static int debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070029module_param(debug, int, 0);
30MODULE_PARM_DESC(debug, "debug verbosity");
31
32/* global variables */
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030033static int hexium_num;
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
35#define HEXIUM_HV_PCI6_ORION 1
36#define HEXIUM_ORION_1SVHS_3BNC 2
37#define HEXIUM_ORION_4BNC 3
38
39#define HEXIUM_INPUTS 9
40static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
41 { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
42 { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
43 { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
44 { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
45 { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
46 { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
47 { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
48 { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
49 { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
50};
51
52#define HEXIUM_AUDIOS 0
53
54struct hexium_data
55{
56 s8 adr;
57 u8 byte;
58};
59
Linus Torvalds1da177e2005-04-16 15:20:36 -070060struct hexium
61{
62 int type;
63 struct video_device *video_dev;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030064 struct i2c_adapter i2c_adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66 int cur_input; /* current input */
67};
68
69/* Philips SAA7110 decoder default registers */
70static u8 hexium_saa7110[53]={
71/*00*/ 0x4C,0x3C,0x0D,0xEF,0xBD,0xF0,0x00,0x00,
72/*08*/ 0xF8,0xF8,0x60,0x60,0x40,0x86,0x18,0x90,
73/*10*/ 0x00,0x2C,0x40,0x46,0x42,0x1A,0xFF,0xDA,
74/*18*/ 0xF0,0x8B,0x00,0x00,0x00,0x00,0x00,0x00,
75/*20*/ 0xD9,0x17,0x40,0x41,0x80,0x41,0x80,0x4F,
76/*28*/ 0xFE,0x01,0x0F,0x0F,0x03,0x01,0x81,0x03,
77/*30*/ 0x44,0x75,0x01,0x8C,0x03
78};
79
80static struct {
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030081 struct hexium_data data[8];
Linus Torvalds1da177e2005-04-16 15:20:36 -070082} hexium_input_select[] = {
83{
84 { /* cvbs 1 */
85 { 0x06, 0x00 },
86 { 0x20, 0xD9 },
87 { 0x21, 0x17 }, // 0x16,
88 { 0x22, 0x40 },
89 { 0x2C, 0x03 },
90 { 0x30, 0x44 },
91 { 0x31, 0x75 }, // ??
92 { 0x21, 0x16 }, // 0x03,
93 }
94}, {
95 { /* cvbs 2 */
96 { 0x06, 0x00 },
97 { 0x20, 0x78 },
98 { 0x21, 0x07 }, // 0x03,
99 { 0x22, 0xD2 },
100 { 0x2C, 0x83 },
101 { 0x30, 0x60 },
102 { 0x31, 0xB5 }, // ?
103 { 0x21, 0x03 },
104 }
105}, {
106 { /* cvbs 3 */
107 { 0x06, 0x00 },
108 { 0x20, 0xBA },
109 { 0x21, 0x07 }, // 0x05,
110 { 0x22, 0x91 },
111 { 0x2C, 0x03 },
112 { 0x30, 0x60 },
113 { 0x31, 0xB5 }, // ??
114 { 0x21, 0x05 }, // 0x03,
115 }
116}, {
117 { /* cvbs 4 */
118 { 0x06, 0x00 },
119 { 0x20, 0xD8 },
120 { 0x21, 0x17 }, // 0x16,
121 { 0x22, 0x40 },
122 { 0x2C, 0x03 },
123 { 0x30, 0x44 },
124 { 0x31, 0x75 }, // ??
125 { 0x21, 0x16 }, // 0x03,
126 }
127}, {
128 { /* cvbs 5 */
129 { 0x06, 0x00 },
130 { 0x20, 0xB8 },
131 { 0x21, 0x07 }, // 0x05,
132 { 0x22, 0x91 },
133 { 0x2C, 0x03 },
134 { 0x30, 0x60 },
135 { 0x31, 0xB5 }, // ??
136 { 0x21, 0x05 }, // 0x03,
137 }
138}, {
139 { /* cvbs 6 */
140 { 0x06, 0x00 },
141 { 0x20, 0x7C },
142 { 0x21, 0x07 }, // 0x03
143 { 0x22, 0xD2 },
144 { 0x2C, 0x83 },
145 { 0x30, 0x60 },
146 { 0x31, 0xB5 }, // ??
147 { 0x21, 0x03 },
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149}, {
150 { /* y/c 1 */
151 { 0x06, 0x80 },
152 { 0x20, 0x59 },
153 { 0x21, 0x17 },
154 { 0x22, 0x42 },
155 { 0x2C, 0xA3 },
156 { 0x30, 0x44 },
157 { 0x31, 0x75 },
158 { 0x21, 0x12 },
159 }
160}, {
161 { /* y/c 2 */
162 { 0x06, 0x80 },
163 { 0x20, 0x9A },
164 { 0x21, 0x17 },
165 { 0x22, 0xB1 },
166 { 0x2C, 0x13 },
167 { 0x30, 0x60 },
168 { 0x31, 0xB5 },
169 { 0x21, 0x14 },
170 }
171}, {
172 { /* y/c 3 */
173 { 0x06, 0x80 },
174 { 0x20, 0x3C },
175 { 0x21, 0x27 },
176 { 0x22, 0xC1 },
177 { 0x2C, 0x23 },
178 { 0x30, 0x44 },
179 { 0x31, 0x75 },
180 { 0x21, 0x21 },
181 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300182}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183};
184
185static struct saa7146_standard hexium_standards[] = {
186 {
187 .name = "PAL", .id = V4L2_STD_PAL,
188 .v_offset = 16, .v_field = 288,
189 .h_offset = 1, .h_pixels = 680,
190 .v_max_out = 576, .h_max_out = 768,
191 }, {
192 .name = "NTSC", .id = V4L2_STD_NTSC,
193 .v_offset = 16, .v_field = 240,
194 .h_offset = 1, .h_pixels = 640,
195 .v_max_out = 480, .h_max_out = 640,
196 }, {
197 .name = "SECAM", .id = V4L2_STD_SECAM,
198 .v_offset = 16, .v_field = 288,
199 .h_offset = 1, .h_pixels = 720,
200 .v_max_out = 576, .h_max_out = 768,
201 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300202};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203
204/* this is only called for old HV-PCI6/Orion cards
205 without eeprom */
206static int hexium_probe(struct saa7146_dev *dev)
207{
208 struct hexium *hexium = NULL;
209 union i2c_smbus_data data;
210 int err = 0;
211
212 DEB_EE((".\n"));
213
214 /* there are no hexium orion cards with revision 0 saa7146s */
215 if (0 == dev->revision) {
216 return -EFAULT;
217 }
218
Hans Verkuilcd7d9be2010-02-20 07:56:25 -0300219 err = saa7146_vv_devinit(dev);
220 if (err)
221 return err;
222
Panagiotis Issaris74081872006-01-11 19:40:56 -0200223 hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 if (NULL == hexium) {
225 printk("hexium_orion: hexium_probe: not enough kernel memory.\n");
226 return -ENOMEM;
227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
229 /* enable i2c-port pins */
230 saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
231
232 saa7146_write(dev, DD1_INIT, 0x01000100);
233 saa7146_write(dev, DD1_STREAM_B, 0x00000000);
234 saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
235
236 hexium->i2c_adapter = (struct i2c_adapter) {
237 .class = I2C_CLASS_TV_ANALOG,
238 .name = "hexium orion",
239 };
240 saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
241 if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
242 DEB_S(("cannot register i2c-device. skipping.\n"));
243 kfree(hexium);
244 return -EFAULT;
245 }
246
247 /* set SAA7110 control GPIO 0 */
248 saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI);
249 /* set HWControl GPIO number 2 */
250 saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
251
252 mdelay(10);
253
254 /* detect newer Hexium Orion cards by subsystem ids */
255 if (0x17c8 == dev->pci->subsystem_vendor && 0x0101 == dev->pci->subsystem_device) {
256 printk("hexium_orion: device is a Hexium Orion w/ 1 SVHS + 3 BNC inputs.\n");
257 /* we store the pointer in our private data field */
258 dev->ext_priv = hexium;
259 hexium->type = HEXIUM_ORION_1SVHS_3BNC;
260 return 0;
261 }
262
263 if (0x17c8 == dev->pci->subsystem_vendor && 0x2101 == dev->pci->subsystem_device) {
264 printk("hexium_orion: device is a Hexium Orion w/ 4 BNC inputs.\n");
265 /* we store the pointer in our private data field */
266 dev->ext_priv = hexium;
267 hexium->type = HEXIUM_ORION_4BNC;
268 return 0;
269 }
270
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300271 /* check if this is an old hexium Orion card by looking at
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 a saa7110 at address 0x4e */
273 if (0 == (err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) {
274 printk("hexium_orion: device is a Hexium HV-PCI6/Orion (old).\n");
275 /* we store the pointer in our private data field */
276 dev->ext_priv = hexium;
277 hexium->type = HEXIUM_HV_PCI6_ORION;
278 return 0;
279 }
280
281 i2c_del_adapter(&hexium->i2c_adapter);
282 kfree(hexium);
283 return -EFAULT;
284}
285
286/* bring hardware to a sane state. this has to be done, just in case someone
287 wants to capture from this device before it has been properly initialized.
288 the capture engine would badly fail, because no valid signal arrives on the
289 saa7146, thus leading to timeouts and stuff. */
290static int hexium_init_done(struct saa7146_dev *dev)
291{
292 struct hexium *hexium = (struct hexium *) dev->ext_priv;
293 union i2c_smbus_data data;
294 int i = 0;
295
296 DEB_D(("hexium_init_done called.\n"));
297
298 /* initialize the helper ics to useful values */
299 for (i = 0; i < sizeof(hexium_saa7110); i++) {
300 data.byte = hexium_saa7110[i];
301 if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
302 printk("hexium_orion: failed for address 0x%02x\n", i);
303 }
304 }
305
306 return 0;
307}
308
309static int hexium_set_input(struct hexium *hexium, int input)
310{
311 union i2c_smbus_data data;
312 int i = 0;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 DEB_D((".\n"));
315
316 for (i = 0; i < 8; i++) {
317 int adr = hexium_input_select[input].data[i].adr;
318 data.byte = hexium_input_select[input].data[i].byte;
319 if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, adr, I2C_SMBUS_BYTE_DATA, &data)) {
320 return -1;
321 }
322 printk("%d: 0x%02x => 0x%02x\n",input, adr,data.byte);
323 }
324
325 return 0;
326}
327
Hans Verkuilb9600742009-01-18 19:59:11 -0300328static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
329{
330 DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
331
Roel Kluin223ffe52009-05-02 16:38:47 -0300332 if (i->index >= HEXIUM_INPUTS)
Hans Verkuilb9600742009-01-18 19:59:11 -0300333 return -EINVAL;
334
335 memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
336
337 DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
338 return 0;
339}
340
341static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
342{
343 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
344 struct hexium *hexium = (struct hexium *) dev->ext_priv;
345
346 *input = hexium->cur_input;
347
348 DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
349 return 0;
350}
351
352static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
353{
354 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
355 struct hexium *hexium = (struct hexium *) dev->ext_priv;
356
Roel Kluinf14a2972009-10-23 07:59:42 -0300357 if (input >= HEXIUM_INPUTS)
Hans Verkuilb9600742009-01-18 19:59:11 -0300358 return -EINVAL;
359
360 hexium->cur_input = input;
361 hexium_set_input(hexium, input);
362
363 return 0;
364}
365
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366static struct saa7146_ext_vv vv_data;
367
368/* this function only gets called when the probing was successful */
369static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
370{
371 struct hexium *hexium = (struct hexium *) dev->ext_priv;
372
373 DEB_EE((".\n"));
374
375 saa7146_vv_init(dev, &vv_data);
Hans Verkuilb9600742009-01-18 19:59:11 -0300376 vv_data.ops.vidioc_enum_input = vidioc_enum_input;
377 vv_data.ops.vidioc_g_input = vidioc_g_input;
378 vv_data.ops.vidioc_s_input = vidioc_s_input;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) {
380 printk("hexium_orion: cannot register capture v4l2 device. skipping.\n");
381 return -1;
382 }
383
384 printk("hexium_orion: found 'hexium orion' frame grabber-%d.\n", hexium_num);
385 hexium_num++;
386
387 /* the rest */
388 hexium->cur_input = 0;
389 hexium_init_done(dev);
390
391 return 0;
392}
393
394static int hexium_detach(struct saa7146_dev *dev)
395{
396 struct hexium *hexium = (struct hexium *) dev->ext_priv;
397
398 DEB_EE(("dev:%p\n", dev));
399
400 saa7146_unregister_device(&hexium->video_dev, dev);
401 saa7146_vv_release(dev);
402
403 hexium_num--;
404
405 i2c_del_adapter(&hexium->i2c_adapter);
406 kfree(hexium);
407 return 0;
408}
409
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
411{
412 return 0;
413}
414
415static struct saa7146_extension extension;
416
417static struct saa7146_pci_extension_data hexium_hv_pci6 = {
418 .ext_priv = "Hexium HV-PCI6 / Orion",
419 .ext = &extension,
420};
421
422static struct saa7146_pci_extension_data hexium_orion_1svhs_3bnc = {
423 .ext_priv = "Hexium HV-PCI6 / Orion (1 SVHS/3 BNC)",
424 .ext = &extension,
425};
426
427static struct saa7146_pci_extension_data hexium_orion_4bnc = {
428 .ext_priv = "Hexium HV-PCI6 / Orion (4 BNC)",
429 .ext = &extension,
430};
431
432static struct pci_device_id pci_tbl[] = {
433 {
434 .vendor = PCI_VENDOR_ID_PHILIPS,
435 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
436 .subvendor = 0x0000,
437 .subdevice = 0x0000,
438 .driver_data = (unsigned long) &hexium_hv_pci6,
439 },
440 {
441 .vendor = PCI_VENDOR_ID_PHILIPS,
442 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
443 .subvendor = 0x17c8,
444 .subdevice = 0x0101,
445 .driver_data = (unsigned long) &hexium_orion_1svhs_3bnc,
446 },
447 {
448 .vendor = PCI_VENDOR_ID_PHILIPS,
449 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
450 .subvendor = 0x17c8,
451 .subdevice = 0x2101,
452 .driver_data = (unsigned long) &hexium_orion_4bnc,
453 },
454 {
455 .vendor = 0,
456 }
457};
458
459MODULE_DEVICE_TABLE(pci, pci_tbl);
460
461static struct saa7146_ext_vv vv_data = {
462 .inputs = HEXIUM_INPUTS,
463 .capabilities = 0,
464 .stds = &hexium_standards[0],
465 .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
466 .std_callback = &std_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467};
468
469static struct saa7146_extension extension = {
Dave Jones922f77d2006-02-07 06:49:15 -0200470 .name = "hexium HV-PCI6 Orion",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 .flags = 0, // SAA7146_USE_I2C_IRQ,
472
473 .pci_tbl = &pci_tbl[0],
474 .module = THIS_MODULE,
475
476 .probe = hexium_probe,
477 .attach = hexium_attach,
478 .detach = hexium_detach,
479
480 .irq_mask = 0,
481 .irq_func = NULL,
482};
483
484static int __init hexium_init_module(void)
485{
486 if (0 != saa7146_register_extension(&extension)) {
487 DEB_S(("failed to register extension.\n"));
488 return -ENODEV;
489 }
490
491 return 0;
492}
493
494static void __exit hexium_cleanup_module(void)
495{
496 saa7146_unregister_extension(&extension);
497}
498
499module_init(hexium_init_module);
500module_exit(hexium_cleanup_module);
501
502MODULE_DESCRIPTION("video4linux-2 driver for Hexium Orion frame grabber cards");
503MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
504MODULE_LICENSE("GPL");