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_saa7113 {
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, 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 
write_reg(struct i2c_client * client,u8 reg,u8 value)105 static int write_reg(struct i2c_client *client, u8 reg, u8 value)
106 {
107 	return i2c_smbus_write_byte_data(client, reg, value);
108 }
109 
write_regs(struct i2c_client * client,u8 * regs)110 static 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 
wis_saa7113_command(struct i2c_client * client,unsigned int cmd,void * arg)120 static 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 
wis_saa7113_probe(struct i2c_client * client,const struct i2c_device_id * id)265 static 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 
wis_saa7113_remove(struct i2c_client * client)299 static 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 
307 static const struct i2c_device_id wis_saa7113_id[] = {
308 	{ "wis_saa7113", 0 },
309 	{ }
310 };
311 MODULE_DEVICE_TABLE(i2c, wis_saa7113_id);
312 
313 static struct i2c_driver wis_saa7113_driver = {
314 	.driver = {
315 		.name	= "WIS SAA7113 I2C driver",
316 	},
317 	.probe		= wis_saa7113_probe,
318 	.remove		= wis_saa7113_remove,
319 	.command	= wis_saa7113_command,
320 	.id_table	= wis_saa7113_id,
321 };
322 
wis_saa7113_init(void)323 static int __init wis_saa7113_init(void)
324 {
325 	return i2c_add_driver(&wis_saa7113_driver);
326 }
327 
wis_saa7113_cleanup(void)328 static void __exit wis_saa7113_cleanup(void)
329 {
330 	i2c_del_driver(&wis_saa7113_driver);
331 }
332 
333 module_init(wis_saa7113_init);
334 module_exit(wis_saa7113_cleanup);
335 
336 MODULE_LICENSE("GPL v2");
337