0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/module.h>
0012 #include <linux/kernel.h>
0013 #include <linux/i2c.h>
0014 #include <linux/videodev2.h>
0015 #include <linux/slab.h>
0016 #include <media/v4l2-device.h>
0017 #include <media/i2c/upd64031a.h>
0018
0019
0020
0021
0022 #define GR_MODE_MASK 0xc0
0023 #define DIRECT_3DYCS_CONNECT_MASK 0xc0
0024 #define SYNC_CIRCUIT_MASK 0xa0
0025
0026
0027
0028 MODULE_DESCRIPTION("uPD64031A driver");
0029 MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil");
0030 MODULE_LICENSE("GPL");
0031
0032 static int debug;
0033 module_param(debug, int, 0644);
0034
0035 MODULE_PARM_DESC(debug, "Debug level (0-1)");
0036
0037
0038 enum {
0039 R00 = 0, R01, R02, R03, R04,
0040 R05, R06, R07, R08, R09,
0041 R0A, R0B, R0C, R0D, R0E, R0F,
0042
0043
0044
0045
0046 TOT_REGS
0047 };
0048
0049 struct upd64031a_state {
0050 struct v4l2_subdev sd;
0051 u8 regs[TOT_REGS];
0052 u8 gr_mode;
0053 u8 direct_3dycs_connect;
0054 u8 ext_comp_sync;
0055 u8 ext_vert_sync;
0056 };
0057
0058 static inline struct upd64031a_state *to_state(struct v4l2_subdev *sd)
0059 {
0060 return container_of(sd, struct upd64031a_state, sd);
0061 }
0062
0063 static u8 upd64031a_init[] = {
0064 0x00, 0xb8, 0x48, 0xd2, 0xe6,
0065 0x03, 0x10, 0x0b, 0xaf, 0x7f,
0066 0x00, 0x00, 0x1d, 0x5e, 0x00,
0067 0xd0
0068 };
0069
0070
0071
0072 static u8 upd64031a_read(struct v4l2_subdev *sd, u8 reg)
0073 {
0074 struct i2c_client *client = v4l2_get_subdevdata(sd);
0075 u8 buf[2];
0076
0077 if (reg >= sizeof(buf))
0078 return 0xff;
0079 i2c_master_recv(client, buf, 2);
0080 return buf[reg];
0081 }
0082
0083
0084
0085 static void upd64031a_write(struct v4l2_subdev *sd, u8 reg, u8 val)
0086 {
0087 struct i2c_client *client = v4l2_get_subdevdata(sd);
0088 u8 buf[2];
0089
0090 buf[0] = reg;
0091 buf[1] = val;
0092 v4l2_dbg(1, debug, sd, "write reg: %02X val: %02X\n", reg, val);
0093 if (i2c_master_send(client, buf, 2) != 2)
0094 v4l2_err(sd, "I/O error write 0x%02x/0x%02x\n", reg, val);
0095 }
0096
0097
0098
0099
0100 static int upd64031a_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq)
0101 {
0102 struct upd64031a_state *state = to_state(sd);
0103 u8 reg = state->regs[R00];
0104
0105 v4l2_dbg(1, debug, sd, "changed input or channel\n");
0106 upd64031a_write(sd, R00, reg | 0x10);
0107 upd64031a_write(sd, R00, reg & ~0x10);
0108 return 0;
0109 }
0110
0111
0112
0113 static int upd64031a_s_routing(struct v4l2_subdev *sd,
0114 u32 input, u32 output, u32 config)
0115 {
0116 struct upd64031a_state *state = to_state(sd);
0117 u8 r00, r05, r08;
0118
0119 state->gr_mode = (input & 3) << 6;
0120 state->direct_3dycs_connect = (input & 0xc) << 4;
0121 state->ext_comp_sync =
0122 (input & UPD64031A_COMPOSITE_EXTERNAL) << 1;
0123 state->ext_vert_sync =
0124 (input & UPD64031A_VERTICAL_EXTERNAL) << 2;
0125 r00 = (state->regs[R00] & ~GR_MODE_MASK) | state->gr_mode;
0126 r05 = (state->regs[R00] & ~SYNC_CIRCUIT_MASK) |
0127 state->ext_comp_sync | state->ext_vert_sync;
0128 r08 = (state->regs[R08] & ~DIRECT_3DYCS_CONNECT_MASK) |
0129 state->direct_3dycs_connect;
0130 upd64031a_write(sd, R00, r00);
0131 upd64031a_write(sd, R05, r05);
0132 upd64031a_write(sd, R08, r08);
0133 return upd64031a_s_frequency(sd, NULL);
0134 }
0135
0136 static int upd64031a_log_status(struct v4l2_subdev *sd)
0137 {
0138 v4l2_info(sd, "Status: SA00=0x%02x SA01=0x%02x\n",
0139 upd64031a_read(sd, 0), upd64031a_read(sd, 1));
0140 return 0;
0141 }
0142
0143 #ifdef CONFIG_VIDEO_ADV_DEBUG
0144 static int upd64031a_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
0145 {
0146 reg->val = upd64031a_read(sd, reg->reg & 0xff);
0147 reg->size = 1;
0148 return 0;
0149 }
0150
0151 static int upd64031a_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
0152 {
0153 upd64031a_write(sd, reg->reg & 0xff, reg->val & 0xff);
0154 return 0;
0155 }
0156 #endif
0157
0158
0159
0160 static const struct v4l2_subdev_core_ops upd64031a_core_ops = {
0161 .log_status = upd64031a_log_status,
0162 #ifdef CONFIG_VIDEO_ADV_DEBUG
0163 .g_register = upd64031a_g_register,
0164 .s_register = upd64031a_s_register,
0165 #endif
0166 };
0167
0168 static const struct v4l2_subdev_tuner_ops upd64031a_tuner_ops = {
0169 .s_frequency = upd64031a_s_frequency,
0170 };
0171
0172 static const struct v4l2_subdev_video_ops upd64031a_video_ops = {
0173 .s_routing = upd64031a_s_routing,
0174 };
0175
0176 static const struct v4l2_subdev_ops upd64031a_ops = {
0177 .core = &upd64031a_core_ops,
0178 .tuner = &upd64031a_tuner_ops,
0179 .video = &upd64031a_video_ops,
0180 };
0181
0182
0183
0184
0185
0186 static int upd64031a_probe(struct i2c_client *client,
0187 const struct i2c_device_id *id)
0188 {
0189 struct upd64031a_state *state;
0190 struct v4l2_subdev *sd;
0191 int i;
0192
0193 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
0194 return -EIO;
0195
0196 v4l_info(client, "chip found @ 0x%x (%s)\n",
0197 client->addr << 1, client->adapter->name);
0198
0199 state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
0200 if (state == NULL)
0201 return -ENOMEM;
0202 sd = &state->sd;
0203 v4l2_i2c_subdev_init(sd, client, &upd64031a_ops);
0204 memcpy(state->regs, upd64031a_init, sizeof(state->regs));
0205 state->gr_mode = UPD64031A_GR_ON << 6;
0206 state->direct_3dycs_connect = UPD64031A_3DYCS_COMPOSITE << 4;
0207 state->ext_comp_sync = state->ext_vert_sync = 0;
0208 for (i = 0; i < TOT_REGS; i++)
0209 upd64031a_write(sd, i, state->regs[i]);
0210 return 0;
0211 }
0212
0213 static int upd64031a_remove(struct i2c_client *client)
0214 {
0215 struct v4l2_subdev *sd = i2c_get_clientdata(client);
0216
0217 v4l2_device_unregister_subdev(sd);
0218 return 0;
0219 }
0220
0221
0222
0223 static const struct i2c_device_id upd64031a_id[] = {
0224 { "upd64031a", 0 },
0225 { }
0226 };
0227 MODULE_DEVICE_TABLE(i2c, upd64031a_id);
0228
0229 static struct i2c_driver upd64031a_driver = {
0230 .driver = {
0231 .name = "upd64031a",
0232 },
0233 .probe = upd64031a_probe,
0234 .remove = upd64031a_remove,
0235 .id_table = upd64031a_id,
0236 };
0237
0238 module_i2c_driver(upd64031a_driver);