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