dm thin metadata: fix __udivdi3 undefined on 32-bit
[linux/fpc-iii.git] / drivers / media / i2c / tw2804.c
blob7347480c0b0c48788e44e6fad150343ccc6941e7
1 /*
2 * Copyright (C) 2005-2006 Micronas USA Inc.
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.
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.
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.
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-ctrls.h>
28 #define TW2804_REG_AUTOGAIN 0x02
29 #define TW2804_REG_HUE 0x0f
30 #define TW2804_REG_SATURATION 0x10
31 #define TW2804_REG_CONTRAST 0x11
32 #define TW2804_REG_BRIGHTNESS 0x12
33 #define TW2804_REG_COLOR_KILLER 0x14
34 #define TW2804_REG_GAIN 0x3c
35 #define TW2804_REG_CHROMA_GAIN 0x3d
36 #define TW2804_REG_BLUE_BALANCE 0x3e
37 #define TW2804_REG_RED_BALANCE 0x3f
39 struct tw2804 {
40 struct v4l2_subdev sd;
41 struct v4l2_ctrl_handler hdl;
42 u8 channel:2;
43 u8 input:1;
44 int norm;
47 static const u8 global_registers[] = {
48 0x39, 0x00,
49 0x3a, 0xff,
50 0x3b, 0x84,
51 0x3c, 0x80,
52 0x3d, 0x80,
53 0x3e, 0x82,
54 0x3f, 0x82,
55 0x78, 0x00,
56 0xff, 0xff, /* Terminator (reg 0xff does not exist) */
59 static const u8 channel_registers[] = {
60 0x01, 0xc4,
61 0x02, 0xa5,
62 0x03, 0x20,
63 0x04, 0xd0,
64 0x05, 0x20,
65 0x06, 0xd0,
66 0x07, 0x88,
67 0x08, 0x20,
68 0x09, 0x07,
69 0x0a, 0xf0,
70 0x0b, 0x07,
71 0x0c, 0xf0,
72 0x0d, 0x40,
73 0x0e, 0xd2,
74 0x0f, 0x80,
75 0x10, 0x80,
76 0x11, 0x80,
77 0x12, 0x80,
78 0x13, 0x1f,
79 0x14, 0x00,
80 0x15, 0x00,
81 0x16, 0x00,
82 0x17, 0x00,
83 0x18, 0xff,
84 0x19, 0xff,
85 0x1a, 0xff,
86 0x1b, 0xff,
87 0x1c, 0xff,
88 0x1d, 0xff,
89 0x1e, 0xff,
90 0x1f, 0xff,
91 0x20, 0x07,
92 0x21, 0x07,
93 0x22, 0x00,
94 0x23, 0x91,
95 0x24, 0x51,
96 0x25, 0x03,
97 0x26, 0x00,
98 0x27, 0x00,
99 0x28, 0x00,
100 0x29, 0x00,
101 0x2a, 0x00,
102 0x2b, 0x00,
103 0x2c, 0x00,
104 0x2d, 0x00,
105 0x2e, 0x00,
106 0x2f, 0x00,
107 0x30, 0x00,
108 0x31, 0x00,
109 0x32, 0x00,
110 0x33, 0x00,
111 0x34, 0x00,
112 0x35, 0x00,
113 0x36, 0x00,
114 0x37, 0x00,
115 0xff, 0xff, /* Terminator (reg 0xff does not exist) */
118 static int write_reg(struct i2c_client *client, u8 reg, u8 value, u8 channel)
120 return i2c_smbus_write_byte_data(client, reg | (channel << 6), value);
123 static int write_regs(struct i2c_client *client, const u8 *regs, u8 channel)
125 int ret;
126 int i;
128 for (i = 0; regs[i] != 0xff; i += 2) {
129 ret = i2c_smbus_write_byte_data(client,
130 regs[i] | (channel << 6), regs[i + 1]);
131 if (ret < 0)
132 return ret;
134 return 0;
137 static int read_reg(struct i2c_client *client, u8 reg, u8 channel)
139 return i2c_smbus_read_byte_data(client, (reg) | (channel << 6));
142 static inline struct tw2804 *to_state(struct v4l2_subdev *sd)
144 return container_of(sd, struct tw2804, sd);
147 static inline struct tw2804 *to_state_from_ctrl(struct v4l2_ctrl *ctrl)
149 return container_of(ctrl->handler, struct tw2804, hdl);
152 static int tw2804_log_status(struct v4l2_subdev *sd)
154 struct tw2804 *state = to_state(sd);
156 v4l2_info(sd, "Standard: %s\n",
157 state->norm & V4L2_STD_525_60 ? "60 Hz" : "50 Hz");
158 v4l2_info(sd, "Channel: %d\n", state->channel);
159 v4l2_info(sd, "Input: %d\n", state->input);
160 return v4l2_ctrl_subdev_log_status(sd);
164 * These volatile controls are needed because all four channels share
165 * these controls. So a change made to them through one channel would
166 * require another channel to be updated.
168 * Normally this would have been done in a different way, but since the one
169 * board that uses this driver sees this single chip as if it was on four
170 * different i2c adapters (each adapter belonging to a separate instance of
171 * the same USB driver) there is no reliable method that I have found to let
172 * the instances know about each other.
174 * So implementing these global registers as volatile is the best we can do.
176 static int tw2804_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
178 struct tw2804 *state = to_state_from_ctrl(ctrl);
179 struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
181 switch (ctrl->id) {
182 case V4L2_CID_GAIN:
183 ctrl->val = read_reg(client, TW2804_REG_GAIN, 0);
184 return 0;
186 case V4L2_CID_CHROMA_GAIN:
187 ctrl->val = read_reg(client, TW2804_REG_CHROMA_GAIN, 0);
188 return 0;
190 case V4L2_CID_BLUE_BALANCE:
191 ctrl->val = read_reg(client, TW2804_REG_BLUE_BALANCE, 0);
192 return 0;
194 case V4L2_CID_RED_BALANCE:
195 ctrl->val = read_reg(client, TW2804_REG_RED_BALANCE, 0);
196 return 0;
198 return 0;
201 static int tw2804_s_ctrl(struct v4l2_ctrl *ctrl)
203 struct tw2804 *state = to_state_from_ctrl(ctrl);
204 struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
205 int addr;
206 int reg;
208 switch (ctrl->id) {
209 case V4L2_CID_AUTOGAIN:
210 addr = TW2804_REG_AUTOGAIN;
211 reg = read_reg(client, addr, state->channel);
212 if (reg < 0)
213 return reg;
214 if (ctrl->val == 0)
215 reg &= ~(1 << 7);
216 else
217 reg |= 1 << 7;
218 return write_reg(client, addr, reg, state->channel);
220 case V4L2_CID_COLOR_KILLER:
221 addr = TW2804_REG_COLOR_KILLER;
222 reg = read_reg(client, addr, state->channel);
223 if (reg < 0)
224 return reg;
225 reg = (reg & ~(0x03)) | (ctrl->val == 0 ? 0x02 : 0x03);
226 return write_reg(client, addr, reg, state->channel);
228 case V4L2_CID_GAIN:
229 return write_reg(client, TW2804_REG_GAIN, ctrl->val, 0);
231 case V4L2_CID_CHROMA_GAIN:
232 return write_reg(client, TW2804_REG_CHROMA_GAIN, ctrl->val, 0);
234 case V4L2_CID_BLUE_BALANCE:
235 return write_reg(client, TW2804_REG_BLUE_BALANCE, ctrl->val, 0);
237 case V4L2_CID_RED_BALANCE:
238 return write_reg(client, TW2804_REG_RED_BALANCE, ctrl->val, 0);
240 case V4L2_CID_BRIGHTNESS:
241 return write_reg(client, TW2804_REG_BRIGHTNESS,
242 ctrl->val, state->channel);
244 case V4L2_CID_CONTRAST:
245 return write_reg(client, TW2804_REG_CONTRAST,
246 ctrl->val, state->channel);
248 case V4L2_CID_SATURATION:
249 return write_reg(client, TW2804_REG_SATURATION,
250 ctrl->val, state->channel);
252 case V4L2_CID_HUE:
253 return write_reg(client, TW2804_REG_HUE,
254 ctrl->val, state->channel);
256 default:
257 break;
259 return -EINVAL;
262 static int tw2804_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
264 struct tw2804 *dec = to_state(sd);
265 struct i2c_client *client = v4l2_get_subdevdata(sd);
266 bool is_60hz = norm & V4L2_STD_525_60;
267 u8 regs[] = {
268 0x01, is_60hz ? 0xc4 : 0x84,
269 0x09, is_60hz ? 0x07 : 0x04,
270 0x0a, is_60hz ? 0xf0 : 0x20,
271 0x0b, is_60hz ? 0x07 : 0x04,
272 0x0c, is_60hz ? 0xf0 : 0x20,
273 0x0d, is_60hz ? 0x40 : 0x4a,
274 0x16, is_60hz ? 0x00 : 0x40,
275 0x17, is_60hz ? 0x00 : 0x40,
276 0x20, is_60hz ? 0x07 : 0x0f,
277 0x21, is_60hz ? 0x07 : 0x0f,
278 0xff, 0xff,
281 write_regs(client, regs, dec->channel);
282 dec->norm = norm;
283 return 0;
286 static int tw2804_s_video_routing(struct v4l2_subdev *sd, u32 input, u32 output,
287 u32 config)
289 struct tw2804 *dec = to_state(sd);
290 struct i2c_client *client = v4l2_get_subdevdata(sd);
291 int reg;
293 if (config && config - 1 != dec->channel) {
294 if (config > 4) {
295 dev_err(&client->dev,
296 "channel %d is not between 1 and 4!\n", config);
297 return -EINVAL;
299 dec->channel = config - 1;
300 dev_dbg(&client->dev, "initializing TW2804 channel %d\n",
301 dec->channel);
302 if (dec->channel == 0 &&
303 write_regs(client, global_registers, 0) < 0) {
304 dev_err(&client->dev,
305 "error initializing TW2804 global registers\n");
306 return -EIO;
308 if (write_regs(client, channel_registers, dec->channel) < 0) {
309 dev_err(&client->dev,
310 "error initializing TW2804 channel %d\n",
311 dec->channel);
312 return -EIO;
316 if (input > 1)
317 return -EINVAL;
319 if (input == dec->input)
320 return 0;
322 reg = read_reg(client, 0x22, dec->channel);
324 if (reg >= 0) {
325 if (input == 0)
326 reg &= ~(1 << 2);
327 else
328 reg |= 1 << 2;
329 reg = write_reg(client, 0x22, reg, dec->channel);
332 if (reg >= 0)
333 dec->input = input;
334 else
335 return reg;
336 return 0;
339 static const struct v4l2_ctrl_ops tw2804_ctrl_ops = {
340 .g_volatile_ctrl = tw2804_g_volatile_ctrl,
341 .s_ctrl = tw2804_s_ctrl,
344 static const struct v4l2_subdev_video_ops tw2804_video_ops = {
345 .s_std = tw2804_s_std,
346 .s_routing = tw2804_s_video_routing,
349 static const struct v4l2_subdev_core_ops tw2804_core_ops = {
350 .log_status = tw2804_log_status,
353 static const struct v4l2_subdev_ops tw2804_ops = {
354 .core = &tw2804_core_ops,
355 .video = &tw2804_video_ops,
358 static int tw2804_probe(struct i2c_client *client,
359 const struct i2c_device_id *id)
361 struct i2c_adapter *adapter = client->adapter;
362 struct tw2804 *state;
363 struct v4l2_subdev *sd;
364 struct v4l2_ctrl *ctrl;
365 int err;
367 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
368 return -ENODEV;
370 state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
371 if (state == NULL)
372 return -ENOMEM;
373 sd = &state->sd;
374 v4l2_i2c_subdev_init(sd, client, &tw2804_ops);
375 state->channel = -1;
376 state->norm = V4L2_STD_NTSC;
378 v4l2_ctrl_handler_init(&state->hdl, 10);
379 v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
380 V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
381 v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
382 V4L2_CID_CONTRAST, 0, 255, 1, 128);
383 v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
384 V4L2_CID_SATURATION, 0, 255, 1, 128);
385 v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
386 V4L2_CID_HUE, 0, 255, 1, 128);
387 v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
388 V4L2_CID_COLOR_KILLER, 0, 1, 1, 0);
389 v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
390 V4L2_CID_AUTOGAIN, 0, 1, 1, 0);
391 ctrl = v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
392 V4L2_CID_GAIN, 0, 255, 1, 128);
393 if (ctrl)
394 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
395 ctrl = v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
396 V4L2_CID_CHROMA_GAIN, 0, 255, 1, 128);
397 if (ctrl)
398 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
399 ctrl = v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
400 V4L2_CID_BLUE_BALANCE, 0, 255, 1, 122);
401 if (ctrl)
402 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
403 ctrl = v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
404 V4L2_CID_RED_BALANCE, 0, 255, 1, 122);
405 if (ctrl)
406 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
407 sd->ctrl_handler = &state->hdl;
408 err = state->hdl.error;
409 if (err) {
410 v4l2_ctrl_handler_free(&state->hdl);
411 return err;
414 v4l_info(client, "chip found @ 0x%02x (%s)\n",
415 client->addr << 1, client->adapter->name);
417 return 0;
420 static int tw2804_remove(struct i2c_client *client)
422 struct v4l2_subdev *sd = i2c_get_clientdata(client);
423 struct tw2804 *state = to_state(sd);
425 v4l2_device_unregister_subdev(sd);
426 v4l2_ctrl_handler_free(&state->hdl);
427 return 0;
430 static const struct i2c_device_id tw2804_id[] = {
431 { "tw2804", 0 },
434 MODULE_DEVICE_TABLE(i2c, tw2804_id);
436 static struct i2c_driver tw2804_driver = {
437 .driver = {
438 .name = "tw2804",
440 .probe = tw2804_probe,
441 .remove = tw2804_remove,
442 .id_table = tw2804_id,
445 module_i2c_driver(tw2804_driver);
447 MODULE_LICENSE("GPL v2");
448 MODULE_DESCRIPTION("TW2804/TW2802 V4L2 i2c driver");
449 MODULE_AUTHOR("Micronas USA Inc");