Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2005-2006 Micronas USA Inc.
0004  */
0005 
0006 #include <linux/module.h>
0007 #include <linux/init.h>
0008 #include <linux/i2c.h>
0009 #include <linux/videodev2.h>
0010 #include <linux/ioctl.h>
0011 #include <linux/slab.h>
0012 #include <media/v4l2-subdev.h>
0013 #include <media/v4l2-device.h>
0014 #include <media/v4l2-ctrls.h>
0015 
0016 #define TW2804_REG_AUTOGAIN     0x02
0017 #define TW2804_REG_HUE          0x0f
0018 #define TW2804_REG_SATURATION       0x10
0019 #define TW2804_REG_CONTRAST     0x11
0020 #define TW2804_REG_BRIGHTNESS       0x12
0021 #define TW2804_REG_COLOR_KILLER     0x14
0022 #define TW2804_REG_GAIN         0x3c
0023 #define TW2804_REG_CHROMA_GAIN      0x3d
0024 #define TW2804_REG_BLUE_BALANCE     0x3e
0025 #define TW2804_REG_RED_BALANCE      0x3f
0026 
0027 struct tw2804 {
0028     struct v4l2_subdev sd;
0029     struct v4l2_ctrl_handler hdl;
0030     u8 channel:2;
0031     u8 input:1;
0032     int norm;
0033 };
0034 
0035 static const u8 global_registers[] = {
0036     0x39, 0x00,
0037     0x3a, 0xff,
0038     0x3b, 0x84,
0039     0x3c, 0x80,
0040     0x3d, 0x80,
0041     0x3e, 0x82,
0042     0x3f, 0x82,
0043     0x78, 0x00,
0044     0xff, 0xff, /* Terminator (reg 0xff does not exist) */
0045 };
0046 
0047 static const u8 channel_registers[] = {
0048     0x01, 0xc4,
0049     0x02, 0xa5,
0050     0x03, 0x20,
0051     0x04, 0xd0,
0052     0x05, 0x20,
0053     0x06, 0xd0,
0054     0x07, 0x88,
0055     0x08, 0x20,
0056     0x09, 0x07,
0057     0x0a, 0xf0,
0058     0x0b, 0x07,
0059     0x0c, 0xf0,
0060     0x0d, 0x40,
0061     0x0e, 0xd2,
0062     0x0f, 0x80,
0063     0x10, 0x80,
0064     0x11, 0x80,
0065     0x12, 0x80,
0066     0x13, 0x1f,
0067     0x14, 0x00,
0068     0x15, 0x00,
0069     0x16, 0x00,
0070     0x17, 0x00,
0071     0x18, 0xff,
0072     0x19, 0xff,
0073     0x1a, 0xff,
0074     0x1b, 0xff,
0075     0x1c, 0xff,
0076     0x1d, 0xff,
0077     0x1e, 0xff,
0078     0x1f, 0xff,
0079     0x20, 0x07,
0080     0x21, 0x07,
0081     0x22, 0x00,
0082     0x23, 0x91,
0083     0x24, 0x51,
0084     0x25, 0x03,
0085     0x26, 0x00,
0086     0x27, 0x00,
0087     0x28, 0x00,
0088     0x29, 0x00,
0089     0x2a, 0x00,
0090     0x2b, 0x00,
0091     0x2c, 0x00,
0092     0x2d, 0x00,
0093     0x2e, 0x00,
0094     0x2f, 0x00,
0095     0x30, 0x00,
0096     0x31, 0x00,
0097     0x32, 0x00,
0098     0x33, 0x00,
0099     0x34, 0x00,
0100     0x35, 0x00,
0101     0x36, 0x00,
0102     0x37, 0x00,
0103     0xff, 0xff, /* Terminator (reg 0xff does not exist) */
0104 };
0105 
0106 static int write_reg(struct i2c_client *client, u8 reg, u8 value, u8 channel)
0107 {
0108     return i2c_smbus_write_byte_data(client, reg | (channel << 6), value);
0109 }
0110 
0111 static int write_regs(struct i2c_client *client, const u8 *regs, u8 channel)
0112 {
0113     int ret;
0114     int i;
0115 
0116     for (i = 0; regs[i] != 0xff; i += 2) {
0117         ret = i2c_smbus_write_byte_data(client,
0118                 regs[i] | (channel << 6), regs[i + 1]);
0119         if (ret < 0)
0120             return ret;
0121     }
0122     return 0;
0123 }
0124 
0125 static int read_reg(struct i2c_client *client, u8 reg, u8 channel)
0126 {
0127     return i2c_smbus_read_byte_data(client, (reg) | (channel << 6));
0128 }
0129 
0130 static inline struct tw2804 *to_state(struct v4l2_subdev *sd)
0131 {
0132     return container_of(sd, struct tw2804, sd);
0133 }
0134 
0135 static inline struct tw2804 *to_state_from_ctrl(struct v4l2_ctrl *ctrl)
0136 {
0137     return container_of(ctrl->handler, struct tw2804, hdl);
0138 }
0139 
0140 static int tw2804_log_status(struct v4l2_subdev *sd)
0141 {
0142     struct tw2804 *state = to_state(sd);
0143 
0144     v4l2_info(sd, "Standard: %s\n",
0145             state->norm & V4L2_STD_525_60 ? "60 Hz" : "50 Hz");
0146     v4l2_info(sd, "Channel: %d\n", state->channel);
0147     v4l2_info(sd, "Input: %d\n", state->input);
0148     return v4l2_ctrl_subdev_log_status(sd);
0149 }
0150 
0151 /*
0152  * These volatile controls are needed because all four channels share
0153  * these controls. So a change made to them through one channel would
0154  * require another channel to be updated.
0155  *
0156  * Normally this would have been done in a different way, but since the one
0157  * board that uses this driver sees this single chip as if it was on four
0158  * different i2c adapters (each adapter belonging to a separate instance of
0159  * the same USB driver) there is no reliable method that I have found to let
0160  * the instances know about each other.
0161  *
0162  * So implementing these global registers as volatile is the best we can do.
0163  */
0164 static int tw2804_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
0165 {
0166     struct tw2804 *state = to_state_from_ctrl(ctrl);
0167     struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
0168 
0169     switch (ctrl->id) {
0170     case V4L2_CID_GAIN:
0171         ctrl->val = read_reg(client, TW2804_REG_GAIN, 0);
0172         return 0;
0173 
0174     case V4L2_CID_CHROMA_GAIN:
0175         ctrl->val = read_reg(client, TW2804_REG_CHROMA_GAIN, 0);
0176         return 0;
0177 
0178     case V4L2_CID_BLUE_BALANCE:
0179         ctrl->val = read_reg(client, TW2804_REG_BLUE_BALANCE, 0);
0180         return 0;
0181 
0182     case V4L2_CID_RED_BALANCE:
0183         ctrl->val = read_reg(client, TW2804_REG_RED_BALANCE, 0);
0184         return 0;
0185     }
0186     return 0;
0187 }
0188 
0189 static int tw2804_s_ctrl(struct v4l2_ctrl *ctrl)
0190 {
0191     struct tw2804 *state = to_state_from_ctrl(ctrl);
0192     struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
0193     int addr;
0194     int reg;
0195 
0196     switch (ctrl->id) {
0197     case V4L2_CID_AUTOGAIN:
0198         addr = TW2804_REG_AUTOGAIN;
0199         reg = read_reg(client, addr, state->channel);
0200         if (reg < 0)
0201             return reg;
0202         if (ctrl->val == 0)
0203             reg &= ~(1 << 7);
0204         else
0205             reg |= 1 << 7;
0206         return write_reg(client, addr, reg, state->channel);
0207 
0208     case V4L2_CID_COLOR_KILLER:
0209         addr = TW2804_REG_COLOR_KILLER;
0210         reg = read_reg(client, addr, state->channel);
0211         if (reg < 0)
0212             return reg;
0213         reg = (reg & ~(0x03)) | (ctrl->val == 0 ? 0x02 : 0x03);
0214         return write_reg(client, addr, reg, state->channel);
0215 
0216     case V4L2_CID_GAIN:
0217         return write_reg(client, TW2804_REG_GAIN, ctrl->val, 0);
0218 
0219     case V4L2_CID_CHROMA_GAIN:
0220         return write_reg(client, TW2804_REG_CHROMA_GAIN, ctrl->val, 0);
0221 
0222     case V4L2_CID_BLUE_BALANCE:
0223         return write_reg(client, TW2804_REG_BLUE_BALANCE, ctrl->val, 0);
0224 
0225     case V4L2_CID_RED_BALANCE:
0226         return write_reg(client, TW2804_REG_RED_BALANCE, ctrl->val, 0);
0227 
0228     case V4L2_CID_BRIGHTNESS:
0229         return write_reg(client, TW2804_REG_BRIGHTNESS,
0230                 ctrl->val, state->channel);
0231 
0232     case V4L2_CID_CONTRAST:
0233         return write_reg(client, TW2804_REG_CONTRAST,
0234                 ctrl->val, state->channel);
0235 
0236     case V4L2_CID_SATURATION:
0237         return write_reg(client, TW2804_REG_SATURATION,
0238                 ctrl->val, state->channel);
0239 
0240     case V4L2_CID_HUE:
0241         return write_reg(client, TW2804_REG_HUE,
0242                 ctrl->val, state->channel);
0243 
0244     default:
0245         break;
0246     }
0247     return -EINVAL;
0248 }
0249 
0250 static int tw2804_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
0251 {
0252     struct tw2804 *dec = to_state(sd);
0253     struct i2c_client *client = v4l2_get_subdevdata(sd);
0254     bool is_60hz = norm & V4L2_STD_525_60;
0255     u8 regs[] = {
0256         0x01, is_60hz ? 0xc4 : 0x84,
0257         0x09, is_60hz ? 0x07 : 0x04,
0258         0x0a, is_60hz ? 0xf0 : 0x20,
0259         0x0b, is_60hz ? 0x07 : 0x04,
0260         0x0c, is_60hz ? 0xf0 : 0x20,
0261         0x0d, is_60hz ? 0x40 : 0x4a,
0262         0x16, is_60hz ? 0x00 : 0x40,
0263         0x17, is_60hz ? 0x00 : 0x40,
0264         0x20, is_60hz ? 0x07 : 0x0f,
0265         0x21, is_60hz ? 0x07 : 0x0f,
0266         0xff, 0xff,
0267     };
0268 
0269     write_regs(client, regs, dec->channel);
0270     dec->norm = norm;
0271     return 0;
0272 }
0273 
0274 static int tw2804_s_video_routing(struct v4l2_subdev *sd, u32 input, u32 output,
0275     u32 config)
0276 {
0277     struct tw2804 *dec = to_state(sd);
0278     struct i2c_client *client = v4l2_get_subdevdata(sd);
0279     int reg;
0280 
0281     if (config && config - 1 != dec->channel) {
0282         if (config > 4) {
0283             dev_err(&client->dev,
0284                 "channel %d is not between 1 and 4!\n", config);
0285             return -EINVAL;
0286         }
0287         dec->channel = config - 1;
0288         dev_dbg(&client->dev, "initializing TW2804 channel %d\n",
0289             dec->channel);
0290         if (dec->channel == 0 &&
0291                 write_regs(client, global_registers, 0) < 0) {
0292             dev_err(&client->dev,
0293                 "error initializing TW2804 global registers\n");
0294             return -EIO;
0295         }
0296         if (write_regs(client, channel_registers, dec->channel) < 0) {
0297             dev_err(&client->dev,
0298                 "error initializing TW2804 channel %d\n",
0299                 dec->channel);
0300             return -EIO;
0301         }
0302     }
0303 
0304     if (input > 1)
0305         return -EINVAL;
0306 
0307     if (input == dec->input)
0308         return 0;
0309 
0310     reg = read_reg(client, 0x22, dec->channel);
0311 
0312     if (reg >= 0) {
0313         if (input == 0)
0314             reg &= ~(1 << 2);
0315         else
0316             reg |= 1 << 2;
0317         reg = write_reg(client, 0x22, reg, dec->channel);
0318     }
0319 
0320     if (reg >= 0)
0321         dec->input = input;
0322     else
0323         return reg;
0324     return 0;
0325 }
0326 
0327 static const struct v4l2_ctrl_ops tw2804_ctrl_ops = {
0328     .g_volatile_ctrl = tw2804_g_volatile_ctrl,
0329     .s_ctrl = tw2804_s_ctrl,
0330 };
0331 
0332 static const struct v4l2_subdev_video_ops tw2804_video_ops = {
0333     .s_std = tw2804_s_std,
0334     .s_routing = tw2804_s_video_routing,
0335 };
0336 
0337 static const struct v4l2_subdev_core_ops tw2804_core_ops = {
0338     .log_status = tw2804_log_status,
0339 };
0340 
0341 static const struct v4l2_subdev_ops tw2804_ops = {
0342     .core = &tw2804_core_ops,
0343     .video = &tw2804_video_ops,
0344 };
0345 
0346 static int tw2804_probe(struct i2c_client *client,
0347                 const struct i2c_device_id *id)
0348 {
0349     struct i2c_adapter *adapter = client->adapter;
0350     struct tw2804 *state;
0351     struct v4l2_subdev *sd;
0352     struct v4l2_ctrl *ctrl;
0353     int err;
0354 
0355     if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
0356         return -ENODEV;
0357 
0358     state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
0359     if (state == NULL)
0360         return -ENOMEM;
0361     sd = &state->sd;
0362     v4l2_i2c_subdev_init(sd, client, &tw2804_ops);
0363     state->channel = -1;
0364     state->norm = V4L2_STD_NTSC;
0365 
0366     v4l2_ctrl_handler_init(&state->hdl, 10);
0367     v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
0368                 V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
0369     v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
0370                 V4L2_CID_CONTRAST, 0, 255, 1, 128);
0371     v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
0372                 V4L2_CID_SATURATION, 0, 255, 1, 128);
0373     v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
0374                 V4L2_CID_HUE, 0, 255, 1, 128);
0375     v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
0376                 V4L2_CID_COLOR_KILLER, 0, 1, 1, 0);
0377     v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
0378                 V4L2_CID_AUTOGAIN, 0, 1, 1, 0);
0379     ctrl = v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
0380                 V4L2_CID_GAIN, 0, 255, 1, 128);
0381     if (ctrl)
0382         ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
0383     ctrl = v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
0384                 V4L2_CID_CHROMA_GAIN, 0, 255, 1, 128);
0385     if (ctrl)
0386         ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
0387     ctrl = v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
0388                 V4L2_CID_BLUE_BALANCE, 0, 255, 1, 122);
0389     if (ctrl)
0390         ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
0391     ctrl = v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
0392                 V4L2_CID_RED_BALANCE, 0, 255, 1, 122);
0393     if (ctrl)
0394         ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
0395     sd->ctrl_handler = &state->hdl;
0396     err = state->hdl.error;
0397     if (err) {
0398         v4l2_ctrl_handler_free(&state->hdl);
0399         return err;
0400     }
0401 
0402     v4l_info(client, "chip found @ 0x%02x (%s)\n",
0403             client->addr << 1, client->adapter->name);
0404 
0405     return 0;
0406 }
0407 
0408 static int tw2804_remove(struct i2c_client *client)
0409 {
0410     struct v4l2_subdev *sd = i2c_get_clientdata(client);
0411     struct tw2804 *state = to_state(sd);
0412 
0413     v4l2_device_unregister_subdev(sd);
0414     v4l2_ctrl_handler_free(&state->hdl);
0415     return 0;
0416 }
0417 
0418 static const struct i2c_device_id tw2804_id[] = {
0419     { "tw2804", 0 },
0420     { }
0421 };
0422 MODULE_DEVICE_TABLE(i2c, tw2804_id);
0423 
0424 static struct i2c_driver tw2804_driver = {
0425     .driver = {
0426         .name   = "tw2804",
0427     },
0428     .probe      = tw2804_probe,
0429     .remove     = tw2804_remove,
0430     .id_table   = tw2804_id,
0431 };
0432 
0433 module_i2c_driver(tw2804_driver);
0434 
0435 MODULE_LICENSE("GPL v2");
0436 MODULE_DESCRIPTION("TW2804/TW2802 V4L2 i2c driver");
0437 MODULE_AUTHOR("Micronas USA Inc");