[PATCH] USB: Add ET61X[12]51 Video4Linux2 driver
[linux-2.6/mini2440.git] / drivers / usb / media / sn9c102_ov7630.c
blob4a36519b5af40f067c05d80c3c1310cd01a4d612
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 ***************************************************************************/
22 #include "sn9c102_sensor.h"
25 static struct sn9c102_sensor ov7630;
28 static int ov7630_init(struct sn9c102_device* cam)
30 int err = 0;
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);
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);
65 return err;
69 static int ov7630_set_ctrl(struct sn9c102_device* cam,
70 const struct v4l2_control* ctrl)
72 int err = 0;
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;
135 return err ? -EIO : 0;
139 static int ov7630_set_crop(struct sn9c102_device* cam,
140 const struct v4l2_rect* rect)
142 struct sn9c102_sensor* s = &ov7630;
143 int err = 0;
144 u8 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
146 err += sn9c102_write_reg(cam, v_start, 0x13);
148 return err;
152 static int ov7630_set_pix_format(struct sn9c102_device* cam,
153 const struct v4l2_pix_format* pix)
155 int err = 0;
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);
162 return err;
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 = {
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
346 .set_ctrl = &ov7630_set_ctrl,
347 .cropcap = {
348 .bounds = {
349 .left = 0,
350 .top = 0,
351 .width = 640,
352 .height = 480,
354 .defrect = {
355 .left = 0,
356 .top = 0,
357 .width = 640,
358 .height = 480,
361 .set_crop = &ov7630_set_crop,
362 .pix_format = {
363 .width = 640,
364 .height = 480,
365 .pixelformat = V4L2_PIX_FMT_SBGGR8,
366 .priv = 8,
368 .set_pix_format = &ov7630_set_pix_format
372 int sn9c102_probe_ov7630(struct sn9c102_device* cam)
374 int err = 0;
376 sn9c102_attach_sensor(cam, &ov7630);
378 if (le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602c &&
379 le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602d &&
380 le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x608f &&
381 le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x60b0)
382 return -ENODEV;
384 err += sn9c102_write_reg(cam, 0x01, 0x01);
385 err += sn9c102_write_reg(cam, 0x00, 0x01);
386 err += sn9c102_write_reg(cam, 0x28, 0x17);
388 if (err)
389 return -EIO;
391 err += sn9c102_i2c_write(cam, 0x0b, 0);
392 if (err)
393 return -ENODEV;
395 return 0;