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