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. */ 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 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 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 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 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 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 */ 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 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 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 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 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