linux/drivers/media/pci/saa7146/hexium_orion.c
<<
>>
Prefs
   1/*
   2    hexium_orion.c - v4l2 driver for the Hexium Orion 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_HV_PCI6_ORION            1
  39#define HEXIUM_ORION_1SVHS_3BNC         2
  40#define HEXIUM_ORION_4BNC               3
  41
  42#define HEXIUM_INPUTS   9
  43static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
  44        { 0, "CVBS 1",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
  45        { 1, "CVBS 2",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
  46        { 2, "CVBS 3",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
  47        { 3, "CVBS 4",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
  48        { 4, "CVBS 5",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
  49        { 5, "CVBS 6",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
  50        { 6, "Y/C 1",   V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
  51        { 7, "Y/C 2",   V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
  52        { 8, "Y/C 3",   V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
  53};
  54
  55#define HEXIUM_AUDIOS   0
  56
  57struct hexium_data
  58{
  59        s8 adr;
  60        u8 byte;
  61};
  62
  63struct hexium
  64{
  65        int type;
  66        struct video_device     video_dev;
  67        struct i2c_adapter      i2c_adapter;
  68
  69        int cur_input;  /* current input */
  70};
  71
  72/* Philips SAA7110 decoder default registers */
  73static u8 hexium_saa7110[53]={
  74/*00*/ 0x4C,0x3C,0x0D,0xEF,0xBD,0xF0,0x00,0x00,
  75/*08*/ 0xF8,0xF8,0x60,0x60,0x40,0x86,0x18,0x90,
  76/*10*/ 0x00,0x2C,0x40,0x46,0x42,0x1A,0xFF,0xDA,
  77/*18*/ 0xF0,0x8B,0x00,0x00,0x00,0x00,0x00,0x00,
  78/*20*/ 0xD9,0x17,0x40,0x41,0x80,0x41,0x80,0x4F,
  79/*28*/ 0xFE,0x01,0x0F,0x0F,0x03,0x01,0x81,0x03,
  80/*30*/ 0x44,0x75,0x01,0x8C,0x03
  81};
  82
  83static struct {
  84        struct hexium_data data[8];
  85} hexium_input_select[] = {
  86{
  87        { /* cvbs 1 */
  88                { 0x06, 0x00 },
  89                { 0x20, 0xD9 },
  90                { 0x21, 0x17 }, // 0x16,
  91                { 0x22, 0x40 },
  92                { 0x2C, 0x03 },
  93                { 0x30, 0x44 },
  94                { 0x31, 0x75 }, // ??
  95                { 0x21, 0x16 }, // 0x03,
  96        }
  97}, {
  98        { /* cvbs 2 */
  99                { 0x06, 0x00 },
 100                { 0x20, 0x78 },
 101                { 0x21, 0x07 }, // 0x03,
 102                { 0x22, 0xD2 },
 103                { 0x2C, 0x83 },
 104                { 0x30, 0x60 },
 105                { 0x31, 0xB5 }, // ?
 106                { 0x21, 0x03 },
 107        }
 108}, {
 109        { /* cvbs 3 */
 110                { 0x06, 0x00 },
 111                { 0x20, 0xBA },
 112                { 0x21, 0x07 }, // 0x05,
 113                { 0x22, 0x91 },
 114                { 0x2C, 0x03 },
 115                { 0x30, 0x60 },
 116                { 0x31, 0xB5 }, // ??
 117                { 0x21, 0x05 }, // 0x03,
 118        }
 119}, {
 120        { /* cvbs 4 */
 121                { 0x06, 0x00 },
 122                { 0x20, 0xD8 },
 123                { 0x21, 0x17 }, // 0x16,
 124                { 0x22, 0x40 },
 125                { 0x2C, 0x03 },
 126                { 0x30, 0x44 },
 127                { 0x31, 0x75 }, // ??
 128                { 0x21, 0x16 }, // 0x03,
 129        }
 130}, {
 131        { /* cvbs 5 */
 132                { 0x06, 0x00 },
 133                { 0x20, 0xB8 },
 134                { 0x21, 0x07 }, // 0x05,
 135                { 0x22, 0x91 },
 136                { 0x2C, 0x03 },
 137                { 0x30, 0x60 },
 138                { 0x31, 0xB5 }, // ??
 139                { 0x21, 0x05 }, // 0x03,
 140        }
 141}, {
 142        { /* cvbs 6 */
 143                { 0x06, 0x00 },
 144                { 0x20, 0x7C },
 145                { 0x21, 0x07 }, // 0x03
 146                { 0x22, 0xD2 },
 147                { 0x2C, 0x83 },
 148                { 0x30, 0x60 },
 149                { 0x31, 0xB5 }, // ??
 150                { 0x21, 0x03 },
 151        }
 152}, {
 153        { /* y/c 1 */
 154                { 0x06, 0x80 },
 155                { 0x20, 0x59 },
 156                { 0x21, 0x17 },
 157                { 0x22, 0x42 },
 158                { 0x2C, 0xA3 },
 159                { 0x30, 0x44 },
 160                { 0x31, 0x75 },
 161                { 0x21, 0x12 },
 162        }
 163}, {
 164        { /* y/c 2 */
 165                { 0x06, 0x80 },
 166                { 0x20, 0x9A },
 167                { 0x21, 0x17 },
 168                { 0x22, 0xB1 },
 169                { 0x2C, 0x13 },
 170                { 0x30, 0x60 },
 171                { 0x31, 0xB5 },
 172                { 0x21, 0x14 },
 173        }
 174}, {
 175        { /* y/c 3 */
 176                { 0x06, 0x80 },
 177                { 0x20, 0x3C },
 178                { 0x21, 0x27 },
 179                { 0x22, 0xC1 },
 180                { 0x2C, 0x23 },
 181                { 0x30, 0x44 },
 182                { 0x31, 0x75 },
 183                { 0x21, 0x21 },
 184        }
 185}
 186};
 187
 188static struct saa7146_standard hexium_standards[] = {
 189        {
 190                .name   = "PAL",        .id     = V4L2_STD_PAL,
 191                .v_offset       = 16,   .v_field        = 288,
 192                .h_offset       = 1,    .h_pixels       = 680,
 193                .v_max_out      = 576,  .h_max_out      = 768,
 194        }, {
 195                .name   = "NTSC",       .id     = V4L2_STD_NTSC,
 196                .v_offset       = 16,   .v_field        = 240,
 197                .h_offset       = 1,    .h_pixels       = 640,
 198                .v_max_out      = 480,  .h_max_out      = 640,
 199        }, {
 200                .name   = "SECAM",      .id     = V4L2_STD_SECAM,
 201                .v_offset       = 16,   .v_field        = 288,
 202                .h_offset       = 1,    .h_pixels       = 720,
 203                .v_max_out      = 576,  .h_max_out      = 768,
 204        }
 205};
 206
 207/* this is only called for old HV-PCI6/Orion cards
 208   without eeprom */
 209static int hexium_probe(struct saa7146_dev *dev)
 210{
 211        struct hexium *hexium = NULL;
 212        union i2c_smbus_data data;
 213        int err = 0;
 214
 215        DEB_EE("\n");
 216
 217        /* there are no hexium orion cards with revision 0 saa7146s */
 218        if (0 == dev->revision) {
 219                return -EFAULT;
 220        }
 221
 222        hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
 223        if (NULL == hexium) {
 224                pr_err("hexium_probe: not enough kernel memory\n");
 225                return -ENOMEM;
 226        }
 227
 228        /* enable i2c-port pins */
 229        saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
 230
 231        saa7146_write(dev, DD1_INIT, 0x01000100);
 232        saa7146_write(dev, DD1_STREAM_B, 0x00000000);
 233        saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
 234
 235        hexium->i2c_adapter = (struct i2c_adapter) {
 236                .name = "hexium orion",
 237        };
 238        saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
 239        if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
 240                DEB_S("cannot register i2c-device. skipping.\n");
 241                kfree(hexium);
 242                return -EFAULT;
 243        }
 244
 245        /* set SAA7110 control GPIO 0 */
 246        saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI);
 247        /*  set HWControl GPIO number 2 */
 248        saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
 249
 250        mdelay(10);
 251
 252        /* detect newer Hexium Orion cards by subsystem ids */
 253        if (0x17c8 == dev->pci->subsystem_vendor && 0x0101 == dev->pci->subsystem_device) {
 254                pr_info("device is a Hexium Orion w/ 1 SVHS + 3 BNC inputs\n");
 255                /* we store the pointer in our private data field */
 256                dev->ext_priv = hexium;
 257                hexium->type = HEXIUM_ORION_1SVHS_3BNC;
 258                return 0;
 259        }
 260
 261        if (0x17c8 == dev->pci->subsystem_vendor && 0x2101 == dev->pci->subsystem_device) {
 262                pr_info("device is a Hexium Orion w/ 4 BNC inputs\n");
 263                /* we store the pointer in our private data field */
 264                dev->ext_priv = hexium;
 265                hexium->type = HEXIUM_ORION_4BNC;
 266                return 0;
 267        }
 268
 269        /* check if this is an old hexium Orion card by looking at
 270           a saa7110 at address 0x4e */
 271        if (0 == (err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) {
 272                pr_info("device is a Hexium HV-PCI6/Orion (old)\n");
 273                /* we store the pointer in our private data field */
 274                dev->ext_priv = hexium;
 275                hexium->type = HEXIUM_HV_PCI6_ORION;
 276                return 0;
 277        }
 278
 279        i2c_del_adapter(&hexium->i2c_adapter);
 280        kfree(hexium);
 281        return -EFAULT;
 282}
 283
 284/* bring hardware to a sane state. this has to be done, just in case someone
 285   wants to capture from this device before it has been properly initialized.
 286   the capture engine would badly fail, because no valid signal arrives on the
 287   saa7146, thus leading to timeouts and stuff. */
 288static int hexium_init_done(struct saa7146_dev *dev)
 289{
 290        struct hexium *hexium = (struct hexium *) dev->ext_priv;
 291        union i2c_smbus_data data;
 292        int i = 0;
 293
 294        DEB_D("hexium_init_done called\n");
 295
 296        /* initialize the helper ics to useful values */
 297        for (i = 0; i < sizeof(hexium_saa7110); i++) {
 298                data.byte = hexium_saa7110[i];
 299                if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
 300                        pr_err("failed for address 0x%02x\n", i);
 301                }
 302        }
 303
 304        return 0;
 305}
 306
 307static int hexium_set_input(struct hexium *hexium, int input)
 308{
 309        union i2c_smbus_data data;
 310        int i = 0;
 311
 312        DEB_D("\n");
 313
 314        for (i = 0; i < 8; i++) {
 315                int adr = hexium_input_select[input].data[i].adr;
 316                data.byte = hexium_input_select[input].data[i].byte;
 317                if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, adr, I2C_SMBUS_BYTE_DATA, &data)) {
 318                        return -1;
 319                }
 320                pr_debug("%d: 0x%02x => 0x%02x\n", input, adr, data.byte);
 321        }
 322
 323        return 0;
 324}
 325
 326static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
 327{
 328        DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index);
 329
 330        if (i->index >= HEXIUM_INPUTS)
 331                return -EINVAL;
 332
 333        memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
 334
 335        DEB_D("v4l2_ioctl: VIDIOC_ENUMINPUT %d\n", i->index);
 336        return 0;
 337}
 338
 339static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
 340{
 341        struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
 342        struct hexium *hexium = (struct hexium *) dev->ext_priv;
 343
 344        *input = hexium->cur_input;
 345
 346        DEB_D("VIDIOC_G_INPUT: %d\n", *input);
 347        return 0;
 348}
 349
 350static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
 351{
 352        struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
 353        struct hexium *hexium = (struct hexium *) dev->ext_priv;
 354
 355        if (input >= HEXIUM_INPUTS)
 356                return -EINVAL;
 357
 358        hexium->cur_input = input;
 359        hexium_set_input(hexium, input);
 360
 361        return 0;
 362}
 363
 364static struct saa7146_ext_vv vv_data;
 365
 366/* this function only gets called when the probing was successful */
 367static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
 368{
 369        struct hexium *hexium = (struct hexium *) dev->ext_priv;
 370
 371        DEB_EE("\n");
 372
 373        saa7146_vv_init(dev, &vv_data);
 374        vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
 375        vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
 376        vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
 377        if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) {
 378                pr_err("cannot register capture v4l2 device. skipping.\n");
 379                return -1;
 380        }
 381
 382        pr_err("found 'hexium orion' frame grabber-%d\n", hexium_num);
 383        hexium_num++;
 384
 385        /* the rest */
 386        hexium->cur_input = 0;
 387        hexium_init_done(dev);
 388
 389        return 0;
 390}
 391
 392static int hexium_detach(struct saa7146_dev *dev)
 393{
 394        struct hexium *hexium = (struct hexium *) dev->ext_priv;
 395
 396        DEB_EE("dev:%p\n", dev);
 397
 398        saa7146_unregister_device(&hexium->video_dev, dev);
 399        saa7146_vv_release(dev);
 400
 401        hexium_num--;
 402
 403        i2c_del_adapter(&hexium->i2c_adapter);
 404        kfree(hexium);
 405        return 0;
 406}
 407
 408static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
 409{
 410        return 0;
 411}
 412
 413static struct saa7146_extension extension;
 414
 415static struct saa7146_pci_extension_data hexium_hv_pci6 = {
 416        .ext_priv = "Hexium HV-PCI6 / Orion",
 417        .ext = &extension,
 418};
 419
 420static struct saa7146_pci_extension_data hexium_orion_1svhs_3bnc = {
 421        .ext_priv = "Hexium HV-PCI6 / Orion (1 SVHS/3 BNC)",
 422        .ext = &extension,
 423};
 424
 425static struct saa7146_pci_extension_data hexium_orion_4bnc = {
 426        .ext_priv = "Hexium HV-PCI6 / Orion (4 BNC)",
 427        .ext = &extension,
 428};
 429
 430static struct pci_device_id pci_tbl[] = {
 431        {
 432         .vendor = PCI_VENDOR_ID_PHILIPS,
 433         .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
 434         .subvendor = 0x0000,
 435         .subdevice = 0x0000,
 436         .driver_data = (unsigned long) &hexium_hv_pci6,
 437         },
 438        {
 439         .vendor = PCI_VENDOR_ID_PHILIPS,
 440         .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
 441         .subvendor = 0x17c8,
 442         .subdevice = 0x0101,
 443         .driver_data = (unsigned long) &hexium_orion_1svhs_3bnc,
 444         },
 445        {
 446         .vendor = PCI_VENDOR_ID_PHILIPS,
 447         .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
 448         .subvendor = 0x17c8,
 449         .subdevice = 0x2101,
 450         .driver_data = (unsigned long) &hexium_orion_4bnc,
 451         },
 452        {
 453         .vendor = 0,
 454         }
 455};
 456
 457MODULE_DEVICE_TABLE(pci, pci_tbl);
 458
 459static struct saa7146_ext_vv vv_data = {
 460        .inputs = HEXIUM_INPUTS,
 461        .capabilities = 0,
 462        .stds = &hexium_standards[0],
 463        .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
 464        .std_callback = &std_callback,
 465};
 466
 467static struct saa7146_extension extension = {
 468        .name = "hexium HV-PCI6 Orion",
 469        .flags = 0,             // SAA7146_USE_I2C_IRQ,
 470
 471        .pci_tbl = &pci_tbl[0],
 472        .module = THIS_MODULE,
 473
 474        .probe = hexium_probe,
 475        .attach = hexium_attach,
 476        .detach = hexium_detach,
 477
 478        .irq_mask = 0,
 479        .irq_func = NULL,
 480};
 481
 482static int __init hexium_init_module(void)
 483{
 484        if (0 != saa7146_register_extension(&extension)) {
 485                DEB_S("failed to register extension\n");
 486                return -ENODEV;
 487        }
 488
 489        return 0;
 490}
 491
 492static void __exit hexium_cleanup_module(void)
 493{
 494        saa7146_unregister_extension(&extension);
 495}
 496
 497module_init(hexium_init_module);
 498module_exit(hexium_cleanup_module);
 499
 500MODULE_DESCRIPTION("video4linux-2 driver for Hexium Orion frame grabber cards");
 501MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
 502MODULE_LICENSE("GPL");
 503