• 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_saa7113 {
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, 0x33,
40	0x04, 0x00,
41	0x05, 0x00,
42	0x06, 0xe9,
43	0x07, 0x0d,
44	0x08, 0xd8,
45	0x09, 0x40,
46	0x0a, 0x80,
47	0x0b, 0x47,
48	0x0c, 0x40,
49	0x0d, 0x00,
50	0x0e, 0x01,
51	0x0f, 0x2a,
52	0x10, 0x40,
53	0x11, 0x0c,
54	0x12, 0xfe,
55	0x13, 0x00,
56	0x14, 0x00,
57	0x15, 0x04,
58	0x16, 0x00,
59	0x17, 0x00,
60	0x18, 0x00,
61	0x19, 0x00,
62	0x1a, 0x00,
63	0x1b, 0x00,
64	0x1c, 0x00,
65	0x1d, 0x00,
66	0x1e, 0x00,
67	0x1f, 0xc8,
68	0x40, 0x00,
69	0x41, 0xff,
70	0x42, 0xff,
71	0x43, 0xff,
72	0x44, 0xff,
73	0x45, 0xff,
74	0x46, 0xff,
75	0x47, 0xff,
76	0x48, 0xff,
77	0x49, 0xff,
78	0x4a, 0xff,
79	0x4b, 0xff,
80	0x4c, 0xff,
81	0x4d, 0xff,
82	0x4e, 0xff,
83	0x4f, 0xff,
84	0x50, 0xff,
85	0x51, 0xff,
86	0x52, 0xff,
87	0x53, 0xff,
88	0x54, 0xff,
89	0x55, 0xff,
90	0x56, 0xff,
91	0x57, 0xff,
92	0x58, 0x00,
93	0x59, 0x54,
94	0x5a, 0x07,
95	0x5b, 0x83,
96	0x5c, 0x00,
97	0x5d, 0x00,
98	0x5e, 0x00,
99	0x5f, 0x00,
100	0x60, 0x00,
101	0x61, 0x00,
102	0x00, 0x00, /* Terminator (reg 0x00 is read-only) */
103};
104
105static int write_reg(struct i2c_client *client, u8 reg, u8 value)
106{
107	return i2c_smbus_write_byte_data(client, reg, value);
108}
109
110static int write_regs(struct i2c_client *client, u8 *regs)
111{
112	int i;
113
114	for (i = 0; regs[i] != 0x00; i += 2)
115		if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0)
116			return -1;
117	return 0;
118}
119
120static int wis_saa7113_command(struct i2c_client *client,
121				unsigned int cmd, void *arg)
122{
123	struct wis_saa7113 *dec = i2c_get_clientdata(client);
124
125	switch (cmd) {
126	case VIDIOC_S_INPUT:
127	{
128		int *input = arg;
129
130		i2c_smbus_write_byte_data(client, 0x02, 0xC0 | *input);
131		i2c_smbus_write_byte_data(client, 0x09,
132				*input < 6 ? 0x40 : 0x80);
133		break;
134	}
135	case VIDIOC_S_STD:
136	{
137		v4l2_std_id *input = arg;
138		dec->norm = *input;
139		if (dec->norm & V4L2_STD_NTSC) {
140			write_reg(client, 0x0e, 0x01);
141			write_reg(client, 0x10, 0x40);
142		} else if (dec->norm & V4L2_STD_PAL) {
143			write_reg(client, 0x0e, 0x01);
144			write_reg(client, 0x10, 0x48);
145		} else if (dec->norm * V4L2_STD_SECAM) {
146			write_reg(client, 0x0e, 0x50);
147			write_reg(client, 0x10, 0x48);
148		}
149		break;
150	}
151	case VIDIOC_QUERYCTRL:
152	{
153		struct v4l2_queryctrl *ctrl = arg;
154
155		switch (ctrl->id) {
156		case V4L2_CID_BRIGHTNESS:
157			ctrl->type = V4L2_CTRL_TYPE_INTEGER;
158			strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
159			ctrl->minimum = 0;
160			ctrl->maximum = 255;
161			ctrl->step = 1;
162			ctrl->default_value = 128;
163			ctrl->flags = 0;
164			break;
165		case V4L2_CID_CONTRAST:
166			ctrl->type = V4L2_CTRL_TYPE_INTEGER;
167			strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
168			ctrl->minimum = 0;
169			ctrl->maximum = 127;
170			ctrl->step = 1;
171			ctrl->default_value = 71;
172			ctrl->flags = 0;
173			break;
174		case V4L2_CID_SATURATION:
175			ctrl->type = V4L2_CTRL_TYPE_INTEGER;
176			strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
177			ctrl->minimum = 0;
178			ctrl->maximum = 127;
179			ctrl->step = 1;
180			ctrl->default_value = 64;
181			ctrl->flags = 0;
182			break;
183		case V4L2_CID_HUE:
184			ctrl->type = V4L2_CTRL_TYPE_INTEGER;
185			strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
186			ctrl->minimum = -128;
187			ctrl->maximum = 127;
188			ctrl->step = 1;
189			ctrl->default_value = 0;
190			ctrl->flags = 0;
191			break;
192		}
193		break;
194	}
195	case VIDIOC_S_CTRL:
196	{
197		struct v4l2_control *ctrl = arg;
198
199		switch (ctrl->id) {
200		case V4L2_CID_BRIGHTNESS:
201			if (ctrl->value > 255)
202				dec->brightness = 255;
203			else if (ctrl->value < 0)
204				dec->brightness = 0;
205			else
206				dec->brightness = ctrl->value;
207			write_reg(client, 0x0a, dec->brightness);
208			break;
209		case V4L2_CID_CONTRAST:
210			if (ctrl->value > 127)
211				dec->contrast = 127;
212			else if (ctrl->value < 0)
213				dec->contrast = 0;
214			else
215				dec->contrast = ctrl->value;
216			write_reg(client, 0x0b, dec->contrast);
217			break;
218		case V4L2_CID_SATURATION:
219			if (ctrl->value > 127)
220				dec->saturation = 127;
221			else if (ctrl->value < 0)
222				dec->saturation = 0;
223			else
224				dec->saturation = ctrl->value;
225			write_reg(client, 0x0c, dec->saturation);
226			break;
227		case V4L2_CID_HUE:
228			if (ctrl->value > 127)
229				dec->hue = 127;
230			else if (ctrl->value < -128)
231				dec->hue = -128;
232			else
233				dec->hue = ctrl->value;
234			write_reg(client, 0x0d, dec->hue);
235			break;
236		}
237		break;
238	}
239	case VIDIOC_G_CTRL:
240	{
241		struct v4l2_control *ctrl = arg;
242
243		switch (ctrl->id) {
244		case V4L2_CID_BRIGHTNESS:
245			ctrl->value = dec->brightness;
246			break;
247		case V4L2_CID_CONTRAST:
248			ctrl->value = dec->contrast;
249			break;
250		case V4L2_CID_SATURATION:
251			ctrl->value = dec->saturation;
252			break;
253		case V4L2_CID_HUE:
254			ctrl->value = dec->hue;
255			break;
256		}
257		break;
258	}
259	default:
260		break;
261	}
262	return 0;
263}
264
265static int wis_saa7113_probe(struct i2c_client *client,
266			     const struct i2c_device_id *id)
267{
268	struct i2c_adapter *adapter = client->adapter;
269	struct wis_saa7113 *dec;
270
271	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
272		return -ENODEV;
273
274	dec = kmalloc(sizeof(struct wis_saa7113), GFP_KERNEL);
275	if (dec == NULL)
276		return -ENOMEM;
277
278	dec->norm = V4L2_STD_NTSC;
279	dec->brightness = 128;
280	dec->contrast = 71;
281	dec->saturation = 64;
282	dec->hue = 0;
283	i2c_set_clientdata(client, dec);
284
285	printk(KERN_DEBUG
286		"wis-saa7113: initializing SAA7113 at address %d on %s\n",
287		client->addr, adapter->name);
288
289	if (write_regs(client, initial_registers) < 0) {
290		printk(KERN_ERR
291			"wis-saa7113: error initializing SAA7113\n");
292		kfree(dec);
293		return -ENODEV;
294	}
295
296	return 0;
297}
298
299static int wis_saa7113_remove(struct i2c_client *client)
300{
301	struct wis_saa7113 *dec = i2c_get_clientdata(client);
302
303	kfree(dec);
304	return 0;
305}
306
307static const struct i2c_device_id wis_saa7113_id[] = {
308	{ "wis_saa7113", 0 },
309	{ }
310};
311
312static struct i2c_driver wis_saa7113_driver = {
313	.driver = {
314		.name	= "WIS SAA7113 I2C driver",
315	},
316	.probe		= wis_saa7113_probe,
317	.remove		= wis_saa7113_remove,
318	.command	= wis_saa7113_command,
319	.id_table	= wis_saa7113_id,
320};
321
322static int __init wis_saa7113_init(void)
323{
324	return i2c_add_driver(&wis_saa7113_driver);
325}
326
327static void __exit wis_saa7113_cleanup(void)
328{
329	i2c_del_driver(&wis_saa7113_driver);
330}
331
332module_init(wis_saa7113_init);
333module_exit(wis_saa7113_cleanup);
334
335MODULE_LICENSE("GPL v2");
336