]> Pileus Git - ~andy/linux/blob - drivers/media/i2c/tw2804.c
Merge branch 'for-next' of git://github.com/rydberg/linux into next
[~andy/linux] / drivers / media / i2c / tw2804.c
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
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
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
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
143 static inline struct tw2804 *to_state(struct v4l2_subdev *sd)
144 {
145         return container_of(sd, struct tw2804, sd);
146 }
147
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
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  */
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
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
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
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
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
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");