Merge master.kernel.org:/pub/scm/linux/kernel/git/dtor/input
[linux-2.6] / drivers / usb / media / sn9c102_ov7630.c
1 /***************************************************************************
2  * Plug-in for OV7630 image sensor connected to the SN9C10x PC Camera      *
3  * Controllers                                                             *
4  *                                                                         *
5  * Copyright (C) 2005 by Luca Risolia <luca.risolia@studio.unibo.it>       *
6  *                                                                         *
7  * This program is free software; you can redistribute it and/or modify    *
8  * it under the terms of the GNU General Public License as published by    *
9  * the Free Software Foundation; either version 2 of the License, or       *
10  * (at your option) any later version.                                     *
11  *                                                                         *
12  * This program is distributed in the hope that it will be useful,         *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
15  * GNU General Public License for more details.                            *
16  *                                                                         *
17  * You should have received a copy of the GNU General Public License       *
18  * along with this program; if not, write to the Free Software             *
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
20  ***************************************************************************/
21
22 #include "sn9c102_sensor.h"
23
24
25 static struct sn9c102_sensor ov7630;
26
27
28 static int ov7630_init(struct sn9c102_device* cam)
29 {
30         int err = 0;
31
32         err += sn9c102_write_reg(cam, 0x00, 0x14);
33         err += sn9c102_write_reg(cam, 0x60, 0x17);
34         err += sn9c102_write_reg(cam, 0x0f, 0x18);
35         err += sn9c102_write_reg(cam, 0x50, 0x19);
36
37         err += sn9c102_i2c_write(cam, 0x12, 0x8d);
38         err += sn9c102_i2c_write(cam, 0x11, 0x00);
39         err += sn9c102_i2c_write(cam, 0x15, 0x34);
40         err += sn9c102_i2c_write(cam, 0x16, 0x03);
41         err += sn9c102_i2c_write(cam, 0x17, 0x1c);
42         err += sn9c102_i2c_write(cam, 0x18, 0xbd);
43         err += sn9c102_i2c_write(cam, 0x19, 0x06);
44         err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
45         err += sn9c102_i2c_write(cam, 0x1b, 0x04);
46         err += sn9c102_i2c_write(cam, 0x20, 0x44);
47         err += sn9c102_i2c_write(cam, 0x23, 0xee);
48         err += sn9c102_i2c_write(cam, 0x26, 0xa0);
49         err += sn9c102_i2c_write(cam, 0x27, 0x9a);
50         err += sn9c102_i2c_write(cam, 0x28, 0x20);
51         err += sn9c102_i2c_write(cam, 0x29, 0x30);
52         err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
53         err += sn9c102_i2c_write(cam, 0x30, 0x24);
54         err += sn9c102_i2c_write(cam, 0x32, 0x86);
55         err += sn9c102_i2c_write(cam, 0x60, 0xa9);
56         err += sn9c102_i2c_write(cam, 0x61, 0x42);
57         err += sn9c102_i2c_write(cam, 0x65, 0x00);
58         err += sn9c102_i2c_write(cam, 0x69, 0x38);
59         err += sn9c102_i2c_write(cam, 0x6f, 0x88);
60         err += sn9c102_i2c_write(cam, 0x70, 0x0b);
61         err += sn9c102_i2c_write(cam, 0x71, 0x00);
62         err += sn9c102_i2c_write(cam, 0x74, 0x21);
63         err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
64
65         return err;
66 }
67
68
69 static int ov7630_set_ctrl(struct sn9c102_device* cam,
70                            const struct v4l2_control* ctrl)
71 {
72         int err = 0;
73
74         switch (ctrl->id) {
75         case V4L2_CID_EXPOSURE:
76                 err += sn9c102_i2c_write(cam, 0x10, ctrl->value >> 2);
77                 err += sn9c102_i2c_write(cam, 0x76, ctrl->value & 0x03);
78                 break;
79         case V4L2_CID_RED_BALANCE:
80                 err += sn9c102_i2c_write(cam, 0x02, ctrl->value);
81                 break;
82         case V4L2_CID_BLUE_BALANCE:
83                 err += sn9c102_i2c_write(cam, 0x03, ctrl->value);
84                 break;
85         case V4L2_CID_GAIN:
86                 err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
87                 break;
88         case V4L2_CID_CONTRAST:
89                 err += ctrl->value ? sn9c102_i2c_write(cam, 0x05,
90                                                        (ctrl->value-1) | 0x20)
91                                    : sn9c102_i2c_write(cam, 0x05, 0x00);
92                 break;
93         case V4L2_CID_BRIGHTNESS:
94                 err += sn9c102_i2c_write(cam, 0x06, ctrl->value);
95                 break;
96         case V4L2_CID_SATURATION:
97                 err += sn9c102_i2c_write(cam, 0x03, ctrl->value << 4);
98                 break;
99         case V4L2_CID_HUE:
100                 err += ctrl->value ? sn9c102_i2c_write(cam, 0x04,
101                                                        (ctrl->value-1) | 0x20)
102                                    : sn9c102_i2c_write(cam, 0x04, 0x00);
103                 break;
104         case V4L2_CID_DO_WHITE_BALANCE:
105                 err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
106                 break;
107         case V4L2_CID_WHITENESS:
108                 err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
109                 break;
110         case V4L2_CID_AUTO_WHITE_BALANCE:
111                 err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x09);
112                 break;
113         case V4L2_CID_AUTOGAIN:
114                 err += sn9c102_i2c_write(cam, 0x13, ctrl->value);
115                 break;
116         case V4L2_CID_VFLIP:
117                 err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7));
118                 break;
119         case V4L2_CID_BLACK_LEVEL:
120                 err += sn9c102_i2c_write(cam, 0x25, ctrl->value);
121                 break;
122         case SN9C102_V4L2_CID_BRIGHT_LEVEL:
123                 err += sn9c102_i2c_write(cam, 0x24, ctrl->value);
124                 break;
125         case SN9C102_V4L2_CID_GAMMA:
126                 err += sn9c102_i2c_write(cam, 0x14, (ctrl->value << 2) | 0x80);
127                 break;
128         case SN9C102_V4L2_CID_BAND_FILTER:
129                 err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2);
130                 break;
131         default:
132                 return -EINVAL;
133         }
134
135         return err ? -EIO : 0;
136 }
137
138
139 static int ov7630_set_crop(struct sn9c102_device* cam,
140                            const struct v4l2_rect* rect)
141 {
142         struct sn9c102_sensor* s = &ov7630;
143         int err = 0;
144         u8 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
145
146         err += sn9c102_write_reg(cam, v_start, 0x13);
147
148         return err;
149 }
150
151
152 static int ov7630_set_pix_format(struct sn9c102_device* cam,
153                                  const struct v4l2_pix_format* pix)
154 {
155         int err = 0;
156
157         if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
158                 err += sn9c102_write_reg(cam, 0x20, 0x19);
159         else
160                 err += sn9c102_write_reg(cam, 0x50, 0x19);
161
162         return err;
163 }
164
165
166 static struct sn9c102_sensor ov7630 = {
167         .name = "OV7630",
168         .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
169         .sysfs_ops = SN9C102_I2C_WRITE,
170         .frequency = SN9C102_I2C_100KHZ,
171         .interface = SN9C102_I2C_2WIRES,
172         .i2c_slave_id = 0x21,
173         .init = &ov7630_init,
174         .qctrl = {
175                 {
176                         .id = V4L2_CID_GAIN,
177                         .type = V4L2_CTRL_TYPE_INTEGER,
178                         .name = "global gain",
179                         .minimum = 0x00,
180                         .maximum = 0x3f,
181                         .step = 0x01,
182                         .default_value = 0x14,
183                         .flags = 0,
184                 },
185                 {
186                         .id = V4L2_CID_HUE,
187                         .type = V4L2_CTRL_TYPE_INTEGER,
188                         .name = "hue",
189                         .minimum = 0x00,
190                         .maximum = 0x1f+1,
191                         .step = 0x01,
192                         .default_value = 0x00,
193                         .flags = 0,
194                 },
195                 {
196                         .id = V4L2_CID_SATURATION,
197                         .type = V4L2_CTRL_TYPE_INTEGER,
198                         .name = "saturation",
199                         .minimum = 0x00,
200                         .maximum = 0x0f,
201                         .step = 0x01,
202                         .default_value = 0x08,
203                         .flags = 0,
204                 },
205                 {
206                         .id = V4L2_CID_CONTRAST,
207                         .type = V4L2_CTRL_TYPE_INTEGER,
208                         .name = "contrast",
209                         .minimum = 0x00,
210                         .maximum = 0x1f+1,
211                         .step = 0x01,
212                         .default_value = 0x00,
213                         .flags = 0,
214                 },
215                 {
216                         .id = V4L2_CID_EXPOSURE,
217                         .type = V4L2_CTRL_TYPE_INTEGER,
218                         .name = "exposure",
219                         .minimum = 0x000,
220                         .maximum = 0x3ff,
221                         .step = 0x001,
222                         .default_value = 0x83<<2,
223                         .flags = 0,
224                 },
225                 {
226                         .id = V4L2_CID_RED_BALANCE,
227                         .type = V4L2_CTRL_TYPE_INTEGER,
228                         .name = "red balance",
229                         .minimum = 0x00,
230                         .maximum = 0xff,
231                         .step = 0x01,
232                         .default_value = 0x3a,
233                         .flags = 0,
234                 },
235                 {
236                         .id = V4L2_CID_BLUE_BALANCE,
237                         .type = V4L2_CTRL_TYPE_INTEGER,
238                         .name = "blue balance",
239                         .minimum = 0x00,
240                         .maximum = 0xff,
241                         .step = 0x01,
242                         .default_value = 0x77,
243                         .flags = 0,
244                 },
245                 {
246                         .id = V4L2_CID_BRIGHTNESS,
247                         .type = V4L2_CTRL_TYPE_INTEGER,
248                         .name = "brightness",
249                         .minimum = 0x00,
250                         .maximum = 0xff,
251                         .step = 0x01,
252                         .default_value = 0xa0,
253                         .flags = 0,
254                 },
255                 {
256                         .id = V4L2_CID_DO_WHITE_BALANCE,
257                         .type = V4L2_CTRL_TYPE_INTEGER,
258                         .name = "white balance background: blue",
259                         .minimum = 0x00,
260                         .maximum = 0x3f,
261                         .step = 0x01,
262                         .default_value = 0x20,
263                         .flags = 0,
264                 },
265                 {
266                         .id = V4L2_CID_WHITENESS,
267                         .type = V4L2_CTRL_TYPE_INTEGER,
268                         .name = "white balance background: red",
269                         .minimum = 0x00,
270                         .maximum = 0x3f,
271                         .step = 0x01,
272                         .default_value = 0x20,
273                         .flags = 0,
274                 },
275                 {
276                         .id = V4L2_CID_AUTO_WHITE_BALANCE,
277                         .type = V4L2_CTRL_TYPE_BOOLEAN,
278                         .name = "auto white balance",
279                         .minimum = 0x00,
280                         .maximum = 0x01,
281                         .step = 0x01,
282                         .default_value = 0x01,
283                         .flags = 0,
284                 },
285                 {
286                         .id = V4L2_CID_AUTOGAIN,
287                         .type = V4L2_CTRL_TYPE_INTEGER,
288                         .name = "gain & exposure mode",
289                         .minimum = 0x00,
290                         .maximum = 0x03,
291                         .step = 0x01,
292                         .default_value = 0x00,
293                         .flags = 0,
294                 },
295                 {
296                         .id = V4L2_CID_VFLIP,
297                         .type = V4L2_CTRL_TYPE_BOOLEAN,
298                         .name = "vertical flip",
299                         .minimum = 0x00,
300                         .maximum = 0x01,
301                         .step = 0x01,
302                         .default_value = 0x01,
303                         .flags = 0,
304                 },
305                 {
306                         .id = V4L2_CID_BLACK_LEVEL,
307                         .type = V4L2_CTRL_TYPE_INTEGER,
308                         .name = "black pixel ratio",
309                         .minimum = 0x01,
310                         .maximum = 0x9a,
311                         .step = 0x01,
312                         .default_value = 0x8a,
313                         .flags = 0,
314                 },
315                 {
316                         .id = SN9C102_V4L2_CID_BRIGHT_LEVEL,
317                         .type = V4L2_CTRL_TYPE_INTEGER,
318                         .name = "bright pixel ratio",
319                         .minimum = 0x01,
320                         .maximum = 0x9a,
321                         .step = 0x01,
322                         .default_value = 0x10,
323                         .flags = 0,
324                 },
325                 {
326                         .id = SN9C102_V4L2_CID_BAND_FILTER,
327                         .type = V4L2_CTRL_TYPE_BOOLEAN,
328                         .name = "band filter",
329                         .minimum = 0x00,
330                         .maximum = 0x01,
331                         .step = 0x01,
332                         .default_value = 0x00,
333                         .flags = 0,
334                 },
335                 {
336                         .id = SN9C102_V4L2_CID_GAMMA,
337                         .type = V4L2_CTRL_TYPE_BOOLEAN,
338                         .name = "rgb gamma",
339                         .minimum = 0x00,
340                         .maximum = 0x01,
341                         .step = 0x01,
342                         .default_value = 0x00,
343                         .flags = 0,
344                 },
345         },
346         .set_ctrl = &ov7630_set_ctrl,
347         .cropcap = {
348                 .bounds = {
349                         .left = 0,
350                         .top = 0,
351                         .width = 640,
352                         .height = 480,
353                 },
354                 .defrect = {
355                         .left = 0,
356                         .top = 0,
357                         .width = 640,
358                         .height = 480,
359                 },
360         },
361         .set_crop = &ov7630_set_crop,
362         .pix_format = {
363                 .width = 640,
364                 .height = 480,
365                 .pixelformat = V4L2_PIX_FMT_SBGGR8,
366                 .priv = 8,
367         },
368         .set_pix_format = &ov7630_set_pix_format
369 };
370
371
372 int sn9c102_probe_ov7630(struct sn9c102_device* cam)
373 {
374         int err = 0;
375
376         sn9c102_attach_sensor(cam, &ov7630);
377
378         if (le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x608f &&
379             le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602c)
380                 return -ENODEV;
381
382         err += sn9c102_write_reg(cam, 0x01, 0x01);
383         err += sn9c102_write_reg(cam, 0x00, 0x01);
384         err += sn9c102_write_reg(cam, 0x28, 0x17);
385
386         if (err)
387                 return -EIO;
388
389         err += sn9c102_i2c_write(cam, 0x0b, 0);
390         if (err)
391                 return -ENODEV;
392
393         return 0;
394 }