linux/drivers/media/video/adv7170.c
<<
>>
Prefs
   1/*
   2 * adv7170 - adv7170, adv7171 video encoder driver version 0.0.1
   3 *
   4 * Copyright (C) 2002 Maxim Yevtyushkin <max@linuxmedialabs.com>
   5 *
   6 * Based on adv7176 driver by:
   7 *
   8 * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
   9 * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
  10 * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
  11 *    - some corrections for Pinnacle Systems Inc. DC10plus card.
  12 *
  13 * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
  14 *    - moved over to linux>=2.4.x i2c protocol (1/1/2003)
  15 *
  16 * This program is free software; you can redistribute it and/or modify
  17 * it under the terms of the GNU General Public License as published by
  18 * the Free Software Foundation; either version 2 of the License, or
  19 * (at your option) any later version.
  20 *
  21 * This program is distributed in the hope that it will be useful,
  22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24 * GNU General Public License for more details.
  25 *
  26 * You should have received a copy of the GNU General Public License
  27 * along with this program; if not, write to the Free Software
  28 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  29 */
  30
  31#include <linux/module.h>
  32#include <linux/init.h>
  33#include <linux/delay.h>
  34#include <linux/errno.h>
  35#include <linux/fs.h>
  36#include <linux/kernel.h>
  37#include <linux/major.h>
  38#include <linux/slab.h>
  39#include <linux/mm.h>
  40#include <linux/signal.h>
  41#include <linux/types.h>
  42#include <linux/i2c.h>
  43#include <asm/io.h>
  44#include <asm/pgtable.h>
  45#include <asm/page.h>
  46#include <asm/uaccess.h>
  47
  48#include <linux/videodev.h>
  49#include <linux/video_encoder.h>
  50
  51MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
  52MODULE_AUTHOR("Maxim Yevtyushkin");
  53MODULE_LICENSE("GPL");
  54
  55
  56#define I2C_NAME(x) (x)->name
  57
  58
  59static int debug = 0;
  60module_param(debug, int, 0);
  61MODULE_PARM_DESC(debug, "Debug level (0-1)");
  62
  63#define dprintk(num, format, args...) \
  64        do { \
  65                if (debug >= num) \
  66                        printk(format, ##args); \
  67        } while (0)
  68
  69/* ----------------------------------------------------------------------- */
  70
  71struct adv7170 {
  72        unsigned char reg[128];
  73
  74        int norm;
  75        int input;
  76        int enable;
  77        int bright;
  78        int contrast;
  79        int hue;
  80        int sat;
  81};
  82
  83#define   I2C_ADV7170        0xd4
  84#define   I2C_ADV7171        0x54
  85
  86static char adv7170_name[] = "adv7170";
  87static char adv7171_name[] = "adv7171";
  88
  89static char *inputs[] = { "pass_through", "play_back" };
  90static char *norms[] = { "PAL", "NTSC" };
  91
  92/* ----------------------------------------------------------------------- */
  93
  94static inline int
  95adv7170_write (struct i2c_client *client,
  96               u8                 reg,
  97               u8                 value)
  98{
  99        struct adv7170 *encoder = i2c_get_clientdata(client);
 100
 101        encoder->reg[reg] = value;
 102        return i2c_smbus_write_byte_data(client, reg, value);
 103}
 104
 105static inline int
 106adv7170_read (struct i2c_client *client,
 107              u8                 reg)
 108{
 109        return i2c_smbus_read_byte_data(client, reg);
 110}
 111
 112static int
 113adv7170_write_block (struct i2c_client *client,
 114                     const u8          *data,
 115                     unsigned int       len)
 116{
 117        int ret = -1;
 118        u8 reg;
 119
 120        /* the adv7170 has an autoincrement function, use it if
 121         * the adapter understands raw I2C */
 122        if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 123                /* do raw I2C, not smbus compatible */
 124                struct adv7170 *encoder = i2c_get_clientdata(client);
 125                u8 block_data[32];
 126                int block_len;
 127
 128                while (len >= 2) {
 129                        block_len = 0;
 130                        block_data[block_len++] = reg = data[0];
 131                        do {
 132                                block_data[block_len++] =
 133                                    encoder->reg[reg++] = data[1];
 134                                len -= 2;
 135                                data += 2;
 136                        } while (len >= 2 && data[0] == reg &&
 137                                 block_len < 32);
 138                        if ((ret = i2c_master_send(client, block_data,
 139                                                   block_len)) < 0)
 140                                break;
 141                }
 142        } else {
 143                /* do some slow I2C emulation kind of thing */
 144                while (len >= 2) {
 145                        reg = *data++;
 146                        if ((ret = adv7170_write(client, reg,
 147                                                 *data++)) < 0)
 148                                break;
 149                        len -= 2;
 150                }
 151        }
 152
 153        return ret;
 154}
 155
 156/* ----------------------------------------------------------------------- */
 157// Output filter:  S-Video  Composite
 158
 159#define MR050       0x11        //0x09
 160#define MR060       0x14        //0x0c
 161
 162//---------------------------------------------------------------------------
 163
 164#define TR0MODE     0x4c
 165#define TR0RST      0x80
 166
 167#define TR1CAPT     0x00
 168#define TR1PLAY     0x00
 169
 170
 171static const unsigned char init_NTSC[] = {
 172        0x00, 0x10,             // MR0
 173        0x01, 0x20,             // MR1
 174        0x02, 0x0e,             // MR2 RTC control: bits 2 and 1
 175        0x03, 0x80,             // MR3
 176        0x04, 0x30,             // MR4
 177        0x05, 0x00,             // Reserved
 178        0x06, 0x00,             // Reserved
 179        0x07, TR0MODE,          // TM0
 180        0x08, TR1CAPT,          // TM1
 181        0x09, 0x16,             // Fsc0
 182        0x0a, 0x7c,             // Fsc1
 183        0x0b, 0xf0,             // Fsc2
 184        0x0c, 0x21,             // Fsc3
 185        0x0d, 0x00,             // Subcarrier Phase
 186        0x0e, 0x00,             // Closed Capt. Ext 0
 187        0x0f, 0x00,             // Closed Capt. Ext 1
 188        0x10, 0x00,             // Closed Capt. 0
 189        0x11, 0x00,             // Closed Capt. 1
 190        0x12, 0x00,             // Pedestal Ctl 0
 191        0x13, 0x00,             // Pedestal Ctl 1
 192        0x14, 0x00,             // Pedestal Ctl 2
 193        0x15, 0x00,             // Pedestal Ctl 3
 194        0x16, 0x00,             // CGMS_WSS_0
 195        0x17, 0x00,             // CGMS_WSS_1
 196        0x18, 0x00,             // CGMS_WSS_2
 197        0x19, 0x00,             // Teletext Ctl
 198};
 199
 200static const unsigned char init_PAL[] = {
 201        0x00, 0x71,             // MR0
 202        0x01, 0x20,             // MR1
 203        0x02, 0x0e,             // MR2 RTC control: bits 2 and 1
 204        0x03, 0x80,             // MR3
 205        0x04, 0x30,             // MR4
 206        0x05, 0x00,             // Reserved
 207        0x06, 0x00,             // Reserved
 208        0x07, TR0MODE,          // TM0
 209        0x08, TR1CAPT,          // TM1
 210        0x09, 0xcb,             // Fsc0
 211        0x0a, 0x8a,             // Fsc1
 212        0x0b, 0x09,             // Fsc2
 213        0x0c, 0x2a,             // Fsc3
 214        0x0d, 0x00,             // Subcarrier Phase
 215        0x0e, 0x00,             // Closed Capt. Ext 0
 216        0x0f, 0x00,             // Closed Capt. Ext 1
 217        0x10, 0x00,             // Closed Capt. 0
 218        0x11, 0x00,             // Closed Capt. 1
 219        0x12, 0x00,             // Pedestal Ctl 0
 220        0x13, 0x00,             // Pedestal Ctl 1
 221        0x14, 0x00,             // Pedestal Ctl 2
 222        0x15, 0x00,             // Pedestal Ctl 3
 223        0x16, 0x00,             // CGMS_WSS_0
 224        0x17, 0x00,             // CGMS_WSS_1
 225        0x18, 0x00,             // CGMS_WSS_2
 226        0x19, 0x00,             // Teletext Ctl
 227};
 228
 229
 230static int
 231adv7170_command (struct i2c_client *client,
 232                 unsigned int       cmd,
 233                 void *             arg)
 234{
 235        struct adv7170 *encoder = i2c_get_clientdata(client);
 236
 237        switch (cmd) {
 238
 239        case 0:
 240#if 0
 241                /* This is just for testing!!! */
 242                adv7170_write_block(client, init_common,
 243                                    sizeof(init_common));
 244                adv7170_write(client, 0x07, TR0MODE | TR0RST);
 245                adv7170_write(client, 0x07, TR0MODE);
 246#endif
 247                break;
 248
 249        case ENCODER_GET_CAPABILITIES:
 250        {
 251                struct video_encoder_capability *cap = arg;
 252
 253                cap->flags = VIDEO_ENCODER_PAL |
 254                             VIDEO_ENCODER_NTSC;
 255                cap->inputs = 2;
 256                cap->outputs = 1;
 257        }
 258                break;
 259
 260        case ENCODER_SET_NORM:
 261        {
 262                int iarg = *(int *) arg;
 263
 264                dprintk(1, KERN_DEBUG "%s_command: set norm %d",
 265                        I2C_NAME(client), iarg);
 266
 267                switch (iarg) {
 268
 269                case VIDEO_MODE_NTSC:
 270                        adv7170_write_block(client, init_NTSC,
 271                                            sizeof(init_NTSC));
 272                        if (encoder->input == 0)
 273                                adv7170_write(client, 0x02, 0x0e);      // Enable genlock
 274                        adv7170_write(client, 0x07, TR0MODE | TR0RST);
 275                        adv7170_write(client, 0x07, TR0MODE);
 276                        break;
 277
 278                case VIDEO_MODE_PAL:
 279                        adv7170_write_block(client, init_PAL,
 280                                            sizeof(init_PAL));
 281                        if (encoder->input == 0)
 282                                adv7170_write(client, 0x02, 0x0e);      // Enable genlock
 283                        adv7170_write(client, 0x07, TR0MODE | TR0RST);
 284                        adv7170_write(client, 0x07, TR0MODE);
 285                        break;
 286
 287                default:
 288                        dprintk(1, KERN_ERR "%s: illegal norm: %d\n",
 289                               I2C_NAME(client), iarg);
 290                        return -EINVAL;
 291
 292                }
 293                dprintk(1, KERN_DEBUG "%s: switched to %s\n", I2C_NAME(client),
 294                        norms[iarg]);
 295                encoder->norm = iarg;
 296        }
 297                break;
 298
 299        case ENCODER_SET_INPUT:
 300        {
 301                int iarg = *(int *) arg;
 302
 303                /* RJ: *iarg = 0: input is from decoder
 304                 *iarg = 1: input is from ZR36060
 305                 *iarg = 2: color bar */
 306
 307                dprintk(1, KERN_DEBUG "%s_command: set input from %s\n",
 308                        I2C_NAME(client),
 309                        iarg == 0 ? "decoder" : "ZR36060");
 310
 311                switch (iarg) {
 312
 313                case 0:
 314                        adv7170_write(client, 0x01, 0x20);
 315                        adv7170_write(client, 0x08, TR1CAPT);   /* TR1 */
 316                        adv7170_write(client, 0x02, 0x0e);      // Enable genlock
 317                        adv7170_write(client, 0x07, TR0MODE | TR0RST);
 318                        adv7170_write(client, 0x07, TR0MODE);
 319                        //udelay(10);
 320                        break;
 321
 322                case 1:
 323                        adv7170_write(client, 0x01, 0x00);
 324                        adv7170_write(client, 0x08, TR1PLAY);   /* TR1 */
 325                        adv7170_write(client, 0x02, 0x08);
 326                        adv7170_write(client, 0x07, TR0MODE | TR0RST);
 327                        adv7170_write(client, 0x07, TR0MODE);
 328                        //udelay(10);
 329                        break;
 330
 331                default:
 332                        dprintk(1, KERN_ERR "%s: illegal input: %d\n",
 333                                I2C_NAME(client), iarg);
 334                        return -EINVAL;
 335
 336                }
 337                dprintk(1, KERN_DEBUG "%s: switched to %s\n", I2C_NAME(client),
 338                        inputs[iarg]);
 339                encoder->input = iarg;
 340        }
 341                break;
 342
 343        case ENCODER_SET_OUTPUT:
 344        {
 345                int *iarg = arg;
 346
 347                /* not much choice of outputs */
 348                if (*iarg != 0) {
 349                        return -EINVAL;
 350                }
 351        }
 352                break;
 353
 354        case ENCODER_ENABLE_OUTPUT:
 355        {
 356                int *iarg = arg;
 357
 358                encoder->enable = !!*iarg;
 359        }
 360                break;
 361
 362        default:
 363                return -EINVAL;
 364        }
 365
 366        return 0;
 367}
 368
 369/* ----------------------------------------------------------------------- */
 370
 371/*
 372 * Generic i2c probe
 373 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
 374 */
 375static unsigned short normal_i2c[] =
 376    { I2C_ADV7170 >> 1, (I2C_ADV7170 >> 1) + 1,
 377        I2C_ADV7171 >> 1, (I2C_ADV7171 >> 1) + 1,
 378        I2C_CLIENT_END
 379};
 380
 381static unsigned short ignore = I2C_CLIENT_END;
 382
 383static struct i2c_client_address_data addr_data = {
 384        .normal_i2c             = normal_i2c,
 385        .probe                  = &ignore,
 386        .ignore                 = &ignore,
 387};
 388
 389static struct i2c_driver i2c_driver_adv7170;
 390
 391static int
 392adv7170_detect_client (struct i2c_adapter *adapter,
 393                       int                 address,
 394                       int                 kind)
 395{
 396        int i;
 397        struct i2c_client *client;
 398        struct adv7170 *encoder;
 399        char *dname;
 400
 401        dprintk(1,
 402                KERN_INFO
 403                "adv7170.c: detecting adv7170 client on address 0x%x\n",
 404                address << 1);
 405
 406        /* Check if the adapter supports the needed features */
 407        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 408                return 0;
 409
 410        client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
 411        if (client == 0)
 412                return -ENOMEM;
 413        client->addr = address;
 414        client->adapter = adapter;
 415        client->driver = &i2c_driver_adv7170;
 416        if ((client->addr == I2C_ADV7170 >> 1) ||
 417            (client->addr == (I2C_ADV7170 >> 1) + 1)) {
 418                dname = adv7170_name;
 419        } else if ((client->addr == I2C_ADV7171 >> 1) ||
 420                   (client->addr == (I2C_ADV7171 >> 1) + 1)) {
 421                dname = adv7171_name;
 422        } else {
 423                /* We should never get here!!! */
 424                kfree(client);
 425                return 0;
 426        }
 427        strlcpy(I2C_NAME(client), dname, sizeof(I2C_NAME(client)));
 428
 429        encoder = kzalloc(sizeof(struct adv7170), GFP_KERNEL);
 430        if (encoder == NULL) {
 431                kfree(client);
 432                return -ENOMEM;
 433        }
 434        encoder->norm = VIDEO_MODE_NTSC;
 435        encoder->input = 0;
 436        encoder->enable = 1;
 437        i2c_set_clientdata(client, encoder);
 438
 439        i = i2c_attach_client(client);
 440        if (i) {
 441                kfree(client);
 442                kfree(encoder);
 443                return i;
 444        }
 445
 446        i = adv7170_write_block(client, init_NTSC, sizeof(init_NTSC));
 447        if (i >= 0) {
 448                i = adv7170_write(client, 0x07, TR0MODE | TR0RST);
 449                i = adv7170_write(client, 0x07, TR0MODE);
 450                i = adv7170_read(client, 0x12);
 451                dprintk(1, KERN_INFO "%s_attach: rev. %d at 0x%02x\n",
 452                        I2C_NAME(client), i & 1, client->addr << 1);
 453        }
 454        if (i < 0) {
 455                dprintk(1, KERN_ERR "%s_attach: init error 0x%x\n",
 456                       I2C_NAME(client), i);
 457        }
 458
 459        return 0;
 460}
 461
 462static int
 463adv7170_attach_adapter (struct i2c_adapter *adapter)
 464{
 465        dprintk(1,
 466                KERN_INFO
 467                "adv7170.c: starting probe for adapter %s (0x%x)\n",
 468                I2C_NAME(adapter), adapter->id);
 469        return i2c_probe(adapter, &addr_data, &adv7170_detect_client);
 470}
 471
 472static int
 473adv7170_detach_client (struct i2c_client *client)
 474{
 475        struct adv7170 *encoder = i2c_get_clientdata(client);
 476        int err;
 477
 478        err = i2c_detach_client(client);
 479        if (err) {
 480                return err;
 481        }
 482
 483        kfree(encoder);
 484        kfree(client);
 485
 486        return 0;
 487}
 488
 489/* ----------------------------------------------------------------------- */
 490
 491static struct i2c_driver i2c_driver_adv7170 = {
 492        .driver = {
 493                .name = "adv7170",      /* name */
 494        },
 495
 496        .id = I2C_DRIVERID_ADV7170,
 497
 498        .attach_adapter = adv7170_attach_adapter,
 499        .detach_client = adv7170_detach_client,
 500        .command = adv7170_command,
 501};
 502
 503static int __init
 504adv7170_init (void)
 505{
 506        return i2c_add_driver(&i2c_driver_adv7170);
 507}
 508
 509static void __exit
 510adv7170_exit (void)
 511{
 512        i2c_del_driver(&i2c_driver_adv7170);
 513}
 514
 515module_init(adv7170_init);
 516module_exit(adv7170_exit);
 517