linux/drivers/staging/go7007/wis-saa7115.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2005-2006 Micronas USA Inc.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License (Version 2) as
   6 * published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 *
  13 * You should have received a copy of the GNU General Public License
  14 * along with this program; if not, write to the Free Software Foundation,
  15 * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  16 */
  17
  18#include <linux/module.h>
  19#include <linux/init.h>
  20#include <linux/i2c.h>
  21#include <linux/videodev2.h>
  22#include <linux/ioctl.h>
  23
  24#include "wis-i2c.h"
  25
  26struct wis_saa7115 {
  27        int norm;
  28        int brightness;
  29        int contrast;
  30        int saturation;
  31        int hue;
  32};
  33
  34static u8 initial_registers[] =
  35{
  36        0x01, 0x08,
  37        0x02, 0xc0,
  38        0x03, 0x20,
  39        0x04, 0x80,
  40        0x05, 0x80,
  41        0x06, 0xeb,
  42        0x07, 0xe0,
  43        0x08, 0xf0,     /* always toggle FID */
  44        0x09, 0x40,
  45        0x0a, 0x80,
  46        0x0b, 0x40,
  47        0x0c, 0x40,
  48        0x0d, 0x00,
  49        0x0e, 0x03,
  50        0x0f, 0x2a,
  51        0x10, 0x0e,
  52        0x11, 0x00,
  53        0x12, 0x8d,
  54        0x13, 0x00,
  55        0x14, 0x00,
  56        0x15, 0x11,
  57        0x16, 0x01,
  58        0x17, 0xda,
  59        0x18, 0x40,
  60        0x19, 0x80,
  61        0x1a, 0x00,
  62        0x1b, 0x42,
  63        0x1c, 0xa9,
  64        0x30, 0x66,
  65        0x31, 0x90,
  66        0x32, 0x01,
  67        0x34, 0x00,
  68        0x35, 0x00,
  69        0x36, 0x20,
  70        0x38, 0x03,
  71        0x39, 0x20,
  72        0x3a, 0x88,
  73        0x40, 0x00,
  74        0x41, 0xff,
  75        0x42, 0xff,
  76        0x43, 0xff,
  77        0x44, 0xff,
  78        0x45, 0xff,
  79        0x46, 0xff,
  80        0x47, 0xff,
  81        0x48, 0xff,
  82        0x49, 0xff,
  83        0x4a, 0xff,
  84        0x4b, 0xff,
  85        0x4c, 0xff,
  86        0x4d, 0xff,
  87        0x4e, 0xff,
  88        0x4f, 0xff,
  89        0x50, 0xff,
  90        0x51, 0xff,
  91        0x52, 0xff,
  92        0x53, 0xff,
  93        0x54, 0xf4 /*0xff*/,
  94        0x55, 0xff,
  95        0x56, 0xff,
  96        0x57, 0xff,
  97        0x58, 0x40,
  98        0x59, 0x47,
  99        0x5a, 0x06 /*0x03*/,
 100        0x5b, 0x83,
 101        0x5d, 0x06,
 102        0x5e, 0x00,
 103        0x80, 0x30, /* window defined scaler operation, task A and B enabled */
 104        0x81, 0x03, /* use scaler datapath generated V */
 105        0x83, 0x00,
 106        0x84, 0x00,
 107        0x85, 0x00,
 108        0x86, 0x45,
 109        0x87, 0x31,
 110        0x88, 0xc0,
 111        0x90, 0x02, /* task A process top field */
 112        0x91, 0x08,
 113        0x92, 0x09,
 114        0x93, 0x80,
 115        0x94, 0x06,
 116        0x95, 0x00,
 117        0x96, 0xc0,
 118        0x97, 0x02,
 119        0x98, 0x12,
 120        0x99, 0x00,
 121        0x9a, 0xf2,
 122        0x9b, 0x00,
 123        0x9c, 0xd0,
 124        0x9d, 0x02,
 125        0x9e, 0xf2,
 126        0x9f, 0x00,
 127        0xa0, 0x01,
 128        0xa1, 0x01,
 129        0xa2, 0x01,
 130        0xa4, 0x80,
 131        0xa5, 0x40,
 132        0xa6, 0x40,
 133        0xa8, 0x00,
 134        0xa9, 0x04,
 135        0xaa, 0x00,
 136        0xac, 0x00,
 137        0xad, 0x02,
 138        0xae, 0x00,
 139        0xb0, 0x00,
 140        0xb1, 0x04,
 141        0xb2, 0x00,
 142        0xb3, 0x04,
 143        0xb4, 0x00,
 144        0xb8, 0x00,
 145        0xbc, 0x00,
 146        0xc0, 0x03,     /* task B process bottom field */
 147        0xc1, 0x08,
 148        0xc2, 0x09,
 149        0xc3, 0x80,
 150        0xc4, 0x06,
 151        0xc5, 0x00,
 152        0xc6, 0xc0,
 153        0xc7, 0x02,
 154        0xc8, 0x12,
 155        0xc9, 0x00,
 156        0xca, 0xf2,
 157        0xcb, 0x00,
 158        0xcc, 0xd0,
 159        0xcd, 0x02,
 160        0xce, 0xf2,
 161        0xcf, 0x00,
 162        0xd0, 0x01,
 163        0xd1, 0x01,
 164        0xd2, 0x01,
 165        0xd4, 0x80,
 166        0xd5, 0x40,
 167        0xd6, 0x40,
 168        0xd8, 0x00,
 169        0xd9, 0x04,
 170        0xda, 0x00,
 171        0xdc, 0x00,
 172        0xdd, 0x02,
 173        0xde, 0x00,
 174        0xe0, 0x00,
 175        0xe1, 0x04,
 176        0xe2, 0x00,
 177        0xe3, 0x04,
 178        0xe4, 0x00,
 179        0xe8, 0x00,
 180        0x88, 0xf0, /* End of original static list */
 181        0x00, 0x00, /* Terminator (reg 0x00 is read-only) */
 182};
 183
 184static int write_reg(struct i2c_client *client, u8 reg, u8 value)
 185{
 186        return i2c_smbus_write_byte_data(client, reg, value);
 187}
 188
 189static int write_regs(struct i2c_client *client, u8 *regs)
 190{
 191        int i;
 192
 193        for (i = 0; regs[i] != 0x00; i += 2)
 194                if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0)
 195                        return -1;
 196        return 0;
 197}
 198
 199static int wis_saa7115_command(struct i2c_client *client,
 200                                unsigned int cmd, void *arg)
 201{
 202        struct wis_saa7115 *dec = i2c_get_clientdata(client);
 203
 204        switch (cmd) {
 205        case VIDIOC_S_INPUT:
 206        {
 207                int *input = arg;
 208
 209                i2c_smbus_write_byte_data(client, 0x02, 0xC0 | *input);
 210                i2c_smbus_write_byte_data(client, 0x09,
 211                                *input < 6 ? 0x40 : 0xC0);
 212                break;
 213        }
 214        case DECODER_SET_RESOLUTION:
 215        {
 216                struct video_decoder_resolution *res = arg;
 217                /* Course-grained scaler */
 218                int h_integer_scaler = res->width < 704 ? 704 / res->width : 1;
 219                /* Fine-grained scaler to take care of remainder */
 220                int h_scaling_increment = (704 / h_integer_scaler) *
 221                                        1024 / res->width;
 222                /* Fine-grained scaler only */
 223                int v_scaling_increment = (dec->norm & V4L2_STD_NTSC ?
 224                                240 : 288) * 1024 / res->height;
 225                u8 regs[] = {
 226                        0x88,   0xc0,
 227                        0x9c,   res->width & 0xff,
 228                        0x9d,   res->width >> 8,
 229                        0x9e,   res->height & 0xff,
 230                        0x9f,   res->height >> 8,
 231                        0xa0,   h_integer_scaler,
 232                        0xa1,   1,
 233                        0xa2,   1,
 234                        0xa8,   h_scaling_increment & 0xff,
 235                        0xa9,   h_scaling_increment >> 8,
 236                        0xac,   (h_scaling_increment / 2) & 0xff,
 237                        0xad,   (h_scaling_increment / 2) >> 8,
 238                        0xb0,   v_scaling_increment & 0xff,
 239                        0xb1,   v_scaling_increment >> 8,
 240                        0xb2,   v_scaling_increment & 0xff,
 241                        0xb3,   v_scaling_increment >> 8,
 242                        0xcc,   res->width & 0xff,
 243                        0xcd,   res->width >> 8,
 244                        0xce,   res->height & 0xff,
 245                        0xcf,   res->height >> 8,
 246                        0xd0,   h_integer_scaler,
 247                        0xd1,   1,
 248                        0xd2,   1,
 249                        0xd8,   h_scaling_increment & 0xff,
 250                        0xd9,   h_scaling_increment >> 8,
 251                        0xdc,   (h_scaling_increment / 2) & 0xff,
 252                        0xdd,   (h_scaling_increment / 2) >> 8,
 253                        0xe0,   v_scaling_increment & 0xff,
 254                        0xe1,   v_scaling_increment >> 8,
 255                        0xe2,   v_scaling_increment & 0xff,
 256                        0xe3,   v_scaling_increment >> 8,
 257                        0x88,   0xf0,
 258                        0,      0,
 259                };
 260                write_regs(client, regs);
 261                break;
 262        }
 263        case VIDIOC_S_STD:
 264        {
 265                v4l2_std_id *input = arg;
 266                u8 regs[] = {
 267                        0x88,   0xc0,
 268                        0x98,   *input & V4L2_STD_NTSC ? 0x12 : 0x16,
 269                        0x9a,   *input & V4L2_STD_NTSC ? 0xf2 : 0x20,
 270                        0x9b,   *input & V4L2_STD_NTSC ? 0x00 : 0x01,
 271                        0xc8,   *input & V4L2_STD_NTSC ? 0x12 : 0x16,
 272                        0xca,   *input & V4L2_STD_NTSC ? 0xf2 : 0x20,
 273                        0xcb,   *input & V4L2_STD_NTSC ? 0x00 : 0x01,
 274                        0x88,   0xf0,
 275                        0x30,   *input & V4L2_STD_NTSC ? 0x66 : 0x00,
 276                        0x31,   *input & V4L2_STD_NTSC ? 0x90 : 0xe0,
 277                        0,      0,
 278                };
 279                write_regs(client, regs);
 280                dec->norm = *input;
 281                break;
 282        }
 283        case VIDIOC_QUERYCTRL:
 284        {
 285                struct v4l2_queryctrl *ctrl = arg;
 286
 287                switch (ctrl->id) {
 288                case V4L2_CID_BRIGHTNESS:
 289                        ctrl->type = V4L2_CTRL_TYPE_INTEGER;
 290                        strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
 291                        ctrl->minimum = 0;
 292                        ctrl->maximum = 255;
 293                        ctrl->step = 1;
 294                        ctrl->default_value = 128;
 295                        ctrl->flags = 0;
 296                        break;
 297                case V4L2_CID_CONTRAST:
 298                        ctrl->type = V4L2_CTRL_TYPE_INTEGER;
 299                        strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
 300                        ctrl->minimum = 0;
 301                        ctrl->maximum = 127;
 302                        ctrl->step = 1;
 303                        ctrl->default_value = 64;
 304                        ctrl->flags = 0;
 305                        break;
 306                case V4L2_CID_SATURATION:
 307                        ctrl->type = V4L2_CTRL_TYPE_INTEGER;
 308                        strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
 309                        ctrl->minimum = 0;
 310                        ctrl->maximum = 127;
 311                        ctrl->step = 1;
 312                        ctrl->default_value = 64;
 313                        ctrl->flags = 0;
 314                        break;
 315                case V4L2_CID_HUE:
 316                        ctrl->type = V4L2_CTRL_TYPE_INTEGER;
 317                        strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
 318                        ctrl->minimum = -128;
 319                        ctrl->maximum = 127;
 320                        ctrl->step = 1;
 321                        ctrl->default_value = 0;
 322                        ctrl->flags = 0;
 323                        break;
 324                }
 325                break;
 326        }
 327        case VIDIOC_S_CTRL:
 328        {
 329                struct v4l2_control *ctrl = arg;
 330
 331                switch (ctrl->id) {
 332                case V4L2_CID_BRIGHTNESS:
 333                        if (ctrl->value > 255)
 334                                dec->brightness = 255;
 335                        else if (ctrl->value < 0)
 336                                dec->brightness = 0;
 337                        else
 338                                dec->brightness = ctrl->value;
 339                        write_reg(client, 0x0a, dec->brightness);
 340                        break;
 341                case V4L2_CID_CONTRAST:
 342                        if (ctrl->value > 127)
 343                                dec->contrast = 127;
 344                        else if (ctrl->value < 0)
 345                                dec->contrast = 0;
 346                        else
 347                                dec->contrast = ctrl->value;
 348                        write_reg(client, 0x0b, dec->contrast);
 349                        break;
 350                case V4L2_CID_SATURATION:
 351                        if (ctrl->value > 127)
 352                                dec->saturation = 127;
 353                        else if (ctrl->value < 0)
 354                                dec->saturation = 0;
 355                        else
 356                                dec->saturation = ctrl->value;
 357                        write_reg(client, 0x0c, dec->saturation);
 358                        break;
 359                case V4L2_CID_HUE:
 360                        if (ctrl->value > 127)
 361                                dec->hue = 127;
 362                        else if (ctrl->value < -128)
 363                                dec->hue = -128;
 364                        else
 365                                dec->hue = ctrl->value;
 366                        write_reg(client, 0x0d, dec->hue);
 367                        break;
 368                }
 369                break;
 370        }
 371        case VIDIOC_G_CTRL:
 372        {
 373                struct v4l2_control *ctrl = arg;
 374
 375                switch (ctrl->id) {
 376                case V4L2_CID_BRIGHTNESS:
 377                        ctrl->value = dec->brightness;
 378                        break;
 379                case V4L2_CID_CONTRAST:
 380                        ctrl->value = dec->contrast;
 381                        break;
 382                case V4L2_CID_SATURATION:
 383                        ctrl->value = dec->saturation;
 384                        break;
 385                case V4L2_CID_HUE:
 386                        ctrl->value = dec->hue;
 387                        break;
 388                }
 389                break;
 390        }
 391        default:
 392                break;
 393        }
 394        return 0;
 395}
 396
 397static int wis_saa7115_probe(struct i2c_client *client,
 398                             const struct i2c_device_id *id)
 399{
 400        struct i2c_adapter *adapter = client->adapter;
 401        struct wis_saa7115 *dec;
 402
 403        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 404                return -ENODEV;
 405
 406        dec = kmalloc(sizeof(struct wis_saa7115), GFP_KERNEL);
 407        if (dec == NULL)
 408                return -ENOMEM;
 409
 410        dec->norm = V4L2_STD_NTSC;
 411        dec->brightness = 128;
 412        dec->contrast = 64;
 413        dec->saturation = 64;
 414        dec->hue = 0;
 415        i2c_set_clientdata(client, dec);
 416
 417        printk(KERN_DEBUG
 418                "wis-saa7115: initializing SAA7115 at address %d on %s\n",
 419                client->addr, adapter->name);
 420
 421        if (write_regs(client, initial_registers) < 0) {
 422                printk(KERN_ERR
 423                        "wis-saa7115: error initializing SAA7115\n");
 424                kfree(dec);
 425                return -ENODEV;
 426        }
 427
 428        return 0;
 429}
 430
 431static int wis_saa7115_remove(struct i2c_client *client)
 432{
 433        struct wis_saa7115 *dec = i2c_get_clientdata(client);
 434
 435        i2c_set_clientdata(client, NULL);
 436        kfree(dec);
 437        return 0;
 438}
 439
 440static struct i2c_device_id wis_saa7115_id[] = {
 441        { "wis_saa7115", 0 },
 442        { }
 443};
 444
 445static struct i2c_driver wis_saa7115_driver = {
 446        .driver = {
 447                .name   = "WIS SAA7115 I2C driver",
 448        },
 449        .probe          = wis_saa7115_probe,
 450        .remove         = wis_saa7115_remove,
 451        .command        = wis_saa7115_command,
 452        .id_table       = wis_saa7115_id,
 453};
 454
 455static int __init wis_saa7115_init(void)
 456{
 457        return i2c_add_driver(&wis_saa7115_driver);
 458}
 459
 460static void __exit wis_saa7115_cleanup(void)
 461{
 462        i2c_del_driver(&wis_saa7115_driver);
 463}
 464
 465module_init(wis_saa7115_init);
 466module_exit(wis_saa7115_cleanup);
 467
 468MODULE_LICENSE("GPL v2");
 469