Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003     hexium_gemini.c - v4l2 driver for Hexium Gemini frame grabber cards
0004 
0005     Visit http://www.mihu.de/linux/saa7146/ and follow the link
0006     to "hexium" for further details about this card.
0007 
0008     Copyright (C) 2003 Michael Hunold <michael@mihu.de>
0009 
0010 */
0011 
0012 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0013 
0014 #define DEBUG_VARIABLE debug
0015 
0016 #include <media/drv-intf/saa7146_vv.h>
0017 #include <linux/module.h>
0018 #include <linux/kernel.h>
0019 
0020 static int debug;
0021 module_param(debug, int, 0);
0022 MODULE_PARM_DESC(debug, "debug verbosity");
0023 
0024 /* global variables */
0025 static int hexium_num;
0026 
0027 #define HEXIUM_GEMINI           4
0028 #define HEXIUM_GEMINI_DUAL      5
0029 
0030 #define HEXIUM_INPUTS   9
0031 static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
0032     { 0, "CVBS 1",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
0033     { 1, "CVBS 2",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
0034     { 2, "CVBS 3",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
0035     { 3, "CVBS 4",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
0036     { 4, "CVBS 5",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
0037     { 5, "CVBS 6",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
0038     { 6, "Y/C 1",   V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
0039     { 7, "Y/C 2",   V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
0040     { 8, "Y/C 3",   V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
0041 };
0042 
0043 #define HEXIUM_AUDIOS   0
0044 
0045 struct hexium_data
0046 {
0047     s8 adr;
0048     u8 byte;
0049 };
0050 
0051 #define HEXIUM_GEMINI_V_1_0     1
0052 #define HEXIUM_GEMINI_DUAL_V_1_0    2
0053 
0054 struct hexium
0055 {
0056     int type;
0057 
0058     struct video_device video_dev;
0059     struct i2c_adapter  i2c_adapter;
0060 
0061     int     cur_input;  /* current input */
0062     v4l2_std_id cur_std;    /* current standard */
0063 };
0064 
0065 /* Samsung KS0127B decoder default registers */
0066 static u8 hexium_ks0127b[0x100]={
0067 /*00*/ 0x00,0x52,0x30,0x40,0x01,0x0C,0x2A,0x10,
0068 /*08*/ 0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x06,
0069 /*10*/ 0x00,0x00,0xE4,0xC0,0x00,0x00,0x00,0x00,
0070 /*18*/ 0x14,0x9B,0xFE,0xFF,0xFC,0xFF,0x03,0x22,
0071 /*20*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0072 /*28*/ 0x00,0x00,0x00,0x00,0x00,0x2C,0x9B,0x00,
0073 /*30*/ 0x00,0x00,0x10,0x80,0x80,0x10,0x80,0x80,
0074 /*38*/ 0x01,0x04,0x00,0x00,0x00,0x29,0xC0,0x00,
0075 /*40*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0076 /*48*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0077 /*50*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0078 /*58*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0079 /*60*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0080 /*68*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0081 /*70*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0082 /*78*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0083 /*80*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0084 /*88*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0085 /*90*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0086 /*98*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0087 /*A0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0088 /*A8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0089 /*B0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0090 /*B8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0091 /*C0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0092 /*C8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0093 /*D0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0094 /*D8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0095 /*E0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0096 /*E8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0097 /*F0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0098 /*F8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
0099 };
0100 
0101 static struct hexium_data hexium_pal[] = {
0102     { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
0103 };
0104 
0105 static struct hexium_data hexium_ntsc[] = {
0106     { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
0107 };
0108 
0109 static struct hexium_data hexium_secam[] = {
0110     { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
0111 };
0112 
0113 static struct hexium_data hexium_input_select[] = {
0114     { 0x02, 0x60 },
0115     { 0x02, 0x64 },
0116     { 0x02, 0x61 },
0117     { 0x02, 0x65 },
0118     { 0x02, 0x62 },
0119     { 0x02, 0x66 },
0120     { 0x02, 0x68 },
0121     { 0x02, 0x69 },
0122     { 0x02, 0x6A },
0123 };
0124 
0125 /* fixme: h_offset = 0 for Hexium Gemini *Dual*, which
0126    are currently *not* supported*/
0127 static struct saa7146_standard hexium_standards[] = {
0128     {
0129         .name   = "PAL",    .id = V4L2_STD_PAL,
0130         .v_offset   = 28,   .v_field    = 288,
0131         .h_offset   = 1,    .h_pixels   = 680,
0132         .v_max_out  = 576,  .h_max_out  = 768,
0133     }, {
0134         .name   = "NTSC",   .id = V4L2_STD_NTSC,
0135         .v_offset   = 28,   .v_field    = 240,
0136         .h_offset   = 1,    .h_pixels   = 640,
0137         .v_max_out  = 480,  .h_max_out  = 640,
0138     }, {
0139         .name   = "SECAM",  .id = V4L2_STD_SECAM,
0140         .v_offset   = 28,   .v_field    = 288,
0141         .h_offset   = 1,    .h_pixels   = 720,
0142         .v_max_out  = 576,  .h_max_out  = 768,
0143     }
0144 };
0145 
0146 /* bring hardware to a sane state. this has to be done, just in case someone
0147    wants to capture from this device before it has been properly initialized.
0148    the capture engine would badly fail, because no valid signal arrives on the
0149    saa7146, thus leading to timeouts and stuff. */
0150 static int hexium_init_done(struct saa7146_dev *dev)
0151 {
0152     struct hexium *hexium = (struct hexium *) dev->ext_priv;
0153     union i2c_smbus_data data;
0154     int i = 0;
0155 
0156     DEB_D("hexium_init_done called\n");
0157 
0158     /* initialize the helper ics to useful values */
0159     for (i = 0; i < sizeof(hexium_ks0127b); i++) {
0160         data.byte = hexium_ks0127b[i];
0161         if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
0162             pr_err("hexium_init_done() failed for address 0x%02x\n",
0163                    i);
0164         }
0165     }
0166 
0167     return 0;
0168 }
0169 
0170 static int hexium_set_input(struct hexium *hexium, int input)
0171 {
0172     union i2c_smbus_data data;
0173 
0174     DEB_D("\n");
0175 
0176     data.byte = hexium_input_select[input].byte;
0177     if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, hexium_input_select[input].adr, I2C_SMBUS_BYTE_DATA, &data)) {
0178         return -1;
0179     }
0180 
0181     return 0;
0182 }
0183 
0184 static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec)
0185 {
0186     union i2c_smbus_data data;
0187     int i = 0;
0188 
0189     DEB_D("\n");
0190 
0191     while (vdec[i].adr != -1) {
0192         data.byte = vdec[i].byte;
0193         if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, vdec[i].adr, I2C_SMBUS_BYTE_DATA, &data)) {
0194             pr_err("hexium_init_done: hexium_set_standard() failed for address 0x%02x\n",
0195                    i);
0196             return -1;
0197         }
0198         i++;
0199     }
0200     return 0;
0201 }
0202 
0203 static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
0204 {
0205     DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index);
0206 
0207     if (i->index >= HEXIUM_INPUTS)
0208         return -EINVAL;
0209 
0210     memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
0211 
0212     DEB_D("v4l2_ioctl: VIDIOC_ENUMINPUT %d\n", i->index);
0213     return 0;
0214 }
0215 
0216 static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
0217 {
0218     struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
0219     struct hexium *hexium = (struct hexium *) dev->ext_priv;
0220 
0221     *input = hexium->cur_input;
0222 
0223     DEB_D("VIDIOC_G_INPUT: %d\n", *input);
0224     return 0;
0225 }
0226 
0227 static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
0228 {
0229     struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
0230     struct hexium *hexium = (struct hexium *) dev->ext_priv;
0231 
0232     DEB_EE("VIDIOC_S_INPUT %d\n", input);
0233 
0234     if (input >= HEXIUM_INPUTS)
0235         return -EINVAL;
0236 
0237     hexium->cur_input = input;
0238     hexium_set_input(hexium, input);
0239     return 0;
0240 }
0241 
0242 static struct saa7146_ext_vv vv_data;
0243 
0244 /* this function only gets called when the probing was successful */
0245 static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
0246 {
0247     struct hexium *hexium;
0248     int ret;
0249 
0250     DEB_EE("\n");
0251 
0252     hexium = kzalloc(sizeof(*hexium), GFP_KERNEL);
0253     if (!hexium)
0254         return -ENOMEM;
0255 
0256     dev->ext_priv = hexium;
0257 
0258     /* enable i2c-port pins */
0259     saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
0260 
0261     strscpy(hexium->i2c_adapter.name, "hexium gemini",
0262         sizeof(hexium->i2c_adapter.name));
0263     saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
0264     if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
0265         DEB_S("cannot register i2c-device. skipping.\n");
0266         kfree(hexium);
0267         return -EFAULT;
0268     }
0269 
0270     /*  set HWControl GPIO number 2 */
0271     saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
0272 
0273     saa7146_write(dev, DD1_INIT, 0x07000700);
0274     saa7146_write(dev, DD1_STREAM_B, 0x00000000);
0275     saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
0276 
0277     /* the rest */
0278     hexium->cur_input = 0;
0279     hexium_init_done(dev);
0280 
0281     hexium_set_standard(hexium, hexium_pal);
0282     hexium->cur_std = V4L2_STD_PAL;
0283 
0284     hexium_set_input(hexium, 0);
0285     hexium->cur_input = 0;
0286 
0287     ret = saa7146_vv_init(dev, &vv_data);
0288     if (ret) {
0289         i2c_del_adapter(&hexium->i2c_adapter);
0290         kfree(hexium);
0291         return ret;
0292     }
0293 
0294     vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
0295     vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
0296     vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
0297     ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_VIDEO);
0298     if (ret < 0) {
0299         pr_err("cannot register capture v4l2 device. skipping.\n");
0300         saa7146_vv_release(dev);
0301         i2c_del_adapter(&hexium->i2c_adapter);
0302         kfree(hexium);
0303         return ret;
0304     }
0305 
0306     pr_info("found 'hexium gemini' frame grabber-%d\n", hexium_num);
0307     hexium_num++;
0308 
0309     return 0;
0310 }
0311 
0312 static int hexium_detach(struct saa7146_dev *dev)
0313 {
0314     struct hexium *hexium = (struct hexium *) dev->ext_priv;
0315 
0316     DEB_EE("dev:%p\n", dev);
0317 
0318     saa7146_unregister_device(&hexium->video_dev, dev);
0319     saa7146_vv_release(dev);
0320 
0321     hexium_num--;
0322 
0323     i2c_del_adapter(&hexium->i2c_adapter);
0324     kfree(hexium);
0325     return 0;
0326 }
0327 
0328 static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
0329 {
0330     struct hexium *hexium = (struct hexium *) dev->ext_priv;
0331 
0332     if (V4L2_STD_PAL == std->id) {
0333         hexium_set_standard(hexium, hexium_pal);
0334         hexium->cur_std = V4L2_STD_PAL;
0335         return 0;
0336     } else if (V4L2_STD_NTSC == std->id) {
0337         hexium_set_standard(hexium, hexium_ntsc);
0338         hexium->cur_std = V4L2_STD_NTSC;
0339         return 0;
0340     } else if (V4L2_STD_SECAM == std->id) {
0341         hexium_set_standard(hexium, hexium_secam);
0342         hexium->cur_std = V4L2_STD_SECAM;
0343         return 0;
0344     }
0345 
0346     return -1;
0347 }
0348 
0349 static struct saa7146_extension hexium_extension;
0350 
0351 static struct saa7146_pci_extension_data hexium_gemini_4bnc = {
0352     .ext_priv = "Hexium Gemini (4 BNC)",
0353     .ext = &hexium_extension,
0354 };
0355 
0356 static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = {
0357     .ext_priv = "Hexium Gemini Dual (4 BNC)",
0358     .ext = &hexium_extension,
0359 };
0360 
0361 static const struct pci_device_id pci_tbl[] = {
0362     {
0363      .vendor = PCI_VENDOR_ID_PHILIPS,
0364      .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
0365      .subvendor = 0x17c8,
0366      .subdevice = 0x2401,
0367      .driver_data = (unsigned long) &hexium_gemini_4bnc,
0368      },
0369     {
0370      .vendor = PCI_VENDOR_ID_PHILIPS,
0371      .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
0372      .subvendor = 0x17c8,
0373      .subdevice = 0x2402,
0374      .driver_data = (unsigned long) &hexium_gemini_dual_4bnc,
0375      },
0376     {
0377      .vendor = 0,
0378      }
0379 };
0380 
0381 MODULE_DEVICE_TABLE(pci, pci_tbl);
0382 
0383 static struct saa7146_ext_vv vv_data = {
0384     .inputs = HEXIUM_INPUTS,
0385     .capabilities = 0,
0386     .stds = &hexium_standards[0],
0387     .num_stds = ARRAY_SIZE(hexium_standards),
0388     .std_callback = &std_callback,
0389 };
0390 
0391 static struct saa7146_extension hexium_extension = {
0392     .name = "hexium gemini",
0393     .flags = SAA7146_USE_I2C_IRQ,
0394 
0395     .pci_tbl = &pci_tbl[0],
0396     .module = THIS_MODULE,
0397 
0398     .attach = hexium_attach,
0399     .detach = hexium_detach,
0400 
0401     .irq_mask = 0,
0402     .irq_func = NULL,
0403 };
0404 
0405 static int __init hexium_init_module(void)
0406 {
0407     if (0 != saa7146_register_extension(&hexium_extension)) {
0408         DEB_S("failed to register extension\n");
0409         return -ENODEV;
0410     }
0411 
0412     return 0;
0413 }
0414 
0415 static void __exit hexium_cleanup_module(void)
0416 {
0417     saa7146_unregister_extension(&hexium_extension);
0418 }
0419 
0420 module_init(hexium_init_module);
0421 module_exit(hexium_cleanup_module);
0422 
0423 MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards");
0424 MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
0425 MODULE_LICENSE("GPL");