6 * @brief Common functions and data for Micron sensors.
8 * @note Copyright (C) Comer352l
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
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>
37 static struct micron_init mt9v111_init
[] = {
38 /* 0x0d: Color Correction Register 8 */
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 /* 0x06: Operating Mode Control */
51 {0x05, 0x0004}, /* 100% sharpening,
52 no automatic sharpness reduction at low light: no sharpening */
53 {0x06, 0x0000}, /* stop AWB at the current values,
54 no on-the-fly defect correction, no auto exposure */
55 /* 0x07: IFP Soft Reset */
56 /* 0x08: Output Format Control */
57 {0x07, 0x3002}, /* reset */
58 {0x08, 0x0480}, /* bypass entire image processing,
59 raw 8+2 Bayer data output directly */
60 {0x01, 0x0004}, /* select sensor address space */
61 {0x02, 0x0016}, /* start with column 22 */
62 /* 0x03: Window Height */
63 /* 0x04: Window Width */
64 {0x03, 0x01e6}, /* 486 */
65 {0x04, 0x0286}, /* 646 */
66 /* 0x05: Horizontal Blanking */
67 /* 0x06: Vertical Blanking */
68 {0x05, 0x0004}, /* 4 columns (pixel clocks) */
69 {0x06, 0x0000}, /* 0 rows */
70 /* 0x07: Output Control */
72 {0x07, 0x3002}, /* normal operation + chip enable*/
73 {0x08, 0x0008}, /* row 8 */
74 /* 0x0c: Shutter Delay */
75 /* 0x0d: Reset (Soft) */
76 {0x0c, 0x0000}, /* 0 master clocks */
77 {0x0d, 0x0000}, /* return to normal operation */
82 /* 0x12: 2X Zoom Col Start
83 => 0x1e bit 0 must be set to activate zoom */
84 /* 0x13: 2X Zoom Row Start
85 => 0x1e bit 0 must be set to activate zoom */
86 {0x12, 0x00b0}, /* column 176 */
87 {0x13, 0x007c}, /* row 124 */
101 /* 0x02: Column Start */
102 /* 0x03: Window Height */
103 {0x02, 0x0016}, /* coulmn 22 */
104 {0x03, 0x01e1}, /* 481 */
105 /* 0x04: Window Width */
106 /* 0x05: Horizontal Blanking */
107 {0x04, 0x0281}, /* 641 */
108 {0x05, 0x0004}, /* 4 columns (pixel clocks) */
109 /* 0x06: Vertical Blanking */
110 /* 0x07: Output Control */
111 {0x06, 0x0000}, /* 0 rows */
112 {0x07, 0x3002}, /* normal operation + chip enable */
113 /* 0x06: Vertical Blanking */
114 {0x06, 0x002d}, /* 45 rows */
115 /* 0x05: Horizontal Blanking */
116 {0x05, 0x0004}, /* 4 columns (pixel clocks) */
117 /* 0x09: Shutter Width */
118 {0x09, 0x0064}, /* integration of 100 rows */
119 /* 0x2b: Green 1 Gain */
120 /* 0x2c: Blue Gain */
121 {0x2b, 0x00a0}, /* 32*0.03125*2 = 2 */
122 {0x2c, 0x00a0}, /* 32*0.03125*2 = 2 */
124 /* 0x2e: Green 2 Gain */
125 {0x2d, 0x00a0}, /* 32*0.03125*2 = 2 */
126 {0x2e, 0x00a0}, /* 32*0.03125*2 = 2 */
127 /* 0x02: Column Start */
128 /* 0x03: Window Hight */
129 {0x02, 0x0016}, /* coulmn 22 */
130 {0x03, 0x01e1}, /* 481 */
131 /* 0x04: Window Width */
132 /* 0x05: Horizontal Blanking */
133 {0x04, 0x0281}, /* 641 */
134 {0x05, 0x0004}, /* 4 columns (pixel clocks) */
135 /* 0x06: Vertical Blanking */
136 /* 0x07: Output Control */
137 {0x06, 0x002d}, /* 45 rows */
138 {0x07, 0x3002}, /* RESERVED options */
139 /* Writes to0x0e: UNDOCUMENTED */
141 /* 0x06: Vertical Blanking */
142 {0x06, 0x002d}, /* 45 rows */
143 /* 0x05: Horizontal Blanking */
144 {0x05, 0x0004}, /* 4 columns (pixel clocks) */
147 static struct micron_init mt9v011_init
[] = {
148 /* 0x07: Output Control */
149 {0x07, 0x0002}, /* chip enable, normal operation */
150 /* 0x0d: Soft Reset */
151 {0x0d, 0x0001}, /* reset */
152 /* 0x0d: Soft Reset */
153 {0x0d, 0x0000}, /* resume operation */
154 /* 0x01: Row start */
155 /* 0x02: Column Start */
156 {0x01, 0x0008}, /* start with row 8 */
157 {0x02, 0x0016}, /* start with column 22 */
158 /* 0x03: Window Height */
159 /* 0x04: Window Width */
160 {0x03, 0x01e1}, /* 481 */
161 {0x04, 0x0281}, /* 641 */
162 /* 0x05: Horizontal Blanking */
163 /* 0x06: Vertical Blanking */
164 {0x05, 0x0083}, /* 131 columns (pixel clocks) */
165 {0x06, 0x0006}, /* 6 rows */
166 /* 0x0d: Soft Reset */
167 {0x0d, 0x0002}, /* UNKNOWN */
168 /* 0x0a: Pixel Clock Speed */
169 /* 0x0b: Frame Restart */
170 {0x0a, 0x0000}, /* default */
171 {0x0b, 0x0000}, /* (has no effect/no restart) */
172 /* 0x0c: Shutter Delay */
173 /* 0x0d: Soft Reset */
174 {0x0c, 0x0000}, /* 0 master clocks */
175 {0x0d, 0x0000}, /* resume operation */
180 /* 0x12: 2X Zoom Column Start (from MT9V111 datasheet) */
181 /* 0x13: 2X Zoom Row Start (from MT9V111 datasheet) */
183 /* column 0 => bit0 of reg 0x1e must be set to activate zoom */
185 /* row 0 => bit0 of reg 0x1e must be set to activate zoom */
197 /* 0x20: Read Mode */
198 {0x20, 0x1101}, /* output all frames (including bad frames) */
223 /* 0x0a: Pixel Clock Speed */
224 {0x0a, 0x0000}, /* default */
225 /* 0x06: Vertical Blanking */
226 {0x06, 0x0029}, /* 41 rows */
227 /* 0x05: Horizontal Blanking */
228 {0x05, 0x0009}, /* 9 columns (pixel clocks) */
229 /* 0x20: Read Mode */
230 {0x20, 0x1101}, /* output all frames (including bad ones) */
231 /* 0x20: Read Mode */
232 {0x20, 0x1101}, /* output all frames (including bad ones) */
233 /* 0x09: Shutter Width */
234 {0x09, 0x0064}, /* integration of 100 rows */
235 /* 0x07: Output Control */
237 /* dont update changes until bit0=0, chip enable, normal operation */
238 /* 0x2b: Green 1 Gain */
239 /* 0x2c: Blue Gain */
240 {0x2b, 0x0033}, /* 51*0.03125*1 = 1.59375 */
241 {0x2c, 0x00a0}, /* 32*0.03125*2 = 2 */
243 /* 0x2e: Green 2 Gain */
244 {0x2d, 0x00a0}, /* 32*0.03125*2 = 2 */
245 {0x2e, 0x0033}, /* 51*0.03125*1 = 1.59375 */
246 /* 0x07: Output Control */
247 {0x07, 0x0002}, /* chip enable, normal operation */
248 /* 0x0a: Pixel Clock Speed */
249 {0x06, 0x0000}, /* default */
250 /* 0x06: Vertical Blanking */
251 {0x06, 0x0029}, /* 41 rows */
252 /* 0x05: Horizontal Blanking */
253 {0x05, 0x0009}, /* 9 columns (pixel clocks) */
256 static struct micron_init mt9m111_init
[] = {
261 /* Select Page map 0x01
262 * This means all new writes now have the address prefix 0x1.
263 * Example: 0x3a becomes 0x13a. */
265 /** Select output format:
266 * - output raw bayer (8+2 bit)
267 * FIXME: There are nearly all YUV and RGB variants possible.
268 * Maybe we should use them.
271 /* measure atoexposure through a mix of both possible windows */
273 /* Switch back to Page map 0x00 */
275 /* The following set the resoutiona and window size.
276 * It's a bit more than SXGA.
294 /* Protect settings */
304 /* Blanking (again?) */
310 static struct micron_init mt9m001_init
[] = {
311 {0x07, 0x0000}, {0x07, 0x0002}, {0x0d, 0x0001}, {0x0d, 0x0000},
312 {0x01, 0x000e}, {0x02, 0x0014}, {0x03, 0x03c1}, {0x04, 0x0501},
313 {0x05, 0x0083}, {0x06, 0x0006}, {0x0d, 0x0002}, {0x09, 0x0000},
314 {0x0a, 0x0000}, {0x0b, 0x0000}, {0x0c, 0x0000}, {0x11, 0x0000},
315 {0x1e, 0x8000}, {0x20, 0x1105}, {0x2b, 0x0008}, {0x2c, 0x0010},
316 {0x2d, 0x0014}, {0x2e, 0x0008}, {0x5f, 0x8904}, {0x60, 0x0000},
317 {0x61, 0x0000}, {0x62, 0x0498}, {0x63, 0x0000}, {0x68, 0x0000},
318 {0x20, 0x111d}, {0x06, 0x00f2}, {0x05, 0x0013}, {0x20, 0x111d},
319 {0x20, 0x111d}, {0x07, 0x0003}, {0x2b, 0x0010}, {0x2c, 0x0010},
320 {0x2d, 0x0010}, {0x2e, 0x0010}, {0x07, 0x0002}, {0x07, 0x0003},
321 {0x2c, 0x001d}, {0x2d, 0x001d}, {0x07, 0x0002}, {0x06, 0x00f2},
322 {0x05, 0x0013}, {0x09, 0x0387}, {0x07, 0x0003}, {0x2b, 0x0028},
323 {0x2c, 0x003f}, {0x2d, 0x003f}, {0x2e, 0x0028}, {0x07, 0x0002},
324 {0x09, 0x04f1}, {0x07, 0x0003}, {0x2b, 0x0024}, {0x2c, 0x0039},
325 {0x2d, 0x0039}, {0x2e, 0x0024}, {0x07, 0x0002},
329 * @brief Initialize micron sensors
331 * @param dev Pointer to device structure
333 * @return 0 or negative error code
336 int micron_initialize(struct usb_microdia
*dev
)
342 switch (dev
->camera
.sensor
->id
) {
344 mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_IFP
);
345 for (i
= 0; i
< ARRAY_SIZE(mt9v111_init
); i
++) {
346 ret
= sn9c20x_write_i2c_data16(dev
, 1,
347 mt9v111_init
[i
].address
,
348 &(mt9v111_init
[i
].value
));
352 mt9v111_setup_autoexposure(dev
);
353 mt9v111_setup_autowhitebalance(dev
);
354 mt9v111_set_autocorrections(dev
, 1);
358 sn9c20x_write_i2c_data16(dev
, 2, 0xf0, &value
);
359 for (i
= 0; i
< ARRAY_SIZE(mt9m111_init
); i
++) {
360 ret
= sn9c20x_write_i2c_data16(dev
, 1,
361 mt9m111_init
[i
].address
,
362 &(mt9m111_init
[i
].value
));
368 for (i
= 0; i
< ARRAY_SIZE(mt9v011_init
); i
++) {
369 ret
= sn9c20x_write_i2c_data16(dev
, 1,
370 mt9v011_init
[i
].address
,
371 &(mt9v011_init
[i
].value
));
377 for (i
= 0; i
< ARRAY_SIZE(mt9m001_init
); i
++) {
378 ret
= sn9c20x_write_i2c_data16(dev
, 1,
379 mt9m001_init
[i
].address
,
380 &(mt9m001_init
[i
].value
));
392 UDIA_ERROR("Sensor Init failed (%d)! - line %d\n", ret
, i
);
396 int mt9v111_select_address_space(struct usb_microdia
*dev
, __u8 address_space
)
402 /* check if selection is valid: */
403 if ((address_space
!= MT9V111_ADDRESSSPACE_IFP
) &&
404 (address_space
!= MT9V111_ADDRESSSPACE_SENSOR
)) {
405 UDIA_WARNING("invalid register address space "
406 "selection for sensor MT9V111/MI0360SOC !\n");
409 /* read address space slection register: */
412 while ((k
< 3) && (retI2C
!= 0)) {
413 retI2C
= sn9c20x_read_i2c_data(dev
, 2, 0x01, buf
);
414 if (retI2C
!= 0 && k
< 2)
419 UDIA_ERROR("MT9V111/MI0360SOC (I2C-slave 0x5c): "
420 "read of reg0x01 (address space selection) failed !\n");
423 /* check current address space: */
424 if ((buf
[0] != 0x00) || (buf
[1] != address_space
)) {
427 while ((k
< 3) && (retI2C
!= 0)) {
428 /* switch address space: */
429 buf
[0] = 0x00; buf
[1] = address_space
;
430 retI2C
= sn9c20x_write_i2c_data(dev
, 2, 0x01, buf
);
431 if (retI2C
!= 0 && k
< 2)
436 if (address_space
== MT9V111_ADDRESSSPACE_IFP
)
437 UDIA_ERROR("MT9V111/MI0360SOC "
438 "(I2C-slave 0x5c): switch to IFP "
439 "address space failed !\n");
441 UDIA_ERROR("MT9V111/MI0360SOC "
442 "(I2C-slave 0x5c): switch to sensor "
443 "core address space failed !\n");
450 int micron_probe(struct usb_microdia
*dev
)
454 static struct sensor_info dummy
;
456 /* This is necessary to allow I2C/SCCB operation */
457 dev
->camera
.sensor
= &dummy
;
458 dev
->camera
.sensor
->address
= 0x5d;
459 sn9c20x_i2c_initialize(dev
);
461 /* MT9V011 goes first */
462 ret
= sn9c20x_read_i2c_data16(dev
, 2, 0xff, &buf
);
463 if ((ret
== 0) || (buf
== 0x8243))
464 return MT9V011_SENSOR
;
466 /* MT9V111 has a different address */
467 dev
->camera
.sensor
->address
= 0x5c;
469 /* Store old address-space */
470 ret
= sn9c20x_read_i2c_data16(dev
, 2, 0x01, &old
);
474 /* Select address-space: sensor */
475 buf
= MT9V111_ADDRESSSPACE_SENSOR
& 0x00ff;
476 ret
= sn9c20x_write_i2c_data16(dev
, 2, 0x01, &buf
);
480 ret
= sn9c20x_read_i2c_data16(dev
, 2, 0xff, &buf
);
481 if ((ret
== 0) || (buf
== 0x823a)) {
482 sn9c20x_write_i2c_data16(dev
, 2, 0x01, &old
);
483 return MT9V111_SENSOR
;
489 int mt9m111_set_raw(struct usb_microdia
*dev
)
493 /* select address-space: IFP */
495 sn9c20x_write_i2c_data16(dev
, 1, 0xf0, &buf
);
497 sn9c20x_read_i2c_data16(dev
, 1, 0x3a, &buf
);
498 buf
= (buf
& 0xfaff) + 0x0500;
499 sn9c20x_write_i2c_data16(dev
, 1, 0x3a, &buf
);
501 sn9c20x_read_i2c_data16(dev
, 1, 0x9b, &buf
);
502 buf
= (buf
& 0xfaff) + 0x0500;
503 sn9c20x_write_i2c_data16(dev
, 1, 0x9b, &buf
);
505 sn9c20x_set_raw(dev
);
510 int mt9m111_set_yuv422(struct usb_microdia
*dev
)
514 /* select address-space: IFP */
516 sn9c20x_write_i2c_data16(dev
, 1, 0xf0, &buf
);
518 sn9c20x_read_i2c_data16(dev
, 1, 0x3a, &buf
);
520 sn9c20x_write_i2c_data16(dev
, 1, 0x3a, &buf
);
522 sn9c20x_read_i2c_data16(dev
, 1, 0x9b, &buf
);
524 sn9c20x_write_i2c_data16(dev
, 1, 0x9b, &buf
);
526 sn9c20x_set_raw(dev
);
531 int mt9v111_setup_autoexposure(struct usb_microdia
*dev
)
537 /* Switch to IFP-register address space: */
538 ret
= mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_IFP
);
540 return -11; /* -EAGAIN */
541 /* Set target luminance and tracking accuracy: */
542 buf
[0] = MT9V111_IFP_AE_TRACKINGACCURACY(12)
543 /* 0-255 (default: 16) */
544 | MT9V111_IFP_AE_TARGETLUMINANCE(100);
545 /* 0-255 (default: 100) */
546 ret
= sn9c20x_write_i2c_data16(dev
, 1,
547 MT9V111_IFPREG_AE_TARGETLUMCTL
, buf
);
548 /* Set speed and sensitivity: */
549 buf
[0] = MT9V111_IFP_AE_DELAY(4)
550 /* 0-7 (fastest-slowest) (default: 4) */
551 | MT9V111_IFP_AE_SPEED(4)
552 /* 0-7 (fastest-slowest) (default: 4) */
553 | MT9V111_IFP_AE_STEPSIZE_MEDIUM
;
554 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
555 MT9V111_IFPREG_AE_SPEEDSENSCTL
, buf
);
556 /* Horizontal boundaries of AE measurement window: */
557 buf
[0] = MT9V111_IFP_AE_WINBOUNDARY_RIGHT(1020)
558 /* 0-1020 (pixel) (default: 1020) */
559 | MT9V111_IFP_AE_WINBOUNDARY_LEFT(12);
560 /* 0-1020 (pixel) (default: 12) */
561 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
562 MT9V111_IFPREG_AE_HWINBOUNDARY
, buf
);
563 /* Vertical boundaries of AE measurement window: */
564 buf
[0] = MT9V111_IFP_AE_WINBOUNDARY_BOTTOM(510)
565 /* 0-510 (pixel) (default: 510) */
566 | MT9V111_IFP_AE_WINBOUNDARY_TOP(32);
567 /* 0-510 (pixel) (default: 32) */
568 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
569 MT9V111_IFPREG_AE_VWINBOUNDARY
, buf
);
570 /* Horizontal boundaries of AE measurement window
571 * for back light compensation: */
572 buf
[0] = MT9V111_IFP_AE_WINBOUNDARY_RIGHT_BLC(480)
573 /* 0-1020 (pixel) (default: 480) */
574 | MT9V111_IFP_AE_WINBOUNDARY_LEFT_BLC(160);
575 /* 0-1020 (pixel) (default: 160) */
576 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
577 MT9V111_IFPREG_AE_HWINBOUNDARY_BLC
, buf
);
578 /* Vertical boundaries of AE measurement window
579 * for back light compensation: */
580 buf
[0] = MT9V111_IFP_AE_WINBOUNDARY_BOTTOM_BLC(360)
581 /* 0-510 (pixel) (default: 360) */
582 | MT9V111_IFP_AE_WINBOUNDARY_TOP_BLC(120);
583 /* 0-510 (pixel) (default: 120) */
584 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
585 MT9V111_IFPREG_AE_VWINBOUNDARY_BLC
, buf
);
586 /* Set digital gains limit: */
587 buf
[0] = MT9V111_IFP_AE_MAXGAIN_POSTLS(64)
588 /* 0-255 (default: 64) */
589 | MT9V111_IFP_AE_MAXGAIN_PRELS(16);
590 /* 0-255 (default: 16) */
591 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
592 MT9V111_IFPREG_AE_DGAINSLIMITS
, buf
);
593 /* Read current value of IFP-register 0x06: */
594 ret2
= sn9c20x_read_i2c_data16(dev
, 1, MT9V111_IFPREG_OPMODECTL
, buf
);
596 /* Set new value for register 0x06: */
597 buf
[0] = (buf
[0] & 0xffe3) | MT9V111_IFP_AE_WIN_COMBINED
|
598 MT9V111_IFP_OPMODE_BYPASSCOLORCORR
;
599 /* NOTE: BYPASS COLOR CORRECTION HAS
600 * TO BE SET FOR PERMANENT AE ! */
601 /* Write new value to IFP-register 0x06:*/
602 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
603 MT9V111_IFPREG_OPMODECTL
, buf
);
605 if (ret
< 0 || ret2
< 0) {
606 UDIA_WARNING("One or more errors occured during "
607 "setup of AE registers.\n");
613 int mt9v111_setup_autowhitebalance(struct usb_microdia
*dev
)
618 /* Switch to IFP-register address space: */
619 ret
= mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_IFP
);
621 return -11; /* -EAGAIN */
623 buf
[0] = MT9V111_IFP_AWB_ADDON_RED(0) /* 0-255 (default: 0) */
624 | MT9V111_IFP_AWB_ADDON_BLUE(0); /* 0-255 (default: 0) */
625 ret
= sn9c20x_write_i2c_data16(dev
, 1, MT9V111_IFPREG_AWB_TINT
, buf
);
626 /* Set AWB speed and color saturation: */
627 buf
[0] = MT9V111_IFP_AWB_SATURATION_FULL
628 | MT9V111_IFP_AWB_AUTOSATLOWLIGHT_ENABLE
629 | MT9V111_IFP_AWB_DELAY(4)
630 /* 0-7 (fastest-slowest) (default: 4) */
631 | MT9V111_IFP_AWB_SPEED(4);
632 /* 0-7 (fastest-slowest) (default: 4) */
633 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
634 MT9V111_IFPREG_AWB_SPEEDCOLORSATCTL
, buf
);
635 /* Boundaries of AWB measurement window: */
636 buf
[0] = MT9V111_IFP_AWB_WINBOUNDARY_TOP(0)
637 /* 0-480 (pixel) (default: 0) */
638 | MT9V111_IFP_AWB_WINBOUNDARY_BOTTOM(480)
639 /* 0-480 (pixel) (default: 448) */
640 | MT9V111_IFP_AWB_WINBOUNDARY_LEFT(0)
641 /* 0-960 (pixel) (default: 0) */
642 | MT9V111_IFP_AWB_WINBOUNDARY_RIGHT(640);
643 /* 0-960 (pixel) (default: 640) */
644 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
645 MT9V111_IFPREG_AWB_WINBOUNDARY
, buf
);
648 UDIA_WARNING("One or more errors occured during "
649 "setup of AWB registers.\n");
655 int mt9v011_set_exposure(struct usb_microdia
*dev
)
660 buf
[0] = (dev
->vsettings
.exposure
>> 12);
662 ret
|= sn9c20x_write_i2c_data(dev
, 2, 0x09, buf
);
663 /* Maybe we have to disable AE/AWB/flicker avoidence (currently not
664 * used) for MT9V111 sensor, because IFP controls this register if
665 * one of them is enabled. */
669 int mt9v111_set_exposure(struct usb_microdia
*dev
)
675 ret
= mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_SENSOR
);
678 return -11; /* -EAGAIN */
680 buf
[0] = (dev
->vsettings
.exposure
>> 12);
682 ret
|= sn9c20x_write_i2c_data(dev
, 2, 0x09, buf
);
683 /* Maybe we have to disable AE/AWB/flicker avoidence (currently not
684 * used) for MT9V111 sensor, because IFP controls this register if
685 * one of them is enabled. */
689 int mt9v011_set_hvflip(struct usb_microdia
*dev
)
694 if ((dev
->vsettings
.hflip
> 1) || (dev
->vsettings
.hflip
< 0))
696 if ((dev
->vsettings
.vflip
> 1) || (dev
->vsettings
.vflip
< 0))
699 ret
= sn9c20x_read_i2c_data(dev
, 2, 0x20, buf
);
703 if (dev
->vsettings
.hflip
) {
705 /* (MSB) set bit 15: read out from
706 * bottom to top (upside down) */
708 /* (LSB) set bit 7: readout starting 1 row later */
710 buf
[0] &= 0x7f; /* (MSB) unset bit 15: normal readout */
711 buf
[1] &= 0x7f; /* (LSB) unset bit 7: normal readout */
713 if (dev
->vsettings
.vflip
) {
715 /* (MSB) set bit 14: read out from right to left (mirrored) */
717 /* (LSB) set bit 5: readout starting 1 column later */
719 buf
[0] &= 0xbf; /* (MSB) unset bit 14: normal readout */
720 buf
[1] &= 0xdf; /* (LSB) unset bit 5: normal readout */
723 ret
= sn9c20x_write_i2c_data(dev
, 2, 0x20, buf
);
727 int mt9v111_set_hvflip(struct usb_microdia
*dev
)
732 if ((dev
->vsettings
.hflip
> 1) || (dev
->vsettings
.hflip
< 0))
734 if ((dev
->vsettings
.vflip
> 1) || (dev
->vsettings
.vflip
< 0))
738 ret
= mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_SENSOR
);
740 return -11; /* -EAGAIN */
742 ret
= sn9c20x_read_i2c_data(dev
, 2, 0x20, buf
);
746 if (dev
->vsettings
.hflip
) {
748 /* (MSB) set bit 15: read out from
749 * bottom to top (upside down) */
751 /* (LSB) set bit 7: readout starting 1 row later */
753 buf
[0] &= 0x7f; /* (MSB) unset bit 15: normal readout */
754 buf
[1] &= 0x7f; /* (LSB) unset bit 7: normal readout */
756 if (dev
->vsettings
.vflip
) {
758 /* (MSB) set bit 14: read out from right to left (mirrored) */
760 /* (LSB) set bit 5: readout starting 1 column later */
762 buf
[0] &= 0xbf; /* (MSB) unset bit 14: normal readout */
763 buf
[1] &= 0xdf; /* (LSB) unset bit 5: normal readout */
766 ret
= sn9c20x_write_i2c_data(dev
, 2, 0x20, buf
);
770 int mt9v111_set_autoexposure(struct usb_microdia
*dev
)
775 /* Switch to IFP-register address space: */
776 ret
= mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_IFP
);
778 return -11; /* -EAGAIN */
779 /* Read current value of IFP-register 0x06: */
780 ret
= sn9c20x_read_i2c_data16(dev
, 1, MT9V111_IFPREG_OPMODECTL
, buf
);
782 UDIA_ERROR("Error: setting of auto exposure failed: "
783 "error while reading from IFP-register 0x06\n");
787 /* Set new value for register 0x06: */
788 switch (dev
->vsettings
.auto_exposure
) {
789 case V4L2_EXPOSURE_AUTO
:
790 buf
[0] |= MT9V111_IFP_OPMODE_AUTOEXPOSURE
;
792 case V4L2_EXPOSURE_MANUAL
:
793 buf
[0] &= ~MT9V111_IFP_OPMODE_AUTOEXPOSURE
;
795 case V4L2_EXPOSURE_SHUTTER_PRIORITY
:
796 buf
[0] &= ~MT9V111_IFP_OPMODE_AUTOEXPOSURE
;
798 case V4L2_EXPOSURE_APERTURE_PRIORITY
:
799 buf
[0] |= MT9V111_IFP_OPMODE_AUTOEXPOSURE
;
804 /* Write new value to IFP-register 0x06: */
805 ret
= sn9c20x_write_i2c_data16(dev
, 1, MT9V111_IFPREG_OPMODECTL
, buf
);
807 UDIA_ERROR("Error: setting of auto exposure failed: "
808 "error while writing to IFP-register 0x06\n");
814 int mt9v111_set_autowhitebalance(struct usb_microdia
*dev
)
819 /* Switch to IFP-register address space: */
820 ret
= mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_IFP
);
822 return -11; /* -EAGAIN */
823 /* Read current value of IFP-register 0x06: */
824 ret
= sn9c20x_read_i2c_data16(dev
, 1,
825 MT9V111_IFPREG_OPMODECTL
, buf
);
827 UDIA_ERROR("Error: setting of auto whitebalance failed: "
828 "error while reading from IFP-register 0x06\n");
831 /* Set new value for register 0x06: */
832 if (dev
->vsettings
.auto_whitebalance
== 1) {
833 /* Enable automatic exposure: */
834 buf
[0] |= MT9V111_IFP_OPMODE_AUTOWHITEBALANCE
;
835 } else if (dev
->vsettings
.auto_whitebalance
== 0) {
836 /* Disable automatic exposure: */
837 buf
[0] &= ~MT9V111_IFP_OPMODE_AUTOWHITEBALANCE
;
840 /* Write new value to IFP-register 0x06:*/
841 ret
= sn9c20x_write_i2c_data16(dev
, 1,
842 MT9V111_IFPREG_OPMODECTL
, buf
);
844 UDIA_ERROR("Error: setting of auto whitebalance failed: "
845 "error while writing to IFP-register 0x06\n");
851 int mt9v111_set_autocorrections(struct usb_microdia
*dev
, int enable
)
856 /* Switch to IFP-register address space: */
857 ret
= mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_IFP
);
859 return -11; /* -EAGAIN */
860 /* Read current value of IFP-register 0x06: */
861 ret
= sn9c20x_read_i2c_data16(dev
, 1,
862 MT9V111_IFPREG_OPMODECTL
, buf
);
864 UDIA_ERROR("Error: setting of sensor auto-correction functions "
865 "failed: error while reading from IFP-register 0x06\n");
868 /* Set new value for register 0x06: */
870 buf
[0] |= MT9V111_IFP_OPMODE_APERTURECORR
|
871 MT9V111_IFP_OPMODE_ONTHEFLYDEFECTCORR
;
872 else if (enable
== 0)
873 buf
[0] &= ~(MT9V111_IFP_OPMODE_APERTURECORR
|
874 MT9V111_IFP_OPMODE_ONTHEFLYDEFECTCORR
);
877 /* Write new value to IFP-register 0x06: */
878 ret
= sn9c20x_write_i2c_data16(dev
, 1,
879 MT9V111_IFPREG_OPMODECTL
, buf
);
881 UDIA_ERROR("Error: setting of sensor auto-correction functions "
882 "failed: error while writing to IFP-register 0x06\n");