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