]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/media/video/sn9c102/sn9c102_ov7630.c
Merge branch 'linus' of master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa
[linux-2.6-omap-h63xx.git] / drivers / media / video / sn9c102 / sn9c102_ov7630.c
1 /***************************************************************************
2  * Plug-in for OV7630 image sensor connected to the SN9C1xx PC Camera      *
3  * Controllers                                                             *
4  *                                                                         *
5  * Copyright (C) 2006-2007 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 int ov7630_init(struct sn9c102_device* cam)
26 {
27         int err = 0;
28
29         switch (sn9c102_get_bridge(cam)) {
30         case BRIDGE_SN9C101:
31         case BRIDGE_SN9C102:
32                 err = sn9c102_write_const_regs(cam, {0x00, 0x14}, {0x60, 0x17},
33                                                {0x0f, 0x18}, {0x50, 0x19});
34
35                 err += sn9c102_i2c_write(cam, 0x12, 0x8d);
36                 err += sn9c102_i2c_write(cam, 0x12, 0x0d);
37                 err += sn9c102_i2c_write(cam, 0x11, 0x00);
38                 err += sn9c102_i2c_write(cam, 0x15, 0x35);
39                 err += sn9c102_i2c_write(cam, 0x16, 0x03);
40                 err += sn9c102_i2c_write(cam, 0x17, 0x1c);
41                 err += sn9c102_i2c_write(cam, 0x18, 0xbd);
42                 err += sn9c102_i2c_write(cam, 0x19, 0x06);
43                 err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
44                 err += sn9c102_i2c_write(cam, 0x1b, 0x04);
45                 err += sn9c102_i2c_write(cam, 0x20, 0x44);
46                 err += sn9c102_i2c_write(cam, 0x23, 0xee);
47                 err += sn9c102_i2c_write(cam, 0x26, 0xa0);
48                 err += sn9c102_i2c_write(cam, 0x27, 0x9a);
49                 err += sn9c102_i2c_write(cam, 0x28, 0x20);
50                 err += sn9c102_i2c_write(cam, 0x29, 0x30);
51                 err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
52                 err += sn9c102_i2c_write(cam, 0x30, 0x24);
53                 err += sn9c102_i2c_write(cam, 0x32, 0x86);
54                 err += sn9c102_i2c_write(cam, 0x60, 0xa9);
55                 err += sn9c102_i2c_write(cam, 0x61, 0x42);
56                 err += sn9c102_i2c_write(cam, 0x65, 0x00);
57                 err += sn9c102_i2c_write(cam, 0x69, 0x38);
58                 err += sn9c102_i2c_write(cam, 0x6f, 0x88);
59                 err += sn9c102_i2c_write(cam, 0x70, 0x0b);
60                 err += sn9c102_i2c_write(cam, 0x71, 0x00);
61                 err += sn9c102_i2c_write(cam, 0x74, 0x21);
62                 err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
63                 break;
64         case BRIDGE_SN9C103:
65                 err = sn9c102_write_const_regs(cam, {0x00, 0x02}, {0x00, 0x03},
66                                                {0x1a, 0x04}, {0x20, 0x05},
67                                                {0x20, 0x06}, {0x20, 0x07},
68                                                {0x03, 0x10}, {0x0a, 0x14},
69                                                {0x60, 0x17}, {0x0f, 0x18},
70                                                {0x50, 0x19}, {0x1d, 0x1a},
71                                                {0x10, 0x1b}, {0x02, 0x1c},
72                                                {0x03, 0x1d}, {0x0f, 0x1e},
73                                                {0x0c, 0x1f}, {0x00, 0x20},
74                                                {0x10, 0x21}, {0x20, 0x22},
75                                                {0x30, 0x23}, {0x40, 0x24},
76                                                {0x50, 0x25}, {0x60, 0x26},
77                                                {0x70, 0x27}, {0x80, 0x28},
78                                                {0x90, 0x29}, {0xa0, 0x2a},
79                                                {0xb0, 0x2b}, {0xc0, 0x2c},
80                                                {0xd0, 0x2d}, {0xe0, 0x2e},
81                                                {0xf0, 0x2f}, {0xff, 0x30});
82
83                 err += sn9c102_i2c_write(cam, 0x12, 0x8d);
84                 err += sn9c102_i2c_write(cam, 0x12, 0x0d);
85                 err += sn9c102_i2c_write(cam, 0x15, 0x34);
86                 err += sn9c102_i2c_write(cam, 0x11, 0x01);
87                 err += sn9c102_i2c_write(cam, 0x1b, 0x04);
88                 err += sn9c102_i2c_write(cam, 0x20, 0x44);
89                 err += sn9c102_i2c_write(cam, 0x23, 0xee);
90                 err += sn9c102_i2c_write(cam, 0x26, 0xa0);
91                 err += sn9c102_i2c_write(cam, 0x27, 0x9a);
92                 err += sn9c102_i2c_write(cam, 0x28, 0x20);
93                 err += sn9c102_i2c_write(cam, 0x29, 0x30);
94                 err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
95                 err += sn9c102_i2c_write(cam, 0x30, 0x24);
96                 err += sn9c102_i2c_write(cam, 0x32, 0x86);
97                 err += sn9c102_i2c_write(cam, 0x60, 0xa9);
98                 err += sn9c102_i2c_write(cam, 0x61, 0x42);
99                 err += sn9c102_i2c_write(cam, 0x65, 0x00);
100                 err += sn9c102_i2c_write(cam, 0x69, 0x38);
101                 err += sn9c102_i2c_write(cam, 0x6f, 0x88);
102                 err += sn9c102_i2c_write(cam, 0x70, 0x0b);
103                 err += sn9c102_i2c_write(cam, 0x71, 0x00);
104                 err += sn9c102_i2c_write(cam, 0x74, 0x21);
105                 err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
106                 break;
107         default:
108                 break;
109         }
110
111         return err;
112 }
113
114
115 static int ov7630_get_ctrl(struct sn9c102_device* cam,
116                            struct v4l2_control* ctrl)
117 {
118         int err = 0;
119
120         switch (ctrl->id) {
121         case V4L2_CID_EXPOSURE:
122                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
123                         return -EIO;
124                 break;
125         case V4L2_CID_RED_BALANCE:
126                 ctrl->value = sn9c102_pread_reg(cam, 0x07);
127                 break;
128         case V4L2_CID_BLUE_BALANCE:
129                 ctrl->value = sn9c102_pread_reg(cam, 0x06);
130                 break;
131         case SN9C102_V4L2_CID_GREEN_BALANCE:
132                 ctrl->value = sn9c102_pread_reg(cam, 0x05);
133                 break;
134         case V4L2_CID_GAIN:
135                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0)
136                         return -EIO;
137                 ctrl->value &= 0x3f;
138                 break;
139         case V4L2_CID_DO_WHITE_BALANCE:
140                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
141                         return -EIO;
142                 ctrl->value &= 0x3f;
143                 break;
144         case V4L2_CID_WHITENESS:
145                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x0d)) < 0)
146                         return -EIO;
147                 ctrl->value &= 0x3f;
148                 break;
149         case V4L2_CID_AUTOGAIN:
150                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0)
151                         return -EIO;
152                 ctrl->value &= 0x01;
153                 break;
154         case V4L2_CID_VFLIP:
155                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x75)) < 0)
156                         return -EIO;
157                 ctrl->value = (ctrl->value & 0x80) ? 1 : 0;
158                 break;
159         case SN9C102_V4L2_CID_GAMMA:
160                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x14)) < 0)
161                         return -EIO;
162                 ctrl->value = (ctrl->value & 0x02) ? 1 : 0;
163                 break;
164         case SN9C102_V4L2_CID_BAND_FILTER:
165                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x2d)) < 0)
166                         return -EIO;
167                 ctrl->value = (ctrl->value & 0x02) ? 1 : 0;
168                 break;
169         default:
170                 return -EINVAL;
171         }
172
173         return err ? -EIO : 0;
174 }
175
176
177 static int ov7630_set_ctrl(struct sn9c102_device* cam,
178                            const struct v4l2_control* ctrl)
179 {
180         int err = 0;
181
182         switch (ctrl->id) {
183         case V4L2_CID_EXPOSURE:
184                 err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
185                 break;
186         case V4L2_CID_RED_BALANCE:
187                 err += sn9c102_write_reg(cam, ctrl->value, 0x07);
188                 break;
189         case V4L2_CID_BLUE_BALANCE:
190                 err += sn9c102_write_reg(cam, ctrl->value, 0x06);
191                 break;
192         case SN9C102_V4L2_CID_GREEN_BALANCE:
193                 err += sn9c102_write_reg(cam, ctrl->value, 0x05);
194                 break;
195         case V4L2_CID_GAIN:
196                 err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
197                 break;
198         case V4L2_CID_DO_WHITE_BALANCE:
199                 err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
200                 break;
201         case V4L2_CID_WHITENESS:
202                 err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
203                 break;
204         case V4L2_CID_AUTOGAIN:
205                 err += sn9c102_i2c_write(cam, 0x13, ctrl->value |
206                                                     (ctrl->value << 1));
207                 break;
208         case V4L2_CID_VFLIP:
209                 err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7));
210                 break;
211         case SN9C102_V4L2_CID_GAMMA:
212                 err += sn9c102_i2c_write(cam, 0x14, ctrl->value << 2);
213                 break;
214         case SN9C102_V4L2_CID_BAND_FILTER:
215                 err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2);
216                 break;
217         default:
218                 return -EINVAL;
219         }
220
221         return err ? -EIO : 0;
222 }
223
224
225 static int ov7630_set_crop(struct sn9c102_device* cam,
226                            const struct v4l2_rect* rect)
227 {
228         struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
229         int err = 0;
230         u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
231            v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
232
233         err += sn9c102_write_reg(cam, h_start, 0x12);
234         err += sn9c102_write_reg(cam, v_start, 0x13);
235
236         return err;
237 }
238
239
240 static int ov7630_set_pix_format(struct sn9c102_device* cam,
241                                  const struct v4l2_pix_format* pix)
242 {
243         int err = 0;
244
245         if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
246                 err += sn9c102_write_reg(cam, 0x20, 0x19);
247         else
248                 err += sn9c102_write_reg(cam, 0x50, 0x19);
249
250         return err;
251 }
252
253
254 static const struct sn9c102_sensor ov7630 = {
255         .name = "OV7630",
256         .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
257         .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
258         .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
259         .frequency = SN9C102_I2C_100KHZ,
260         .interface = SN9C102_I2C_2WIRES,
261         .i2c_slave_id = 0x21,
262         .init = &ov7630_init,
263         .qctrl = {
264                 {
265                         .id = V4L2_CID_GAIN,
266                         .type = V4L2_CTRL_TYPE_INTEGER,
267                         .name = "global gain",
268                         .minimum = 0x00,
269                         .maximum = 0x3f,
270                         .step = 0x01,
271                         .default_value = 0x14,
272                         .flags = 0,
273                 },
274                 {
275                         .id = V4L2_CID_EXPOSURE,
276                         .type = V4L2_CTRL_TYPE_INTEGER,
277                         .name = "exposure",
278                         .minimum = 0x00,
279                         .maximum = 0xff,
280                         .step = 0x01,
281                         .default_value = 0x60,
282                         .flags = 0,
283                 },
284                 {
285                         .id = V4L2_CID_WHITENESS,
286                         .type = V4L2_CTRL_TYPE_INTEGER,
287                         .name = "white balance background: red",
288                         .minimum = 0x00,
289                         .maximum = 0x3f,
290                         .step = 0x01,
291                         .default_value = 0x20,
292                         .flags = 0,
293                 },
294                 {
295                         .id = V4L2_CID_DO_WHITE_BALANCE,
296                         .type = V4L2_CTRL_TYPE_INTEGER,
297                         .name = "white balance background: blue",
298                         .minimum = 0x00,
299                         .maximum = 0x3f,
300                         .step = 0x01,
301                         .default_value = 0x20,
302                         .flags = 0,
303                 },
304                 {
305                         .id = V4L2_CID_RED_BALANCE,
306                         .type = V4L2_CTRL_TYPE_INTEGER,
307                         .name = "red balance",
308                         .minimum = 0x00,
309                         .maximum = 0x7f,
310                         .step = 0x01,
311                         .default_value = 0x20,
312                         .flags = 0,
313                 },
314                 {
315                         .id = V4L2_CID_BLUE_BALANCE,
316                         .type = V4L2_CTRL_TYPE_INTEGER,
317                         .name = "blue balance",
318                         .minimum = 0x00,
319                         .maximum = 0x7f,
320                         .step = 0x01,
321                         .default_value = 0x20,
322                         .flags = 0,
323                 },
324                 {
325                         .id = V4L2_CID_AUTOGAIN,
326                         .type = V4L2_CTRL_TYPE_BOOLEAN,
327                         .name = "auto adjust",
328                         .minimum = 0x00,
329                         .maximum = 0x01,
330                         .step = 0x01,
331                         .default_value = 0x00,
332                         .flags = 0,
333                 },
334                 {
335                         .id = V4L2_CID_VFLIP,
336                         .type = V4L2_CTRL_TYPE_BOOLEAN,
337                         .name = "vertical flip",
338                         .minimum = 0x00,
339                         .maximum = 0x01,
340                         .step = 0x01,
341                         .default_value = 0x01,
342                         .flags = 0,
343                 },
344                 {
345                         .id = SN9C102_V4L2_CID_GREEN_BALANCE,
346                         .type = V4L2_CTRL_TYPE_INTEGER,
347                         .name = "green balance",
348                         .minimum = 0x00,
349                         .maximum = 0x7f,
350                         .step = 0x01,
351                         .default_value = 0x20,
352                         .flags = 0,
353                 },
354                 {
355                         .id = SN9C102_V4L2_CID_BAND_FILTER,
356                         .type = V4L2_CTRL_TYPE_BOOLEAN,
357                         .name = "band filter",
358                         .minimum = 0x00,
359                         .maximum = 0x01,
360                         .step = 0x01,
361                         .default_value = 0x00,
362                         .flags = 0,
363                 },
364                 {
365                         .id = SN9C102_V4L2_CID_GAMMA,
366                         .type = V4L2_CTRL_TYPE_BOOLEAN,
367                         .name = "rgb gamma",
368                         .minimum = 0x00,
369                         .maximum = 0x01,
370                         .step = 0x01,
371                         .default_value = 0x00,
372                         .flags = 0,
373                 },
374         },
375         .get_ctrl = &ov7630_get_ctrl,
376         .set_ctrl = &ov7630_set_ctrl,
377         .cropcap = {
378                 .bounds = {
379                         .left = 0,
380                         .top = 0,
381                         .width = 640,
382                         .height = 480,
383                 },
384                 .defrect = {
385                         .left = 0,
386                         .top = 0,
387                         .width = 640,
388                         .height = 480,
389                 },
390         },
391         .set_crop = &ov7630_set_crop,
392         .pix_format = {
393                 .width = 640,
394                 .height = 480,
395                 .pixelformat = V4L2_PIX_FMT_SN9C10X,
396                 .priv = 8,
397         },
398         .set_pix_format = &ov7630_set_pix_format
399 };
400
401
402 int sn9c102_probe_ov7630(struct sn9c102_device* cam)
403 {
404         int pid, ver, err = 0;
405
406         switch (sn9c102_get_bridge(cam)) {
407         case BRIDGE_SN9C101:
408         case BRIDGE_SN9C102:
409                 err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01},
410                                                {0x28, 0x17});
411                 break;
412         case BRIDGE_SN9C103: /* do _not_ change anything! */
413                 err = sn9c102_write_const_regs(cam, {0x09, 0x01}, {0x42, 0x01},
414                                                {0x28, 0x17}, {0x44, 0x02});
415                 pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a);
416                 if (err || pid < 0) /* try a different initialization */
417                         err += sn9c102_write_const_regs(cam, {0x01, 0x01},
418                                                         {0x00, 0x01});
419                 break;
420         default:
421                 break;
422         }
423
424         pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a);
425         ver = sn9c102_i2c_try_read(cam, &ov7630, 0x0b);
426         if (err || pid < 0 || ver < 0)
427                 return -EIO;
428         if (pid != 0x76 || ver != 0x31)
429                 return -ENODEV;
430         sn9c102_attach_sensor(cam, &ov7630);
431
432         return 0;
433 }