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 
25 #include "wis-i2c.h"
26 
27 struct wis_saa7115 {
28 	int norm;
29 	int brightness;
30 	int contrast;
31 	int saturation;
32 	int hue;
33 };
34 
35 static u8 initial_registers[] =
36 {
37 	0x01, 0x08,
38 	0x02, 0xc0,
39 	0x03, 0x20,
40 	0x04, 0x80,
41 	0x05, 0x80,
42 	0x06, 0xeb,
43 	0x07, 0xe0,
44 	0x08, 0xf0,	/* always toggle FID */
45 	0x09, 0x40,
46 	0x0a, 0x80,
47 	0x0b, 0x40,
48 	0x0c, 0x40,
49 	0x0d, 0x00,
50 	0x0e, 0x03,
51 	0x0f, 0x2a,
52 	0x10, 0x0e,
53 	0x11, 0x00,
54 	0x12, 0x8d,
55 	0x13, 0x00,
56 	0x14, 0x00,
57 	0x15, 0x11,
58 	0x16, 0x01,
59 	0x17, 0xda,
60 	0x18, 0x40,
61 	0x19, 0x80,
62 	0x1a, 0x00,
63 	0x1b, 0x42,
64 	0x1c, 0xa9,
65 	0x30, 0x66,
66 	0x31, 0x90,
67 	0x32, 0x01,
68 	0x34, 0x00,
69 	0x35, 0x00,
70 	0x36, 0x20,
71 	0x38, 0x03,
72 	0x39, 0x20,
73 	0x3a, 0x88,
74 	0x40, 0x00,
75 	0x41, 0xff,
76 	0x42, 0xff,
77 	0x43, 0xff,
78 	0x44, 0xff,
79 	0x45, 0xff,
80 	0x46, 0xff,
81 	0x47, 0xff,
82 	0x48, 0xff,
83 	0x49, 0xff,
84 	0x4a, 0xff,
85 	0x4b, 0xff,
86 	0x4c, 0xff,
87 	0x4d, 0xff,
88 	0x4e, 0xff,
89 	0x4f, 0xff,
90 	0x50, 0xff,
91 	0x51, 0xff,
92 	0x52, 0xff,
93 	0x53, 0xff,
94 	0x54, 0xf4 /*0xff*/,
95 	0x55, 0xff,
96 	0x56, 0xff,
97 	0x57, 0xff,
98 	0x58, 0x40,
99 	0x59, 0x47,
100 	0x5a, 0x06 /*0x03*/,
101 	0x5b, 0x83,
102 	0x5d, 0x06,
103 	0x5e, 0x00,
104 	0x80, 0x30, /* window defined scaler operation, task A and B enabled */
105 	0x81, 0x03, /* use scaler datapath generated V */
106 	0x83, 0x00,
107 	0x84, 0x00,
108 	0x85, 0x00,
109 	0x86, 0x45,
110 	0x87, 0x31,
111 	0x88, 0xc0,
112 	0x90, 0x02, /* task A process top field */
113 	0x91, 0x08,
114 	0x92, 0x09,
115 	0x93, 0x80,
116 	0x94, 0x06,
117 	0x95, 0x00,
118 	0x96, 0xc0,
119 	0x97, 0x02,
120 	0x98, 0x12,
121 	0x99, 0x00,
122 	0x9a, 0xf2,
123 	0x9b, 0x00,
124 	0x9c, 0xd0,
125 	0x9d, 0x02,
126 	0x9e, 0xf2,
127 	0x9f, 0x00,
128 	0xa0, 0x01,
129 	0xa1, 0x01,
130 	0xa2, 0x01,
131 	0xa4, 0x80,
132 	0xa5, 0x40,
133 	0xa6, 0x40,
134 	0xa8, 0x00,
135 	0xa9, 0x04,
136 	0xaa, 0x00,
137 	0xac, 0x00,
138 	0xad, 0x02,
139 	0xae, 0x00,
140 	0xb0, 0x00,
141 	0xb1, 0x04,
142 	0xb2, 0x00,
143 	0xb3, 0x04,
144 	0xb4, 0x00,
145 	0xb8, 0x00,
146 	0xbc, 0x00,
147 	0xc0, 0x03,	/* task B process bottom field */
148 	0xc1, 0x08,
149 	0xc2, 0x09,
150 	0xc3, 0x80,
151 	0xc4, 0x06,
152 	0xc5, 0x00,
153 	0xc6, 0xc0,
154 	0xc7, 0x02,
155 	0xc8, 0x12,
156 	0xc9, 0x00,
157 	0xca, 0xf2,
158 	0xcb, 0x00,
159 	0xcc, 0xd0,
160 	0xcd, 0x02,
161 	0xce, 0xf2,
162 	0xcf, 0x00,
163 	0xd0, 0x01,
164 	0xd1, 0x01,
165 	0xd2, 0x01,
166 	0xd4, 0x80,
167 	0xd5, 0x40,
168 	0xd6, 0x40,
169 	0xd8, 0x00,
170 	0xd9, 0x04,
171 	0xda, 0x00,
172 	0xdc, 0x00,
173 	0xdd, 0x02,
174 	0xde, 0x00,
175 	0xe0, 0x00,
176 	0xe1, 0x04,
177 	0xe2, 0x00,
178 	0xe3, 0x04,
179 	0xe4, 0x00,
180 	0xe8, 0x00,
181 	0x88, 0xf0, /* End of original static list */
182 	0x00, 0x00, /* Terminator (reg 0x00 is read-only) */
183 };
184 
write_reg(struct i2c_client * client,u8 reg,u8 value)185 static int write_reg(struct i2c_client *client, u8 reg, u8 value)
186 {
187 	return i2c_smbus_write_byte_data(client, reg, value);
188 }
189 
write_regs(struct i2c_client * client,u8 * regs)190 static int write_regs(struct i2c_client *client, u8 *regs)
191 {
192 	int i;
193 
194 	for (i = 0; regs[i] != 0x00; i += 2)
195 		if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0)
196 			return -1;
197 	return 0;
198 }
199 
wis_saa7115_command(struct i2c_client * client,unsigned int cmd,void * arg)200 static int wis_saa7115_command(struct i2c_client *client,
201 				unsigned int cmd, void *arg)
202 {
203 	struct wis_saa7115 *dec = i2c_get_clientdata(client);
204 
205 	switch (cmd) {
206 	case VIDIOC_S_INPUT:
207 	{
208 		int *input = arg;
209 
210 		i2c_smbus_write_byte_data(client, 0x02, 0xC0 | *input);
211 		i2c_smbus_write_byte_data(client, 0x09,
212 				*input < 6 ? 0x40 : 0xC0);
213 		break;
214 	}
215 	case DECODER_SET_RESOLUTION:
216 	{
217 		struct video_decoder_resolution *res = arg;
218 		/* Course-grained scaler */
219 		int h_integer_scaler = res->width < 704 ? 704 / res->width : 1;
220 		/* Fine-grained scaler to take care of remainder */
221 		int h_scaling_increment = (704 / h_integer_scaler) *
222 					1024 / res->width;
223 		/* Fine-grained scaler only */
224 		int v_scaling_increment = (dec->norm & V4L2_STD_NTSC ?
225 				240 : 288) * 1024 / res->height;
226 		u8 regs[] = {
227 			0x88,	0xc0,
228 			0x9c,	res->width & 0xff,
229 			0x9d,	res->width >> 8,
230 			0x9e,	res->height & 0xff,
231 			0x9f,	res->height >> 8,
232 			0xa0,	h_integer_scaler,
233 			0xa1,	1,
234 			0xa2,	1,
235 			0xa8,	h_scaling_increment & 0xff,
236 			0xa9,	h_scaling_increment >> 8,
237 			0xac,	(h_scaling_increment / 2) & 0xff,
238 			0xad,	(h_scaling_increment / 2) >> 8,
239 			0xb0,	v_scaling_increment & 0xff,
240 			0xb1,	v_scaling_increment >> 8,
241 			0xb2,	v_scaling_increment & 0xff,
242 			0xb3,	v_scaling_increment >> 8,
243 			0xcc,	res->width & 0xff,
244 			0xcd,	res->width >> 8,
245 			0xce,	res->height & 0xff,
246 			0xcf,	res->height >> 8,
247 			0xd0,	h_integer_scaler,
248 			0xd1,	1,
249 			0xd2,	1,
250 			0xd8,	h_scaling_increment & 0xff,
251 			0xd9,	h_scaling_increment >> 8,
252 			0xdc,	(h_scaling_increment / 2) & 0xff,
253 			0xdd,	(h_scaling_increment / 2) >> 8,
254 			0xe0,	v_scaling_increment & 0xff,
255 			0xe1,	v_scaling_increment >> 8,
256 			0xe2,	v_scaling_increment & 0xff,
257 			0xe3,	v_scaling_increment >> 8,
258 			0x88,	0xf0,
259 			0,	0,
260 		};
261 		write_regs(client, regs);
262 		break;
263 	}
264 	case VIDIOC_S_STD:
265 	{
266 		v4l2_std_id *input = arg;
267 		u8 regs[] = {
268 			0x88,	0xc0,
269 			0x98,	*input & V4L2_STD_NTSC ? 0x12 : 0x16,
270 			0x9a,	*input & V4L2_STD_NTSC ? 0xf2 : 0x20,
271 			0x9b,	*input & V4L2_STD_NTSC ? 0x00 : 0x01,
272 			0xc8,	*input & V4L2_STD_NTSC ? 0x12 : 0x16,
273 			0xca,	*input & V4L2_STD_NTSC ? 0xf2 : 0x20,
274 			0xcb,	*input & V4L2_STD_NTSC ? 0x00 : 0x01,
275 			0x88,	0xf0,
276 			0x30,	*input & V4L2_STD_NTSC ? 0x66 : 0x00,
277 			0x31,	*input & V4L2_STD_NTSC ? 0x90 : 0xe0,
278 			0,	0,
279 		};
280 		write_regs(client, regs);
281 		dec->norm = *input;
282 		break;
283 	}
284 	case VIDIOC_QUERYCTRL:
285 	{
286 		struct v4l2_queryctrl *ctrl = arg;
287 
288 		switch (ctrl->id) {
289 		case V4L2_CID_BRIGHTNESS:
290 			ctrl->type = V4L2_CTRL_TYPE_INTEGER;
291 			strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
292 			ctrl->minimum = 0;
293 			ctrl->maximum = 255;
294 			ctrl->step = 1;
295 			ctrl->default_value = 128;
296 			ctrl->flags = 0;
297 			break;
298 		case V4L2_CID_CONTRAST:
299 			ctrl->type = V4L2_CTRL_TYPE_INTEGER;
300 			strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
301 			ctrl->minimum = 0;
302 			ctrl->maximum = 127;
303 			ctrl->step = 1;
304 			ctrl->default_value = 64;
305 			ctrl->flags = 0;
306 			break;
307 		case V4L2_CID_SATURATION:
308 			ctrl->type = V4L2_CTRL_TYPE_INTEGER;
309 			strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
310 			ctrl->minimum = 0;
311 			ctrl->maximum = 127;
312 			ctrl->step = 1;
313 			ctrl->default_value = 64;
314 			ctrl->flags = 0;
315 			break;
316 		case V4L2_CID_HUE:
317 			ctrl->type = V4L2_CTRL_TYPE_INTEGER;
318 			strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
319 			ctrl->minimum = -128;
320 			ctrl->maximum = 127;
321 			ctrl->step = 1;
322 			ctrl->default_value = 0;
323 			ctrl->flags = 0;
324 			break;
325 		}
326 		break;
327 	}
328 	case VIDIOC_S_CTRL:
329 	{
330 		struct v4l2_control *ctrl = arg;
331 
332 		switch (ctrl->id) {
333 		case V4L2_CID_BRIGHTNESS:
334 			if (ctrl->value > 255)
335 				dec->brightness = 255;
336 			else if (ctrl->value < 0)
337 				dec->brightness = 0;
338 			else
339 				dec->brightness = ctrl->value;
340 			write_reg(client, 0x0a, dec->brightness);
341 			break;
342 		case V4L2_CID_CONTRAST:
343 			if (ctrl->value > 127)
344 				dec->contrast = 127;
345 			else if (ctrl->value < 0)
346 				dec->contrast = 0;
347 			else
348 				dec->contrast = ctrl->value;
349 			write_reg(client, 0x0b, dec->contrast);
350 			break;
351 		case V4L2_CID_SATURATION:
352 			if (ctrl->value > 127)
353 				dec->saturation = 127;
354 			else if (ctrl->value < 0)
355 				dec->saturation = 0;
356 			else
357 				dec->saturation = ctrl->value;
358 			write_reg(client, 0x0c, dec->saturation);
359 			break;
360 		case V4L2_CID_HUE:
361 			if (ctrl->value > 127)
362 				dec->hue = 127;
363 			else if (ctrl->value < -128)
364 				dec->hue = -128;
365 			else
366 				dec->hue = ctrl->value;
367 			write_reg(client, 0x0d, dec->hue);
368 			break;
369 		}
370 		break;
371 	}
372 	case VIDIOC_G_CTRL:
373 	{
374 		struct v4l2_control *ctrl = arg;
375 
376 		switch (ctrl->id) {
377 		case V4L2_CID_BRIGHTNESS:
378 			ctrl->value = dec->brightness;
379 			break;
380 		case V4L2_CID_CONTRAST:
381 			ctrl->value = dec->contrast;
382 			break;
383 		case V4L2_CID_SATURATION:
384 			ctrl->value = dec->saturation;
385 			break;
386 		case V4L2_CID_HUE:
387 			ctrl->value = dec->hue;
388 			break;
389 		}
390 		break;
391 	}
392 	default:
393 		break;
394 	}
395 	return 0;
396 }
397 
wis_saa7115_probe(struct i2c_client * client,const struct i2c_device_id * id)398 static int wis_saa7115_probe(struct i2c_client *client,
399 			     const struct i2c_device_id *id)
400 {
401 	struct i2c_adapter *adapter = client->adapter;
402 	struct wis_saa7115 *dec;
403 
404 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
405 		return -ENODEV;
406 
407 	dec = kmalloc(sizeof(struct wis_saa7115), GFP_KERNEL);
408 	if (dec == NULL)
409 		return -ENOMEM;
410 
411 	dec->norm = V4L2_STD_NTSC;
412 	dec->brightness = 128;
413 	dec->contrast = 64;
414 	dec->saturation = 64;
415 	dec->hue = 0;
416 	i2c_set_clientdata(client, dec);
417 
418 	printk(KERN_DEBUG
419 		"wis-saa7115: initializing SAA7115 at address %d on %s\n",
420 		client->addr, adapter->name);
421 
422 	if (write_regs(client, initial_registers) < 0) {
423 		printk(KERN_ERR
424 			"wis-saa7115: error initializing SAA7115\n");
425 		kfree(dec);
426 		return -ENODEV;
427 	}
428 
429 	return 0;
430 }
431 
wis_saa7115_remove(struct i2c_client * client)432 static int wis_saa7115_remove(struct i2c_client *client)
433 {
434 	struct wis_saa7115 *dec = i2c_get_clientdata(client);
435 
436 	kfree(dec);
437 	return 0;
438 }
439 
440 static const struct i2c_device_id wis_saa7115_id[] = {
441 	{ "wis_saa7115", 0 },
442 	{ }
443 };
444 MODULE_DEVICE_TABLE(i2c, wis_saa7115_id);
445 
446 static struct i2c_driver wis_saa7115_driver = {
447 	.driver = {
448 		.name	= "WIS SAA7115 I2C driver",
449 	},
450 	.probe		= wis_saa7115_probe,
451 	.remove		= wis_saa7115_remove,
452 	.command	= wis_saa7115_command,
453 	.id_table	= wis_saa7115_id,
454 };
455 
wis_saa7115_init(void)456 static int __init wis_saa7115_init(void)
457 {
458 	return i2c_add_driver(&wis_saa7115_driver);
459 }
460 
wis_saa7115_cleanup(void)461 static void __exit wis_saa7115_cleanup(void)
462 {
463 	i2c_del_driver(&wis_saa7115_driver);
464 }
465 
466 module_init(wis_saa7115_init);
467 module_exit(wis_saa7115_cleanup);
468 
469 MODULE_LICENSE("GPL v2");
470