Fix SXGA support to enforce bayer format
[microdia.git] / sn9c20x-dev.c
blobbcff79fd85e8362df75124e119ddd8a5ebb5801e
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}
80 .width = 1280,
81 .height = 1024,
82 .scale = SN9C20X_NO_SCALE,
83 .window = {0, 0, 1280, 1024}
87 struct sn9c20x_video_format sn9c20x_fmts[SN9C20X_N_FMTS] = {
89 .pix_fmt = V4L2_PIX_FMT_SN9C20X_I420,
90 .desc = "SN9C20X I420 (YUV 4:2:0)",
91 .depth = 12,
92 .set_format = sn9c20x_set_yuv420,
95 .pix_fmt = V4L2_PIX_FMT_SBGGR8,
96 .desc = "Bayer 8bit (BGGR)",
97 .depth = 8,
98 .set_format = sn9c20x_set_raw,
102 .pix_fmt = V4L2_PIX_FMT_YUYV,
103 .desc = "YUYV (YUV 4:2:0)",
104 .depth = 16,
105 .set_format = sn9c20x_set_yuv422,
109 .pix_fmt = V4L2_PIX_FMT_JPEG,
110 .desc = "JPEG (YUV 4:2:2)",
111 .depth = 16,
112 .set_format = sn9c20x_set_jpeg,
116 int sn9c20x_initialize_sensor(struct usb_sn9c20x *dev)
118 int ret = 0;
119 int i;
121 dev->camera.min_yavg = 80;
122 dev->camera.max_yavg = 130;
123 dev->camera.old_step = 0;
124 dev->camera.older_step = 0;
125 dev->camera.exposure_step = 16;
127 /* Probe sensor first if sensor set to probe*/
128 if (dev->camera.sensor == PROBE_SENSOR) {
129 for (i = 0; i < ARRAY_SIZE(sn_probes); i++) {
130 ret = sn_probes[i](dev);
131 dev->camera.sensor = ret;
132 if (ret > 0)
133 break;
137 switch (dev->camera.sensor) {
138 case SOI968_SENSOR:
139 sn9c20x_write_i2c_array(dev, soi968_init, 0);
140 dev->camera.set_sxga_mode = ov965x_set_sxga_mode;
141 dev->camera.set_exposure = soi968_set_exposure;
142 dev->camera.set_auto_exposure = soi968_set_autoexposure;
143 dev->camera.set_gain = soi968_set_gain;
144 dev->camera.set_auto_gain = ov_set_autogain;
145 dev->camera.set_auto_whitebalance = soi968_set_autowhitebalance;
146 dev->camera.hstart = 60;
147 dev->camera.vstart = 11;
148 UDIA_INFO("Detected SOI968 Sensor.\n");
149 break;
150 case OV9650_SENSOR:
151 sn9c20x_write_i2c_array(dev, ov9650_init, 0);
152 dev->camera.hstart = 1;
153 dev->camera.vstart = 7;
154 dev->camera.set_sxga_mode = ov965x_set_sxga_mode;
155 dev->camera.set_hvflip = ov965x_set_hvflip;
156 dev->camera.set_exposure = ov_set_exposure;
157 dev->camera.set_auto_gain = ov_set_autogain;
158 dev->camera.set_gain = ov9650_set_gain;
159 dev->camera.flip_detect = ov965x_flip_detect;
160 UDIA_INFO("Detected OV9650 Sensor.\n");
161 break;
162 case OV9655_SENSOR:
163 sn9c20x_write_i2c_array(dev, ov9655_init, 0);
164 dev->camera.set_sxga_mode = ov965x_set_sxga_mode;
165 dev->camera.set_exposure = ov_set_exposure;
166 dev->camera.set_auto_gain = ov_set_autogain;
167 dev->camera.hstart = 0;
168 dev->camera.vstart = 7;
169 UDIA_INFO("Detected OV9655 Sensor.\n");
170 break;
171 case OV7670_SENSOR:
172 sn9c20x_write_i2c_array(dev, ov7670_init, 0);
173 dev->camera.set_exposure = ov_set_exposure;
174 dev->camera.set_auto_gain = ov_set_autogain;
175 dev->camera.flip_detect = ov7670_flip_detect;
176 dev->camera.hstart = 0;
177 dev->camera.vstart = 1;
178 UDIA_INFO("Detected OV7670 Sensor.\n");
179 break;
180 case OV7660_SENSOR:
181 sn9c20x_write_i2c_array(dev, ov7660_init, 0);
182 dev->camera.set_exposure = ov_set_exposure;
183 dev->camera.set_auto_gain = ov_set_autogain;
184 dev->camera.set_gain = ov9650_set_gain;
185 dev->camera.hstart = 1;
186 dev->camera.vstart = 1;
187 UDIA_INFO("Detected OV7660 Sensor.\n");
188 break;
189 case MT9V111_SENSOR:
190 sn9c20x_write_i2c_array(dev, mt9v111_init, 1);
191 dev->camera.set_hvflip = mt9v111_set_hvflip;
192 dev->camera.set_exposure = mt9v111_set_exposure;
193 dev->camera.set_auto_exposure = mt9v111_set_autoexposure;
194 dev->camera.set_auto_whitebalance = mt9v111_set_autowhitebalance;
195 dev->camera.hstart = 2;
196 dev->camera.vstart = 2;
197 UDIA_INFO("Detected MT9V111 Sensor.\n");
198 break;
199 case MT9V112_SENSOR:
200 sn9c20x_write_i2c_array(dev, mt9v112_init, 1);
201 dev->camera.set_hvflip = mt9v112_set_hvflip;
202 dev->camera.hstart = 6;
203 dev->camera.vstart = 2;
204 UDIA_INFO("Detected MT9V112 Sensor.\n");
205 break;
206 case MT9M111_SENSOR:
207 sn9c20x_write_i2c_array(dev, mt9m111_init, 1);
208 dev->camera.set_exposure = mt9m111_set_exposure;
209 dev->camera.set_auto_exposure = mt9m111_set_autoexposure;
210 dev->camera.set_auto_whitebalance = mt9m111_set_autowhitebalance;
211 dev->camera.hstart = 0;
212 dev->camera.vstart = 2;
213 UDIA_INFO("Detected MT9M111 Sensor.\n");
214 break;
215 case MT9V011_SENSOR:
216 sn9c20x_write_i2c_array(dev, mt9v011_init, 1);
217 dev->camera.set_hvflip = mt9v011_set_hvflip;
218 dev->camera.set_exposure = mt9v011_set_exposure;
219 dev->camera.hstart = 2;
220 dev->camera.vstart = 2;
221 UDIA_INFO("Detected MT9V011 Sensor.\n");
222 break;
223 case MT9M001_SENSOR:
224 sn9c20x_write_i2c_array(dev, mt9m001_init, 1);
225 dev->camera.hstart = 2;
226 dev->camera.vstart = 2;
227 UDIA_INFO("Detected MT9M001 Sensor.\n");
228 break;
229 case HV7131R_SENSOR:
230 dev->camera.i2c_flags |= SN9C20X_I2C_400KHZ;
231 sn9c20x_write_i2c_array(dev, hv7131r_init, 0);
232 dev->camera.set_hvflip = hv7131r_set_hvflip;
233 dev->camera.set_gain = hv7131r_set_gain;
234 dev->camera.set_exposure = hv7131r_set_exposure;
235 dev->camera.hstart = 0;
236 dev->camera.vstart = 1;
237 UDIA_INFO("Detected HV7131R Sensor.\n");
238 break;
239 default:
240 ret = -EINVAL;
241 UDIA_INFO("Unsupported sensor.\n");
243 return ret;
248 * @brief Wrapper function to detect hardware states
250 * @param dev Pointer to device structure
252 * @returns 0
254 int dev_sn9c20x_call_constantly(struct usb_sn9c20x *dev)
257 /* Know to be broken, temporarely disabled */
258 /*dev_sn9c20x_flip_detection(dev);*/
259 if (!dev->camera.set_auto_exposure &&
260 dev->vsettings.auto_exposure) {
261 dev_sn9c20x_perform_soft_ae(dev);
264 return 0;
268 * @brief Wrapper function to detect a flipped sensor
270 * @param dev Pointer to device structure
272 * @returns 0 or negative error value
275 int dev_sn9c20x_flip_detection(struct usb_sn9c20x *dev)
277 int ret = -ENODEV;
278 if (dev && dev->camera.flip_detect)
279 ret = dev->camera.flip_detect(dev);
280 return ret;
284 * @brief Perform software autoexposure
286 * @param dev
288 * @returns 0 or negative error value
290 * @author Stefan Krastanov
292 int dev_sn9c20x_perform_soft_ae(struct usb_sn9c20x *dev)
294 int yavg, new_exp;
295 yavg = -1;
297 if (!dev->camera.set_exposure)
298 return -1;
299 yavg = atomic_read(&dev->camera.yavg);
301 UDIA_DEBUG("Sensor YAVG: %d\n", yavg);
302 if (yavg < 0) {
303 /* Can't get YAVG - we have nothing to do */
304 return -1;
307 /*some hardcoded values are present
308 *like those for maximal/minimal exposure
309 *and exposure steps*/
311 /* image too dark */
312 if (yavg < dev->camera.min_yavg) {
313 /*worst case - exposure is allready maximal*/
314 if (dev->vsettings.exposure > 0xf5)
315 return 0;
316 /*change exposure just a bit*/
317 new_exp = dev->vsettings.exposure + dev->camera.exposure_step;
318 if (new_exp > 0xff)
319 new_exp = 0xff;
320 if (new_exp < 0x1)
321 new_exp = 1;
322 /*set it*/
323 dev->vsettings.exposure = new_exp;
324 dev->camera.set_exposure(dev);
325 /*note the direction of the change*/
326 dev->camera.older_step = dev->camera.old_step;
327 dev->camera.old_step = 1; /*it's going up*/
329 /*check if it's oscillating and take smaller step if it is*/
330 if (dev->camera.old_step ^ dev->camera.older_step)
331 dev->camera.exposure_step /= 2;
332 /* oscilating - divide the step by 2 */
333 else
334 dev->camera.exposure_step += 2;
335 /* same direction - step must be bigger */
337 /*image too light*/
338 if (yavg > dev->camera.max_yavg) {
339 /*worst case - exposure is allready minimal*/
340 if (dev->vsettings.exposure < 0x10)
341 return 0;
342 /*change exposure just a bit*/
343 new_exp = dev->vsettings.exposure - dev->camera.exposure_step;
344 if (new_exp > 0xff)
345 new_exp = 0xff;
346 if (new_exp < 0x1)
347 new_exp = 1;
348 /*set it*/
349 dev->vsettings.exposure = new_exp;
350 dev->camera.set_exposure(dev);
351 /*note the direction of the change*/
352 dev->camera.older_step = dev->camera.old_step;
353 dev->camera.old_step = 0; /*it's going down*/
355 /*check if it's oscillating and take smaller step if it is*/
356 if (dev->camera.old_step ^ dev->camera.older_step)
357 dev->camera.exposure_step /= 2;
358 /* oscilating - divide the step by 2 */
359 else
360 dev->camera.exposure_step += 2;
361 /* same direction - step must be bigger */
364 return 0;