Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs
[linux-2.6] / 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
24 #include "wis-i2c.h"
25
26 struct wis_saa7115 {
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, 0x20,
39         0x04, 0x80,
40         0x05, 0x80,
41         0x06, 0xeb,
42         0x07, 0xe0,
43         0x08, 0xf0,     /* always toggle FID */
44         0x09, 0x40,
45         0x0a, 0x80,
46         0x0b, 0x40,
47         0x0c, 0x40,
48         0x0d, 0x00,
49         0x0e, 0x03,
50         0x0f, 0x2a,
51         0x10, 0x0e,
52         0x11, 0x00,
53         0x12, 0x8d,
54         0x13, 0x00,
55         0x14, 0x00,
56         0x15, 0x11,
57         0x16, 0x01,
58         0x17, 0xda,
59         0x18, 0x40,
60         0x19, 0x80,
61         0x1a, 0x00,
62         0x1b, 0x42,
63         0x1c, 0xa9,
64         0x30, 0x66,
65         0x31, 0x90,
66         0x32, 0x01,
67         0x34, 0x00,
68         0x35, 0x00,
69         0x36, 0x20,
70         0x38, 0x03,
71         0x39, 0x20,
72         0x3a, 0x88,
73         0x40, 0x00,
74         0x41, 0xff,
75         0x42, 0xff,
76         0x43, 0xff,
77         0x44, 0xff,
78         0x45, 0xff,
79         0x46, 0xff,
80         0x47, 0xff,
81         0x48, 0xff,
82         0x49, 0xff,
83         0x4a, 0xff,
84         0x4b, 0xff,
85         0x4c, 0xff,
86         0x4d, 0xff,
87         0x4e, 0xff,
88         0x4f, 0xff,
89         0x50, 0xff,
90         0x51, 0xff,
91         0x52, 0xff,
92         0x53, 0xff,
93         0x54, 0xf4 /*0xff*/,
94         0x55, 0xff,
95         0x56, 0xff,
96         0x57, 0xff,
97         0x58, 0x40,
98         0x59, 0x47,
99         0x5a, 0x06 /*0x03*/,
100         0x5b, 0x83,
101         0x5d, 0x06,
102         0x5e, 0x00,
103         0x80, 0x30, /* window defined scaler operation, task A and B enabled */
104         0x81, 0x03, /* use scaler datapath generated V */
105         0x83, 0x00,
106         0x84, 0x00,
107         0x85, 0x00,
108         0x86, 0x45,
109         0x87, 0x31,
110         0x88, 0xc0,
111         0x90, 0x02, /* task A process top field */
112         0x91, 0x08,
113         0x92, 0x09,
114         0x93, 0x80,
115         0x94, 0x06,
116         0x95, 0x00,
117         0x96, 0xc0,
118         0x97, 0x02,
119         0x98, 0x12,
120         0x99, 0x00,
121         0x9a, 0xf2,
122         0x9b, 0x00,
123         0x9c, 0xd0,
124         0x9d, 0x02,
125         0x9e, 0xf2,
126         0x9f, 0x00,
127         0xa0, 0x01,
128         0xa1, 0x01,
129         0xa2, 0x01,
130         0xa4, 0x80,
131         0xa5, 0x40,
132         0xa6, 0x40,
133         0xa8, 0x00,
134         0xa9, 0x04,
135         0xaa, 0x00,
136         0xac, 0x00,
137         0xad, 0x02,
138         0xae, 0x00,
139         0xb0, 0x00,
140         0xb1, 0x04,
141         0xb2, 0x00,
142         0xb3, 0x04,
143         0xb4, 0x00,
144         0xb8, 0x00,
145         0xbc, 0x00,
146         0xc0, 0x03,     /* task B process bottom field */
147         0xc1, 0x08,
148         0xc2, 0x09,
149         0xc3, 0x80,
150         0xc4, 0x06,
151         0xc5, 0x00,
152         0xc6, 0xc0,
153         0xc7, 0x02,
154         0xc8, 0x12,
155         0xc9, 0x00,
156         0xca, 0xf2,
157         0xcb, 0x00,
158         0xcc, 0xd0,
159         0xcd, 0x02,
160         0xce, 0xf2,
161         0xcf, 0x00,
162         0xd0, 0x01,
163         0xd1, 0x01,
164         0xd2, 0x01,
165         0xd4, 0x80,
166         0xd5, 0x40,
167         0xd6, 0x40,
168         0xd8, 0x00,
169         0xd9, 0x04,
170         0xda, 0x00,
171         0xdc, 0x00,
172         0xdd, 0x02,
173         0xde, 0x00,
174         0xe0, 0x00,
175         0xe1, 0x04,
176         0xe2, 0x00,
177         0xe3, 0x04,
178         0xe4, 0x00,
179         0xe8, 0x00,
180         0x88, 0xf0, /* End of original static list */
181         0x00, 0x00, /* Terminator (reg 0x00 is read-only) */
182 };
183
184 static int write_reg(struct i2c_client *client, u8 reg, u8 value)
185 {
186         return i2c_smbus_write_byte_data(client, reg, value);
187 }
188
189 static int write_regs(struct i2c_client *client, u8 *regs)
190 {
191         int i;
192
193         for (i = 0; regs[i] != 0x00; i += 2)
194                 if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0)
195                         return -1;
196         return 0;
197 }
198
199 static int wis_saa7115_command(struct i2c_client *client,
200                                 unsigned int cmd, void *arg)
201 {
202         struct wis_saa7115 *dec = i2c_get_clientdata(client);
203
204         switch (cmd) {
205         case VIDIOC_S_INPUT:
206         {
207                 int *input = arg;
208
209                 i2c_smbus_write_byte_data(client, 0x02, 0xC0 | *input);
210                 i2c_smbus_write_byte_data(client, 0x09,
211                                 *input < 6 ? 0x40 : 0xC0);
212                 break;
213         }
214         case DECODER_SET_RESOLUTION:
215         {
216                 struct video_decoder_resolution *res = arg;
217                 /* Course-grained scaler */
218                 int h_integer_scaler = res->width < 704 ? 704 / res->width : 1;
219                 /* Fine-grained scaler to take care of remainder */
220                 int h_scaling_increment = (704 / h_integer_scaler) *
221                                         1024 / res->width;
222                 /* Fine-grained scaler only */
223                 int v_scaling_increment = (dec->norm & V4L2_STD_NTSC ?
224                                 240 : 288) * 1024 / res->height;
225                 u8 regs[] = {
226                         0x88,   0xc0,
227                         0x9c,   res->width & 0xff,
228                         0x9d,   res->width >> 8,
229                         0x9e,   res->height & 0xff,
230                         0x9f,   res->height >> 8,
231                         0xa0,   h_integer_scaler,
232                         0xa1,   1,
233                         0xa2,   1,
234                         0xa8,   h_scaling_increment & 0xff,
235                         0xa9,   h_scaling_increment >> 8,
236                         0xac,   (h_scaling_increment / 2) & 0xff,
237                         0xad,   (h_scaling_increment / 2) >> 8,
238                         0xb0,   v_scaling_increment & 0xff,
239                         0xb1,   v_scaling_increment >> 8,
240                         0xb2,   v_scaling_increment & 0xff,
241                         0xb3,   v_scaling_increment >> 8,
242                         0xcc,   res->width & 0xff,
243                         0xcd,   res->width >> 8,
244                         0xce,   res->height & 0xff,
245                         0xcf,   res->height >> 8,
246                         0xd0,   h_integer_scaler,
247                         0xd1,   1,
248                         0xd2,   1,
249                         0xd8,   h_scaling_increment & 0xff,
250                         0xd9,   h_scaling_increment >> 8,
251                         0xdc,   (h_scaling_increment / 2) & 0xff,
252                         0xdd,   (h_scaling_increment / 2) >> 8,
253                         0xe0,   v_scaling_increment & 0xff,
254                         0xe1,   v_scaling_increment >> 8,
255                         0xe2,   v_scaling_increment & 0xff,
256                         0xe3,   v_scaling_increment >> 8,
257                         0x88,   0xf0,
258                         0,      0,
259                 };
260                 write_regs(client, regs);
261                 break;
262         }
263         case VIDIOC_S_STD:
264         {
265                 v4l2_std_id *input = arg;
266                 u8 regs[] = {
267                         0x88,   0xc0,
268                         0x98,   *input & V4L2_STD_NTSC ? 0x12 : 0x16,
269                         0x9a,   *input & V4L2_STD_NTSC ? 0xf2 : 0x20,
270                         0x9b,   *input & V4L2_STD_NTSC ? 0x00 : 0x01,
271                         0xc8,   *input & V4L2_STD_NTSC ? 0x12 : 0x16,
272                         0xca,   *input & V4L2_STD_NTSC ? 0xf2 : 0x20,
273                         0xcb,   *input & V4L2_STD_NTSC ? 0x00 : 0x01,
274                         0x88,   0xf0,
275                         0x30,   *input & V4L2_STD_NTSC ? 0x66 : 0x00,
276                         0x31,   *input & V4L2_STD_NTSC ? 0x90 : 0xe0,
277                         0,      0,
278                 };
279                 write_regs(client, regs);
280                 dec->norm = *input;
281                 break;
282         }
283         case VIDIOC_QUERYCTRL:
284         {
285                 struct v4l2_queryctrl *ctrl = arg;
286
287                 switch (ctrl->id) {
288                 case V4L2_CID_BRIGHTNESS:
289                         ctrl->type = V4L2_CTRL_TYPE_INTEGER;
290                         strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
291                         ctrl->minimum = 0;
292                         ctrl->maximum = 255;
293                         ctrl->step = 1;
294                         ctrl->default_value = 128;
295                         ctrl->flags = 0;
296                         break;
297                 case V4L2_CID_CONTRAST:
298                         ctrl->type = V4L2_CTRL_TYPE_INTEGER;
299                         strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
300                         ctrl->minimum = 0;
301                         ctrl->maximum = 127;
302                         ctrl->step = 1;
303                         ctrl->default_value = 64;
304                         ctrl->flags = 0;
305                         break;
306                 case V4L2_CID_SATURATION:
307                         ctrl->type = V4L2_CTRL_TYPE_INTEGER;
308                         strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
309                         ctrl->minimum = 0;
310                         ctrl->maximum = 127;
311                         ctrl->step = 1;
312                         ctrl->default_value = 64;
313                         ctrl->flags = 0;
314                         break;
315                 case V4L2_CID_HUE:
316                         ctrl->type = V4L2_CTRL_TYPE_INTEGER;
317                         strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
318                         ctrl->minimum = -128;
319                         ctrl->maximum = 127;
320                         ctrl->step = 1;
321                         ctrl->default_value = 0;
322                         ctrl->flags = 0;
323                         break;
324                 }
325                 break;
326         }
327         case VIDIOC_S_CTRL:
328         {
329                 struct v4l2_control *ctrl = arg;
330
331                 switch (ctrl->id) {
332                 case V4L2_CID_BRIGHTNESS:
333                         if (ctrl->value > 255)
334                                 dec->brightness = 255;
335                         else if (ctrl->value < 0)
336                                 dec->brightness = 0;
337                         else
338                                 dec->brightness = ctrl->value;
339                         write_reg(client, 0x0a, dec->brightness);
340                         break;
341                 case V4L2_CID_CONTRAST:
342                         if (ctrl->value > 127)
343                                 dec->contrast = 127;
344                         else if (ctrl->value < 0)
345                                 dec->contrast = 0;
346                         else
347                                 dec->contrast = ctrl->value;
348                         write_reg(client, 0x0b, dec->contrast);
349                         break;
350                 case V4L2_CID_SATURATION:
351                         if (ctrl->value > 127)
352                                 dec->saturation = 127;
353                         else if (ctrl->value < 0)
354                                 dec->saturation = 0;
355                         else
356                                 dec->saturation = ctrl->value;
357                         write_reg(client, 0x0c, dec->saturation);
358                         break;
359                 case V4L2_CID_HUE:
360                         if (ctrl->value > 127)
361                                 dec->hue = 127;
362                         else if (ctrl->value < -128)
363                                 dec->hue = -128;
364                         else
365                                 dec->hue = ctrl->value;
366                         write_reg(client, 0x0d, dec->hue);
367                         break;
368                 }
369                 break;
370         }
371         case VIDIOC_G_CTRL:
372         {
373                 struct v4l2_control *ctrl = arg;
374
375                 switch (ctrl->id) {
376                 case V4L2_CID_BRIGHTNESS:
377                         ctrl->value = dec->brightness;
378                         break;
379                 case V4L2_CID_CONTRAST:
380                         ctrl->value = dec->contrast;
381                         break;
382                 case V4L2_CID_SATURATION:
383                         ctrl->value = dec->saturation;
384                         break;
385                 case V4L2_CID_HUE:
386                         ctrl->value = dec->hue;
387                         break;
388                 }
389                 break;
390         }
391         default:
392                 break;
393         }
394         return 0;
395 }
396
397 static int wis_saa7115_probe(struct i2c_client *client,
398                              const struct i2c_device_id *id)
399 {
400         struct i2c_adapter *adapter = client->adapter;
401         struct wis_saa7115 *dec;
402
403         if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
404                 return -ENODEV;
405
406         dec = kmalloc(sizeof(struct wis_saa7115), GFP_KERNEL);
407         if (dec == NULL)
408                 return -ENOMEM;
409
410         dec->norm = V4L2_STD_NTSC;
411         dec->brightness = 128;
412         dec->contrast = 64;
413         dec->saturation = 64;
414         dec->hue = 0;
415         i2c_set_clientdata(client, dec);
416
417         printk(KERN_DEBUG
418                 "wis-saa7115: initializing SAA7115 at address %d on %s\n",
419                 client->addr, adapter->name);
420
421         if (write_regs(client, initial_registers) < 0) {
422                 printk(KERN_ERR
423                         "wis-saa7115: error initializing SAA7115\n");
424                 kfree(dec);
425                 return -ENODEV;
426         }
427
428         return 0;
429 }
430
431 static int wis_saa7115_remove(struct i2c_client *client)
432 {
433         struct wis_saa7115 *dec = i2c_get_clientdata(client);
434
435         i2c_set_clientdata(client, NULL);
436         kfree(dec);
437         return 0;
438 }
439
440 static struct i2c_device_id wis_saa7115_id[] = {
441         { "wis_saa7115", 0 },
442         { }
443 };
444
445 static 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
455 static int __init wis_saa7115_init(void)
456 {
457         return i2c_add_driver(&wis_saa7115_driver);
458 }
459
460 static void __exit wis_saa7115_cleanup(void)
461 {
462         i2c_del_driver(&wis_saa7115_driver);
463 }
464
465 module_init(wis_saa7115_init);
466 module_exit(wis_saa7115_cleanup);
467
468 MODULE_LICENSE("GPL v2");