Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * upd6408x - NEC Electronics 3-Dimensional Y/C separation driver
0004  *
0005  * 2003 by T.Adachi (tadachi@tadachi-net.com)
0006  * 2003 by Takeru KOMORIYA <komoriya@paken.org>
0007  * 2006 by Hans Verkuil <hverkuil@xs4all.nl>
0008  */
0009 
0010 #include <linux/module.h>
0011 #include <linux/kernel.h>
0012 #include <linux/i2c.h>
0013 #include <linux/videodev2.h>
0014 #include <linux/slab.h>
0015 #include <media/v4l2-device.h>
0016 #include <media/i2c/upd64083.h>
0017 
0018 MODULE_DESCRIPTION("uPD64083 driver");
0019 MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil");
0020 MODULE_LICENSE("GPL");
0021 
0022 static bool debug;
0023 module_param(debug, bool, 0644);
0024 
0025 MODULE_PARM_DESC(debug, "Debug level (0-1)");
0026 
0027 
0028 enum {
0029     R00 = 0, R01, R02, R03, R04,
0030     R05, R06, R07, R08, R09,
0031     R0A, R0B, R0C, R0D, R0E, R0F,
0032     R10, R11, R12, R13, R14,
0033     R15, R16,
0034     TOT_REGS
0035 };
0036 
0037 struct upd64083_state {
0038     struct v4l2_subdev sd;
0039     u8 mode;
0040     u8 ext_y_adc;
0041     u8 regs[TOT_REGS];
0042 };
0043 
0044 static inline struct upd64083_state *to_state(struct v4l2_subdev *sd)
0045 {
0046     return container_of(sd, struct upd64083_state, sd);
0047 }
0048 
0049 /* Initial values when used in combination with the
0050    NEC upd64031a ghost reduction chip. */
0051 static u8 upd64083_init[] = {
0052     0x1f, 0x01, 0xa0, 0x2d, 0x29,  /* we use EXCSS=0 */
0053     0x36, 0xdd, 0x05, 0x56, 0x48,
0054     0x00, 0x3a, 0xa0, 0x05, 0x08,
0055     0x44, 0x60, 0x08, 0x52, 0xf8,
0056     0x53, 0x60, 0x10
0057 };
0058 
0059 /* ------------------------------------------------------------------------ */
0060 
0061 static void upd64083_write(struct v4l2_subdev *sd, u8 reg, u8 val)
0062 {
0063     struct i2c_client *client = v4l2_get_subdevdata(sd);
0064     u8 buf[2];
0065 
0066     buf[0] = reg;
0067     buf[1] = val;
0068     v4l2_dbg(1, debug, sd, "write reg: %02x val: %02x\n", reg, val);
0069     if (i2c_master_send(client, buf, 2) != 2)
0070         v4l2_err(sd, "I/O error write 0x%02x/0x%02x\n", reg, val);
0071 }
0072 
0073 /* ------------------------------------------------------------------------ */
0074 
0075 #ifdef CONFIG_VIDEO_ADV_DEBUG
0076 static u8 upd64083_read(struct v4l2_subdev *sd, u8 reg)
0077 {
0078     struct i2c_client *client = v4l2_get_subdevdata(sd);
0079     u8 buf[7];
0080 
0081     if (reg >= sizeof(buf))
0082         return 0xff;
0083     i2c_master_recv(client, buf, sizeof(buf));
0084     return buf[reg];
0085 }
0086 #endif
0087 
0088 /* ------------------------------------------------------------------------ */
0089 
0090 static int upd64083_s_routing(struct v4l2_subdev *sd,
0091                   u32 input, u32 output, u32 config)
0092 {
0093     struct upd64083_state *state = to_state(sd);
0094     u8 r00, r02;
0095 
0096     if (input > 7 || (input & 6) == 6)
0097         return -EINVAL;
0098     state->mode = (input & 3) << 6;
0099     state->ext_y_adc = (input & UPD64083_EXT_Y_ADC) << 3;
0100     r00 = (state->regs[R00] & ~(3 << 6)) | state->mode;
0101     r02 = (state->regs[R02] & ~(1 << 5)) | state->ext_y_adc;
0102     upd64083_write(sd, R00, r00);
0103     upd64083_write(sd, R02, r02);
0104     return 0;
0105 }
0106 
0107 #ifdef CONFIG_VIDEO_ADV_DEBUG
0108 static int upd64083_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
0109 {
0110     reg->val = upd64083_read(sd, reg->reg & 0xff);
0111     reg->size = 1;
0112     return 0;
0113 }
0114 
0115 static int upd64083_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
0116 {
0117     upd64083_write(sd, reg->reg & 0xff, reg->val & 0xff);
0118     return 0;
0119 }
0120 #endif
0121 
0122 static int upd64083_log_status(struct v4l2_subdev *sd)
0123 {
0124     struct i2c_client *client = v4l2_get_subdevdata(sd);
0125     u8 buf[7];
0126 
0127     i2c_master_recv(client, buf, 7);
0128     v4l2_info(sd, "Status: SA00=%02x SA01=%02x SA02=%02x SA03=%02x "
0129               "SA04=%02x SA05=%02x SA06=%02x\n",
0130         buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
0131     return 0;
0132 }
0133 
0134 /* ----------------------------------------------------------------------- */
0135 
0136 static const struct v4l2_subdev_core_ops upd64083_core_ops = {
0137     .log_status = upd64083_log_status,
0138 #ifdef CONFIG_VIDEO_ADV_DEBUG
0139     .g_register = upd64083_g_register,
0140     .s_register = upd64083_s_register,
0141 #endif
0142 };
0143 
0144 static const struct v4l2_subdev_video_ops upd64083_video_ops = {
0145     .s_routing = upd64083_s_routing,
0146 };
0147 
0148 static const struct v4l2_subdev_ops upd64083_ops = {
0149     .core = &upd64083_core_ops,
0150     .video = &upd64083_video_ops,
0151 };
0152 
0153 /* ------------------------------------------------------------------------ */
0154 
0155 /* i2c implementation */
0156 
0157 static int upd64083_probe(struct i2c_client *client,
0158               const struct i2c_device_id *id)
0159 {
0160     struct upd64083_state *state;
0161     struct v4l2_subdev *sd;
0162     int i;
0163 
0164     if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
0165         return -EIO;
0166 
0167     v4l_info(client, "chip found @ 0x%x (%s)\n",
0168             client->addr << 1, client->adapter->name);
0169 
0170     state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
0171     if (state == NULL)
0172         return -ENOMEM;
0173     sd = &state->sd;
0174     v4l2_i2c_subdev_init(sd, client, &upd64083_ops);
0175     /* Initially assume that a ghost reduction chip is present */
0176     state->mode = 0;  /* YCS mode */
0177     state->ext_y_adc = (1 << 5);
0178     memcpy(state->regs, upd64083_init, TOT_REGS);
0179     for (i = 0; i < TOT_REGS; i++)
0180         upd64083_write(sd, i, state->regs[i]);
0181     return 0;
0182 }
0183 
0184 static int upd64083_remove(struct i2c_client *client)
0185 {
0186     struct v4l2_subdev *sd = i2c_get_clientdata(client);
0187 
0188     v4l2_device_unregister_subdev(sd);
0189     return 0;
0190 }
0191 
0192 /* ----------------------------------------------------------------------- */
0193 
0194 static const struct i2c_device_id upd64083_id[] = {
0195     { "upd64083", 0 },
0196     { }
0197 };
0198 MODULE_DEVICE_TABLE(i2c, upd64083_id);
0199 
0200 static struct i2c_driver upd64083_driver = {
0201     .driver = {
0202         .name   = "upd64083",
0203     },
0204     .probe      = upd64083_probe,
0205     .remove     = upd64083_remove,
0206     .id_table   = upd64083_id,
0207 };
0208 
0209 module_i2c_driver(upd64083_driver);