Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * saa7110 - Philips SAA7110(A) video decoder driver
0004  *
0005  * Copyright (C) 1998 Pauline Middelink <middelin@polyware.nl>
0006  *
0007  * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
0008  * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
0009  *    - some corrections for Pinnacle Systems Inc. DC10plus card.
0010  *
0011  * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
0012  *    - moved over to linux>=2.4.x i2c protocol (1/1/2003)
0013  */
0014 
0015 #include <linux/module.h>
0016 #include <linux/init.h>
0017 #include <linux/types.h>
0018 #include <linux/delay.h>
0019 #include <linux/slab.h>
0020 #include <linux/wait.h>
0021 #include <linux/uaccess.h>
0022 #include <linux/i2c.h>
0023 #include <linux/videodev2.h>
0024 #include <media/v4l2-device.h>
0025 #include <media/v4l2-ctrls.h>
0026 
0027 MODULE_DESCRIPTION("Philips SAA7110 video decoder driver");
0028 MODULE_AUTHOR("Pauline Middelink");
0029 MODULE_LICENSE("GPL");
0030 
0031 
0032 static int debug;
0033 module_param(debug, int, 0);
0034 MODULE_PARM_DESC(debug, "Debug level (0-1)");
0035 
0036 #define SAA7110_MAX_INPUT   9   /* 6 CVBS, 3 SVHS */
0037 #define SAA7110_MAX_OUTPUT  1   /* 1 YUV */
0038 
0039 #define SAA7110_NR_REG      0x35
0040 
0041 struct saa7110 {
0042     struct v4l2_subdev sd;
0043     struct v4l2_ctrl_handler hdl;
0044     u8 reg[SAA7110_NR_REG];
0045 
0046     v4l2_std_id norm;
0047     int input;
0048     int enable;
0049 
0050     wait_queue_head_t wq;
0051 };
0052 
0053 static inline struct saa7110 *to_saa7110(struct v4l2_subdev *sd)
0054 {
0055     return container_of(sd, struct saa7110, sd);
0056 }
0057 
0058 static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
0059 {
0060     return &container_of(ctrl->handler, struct saa7110, hdl)->sd;
0061 }
0062 
0063 /* ----------------------------------------------------------------------- */
0064 /* I2C support functions                           */
0065 /* ----------------------------------------------------------------------- */
0066 
0067 static int saa7110_write(struct v4l2_subdev *sd, u8 reg, u8 value)
0068 {
0069     struct i2c_client *client = v4l2_get_subdevdata(sd);
0070     struct saa7110 *decoder = to_saa7110(sd);
0071 
0072     decoder->reg[reg] = value;
0073     return i2c_smbus_write_byte_data(client, reg, value);
0074 }
0075 
0076 static int saa7110_write_block(struct v4l2_subdev *sd, const u8 *data, unsigned int len)
0077 {
0078     struct i2c_client *client = v4l2_get_subdevdata(sd);
0079     struct saa7110 *decoder = to_saa7110(sd);
0080     int ret = -1;
0081     u8 reg = *data;     /* first register to write to */
0082 
0083     /* Sanity check */
0084     if (reg + (len - 1) > SAA7110_NR_REG)
0085         return ret;
0086 
0087     /* the saa7110 has an autoincrement function, use it if
0088      * the adapter understands raw I2C */
0089     if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
0090         ret = i2c_master_send(client, data, len);
0091 
0092         /* Cache the written data */
0093         memcpy(decoder->reg + reg, data + 1, len - 1);
0094     } else {
0095         for (++data, --len; len; len--) {
0096             ret = saa7110_write(sd, reg++, *data++);
0097             if (ret < 0)
0098                 break;
0099         }
0100     }
0101 
0102     return ret;
0103 }
0104 
0105 static inline int saa7110_read(struct v4l2_subdev *sd)
0106 {
0107     struct i2c_client *client = v4l2_get_subdevdata(sd);
0108 
0109     return i2c_smbus_read_byte(client);
0110 }
0111 
0112 /* ----------------------------------------------------------------------- */
0113 /* SAA7110 functions                               */
0114 /* ----------------------------------------------------------------------- */
0115 
0116 #define FRESP_06H_COMPST 0x03   /*0x13*/
0117 #define FRESP_06H_SVIDEO 0x83   /*0xC0*/
0118 
0119 
0120 static int saa7110_selmux(struct v4l2_subdev *sd, int chan)
0121 {
0122     static const unsigned char modes[9][8] = {
0123         /* mode 0 */
0124         {FRESP_06H_COMPST, 0xD9, 0x17, 0x40, 0x03,
0125                   0x44, 0x75, 0x16},
0126         /* mode 1 */
0127         {FRESP_06H_COMPST, 0xD8, 0x17, 0x40, 0x03,
0128                   0x44, 0x75, 0x16},
0129         /* mode 2 */
0130         {FRESP_06H_COMPST, 0xBA, 0x07, 0x91, 0x03,
0131                   0x60, 0xB5, 0x05},
0132         /* mode 3 */
0133         {FRESP_06H_COMPST, 0xB8, 0x07, 0x91, 0x03,
0134                   0x60, 0xB5, 0x05},
0135         /* mode 4 */
0136         {FRESP_06H_COMPST, 0x7C, 0x07, 0xD2, 0x83,
0137                   0x60, 0xB5, 0x03},
0138         /* mode 5 */
0139         {FRESP_06H_COMPST, 0x78, 0x07, 0xD2, 0x83,
0140                   0x60, 0xB5, 0x03},
0141         /* mode 6 */
0142         {FRESP_06H_SVIDEO, 0x59, 0x17, 0x42, 0xA3,
0143                   0x44, 0x75, 0x12},
0144         /* mode 7 */
0145         {FRESP_06H_SVIDEO, 0x9A, 0x17, 0xB1, 0x13,
0146                   0x60, 0xB5, 0x14},
0147         /* mode 8 */
0148         {FRESP_06H_SVIDEO, 0x3C, 0x27, 0xC1, 0x23,
0149                   0x44, 0x75, 0x21}
0150     };
0151     struct saa7110 *decoder = to_saa7110(sd);
0152     const unsigned char *ptr = modes[chan];
0153 
0154     saa7110_write(sd, 0x06, ptr[0]);    /* Luminance control    */
0155     saa7110_write(sd, 0x20, ptr[1]);    /* Analog Control #1    */
0156     saa7110_write(sd, 0x21, ptr[2]);    /* Analog Control #2    */
0157     saa7110_write(sd, 0x22, ptr[3]);    /* Mixer Control #1     */
0158     saa7110_write(sd, 0x2C, ptr[4]);    /* Mixer Control #2     */
0159     saa7110_write(sd, 0x30, ptr[5]);    /* ADCs gain control    */
0160     saa7110_write(sd, 0x31, ptr[6]);    /* Mixer Control #3     */
0161     saa7110_write(sd, 0x21, ptr[7]);    /* Analog Control #2    */
0162     decoder->input = chan;
0163 
0164     return 0;
0165 }
0166 
0167 static const unsigned char initseq[1 + SAA7110_NR_REG] = {
0168     0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF2, 0x03, 0x00,
0169     /* 0x08 */ 0xF8, 0xF8, 0x60, 0x60, 0x00, 0x86, 0x18, 0x90,
0170     /* 0x10 */ 0x00, 0x59, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA,
0171     /* 0x18 */ 0xF2, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0172     /* 0x20 */ 0xD9, 0x16, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F,
0173     /* 0x28 */ 0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x03, 0x0C,
0174     /* 0x30 */ 0x44, 0x71, 0x02, 0x8C, 0x02
0175 };
0176 
0177 static v4l2_std_id determine_norm(struct v4l2_subdev *sd)
0178 {
0179     DEFINE_WAIT(wait);
0180     struct saa7110 *decoder = to_saa7110(sd);
0181     int status;
0182 
0183     /* mode changed, start automatic detection */
0184     saa7110_write_block(sd, initseq, sizeof(initseq));
0185     saa7110_selmux(sd, decoder->input);
0186     prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
0187     schedule_timeout(msecs_to_jiffies(250));
0188     finish_wait(&decoder->wq, &wait);
0189     status = saa7110_read(sd);
0190     if (status & 0x40) {
0191         v4l2_dbg(1, debug, sd, "status=0x%02x (no signal)\n", status);
0192         return V4L2_STD_UNKNOWN;
0193     }
0194     if ((status & 3) == 0) {
0195         saa7110_write(sd, 0x06, 0x83);
0196         if (status & 0x20) {
0197             v4l2_dbg(1, debug, sd, "status=0x%02x (NTSC/no color)\n", status);
0198             /*saa7110_write(sd,0x2E,0x81);*/
0199             return V4L2_STD_NTSC;
0200         }
0201         v4l2_dbg(1, debug, sd, "status=0x%02x (PAL/no color)\n", status);
0202         /*saa7110_write(sd,0x2E,0x9A);*/
0203         return V4L2_STD_PAL;
0204     }
0205     /*saa7110_write(sd,0x06,0x03);*/
0206     if (status & 0x20) {    /* 60Hz */
0207         v4l2_dbg(1, debug, sd, "status=0x%02x (NTSC)\n", status);
0208         saa7110_write(sd, 0x0D, 0x86);
0209         saa7110_write(sd, 0x0F, 0x50);
0210         saa7110_write(sd, 0x11, 0x2C);
0211         /*saa7110_write(sd,0x2E,0x81);*/
0212         return V4L2_STD_NTSC;
0213     }
0214 
0215     /* 50Hz -> PAL/SECAM */
0216     saa7110_write(sd, 0x0D, 0x86);
0217     saa7110_write(sd, 0x0F, 0x10);
0218     saa7110_write(sd, 0x11, 0x59);
0219     /*saa7110_write(sd,0x2E,0x9A);*/
0220 
0221     prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
0222     schedule_timeout(msecs_to_jiffies(250));
0223     finish_wait(&decoder->wq, &wait);
0224 
0225     status = saa7110_read(sd);
0226     if ((status & 0x03) == 0x01) {
0227         v4l2_dbg(1, debug, sd, "status=0x%02x (SECAM)\n", status);
0228         saa7110_write(sd, 0x0D, 0x87);
0229         return V4L2_STD_SECAM;
0230     }
0231     v4l2_dbg(1, debug, sd, "status=0x%02x (PAL)\n", status);
0232     return V4L2_STD_PAL;
0233 }
0234 
0235 static int saa7110_g_input_status(struct v4l2_subdev *sd, u32 *pstatus)
0236 {
0237     struct saa7110 *decoder = to_saa7110(sd);
0238     int res = V4L2_IN_ST_NO_SIGNAL;
0239     int status = saa7110_read(sd);
0240 
0241     v4l2_dbg(1, debug, sd, "status=0x%02x norm=%llx\n",
0242                status, (unsigned long long)decoder->norm);
0243     if (!(status & 0x40))
0244         res = 0;
0245     if (!(status & 0x03))
0246         res |= V4L2_IN_ST_NO_COLOR;
0247 
0248     *pstatus = res;
0249     return 0;
0250 }
0251 
0252 static int saa7110_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
0253 {
0254     *std &= determine_norm(sd);
0255     return 0;
0256 }
0257 
0258 static int saa7110_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
0259 {
0260     struct saa7110 *decoder = to_saa7110(sd);
0261 
0262     if (decoder->norm != std) {
0263         decoder->norm = std;
0264         /*saa7110_write(sd, 0x06, 0x03);*/
0265         if (std & V4L2_STD_NTSC) {
0266             saa7110_write(sd, 0x0D, 0x86);
0267             saa7110_write(sd, 0x0F, 0x50);
0268             saa7110_write(sd, 0x11, 0x2C);
0269             /*saa7110_write(sd, 0x2E, 0x81);*/
0270             v4l2_dbg(1, debug, sd, "switched to NTSC\n");
0271         } else if (std & V4L2_STD_PAL) {
0272             saa7110_write(sd, 0x0D, 0x86);
0273             saa7110_write(sd, 0x0F, 0x10);
0274             saa7110_write(sd, 0x11, 0x59);
0275             /*saa7110_write(sd, 0x2E, 0x9A);*/
0276             v4l2_dbg(1, debug, sd, "switched to PAL\n");
0277         } else if (std & V4L2_STD_SECAM) {
0278             saa7110_write(sd, 0x0D, 0x87);
0279             saa7110_write(sd, 0x0F, 0x10);
0280             saa7110_write(sd, 0x11, 0x59);
0281             /*saa7110_write(sd, 0x2E, 0x9A);*/
0282             v4l2_dbg(1, debug, sd, "switched to SECAM\n");
0283         } else {
0284             return -EINVAL;
0285         }
0286     }
0287     return 0;
0288 }
0289 
0290 static int saa7110_s_routing(struct v4l2_subdev *sd,
0291                  u32 input, u32 output, u32 config)
0292 {
0293     struct saa7110 *decoder = to_saa7110(sd);
0294 
0295     if (input >= SAA7110_MAX_INPUT) {
0296         v4l2_dbg(1, debug, sd, "input=%d not available\n", input);
0297         return -EINVAL;
0298     }
0299     if (decoder->input != input) {
0300         saa7110_selmux(sd, input);
0301         v4l2_dbg(1, debug, sd, "switched to input=%d\n", input);
0302     }
0303     return 0;
0304 }
0305 
0306 static int saa7110_s_stream(struct v4l2_subdev *sd, int enable)
0307 {
0308     struct saa7110 *decoder = to_saa7110(sd);
0309 
0310     if (decoder->enable != enable) {
0311         decoder->enable = enable;
0312         saa7110_write(sd, 0x0E, enable ? 0x18 : 0x80);
0313         v4l2_dbg(1, debug, sd, "YUV %s\n", enable ? "on" : "off");
0314     }
0315     return 0;
0316 }
0317 
0318 static int saa7110_s_ctrl(struct v4l2_ctrl *ctrl)
0319 {
0320     struct v4l2_subdev *sd = to_sd(ctrl);
0321 
0322     switch (ctrl->id) {
0323     case V4L2_CID_BRIGHTNESS:
0324         saa7110_write(sd, 0x19, ctrl->val);
0325         break;
0326     case V4L2_CID_CONTRAST:
0327         saa7110_write(sd, 0x13, ctrl->val);
0328         break;
0329     case V4L2_CID_SATURATION:
0330         saa7110_write(sd, 0x12, ctrl->val);
0331         break;
0332     case V4L2_CID_HUE:
0333         saa7110_write(sd, 0x07, ctrl->val);
0334         break;
0335     default:
0336         return -EINVAL;
0337     }
0338     return 0;
0339 }
0340 
0341 /* ----------------------------------------------------------------------- */
0342 
0343 static const struct v4l2_ctrl_ops saa7110_ctrl_ops = {
0344     .s_ctrl = saa7110_s_ctrl,
0345 };
0346 
0347 static const struct v4l2_subdev_video_ops saa7110_video_ops = {
0348     .s_std = saa7110_s_std,
0349     .s_routing = saa7110_s_routing,
0350     .s_stream = saa7110_s_stream,
0351     .querystd = saa7110_querystd,
0352     .g_input_status = saa7110_g_input_status,
0353 };
0354 
0355 static const struct v4l2_subdev_ops saa7110_ops = {
0356     .video = &saa7110_video_ops,
0357 };
0358 
0359 /* ----------------------------------------------------------------------- */
0360 
0361 static int saa7110_probe(struct i2c_client *client,
0362             const struct i2c_device_id *id)
0363 {
0364     struct saa7110 *decoder;
0365     struct v4l2_subdev *sd;
0366     int rv;
0367 
0368     /* Check if the adapter supports the needed features */
0369     if (!i2c_check_functionality(client->adapter,
0370         I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
0371         return -ENODEV;
0372 
0373     v4l_info(client, "chip found @ 0x%x (%s)\n",
0374             client->addr << 1, client->adapter->name);
0375 
0376     decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
0377     if (!decoder)
0378         return -ENOMEM;
0379     sd = &decoder->sd;
0380     v4l2_i2c_subdev_init(sd, client, &saa7110_ops);
0381     decoder->norm = V4L2_STD_PAL;
0382     decoder->input = 0;
0383     decoder->enable = 1;
0384     v4l2_ctrl_handler_init(&decoder->hdl, 2);
0385     v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
0386         V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
0387     v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
0388         V4L2_CID_CONTRAST, 0, 127, 1, 64);
0389     v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
0390         V4L2_CID_SATURATION, 0, 127, 1, 64);
0391     v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
0392         V4L2_CID_HUE, -128, 127, 1, 0);
0393     sd->ctrl_handler = &decoder->hdl;
0394     if (decoder->hdl.error) {
0395         int err = decoder->hdl.error;
0396 
0397         v4l2_ctrl_handler_free(&decoder->hdl);
0398         return err;
0399     }
0400     v4l2_ctrl_handler_setup(&decoder->hdl);
0401 
0402     init_waitqueue_head(&decoder->wq);
0403 
0404     rv = saa7110_write_block(sd, initseq, sizeof(initseq));
0405     if (rv < 0) {
0406         v4l2_dbg(1, debug, sd, "init status %d\n", rv);
0407     } else {
0408         int ver, status;
0409         saa7110_write(sd, 0x21, 0x10);
0410         saa7110_write(sd, 0x0e, 0x18);
0411         saa7110_write(sd, 0x0D, 0x04);
0412         ver = saa7110_read(sd);
0413         saa7110_write(sd, 0x0D, 0x06);
0414         /*mdelay(150);*/
0415         status = saa7110_read(sd);
0416         v4l2_dbg(1, debug, sd, "version %x, status=0x%02x\n",
0417                    ver, status);
0418         saa7110_write(sd, 0x0D, 0x86);
0419         saa7110_write(sd, 0x0F, 0x10);
0420         saa7110_write(sd, 0x11, 0x59);
0421         /*saa7110_write(sd, 0x2E, 0x9A);*/
0422     }
0423 
0424     /*saa7110_selmux(sd,0);*/
0425     /*determine_norm(sd);*/
0426     /* setup and implicit mode 0 select has been performed */
0427 
0428     return 0;
0429 }
0430 
0431 static int saa7110_remove(struct i2c_client *client)
0432 {
0433     struct v4l2_subdev *sd = i2c_get_clientdata(client);
0434     struct saa7110 *decoder = to_saa7110(sd);
0435 
0436     v4l2_device_unregister_subdev(sd);
0437     v4l2_ctrl_handler_free(&decoder->hdl);
0438     return 0;
0439 }
0440 
0441 /* ----------------------------------------------------------------------- */
0442 
0443 static const struct i2c_device_id saa7110_id[] = {
0444     { "saa7110", 0 },
0445     { }
0446 };
0447 MODULE_DEVICE_TABLE(i2c, saa7110_id);
0448 
0449 static struct i2c_driver saa7110_driver = {
0450     .driver = {
0451         .name   = "saa7110",
0452     },
0453     .probe      = saa7110_probe,
0454     .remove     = saa7110_remove,
0455     .id_table   = saa7110_id,
0456 };
0457 
0458 module_i2c_driver(saa7110_driver);