Merge branch 'upstream'
[linux-2.6] / drivers / media / video / sn9c102 / sn9c102_ov7630.c
1 /***************************************************************************
2  * Plug-in for OV7630 image sensor connected to the SN9C10x PC Camera      *
3  * Controllers                                                             *
4  *                                                                         *
5  * Copyright (C) 2005-2006 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, 0x80);
38         err += sn9c102_i2c_write(cam, 0x11, 0x01);
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, 0xf6);
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, 0xa0);
51         err += sn9c102_i2c_write(cam, 0x29, 0x30);
52         err += sn9c102_i2c_write(cam, 0x2a, 0xa0);
53         err += sn9c102_i2c_write(cam, 0x2b, 0x1f);
54         err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
55         err += sn9c102_i2c_write(cam, 0x30, 0x24);
56         err += sn9c102_i2c_write(cam, 0x32, 0x86);
57         err += sn9c102_i2c_write(cam, 0x60, 0xa9);
58         err += sn9c102_i2c_write(cam, 0x61, 0x42);
59         err += sn9c102_i2c_write(cam, 0x65, 0x00);
60         err += sn9c102_i2c_write(cam, 0x69, 0x38);
61         err += sn9c102_i2c_write(cam, 0x6f, 0x88);
62         err += sn9c102_i2c_write(cam, 0x70, 0x0b);
63         err += sn9c102_i2c_write(cam, 0x71, 0x00);
64         err += sn9c102_i2c_write(cam, 0x74, 0x21);
65         err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
66
67         return err;
68 }
69
70
71 static int ov7630_set_ctrl(struct sn9c102_device* cam,
72                            const struct v4l2_control* ctrl)
73 {
74         int err = 0;
75
76         switch (ctrl->id) {
77         case V4L2_CID_EXPOSURE:
78                 err += sn9c102_i2c_write(cam, 0x10, ctrl->value >> 2);
79                 err += sn9c102_i2c_write(cam, 0x76, ctrl->value & 0x03);
80                 break;
81         case V4L2_CID_RED_BALANCE:
82                 err += sn9c102_i2c_write(cam, 0x02, ctrl->value);
83                 break;
84         case V4L2_CID_BLUE_BALANCE:
85                 err += sn9c102_i2c_write(cam, 0x01, ctrl->value);
86                 break;
87         case V4L2_CID_GAIN:
88                 err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
89                 break;
90         case V4L2_CID_CONTRAST:
91                 err += ctrl->value ? sn9c102_i2c_write(cam, 0x05,
92                                                        (ctrl->value-1) | 0x20)
93                                    : sn9c102_i2c_write(cam, 0x05, 0x00);
94                 break;
95         case V4L2_CID_BRIGHTNESS:
96                 err += sn9c102_i2c_write(cam, 0x06, ctrl->value);
97                 break;
98         case V4L2_CID_SATURATION:
99                 err += sn9c102_i2c_write(cam, 0x03, ctrl->value << 4);
100                 break;
101         case V4L2_CID_HUE:
102                 err += ctrl->value ? sn9c102_i2c_write(cam, 0x04,
103                                                        (ctrl->value-1) | 0x20)
104                                    : sn9c102_i2c_write(cam, 0x04, 0x00);
105                 break;
106         case V4L2_CID_DO_WHITE_BALANCE:
107                 err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
108                 break;
109         case V4L2_CID_WHITENESS:
110                 err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
111                 break;
112         case V4L2_CID_AUTO_WHITE_BALANCE:
113                 err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x78);
114                 break;
115         case V4L2_CID_AUTOGAIN:
116                 err += sn9c102_i2c_write(cam, 0x13, ctrl->value);
117                 break;
118         case V4L2_CID_VFLIP:
119                 err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7));
120                 break;
121         case V4L2_CID_BLACK_LEVEL:
122                 err += sn9c102_i2c_write(cam, 0x25, ctrl->value);
123                 break;
124         case SN9C102_V4L2_CID_BRIGHT_LEVEL:
125                 err += sn9c102_i2c_write(cam, 0x24, ctrl->value);
126                 break;
127         case SN9C102_V4L2_CID_GAMMA:
128                 err += sn9c102_i2c_write(cam, 0x14, (ctrl->value << 2) | 0x80);
129                 break;
130         case SN9C102_V4L2_CID_BAND_FILTER:
131                 err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2);
132                 break;
133         default:
134                 return -EINVAL;
135         }
136
137         return err ? -EIO : 0;
138 }
139
140
141 static int ov7630_set_crop(struct sn9c102_device* cam,
142                            const struct v4l2_rect* rect)
143 {
144         struct sn9c102_sensor* s = &ov7630;
145         int err = 0;
146         u8 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
147
148         err += sn9c102_write_reg(cam, v_start, 0x13);
149
150         return err;
151 }
152
153
154 static int ov7630_set_pix_format(struct sn9c102_device* cam,
155                                  const struct v4l2_pix_format* pix)
156 {
157         int err = 0;
158
159         if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
160                 err += sn9c102_write_reg(cam, 0x20, 0x19);
161         else
162                 err += sn9c102_write_reg(cam, 0x50, 0x19);
163
164         return err;
165 }
166
167
168 static struct sn9c102_sensor ov7630 = {
169         .name = "OV7630",
170         .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
171         .sysfs_ops = SN9C102_I2C_WRITE,
172         .frequency = SN9C102_I2C_100KHZ,
173         .interface = SN9C102_I2C_2WIRES,
174         .i2c_slave_id = 0x21,
175         .init = &ov7630_init,
176         .qctrl = {
177                 {
178                         .id = V4L2_CID_GAIN,
179                         .type = V4L2_CTRL_TYPE_INTEGER,
180                         .name = "global gain",
181                         .minimum = 0x00,
182                         .maximum = 0x3f,
183                         .step = 0x01,
184                         .default_value = 0x14,
185                         .flags = 0,
186                 },
187                 {
188                         .id = V4L2_CID_HUE,
189                         .type = V4L2_CTRL_TYPE_INTEGER,
190                         .name = "hue",
191                         .minimum = 0x00,
192                         .maximum = 0x1f+1,
193                         .step = 0x01,
194                         .default_value = 0x00,
195                         .flags = 0,
196                 },
197                 {
198                         .id = V4L2_CID_SATURATION,
199                         .type = V4L2_CTRL_TYPE_INTEGER,
200                         .name = "saturation",
201                         .minimum = 0x00,
202                         .maximum = 0x0f,
203                         .step = 0x01,
204                         .default_value = 0x08,
205                         .flags = 0,
206                 },
207                 {
208                         .id = V4L2_CID_CONTRAST,
209                         .type = V4L2_CTRL_TYPE_INTEGER,
210                         .name = "contrast",
211                         .minimum = 0x00,
212                         .maximum = 0x1f+1,
213                         .step = 0x01,
214                         .default_value = 0x00,
215                         .flags = 0,
216                 },
217                 {
218                         .id = V4L2_CID_EXPOSURE,
219                         .type = V4L2_CTRL_TYPE_INTEGER,
220                         .name = "exposure",
221                         .minimum = 0x000,
222                         .maximum = 0x3ff,
223                         .step = 0x001,
224                         .default_value = 0x83<<2,
225                         .flags = 0,
226                 },
227                 {
228                         .id = V4L2_CID_RED_BALANCE,
229                         .type = V4L2_CTRL_TYPE_INTEGER,
230                         .name = "red balance",
231                         .minimum = 0x00,
232                         .maximum = 0xff,
233                         .step = 0x01,
234                         .default_value = 0x3a,
235                         .flags = 0,
236                 },
237                 {
238                         .id = V4L2_CID_BLUE_BALANCE,
239                         .type = V4L2_CTRL_TYPE_INTEGER,
240                         .name = "blue balance",
241                         .minimum = 0x00,
242                         .maximum = 0xff,
243                         .step = 0x01,
244                         .default_value = 0x77,
245                         .flags = 0,
246                 },
247                 {
248                         .id = V4L2_CID_BRIGHTNESS,
249                         .type = V4L2_CTRL_TYPE_INTEGER,
250                         .name = "brightness",
251                         .minimum = 0x00,
252                         .maximum = 0xff,
253                         .step = 0x01,
254                         .default_value = 0xa0,
255                         .flags = 0,
256                 },
257                 {
258                         .id = V4L2_CID_DO_WHITE_BALANCE,
259                         .type = V4L2_CTRL_TYPE_INTEGER,
260                         .name = "white balance background: blue",
261                         .minimum = 0x00,
262                         .maximum = 0x3f,
263                         .step = 0x01,
264                         .default_value = 0x20,
265                         .flags = 0,
266                 },
267                 {
268                         .id = V4L2_CID_WHITENESS,
269                         .type = V4L2_CTRL_TYPE_INTEGER,
270                         .name = "white balance background: red",
271                         .minimum = 0x00,
272                         .maximum = 0x3f,
273                         .step = 0x01,
274                         .default_value = 0x20,
275                         .flags = 0,
276                 },
277                 {
278                         .id = V4L2_CID_AUTO_WHITE_BALANCE,
279                         .type = V4L2_CTRL_TYPE_BOOLEAN,
280                         .name = "auto white balance",
281                         .minimum = 0x00,
282                         .maximum = 0x01,
283                         .step = 0x01,
284                         .default_value = 0x01,
285                         .flags = 0,
286                 },
287                 {
288                         .id = V4L2_CID_AUTOGAIN,
289                         .type = V4L2_CTRL_TYPE_INTEGER,
290                         .name = "gain & exposure mode",
291                         .minimum = 0x00,
292                         .maximum = 0x03,
293                         .step = 0x01,
294                         .default_value = 0x00,
295                         .flags = 0,
296                 },
297                 {
298                         .id = V4L2_CID_VFLIP,
299                         .type = V4L2_CTRL_TYPE_BOOLEAN,
300                         .name = "vertical flip",
301                         .minimum = 0x00,
302                         .maximum = 0x01,
303                         .step = 0x01,
304                         .default_value = 0x01,
305                         .flags = 0,
306                 },
307                 {
308                         .id = V4L2_CID_BLACK_LEVEL,
309                         .type = V4L2_CTRL_TYPE_INTEGER,
310                         .name = "black pixel ratio",
311                         .minimum = 0x01,
312                         .maximum = 0x9a,
313                         .step = 0x01,
314                         .default_value = 0x8a,
315                         .flags = 0,
316                 },
317                 {
318                         .id = SN9C102_V4L2_CID_BRIGHT_LEVEL,
319                         .type = V4L2_CTRL_TYPE_INTEGER,
320                         .name = "bright pixel ratio",
321                         .minimum = 0x01,
322                         .maximum = 0x9a,
323                         .step = 0x01,
324                         .default_value = 0x10,
325                         .flags = 0,
326                 },
327                 {
328                         .id = SN9C102_V4L2_CID_BAND_FILTER,
329                         .type = V4L2_CTRL_TYPE_BOOLEAN,
330                         .name = "band filter",
331                         .minimum = 0x00,
332                         .maximum = 0x01,
333                         .step = 0x01,
334                         .default_value = 0x00,
335                         .flags = 0,
336                 },
337                 {
338                         .id = SN9C102_V4L2_CID_GAMMA,
339                         .type = V4L2_CTRL_TYPE_BOOLEAN,
340                         .name = "rgb gamma",
341                         .minimum = 0x00,
342                         .maximum = 0x01,
343                         .step = 0x01,
344                         .default_value = 0x00,
345                         .flags = 0,
346                 },
347         },
348         .set_ctrl = &ov7630_set_ctrl,
349         .cropcap = {
350                 .bounds = {
351                         .left = 0,
352                         .top = 0,
353                         .width = 640,
354                         .height = 480,
355                 },
356                 .defrect = {
357                         .left = 0,
358                         .top = 0,
359                         .width = 640,
360                         .height = 480,
361                 },
362         },
363         .set_crop = &ov7630_set_crop,
364         .pix_format = {
365                 .width = 640,
366                 .height = 480,
367                 .pixelformat = V4L2_PIX_FMT_SBGGR8,
368                 .priv = 8,
369         },
370         .set_pix_format = &ov7630_set_pix_format
371 };
372
373
374 int sn9c102_probe_ov7630(struct sn9c102_device* cam)
375 {
376         const struct usb_device_id ov7630_id_table[] = {
377                 { USB_DEVICE(0x0c45, 0x602c), },
378                 { USB_DEVICE(0x0c45, 0x602d), },
379                 { USB_DEVICE(0x0c45, 0x608f), },
380                 { USB_DEVICE(0x0c45, 0x60b0), },
381                 { }
382         };
383         int err = 0;
384
385         if (!sn9c102_match_id(cam, ov7630_id_table))
386                 return -ENODEV;
387
388         err += sn9c102_write_reg(cam, 0x01, 0x01);
389         err += sn9c102_write_reg(cam, 0x00, 0x01);
390         err += sn9c102_write_reg(cam, 0x28, 0x17);
391         if (err)
392                 return -EIO;
393
394         err += sn9c102_i2c_try_write(cam, &ov7630, 0x0b, 0);
395         if (err)
396                 return -ENODEV;
397
398         sn9c102_attach_sensor(cam, &ov7630);
399
400         return 0;
401 }