1 /*
2 * Copyright (C) 2005-2006 Micronas USA Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License (Version 2) as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
16 */
17
18 #include <linux/module.h>
19 #include <linux/init.h>
20 #include <linux/i2c.h>
21 #include <linux/videodev2.h>
22 #include <linux/ioctl.h>
23 #include <linux/slab.h>
24 #include <media/v4l2-subdev.h>
25 #include <media/v4l2-device.h>
26 #include <media/v4l2-chip-ident.h>
27 #include <media/v4l2-ctrls.h>
28
29 #define TW2804_REG_AUTOGAIN 0x02
30 #define TW2804_REG_HUE 0x0f
31 #define TW2804_REG_SATURATION 0x10
32 #define TW2804_REG_CONTRAST 0x11
33 #define TW2804_REG_BRIGHTNESS 0x12
34 #define TW2804_REG_COLOR_KILLER 0x14
35 #define TW2804_REG_GAIN 0x3c
36 #define TW2804_REG_CHROMA_GAIN 0x3d
37 #define TW2804_REG_BLUE_BALANCE 0x3e
38 #define TW2804_REG_RED_BALANCE 0x3f
39
40 struct tw2804 {
41 struct v4l2_subdev sd;
42 struct v4l2_ctrl_handler hdl;
43 u8 channel:2;
44 u8 input:1;
45 int norm;
46 };
47
48 static const u8 global_registers[] = {
49 0x39, 0x00,
50 0x3a, 0xff,
51 0x3b, 0x84,
52 0x3c, 0x80,
53 0x3d, 0x80,
54 0x3e, 0x82,
55 0x3f, 0x82,
56 0x78, 0x00,
57 0xff, 0xff, /* Terminator (reg 0xff does not exist) */
58 };
59
60 static const u8 channel_registers[] = {
61 0x01, 0xc4,
62 0x02, 0xa5,
63 0x03, 0x20,
64 0x04, 0xd0,
65 0x05, 0x20,
66 0x06, 0xd0,
67 0x07, 0x88,
68 0x08, 0x20,
69 0x09, 0x07,
70 0x0a, 0xf0,
71 0x0b, 0x07,
72 0x0c, 0xf0,
73 0x0d, 0x40,
74 0x0e, 0xd2,
75 0x0f, 0x80,
76 0x10, 0x80,
77 0x11, 0x80,
78 0x12, 0x80,
79 0x13, 0x1f,
80 0x14, 0x00,
81 0x15, 0x00,
82 0x16, 0x00,
83 0x17, 0x00,
84 0x18, 0xff,
85 0x19, 0xff,
86 0x1a, 0xff,
87 0x1b, 0xff,
88 0x1c, 0xff,
89 0x1d, 0xff,
90 0x1e, 0xff,
91 0x1f, 0xff,
92 0x20, 0x07,
93 0x21, 0x07,
94 0x22, 0x00,
95 0x23, 0x91,
96 0x24, 0x51,
97 0x25, 0x03,
98 0x26, 0x00,
99 0x27, 0x00,
100 0x28, 0x00,
101 0x29, 0x00,
102 0x2a, 0x00,
103 0x2b, 0x00,
104 0x2c, 0x00,
105 0x2d, 0x00,
106 0x2e, 0x00,
107 0x2f, 0x00,
108 0x30, 0x00,
109 0x31, 0x00,
110 0x32, 0x00,
111 0x33, 0x00,
112 0x34, 0x00,
113 0x35, 0x00,
114 0x36, 0x00,
115 0x37, 0x00,
116 0xff, 0xff, /* Terminator (reg 0xff does not exist) */
117 };
118
write_reg(struct i2c_client * client,u8 reg,u8 value,u8 channel)119 static int write_reg(struct i2c_client *client, u8 reg, u8 value, u8 channel)
120 {
121 return i2c_smbus_write_byte_data(client, reg | (channel << 6), value);
122 }
123
write_regs(struct i2c_client * client,const u8 * regs,u8 channel)124 static int write_regs(struct i2c_client *client, const u8 *regs, u8 channel)
125 {
126 int ret;
127 int i;
128
129 for (i = 0; regs[i] != 0xff; i += 2) {
130 ret = i2c_smbus_write_byte_data(client,
131 regs[i] | (channel << 6), regs[i + 1]);
132 if (ret < 0)
133 return ret;
134 }
135 return 0;
136 }
137
read_reg(struct i2c_client * client,u8 reg,u8 channel)138 static int read_reg(struct i2c_client *client, u8 reg, u8 channel)
139 {
140 return i2c_smbus_read_byte_data(client, (reg) | (channel << 6));
141 }
142
to_state(struct v4l2_subdev * sd)143 static inline struct tw2804 *to_state(struct v4l2_subdev *sd)
144 {
145 return container_of(sd, struct tw2804, sd);
146 }
147
to_state_from_ctrl(struct v4l2_ctrl * ctrl)148 static inline struct tw2804 *to_state_from_ctrl(struct v4l2_ctrl *ctrl)
149 {
150 return container_of(ctrl->handler, struct tw2804, hdl);
151 }
152
tw2804_log_status(struct v4l2_subdev * sd)153 static int tw2804_log_status(struct v4l2_subdev *sd)
154 {
155 struct tw2804 *state = to_state(sd);
156
157 v4l2_info(sd, "Standard: %s\n",
158 state->norm & V4L2_STD_525_60 ? "60 Hz" : "50 Hz");
159 v4l2_info(sd, "Channel: %d\n", state->channel);
160 v4l2_info(sd, "Input: %d\n", state->input);
161 return v4l2_ctrl_subdev_log_status(sd);
162 }
163
164 /*
165 * These volatile controls are needed because all four channels share
166 * these controls. So a change made to them through one channel would
167 * require another channel to be updated.
168 *
169 * Normally this would have been done in a different way, but since the one
170 * board that uses this driver sees this single chip as if it was on four
171 * different i2c adapters (each adapter belonging to a separate instance of
172 * the same USB driver) there is no reliable method that I have found to let
173 * the instances know about each other.
174 *
175 * So implementing these global registers as volatile is the best we can do.
176 */
tw2804_g_volatile_ctrl(struct v4l2_ctrl * ctrl)177 static int tw2804_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
178 {
179 struct tw2804 *state = to_state_from_ctrl(ctrl);
180 struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
181
182 switch (ctrl->id) {
183 case V4L2_CID_GAIN:
184 ctrl->val = read_reg(client, TW2804_REG_GAIN, 0);
185 return 0;
186
187 case V4L2_CID_CHROMA_GAIN:
188 ctrl->val = read_reg(client, TW2804_REG_CHROMA_GAIN, 0);
189 return 0;
190
191 case V4L2_CID_BLUE_BALANCE:
192 ctrl->val = read_reg(client, TW2804_REG_BLUE_BALANCE, 0);
193 return 0;
194
195 case V4L2_CID_RED_BALANCE:
196 ctrl->val = read_reg(client, TW2804_REG_RED_BALANCE, 0);
197 return 0;
198 }
199 return 0;
200 }
201
tw2804_s_ctrl(struct v4l2_ctrl * ctrl)202 static int tw2804_s_ctrl(struct v4l2_ctrl *ctrl)
203 {
204 struct tw2804 *state = to_state_from_ctrl(ctrl);
205 struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
206 int addr;
207 int reg;
208
209 switch (ctrl->id) {
210 case V4L2_CID_AUTOGAIN:
211 addr = TW2804_REG_AUTOGAIN;
212 reg = read_reg(client, addr, state->channel);
213 if (reg < 0)
214 return reg;
215 if (ctrl->val == 0)
216 reg &= ~(1 << 7);
217 else
218 reg |= 1 << 7;
219 return write_reg(client, addr, reg, state->channel);
220
221 case V4L2_CID_COLOR_KILLER:
222 addr = TW2804_REG_COLOR_KILLER;
223 reg = read_reg(client, addr, state->channel);
224 if (reg < 0)
225 return reg;
226 reg = (reg & ~(0x03)) | (ctrl->val == 0 ? 0x02 : 0x03);
227 return write_reg(client, addr, reg, state->channel);
228
229 case V4L2_CID_GAIN:
230 return write_reg(client, TW2804_REG_GAIN, ctrl->val, 0);
231
232 case V4L2_CID_CHROMA_GAIN:
233 return write_reg(client, TW2804_REG_CHROMA_GAIN, ctrl->val, 0);
234
235 case V4L2_CID_BLUE_BALANCE:
236 return write_reg(client, TW2804_REG_BLUE_BALANCE, ctrl->val, 0);
237
238 case V4L2_CID_RED_BALANCE:
239 return write_reg(client, TW2804_REG_RED_BALANCE, ctrl->val, 0);
240
241 case V4L2_CID_BRIGHTNESS:
242 return write_reg(client, TW2804_REG_BRIGHTNESS,
243 ctrl->val, state->channel);
244
245 case V4L2_CID_CONTRAST:
246 return write_reg(client, TW2804_REG_CONTRAST,
247 ctrl->val, state->channel);
248
249 case V4L2_CID_SATURATION:
250 return write_reg(client, TW2804_REG_SATURATION,
251 ctrl->val, state->channel);
252
253 case V4L2_CID_HUE:
254 return write_reg(client, TW2804_REG_HUE,
255 ctrl->val, state->channel);
256
257 default:
258 break;
259 }
260 return -EINVAL;
261 }
262
tw2804_s_std(struct v4l2_subdev * sd,v4l2_std_id norm)263 static int tw2804_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
264 {
265 struct tw2804 *dec = to_state(sd);
266 struct i2c_client *client = v4l2_get_subdevdata(sd);
267 bool is_60hz = norm & V4L2_STD_525_60;
268 u8 regs[] = {
269 0x01, is_60hz ? 0xc4 : 0x84,
270 0x09, is_60hz ? 0x07 : 0x04,
271 0x0a, is_60hz ? 0xf0 : 0x20,
272 0x0b, is_60hz ? 0x07 : 0x04,
273 0x0c, is_60hz ? 0xf0 : 0x20,
274 0x0d, is_60hz ? 0x40 : 0x4a,
275 0x16, is_60hz ? 0x00 : 0x40,
276 0x17, is_60hz ? 0x00 : 0x40,
277 0x20, is_60hz ? 0x07 : 0x0f,
278 0x21, is_60hz ? 0x07 : 0x0f,
279 0xff, 0xff,
280 };
281
282 write_regs(client, regs, dec->channel);
283 dec->norm = norm;
284 return 0;
285 }
286
tw2804_s_video_routing(struct v4l2_subdev * sd,u32 input,u32 output,u32 config)287 static int tw2804_s_video_routing(struct v4l2_subdev *sd, u32 input, u32 output,
288 u32 config)
289 {
290 struct tw2804 *dec = to_state(sd);
291 struct i2c_client *client = v4l2_get_subdevdata(sd);
292 int reg;
293
294 if (config && config - 1 != dec->channel) {
295 if (config > 4) {
296 dev_err(&client->dev,
297 "channel %d is not between 1 and 4!\n", config);
298 return -EINVAL;
299 }
300 dec->channel = config - 1;
301 dev_dbg(&client->dev, "initializing TW2804 channel %d\n",
302 dec->channel);
303 if (dec->channel == 0 &&
304 write_regs(client, global_registers, 0) < 0) {
305 dev_err(&client->dev,
306 "error initializing TW2804 global registers\n");
307 return -EIO;
308 }
309 if (write_regs(client, channel_registers, dec->channel) < 0) {
310 dev_err(&client->dev,
311 "error initializing TW2804 channel %d\n",
312 dec->channel);
313 return -EIO;
314 }
315 }
316
317 if (input > 1)
318 return -EINVAL;
319
320 if (input == dec->input)
321 return 0;
322
323 reg = read_reg(client, 0x22, dec->channel);
324
325 if (reg >= 0) {
326 if (input == 0)
327 reg &= ~(1 << 2);
328 else
329 reg |= 1 << 2;
330 reg = write_reg(client, 0x22, reg, dec->channel);
331 }
332
333 if (reg >= 0)
334 dec->input = input;
335 else
336 return reg;
337 return 0;
338 }
339
340 static const struct v4l2_ctrl_ops tw2804_ctrl_ops = {
341 .g_volatile_ctrl = tw2804_g_volatile_ctrl,
342 .s_ctrl = tw2804_s_ctrl,
343 };
344
345 static const struct v4l2_subdev_video_ops tw2804_video_ops = {
346 .s_routing = tw2804_s_video_routing,
347 };
348
349 static const struct v4l2_subdev_core_ops tw2804_core_ops = {
350 .log_status = tw2804_log_status,
351 .s_std = tw2804_s_std,
352 };
353
354 static const struct v4l2_subdev_ops tw2804_ops = {
355 .core = &tw2804_core_ops,
356 .video = &tw2804_video_ops,
357 };
358
tw2804_probe(struct i2c_client * client,const struct i2c_device_id * id)359 static int tw2804_probe(struct i2c_client *client,
360 const struct i2c_device_id *id)
361 {
362 struct i2c_adapter *adapter = client->adapter;
363 struct tw2804 *state;
364 struct v4l2_subdev *sd;
365 struct v4l2_ctrl *ctrl;
366 int err;
367
368 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
369 return -ENODEV;
370
371 state = kzalloc(sizeof(struct tw2804), GFP_KERNEL);
372
373 if (state == NULL)
374 return -ENOMEM;
375 sd = &state->sd;
376 v4l2_i2c_subdev_init(sd, client, &tw2804_ops);
377 state->channel = -1;
378 state->norm = V4L2_STD_NTSC;
379
380 v4l2_ctrl_handler_init(&state->hdl, 10);
381 v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
382 V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
383 v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
384 V4L2_CID_CONTRAST, 0, 255, 1, 128);
385 v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
386 V4L2_CID_SATURATION, 0, 255, 1, 128);
387 v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
388 V4L2_CID_HUE, 0, 255, 1, 128);
389 v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
390 V4L2_CID_COLOR_KILLER, 0, 1, 1, 0);
391 v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
392 V4L2_CID_AUTOGAIN, 0, 1, 1, 0);
393 ctrl = v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
394 V4L2_CID_GAIN, 0, 255, 1, 128);
395 if (ctrl)
396 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
397 ctrl = v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
398 V4L2_CID_CHROMA_GAIN, 0, 255, 1, 128);
399 if (ctrl)
400 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
401 ctrl = v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
402 V4L2_CID_BLUE_BALANCE, 0, 255, 1, 122);
403 if (ctrl)
404 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
405 ctrl = v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
406 V4L2_CID_RED_BALANCE, 0, 255, 1, 122);
407 if (ctrl)
408 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
409 sd->ctrl_handler = &state->hdl;
410 err = state->hdl.error;
411 if (err) {
412 v4l2_ctrl_handler_free(&state->hdl);
413 kfree(state);
414 return err;
415 }
416
417 v4l_info(client, "chip found @ 0x%02x (%s)\n",
418 client->addr << 1, client->adapter->name);
419
420 return 0;
421 }
422
tw2804_remove(struct i2c_client * client)423 static int tw2804_remove(struct i2c_client *client)
424 {
425 struct v4l2_subdev *sd = i2c_get_clientdata(client);
426 struct tw2804 *state = to_state(sd);
427
428 v4l2_device_unregister_subdev(sd);
429 v4l2_ctrl_handler_free(&state->hdl);
430 kfree(state);
431 return 0;
432 }
433
434 static const struct i2c_device_id tw2804_id[] = {
435 { "tw2804", 0 },
436 { }
437 };
438 MODULE_DEVICE_TABLE(i2c, tw2804_id);
439
440 static struct i2c_driver tw2804_driver = {
441 .driver = {
442 .name = "tw2804",
443 },
444 .probe = tw2804_probe,
445 .remove = tw2804_remove,
446 .id_table = tw2804_id,
447 };
448
449 module_i2c_driver(tw2804_driver);
450
451 MODULE_LICENSE("GPL v2");
452 MODULE_DESCRIPTION("TW2804/TW2802 V4L2 i2c driver");
453 MODULE_AUTHOR("Micronas USA Inc");
454