linux/drivers/media/i2c/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/uaccess.h>
  35#include <linux/i2c.h>
  36#include <linux/videodev2.h>
  37#include <media/v4l2-device.h>
  38#include <media/v4l2-chip-ident.h>
  39#include <media/v4l2-ctrls.h>
  40
  41MODULE_DESCRIPTION("Philips SAA7110 video decoder driver");
  42MODULE_AUTHOR("Pauline Middelink");
  43MODULE_LICENSE("GPL");
  44
  45
  46static int debug;
  47module_param(debug, int, 0);
  48MODULE_PARM_DESC(debug, "Debug level (0-1)");
  49
  50#define SAA7110_MAX_INPUT       9       /* 6 CVBS, 3 SVHS */
  51#define SAA7110_MAX_OUTPUT      1       /* 1 YUV */
  52
  53#define SAA7110_NR_REG          0x35
  54
  55struct saa7110 {
  56        struct v4l2_subdev sd;
  57        struct v4l2_ctrl_handler hdl;
  58        u8 reg[SAA7110_NR_REG];
  59
  60        v4l2_std_id norm;
  61        int input;
  62        int enable;
  63
  64        wait_queue_head_t wq;
  65};
  66
  67static inline struct saa7110 *to_saa7110(struct v4l2_subdev *sd)
  68{
  69        return container_of(sd, struct saa7110, sd);
  70}
  71
  72static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
  73{
  74        return &container_of(ctrl->handler, struct saa7110, hdl)->sd;
  75}
  76
  77/* ----------------------------------------------------------------------- */
  78/* I2C support functions                                                   */
  79/* ----------------------------------------------------------------------- */
  80
  81static int saa7110_write(struct v4l2_subdev *sd, u8 reg, u8 value)
  82{
  83        struct i2c_client *client = v4l2_get_subdevdata(sd);
  84        struct saa7110 *decoder = to_saa7110(sd);
  85
  86        decoder->reg[reg] = value;
  87        return i2c_smbus_write_byte_data(client, reg, value);
  88}
  89
  90static int saa7110_write_block(struct v4l2_subdev *sd, const u8 *data, unsigned int len)
  91{
  92        struct i2c_client *client = v4l2_get_subdevdata(sd);
  93        struct saa7110 *decoder = to_saa7110(sd);
  94        int ret = -1;
  95        u8 reg = *data;         /* first register to write to */
  96
  97        /* Sanity check */
  98        if (reg + (len - 1) > SAA7110_NR_REG)
  99                return ret;
 100
 101        /* the saa7110 has an autoincrement function, use it if
 102         * the adapter understands raw I2C */
 103        if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 104                ret = i2c_master_send(client, data, len);
 105
 106                /* Cache the written data */
 107                memcpy(decoder->reg + reg, data + 1, len - 1);
 108        } else {
 109                for (++data, --len; len; len--) {
 110                        ret = saa7110_write(sd, reg++, *data++);
 111                        if (ret < 0)
 112                                break;
 113                }
 114        }
 115
 116        return ret;
 117}
 118
 119static inline int saa7110_read(struct v4l2_subdev *sd)
 120{
 121        struct i2c_client *client = v4l2_get_subdevdata(sd);
 122
 123        return i2c_smbus_read_byte(client);
 124}
 125
 126/* ----------------------------------------------------------------------- */
 127/* SAA7110 functions                                                       */
 128/* ----------------------------------------------------------------------- */
 129
 130#define FRESP_06H_COMPST 0x03   /*0x13*/
 131#define FRESP_06H_SVIDEO 0x83   /*0xC0*/
 132
 133
 134static int saa7110_selmux(struct v4l2_subdev *sd, int chan)
 135{
 136        static const unsigned char modes[9][8] = {
 137                /* mode 0 */
 138                {FRESP_06H_COMPST, 0xD9, 0x17, 0x40, 0x03,
 139                              0x44, 0x75, 0x16},
 140                /* mode 1 */
 141                {FRESP_06H_COMPST, 0xD8, 0x17, 0x40, 0x03,
 142                              0x44, 0x75, 0x16},
 143                /* mode 2 */
 144                {FRESP_06H_COMPST, 0xBA, 0x07, 0x91, 0x03,
 145                              0x60, 0xB5, 0x05},
 146                /* mode 3 */
 147                {FRESP_06H_COMPST, 0xB8, 0x07, 0x91, 0x03,
 148                              0x60, 0xB5, 0x05},
 149                /* mode 4 */
 150                {FRESP_06H_COMPST, 0x7C, 0x07, 0xD2, 0x83,
 151                              0x60, 0xB5, 0x03},
 152                /* mode 5 */
 153                {FRESP_06H_COMPST, 0x78, 0x07, 0xD2, 0x83,
 154                              0x60, 0xB5, 0x03},
 155                /* mode 6 */
 156                {FRESP_06H_SVIDEO, 0x59, 0x17, 0x42, 0xA3,
 157                              0x44, 0x75, 0x12},
 158                /* mode 7 */
 159                {FRESP_06H_SVIDEO, 0x9A, 0x17, 0xB1, 0x13,
 160                              0x60, 0xB5, 0x14},
 161                /* mode 8 */
 162                {FRESP_06H_SVIDEO, 0x3C, 0x27, 0xC1, 0x23,
 163                              0x44, 0x75, 0x21}
 164        };
 165        struct saa7110 *decoder = to_saa7110(sd);
 166        const unsigned char *ptr = modes[chan];
 167
 168        saa7110_write(sd, 0x06, ptr[0]);        /* Luminance control    */
 169        saa7110_write(sd, 0x20, ptr[1]);        /* Analog Control #1    */
 170        saa7110_write(sd, 0x21, ptr[2]);        /* Analog Control #2    */
 171        saa7110_write(sd, 0x22, ptr[3]);        /* Mixer Control #1     */
 172        saa7110_write(sd, 0x2C, ptr[4]);        /* Mixer Control #2     */
 173        saa7110_write(sd, 0x30, ptr[5]);        /* ADCs gain control    */
 174        saa7110_write(sd, 0x31, ptr[6]);        /* Mixer Control #3     */
 175        saa7110_write(sd, 0x21, ptr[7]);        /* Analog Control #2    */
 176        decoder->input = chan;
 177
 178        return 0;
 179}
 180
 181static const unsigned char initseq[1 + SAA7110_NR_REG] = {
 182        0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF2, 0x03, 0x00,
 183        /* 0x08 */ 0xF8, 0xF8, 0x60, 0x60, 0x00, 0x86, 0x18, 0x90,
 184        /* 0x10 */ 0x00, 0x59, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA,
 185        /* 0x18 */ 0xF2, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 186        /* 0x20 */ 0xD9, 0x16, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F,
 187        /* 0x28 */ 0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x03, 0x0C,
 188        /* 0x30 */ 0x44, 0x71, 0x02, 0x8C, 0x02
 189};
 190
 191static v4l2_std_id determine_norm(struct v4l2_subdev *sd)
 192{
 193        DEFINE_WAIT(wait);
 194        struct saa7110 *decoder = to_saa7110(sd);
 195        int status;
 196
 197        /* mode changed, start automatic detection */
 198        saa7110_write_block(sd, initseq, sizeof(initseq));
 199        saa7110_selmux(sd, decoder->input);
 200        prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
 201        schedule_timeout(msecs_to_jiffies(250));
 202        finish_wait(&decoder->wq, &wait);
 203        status = saa7110_read(sd);
 204        if (status & 0x40) {
 205                v4l2_dbg(1, debug, sd, "status=0x%02x (no signal)\n", status);
 206                return decoder->norm;   /* no change*/
 207        }
 208        if ((status & 3) == 0) {
 209                saa7110_write(sd, 0x06, 0x83);
 210                if (status & 0x20) {
 211                        v4l2_dbg(1, debug, sd, "status=0x%02x (NTSC/no color)\n", status);
 212                        /*saa7110_write(sd,0x2E,0x81);*/
 213                        return V4L2_STD_NTSC;
 214                }
 215                v4l2_dbg(1, debug, sd, "status=0x%02x (PAL/no color)\n", status);
 216                /*saa7110_write(sd,0x2E,0x9A);*/
 217                return V4L2_STD_PAL;
 218        }
 219        /*saa7110_write(sd,0x06,0x03);*/
 220        if (status & 0x20) {    /* 60Hz */
 221                v4l2_dbg(1, debug, sd, "status=0x%02x (NTSC)\n", status);
 222                saa7110_write(sd, 0x0D, 0x86);
 223                saa7110_write(sd, 0x0F, 0x50);
 224                saa7110_write(sd, 0x11, 0x2C);
 225                /*saa7110_write(sd,0x2E,0x81);*/
 226                return V4L2_STD_NTSC;
 227        }
 228
 229        /* 50Hz -> PAL/SECAM */
 230        saa7110_write(sd, 0x0D, 0x86);
 231        saa7110_write(sd, 0x0F, 0x10);
 232        saa7110_write(sd, 0x11, 0x59);
 233        /*saa7110_write(sd,0x2E,0x9A);*/
 234
 235        prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
 236        schedule_timeout(msecs_to_jiffies(250));
 237        finish_wait(&decoder->wq, &wait);
 238
 239        status = saa7110_read(sd);
 240        if ((status & 0x03) == 0x01) {
 241                v4l2_dbg(1, debug, sd, "status=0x%02x (SECAM)\n", status);
 242                saa7110_write(sd, 0x0D, 0x87);
 243                return V4L2_STD_SECAM;
 244        }
 245        v4l2_dbg(1, debug, sd, "status=0x%02x (PAL)\n", status);
 246        return V4L2_STD_PAL;
 247}
 248
 249static int saa7110_g_input_status(struct v4l2_subdev *sd, u32 *pstatus)
 250{
 251        struct saa7110 *decoder = to_saa7110(sd);
 252        int res = V4L2_IN_ST_NO_SIGNAL;
 253        int status = saa7110_read(sd);
 254
 255        v4l2_dbg(1, debug, sd, "status=0x%02x norm=%llx\n",
 256                       status, (unsigned long long)decoder->norm);
 257        if (!(status & 0x40))
 258                res = 0;
 259        if (!(status & 0x03))
 260                res |= V4L2_IN_ST_NO_COLOR;
 261
 262        *pstatus = res;
 263        return 0;
 264}
 265
 266static int saa7110_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
 267{
 268        *(v4l2_std_id *)std = determine_norm(sd);
 269        return 0;
 270}
 271
 272static int saa7110_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
 273{
 274        struct saa7110 *decoder = to_saa7110(sd);
 275
 276        if (decoder->norm != std) {
 277                decoder->norm = std;
 278                /*saa7110_write(sd, 0x06, 0x03);*/
 279                if (std & V4L2_STD_NTSC) {
 280                        saa7110_write(sd, 0x0D, 0x86);
 281                        saa7110_write(sd, 0x0F, 0x50);
 282                        saa7110_write(sd, 0x11, 0x2C);
 283                        /*saa7110_write(sd, 0x2E, 0x81);*/
 284                        v4l2_dbg(1, debug, sd, "switched to NTSC\n");
 285                } else if (std & V4L2_STD_PAL) {
 286                        saa7110_write(sd, 0x0D, 0x86);
 287                        saa7110_write(sd, 0x0F, 0x10);
 288                        saa7110_write(sd, 0x11, 0x59);
 289                        /*saa7110_write(sd, 0x2E, 0x9A);*/
 290                        v4l2_dbg(1, debug, sd, "switched to PAL\n");
 291                } else if (std & V4L2_STD_SECAM) {
 292                        saa7110_write(sd, 0x0D, 0x87);
 293                        saa7110_write(sd, 0x0F, 0x10);
 294                        saa7110_write(sd, 0x11, 0x59);
 295                        /*saa7110_write(sd, 0x2E, 0x9A);*/
 296                        v4l2_dbg(1, debug, sd, "switched to SECAM\n");
 297                } else {
 298                        return -EINVAL;
 299                }
 300        }
 301        return 0;
 302}
 303
 304static int saa7110_s_routing(struct v4l2_subdev *sd,
 305                             u32 input, u32 output, u32 config)
 306{
 307        struct saa7110 *decoder = to_saa7110(sd);
 308
 309        if (input >= SAA7110_MAX_INPUT) {
 310                v4l2_dbg(1, debug, sd, "input=%d not available\n", input);
 311                return -EINVAL;
 312        }
 313        if (decoder->input != input) {
 314                saa7110_selmux(sd, input);
 315                v4l2_dbg(1, debug, sd, "switched to input=%d\n", input);
 316        }
 317        return 0;
 318}
 319
 320static int saa7110_s_stream(struct v4l2_subdev *sd, int enable)
 321{
 322        struct saa7110 *decoder = to_saa7110(sd);
 323
 324        if (decoder->enable != enable) {
 325                decoder->enable = enable;
 326                saa7110_write(sd, 0x0E, enable ? 0x18 : 0x80);
 327                v4l2_dbg(1, debug, sd, "YUV %s\n", enable ? "on" : "off");
 328        }
 329        return 0;
 330}
 331
 332static int saa7110_s_ctrl(struct v4l2_ctrl *ctrl)
 333{
 334        struct v4l2_subdev *sd = to_sd(ctrl);
 335
 336        switch (ctrl->id) {
 337        case V4L2_CID_BRIGHTNESS:
 338                saa7110_write(sd, 0x19, ctrl->val);
 339                break;
 340        case V4L2_CID_CONTRAST:
 341                saa7110_write(sd, 0x13, ctrl->val);
 342                break;
 343        case V4L2_CID_SATURATION:
 344                saa7110_write(sd, 0x12, ctrl->val);
 345                break;
 346        case V4L2_CID_HUE:
 347                saa7110_write(sd, 0x07, ctrl->val);
 348                break;
 349        default:
 350                return -EINVAL;
 351        }
 352        return 0;
 353}
 354
 355static int saa7110_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
 356{
 357        struct i2c_client *client = v4l2_get_subdevdata(sd);
 358
 359        return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7110, 0);
 360}
 361
 362/* ----------------------------------------------------------------------- */
 363
 364static const struct v4l2_ctrl_ops saa7110_ctrl_ops = {
 365        .s_ctrl = saa7110_s_ctrl,
 366};
 367
 368static const struct v4l2_subdev_core_ops saa7110_core_ops = {
 369        .g_chip_ident = saa7110_g_chip_ident,
 370        .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
 371        .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
 372        .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
 373        .g_ctrl = v4l2_subdev_g_ctrl,
 374        .s_ctrl = v4l2_subdev_s_ctrl,
 375        .queryctrl = v4l2_subdev_queryctrl,
 376        .querymenu = v4l2_subdev_querymenu,
 377        .s_std = saa7110_s_std,
 378};
 379
 380static const struct v4l2_subdev_video_ops saa7110_video_ops = {
 381        .s_routing = saa7110_s_routing,
 382        .s_stream = saa7110_s_stream,
 383        .querystd = saa7110_querystd,
 384        .g_input_status = saa7110_g_input_status,
 385};
 386
 387static const struct v4l2_subdev_ops saa7110_ops = {
 388        .core = &saa7110_core_ops,
 389        .video = &saa7110_video_ops,
 390};
 391
 392/* ----------------------------------------------------------------------- */
 393
 394static int saa7110_probe(struct i2c_client *client,
 395                        const struct i2c_device_id *id)
 396{
 397        struct saa7110 *decoder;
 398        struct v4l2_subdev *sd;
 399        int rv;
 400
 401        /* Check if the adapter supports the needed features */
 402        if (!i2c_check_functionality(client->adapter,
 403                I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
 404                return -ENODEV;
 405
 406        v4l_info(client, "chip found @ 0x%x (%s)\n",
 407                        client->addr << 1, client->adapter->name);
 408
 409        decoder = kzalloc(sizeof(struct saa7110), GFP_KERNEL);
 410        if (!decoder)
 411                return -ENOMEM;
 412        sd = &decoder->sd;
 413        v4l2_i2c_subdev_init(sd, client, &saa7110_ops);
 414        decoder->norm = V4L2_STD_PAL;
 415        decoder->input = 0;
 416        decoder->enable = 1;
 417        v4l2_ctrl_handler_init(&decoder->hdl, 2);
 418        v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
 419                V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
 420        v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
 421                V4L2_CID_CONTRAST, 0, 127, 1, 64);
 422        v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
 423                V4L2_CID_SATURATION, 0, 127, 1, 64);
 424        v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
 425                V4L2_CID_HUE, -128, 127, 1, 0);
 426        sd->ctrl_handler = &decoder->hdl;
 427        if (decoder->hdl.error) {
 428                int err = decoder->hdl.error;
 429
 430                v4l2_ctrl_handler_free(&decoder->hdl);
 431                kfree(decoder);
 432                return err;
 433        }
 434        v4l2_ctrl_handler_setup(&decoder->hdl);
 435
 436        init_waitqueue_head(&decoder->wq);
 437
 438        rv = saa7110_write_block(sd, initseq, sizeof(initseq));
 439        if (rv < 0) {
 440                v4l2_dbg(1, debug, sd, "init status %d\n", rv);
 441        } else {
 442                int ver, status;
 443                saa7110_write(sd, 0x21, 0x10);
 444                saa7110_write(sd, 0x0e, 0x18);
 445                saa7110_write(sd, 0x0D, 0x04);
 446                ver = saa7110_read(sd);
 447                saa7110_write(sd, 0x0D, 0x06);
 448                /*mdelay(150);*/
 449                status = saa7110_read(sd);
 450                v4l2_dbg(1, debug, sd, "version %x, status=0x%02x\n",
 451                               ver, status);
 452                saa7110_write(sd, 0x0D, 0x86);
 453                saa7110_write(sd, 0x0F, 0x10);
 454                saa7110_write(sd, 0x11, 0x59);
 455                /*saa7110_write(sd, 0x2E, 0x9A);*/
 456        }
 457
 458        /*saa7110_selmux(sd,0);*/
 459        /*determine_norm(sd);*/
 460        /* setup and implicit mode 0 select has been performed */
 461
 462        return 0;
 463}
 464
 465static int saa7110_remove(struct i2c_client *client)
 466{
 467        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 468        struct saa7110 *decoder = to_saa7110(sd);
 469
 470        v4l2_device_unregister_subdev(sd);
 471        v4l2_ctrl_handler_free(&decoder->hdl);
 472        kfree(decoder);
 473        return 0;
 474}
 475
 476/* ----------------------------------------------------------------------- */
 477
 478static const struct i2c_device_id saa7110_id[] = {
 479        { "saa7110", 0 },
 480        { }
 481};
 482MODULE_DEVICE_TABLE(i2c, saa7110_id);
 483
 484static struct i2c_driver saa7110_driver = {
 485        .driver = {
 486                .owner  = THIS_MODULE,
 487                .name   = "saa7110",
 488        },
 489        .probe          = saa7110_probe,
 490        .remove         = saa7110_remove,
 491        .id_table       = saa7110_id,
 492};
 493
 494module_i2c_driver(saa7110_driver);
 495