Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6
[pandora-kernel.git] / drivers / staging / go7007 / wis-saa7115.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 #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
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
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
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
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
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
456 static int __init wis_saa7115_init(void)
457 {
458         return i2c_add_driver(&wis_saa7115_driver);
459 }
460
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");