root/drivers/media/i2c/saa7110.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. to_saa7110
  2. to_sd
  3. saa7110_write
  4. saa7110_write_block
  5. saa7110_read
  6. saa7110_selmux
  7. determine_norm
  8. saa7110_g_input_status
  9. saa7110_querystd
  10. saa7110_s_std
  11. saa7110_s_routing
  12. saa7110_s_stream
  13. saa7110_s_ctrl
  14. saa7110_probe
  15. saa7110_remove

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

/* [<][>][^][v][top][bottom][index][help] */