xref: /openbmc/linux/drivers/media/i2c/tw2804.c (revision a8fe58ce)
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-ctrls.h>
27 
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
38 
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;
45 };
46 
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) */
57 };
58 
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) */
116 };
117 
118 static int write_reg(struct i2c_client *client, u8 reg, u8 value, u8 channel)
119 {
120 	return i2c_smbus_write_byte_data(client, reg | (channel << 6), value);
121 }
122 
123 static int write_regs(struct i2c_client *client, const u8 *regs, u8 channel)
124 {
125 	int ret;
126 	int i;
127 
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;
133 	}
134 	return 0;
135 }
136 
137 static int read_reg(struct i2c_client *client, u8 reg, u8 channel)
138 {
139 	return i2c_smbus_read_byte_data(client, (reg) | (channel << 6));
140 }
141 
142 static inline struct tw2804 *to_state(struct v4l2_subdev *sd)
143 {
144 	return container_of(sd, struct tw2804, sd);
145 }
146 
147 static inline struct tw2804 *to_state_from_ctrl(struct v4l2_ctrl *ctrl)
148 {
149 	return container_of(ctrl->handler, struct tw2804, hdl);
150 }
151 
152 static int tw2804_log_status(struct v4l2_subdev *sd)
153 {
154 	struct tw2804 *state = to_state(sd);
155 
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);
161 }
162 
163 /*
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.
167  *
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.
173  *
174  * So implementing these global registers as volatile is the best we can do.
175  */
176 static int tw2804_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
177 {
178 	struct tw2804 *state = to_state_from_ctrl(ctrl);
179 	struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
180 
181 	switch (ctrl->id) {
182 	case V4L2_CID_GAIN:
183 		ctrl->val = read_reg(client, TW2804_REG_GAIN, 0);
184 		return 0;
185 
186 	case V4L2_CID_CHROMA_GAIN:
187 		ctrl->val = read_reg(client, TW2804_REG_CHROMA_GAIN, 0);
188 		return 0;
189 
190 	case V4L2_CID_BLUE_BALANCE:
191 		ctrl->val = read_reg(client, TW2804_REG_BLUE_BALANCE, 0);
192 		return 0;
193 
194 	case V4L2_CID_RED_BALANCE:
195 		ctrl->val = read_reg(client, TW2804_REG_RED_BALANCE, 0);
196 		return 0;
197 	}
198 	return 0;
199 }
200 
201 static int tw2804_s_ctrl(struct v4l2_ctrl *ctrl)
202 {
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;
207 
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);
219 
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);
227 
228 	case V4L2_CID_GAIN:
229 		return write_reg(client, TW2804_REG_GAIN, ctrl->val, 0);
230 
231 	case V4L2_CID_CHROMA_GAIN:
232 		return write_reg(client, TW2804_REG_CHROMA_GAIN, ctrl->val, 0);
233 
234 	case V4L2_CID_BLUE_BALANCE:
235 		return write_reg(client, TW2804_REG_BLUE_BALANCE, ctrl->val, 0);
236 
237 	case V4L2_CID_RED_BALANCE:
238 		return write_reg(client, TW2804_REG_RED_BALANCE, ctrl->val, 0);
239 
240 	case V4L2_CID_BRIGHTNESS:
241 		return write_reg(client, TW2804_REG_BRIGHTNESS,
242 				ctrl->val, state->channel);
243 
244 	case V4L2_CID_CONTRAST:
245 		return write_reg(client, TW2804_REG_CONTRAST,
246 				ctrl->val, state->channel);
247 
248 	case V4L2_CID_SATURATION:
249 		return write_reg(client, TW2804_REG_SATURATION,
250 				ctrl->val, state->channel);
251 
252 	case V4L2_CID_HUE:
253 		return write_reg(client, TW2804_REG_HUE,
254 				ctrl->val, state->channel);
255 
256 	default:
257 		break;
258 	}
259 	return -EINVAL;
260 }
261 
262 static int tw2804_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
263 {
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,
279 	};
280 
281 	write_regs(client, regs, dec->channel);
282 	dec->norm = norm;
283 	return 0;
284 }
285 
286 static int tw2804_s_video_routing(struct v4l2_subdev *sd, u32 input, u32 output,
287 	u32 config)
288 {
289 	struct tw2804 *dec = to_state(sd);
290 	struct i2c_client *client = v4l2_get_subdevdata(sd);
291 	int reg;
292 
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;
298 		}
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;
307 		}
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;
313 		}
314 	}
315 
316 	if (input > 1)
317 		return -EINVAL;
318 
319 	if (input == dec->input)
320 		return 0;
321 
322 	reg = read_reg(client, 0x22, dec->channel);
323 
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);
330 	}
331 
332 	if (reg >= 0)
333 		dec->input = input;
334 	else
335 		return reg;
336 	return 0;
337 }
338 
339 static const struct v4l2_ctrl_ops tw2804_ctrl_ops = {
340 	.g_volatile_ctrl = tw2804_g_volatile_ctrl,
341 	.s_ctrl = tw2804_s_ctrl,
342 };
343 
344 static const struct v4l2_subdev_video_ops tw2804_video_ops = {
345 	.s_std = tw2804_s_std,
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 };
352 
353 static const struct v4l2_subdev_ops tw2804_ops = {
354 	.core = &tw2804_core_ops,
355 	.video = &tw2804_video_ops,
356 };
357 
358 static int tw2804_probe(struct i2c_client *client,
359 			    const struct i2c_device_id *id)
360 {
361 	struct i2c_adapter *adapter = client->adapter;
362 	struct tw2804 *state;
363 	struct v4l2_subdev *sd;
364 	struct v4l2_ctrl *ctrl;
365 	int err;
366 
367 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
368 		return -ENODEV;
369 
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;
377 
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;
412 	}
413 
414 	v4l_info(client, "chip found @ 0x%02x (%s)\n",
415 			client->addr << 1, client->adapter->name);
416 
417 	return 0;
418 }
419 
420 static int tw2804_remove(struct i2c_client *client)
421 {
422 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
423 	struct tw2804 *state = to_state(sd);
424 
425 	v4l2_device_unregister_subdev(sd);
426 	v4l2_ctrl_handler_free(&state->hdl);
427 	return 0;
428 }
429 
430 static const struct i2c_device_id tw2804_id[] = {
431 	{ "tw2804", 0 },
432 	{ }
433 };
434 MODULE_DEVICE_TABLE(i2c, tw2804_id);
435 
436 static struct i2c_driver tw2804_driver = {
437 	.driver = {
438 		.name	= "tw2804",
439 	},
440 	.probe		= tw2804_probe,
441 	.remove		= tw2804_remove,
442 	.id_table	= tw2804_id,
443 };
444 
445 module_i2c_driver(tw2804_driver);
446 
447 MODULE_LICENSE("GPL v2");
448 MODULE_DESCRIPTION("TW2804/TW2802 V4L2 i2c driver");
449 MODULE_AUTHOR("Micronas USA Inc");
450