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