linux/drivers/media/pci/saa7146/hexium_gemini.c
<<
>>
Prefs
   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_INPUTS   9
  31static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
  32        { 0, "CVBS 1",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
  33        { 1, "CVBS 2",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
  34        { 2, "CVBS 3",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
  35        { 3, "CVBS 4",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
  36        { 4, "CVBS 5",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
  37        { 5, "CVBS 6",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
  38        { 6, "Y/C 1",   V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
  39        { 7, "Y/C 2",   V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
  40        { 8, "Y/C 3",   V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
  41};
  42
  43#define HEXIUM_AUDIOS   0
  44
  45struct hexium_data
  46{
  47        s8 adr;
  48        u8 byte;
  49};
  50
  51#define HEXIUM_GEMINI_V_1_0             1
  52#define HEXIUM_GEMINI_DUAL_V_1_0        2
  53
  54struct hexium
  55{
  56        int type;
  57
  58        struct video_device     video_dev;
  59        struct i2c_adapter      i2c_adapter;
  60
  61        int             cur_input;      /* current input */
  62        v4l2_std_id     cur_std;        /* current standard */
  63};
  64
  65/* Samsung KS0127B decoder default registers */
  66static u8 hexium_ks0127b[0x100]={
  67/*00*/ 0x00,0x52,0x30,0x40,0x01,0x0C,0x2A,0x10,
  68/*08*/ 0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x06,
  69/*10*/ 0x00,0x00,0xE4,0xC0,0x00,0x00,0x00,0x00,
  70/*18*/ 0x14,0x9B,0xFE,0xFF,0xFC,0xFF,0x03,0x22,
  71/*20*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  72/*28*/ 0x00,0x00,0x00,0x00,0x00,0x2C,0x9B,0x00,
  73/*30*/ 0x00,0x00,0x10,0x80,0x80,0x10,0x80,0x80,
  74/*38*/ 0x01,0x04,0x00,0x00,0x00,0x29,0xC0,0x00,
  75/*40*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  76/*48*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  77/*50*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  78/*58*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  79/*60*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  80/*68*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  81/*70*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  82/*78*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  83/*80*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  84/*88*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  85/*90*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  86/*98*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  87/*A0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  88/*A8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  89/*B0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  90/*B8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  91/*C0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  92/*C8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  93/*D0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  94/*D8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  95/*E0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  96/*E8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  97/*F0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  98/*F8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  99};
 100
 101static struct hexium_data hexium_pal[] = {
 102        { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
 103};
 104
 105static struct hexium_data hexium_ntsc[] = {
 106        { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
 107};
 108
 109static struct hexium_data hexium_secam[] = {
 110        { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
 111};
 112
 113static struct hexium_data hexium_input_select[] = {
 114        { 0x02, 0x60 },
 115        { 0x02, 0x64 },
 116        { 0x02, 0x61 },
 117        { 0x02, 0x65 },
 118        { 0x02, 0x62 },
 119        { 0x02, 0x66 },
 120        { 0x02, 0x68 },
 121        { 0x02, 0x69 },
 122        { 0x02, 0x6A },
 123};
 124
 125/* fixme: h_offset = 0 for Hexium Gemini *Dual*, which
 126   are currently *not* supported*/
 127static struct saa7146_standard hexium_standards[] = {
 128        {
 129                .name   = "PAL",        .id     = V4L2_STD_PAL,
 130                .v_offset       = 28,   .v_field        = 288,
 131                .h_offset       = 1,    .h_pixels       = 680,
 132                .v_max_out      = 576,  .h_max_out      = 768,
 133        }, {
 134                .name   = "NTSC",       .id     = V4L2_STD_NTSC,
 135                .v_offset       = 28,   .v_field        = 240,
 136                .h_offset       = 1,    .h_pixels       = 640,
 137                .v_max_out      = 480,  .h_max_out      = 640,
 138        }, {
 139                .name   = "SECAM",      .id     = V4L2_STD_SECAM,
 140                .v_offset       = 28,   .v_field        = 288,
 141                .h_offset       = 1,    .h_pixels       = 720,
 142                .v_max_out      = 576,  .h_max_out      = 768,
 143        }
 144};
 145
 146/* bring hardware to a sane state. this has to be done, just in case someone
 147   wants to capture from this device before it has been properly initialized.
 148   the capture engine would badly fail, because no valid signal arrives on the
 149   saa7146, thus leading to timeouts and stuff. */
 150static int hexium_init_done(struct saa7146_dev *dev)
 151{
 152        struct hexium *hexium = (struct hexium *) dev->ext_priv;
 153        union i2c_smbus_data data;
 154        int i = 0;
 155
 156        DEB_D("hexium_init_done called\n");
 157
 158        /* initialize the helper ics to useful values */
 159        for (i = 0; i < sizeof(hexium_ks0127b); i++) {
 160                data.byte = hexium_ks0127b[i];
 161                if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
 162                        pr_err("hexium_init_done() failed for address 0x%02x\n",
 163                               i);
 164                }
 165        }
 166
 167        return 0;
 168}
 169
 170static int hexium_set_input(struct hexium *hexium, int input)
 171{
 172        union i2c_smbus_data data;
 173
 174        DEB_D("\n");
 175
 176        data.byte = hexium_input_select[input].byte;
 177        if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, hexium_input_select[input].adr, I2C_SMBUS_BYTE_DATA, &data)) {
 178                return -1;
 179        }
 180
 181        return 0;
 182}
 183
 184static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec)
 185{
 186        union i2c_smbus_data data;
 187        int i = 0;
 188
 189        DEB_D("\n");
 190
 191        while (vdec[i].adr != -1) {
 192                data.byte = vdec[i].byte;
 193                if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, vdec[i].adr, I2C_SMBUS_BYTE_DATA, &data)) {
 194                        pr_err("hexium_init_done: hexium_set_standard() failed for address 0x%02x\n",
 195                               i);
 196                        return -1;
 197                }
 198                i++;
 199        }
 200        return 0;
 201}
 202
 203static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
 204{
 205        DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index);
 206
 207        if (i->index >= HEXIUM_INPUTS)
 208                return -EINVAL;
 209
 210        memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
 211
 212        DEB_D("v4l2_ioctl: VIDIOC_ENUMINPUT %d\n", i->index);
 213        return 0;
 214}
 215
 216static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
 217{
 218        struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
 219        struct hexium *hexium = (struct hexium *) dev->ext_priv;
 220
 221        *input = hexium->cur_input;
 222
 223        DEB_D("VIDIOC_G_INPUT: %d\n", *input);
 224        return 0;
 225}
 226
 227static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
 228{
 229        struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
 230        struct hexium *hexium = (struct hexium *) dev->ext_priv;
 231
 232        DEB_EE("VIDIOC_S_INPUT %d\n", input);
 233
 234        if (input >= HEXIUM_INPUTS)
 235                return -EINVAL;
 236
 237        hexium->cur_input = input;
 238        hexium_set_input(hexium, input);
 239        return 0;
 240}
 241
 242static struct saa7146_ext_vv vv_data;
 243
 244/* this function only gets called when the probing was successful */
 245static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
 246{
 247        struct hexium *hexium;
 248        int ret;
 249
 250        DEB_EE("\n");
 251
 252        hexium = kzalloc(sizeof(*hexium), GFP_KERNEL);
 253        if (!hexium)
 254                return -ENOMEM;
 255
 256        dev->ext_priv = hexium;
 257
 258        /* enable i2c-port pins */
 259        saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
 260
 261        strscpy(hexium->i2c_adapter.name, "hexium gemini",
 262                sizeof(hexium->i2c_adapter.name));
 263        saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
 264        if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
 265                DEB_S("cannot register i2c-device. skipping.\n");
 266                kfree(hexium);
 267                return -EFAULT;
 268        }
 269
 270        /*  set HWControl GPIO number 2 */
 271        saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
 272
 273        saa7146_write(dev, DD1_INIT, 0x07000700);
 274        saa7146_write(dev, DD1_STREAM_B, 0x00000000);
 275        saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
 276
 277        /* the rest */
 278        hexium->cur_input = 0;
 279        hexium_init_done(dev);
 280
 281        hexium_set_standard(hexium, hexium_pal);
 282        hexium->cur_std = V4L2_STD_PAL;
 283
 284        hexium_set_input(hexium, 0);
 285        hexium->cur_input = 0;
 286
 287        saa7146_vv_init(dev, &vv_data);
 288
 289        vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
 290        vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
 291        vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
 292        ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_VIDEO);
 293        if (ret < 0) {
 294                pr_err("cannot register capture v4l2 device. skipping.\n");
 295                saa7146_vv_release(dev);
 296                i2c_del_adapter(&hexium->i2c_adapter);
 297                kfree(hexium);
 298                return ret;
 299        }
 300
 301        pr_info("found 'hexium gemini' frame grabber-%d\n", hexium_num);
 302        hexium_num++;
 303
 304        return 0;
 305}
 306
 307static int hexium_detach(struct saa7146_dev *dev)
 308{
 309        struct hexium *hexium = (struct hexium *) dev->ext_priv;
 310
 311        DEB_EE("dev:%p\n", dev);
 312
 313        saa7146_unregister_device(&hexium->video_dev, dev);
 314        saa7146_vv_release(dev);
 315
 316        hexium_num--;
 317
 318        i2c_del_adapter(&hexium->i2c_adapter);
 319        kfree(hexium);
 320        return 0;
 321}
 322
 323static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
 324{
 325        struct hexium *hexium = (struct hexium *) dev->ext_priv;
 326
 327        if (V4L2_STD_PAL == std->id) {
 328                hexium_set_standard(hexium, hexium_pal);
 329                hexium->cur_std = V4L2_STD_PAL;
 330                return 0;
 331        } else if (V4L2_STD_NTSC == std->id) {
 332                hexium_set_standard(hexium, hexium_ntsc);
 333                hexium->cur_std = V4L2_STD_NTSC;
 334                return 0;
 335        } else if (V4L2_STD_SECAM == std->id) {
 336                hexium_set_standard(hexium, hexium_secam);
 337                hexium->cur_std = V4L2_STD_SECAM;
 338                return 0;
 339        }
 340
 341        return -1;
 342}
 343
 344static struct saa7146_extension hexium_extension;
 345
 346static struct saa7146_pci_extension_data hexium_gemini_4bnc = {
 347        .ext_priv = "Hexium Gemini (4 BNC)",
 348        .ext = &hexium_extension,
 349};
 350
 351static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = {
 352        .ext_priv = "Hexium Gemini Dual (4 BNC)",
 353        .ext = &hexium_extension,
 354};
 355
 356static const struct pci_device_id pci_tbl[] = {
 357        {
 358         .vendor = PCI_VENDOR_ID_PHILIPS,
 359         .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
 360         .subvendor = 0x17c8,
 361         .subdevice = 0x2401,
 362         .driver_data = (unsigned long) &hexium_gemini_4bnc,
 363         },
 364        {
 365         .vendor = PCI_VENDOR_ID_PHILIPS,
 366         .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
 367         .subvendor = 0x17c8,
 368         .subdevice = 0x2402,
 369         .driver_data = (unsigned long) &hexium_gemini_dual_4bnc,
 370         },
 371        {
 372         .vendor = 0,
 373         }
 374};
 375
 376MODULE_DEVICE_TABLE(pci, pci_tbl);
 377
 378static struct saa7146_ext_vv vv_data = {
 379        .inputs = HEXIUM_INPUTS,
 380        .capabilities = 0,
 381        .stds = &hexium_standards[0],
 382        .num_stds = ARRAY_SIZE(hexium_standards),
 383        .std_callback = &std_callback,
 384};
 385
 386static struct saa7146_extension hexium_extension = {
 387        .name = "hexium gemini",
 388        .flags = SAA7146_USE_I2C_IRQ,
 389
 390        .pci_tbl = &pci_tbl[0],
 391        .module = THIS_MODULE,
 392
 393        .attach = hexium_attach,
 394        .detach = hexium_detach,
 395
 396        .irq_mask = 0,
 397        .irq_func = NULL,
 398};
 399
 400static int __init hexium_init_module(void)
 401{
 402        if (0 != saa7146_register_extension(&hexium_extension)) {
 403                DEB_S("failed to register extension\n");
 404                return -ENODEV;
 405        }
 406
 407        return 0;
 408}
 409
 410static void __exit hexium_cleanup_module(void)
 411{
 412        saa7146_unregister_extension(&hexium_extension);
 413}
 414
 415module_init(hexium_init_module);
 416module_exit(hexium_cleanup_module);
 417
 418MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards");
 419MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
 420MODULE_LICENSE("GPL");
 421