linux/drivers/media/video/saa7110.c
<<
>>
Prefs
   1/*
   2 * saa7110 - Philips SAA7110(A) video decoder driver
   3 *
   4 * Copyright (C) 1998 Pauline Middelink <middelin@polyware.nl>
   5 *
   6 * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
   7 * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
   8 *    - some corrections for Pinnacle Systems Inc. DC10plus card.
   9 *
  10 * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
  11 *    - moved over to linux>=2.4.x i2c protocol (1/1/2003)
  12 *
  13 * This program is free software; you can redistribute it and/or modify
  14 * it under the terms of the GNU General Public License as published by
  15 * the Free Software Foundation; either version 2 of the License, or
  16 * (at your option) any later version.
  17 *
  18 * This program is distributed in the hope that it will be useful,
  19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21 * GNU General Public License for more details.
  22 *
  23 * You should have received a copy of the GNU General Public License
  24 * along with this program; if not, write to the Free Software
  25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  26 */
  27
  28#include <linux/module.h>
  29#include <linux/init.h>
  30#include <linux/types.h>
  31#include <linux/delay.h>
  32#include <linux/slab.h>
  33#include <linux/wait.h>
  34#include <asm/io.h>
  35#include <asm/uaccess.h>
  36
  37MODULE_DESCRIPTION("Philips SAA7110 video decoder driver");
  38MODULE_AUTHOR("Pauline Middelink");
  39MODULE_LICENSE("GPL");
  40
  41#include <linux/i2c.h>
  42
  43#define I2C_NAME(s) (s)->name
  44
  45#include <linux/videodev.h>
  46#include <media/v4l2-common.h>
  47#include <linux/video_decoder.h>
  48
  49static int debug = 0;
  50module_param(debug, int, 0);
  51MODULE_PARM_DESC(debug, "Debug level (0-1)");
  52
  53#define dprintk(num, format, args...) \
  54        do { \
  55                if (debug >= num) \
  56                        printk(format, ##args); \
  57        } while (0)
  58
  59#define SAA7110_MAX_INPUT       9       /* 6 CVBS, 3 SVHS */
  60#define SAA7110_MAX_OUTPUT      0       /* its a decoder only */
  61
  62#define I2C_SAA7110             0x9C    /* or 0x9E */
  63
  64#define SAA7110_NR_REG          0x35
  65
  66struct saa7110 {
  67        u8 reg[SAA7110_NR_REG];
  68
  69        int norm;
  70        int input;
  71        int enable;
  72        int bright;
  73        int contrast;
  74        int hue;
  75        int sat;
  76
  77        wait_queue_head_t wq;
  78};
  79
  80/* ----------------------------------------------------------------------- */
  81/* I2C support functions                                                   */
  82/* ----------------------------------------------------------------------- */
  83
  84static int
  85saa7110_write (struct i2c_client *client,
  86               u8                 reg,
  87               u8                 value)
  88{
  89        struct saa7110 *decoder = i2c_get_clientdata(client);
  90
  91        decoder->reg[reg] = value;
  92        return i2c_smbus_write_byte_data(client, reg, value);
  93}
  94
  95static int
  96saa7110_write_block (struct i2c_client *client,
  97                     const u8          *data,
  98                     unsigned int       len)
  99{
 100        int ret = -1;
 101        u8 reg = *data;         /* first register to write to */
 102
 103        /* Sanity check */
 104        if (reg + (len - 1) > SAA7110_NR_REG)
 105                return ret;
 106
 107        /* the saa7110 has an autoincrement function, use it if
 108         * the adapter understands raw I2C */
 109        if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 110                struct saa7110 *decoder = i2c_get_clientdata(client);
 111
 112                ret = i2c_master_send(client, data, len);
 113
 114                /* Cache the written data */
 115                memcpy(decoder->reg + reg, data + 1, len - 1);
 116        } else {
 117                for (++data, --len; len; len--) {
 118                        if ((ret = saa7110_write(client, reg++,
 119                                                 *data++)) < 0)
 120                                break;
 121                }
 122        }
 123
 124        return ret;
 125}
 126
 127static inline int
 128saa7110_read (struct i2c_client *client)
 129{
 130        return i2c_smbus_read_byte(client);
 131}
 132
 133/* ----------------------------------------------------------------------- */
 134/* SAA7110 functions                                                       */
 135/* ----------------------------------------------------------------------- */
 136
 137#define FRESP_06H_COMPST 0x03   //0x13
 138#define FRESP_06H_SVIDEO 0x83   //0xC0
 139
 140
 141static int
 142saa7110_selmux (struct i2c_client *client,
 143                int                chan)
 144{
 145        static const unsigned char modes[9][8] = {
 146                /* mode 0 */
 147                {FRESP_06H_COMPST, 0xD9, 0x17, 0x40, 0x03,
 148                              0x44, 0x75, 0x16},
 149                /* mode 1 */
 150                {FRESP_06H_COMPST, 0xD8, 0x17, 0x40, 0x03,
 151                              0x44, 0x75, 0x16},
 152                /* mode 2 */
 153                {FRESP_06H_COMPST, 0xBA, 0x07, 0x91, 0x03,
 154                              0x60, 0xB5, 0x05},
 155                /* mode 3 */
 156                {FRESP_06H_COMPST, 0xB8, 0x07, 0x91, 0x03,
 157                              0x60, 0xB5, 0x05},
 158                /* mode 4 */
 159                {FRESP_06H_COMPST, 0x7C, 0x07, 0xD2, 0x83,
 160                              0x60, 0xB5, 0x03},
 161                /* mode 5 */
 162                {FRESP_06H_COMPST, 0x78, 0x07, 0xD2, 0x83,
 163                              0x60, 0xB5, 0x03},
 164                /* mode 6 */
 165                {FRESP_06H_SVIDEO, 0x59, 0x17, 0x42, 0xA3,
 166                              0x44, 0x75, 0x12},
 167                /* mode 7 */
 168                {FRESP_06H_SVIDEO, 0x9A, 0x17, 0xB1, 0x13,
 169                              0x60, 0xB5, 0x14},
 170                /* mode 8 */
 171                {FRESP_06H_SVIDEO, 0x3C, 0x27, 0xC1, 0x23,
 172                              0x44, 0x75, 0x21}
 173        };
 174        struct saa7110 *decoder = i2c_get_clientdata(client);
 175        const unsigned char *ptr = modes[chan];
 176
 177        saa7110_write(client, 0x06, ptr[0]);    /* Luminance control    */
 178        saa7110_write(client, 0x20, ptr[1]);    /* Analog Control #1    */
 179        saa7110_write(client, 0x21, ptr[2]);    /* Analog Control #2    */
 180        saa7110_write(client, 0x22, ptr[3]);    /* Mixer Control #1     */
 181        saa7110_write(client, 0x2C, ptr[4]);    /* Mixer Control #2     */
 182        saa7110_write(client, 0x30, ptr[5]);    /* ADCs gain control    */
 183        saa7110_write(client, 0x31, ptr[6]);    /* Mixer Control #3     */
 184        saa7110_write(client, 0x21, ptr[7]);    /* Analog Control #2    */
 185        decoder->input = chan;
 186
 187        return 0;
 188}
 189
 190static const unsigned char initseq[1 + SAA7110_NR_REG] = {
 191        0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF2, 0x03, 0x00,
 192        /* 0x08 */ 0xF8, 0xF8, 0x60, 0x60, 0x00, 0x86, 0x18, 0x90,
 193        /* 0x10 */ 0x00, 0x59, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA,
 194        /* 0x18 */ 0xF2, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 195        /* 0x20 */ 0xD9, 0x16, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F,
 196        /* 0x28 */ 0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x03, 0x0C,
 197        /* 0x30 */ 0x44, 0x71, 0x02, 0x8C, 0x02
 198};
 199
 200static int
 201determine_norm (struct i2c_client *client)
 202{
 203        DEFINE_WAIT(wait);
 204        struct saa7110 *decoder = i2c_get_clientdata(client);
 205        int status;
 206
 207        /* mode changed, start automatic detection */
 208        saa7110_write_block(client, initseq, sizeof(initseq));
 209        saa7110_selmux(client, decoder->input);
 210        prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
 211        schedule_timeout(msecs_to_jiffies(250));
 212        finish_wait(&decoder->wq, &wait);
 213        status = saa7110_read(client);
 214        if (status & 0x40) {
 215                dprintk(1, KERN_INFO "%s: status=0x%02x (no signal)\n",
 216                        I2C_NAME(client), status);
 217                return decoder->norm;   // no change
 218        }
 219        if ((status & 3) == 0) {
 220                saa7110_write(client, 0x06, 0x83);
 221                if (status & 0x20) {
 222                        dprintk(1,
 223                                KERN_INFO
 224                                "%s: status=0x%02x (NTSC/no color)\n",
 225                                I2C_NAME(client), status);
 226                        //saa7110_write(client,0x2E,0x81);
 227                        return VIDEO_MODE_NTSC;
 228                }
 229                dprintk(1, KERN_INFO "%s: status=0x%02x (PAL/no color)\n",
 230                        I2C_NAME(client), status);
 231                //saa7110_write(client,0x2E,0x9A);
 232                return VIDEO_MODE_PAL;
 233        }
 234        //saa7110_write(client,0x06,0x03);
 235        if (status & 0x20) {    /* 60Hz */
 236                dprintk(1, KERN_INFO "%s: status=0x%02x (NTSC)\n",
 237                        I2C_NAME(client), status);
 238                saa7110_write(client, 0x0D, 0x86);
 239                saa7110_write(client, 0x0F, 0x50);
 240                saa7110_write(client, 0x11, 0x2C);
 241                //saa7110_write(client,0x2E,0x81);
 242                return VIDEO_MODE_NTSC;
 243        }
 244
 245        /* 50Hz -> PAL/SECAM */
 246        saa7110_write(client, 0x0D, 0x86);
 247        saa7110_write(client, 0x0F, 0x10);
 248        saa7110_write(client, 0x11, 0x59);
 249        //saa7110_write(client,0x2E,0x9A);
 250
 251        prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
 252        schedule_timeout(msecs_to_jiffies(250));
 253        finish_wait(&decoder->wq, &wait);
 254
 255        status = saa7110_read(client);
 256        if ((status & 0x03) == 0x01) {
 257                dprintk(1, KERN_INFO "%s: status=0x%02x (SECAM)\n",
 258                        I2C_NAME(client), status);
 259                saa7110_write(client, 0x0D, 0x87);
 260                return VIDEO_MODE_SECAM;
 261        }
 262        dprintk(1, KERN_INFO "%s: status=0x%02x (PAL)\n", I2C_NAME(client),
 263                status);
 264        return VIDEO_MODE_PAL;
 265}
 266
 267static int
 268saa7110_command (struct i2c_client *client,
 269                 unsigned int       cmd,
 270                 void              *arg)
 271{
 272        struct saa7110 *decoder = i2c_get_clientdata(client);
 273        int v;
 274
 275        switch (cmd) {
 276        case 0:
 277                //saa7110_write_block(client, initseq, sizeof(initseq));
 278                break;
 279
 280        case DECODER_GET_CAPABILITIES:
 281        {
 282                struct video_decoder_capability *dc = arg;
 283
 284                dc->flags =
 285                    VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC |
 286                    VIDEO_DECODER_SECAM | VIDEO_DECODER_AUTO;
 287                dc->inputs = SAA7110_MAX_INPUT;
 288                dc->outputs = SAA7110_MAX_OUTPUT;
 289        }
 290                break;
 291
 292        case DECODER_GET_STATUS:
 293        {
 294                int status;
 295                int res = 0;
 296
 297                status = saa7110_read(client);
 298                dprintk(1, KERN_INFO "%s: status=0x%02x norm=%d\n",
 299                        I2C_NAME(client), status, decoder->norm);
 300                if (!(status & 0x40))
 301                        res |= DECODER_STATUS_GOOD;
 302                if (status & 0x03)
 303                        res |= DECODER_STATUS_COLOR;
 304
 305                switch (decoder->norm) {
 306                case VIDEO_MODE_NTSC:
 307                        res |= DECODER_STATUS_NTSC;
 308                        break;
 309                case VIDEO_MODE_PAL:
 310                        res |= DECODER_STATUS_PAL;
 311                        break;
 312                case VIDEO_MODE_SECAM:
 313                        res |= DECODER_STATUS_SECAM;
 314                        break;
 315                }
 316                *(int *) arg = res;
 317        }
 318                break;
 319
 320        case DECODER_SET_NORM:
 321                v = *(int *) arg;
 322                if (decoder->norm != v) {
 323                        decoder->norm = v;
 324                        //saa7110_write(client, 0x06, 0x03);
 325                        switch (v) {
 326                        case VIDEO_MODE_NTSC:
 327                                saa7110_write(client, 0x0D, 0x86);
 328                                saa7110_write(client, 0x0F, 0x50);
 329                                saa7110_write(client, 0x11, 0x2C);
 330                                //saa7110_write(client, 0x2E, 0x81);
 331                                dprintk(1,
 332                                        KERN_INFO "%s: switched to NTSC\n",
 333                                        I2C_NAME(client));
 334                                break;
 335                        case VIDEO_MODE_PAL:
 336                                saa7110_write(client, 0x0D, 0x86);
 337                                saa7110_write(client, 0x0F, 0x10);
 338                                saa7110_write(client, 0x11, 0x59);
 339                                //saa7110_write(client, 0x2E, 0x9A);
 340                                dprintk(1,
 341                                        KERN_INFO "%s: switched to PAL\n",
 342                                        I2C_NAME(client));
 343                                break;
 344                        case VIDEO_MODE_SECAM:
 345                                saa7110_write(client, 0x0D, 0x87);
 346                                saa7110_write(client, 0x0F, 0x10);
 347                                saa7110_write(client, 0x11, 0x59);
 348                                //saa7110_write(client, 0x2E, 0x9A);
 349                                dprintk(1,
 350                                        KERN_INFO
 351                                        "%s: switched to SECAM\n",
 352                                        I2C_NAME(client));
 353                                break;
 354                        case VIDEO_MODE_AUTO:
 355                                dprintk(1,
 356                                        KERN_INFO
 357                                        "%s: TV standard detection...\n",
 358                                        I2C_NAME(client));
 359                                decoder->norm = determine_norm(client);
 360                                *(int *) arg = decoder->norm;
 361                                break;
 362                        default:
 363                                return -EPERM;
 364                        }
 365                }
 366                break;
 367
 368        case DECODER_SET_INPUT:
 369                v = *(int *) arg;
 370                if (v < 0 || v > SAA7110_MAX_INPUT) {
 371                        dprintk(1,
 372                                KERN_INFO "%s: input=%d not available\n",
 373                                I2C_NAME(client), v);
 374                        return -EINVAL;
 375                }
 376                if (decoder->input != v) {
 377                        saa7110_selmux(client, v);
 378                        dprintk(1, KERN_INFO "%s: switched to input=%d\n",
 379                                I2C_NAME(client), v);
 380                }
 381                break;
 382
 383        case DECODER_SET_OUTPUT:
 384                v = *(int *) arg;
 385                /* not much choice of outputs */
 386                if (v != 0)
 387                        return -EINVAL;
 388                break;
 389
 390        case DECODER_ENABLE_OUTPUT:
 391                v = *(int *) arg;
 392                if (decoder->enable != v) {
 393                        decoder->enable = v;
 394                        saa7110_write(client, 0x0E, v ? 0x18 : 0x80);
 395                        dprintk(1, KERN_INFO "%s: YUV %s\n", I2C_NAME(client),
 396                                v ? "on" : "off");
 397                }
 398                break;
 399
 400        case DECODER_SET_PICTURE:
 401        {
 402                struct video_picture *pic = arg;
 403
 404                if (decoder->bright != pic->brightness) {
 405                        /* We want 0 to 255 we get 0-65535 */
 406                        decoder->bright = pic->brightness;
 407                        saa7110_write(client, 0x19, decoder->bright >> 8);
 408                }
 409                if (decoder->contrast != pic->contrast) {
 410                        /* We want 0 to 127 we get 0-65535 */
 411                        decoder->contrast = pic->contrast;
 412                        saa7110_write(client, 0x13,
 413                                      decoder->contrast >> 9);
 414                }
 415                if (decoder->sat != pic->colour) {
 416                        /* We want 0 to 127 we get 0-65535 */
 417                        decoder->sat = pic->colour;
 418                        saa7110_write(client, 0x12, decoder->sat >> 9);
 419                }
 420                if (decoder->hue != pic->hue) {
 421                        /* We want -128 to 127 we get 0-65535 */
 422                        decoder->hue = pic->hue;
 423                        saa7110_write(client, 0x07,
 424                                      (decoder->hue >> 8) - 128);
 425                }
 426        }
 427                break;
 428
 429        case DECODER_DUMP:
 430                for (v = 0; v < SAA7110_NR_REG; v += 16) {
 431                        int j;
 432                        dprintk(1, KERN_DEBUG "%s: %02x:", I2C_NAME(client),
 433                                v);
 434                        for (j = 0; j < 16 && v + j < SAA7110_NR_REG; j++)
 435                                dprintk(1, " %02x", decoder->reg[v + j]);
 436                        dprintk(1, "\n");
 437                }
 438                break;
 439
 440        default:
 441                dprintk(1, KERN_INFO "unknown saa7110_command??(%d)\n",
 442                        cmd);
 443                return -EINVAL;
 444        }
 445        return 0;
 446}
 447
 448/* ----------------------------------------------------------------------- */
 449
 450/*
 451 * Generic i2c probe
 452 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
 453 */
 454static unsigned short normal_i2c[] = {
 455        I2C_SAA7110 >> 1,
 456        (I2C_SAA7110 >> 1) + 1,
 457        I2C_CLIENT_END
 458};
 459
 460static unsigned short ignore = I2C_CLIENT_END;
 461
 462static struct i2c_client_address_data addr_data = {
 463        .normal_i2c             = normal_i2c,
 464        .probe                  = &ignore,
 465        .ignore                 = &ignore,
 466};
 467
 468static struct i2c_driver i2c_driver_saa7110;
 469
 470static int
 471saa7110_detect_client (struct i2c_adapter *adapter,
 472                       int                 address,
 473                       int                 kind)
 474{
 475        struct i2c_client *client;
 476        struct saa7110 *decoder;
 477        int rv;
 478
 479        dprintk(1,
 480                KERN_INFO
 481                "saa7110.c: detecting saa7110 client on address 0x%x\n",
 482                address << 1);
 483
 484        /* Check if the adapter supports the needed features */
 485        if (!i2c_check_functionality
 486            (adapter,
 487             I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
 488                return 0;
 489
 490        client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
 491        if (client == 0)
 492                return -ENOMEM;
 493        client->addr = address;
 494        client->adapter = adapter;
 495        client->driver = &i2c_driver_saa7110;
 496        strlcpy(I2C_NAME(client), "saa7110", sizeof(I2C_NAME(client)));
 497
 498        decoder = kzalloc(sizeof(struct saa7110), GFP_KERNEL);
 499        if (decoder == 0) {
 500                kfree(client);
 501                return -ENOMEM;
 502        }
 503        decoder->norm = VIDEO_MODE_PAL;
 504        decoder->input = 0;
 505        decoder->enable = 1;
 506        decoder->bright = 32768;
 507        decoder->contrast = 32768;
 508        decoder->hue = 32768;
 509        decoder->sat = 32768;
 510        init_waitqueue_head(&decoder->wq);
 511        i2c_set_clientdata(client, decoder);
 512
 513        rv = i2c_attach_client(client);
 514        if (rv) {
 515                kfree(client);
 516                kfree(decoder);
 517                return rv;
 518        }
 519
 520        rv = saa7110_write_block(client, initseq, sizeof(initseq));
 521        if (rv < 0)
 522                dprintk(1, KERN_ERR "%s_attach: init status %d\n",
 523                        I2C_NAME(client), rv);
 524        else {
 525                int ver, status;
 526                saa7110_write(client, 0x21, 0x10);
 527                saa7110_write(client, 0x0e, 0x18);
 528                saa7110_write(client, 0x0D, 0x04);
 529                ver = saa7110_read(client);
 530                saa7110_write(client, 0x0D, 0x06);
 531                //mdelay(150);
 532                status = saa7110_read(client);
 533                dprintk(1,
 534                        KERN_INFO
 535                        "%s_attach: SAA7110A version %x at 0x%02x, status=0x%02x\n",
 536                        I2C_NAME(client), ver, client->addr << 1, status);
 537                saa7110_write(client, 0x0D, 0x86);
 538                saa7110_write(client, 0x0F, 0x10);
 539                saa7110_write(client, 0x11, 0x59);
 540                //saa7110_write(client, 0x2E, 0x9A);
 541        }
 542
 543        //saa7110_selmux(client,0);
 544        //determine_norm(client);
 545        /* setup and implicit mode 0 select has been performed */
 546
 547        return 0;
 548}
 549
 550static int
 551saa7110_attach_adapter (struct i2c_adapter *adapter)
 552{
 553        dprintk(1,
 554                KERN_INFO
 555                "saa7110.c: starting probe for adapter %s (0x%x)\n",
 556                I2C_NAME(adapter), adapter->id);
 557        return i2c_probe(adapter, &addr_data, &saa7110_detect_client);
 558}
 559
 560static int
 561saa7110_detach_client (struct i2c_client *client)
 562{
 563        struct saa7110 *decoder = i2c_get_clientdata(client);
 564        int err;
 565
 566        err = i2c_detach_client(client);
 567        if (err) {
 568                return err;
 569        }
 570
 571        kfree(decoder);
 572        kfree(client);
 573
 574        return 0;
 575}
 576
 577/* ----------------------------------------------------------------------- */
 578
 579static struct i2c_driver i2c_driver_saa7110 = {
 580        .driver = {
 581                .name = "saa7110",
 582        },
 583
 584        .id = I2C_DRIVERID_SAA7110,
 585
 586        .attach_adapter = saa7110_attach_adapter,
 587        .detach_client = saa7110_detach_client,
 588        .command = saa7110_command,
 589};
 590
 591static int __init
 592saa7110_init (void)
 593{
 594        return i2c_add_driver(&i2c_driver_saa7110);
 595}
 596
 597static void __exit
 598saa7110_exit (void)
 599{
 600        i2c_del_driver(&i2c_driver_saa7110);
 601}
 602
 603module_init(saa7110_init);
 604module_exit(saa7110_exit);
 605