Autogain and Autoexposure for most Omnivision sensors
[microdia.git] / microdia-dev.c
blobf5d86fa179c2d11ac7b0ef28835efad8e1ea4290
1 /**
2 * @file microdia-dev.c
3 * @author Nicolas VIVIEN
4 * @date 2008-02-01
6 * @brief Device specific functions
8 * @note Copyright (C) Nicolas VIVIEN
10 * @par Licences
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <linux/errno.h>
28 #include <linux/string.h>
29 #include <stdarg.h>
31 #include "microdia.h"
32 #include "sn9c20x.h"
33 #include "omnivision.h"
34 #include "micron.h"
36 static struct sensor_info sensors[] = {
38 .id = OV9650_SENSOR,
39 .name = "OV9650",
40 .address = 0x30,
41 .initialize = ov_initialize,
42 .hstart = 0,
43 .vstart = 7,
44 .set_hvflip = ov965x_set_hvflip,
45 .set_exposure = ov965x_set_exposure,
46 .set_auto_gain = ov_set_autogain,
47 .flip_detect = ov965x_flip_detect,
50 .id = OV9655_SENSOR,
51 .name = "OV9655",
52 .address = 0x30,
53 .initialize = ov_initialize,
54 .set_auto_exposure = ov_set_autoexposure,
55 .set_auto_gain = ov_set_autogain,
56 .hstart = 0,
57 .vstart = 7,
60 .id = SOI968_SENSOR,
61 .name = "SOI968",
62 .address = 0x30,
63 .initialize = ov_initialize,
64 .set_exposure = soi968_set_exposure,
65 .set_auto_exposure = ov_set_autoexposure,
66 .set_auto_gain = ov_set_autogain,
67 .hstart = 60,
68 .vstart = 11,
71 .id = OV7660_SENSOR,
72 .name = "OV7660",
73 .address = 0x21,
74 .initialize = ov_initialize,
75 .set_exposure = ov7660_set_exposure,
76 .set_auto_exposure = ov_set_autoexposure,
77 .set_auto_gain = ov_set_autogain,
78 .hstart = 1,
79 .vstart = 1,
82 .id = OV7670_SENSOR,
83 .name = "OV7670",
84 .address = 0x21,
85 .initialize = ov_initialize,
86 .set_auto_exposure = ov_set_autoexposure,
87 .set_auto_gain = ov_set_autogain,
88 .flip_detect = ov7670_flip_detect,
89 .hstart = 0,
90 .vstart = 1,
93 .id = MT9V111_SENSOR,
94 .name = "MT9V111",
95 .address = 0x5c,
96 .initialize = micron_initialize,
97 .set_hvflip = mt9v111_set_hvflip,
98 .set_exposure = mt9v111_set_exposure,
99 .set_auto_exposure = mt9v111_set_autoexposure,
100 .hstart = 2,
101 .vstart = 2,
104 .id = MT9M111_SENSOR,
105 .name = "MT9M111",
106 .address = 0x5d,
107 .initialize = micron_initialize,
108 .set_yuv422 = mt9m111_set_yuv422,
109 .set_bayer = mt9m111_set_raw,
110 .hstart = 6,
111 .vstart = 2,
114 .id = MT9V011_SENSOR,
115 .name = "MT9V011",
116 .address = 0x5d,
117 .initialize = micron_initialize,
118 .set_hvflip = mt9v011_set_hvflip,
119 .set_exposure = mt9v011_set_exposure,
120 .hstart = 2,
121 .vstart = 2,
124 .id = MT9M001_SENSOR,
125 .name = "MT9M001",
126 .address = 0x5d,
127 .initialize = micron_initialize,
128 .hstart = 2,
129 .vstart = 2,
133 static __u16 known_cams[][2] = {
134 {0x6240, MT9M001_SENSOR},
135 {0x6242, MT9M111_SENSOR},
136 {0x6248, OV9655_SENSOR},
137 {0x624e, SOI968_SENSOR},
138 {0x624f, OV9650_SENSOR},
139 {0x6253, OV9650_SENSOR},
140 {0x6260, OV7670_SENSOR},
141 {0x627b, OV7660_SENSOR},
142 {0x627f, OV9650_SENSOR},
143 {0x6288, OV9655_SENSOR},
144 {0x628e, SOI968_SENSOR},
145 {0x62a0, OV7670_SENSOR},
146 {0x62b3, OV9655_SENSOR},
147 {0x62bb, OV7660_SENSOR},
148 /* The following PIDs have VIDs different from 0x0c45. */
149 {0x00f4, OV9650_SENSOR},
150 {0x013d, OV7660_SENSOR},
153 int dev_microdia_assign_sensor(struct usb_microdia *dev)
155 int i, j, ret;
156 __u16 pid = le16_to_cpu(dev->udev->descriptor.idProduct);
158 for (i = 0; i < ARRAY_SIZE(known_cams); i++) {
159 if (pid == known_cams[i][0]) {
160 for (j = 0; j < ARRAY_SIZE(sensors); j++) {
161 if (known_cams[i][1] == sensors[j].id) {
162 dev->camera.sensor = &(sensors[j]);
163 return 0;
169 if ((pid == 0x6270) || (pid == 0x62b0)) {
170 ret = micron_probe(dev);
171 for (j = 0; j < ARRAY_SIZE(sensors); j++) {
172 if (ret == sensors[j].id) {
173 dev->camera.sensor = &(sensors[j]);
174 return 0;
179 UDIA_ERROR("Could not assign sensor: "
180 "Please report to microdia@googlegroups.com .\n");
182 return -EINVAL;
185 int dev_microdia_initialize_sensor(struct usb_microdia *dev)
187 int ret = -ENODEV;
188 if (dev && dev->camera.sensor->initialize)
189 ret = dev->camera.sensor->initialize(dev);
190 return ret;
193 static struct microdia_video_format default_fmts[] = {
195 .pix_fmt = V4L2_PIX_FMT_SBGGR8,
196 .desc = "Bayer 8bit (BGGR)",
197 .depth = 8,
198 .modes = {
199 {160, 120, SN9C20X_1_4_SCALE,
200 {0, 0, 640, 480},
201 {0, 0, 160, 120} },
202 {320, 240, SN9C20X_1_2_SCALE,
203 {0, 0, 640, 480},
204 {0, 0, 320, 240} },
205 {640, 480, SN9C20X_NO_SCALE,
206 {0, 0, 640, 480},
207 {0, 0, 640, 480} },
209 .set_format = sn9c20x_set_raw
212 .pix_fmt = V4L2_PIX_FMT_JPEG,
213 .desc = "JPEG (YUV 4:2:2)",
214 .depth = 16,
215 .modes = {
216 {160, 120, SN9C20X_1_4_SCALE,
217 {0, 0, 640, 480},
218 {0, 0, 160, 120} },
219 {320, 240, SN9C20X_1_2_SCALE,
220 {0, 0, 640, 480},
221 {0, 0, 320, 240} },
222 {640, 480, SN9C20X_NO_SCALE,
223 {0, 0, 640, 480},
224 {0, 0, 640, 480} },
226 .set_format = sn9c20x_set_jpeg
229 .pix_fmt = V4L2_PIX_FMT_YUYV,
230 .desc = "YUV 4:2:2 (YUYV)",
231 .depth = 16,
232 .modes = {
233 {160, 120, SN9C20X_1_4_SCALE,
234 {0, 0, 1280, 480},
235 {0, 0, 320, 120} },
236 {320, 240, SN9C20X_1_2_SCALE,
237 {0, 0, 1280, 480},
238 {0, 0, 640, 240} },
239 {640, 480, SN9C20X_NO_SCALE,
240 {0, 0, 1280, 480},
241 {0, 0, 1280, 480} },
243 .set_format = NULL
247 int dev_microdia_assign_fmts(struct usb_microdia *dev)
249 int i, j;
251 dev->camera.fmts = default_fmts;
252 dev->camera.nfmts = ARRAY_SIZE(default_fmts);
254 for (i = 0; i < ARRAY_SIZE(default_fmts); i++) {
255 if ((dev->camera.sensor->set_yuv422 != NULL) &&
256 (dev->camera.fmts[i].pix_fmt == V4L2_PIX_FMT_YUYV))
257 dev->camera.fmts[i].set_format =
258 dev->camera.sensor->set_yuv422;
259 if ((dev->camera.sensor->set_bayer != NULL) &&
260 (dev->camera.fmts[i].pix_fmt == V4L2_PIX_FMT_SBGGR8))
261 dev->camera.fmts[i].set_format =
262 dev->camera.sensor->set_bayer;
263 for (j = 0; j < N_MODES; j++) {
264 dev->camera.fmts[i].modes[j].hw_window[0] =
265 dev->camera.sensor->hstart;
266 dev->camera.fmts[i].modes[j].hw_window[1] =
267 dev->camera.sensor->vstart;
271 return 0;
275 * @brief Wrapper function for camera-setting functions
277 * @param dev Pointer to device structure
279 * @returns 0
281 int dev_microdia_camera_settings(struct usb_microdia *dev)
283 dev_microdia_camera_set_contrast(dev);
284 dev_microdia_camera_set_brightness(dev);
285 dev_microdia_camera_set_gamma(dev);
286 dev_microdia_camera_set_exposure(dev);
287 dev_microdia_camera_set_hvflip(dev);
288 dev_microdia_camera_set_sharpness(dev);
289 dev_microdia_camera_set_rgb_gain(dev);
290 dev_microdia_camera_set_auto_exposure(dev);
291 dev_microdia_camera_set_auto_gain(dev);
292 dev_microdia_camera_set_auto_whitebalance(dev);
293 return 0;
297 * @brief Wrapper function for device-specific contrast functions
299 * @param dev Pointer to device structure
301 * @returns 0 or negative error value
304 int dev_microdia_camera_set_contrast(struct usb_microdia *dev)
306 int ret = -ENODEV;
307 if (dev && dev->camera.set_contrast)
308 ret = dev->camera.set_contrast(dev);
309 return ret;
313 * @brief Wrapper function for device-specific brightness functions
315 * @param dev Pointer to device structure
317 * @returns 0 or negative error value
320 int dev_microdia_camera_set_brightness(struct usb_microdia *dev)
322 int ret = -ENODEV;
323 if (dev && dev->camera.set_brightness)
324 ret = dev->camera.set_brightness(dev);
325 return ret;
329 * @brief Wrapper function for device-specific gamma functions
331 * @param dev Pointer to device structure
333 * @returns 0 or negative error value
336 int dev_microdia_camera_set_gamma(struct usb_microdia *dev)
338 int ret = -ENODEV;
339 if (dev && dev->camera.set_gamma)
340 ret = dev->camera.set_gamma(dev);
341 return ret;
345 * @brief Wrapper function for device-specific exposure functions
347 * @param dev Pointer to device structure
349 * @returns 0 or negative error value
352 int dev_microdia_camera_set_exposure(struct usb_microdia *dev)
354 if (dev && dev->camera.sensor->set_exposure != NULL)
355 return dev->camera.sensor->set_exposure(dev);
357 return 0;
361 * @brief Wrapper function for device-specific hvflip functions
363 * @param dev Pointer to device structure
365 * @returns 0 or negative error value
368 int dev_microdia_camera_set_hvflip(struct usb_microdia *dev)
370 int ret = -ENODEV;
371 if (dev && dev->camera.sensor->set_hvflip)
372 ret = dev->camera.sensor->set_hvflip(dev);
374 return ret;
378 * @brief Wrapper function for device-specific sharpness functions
380 * @param dev Pointer to device structure
382 * @returns 0 or negative error value
385 int dev_microdia_camera_set_sharpness(struct usb_microdia *dev)
387 int ret = -ENODEV;
388 if (dev && dev->camera.set_sharpness)
389 ret = dev->camera.set_sharpness(dev);
391 return ret;
395 * @brief Wrapper function for device-specific rgb-gain functions
397 * @param dev Pointer to device structure
399 * @returns 0 or negative error value
402 int dev_microdia_camera_set_rgb_gain(struct usb_microdia *dev)
404 int ret = -ENODEV;
405 if (dev && dev->camera.set_rgb_gain)
406 ret = dev->camera.set_rgb_gain(dev);
408 return ret;
412 * @brief Wrapper function for device-specific auto-exposure functions
414 * @param dev Pointer to device structure
416 * @returns 0 or negative error value
419 int dev_microdia_camera_set_auto_exposure(struct usb_microdia *dev)
421 int ret = -ENODEV;
422 if (dev && dev->camera.sensor->set_auto_exposure)
423 ret = dev->camera.sensor->set_auto_exposure(dev);
425 return ret;
429 * @brief Wrapper function for device-specific auto-gain functions
431 * @param dev Pointer to device structure
433 * @returns 0 or negative error value
436 int dev_microdia_camera_set_auto_gain(struct usb_microdia *dev)
438 int ret = -ENODEV;
439 if (dev && dev->camera.sensor->set_auto_gain)
440 ret = dev->camera.sensor->set_auto_gain(dev);
442 return ret;
446 * @brief Wrapper function for device-specific auto-whitebalance functions
448 * @param dev Pointer to device structure
450 * @returns 0 or negative error value
453 int dev_microdia_camera_set_auto_whitebalance(struct usb_microdia *dev)
455 int ret = -ENODEV;
456 if (dev && dev->camera.sensor->set_auto_whitebalance)
457 ret = dev->camera.sensor->set_auto_whitebalance(dev);
459 return ret;
463 * @brief Wrapper function for device-specific initialization functions
465 * @param dev Pointer to device structure
466 * @param flags
468 * @returns 0 or negative error value
471 int dev_microdia_initialize_device(struct usb_microdia *dev, __u32 flags)
473 switch (flags >> 16) {
474 case (SN9C20X_BRIDGE >> 16):
475 UDIA_INFO("Detected SN9C20X Bridge\n");
476 return sn9c20x_initialize(dev);
477 default:
478 UDIA_INFO("Unsupported bridge\n");
480 return -ENODEV;
484 * @brief Wrapper function for for enable video stream for specific bridge
486 * @param dev Pointer to device structure
487 * @param enable Contains the wanted state
489 * @returns 0
492 int dev_microdia_enable_video(struct usb_microdia *dev, int enable)
494 int ret = -ENODEV;
495 if (dev && dev->camera.enable_video)
496 ret = dev->camera.enable_video(dev, enable);
498 return ret;