Removed ov7660_set_exposure
[microdia.git] / sn9c20x-dev.c
blobf73b0eef87107dcb23677d94bdc249be8d18df00
1 /**
2 * @file sn9c20x-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 "sn9c20x.h"
32 #include "sn9c20x-bridge.h"
33 #include "omnivision.h"
34 #include "micron.h"
36 int (*sn_probes[])(struct usb_sn9c20x *dev) = {
37 mt9v011_probe,
38 mt9v111_probe,
39 mt9v112_probe,
42 struct sn9c20x_video_mode sn9c20x_modes[SN9C20X_N_MODES] = {
44 .width = 128,
45 .height = 96,
46 .scale = SN9C20X_1_4_SCALE,
47 .window = {65, 48, 1024, 768}
50 .width = 160,
51 .height = 120,
52 .scale = SN9C20X_1_4_SCALE,
53 .window = {0, 0, 640, 480}
56 .width = 176,
57 .height = 144,
58 .scale = SN9C20X_1_2_SCALE,
59 .window = {145, 96, 704, 576}
62 .width = 320,
63 .height = 240,
64 .scale = SN9C20X_1_2_SCALE,
65 .window = {0, 0, 640, 480}
68 .width = 352,
69 .height = 288,
70 .scale = SN9C20X_NO_SCALE,
71 .window = {145, 96, 704, 576}
74 .width = 640,
75 .height = 480,
76 .scale = SN9C20X_NO_SCALE,
77 .window = {0, 0, 640, 480}
81 struct sn9c20x_video_format sn9c20x_fmts[SN9C20X_N_FMTS] = {
83 .pix_fmt = V4L2_PIX_FMT_SBGGR8,
84 .desc = "Bayer 8bit (BGGR)",
85 .depth = 8,
86 .set_format = sn9c20x_set_raw,
89 .pix_fmt = V4L2_PIX_FMT_YUV420,
90 .desc = "I420 (YUV 4:2:0)",
91 .depth = 12,
92 .set_format = sn9c20x_set_yuv420,
95 .pix_fmt = V4L2_PIX_FMT_YUYV,
96 .desc = "YUYV (YUV 4:2:0)",
97 .depth = 16,
98 .set_format = sn9c20x_set_yuv422,
101 .pix_fmt = V4L2_PIX_FMT_JPEG,
102 .desc = "JPEG (YUV 4:2:2)",
103 .depth = 16,
104 .set_format = sn9c20x_set_jpeg,
108 int sn9c20x_initialize_sensor(struct usb_sn9c20x *dev)
110 int ret = 0;
111 int i;
113 dev->camera.min_yavg = 60;
114 dev->camera.max_yavg = 150;
115 dev->camera.min_stable_yavg = 70;
116 dev->camera.max_stable_yavg = 140;
118 /* Probe sensor first if sensor set to probe*/
119 if (dev->camera.sensor == PROBE_SENSOR) {
120 for (i = 0; i < ARRAY_SIZE(sn_probes); i++) {
121 ret = sn_probes[i](dev);
122 if (ret != -EINVAL)
123 break;
124 dev->camera.sensor = ret;
128 switch (dev->camera.sensor) {
129 case SOI968_SENSOR:
130 sn9c20x_write_i2c_array(dev, soi968_init, 0);
131 dev->camera.set_exposure = soi968_set_exposure;
132 dev->camera.set_gain = soi968_set_gain;
133 dev->camera.set_auto_exposure = ov_set_autoexposure;
134 dev->camera.set_auto_gain = ov_set_autogain;
135 dev->camera.button_detect = soi968_button_detect;
136 dev->camera.hstart = 60;
137 dev->camera.vstart = 11;
138 UDIA_INFO("Detected SOI968 Sensor.\n");
139 break;
140 case OV9650_SENSOR:
141 sn9c20x_write_i2c_array(dev, ov9650_init, 0);
142 dev->camera.hstart = 1;
143 dev->camera.vstart = 7;
144 dev->camera.set_hvflip = ov965x_set_hvflip;
145 dev->camera.set_exposure = ov_set_exposure;
146 dev->camera.set_auto_gain = ov_set_autogain;
147 dev->camera.flip_detect = ov965x_flip_detect;
148 UDIA_INFO("Detected OV9650 Sensor.\n");
149 break;
150 case OV9655_SENSOR:
151 sn9c20x_write_i2c_array(dev, ov9655_init, 0);
152 dev->camera.set_auto_exposure = ov_set_autoexposure;
153 dev->camera.set_exposure = ov_set_exposure;
154 dev->camera.set_auto_gain = ov_set_autogain;
155 dev->camera.hstart = 0;
156 dev->camera.vstart = 7;
157 UDIA_INFO("Detected OV9655 Sensor.\n");
158 break;
159 case OV7670_SENSOR:
160 sn9c20x_write_i2c_array(dev, ov7670_init, 0);
161 dev->camera.set_auto_exposure = ov_set_autoexposure;
162 dev->camera.set_exposure = ov_set_exposure;
163 dev->camera.set_auto_gain = ov_set_autogain;
164 dev->camera.flip_detect = ov7670_flip_detect;
165 dev->camera.hstart = 0;
166 dev->camera.vstart = 1;
167 UDIA_INFO("Detected OV7670 Sensor.\n");
168 break;
169 case OV7660_SENSOR:
170 sn9c20x_write_i2c_array(dev, ov7660_init, 0);
171 dev->camera.set_exposure = ov_set_exposure;
172 dev->camera.set_auto_gain = ov_set_autogain;
173 dev->camera.hstart = 1;
174 dev->camera.vstart = 1;
175 UDIA_INFO("Detected OV7660 Sensor.\n");
176 break;
177 case MT9V111_SENSOR:
178 sn9c20x_write_i2c_array(dev, mt9v111_init, 1);
179 dev->camera.set_hvflip = mt9v111_set_hvflip;
180 dev->camera.set_exposure = mt9v111_set_exposure;
181 dev->camera.set_auto_exposure = mt9v111_set_autoexposure;
182 dev->camera.hstart = 2;
183 dev->camera.vstart = 2;
184 UDIA_INFO("Detected MT9V111 Sensor.\n");
185 break;
186 case MT9V112_SENSOR:
187 sn9c20x_write_i2c_array(dev, mt9v112_init, 1);
188 dev->camera.hstart = 6;
189 dev->camera.vstart = 2;
190 UDIA_INFO("Detected MT9V112 Sensor.\n");
191 break;
192 case MT9M111_SENSOR:
193 sn9c20x_write_i2c_array(dev, mt9m111_init, 1);
194 dev->camera.hstart = 6;
195 dev->camera.vstart = 2;
196 UDIA_INFO("Detected MT9M111 Sensor.\n");
197 break;
198 case MT9V011_SENSOR:
199 sn9c20x_write_i2c_array(dev, mt9v011_init, 1);
200 dev->camera.set_hvflip = mt9v011_set_hvflip;
201 dev->camera.set_exposure = mt9v011_set_exposure;
202 dev->camera.hstart = 2;
203 dev->camera.vstart = 2;
204 UDIA_INFO("Detected MT9V011 Sensor.\n");
205 break;
206 case MT9M001_SENSOR:
207 sn9c20x_write_i2c_array(dev, mt9m001_init, 1);
208 dev->camera.hstart = 2;
209 dev->camera.vstart = 2;
210 UDIA_INFO("Detected MT9M001 Sensor.\n");
211 break;
212 case HV7131R_SENSOR:
213 dev->camera.i2c_flags |= SN9C20X_I2C_400KHZ;
214 sn9c20x_write_i2c_array(dev, hv7131r_init, 0);
215 dev->camera.set_hvflip = hv7131r_set_hvflip;
216 dev->camera.set_gain = hv7131r_set_gain;
217 dev->camera.set_exposure = hv7131r_set_exposure;
218 dev->camera.hstart = 0;
219 dev->camera.vstart = 1;
220 UDIA_INFO("Detected HV7131R Sensor.\n");
221 break;
222 default:
223 ret = -EINVAL;
224 UDIA_INFO("Unsupported sensor.\n");
226 return ret;
231 * @brief Wrapper function to detect hardware states
233 * @param dev Pointer to device structure
235 * @returns 0
237 int dev_sn9c20x_call_constantly(struct usb_sn9c20x *dev)
240 /* Know to be broken, temporarely disabled */
241 /*dev_sn9c20x_flip_detection(dev);*/
242 dev_sn9c20x_button_detection(dev);
243 if (!dev->camera.set_auto_exposure &&
244 dev->vsettings.auto_exposure == V4L2_EXPOSURE_AUTO) {
245 dev_sn9c20x_perform_soft_ae(dev);
248 return 0;
252 * @brief Wrapper function to detect a flipped sensor
254 * @param dev Pointer to device structure
256 * @returns 0 or negative error value
259 int dev_sn9c20x_flip_detection(struct usb_sn9c20x *dev)
261 int ret = -ENODEV;
262 if (dev && dev->camera.flip_detect)
263 ret = dev->camera.flip_detect(dev);
264 return ret;
268 * @brief Wrapper function to detect a pushed button
270 * @param dev Pointer to device structure
272 * @returns 0 or negative error value
275 int dev_sn9c20x_button_detection(struct usb_sn9c20x *dev)
277 int ret = -ENODEV;
278 if (dev && dev->camera.button_detect)
279 ret = dev->camera.button_detect(dev);
280 return ret;
284 * @brief Perform software autoexposure
286 * @param dev
288 * @returns 0 or negative error value
290 * @author Vasily Khoruzhick
292 int dev_sn9c20x_perform_soft_ae(struct usb_sn9c20x *dev)
294 int yavg;
295 static int old_yavg = -1;
296 int koef = 100, new_exp, i;
297 yavg = -1;
298 i = 10;
300 if (!dev->camera.set_exposure)
301 return -1;
302 yavg = atomic_read(&dev->camera.yavg);
304 UDIA_INFO("Sensor YAVG: %d\n", yavg);
305 if (yavg < 0) {
306 /* Can't get YAVG - we have nothing to do */
307 return -1;
310 /* Image is too dark */
311 if (yavg < dev->camera.min_yavg) {
312 /* yavg can't be 0 - in that way new_exp == infinity */
313 if (yavg == 0)
314 yavg = 1;
315 if (old_yavg != -1) {
316 /* Previous correction was made to make image darker,
317 * but we made it too dark. Calculating our error
318 * and taking it into account.
319 * Usually error is 0.7 - 2, so we multiply it by 100
321 if (old_yavg > dev->camera.max_yavg)
322 koef = 100 * dev->camera.
323 min_stable_yavg / yavg;
324 else
325 koef = 100;
328 /* Calculating new exposure value. We assuming that
329 * exposure linearly depends on YAVG, but we taking
330 * our calculated error into account */
331 new_exp = (dev->camera.min_stable_yavg
332 * dev->vsettings.exposure * 100) / (yavg * koef);
334 /* Exposure can't be more than 0xff or less than 0x1 */
335 if (new_exp > 0xff)
336 new_exp = 0xff;
337 if (new_exp < 0x1)
338 new_exp = 1;
340 old_yavg = yavg;
342 /* Applying new exposure */
343 dev->vsettings.exposure = new_exp;
344 dev->camera.set_exposure(dev);
347 /* Image is too bright */
348 else if (yavg > dev->camera.max_yavg) {
349 /* yavg can't be 0 - in that way new_exp == infinity */
350 if (yavg == 0)
351 yavg = 1;
352 if (old_yavg != -1) {
354 /* Previous correction was made to make image brighter,
355 * but we made it too bright. Calculating our error
356 * and taking it into account.
357 * Usually error is 0.7 - 2, so we multiply it by 100
359 if (old_yavg < dev->camera.min_yavg)
360 koef = 100 * yavg / dev->camera.
361 max_stable_yavg;
362 else
363 koef = 100;
366 /* Calculating new exposure value. We assuming that
367 * exposure linearly depends on YAVG, but we taking
368 * our calculated error into account */
369 new_exp = (koef * dev->camera.max_stable_yavg
370 * dev->vsettings.exposure) / (yavg * 100);
372 /* Exposure can't be more than 0xff or less than 0x1 */
373 if (new_exp > 0xff)
374 new_exp = 0xff;
375 if (new_exp < 0x1)
376 new_exp = 1;
378 old_yavg = yavg;
380 /* Applying new exposure */
381 dev->vsettings.exposure = new_exp;
382 dev->camera.set_exposure(dev);
385 return 0;