Removed setup_autoexposure, setup_autowhitebalanace, and set_autocorrections
[microdia.git] / micron.c
blob167a2d42c09abd4d63a46dd7f0ba45806d082a2e
1 /**
2 * @file micron.c
3 * @author Comer352l
4 * @date 2008-04-25
6 * @brief Common functions and data for Micron sensors.
8 * @note Copyright (C) Comer352l
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/delay.h>
28 #include "microdia.h"
29 #include "sn9c20x.h"
30 #include "micron.h"
32 struct micron_init {
33 __u8 address;
34 __u16 value;
37 static struct micron_init mt9v111_init[] = {
38 /* 0x0d: Color Correction Register 8 */
39 {0x0d, 0x0001},
40 /* 0x0d: Color Correction Register 8 */
41 {0x0d, 0x0000}, /* ??? */
42 /* 0x02: Color Correction Register 1 */
43 {0x01, 0x0001}, /* select IFP address space */
44 {0x02, 0x0016}, /* ??? */
45 /* 0x03: Color Correction Register 3 */
46 /* 0x04: Color Correction Register 4 */
47 {0x03, 0x01e1}, /* ??? */
48 {0x04, 0x0281}, /* ??? */
49 /* 0x05: Aperture Correction (Sharpening) */
50 {0x05, 0x0004}, /* 100% sharpening,
51 no automatic sharpness reduction at low light: no sharpening */
52 /* 0x07: IFP Soft Reset */
53 /* 0x08: Output Format Control */
54 {0x07, 0x3002}, /* reset */
55 {0x21, 0x0000},
56 {0x25, 0x4024},
57 {0x26, 0xff03},
58 {0x27, 0xff10},
59 {0x2b, 0x7828},
60 {0x2c, 0xb43c},
61 {0x2d, 0xf0a0},
62 {0x2e, 0x0c64},
63 {0x2f, 0x0064},
64 {0x67, 0x4010},
65 {0x06, 0x301c}, /* stop AWB at the current values,
66 no on-the-fly defect correction, no auto exposure */
67 {0x08, 0x0480}, /* bypass entire image processing,
68 raw 8+2 Bayer data output directly */
69 {0x01, 0x0004}, /* select sensor address space */
70 {0x02, 0x0016}, /* start with column 22 */
71 /* 0x03: Window Height */
72 /* 0x04: Window Width */
73 {0x03, 0x01e6}, /* 486 */
74 {0x04, 0x0286}, /* 646 */
75 /* 0x05: Horizontal Blanking */
76 /* 0x06: Vertical Blanking */
77 {0x05, 0x0004}, /* 4 columns (pixel clocks) */
78 {0x06, 0x0000}, /* 0 rows */
79 /* 0x07: Output Control */
80 /* 0x08: Row Start */
81 {0x07, 0x3002}, /* normal operation + chip enable*/
82 {0x08, 0x0008}, /* row 8 */
83 /* 0x0c: Shutter Delay */
84 /* 0x0d: Reset (Soft) */
85 {0x0c, 0x0000}, /* 0 master clocks */
86 {0x0d, 0x0000}, /* return to normal operation */
87 {0x0e, 0x0000},
88 {0x0f, 0x0000},
89 {0x10, 0x0000},
90 {0x11, 0x0000},
91 /* 0x12: 2X Zoom Col Start
92 => 0x1e bit 0 must be set to activate zoom */
93 /* 0x13: 2X Zoom Row Start
94 => 0x1e bit 0 must be set to activate zoom */
95 {0x12, 0x00b0}, /* column 176 */
96 {0x13, 0x007c}, /* row 124 */
97 {0x14, 0x0000},
98 {0x15, 0x0000},
99 {0x16, 0x0000},
100 {0x17, 0x0000},
101 {0x18, 0x0000},
102 {0x19, 0x0000},
103 {0x1a, 0x0000},
104 {0x1b, 0x0000},
105 {0x1c, 0x0000},
106 {0x1d, 0x0000},
107 {0x30, 0x0000},
108 {0x30, 0x0005},
109 {0x31, 0x0000},
110 /* 0x02: Column Start */
111 /* 0x03: Window Height */
112 {0x02, 0x0016}, /* coulmn 22 */
113 {0x03, 0x01e1}, /* 481 */
114 /* 0x04: Window Width */
115 /* 0x05: Horizontal Blanking */
116 {0x04, 0x0281}, /* 641 */
117 {0x05, 0x0004}, /* 4 columns (pixel clocks) */
118 /* 0x06: Vertical Blanking */
119 /* 0x07: Output Control */
120 {0x06, 0x0000}, /* 0 rows */
121 {0x07, 0x3002}, /* normal operation + chip enable */
122 /* 0x06: Vertical Blanking */
123 {0x06, 0x002d}, /* 45 rows */
124 /* 0x05: Horizontal Blanking */
125 {0x05, 0x0004}, /* 4 columns (pixel clocks) */
126 /* 0x09: Shutter Width */
127 {0x09, 0x0064}, /* integration of 100 rows */
128 /* 0x2b: Green 1 Gain */
129 /* 0x2c: Blue Gain */
130 {0x2b, 0x00a0}, /* 32*0.03125*2 = 2 */
131 {0x2c, 0x00a0}, /* 32*0.03125*2 = 2 */
132 /* 0x2d: Red Gain */
133 /* 0x2e: Green 2 Gain */
134 {0x2d, 0x00a0}, /* 32*0.03125*2 = 2 */
135 {0x2e, 0x00a0}, /* 32*0.03125*2 = 2 */
136 /* 0x02: Column Start */
137 /* 0x03: Window Hight */
138 {0x02, 0x0016}, /* coulmn 22 */
139 {0x03, 0x01e1}, /* 481 */
140 /* 0x04: Window Width */
141 /* 0x05: Horizontal Blanking */
142 {0x04, 0x0281}, /* 641 */
143 {0x05, 0x0004}, /* 4 columns (pixel clocks) */
144 /* 0x06: Vertical Blanking */
145 /* 0x07: Output Control */
146 {0x06, 0x002d}, /* 45 rows */
147 {0x07, 0x3002}, /* RESERVED options */
148 /* Writes to0x0e: UNDOCUMENTED */
149 {0x0e, 0x0008},
150 /* 0x06: Vertical Blanking */
151 {0x06, 0x002d}, /* 45 rows */
152 /* 0x05: Horizontal Blanking */
153 {0x05, 0x0004}, /* 4 columns (pixel clocks) */
156 static struct micron_init mt9v011_init[] = {
157 /* 0x07: Output Control */
158 {0x07, 0x0002}, /* chip enable, normal operation */
159 /* 0x0d: Soft Reset */
160 {0x0d, 0x0001}, /* reset */
161 /* 0x0d: Soft Reset */
162 {0x0d, 0x0000}, /* resume operation */
163 /* 0x01: Row start */
164 /* 0x02: Column Start */
165 {0x01, 0x0008}, /* start with row 8 */
166 {0x02, 0x0016}, /* start with column 22 */
167 /* 0x03: Window Height */
168 /* 0x04: Window Width */
169 {0x03, 0x01e1}, /* 481 */
170 {0x04, 0x0281}, /* 641 */
171 /* 0x05: Horizontal Blanking */
172 /* 0x06: Vertical Blanking */
173 {0x05, 0x0083}, /* 131 columns (pixel clocks) */
174 {0x06, 0x0006}, /* 6 rows */
175 /* 0x0d: Soft Reset */
176 {0x0d, 0x0002}, /* UNKNOWN */
177 /* 0x0a: Pixel Clock Speed */
178 /* 0x0b: Frame Restart */
179 {0x0a, 0x0000}, /* default */
180 {0x0b, 0x0000}, /* (has no effect/no restart) */
181 /* 0x0c: Shutter Delay */
182 /* 0x0d: Soft Reset */
183 {0x0c, 0x0000}, /* 0 master clocks */
184 {0x0d, 0x0000}, /* resume operation */
185 {0x0e, 0x0000},
186 {0x0f, 0x0000},
187 {0x10, 0x0000},
188 {0x11, 0x0000},
189 /* 0x12: 2X Zoom Column Start (from MT9V111 datasheet) */
190 /* 0x13: 2X Zoom Row Start (from MT9V111 datasheet) */
191 {0x12, 0x0000},
192 /* column 0 => bit0 of reg 0x1e must be set to activate zoom */
193 {0x13, 0x0000},
194 /* row 0 => bit0 of reg 0x1e must be set to activate zoom */
195 {0x14, 0x0000},
196 {0x15, 0x0000},
197 {0x16, 0x0000},
198 {0x17, 0x0000},
199 {0x18, 0x0000},
200 {0x19, 0x0000},
201 {0x1a, 0x0000},
202 {0x1b, 0x0000},
203 {0x1c, 0x0000},
204 {0x1d, 0x0000},
205 {0x32, 0x0000},
206 /* 0x20: Read Mode */
207 {0x20, 0x1101}, /* output all frames (including bad frames) */
208 {0x21, 0x0000},
209 {0x22, 0x0000},
210 {0x23, 0x0000},
211 {0x24, 0x0000},
212 {0x25, 0x0000},
213 {0x26, 0x0000},
214 {0x27, 0x0024},
215 {0x2f, 0xf7b0},
216 {0x30, 0x0005},
217 {0x31, 0x0000},
218 {0x32, 0x0000},
219 {0x33, 0x0000},
220 {0x34, 0x0100},
221 {0x3d, 0x068f},
222 {0x40, 0x01e0},
223 {0x41, 0x00d1},
224 {0x44, 0x0082},
225 {0x5a, 0x0000},
226 {0x5b, 0x0000},
227 {0x5c, 0x0000},
228 {0x5d, 0x0000},
229 {0x5e, 0x0000},
230 {0x5f, 0xa31d},
231 {0x62, 0x0611},
232 /* 0x0a: Pixel Clock Speed */
233 {0x0a, 0x0000}, /* default */
234 /* 0x06: Vertical Blanking */
235 {0x06, 0x0029}, /* 41 rows */
236 /* 0x05: Horizontal Blanking */
237 {0x05, 0x0009}, /* 9 columns (pixel clocks) */
238 /* 0x20: Read Mode */
239 {0x20, 0x1101}, /* output all frames (including bad ones) */
240 /* 0x20: Read Mode */
241 {0x20, 0x1101}, /* output all frames (including bad ones) */
242 /* 0x09: Shutter Width */
243 {0x09, 0x0064}, /* integration of 100 rows */
244 /* 0x07: Output Control */
245 {0x07, 0x0003},
246 /* dont update changes until bit0=0, chip enable, normal operation */
247 /* 0x2b: Green 1 Gain */
248 /* 0x2c: Blue Gain */
249 {0x2b, 0x0033}, /* 51*0.03125*1 = 1.59375 */
250 {0x2c, 0x00a0}, /* 32*0.03125*2 = 2 */
251 /* 0x2d: Red Gain */
252 /* 0x2e: Green 2 Gain */
253 {0x2d, 0x00a0}, /* 32*0.03125*2 = 2 */
254 {0x2e, 0x0033}, /* 51*0.03125*1 = 1.59375 */
255 /* 0x07: Output Control */
256 {0x07, 0x0002}, /* chip enable, normal operation */
257 /* 0x0a: Pixel Clock Speed */
258 {0x06, 0x0000}, /* default */
259 /* 0x06: Vertical Blanking */
260 {0x06, 0x0029}, /* 41 rows */
261 /* 0x05: Horizontal Blanking */
262 {0x05, 0x0009}, /* 9 columns (pixel clocks) */
265 static struct micron_init mt9m111_init[] = {
266 /* Reset sensor */
267 {0x0d, 0x0008},
268 {0x0d, 0x0009},
269 {0x0d, 0x0008},
270 /* Select Page map 0x01
271 * This means all new writes now have the address prefix 0x1.
272 * Example: 0x3a becomes 0x13a. */
273 {0xf0, 0x0001},
274 /** Select output format:
275 * - output raw bayer (8+2 bit)
276 * FIXME: There are nearly all YUV and RGB variants possible.
277 * Maybe we should use them.
279 {0x3a, 0x7300},
280 /* measure atoexposure through a mix of both possible windows */
281 {0x06, 0x308c},
282 /* Switch back to Page map 0x00 */
283 {0xf0, 0x0000},
284 /* The following set the resoutiona and window size.
285 * It's a bit more than SXGA.
286 * VSTART */
287 {0x01, 0x000e},
288 /* HSTART */
289 {0x02, 0x0014},
290 /* VSIZE */
291 {0x03, 0x03c4},
292 /* HSIZE */
293 {0x04, 0x0514},
294 /* Blanking */
295 {0xc8, 0x0003},
296 {0x0a, 0x0001},
297 {0x06, 0x0029},
298 {0x05, 0x0072},
299 {0x20, 0x0000},
300 {0x20, 0x0000},
301 /* Shutter width */
302 {0x09, 0x0190},
303 /* Protect settings */
304 {0x0d, 0x8008},
305 /* Green 1 gain */
306 {0x2b, 0x0188},
307 /* Blue gain */
308 {0x2c, 0x0188},
309 /* Red gain */
310 {0x2d, 0x0188},
311 /* Green 2 gain */
312 {0x2e, 0x0188},
313 /* Blanking (again?) */
314 {0x0a, 0x0001},
315 {0x06, 0x0029},
316 {0x05, 0x0072},
319 static struct micron_init mt9m001_init[] = {
320 {0x07, 0x0000}, {0x07, 0x0002}, {0x0d, 0x0001}, {0x0d, 0x0000},
321 {0x01, 0x000e}, {0x02, 0x0014}, {0x03, 0x03c1}, {0x04, 0x0501},
322 {0x05, 0x0083}, {0x06, 0x0006}, {0x0d, 0x0002}, {0x09, 0x0000},
323 {0x0a, 0x0000}, {0x0b, 0x0000}, {0x0c, 0x0000}, {0x11, 0x0000},
324 {0x1e, 0x8000}, {0x20, 0x1105}, {0x2b, 0x0008}, {0x2c, 0x0010},
325 {0x2d, 0x0014}, {0x2e, 0x0008}, {0x5f, 0x8904}, {0x60, 0x0000},
326 {0x61, 0x0000}, {0x62, 0x0498}, {0x63, 0x0000}, {0x68, 0x0000},
327 {0x20, 0x111d}, {0x06, 0x00f2}, {0x05, 0x0013}, {0x20, 0x111d},
328 {0x20, 0x111d}, {0x07, 0x0003}, {0x2b, 0x0010}, {0x2c, 0x0010},
329 {0x2d, 0x0010}, {0x2e, 0x0010}, {0x07, 0x0002}, {0x07, 0x0003},
330 {0x2c, 0x001d}, {0x2d, 0x001d}, {0x07, 0x0002}, {0x06, 0x00f2},
331 {0x05, 0x0013}, {0x09, 0x0387}, {0x07, 0x0003}, {0x2b, 0x0028},
332 {0x2c, 0x003f}, {0x2d, 0x003f}, {0x2e, 0x0028}, {0x07, 0x0002},
333 {0x09, 0x04f1}, {0x07, 0x0003}, {0x2b, 0x0024}, {0x2c, 0x0039},
334 {0x2d, 0x0039}, {0x2e, 0x0024}, {0x07, 0x0002},
338 * @brief Initialize micron sensors
340 * @param dev Pointer to device structure
342 * @return 0 or negative error code
345 int micron_initialize(struct usb_microdia *dev)
347 int i;
348 int ret = 0;
349 __u16 value;
351 switch (dev->camera.sensor->id) {
352 case MT9V111_SENSOR:
353 mt9v111_select_address_space(dev, MT9V111_ADDRESSSPACE_IFP);
354 for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) {
355 ret = sn9c20x_write_i2c_data16(dev, 1,
356 mt9v111_init[i].address,
357 &(mt9v111_init[i].value));
358 if (ret < 0)
359 goto err;
361 break;
362 case MT9M111_SENSOR:
363 value = 0x0000;
364 sn9c20x_write_i2c_data16(dev, 2, 0xf0, &value);
365 for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) {
366 ret = sn9c20x_write_i2c_data16(dev, 1,
367 mt9m111_init[i].address,
368 &(mt9m111_init[i].value));
369 if (ret < 0)
370 goto err;
372 break;
373 case MT9V011_SENSOR:
374 for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) {
375 ret = sn9c20x_write_i2c_data16(dev, 1,
376 mt9v011_init[i].address,
377 &(mt9v011_init[i].value));
378 if (ret < 0)
379 goto err;
381 break;
382 case MT9M001_SENSOR:
383 for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) {
384 ret = sn9c20x_write_i2c_data16(dev, 1,
385 mt9m001_init[i].address,
386 &(mt9m001_init[i].value));
387 if (ret < 0)
388 goto err;
390 break;
391 default:
392 return -EINVAL;
395 return ret;
397 err:
398 UDIA_ERROR("Sensor Init failed (%d)! - line %d\n", ret, i);
399 return ret;
402 int mt9v111_select_address_space(struct usb_microdia *dev, __u8 address_space)
404 __u8 buf[2];
405 int retI2C;
406 int k;
408 /* check if selection is valid: */
409 if ((address_space != MT9V111_ADDRESSSPACE_IFP) &&
410 (address_space != MT9V111_ADDRESSSPACE_SENSOR)) {
411 UDIA_WARNING("invalid register address space "
412 "selection for sensor MT9V111/MI0360SOC !\n");
413 return -1;
415 /* read address space slection register: */
416 k = 0;
417 retI2C = -1;
418 while ((k < 3) && (retI2C != 0)) {
419 retI2C = sn9c20x_read_i2c_data(dev, 2, 0x01, buf);
420 if (retI2C != 0 && k < 2)
421 udelay(1000);
422 k++;
424 if (retI2C != 0) {
425 UDIA_ERROR("MT9V111/MI0360SOC (I2C-slave 0x5c): "
426 "read of reg0x01 (address space selection) failed !\n");
427 return -1;
429 /* check current address space: */
430 if ((buf[0] != 0x00) || (buf[1] != address_space)) {
431 k = 0;
432 retI2C = -1;
433 while ((k < 3) && (retI2C != 0)) {
434 /* switch address space: */
435 buf[0] = 0x00; buf[1] = address_space;
436 retI2C = sn9c20x_write_i2c_data(dev, 2, 0x01, buf);
437 if (retI2C != 0 && k < 2)
438 udelay(1000);
439 k++;
441 if (retI2C != 0) {
442 if (address_space == MT9V111_ADDRESSSPACE_IFP)
443 UDIA_ERROR("MT9V111/MI0360SOC "
444 "(I2C-slave 0x5c): switch to IFP "
445 "address space failed !\n");
446 else
447 UDIA_ERROR("MT9V111/MI0360SOC "
448 "(I2C-slave 0x5c): switch to sensor "
449 "core address space failed !\n");
450 return -1;
453 return 0;
456 int micron_probe(struct usb_microdia *dev)
458 __u16 buf, old;
459 int ret;
460 static struct sensor_info dummy;
462 /* This is necessary to allow I2C/SCCB operation */
463 dev->camera.sensor = &dummy;
464 dev->camera.sensor->address = 0x5d;
465 sn9c20x_i2c_initialize(dev);
467 /* MT9V011 goes first */
468 ret = sn9c20x_read_i2c_data16(dev, 2, 0xff, &buf);
469 if ((ret == 0) || (buf == 0x8243))
470 return MT9V011_SENSOR;
472 /* MT9V111 has a different address */
473 dev->camera.sensor->address = 0x5c;
475 /* Store old address-space */
476 ret = sn9c20x_read_i2c_data16(dev, 2, 0x01, &old);
477 if (ret != 0)
478 return ret;
480 /* Select address-space: sensor */
481 buf = MT9V111_ADDRESSSPACE_SENSOR & 0x00ff;
482 ret = sn9c20x_write_i2c_data16(dev, 2, 0x01, &buf);
483 if (ret != 0)
484 return ret;
486 ret = sn9c20x_read_i2c_data16(dev, 2, 0xff, &buf);
487 if ((ret == 0) || (buf == 0x823a)) {
488 sn9c20x_write_i2c_data16(dev, 2, 0x01, &old);
489 return MT9V111_SENSOR;
492 return -EINVAL;
495 int mt9m111_set_raw(struct usb_microdia *dev)
497 __u16 buf;
499 /* select address-space: IFP */
500 buf = 0x0001;
501 sn9c20x_write_i2c_data16(dev, 1, 0xf0, &buf);
503 sn9c20x_read_i2c_data16(dev, 1, 0x3a, &buf);
504 buf = (buf & 0xfaff) + 0x0500;
505 sn9c20x_write_i2c_data16(dev, 1, 0x3a, &buf);
507 sn9c20x_read_i2c_data16(dev, 1, 0x9b, &buf);
508 buf = (buf & 0xfaff) + 0x0500;
509 sn9c20x_write_i2c_data16(dev, 1, 0x9b, &buf);
511 sn9c20x_set_raw(dev);
513 return 0;
516 int mt9m111_set_yuv422(struct usb_microdia *dev)
518 __u16 buf;
520 /* select address-space: IFP */
521 buf = 0x0001;
522 sn9c20x_write_i2c_data16(dev, 1, 0xf0, &buf);
524 sn9c20x_read_i2c_data16(dev, 1, 0x3a, &buf);
525 buf &= 0xfaff;
526 sn9c20x_write_i2c_data16(dev, 1, 0x3a, &buf);
528 sn9c20x_read_i2c_data16(dev, 1, 0x9b, &buf);
529 buf &= 0xfaff;
530 sn9c20x_write_i2c_data16(dev, 1, 0x9b, &buf);
532 sn9c20x_set_raw(dev);
534 return 0;
537 int mt9v011_set_exposure(struct usb_microdia *dev)
539 int ret = 0;
540 __u8 buf[2];
542 buf[0] = (dev->vsettings.exposure >> 12);
543 buf[1] = 0;
544 ret |= sn9c20x_write_i2c_data(dev, 2, 0x09, buf);
545 /* Maybe we have to disable AE/AWB/flicker avoidence (currently not
546 * used) for MT9V111 sensor, because IFP controls this register if
547 * one of them is enabled. */
548 return ret;
551 int mt9v111_set_exposure(struct usb_microdia *dev)
553 int ret = 0;
554 __u8 buf[2];
557 ret = mt9v111_select_address_space(dev, MT9V111_ADDRESSSPACE_SENSOR);
559 if (ret < 0)
560 return -11; /* -EAGAIN */
562 buf[0] = (dev->vsettings.exposure >> 12);
563 buf[1] = 0;
564 ret |= sn9c20x_write_i2c_data(dev, 2, 0x09, buf);
565 /* Maybe we have to disable AE/AWB/flicker avoidence (currently not
566 * used) for MT9V111 sensor, because IFP controls this register if
567 * one of them is enabled. */
568 return ret;
571 int mt9v011_set_hvflip(struct usb_microdia *dev)
573 int ret = 0;
574 __u8 buf[2];
576 if ((dev->vsettings.hflip > 1) || (dev->vsettings.hflip < 0))
577 return -EINVAL;
578 if ((dev->vsettings.vflip > 1) || (dev->vsettings.vflip < 0))
579 return -EINVAL;
581 ret = sn9c20x_read_i2c_data(dev, 2, 0x20, buf);
582 if (ret < 0)
583 return ret;
585 if (dev->vsettings.hflip) {
586 buf[0] |= 0x80;
587 /* (MSB) set bit 15: read out from
588 * bottom to top (upside down) */
589 buf[1] |= 0x80;
590 /* (LSB) set bit 7: readout starting 1 row later */
591 } else {
592 buf[0] &= 0x7f; /* (MSB) unset bit 15: normal readout */
593 buf[1] &= 0x7f; /* (LSB) unset bit 7: normal readout */
595 if (dev->vsettings.vflip) {
596 buf[0] |= 0x40;
597 /* (MSB) set bit 14: read out from right to left (mirrored) */
598 buf[1] |= 0x20;
599 /* (LSB) set bit 5: readout starting 1 column later */
600 } else {
601 buf[0] &= 0xbf; /* (MSB) unset bit 14: normal readout */
602 buf[1] &= 0xdf; /* (LSB) unset bit 5: normal readout */
605 ret = sn9c20x_write_i2c_data(dev, 2, 0x20, buf);
606 return ret;
609 int mt9v111_set_hvflip(struct usb_microdia *dev)
611 int ret = 0;
612 __u8 buf[2];
614 if ((dev->vsettings.hflip > 1) || (dev->vsettings.hflip < 0))
615 return -EINVAL;
616 if ((dev->vsettings.vflip > 1) || (dev->vsettings.vflip < 0))
617 return -EINVAL;
620 ret = mt9v111_select_address_space(dev, MT9V111_ADDRESSSPACE_SENSOR);
621 if (ret < 0)
622 return -11; /* -EAGAIN */
624 ret = sn9c20x_read_i2c_data(dev, 2, 0x20, buf);
625 if (ret < 0)
626 return ret;
628 if (dev->vsettings.hflip) {
629 buf[0] |= 0x80;
630 /* (MSB) set bit 15: read out from
631 * bottom to top (upside down) */
632 buf[1] |= 0x80;
633 /* (LSB) set bit 7: readout starting 1 row later */
634 } else {
635 buf[0] &= 0x7f; /* (MSB) unset bit 15: normal readout */
636 buf[1] &= 0x7f; /* (LSB) unset bit 7: normal readout */
638 if (dev->vsettings.vflip) {
639 buf[0] |= 0x40;
640 /* (MSB) set bit 14: read out from right to left (mirrored) */
641 buf[1] |= 0x20;
642 /* (LSB) set bit 5: readout starting 1 column later */
643 } else {
644 buf[0] &= 0xbf; /* (MSB) unset bit 14: normal readout */
645 buf[1] &= 0xdf; /* (LSB) unset bit 5: normal readout */
648 ret = sn9c20x_write_i2c_data(dev, 2, 0x20, buf);
649 return ret;
652 int mt9v111_set_autoexposure(struct usb_microdia *dev)
654 __u16 buf[1];
655 int ret = 0;
657 /* Switch to IFP-register address space: */
658 ret = mt9v111_select_address_space(dev, MT9V111_ADDRESSSPACE_IFP);
659 if (ret < 0)
660 return -11; /* -EAGAIN */
661 /* Read current value of IFP-register 0x06: */
662 ret = sn9c20x_read_i2c_data16(dev, 1, MT9V111_IFPREG_OPMODECTL, buf);
663 if (ret < 0) {
664 UDIA_ERROR("Error: setting of auto exposure failed: "
665 "error while reading from IFP-register 0x06\n");
666 return ret;
669 /* Set new value for register 0x06: */
670 switch (dev->vsettings.auto_exposure) {
671 case V4L2_EXPOSURE_AUTO:
672 buf[0] |= MT9V111_IFP_OPMODE_AUTOEXPOSURE;
673 break;
674 case V4L2_EXPOSURE_MANUAL:
675 buf[0] &= ~MT9V111_IFP_OPMODE_AUTOEXPOSURE;
676 break;
677 case V4L2_EXPOSURE_SHUTTER_PRIORITY:
678 buf[0] &= ~MT9V111_IFP_OPMODE_AUTOEXPOSURE;
679 break;
680 case V4L2_EXPOSURE_APERTURE_PRIORITY:
681 buf[0] |= MT9V111_IFP_OPMODE_AUTOEXPOSURE;
682 break;
683 default:
684 return -EINVAL;
686 /* Write new value to IFP-register 0x06: */
687 ret = sn9c20x_write_i2c_data16(dev, 1, MT9V111_IFPREG_OPMODECTL, buf);
688 if (ret < 0) {
689 UDIA_ERROR("Error: setting of auto exposure failed: "
690 "error while writing to IFP-register 0x06\n");
691 return ret;
693 return 0;
696 int mt9v111_set_autowhitebalance(struct usb_microdia *dev)
698 __u16 buf[1];
699 int ret = 0;
701 /* Switch to IFP-register address space: */
702 ret = mt9v111_select_address_space(dev, MT9V111_ADDRESSSPACE_IFP);
703 if (ret < 0)
704 return -11; /* -EAGAIN */
705 /* Read current value of IFP-register 0x06: */
706 ret = sn9c20x_read_i2c_data16(dev, 1,
707 MT9V111_IFPREG_OPMODECTL, buf);
708 if (ret < 0) {
709 UDIA_ERROR("Error: setting of auto whitebalance failed: "
710 "error while reading from IFP-register 0x06\n");
711 return ret;
713 /* Set new value for register 0x06: */
714 if (dev->vsettings.auto_whitebalance == 1) {
715 /* Enable automatic exposure: */
716 buf[0] |= MT9V111_IFP_OPMODE_AUTOWHITEBALANCE;
717 } else if (dev->vsettings.auto_whitebalance == 0) {
718 /* Disable automatic exposure: */
719 buf[0] &= ~MT9V111_IFP_OPMODE_AUTOWHITEBALANCE;
720 } else
721 return -EINVAL;
722 /* Write new value to IFP-register 0x06:*/
723 ret = sn9c20x_write_i2c_data16(dev, 1,
724 MT9V111_IFPREG_OPMODECTL, buf);
725 if (ret < 0) {
726 UDIA_ERROR("Error: setting of auto whitebalance failed: "
727 "error while writing to IFP-register 0x06\n");
728 return ret;
730 return 0;