6 * @brief Common functions and data for the Micron MT9Vx11 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>
33 struct microdia_video_format mt9vx11_fmts
[] = {
35 .pix_fmt
= V4L2_PIX_FMT_SBGGR8
,
36 .desc
= "Bayer 8bit (BGGR)",
38 .set_format
= sn9c20x_set_raw
41 .pix_fmt
= V4L2_PIX_FMT_JPEG
,
42 .desc
= "JPEG (YUV 4:2:2)",
44 .set_format
= sn9c20x_set_jpeg
48 struct microdia_video_resolution mt9vx11_resolutions
[] = {
52 .scale
= SN9C20X_1_4_SCALE
,
53 .window
= {2, 2, 640, 480}
58 .scale
= SN9C20X_1_2_SCALE
,
59 .window
= {2, 2, 640, 480}
64 .scale
= SN9C20X_NO_SCALE
,
65 .window
= {2, 2, 640, 480}
69 static __u8 mt9v111_init
[][3] = {
70 /* 0x0d: Color Correction Register 8 */
72 /* 0x0d: Color Correction Register 8 */
73 {0x0d ,0x00, 0x00}, /* ??? */
74 /* 0x02: Color Correction Register 1 */
75 {0x01 ,0x00, 0x01}, /* select IFP address space */
76 {0x02 ,0x00, 0x16}, /* ??? */
77 /* 0x03: Color Correction Register 3 */
78 /* 0x04: Color Correction Register 4 */
79 {0x03 ,0x01, 0xe1}, /* ??? */
80 {0x04 ,0x02, 0x81}, /* ??? */
81 /* 0x05: Aperture Correction (Sharpening) */
82 /* 0x06: Operating Mode Control */
83 {0x05 ,0x00, 0x04}, /* 100% sharpening,
84 no automatic sharpness reduction at low light: no sharpening */
85 {0x06 ,0x00, 0x00}, /* stop AWB at the current values,
86 no on-the-fly defect correction, no auto exposure */
87 /* 0x07: IFP Soft Reset */
88 /* 0x08: Output Format Control */
89 {0x07 ,0x30, 0x02}, /* reset */
90 {0x08 ,0x04, 0x80}, /* bypass entire image processing,
91 raw 8+2 Bayer data output directly */
92 {0x01 ,0x00, 0x04}, /* select sensor address space */
93 {0x02 ,0x00, 0x16}, /* start with column 22 */
94 /* 0x03: Window Height */
95 /* 0x04: Window Width */
96 {0x03 ,0x01, 0xe6}, /* 486 */
97 {0x04 ,0x02, 0x86}, /* 646 */
98 /* 0x05: Horizontal Blanking */
99 /* 0x06: Vertical Blanking */
100 {0x05 ,0x00, 0x04}, /* 4 columns (pixel clocks) */
101 {0x06 ,0x00, 0x00}, /* 0 rows */
102 /* 0x07: Output Control */
103 /* 0x08: Row Start */
104 {0x07 ,0x30, 0x02}, /* normal operation + chip enable*/
105 {0x08 ,0x00, 0x08}, /* row 8 */
106 /* 0x0c: Shutter Delay */
107 /* 0x0d: Reset (Soft) */
108 {0x0c ,0x00, 0x00}, /* 0 master clocks */
109 {0x0d ,0x00, 0x00}, /* return to normal operation */
114 /* 0x12: 2X Zoom Col Start
115 => 0x1e bit 0 must be set to activate zoom */
116 /* 0x13: 2X Zoom Row Start
117 => 0x1e bit 0 must be set to activate zoom */
118 {0x12 ,0x00, 0xb0}, /* column 176 */
119 {0x13 ,0x00, 0x7c}, /* row 124 */
133 /* 0x02: Column Start */
134 /* 0x03: Window Height */
135 {0x02 ,0x00, 0x16}, /* coulmn 22 */
136 {0x03 ,0x01, 0xe1}, /* 481 */
137 /* 0x04: Window Width */
138 /* 0x05: Horizontal Blanking */
139 {0x04 ,0x02, 0x81}, /* 641 */
140 {0x05 ,0x00, 0x04}, /* 4 columns (pixel clocks) */
141 /* 0x06: Vertical Blanking */
142 /* 0x07: Output Control */
143 {0x06 ,0x00, 0x00}, /* 0 rows */
144 {0x07 ,0x30, 0x02}, /* normal operation + chip enable */
145 /* 0x06: Vertical Blanking */
146 {0x06 ,0x00, 0x2d}, /* 45 rows */
147 /* 0x05: Horizontal Blanking */
148 {0x05 ,0x00, 0x04}, /* 4 columns (pixel clocks) */
149 /* 0x09: Shutter Width */
150 {0x09 ,0x00, 0x64}, /* integration of 100 rows */
151 /* 0x2b: Green 1 Gain */
152 /* 0x2c: Blue Gain */
153 {0x2b ,0x00, 0xa0}, /* 32*0.03125*2 = 2 */
154 {0x2c ,0x00, 0xa0}, /* 32*0.03125*2 = 2 */
156 /* 0x2e: Green 2 Gain */
157 {0x2d ,0x00, 0xa0}, /* 32*0.03125*2 = 2 */
158 {0x2e ,0x00, 0xa0}, /* 32*0.03125*2 = 2 */
159 /* 0x02: Column Start */
160 /* 0x03: Window Hight */
161 {0x02 ,0x00, 0x16}, /* coulmn 22 */
162 {0x03 ,0x01, 0xe1}, /* 481 */
163 /* 0x04: Window Width */
164 /* 0x05: Horizontal Blanking */
165 {0x04 ,0x02, 0x81}, /* 641 */
166 {0x05 ,0x00, 0x04}, /* 4 columns (pixel clocks) */
167 /* 0x06: Vertical Blanking */
168 /* 0x07: Output Control */
169 {0x06 ,0x00, 0x2d}, /* 45 rows */
170 {0x07 ,0x30, 0x02}, /* RESERVED options */
171 /* Writes to0x0e: UNDOCUMENTED */
173 /* 0x06: Vertical Blanking */
174 {0x06 ,0x00, 0x2d}, /* 45 rows */
175 /* 0x05: Horizontal Blanking */
176 {0x05 ,0x00, 0x04}, /* 4 columns (pixel clocks) */
179 static __u8 mt9v011_init
[][3] = {
180 /* 0x07: Output Control */
181 {0x07, 0x00, 0x02}, /* chip enable, normal operation */
182 /* 0x0d: Soft Reset */
183 {0x0d, 0x00, 0x01}, /* reset */
184 /* 0x0d: Soft Reset */
185 {0x0d, 0x00, 0x00}, /* resume operation */
186 /* 0x01: Row start */
187 /* 0x02: Column Start */
188 {0x01, 0x00, 0x08}, /* start with row 8 */
189 {0x02, 0x00, 0x16}, /* start with column 22 */
190 /* 0x03: Window Height */
191 /* 0x04: Window Width */
192 {0x03, 0x01, 0xe1}, /* 481 */
193 {0x04, 0x02, 0x81}, /* 641 */
194 /* 0x05: Horizontal Blanking */
195 /* 0x06: Vertical Blanking */
196 {0x05, 0x00, 0x83}, /* 131 columns (pixel clocks) */
197 {0x06, 0x00, 0x06}, /* 6 rows */
198 /* 0x0d: Soft Reset */
199 {0x0d, 0x00, 0x02}, /* UNKNOWN */
200 /* 0x0a: Pixel Clock Speed */
201 /* 0x0b: Frame Restart */
202 {0x0a, 0x00, 0x00}, /* default */
203 {0x0b, 0x00, 0x00}, /* (has no effect/no restart) */
204 /* 0x0c: Shutter Delay */
205 /* 0x0d: Soft Reset */
206 {0x0c, 0x00, 0x00}, /* 0 master clocks */
207 {0x0d, 0x00, 0x00}, /* resume operation */
212 /* 0x12: 2X Zoom Column Start (from MT9V111 datasheet) */
213 /* 0x13: 2X Zoom Row Start (from MT9V111 datasheet) */
215 /* column 0 => bit0 of reg 0x1e must be set to activate zoom */
217 /* row 0 => bit0 of reg 0x1e must be set to activate zoom */
229 /* 0x20: Read Mode */
230 {0x20, 0x11, 0x01}, /* output all frames (including bad frames) */
255 /* 0x0a: Pixel Clock Speed */
256 {0x0a, 0x00, 0x00}, /* default */
257 /* 0x06: Vertical Blanking */
258 {0x06, 0x00, 0x29}, /* 41 rows */
259 /* 0x05: Horizontal Blanking */
260 {0x05, 0x00, 0x09}, /* 9 columns (pixel clocks) */
261 /* 0x20: Read Mode */
262 {0x20, 0x11, 0x01}, /* output all frames (including bad ones) */
263 /* 0x20: Read Mode */
264 {0x20, 0x11, 0x01}, /* output all frames (including bad ones) */
265 /* 0x09: Shutter Width */
266 {0x09, 0x00, 0x64}, /* integration of 100 rows */
267 /* 0x07: Output Control */
269 /* dont update changes until bit0=0, chip enable, normal operation */
270 /* 0x2b: Green 1 Gain */
271 /* 0x2c: Blue Gain */
272 {0x2b, 0x00, 0x33}, /* 51*0.03125*1 = 1.59375 */
273 {0x2c, 0x00, 0xa0}, /* 32*0.03125*2 = 2 */
275 /* 0x2e: Green 2 Gain */
276 {0x2d, 0x00, 0xa0}, /* 32*0.03125*2 = 2 */
277 {0x2e, 0x00, 0x33}, /* 51*0.03125*1 = 1.59375 */
278 /* 0x07: Output Control */
279 {0x07, 0x00, 0x02}, /* chip enable, normal operation */
280 /* 0x0a: Pixel Clock Speed */
281 {0x06, 0x00, 0x00}, /* default */
282 /* 0x06: Vertical Blanking */
283 {0x06, 0x00, 0x29}, /* 41 rows */
284 /* 0x05: Horizontal Blanking */
285 {0x05, 0x00, 0x09}, /* 9 columns (pixel clocks) */
289 * @brief Initialize mt9v011 sensors
291 * @param dev Pointer to device structure
293 * @return 0 or negative error code
296 int mt9v011_initialize(struct usb_microdia
*dev
)
301 dev
->camera
.sensor_slave_address
= MT9V011_I2C_SLAVE_ADDRESS
;
302 for (i
= 0; i
< ARRAY_SIZE(mt9v011_init
); i
++) {
303 reg
= mt9v011_init
[i
][0];
304 value
[0] = mt9v011_init
[i
][1];
305 value
[1] = mt9v011_init
[i
][2];
306 ret
= sn9c20x_write_i2c_data(dev
, 2, reg
, value
);
308 UDIA_INFO("Sensor Init Error (%d). line %d\n", ret
, i
);
317 * @brief Initialize mt9v111 sensors
319 * @param dev Pointer to device structure
321 * @return 0 or negative error code
324 int mt9v111_initialize(struct usb_microdia
*dev
)
329 dev
->camera
.sensor_slave_address
= MT9V111_I2C_SLAVE_ADDRESS
;
330 mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_IFP
);
332 for (i
= 0; i
< ARRAY_SIZE(mt9v111_init
); i
++) {
333 reg
= mt9v111_init
[i
][0];
334 value
[0] = mt9v111_init
[i
][1];
335 value
[1] = mt9v111_init
[i
][2];
336 ret
= sn9c20x_write_i2c_data(dev
, 2, reg
, value
);
338 UDIA_INFO("Sensor Init Error (%d). line %d\n", ret
, i
);
343 mt9v111_setup_autoexposure(dev
);
344 mt9v111_setup_autowhitebalance(dev
);
345 mt9v111_set_autocorrections(dev
, 1);
350 int mt9v011_probe(struct usb_microdia
*dev
)
355 ret
= sn9c20x_read_i2c_data(dev
, 2, 0xff, buf
);
359 if (buf
[1] == 0x43) {
360 mt9v011_initialize(dev
);
361 dev
->camera
.set_hvflip
= mt9v011_set_hvflip
;
362 dev
->camera
.set_exposure
= mt9v011_set_exposure
;
363 dev
->camera
.modes
= mt9vx11_resolutions
;
364 dev
->camera
.nmodes
= ARRAY_SIZE(mt9vx11_resolutions
);
365 dev
->camera
.fmts
= mt9vx11_fmts
;
366 dev
->camera
.nfmts
= ARRAY_SIZE(mt9vx11_fmts
);
367 return MT9V011_SENSOR
;
370 UDIA_INFO("Failed on i2c read in mt9v011_probe\n");
372 /** NOTE: DNT DigiMicro 1.3 (microscope camera):
373 * This device uses sensor MT9V111, but slave 0x5d is also successfully
374 * read. Registers 0x00, 0x36 and 0xff of slave 0x5d return chip version
380 int mt9v111_select_address_space(struct usb_microdia
*dev
, __u8 address_space
)
386 /* check if selection is valid: */
387 if ((address_space
!= MT9V111_ADDRESSSPACE_IFP
) &&
388 (address_space
!= MT9V111_ADDRESSSPACE_SENSOR
)) {
389 UDIA_INFO("Error: invalid register address space "
390 "selection for sensor MT9V111/MI0360SOC !\n");
393 /* read address space slection register: */
396 while ((k
< 3) && (retI2C
!= 0)) {
397 retI2C
= sn9c20x_read_i2c_data(dev
, 2, 0x01, buf
);
398 if (retI2C
!= 0 && k
< 2)
403 UDIA_INFO("Error: MT9V111/MI0360SOC (I2C-slave 0x5c): "
404 "read of reg0x01 (address space selection) failed !\n");
407 /* check current address space: */
408 if ((buf
[0] != 0x00) || (buf
[1] != address_space
)) {
411 while ((k
< 3) && (retI2C
!= 0)) {
412 /* switch address space: */
413 buf
[0] = 0x00; buf
[1] = address_space
;
414 retI2C
= sn9c20x_write_i2c_data(dev
, 2, 0x01, buf
);
415 if (retI2C
!= 0 && k
< 2)
420 if (address_space
== MT9V111_ADDRESSSPACE_IFP
)
421 UDIA_INFO("Error: MT9V111/MI0360SOC "
422 "(I2C-slave 0x5c): switch to IFP "
423 "address space failed !\n");
425 UDIA_INFO("Error: MT9V111/MI0360SOC "
426 "(I2C-slave 0x5c): switch to sensor "
427 "core address space failed !\n");
434 int mt9v111_probe(struct usb_microdia
*dev
)
439 ret
= mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_SENSOR
);
443 ret
= sn9c20x_read_i2c_data(dev
, 2, 0xff, buf
);
447 if (buf
[1] == 0x3a) {
448 mt9v111_initialize(dev
);
449 dev
->camera
.set_hvflip
= mt9v111_set_hvflip
;
450 dev
->camera
.set_exposure
= mt9v111_set_exposure
;
451 dev
->camera
.set_auto_exposure
= mt9v111_set_autoexposure
;
452 dev
->camera
.modes
= mt9vx11_resolutions
;
453 dev
->camera
.nmodes
= ARRAY_SIZE(mt9vx11_resolutions
);
454 dev
->camera
.fmts
= mt9vx11_fmts
;
455 dev
->camera
.nfmts
= ARRAY_SIZE(mt9vx11_fmts
);
456 return MT9V111_SENSOR
;
459 UDIA_INFO("Failed on i2c read in mt9v111_probe\n");
461 /** FIXME: always switch back to last register address space */
466 int mt9v111_setup_autoexposure(struct usb_microdia
*dev
)
472 /* Switch to IFP-register address space: */
473 ret
= mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_IFP
);
475 return -11; /* -EAGAIN */
476 /* Set target luminance and tracking accuracy: */
477 buf
[0] = MT9V111_IFP_AE_TRACKINGACCURACY(12)
478 /* 0-255 (default: 16) */
479 | MT9V111_IFP_AE_TARGETLUMINANCE(100);
480 /* 0-255 (default: 100) */
481 ret
= sn9c20x_write_i2c_data16(dev
, 1,
482 MT9V111_IFPREG_AE_TARGETLUMCTL
, buf
);
483 /* Set speed and sensitivity: */
484 buf
[0] = MT9V111_IFP_AE_DELAY(4)
485 /* 0-7 (fastest-slowest) (default: 4) */
486 | MT9V111_IFP_AE_SPEED(4)
487 /* 0-7 (fastest-slowest) (default: 4) */
488 | MT9V111_IFP_AE_STEPSIZE_MEDIUM
;
489 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
490 MT9V111_IFPREG_AE_SPEEDSENSCTL
, buf
);
491 /* Horizontal boundaries of AE measurement window: */
492 buf
[0] = MT9V111_IFP_AE_WINBOUNDARY_RIGHT(1020)
493 /* 0-1020 (pixel) (default: 1020) */
494 | MT9V111_IFP_AE_WINBOUNDARY_LEFT(12);
495 /* 0-1020 (pixel) (default: 12) */
496 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
497 MT9V111_IFPREG_AE_HWINBOUNDARY
, buf
);
498 /* Vertical boundaries of AE measurement window: */
499 buf
[0] = MT9V111_IFP_AE_WINBOUNDARY_BOTTOM(510)
500 /* 0-510 (pixel) (default: 510) */
501 | MT9V111_IFP_AE_WINBOUNDARY_TOP(32);
502 /* 0-510 (pixel) (default: 32) */
503 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
504 MT9V111_IFPREG_AE_VWINBOUNDARY
, buf
);
505 /* Horizontal boundaries of AE measurement window
506 * for back light compensation: */
507 buf
[0] = MT9V111_IFP_AE_WINBOUNDARY_RIGHT_BLC(480)
508 /* 0-1020 (pixel) (default: 480) */
509 | MT9V111_IFP_AE_WINBOUNDARY_LEFT_BLC(160);
510 /* 0-1020 (pixel) (default: 160) */
511 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
512 MT9V111_IFPREG_AE_HWINBOUNDARY_BLC
, buf
);
513 /* Vertical boundaries of AE measurement window
514 * for back light compensation: */
515 buf
[0] = MT9V111_IFP_AE_WINBOUNDARY_BOTTOM_BLC(360)
516 /* 0-510 (pixel) (default: 360) */
517 | MT9V111_IFP_AE_WINBOUNDARY_TOP_BLC(120);
518 /* 0-510 (pixel) (default: 120) */
519 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
520 MT9V111_IFPREG_AE_VWINBOUNDARY_BLC
, buf
);
521 /* Set digital gains limit: */
522 buf
[0] = MT9V111_IFP_AE_MAXGAIN_POSTLS(64)
523 /* 0-255 (default: 64) */
524 | MT9V111_IFP_AE_MAXGAIN_PRELS(16);
525 /* 0-255 (default: 16) */
526 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
527 MT9V111_IFPREG_AE_DGAINSLIMITS
, buf
);
528 /* Read current value of IFP-register 0x06: */
529 ret2
= sn9c20x_read_i2c_data16(dev
, 1, MT9V111_IFPREG_OPMODECTL
, buf
);
531 /* Set new value for register 0x06: */
532 buf
[0] = (buf
[0] & 0xffe3) | MT9V111_IFP_AE_WIN_COMBINED
|
533 MT9V111_IFP_OPMODE_BYPASSCOLORCORR
;
534 /* NOTE: BYPASS COLOR CORRECTION HAS
535 * TO BE SET FOR PERMANENT AE ! */
536 /* Write new value to IFP-register 0x06:*/
537 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
538 MT9V111_IFPREG_OPMODECTL
, buf
);
540 if (ret
< 0 || ret2
< 0) {
541 UDIA_INFO("One or more errors occured during "
542 "setup of AE registers.\n");
548 int mt9v111_setup_autowhitebalance(struct usb_microdia
*dev
)
553 /* Switch to IFP-register address space: */
554 ret
= mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_IFP
);
556 return -11; /* -EAGAIN */
558 buf
[0] = MT9V111_IFP_AWB_ADDON_RED(0) /* 0-255 (default: 0) */
559 | MT9V111_IFP_AWB_ADDON_BLUE(0); /* 0-255 (default: 0) */
560 ret
= sn9c20x_write_i2c_data16(dev
, 1, MT9V111_IFPREG_AWB_TINT
, buf
);
561 /* Set AWB speed and color saturation: */
562 buf
[0] = MT9V111_IFP_AWB_SATURATION_FULL
563 | MT9V111_IFP_AWB_AUTOSATLOWLIGHT_ENABLE
564 | MT9V111_IFP_AWB_DELAY(4)
565 /* 0-7 (fastest-slowest) (default: 4) */
566 | MT9V111_IFP_AWB_SPEED(4);
567 /* 0-7 (fastest-slowest) (default: 4) */
568 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
569 MT9V111_IFPREG_AWB_SPEEDCOLORSATCTL
, buf
);
570 /* Boundaries of AWB measurement window: */
571 buf
[0] = MT9V111_IFP_AWB_WINBOUNDARY_TOP(0)
572 /* 0-480 (pixel) (default: 0) */
573 | MT9V111_IFP_AWB_WINBOUNDARY_BOTTOM(480)
574 /* 0-480 (pixel) (default: 448) */
575 | MT9V111_IFP_AWB_WINBOUNDARY_LEFT(0)
576 /* 0-960 (pixel) (default: 0) */
577 | MT9V111_IFP_AWB_WINBOUNDARY_RIGHT(640);
578 /* 0-960 (pixel) (default: 640) */
579 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
580 MT9V111_IFPREG_AWB_WINBOUNDARY
, buf
);
583 UDIA_INFO("One or more errors occured during "
584 "setup of AWB registers.\n");
590 int mt9v011_set_exposure(struct usb_microdia
*dev
)
595 buf
[0] = (dev
->vsettings
.exposure
>> 12);
597 ret
|= sn9c20x_write_i2c_data(dev
, 2, 0x09, buf
);
598 /* Maybe we have to disable AE/AWB/flicker avoidence (currently not
599 * used) for MT9V111 sensor, because IFP controls this register if
600 * one of them is enabled. */
604 int mt9v111_set_exposure(struct usb_microdia
*dev
)
610 ret
= mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_SENSOR
);
613 return -11; /* -EAGAIN */
615 buf
[0] = (dev
->vsettings
.exposure
>> 12);
617 ret
|= sn9c20x_write_i2c_data(dev
, 2, 0x09, buf
);
618 /* Maybe we have to disable AE/AWB/flicker avoidence (currently not
619 * used) for MT9V111 sensor, because IFP controls this register if
620 * one of them is enabled. */
624 int mt9v011_set_hvflip(struct usb_microdia
*dev
)
629 if ((dev
->vsettings
.hflip
> 1) || (dev
->vsettings
.hflip
< 0))
631 if ((dev
->vsettings
.vflip
> 1) || (dev
->vsettings
.vflip
< 0))
634 ret
= sn9c20x_read_i2c_data(dev
, 2, 0x20, buf
);
638 if (dev
->vsettings
.hflip
) {
640 /* (MSB) set bit 15: read out from
641 * bottom to top (upside down) */
643 /* (LSB) set bit 7: readout starting 1 row later */
645 buf
[0] &= 0x7f; /* (MSB) unset bit 15: normal readout */
646 buf
[1] &= 0x7f; /* (LSB) unset bit 7: normal readout */
648 if (dev
->vsettings
.vflip
) {
650 /* (MSB) set bit 14: read out from right to left (mirrored) */
652 /* (LSB) set bit 5: readout starting 1 column later */
654 buf
[0] &= 0xbf; /* (MSB) unset bit 14: normal readout */
655 buf
[1] &= 0xdf; /* (LSB) unset bit 5: normal readout */
658 ret
= sn9c20x_write_i2c_data(dev
, 2, 0x20, buf
);
662 int mt9v111_set_hvflip(struct usb_microdia
*dev
)
667 if ((dev
->vsettings
.hflip
> 1) || (dev
->vsettings
.hflip
< 0))
669 if ((dev
->vsettings
.vflip
> 1) || (dev
->vsettings
.vflip
< 0))
673 ret
= mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_SENSOR
);
675 return -11; /* -EAGAIN */
677 ret
= sn9c20x_read_i2c_data(dev
, 2, 0x20, buf
);
681 if (dev
->vsettings
.hflip
) {
683 /* (MSB) set bit 15: read out from
684 * bottom to top (upside down) */
686 /* (LSB) set bit 7: readout starting 1 row later */
688 buf
[0] &= 0x7f; /* (MSB) unset bit 15: normal readout */
689 buf
[1] &= 0x7f; /* (LSB) unset bit 7: normal readout */
691 if (dev
->vsettings
.vflip
) {
693 /* (MSB) set bit 14: read out from right to left (mirrored) */
695 /* (LSB) set bit 5: readout starting 1 column later */
697 buf
[0] &= 0xbf; /* (MSB) unset bit 14: normal readout */
698 buf
[1] &= 0xdf; /* (LSB) unset bit 5: normal readout */
701 ret
= sn9c20x_write_i2c_data(dev
, 2, 0x20, buf
);
705 int mt9v111_set_autoexposure(struct usb_microdia
*dev
)
710 /* Switch to IFP-register address space: */
711 ret
= mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_IFP
);
713 return -11; /* -EAGAIN */
714 /* Read current value of IFP-register 0x06: */
715 ret
= sn9c20x_read_i2c_data16(dev
, 1, MT9V111_IFPREG_OPMODECTL
, buf
);
717 UDIA_ERROR("Error: setting of auto exposure failed: "
718 "error while reading from IFP-register 0x06\n");
721 /* Set new value for register 0x06: */
722 if (dev
->vsettings
.auto_exposure
== 1) {
723 /* Enable automatic exposure: */
724 buf
[0] |= MT9V111_IFP_OPMODE_AUTOEXPOSURE
;
725 } else if (dev
->vsettings
.auto_exposure
== 0) {
726 /* Disable automatic exposure: */
727 buf
[0] &= ~MT9V111_IFP_OPMODE_AUTOEXPOSURE
;
730 /* Write new value to IFP-register 0x06: */
731 ret
= sn9c20x_write_i2c_data16(dev
, 1, MT9V111_IFPREG_OPMODECTL
, buf
);
733 UDIA_ERROR("Error: setting of auto exposure failed: "
734 "error while writing to IFP-register 0x06\n");
740 int mt9v111_set_autowhitebalance(struct usb_microdia
*dev
)
745 /* Switch to IFP-register address space: */
746 ret
= mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_IFP
);
748 return -11; /* -EAGAIN */
749 /* Read current value of IFP-register 0x06: */
750 ret
= sn9c20x_read_i2c_data16(dev
, 1,
751 MT9V111_IFPREG_OPMODECTL
, buf
);
753 UDIA_ERROR("Error: setting of auto whitebalance failed: "
754 "error while reading from IFP-register 0x06\n");
757 /* Set new value for register 0x06: */
758 if (dev
->vsettings
.auto_whitebalance
== 1) {
759 /* Enable automatic exposure: */
760 buf
[0] |= MT9V111_IFP_OPMODE_AUTOWHITEBALANCE
;
761 } else if (dev
->vsettings
.auto_whitebalance
== 0) {
762 /* Disable automatic exposure: */
763 buf
[0] &= ~MT9V111_IFP_OPMODE_AUTOWHITEBALANCE
;
766 /* Write new value to IFP-register 0x06:*/
767 ret
= sn9c20x_write_i2c_data16(dev
, 1,
768 MT9V111_IFPREG_OPMODECTL
, buf
);
770 UDIA_ERROR("Error: setting of auto whitebalance failed: "
771 "error while writing to IFP-register 0x06\n");
777 int mt9v111_set_autocorrections(struct usb_microdia
*dev
, int enable
)
782 /* Switch to IFP-register address space: */
783 ret
= mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_IFP
);
785 return -11; /* -EAGAIN */
786 /* Read current value of IFP-register 0x06: */
787 ret
= sn9c20x_read_i2c_data16(dev
, 1,
788 MT9V111_IFPREG_OPMODECTL
, buf
);
790 UDIA_ERROR("Error: setting of sensor auto-correction functions "
791 "failed: error while reading from IFP-register 0x06\n");
794 /* Set new value for register 0x06: */
796 buf
[0] |= MT9V111_IFP_OPMODE_APERTURECORR
|
797 MT9V111_IFP_OPMODE_ONTHEFLYDEFECTCORR
;
798 else if (enable
== 0)
799 buf
[0] &= ~(MT9V111_IFP_OPMODE_APERTURECORR
|
800 MT9V111_IFP_OPMODE_ONTHEFLYDEFECTCORR
);
803 /* Write new value to IFP-register 0x06: */
804 ret
= sn9c20x_write_i2c_data16(dev
, 1,
805 MT9V111_IFPREG_OPMODECTL
, buf
);
807 UDIA_ERROR("Error: setting of sensor auto-correction functions "
808 "failed: error while writing to IFP-register 0x06\n");