• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/staging/go7007/
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
27struct wis_saa7115 {
28	int norm;
29	int brightness;
30	int contrast;
31	int saturation;
32	int hue;
33};
34
35static 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
185static int write_reg(struct i2c_client *client, u8 reg, u8 value)
186{
187	return i2c_smbus_write_byte_data(client, reg, value);
188}
189
190static 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
200static 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
398static 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
432static 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
440static const struct i2c_device_id wis_saa7115_id[] = {
441	{ "wis_saa7115", 0 },
442	{ }
443};
444
445static struct i2c_driver wis_saa7115_driver = {
446	.driver = {
447		.name	= "WIS SAA7115 I2C driver",
448	},
449	.probe		= wis_saa7115_probe,
450	.remove		= wis_saa7115_remove,
451	.command	= wis_saa7115_command,
452	.id_table	= wis_saa7115_id,
453};
454
455static int __init wis_saa7115_init(void)
456{
457	return i2c_add_driver(&wis_saa7115_driver);
458}
459
460static void __exit wis_saa7115_cleanup(void)
461{
462	i2c_del_driver(&wis_saa7115_driver);
463}
464
465module_init(wis_saa7115_init);
466module_exit(wis_saa7115_cleanup);
467
468MODULE_LICENSE("GPL v2");
469