Add "bandwidth" parameter for ISOC
[microdia.git] / sn9c20x-dev.c
blob160895ef34718b20b5e5d53cac474a8dc9cf23f8
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,
41 struct sn9c20x_video_mode sn9c20x_modes[SN9C20X_N_MODES] = {
43 .width = 128,
44 .height = 96,
45 .scale = SN9C20X_1_4_SCALE,
46 .window = {65, 48, 1024, 768}
49 .width = 160,
50 .height = 120,
51 .scale = SN9C20X_1_4_SCALE,
52 .window = {0, 0, 640, 480}
55 .width = 176,
56 .height = 144,
57 .scale = SN9C20X_1_2_SCALE,
58 .window = {145, 96, 704, 576}
61 .width = 320,
62 .height = 240,
63 .scale = SN9C20X_1_2_SCALE,
64 .window = {0, 0, 640, 480}
67 .width = 352,
68 .height = 288,
69 .scale = SN9C20X_NO_SCALE,
70 .window = {145, 96, 704, 576}
73 .width = 640,
74 .height = 480,
75 .scale = SN9C20X_NO_SCALE,
76 .window = {0, 0, 640, 480}
80 struct sn9c20x_video_format sn9c20x_fmts[SN9C20X_N_FMTS] = {
82 .pix_fmt = V4L2_PIX_FMT_SBGGR8,
83 .desc = "Bayer 8bit (BGGR)",
84 .depth = 8,
85 .set_format = sn9c20x_set_raw,
88 .pix_fmt = V4L2_PIX_FMT_YUV420,
89 .desc = "I420 (YUV 4:2:0)",
90 .depth = 12,
91 .set_format = sn9c20x_set_yuv420,
94 .pix_fmt = V4L2_PIX_FMT_YUYV,
95 .desc = "YUYV (YUV 4:2:0)",
96 .depth = 16,
97 .set_format = sn9c20x_set_yuv422,
100 .pix_fmt = V4L2_PIX_FMT_JPEG,
101 .desc = "JPEG (YUV 4:2:2)",
102 .depth = 16,
103 .set_format = sn9c20x_set_jpeg,
107 int sn9c20x_initialize_sensor(struct usb_sn9c20x *dev)
109 int ret = 0;
110 int i;
112 dev->camera.min_yavg = 30;
113 dev->camera.max_yavg = 60;
114 dev->camera.min_stable_yavg = 32;
115 dev->camera.max_stable_yavg = 58;
117 /* Probe sensor first if sensor set to probe*/
118 if (dev->camera.sensor == PROBE_SENSOR) {
119 for (i = 0; i < ARRAY_SIZE(sn_probes); i++) {
120 ret = sn_probes[i](dev);
121 if (ret != -EINVAL)
122 break;
123 dev->camera.sensor = ret;
127 switch (dev->camera.sensor) {
128 case SOI968_SENSOR:
129 sn9c20x_write_i2c_array(dev, soi968_init, 0);
130 dev->camera.set_exposure = soi968_set_exposure;
131 dev->camera.set_auto_exposure = ov_set_autoexposure;
132 dev->camera.set_auto_gain = ov_set_autogain;
133 dev->camera.button_detect = soi968_button_detect;
134 dev->camera.hstart = 60;
135 dev->camera.vstart = 11;
136 UDIA_INFO("Detected SOI968 Sensor.\n");
137 break;
138 case OV9650_SENSOR:
139 sn9c20x_write_i2c_array(dev, ov9650_init, 0);
140 dev->camera.hstart = 1;
141 dev->camera.vstart = 7;
142 dev->camera.set_hvflip = ov965x_set_hvflip;
143 dev->camera.set_exposure = ov965x_set_exposure;
144 dev->camera.set_auto_gain = ov_set_autogain;
145 dev->camera.flip_detect = ov965x_flip_detect;
146 dev->camera.get_yavg = ov965x_get_yavg;
147 UDIA_INFO("Detected OV9650 Sensor.\n");
148 break;
149 case OV9655_SENSOR:
150 sn9c20x_write_i2c_array(dev, ov9655_init, 0);
151 dev->camera.set_auto_exposure = ov_set_autoexposure;
152 dev->camera.set_auto_gain = ov_set_autogain;
153 dev->camera.hstart = 0;
154 dev->camera.vstart = 7;
155 UDIA_INFO("Detected OV9655 Sensor.\n");
156 break;
157 case OV7670_SENSOR:
158 sn9c20x_write_i2c_array(dev, ov7670_init, 0);
159 dev->camera.set_auto_exposure = ov_set_autoexposure;
160 dev->camera.set_exposure = ov7660_set_exposure;
161 dev->camera.set_auto_gain = ov_set_autogain;
162 dev->camera.flip_detect = ov7670_flip_detect;
163 dev->camera.hstart = 0;
164 dev->camera.vstart = 1;
165 UDIA_INFO("Detected OV7670 Sensor.\n");
166 break;
167 case OV7660_SENSOR:
168 sn9c20x_write_i2c_array(dev, ov7660_init, 0);
169 dev->camera.set_exposure = ov7660_set_exposure;
170 dev->camera.set_auto_gain = ov_set_autogain;
171 dev->camera.hstart = 1;
172 dev->camera.vstart = 1;
173 dev->camera.get_yavg = ov965x_get_yavg;
174 UDIA_INFO("Detected OV7660 Sensor.\n");
175 break;
176 case MT9V111_SENSOR:
177 sn9c20x_write_i2c_array(dev, mt9v111_init, 1);
178 dev->camera.set_hvflip = mt9v111_set_hvflip;
179 dev->camera.set_exposure = mt9v111_set_exposure;
180 dev->camera.set_auto_exposure = mt9v111_set_autoexposure;
181 dev->camera.hstart = 2;
182 dev->camera.vstart = 2;
183 UDIA_INFO("Detected MT9V111 Sensor.\n");
184 break;
185 case MT9M111_SENSOR:
186 sn9c20x_write_i2c_array(dev, mt9m111_init, 1);
187 dev->camera.hstart = 6;
188 dev->camera.vstart = 2;
189 UDIA_INFO("Detected MT9M111 Sensor.\n");
190 break;
191 case MT9V011_SENSOR:
192 sn9c20x_write_i2c_array(dev, mt9v011_init, 1);
193 dev->camera.set_hvflip = mt9v011_set_hvflip;
194 dev->camera.set_exposure = mt9v011_set_exposure;
195 dev->camera.hstart = 2;
196 dev->camera.vstart = 2;
197 UDIA_INFO("Detected MT9V011 Sensor.\n");
198 break;
199 case MT9M001_SENSOR:
200 sn9c20x_write_i2c_array(dev, mt9m001_init, 1);
201 dev->camera.hstart = 2;
202 dev->camera.vstart = 2;
203 UDIA_INFO("Detected MT9M001 Sensor.\n");
204 break;
205 case HV7131R_SENSOR:
206 dev->camera.i2c_flags |= SN9C20X_I2C_400KHZ;
207 sn9c20x_write_i2c_array(dev, hv7131r_init, 0);
208 dev->camera.set_hvflip = hv7131r_set_hvflip;
209 dev->camera.set_gain = hv7131r_set_gain;
210 dev->camera.set_exposure = hv7131r_set_exposure;
211 dev->camera.hstart = 0;
212 dev->camera.vstart = 1;
213 UDIA_INFO("Detected HV7131R Sensor.\n");
214 break;
215 default:
216 ret = -EINVAL;
217 UDIA_INFO("Unsupported sensor.\n");
219 return ret;
224 * @brief Wrapper function to detect hardware states
226 * @param dev Pointer to device structure
228 * @returns 0
230 int dev_sn9c20x_call_constantly(struct usb_sn9c20x *dev)
233 /* Know to be broken, temporarely disabled */
234 /*dev_sn9c20x_flip_detection(dev);*/
235 dev_sn9c20x_button_detection(dev);
236 if (!dev->camera.set_auto_exposure &&
237 dev->camera.get_yavg &&
238 dev->vsettings.auto_exposure == V4L2_EXPOSURE_AUTO) {
239 dev_sn9c20x_perform_soft_ae(dev);
242 return 0;
246 * @brief Wrapper function to detect a flipped sensor
248 * @param dev Pointer to device structure
250 * @returns 0 or negative error value
253 int dev_sn9c20x_flip_detection(struct usb_sn9c20x *dev)
255 int ret = -ENODEV;
256 if (dev && dev->camera.flip_detect)
257 ret = dev->camera.flip_detect(dev);
258 return ret;
262 * @brief Wrapper function to detect a pushed button
264 * @param dev Pointer to device structure
266 * @returns 0 or negative error value
269 int dev_sn9c20x_button_detection(struct usb_sn9c20x *dev)
271 int ret = -ENODEV;
272 if (dev && dev->camera.button_detect)
273 ret = dev->camera.button_detect(dev);
274 return ret;
278 * @brief Perform software autoexposure
280 * @param dev
282 * @returns 0 or negative error value
284 * @author Vasily Khoruzhick
286 int dev_sn9c20x_perform_soft_ae(struct usb_sn9c20x *dev)
288 int yavg;
289 static int old_yavg = -1, old_exp = -1;
290 int koef = 100, new_exp, i;
291 yavg = -1;
292 i = 10;
294 if (!dev->camera.set_exposure)
295 return -1;
296 if (!dev->camera.get_yavg)
297 return -1;
299 /* Trying to get average value of Y */
300 while ((yavg == -1) && (i--))
301 yavg = dev->camera.get_yavg(dev);
303 if (yavg == -1) {
304 /* Can't get YAVG - we have nothing to do */
305 return -1;
308 /* Image is too dark */
309 if (yavg < dev->camera.min_yavg) {
310 /* yavg can't be 0 - in that way new_exp == infinity */
311 if (yavg == 0)
312 yavg = 1;
313 if (old_yavg != -1) {
314 /* Previous correction was made to make image darker,
315 * but we made it too dark. Calculating our error
316 * and taking it into account.
317 * Usually error is 0.7 - 2, so we multiply it by 100
319 if (old_yavg > dev->camera.max_yavg)
320 koef = 100 * dev->camera.
321 min_stable_yavg / yavg;
322 else
323 koef = 100;
326 /* Calculating new exposure value. We assuming that
327 * exposure linearly depends on YAVG, but we taking
328 * our calculated error into account */
329 new_exp = (dev->camera.min_stable_yavg
330 * dev->vsettings.exposure * 100) / (yavg * koef);
332 /* Exposure can't be more than 0xff or less than 0x1 */
333 if (new_exp > 0xff)
334 new_exp = 0xff;
335 if (new_exp < 0x1)
336 new_exp = 1;
338 old_exp = dev->vsettings.exposure;
339 old_yavg = yavg;
341 /* Applying new exposure */
342 dev->vsettings.exposure = new_exp;
343 dev->camera.set_exposure(dev);
346 /* Image is too bright */
347 else if (yavg > dev->camera.max_yavg) {
348 /* yavg can't be 0 - in that way new_exp == infinity */
349 if (yavg == 0)
350 yavg = 1;
351 if (old_yavg != -1) {
353 /* Previous correction was made to make image brighter,
354 * but we made it too bright. Calculating our error
355 * and taking it into account.
356 * Usually error is 0.7 - 2, so we multiply it by 100
358 if (old_yavg < dev->camera.min_yavg)
359 koef = 100 * yavg / dev->camera.
360 max_stable_yavg;
361 else
362 koef = 100;
365 /* Calculating new exposure value. We assuming that
366 * exposure linearly depends on YAVG, but we taking
367 * our calculated error into account */
368 new_exp = (koef * dev->camera.max_stable_yavg
369 * dev->vsettings.exposure) / (yavg * 100);
371 /* Exposure can't be more than 0xff or less than 0x1 */
372 if (new_exp > 0xff)
373 new_exp = 0xff;
374 if (new_exp < 0x1)
375 new_exp = 1;
377 old_exp = dev->vsettings.exposure;
378 old_yavg = yavg;
380 /* Applying new exposure */
381 dev->vsettings.exposure = new_exp;
382 dev->camera.set_exposure(dev);
385 return 0;