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>
33 struct microdia_video_format mt9x0xx_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_format mt9m111_fmts
[] = {
50 .pix_fmt
= V4L2_PIX_FMT_SBGGR8
,
51 .desc
= "Bayer 8bit (BGGR)",
53 .set_format
= mt9m111_set_raw
56 .pix_fmt
= V4L2_PIX_FMT_YUYV
,
59 .set_format
= mt9m111_set_yuv422
62 .pix_fmt
= V4L2_PIX_FMT_JPEG
,
63 .desc
= "JPEG (YUV 4:2:2)",
65 .set_format
= sn9c20x_set_jpeg
69 struct microdia_video_format mt9v111_fmts
[] = {
71 .pix_fmt
= V4L2_PIX_FMT_SBGGR8
,
72 .desc
= "Bayer 8bit (BGGR)",
74 .set_format
= sn9c20x_set_raw
77 .pix_fmt
= V4L2_PIX_FMT_JPEG
,
78 .desc
= "JPEG (YUV 4:2:2)",
80 .set_format
= sn9c20x_set_jpeg
84 struct microdia_video_resolution micron_resolutions
[] = {
88 .scale
= SN9C20X_1_4_SCALE
,
89 .window
= {2, 2, 640, 480}
94 .scale
= SN9C20X_1_2_SCALE
,
95 .window
= {2, 2, 640, 480}
100 .scale
= SN9C20X_NO_SCALE
,
101 .window
= {2, 2, 640, 480}
105 struct microdia_video_resolution mt9m111_resolutions
[] = {
109 .scale
= SN9C20X_1_4_SCALE
,
110 .window
= {6, 2, 640, 480}
115 .scale
= SN9C20X_1_2_SCALE
,
116 .window
= {6, 2, 640, 480}
121 .scale
= SN9C20X_NO_SCALE
,
122 .window
= {6, 2, 640, 480}
126 static __u8 mt9v111_init
[][3] = {
127 /* 0x0d: Color Correction Register 8 */
129 /* 0x0d: Color Correction Register 8 */
130 {0x0d, 0x00, 0x00}, /* ??? */
131 /* 0x02: Color Correction Register 1 */
132 {0x01, 0x00, 0x01}, /* select IFP address space */
133 {0x02, 0x00, 0x16}, /* ??? */
134 /* 0x03: Color Correction Register 3 */
135 /* 0x04: Color Correction Register 4 */
136 {0x03, 0x01, 0xe1}, /* ??? */
137 {0x04, 0x02, 0x81}, /* ??? */
138 /* 0x05: Aperture Correction (Sharpening) */
139 /* 0x06: Operating Mode Control */
140 {0x05, 0x00, 0x04}, /* 100% sharpening,
141 no automatic sharpness reduction at low light: no sharpening */
142 {0x06, 0x00, 0x00}, /* stop AWB at the current values,
143 no on-the-fly defect correction, no auto exposure */
144 /* 0x07: IFP Soft Reset */
145 /* 0x08: Output Format Control */
146 {0x07, 0x30, 0x02}, /* reset */
147 {0x08, 0x04, 0x80}, /* bypass entire image processing,
148 raw 8+2 Bayer data output directly */
149 {0x01, 0x00, 0x04}, /* select sensor address space */
150 {0x02, 0x00, 0x16}, /* start with column 22 */
151 /* 0x03: Window Height */
152 /* 0x04: Window Width */
153 {0x03, 0x01, 0xe6}, /* 486 */
154 {0x04, 0x02, 0x86}, /* 646 */
155 /* 0x05: Horizontal Blanking */
156 /* 0x06: Vertical Blanking */
157 {0x05, 0x00, 0x04}, /* 4 columns (pixel clocks) */
158 {0x06, 0x00, 0x00}, /* 0 rows */
159 /* 0x07: Output Control */
160 /* 0x08: Row Start */
161 {0x07, 0x30, 0x02}, /* normal operation + chip enable*/
162 {0x08, 0x00, 0x08}, /* row 8 */
163 /* 0x0c: Shutter Delay */
164 /* 0x0d: Reset (Soft) */
165 {0x0c, 0x00, 0x00}, /* 0 master clocks */
166 {0x0d, 0x00, 0x00}, /* return to normal operation */
171 /* 0x12: 2X Zoom Col Start
172 => 0x1e bit 0 must be set to activate zoom */
173 /* 0x13: 2X Zoom Row Start
174 => 0x1e bit 0 must be set to activate zoom */
175 {0x12, 0x00, 0xb0}, /* column 176 */
176 {0x13, 0x00, 0x7c}, /* row 124 */
190 /* 0x02: Column Start */
191 /* 0x03: Window Height */
192 {0x02, 0x00, 0x16}, /* coulmn 22 */
193 {0x03, 0x01, 0xe1}, /* 481 */
194 /* 0x04: Window Width */
195 /* 0x05: Horizontal Blanking */
196 {0x04, 0x02, 0x81}, /* 641 */
197 {0x05, 0x00, 0x04}, /* 4 columns (pixel clocks) */
198 /* 0x06: Vertical Blanking */
199 /* 0x07: Output Control */
200 {0x06, 0x00, 0x00}, /* 0 rows */
201 {0x07, 0x30, 0x02}, /* normal operation + chip enable */
202 /* 0x06: Vertical Blanking */
203 {0x06, 0x00, 0x2d}, /* 45 rows */
204 /* 0x05: Horizontal Blanking */
205 {0x05, 0x00, 0x04}, /* 4 columns (pixel clocks) */
206 /* 0x09: Shutter Width */
207 {0x09, 0x00, 0x64}, /* integration of 100 rows */
208 /* 0x2b: Green 1 Gain */
209 /* 0x2c: Blue Gain */
210 {0x2b, 0x00, 0xa0}, /* 32*0.03125*2 = 2 */
211 {0x2c, 0x00, 0xa0}, /* 32*0.03125*2 = 2 */
213 /* 0x2e: Green 2 Gain */
214 {0x2d, 0x00, 0xa0}, /* 32*0.03125*2 = 2 */
215 {0x2e, 0x00, 0xa0}, /* 32*0.03125*2 = 2 */
216 /* 0x02: Column Start */
217 /* 0x03: Window Hight */
218 {0x02, 0x00, 0x16}, /* coulmn 22 */
219 {0x03, 0x01, 0xe1}, /* 481 */
220 /* 0x04: Window Width */
221 /* 0x05: Horizontal Blanking */
222 {0x04, 0x02, 0x81}, /* 641 */
223 {0x05, 0x00, 0x04}, /* 4 columns (pixel clocks) */
224 /* 0x06: Vertical Blanking */
225 /* 0x07: Output Control */
226 {0x06, 0x00, 0x2d}, /* 45 rows */
227 {0x07, 0x30, 0x02}, /* RESERVED options */
228 /* Writes to0x0e: UNDOCUMENTED */
230 /* 0x06: Vertical Blanking */
231 {0x06, 0x00, 0x2d}, /* 45 rows */
232 /* 0x05: Horizontal Blanking */
233 {0x05, 0x00, 0x04}, /* 4 columns (pixel clocks) */
236 static __u8 mt9v011_init
[][3] = {
237 /* 0x07: Output Control */
238 {0x07, 0x00, 0x02}, /* chip enable, normal operation */
239 /* 0x0d: Soft Reset */
240 {0x0d, 0x00, 0x01}, /* reset */
241 /* 0x0d: Soft Reset */
242 {0x0d, 0x00, 0x00}, /* resume operation */
243 /* 0x01: Row start */
244 /* 0x02: Column Start */
245 {0x01, 0x00, 0x08}, /* start with row 8 */
246 {0x02, 0x00, 0x16}, /* start with column 22 */
247 /* 0x03: Window Height */
248 /* 0x04: Window Width */
249 {0x03, 0x01, 0xe1}, /* 481 */
250 {0x04, 0x02, 0x81}, /* 641 */
251 /* 0x05: Horizontal Blanking */
252 /* 0x06: Vertical Blanking */
253 {0x05, 0x00, 0x83}, /* 131 columns (pixel clocks) */
254 {0x06, 0x00, 0x06}, /* 6 rows */
255 /* 0x0d: Soft Reset */
256 {0x0d, 0x00, 0x02}, /* UNKNOWN */
257 /* 0x0a: Pixel Clock Speed */
258 /* 0x0b: Frame Restart */
259 {0x0a, 0x00, 0x00}, /* default */
260 {0x0b, 0x00, 0x00}, /* (has no effect/no restart) */
261 /* 0x0c: Shutter Delay */
262 /* 0x0d: Soft Reset */
263 {0x0c, 0x00, 0x00}, /* 0 master clocks */
264 {0x0d, 0x00, 0x00}, /* resume operation */
269 /* 0x12: 2X Zoom Column Start (from MT9V111 datasheet) */
270 /* 0x13: 2X Zoom Row Start (from MT9V111 datasheet) */
272 /* column 0 => bit0 of reg 0x1e must be set to activate zoom */
274 /* row 0 => bit0 of reg 0x1e must be set to activate zoom */
286 /* 0x20: Read Mode */
287 {0x20, 0x11, 0x01}, /* output all frames (including bad frames) */
312 /* 0x0a: Pixel Clock Speed */
313 {0x0a, 0x00, 0x00}, /* default */
314 /* 0x06: Vertical Blanking */
315 {0x06, 0x00, 0x29}, /* 41 rows */
316 /* 0x05: Horizontal Blanking */
317 {0x05, 0x00, 0x09}, /* 9 columns (pixel clocks) */
318 /* 0x20: Read Mode */
319 {0x20, 0x11, 0x01}, /* output all frames (including bad ones) */
320 /* 0x20: Read Mode */
321 {0x20, 0x11, 0x01}, /* output all frames (including bad ones) */
322 /* 0x09: Shutter Width */
323 {0x09, 0x00, 0x64}, /* integration of 100 rows */
324 /* 0x07: Output Control */
326 /* dont update changes until bit0=0, chip enable, normal operation */
327 /* 0x2b: Green 1 Gain */
328 /* 0x2c: Blue Gain */
329 {0x2b, 0x00, 0x33}, /* 51*0.03125*1 = 1.59375 */
330 {0x2c, 0x00, 0xa0}, /* 32*0.03125*2 = 2 */
332 /* 0x2e: Green 2 Gain */
333 {0x2d, 0x00, 0xa0}, /* 32*0.03125*2 = 2 */
334 {0x2e, 0x00, 0x33}, /* 51*0.03125*1 = 1.59375 */
335 /* 0x07: Output Control */
336 {0x07, 0x00, 0x02}, /* chip enable, normal operation */
337 /* 0x0a: Pixel Clock Speed */
338 {0x06, 0x00, 0x00}, /* default */
339 /* 0x06: Vertical Blanking */
340 {0x06, 0x00, 0x29}, /* 41 rows */
341 /* 0x05: Horizontal Blanking */
342 {0x05, 0x00, 0x09}, /* 9 columns (pixel clocks) */
345 static __u8 mt9m111_init
[][3] = {
350 /* Select Page map 0x01
351 * This means all new writes now have the address prefix 0x1.
352 * Example: 0x3a becomes 0x13a. */
354 /** Select output format:
355 * - output raw bayer (8+2 bit)
356 * FIXME: There are nearly all YUV and RGB variants possible.
357 * Maybe we should use them.
360 /* measure atoexposure through a mix of both possible windows */
362 /* Switch back to Page map 0x00 */
364 /* The following set the resoutiona and window size.
365 * It's a bit more than SXGA.
383 /* Protect settings */
393 /* Blanking (again?) */
399 static __u8 mt9m001_init
[][3] = {
400 {0x07, 0x00, 0x00}, {0x07, 0x00, 0x02}, {0x0d, 0x00, 0x01},
401 {0x0d, 0x00, 0x00}, {0x01, 0x00, 0x0e}, {0x02, 0x00, 0x14},
402 {0x03, 0x03, 0xc1}, {0x04, 0x05, 0x01}, {0x05, 0x00, 0x83},
403 {0x06, 0x00, 0x06}, {0x0d, 0x00, 0x02}, {0x09, 0x00, 0x00},
404 {0x0a, 0x00, 0x00}, {0x0b, 0x00, 0x00}, {0x0c, 0x00, 0x00},
405 {0x11, 0x00, 0x00}, {0x1e, 0x80, 0x00}, {0x20, 0x11, 0x05},
406 {0x2b, 0x00, 0x08}, {0x2c, 0x00, 0x10}, {0x2d, 0x00, 0x14},
407 {0x2e, 0x00, 0x08}, {0x5f, 0x89, 0x04}, {0x60, 0x00, 0x00},
408 {0x61, 0x00, 0x00}, {0x62, 0x04, 0x98}, {0x63, 0x00, 0x00},
409 {0x68, 0x00, 0x00}, {0x20, 0x11, 0x1d}, {0x06, 0x00, 0xf2},
410 {0x05, 0x00, 0x13}, {0x20, 0x11, 0x1d}, {0x20, 0x11, 0x1d},
411 {0x07, 0x00, 0x03}, {0x2b, 0x00, 0x10}, {0x2c, 0x00, 0x10},
412 {0x2d, 0x00, 0x10}, {0x2e, 0x00, 0x10}, {0x07, 0x00, 0x02},
413 {0x07, 0x00, 0x03}, {0x2c, 0x00, 0x1d}, {0x2d, 0x00, 0x1d},
414 {0x07, 0x00, 0x02}, {0x06, 0x00, 0xf2}, {0x05, 0x00, 0x13},
415 {0x09, 0x03, 0x87}, {0x07, 0x00, 0x03}, {0x2b, 0x00, 0x28},
416 {0x2c, 0x00, 0x3f}, {0x2d, 0x00, 0x3f}, {0x2e, 0x00, 0x28},
417 {0x07, 0x00, 0x02}, {0x09, 0x04, 0xf1}, {0x07, 0x00, 0x03},
418 {0x2b, 0x00, 0x24}, {0x2c, 0x00, 0x39}, {0x2d, 0x00, 0x39},
419 {0x2e, 0x00, 0x24}, {0x07, 0x00, 0x02},
423 * @brief Initialize mt9v011 sensors
425 * @param dev Pointer to device structure
427 * @return 0 or negative error code
430 int mt9v011_initialize(struct usb_microdia
*dev
)
435 for (i
= 0; i
< ARRAY_SIZE(mt9v011_init
); i
++) {
436 reg
= mt9v011_init
[i
][0];
437 value
[0] = mt9v011_init
[i
][1];
438 value
[1] = mt9v011_init
[i
][2];
439 ret
= sn9c20x_write_i2c_data(dev
, 2, reg
, value
);
441 UDIA_WARNING("Sensor Init Error (%d). "
442 "line %d\n", ret
, i
);
451 * @brief Initialize mt9v111 sensors
453 * @param dev Pointer to device structure
455 * @return 0 or negative error code
458 int mt9v111_initialize(struct usb_microdia
*dev
)
463 mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_IFP
);
465 for (i
= 0; i
< ARRAY_SIZE(mt9v111_init
); i
++) {
466 reg
= mt9v111_init
[i
][0];
467 value
[0] = mt9v111_init
[i
][1];
468 value
[1] = mt9v111_init
[i
][2];
469 ret
= sn9c20x_write_i2c_data(dev
, 2, reg
, value
);
471 UDIA_WARNING("Sensor Init Error (%d). "
472 "line %d\n", ret
, i
);
477 mt9v111_setup_autoexposure(dev
);
478 mt9v111_setup_autowhitebalance(dev
);
479 mt9v111_set_autocorrections(dev
, 1);
484 int mt9v011_probe(struct usb_microdia
*dev
)
489 ret
= sn9c20x_read_i2c_data(dev
, 2, 0xff, buf
);
493 if (buf
[1] == 0x43) {
494 mt9v011_initialize(dev
);
495 dev
->camera
.set_hvflip
= mt9v011_set_hvflip
;
496 dev
->camera
.set_exposure
= mt9v011_set_exposure
;
497 dev
->camera
.modes
= micron_resolutions
;
498 dev
->camera
.nmodes
= ARRAY_SIZE(micron_resolutions
);
499 dev
->camera
.fmts
= mt9x0xx_fmts
;
500 dev
->camera
.nfmts
= ARRAY_SIZE(mt9x0xx_fmts
);
501 return MT9V011_SENSOR
;
505 /** NOTE: DNT DigiMicro 1.3 (microscope camera):
506 * This device uses sensor MT9V111, but slave 0x5d is also successfully
507 * read. Registers 0x00, 0x36 and 0xff of slave 0x5d return chip version
513 int mt9v111_select_address_space(struct usb_microdia
*dev
, __u8 address_space
)
519 /* check if selection is valid: */
520 if ((address_space
!= MT9V111_ADDRESSSPACE_IFP
) &&
521 (address_space
!= MT9V111_ADDRESSSPACE_SENSOR
)) {
522 UDIA_WARNING("invalid register address space "
523 "selection for sensor MT9V111/MI0360SOC !\n");
526 /* read address space slection register: */
529 while ((k
< 3) && (retI2C
!= 0)) {
530 retI2C
= sn9c20x_read_i2c_data(dev
, 2, 0x01, buf
);
531 if (retI2C
!= 0 && k
< 2)
536 UDIA_ERROR("MT9V111/MI0360SOC (I2C-slave 0x5c): "
537 "read of reg0x01 (address space selection) failed !\n");
540 /* check current address space: */
541 if ((buf
[0] != 0x00) || (buf
[1] != address_space
)) {
544 while ((k
< 3) && (retI2C
!= 0)) {
545 /* switch address space: */
546 buf
[0] = 0x00; buf
[1] = address_space
;
547 retI2C
= sn9c20x_write_i2c_data(dev
, 2, 0x01, buf
);
548 if (retI2C
!= 0 && k
< 2)
553 if (address_space
== MT9V111_ADDRESSSPACE_IFP
)
554 UDIA_ERROR("MT9V111/MI0360SOC "
555 "(I2C-slave 0x5c): switch to IFP "
556 "address space failed !\n");
558 UDIA_ERROR("MT9V111/MI0360SOC "
559 "(I2C-slave 0x5c): switch to sensor "
560 "core address space failed !\n");
567 int mt9v111_probe(struct usb_microdia
*dev
)
572 /* Select address-space: sensor */
573 buf
[0] = 0x00; buf
[1] = MT9V111_ADDRESSSPACE_SENSOR
;
574 ret
= sn9c20x_write_i2c_data(dev
, 2, 0x01, buf
);
578 ret
= sn9c20x_read_i2c_data(dev
, 2, 0xff, buf
);
582 if (buf
[1] == 0x3a) {
583 mt9v111_initialize(dev
);
584 dev
->camera
.set_hvflip
= mt9v111_set_hvflip
;
585 dev
->camera
.set_exposure
= mt9v111_set_exposure
;
586 dev
->camera
.set_auto_exposure
= mt9v111_set_autoexposure
;
587 dev
->camera
.modes
= micron_resolutions
;
588 dev
->camera
.nmodes
= ARRAY_SIZE(micron_resolutions
);
589 dev
->camera
.fmts
= mt9v111_fmts
;
590 dev
->camera
.nfmts
= ARRAY_SIZE(mt9v111_fmts
);
591 return MT9V111_SENSOR
;
595 /** FIXME: always switch back to last register address space */
601 * @brief Initialize mt9m111 sensors
603 * @param dev Pointer to device structure
605 * @return 0 or negative error code
608 int mt9m001_initialize(struct usb_microdia
*dev
)
614 for (i
= 0; i
< ARRAY_SIZE(mt9m001_init
); i
++) {
615 reg
= mt9m001_init
[i
][0];
616 value
[0] = mt9m001_init
[i
][1];
617 value
[1] = mt9m001_init
[i
][2];
618 ret
= sn9c20x_write_i2c_data(dev
, 2, reg
, value
);
620 UDIA_WARNING("Sensor Init Error (%d). "
621 "line %d\n", ret
, i
);
629 int mt9m001_probe(struct usb_microdia
*dev
)
633 ret
= sn9c20x_read_i2c_data(dev
, 2, 0x00, buf
);
637 if (buf
[1] == 0x31) {
638 mt9m001_initialize(dev
);
639 dev
->camera
.modes
= micron_resolutions
;
640 dev
->camera
.nmodes
= ARRAY_SIZE(micron_resolutions
);
641 dev
->camera
.fmts
= mt9x0xx_fmts
;
642 dev
->camera
.nfmts
= ARRAY_SIZE(mt9x0xx_fmts
);
643 return MT9M001_SENSOR
;
651 * @brief Initialize mt9m111 sensors
653 * @param dev Pointer to device structure
655 * @return 0 or negative error code
658 int mt9m111_initialize(struct usb_microdia
*dev
)
663 __u8 value
[2] = {0x00, 0x00};
665 /* Select address-space: Sensor */
666 sn9c20x_write_i2c_data(dev
, 2, 0xf0, value
);
668 for (i
= 0; i
< ARRAY_SIZE(mt9m111_init
); i
++) {
669 reg
= mt9m111_init
[i
][0];
670 value
[0] = mt9m111_init
[i
][1];
671 value
[1] = mt9m111_init
[i
][2];
672 ret
= sn9c20x_write_i2c_data(dev
, 2, reg
, value
);
674 UDIA_WARNING("Sensor Init Error (%d). "
675 "line %d\n", ret
, i
);
683 int mt9m111_probe(struct usb_microdia
*dev
)
686 __u8 buf
[2] = {0x00, 0x00};
688 /* Select address-space: Sensor */
689 sn9c20x_write_i2c_data(dev
, 2, 0xf0, buf
);
691 ret
= sn9c20x_read_i2c_data(dev
, 2, 0x00, buf
);
695 if (buf
[1] == 0x3a) {
696 mt9m111_initialize(dev
);
697 dev
->camera
.modes
= mt9m111_resolutions
;
698 dev
->camera
.nmodes
= ARRAY_SIZE(mt9m111_resolutions
);
699 dev
->camera
.fmts
= mt9m111_fmts
;
700 dev
->camera
.nfmts
= ARRAY_SIZE(mt9m111_fmts
);
701 return MT9M111_SENSOR
;
708 int mt9m111_set_raw(struct usb_microdia
*dev
)
712 /* select address-space: IFP */
714 sn9c20x_write_i2c_data16(dev
, 1, 0xf0, &buf
);
716 sn9c20x_read_i2c_data16(dev
, 1, 0x3a, &buf
);
717 buf
= (buf
& 0xfaff) + 0x0500;
718 sn9c20x_write_i2c_data16(dev
, 1, 0x3a, &buf
);
720 sn9c20x_read_i2c_data16(dev
, 1, 0x9b, &buf
);
721 buf
= (buf
& 0xfaff) + 0x0500;
722 sn9c20x_write_i2c_data16(dev
, 1, 0x9b, &buf
);
724 sn9c20x_set_raw(dev
);
729 int mt9m111_set_yuv422(struct usb_microdia
*dev
)
733 /* select address-space: IFP */
735 sn9c20x_write_i2c_data16(dev
, 1, 0xf0, &buf
);
737 sn9c20x_read_i2c_data16(dev
, 1, 0x3a, &buf
);
739 sn9c20x_write_i2c_data16(dev
, 1, 0x3a, &buf
);
741 sn9c20x_read_i2c_data16(dev
, 1, 0x9b, &buf
);
743 sn9c20x_write_i2c_data16(dev
, 1, 0x9b, &buf
);
745 sn9c20x_set_raw(dev
);
750 int mt9v111_setup_autoexposure(struct usb_microdia
*dev
)
756 /* Switch to IFP-register address space: */
757 ret
= mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_IFP
);
759 return -11; /* -EAGAIN */
760 /* Set target luminance and tracking accuracy: */
761 buf
[0] = MT9V111_IFP_AE_TRACKINGACCURACY(12)
762 /* 0-255 (default: 16) */
763 | MT9V111_IFP_AE_TARGETLUMINANCE(100);
764 /* 0-255 (default: 100) */
765 ret
= sn9c20x_write_i2c_data16(dev
, 1,
766 MT9V111_IFPREG_AE_TARGETLUMCTL
, buf
);
767 /* Set speed and sensitivity: */
768 buf
[0] = MT9V111_IFP_AE_DELAY(4)
769 /* 0-7 (fastest-slowest) (default: 4) */
770 | MT9V111_IFP_AE_SPEED(4)
771 /* 0-7 (fastest-slowest) (default: 4) */
772 | MT9V111_IFP_AE_STEPSIZE_MEDIUM
;
773 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
774 MT9V111_IFPREG_AE_SPEEDSENSCTL
, buf
);
775 /* Horizontal boundaries of AE measurement window: */
776 buf
[0] = MT9V111_IFP_AE_WINBOUNDARY_RIGHT(1020)
777 /* 0-1020 (pixel) (default: 1020) */
778 | MT9V111_IFP_AE_WINBOUNDARY_LEFT(12);
779 /* 0-1020 (pixel) (default: 12) */
780 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
781 MT9V111_IFPREG_AE_HWINBOUNDARY
, buf
);
782 /* Vertical boundaries of AE measurement window: */
783 buf
[0] = MT9V111_IFP_AE_WINBOUNDARY_BOTTOM(510)
784 /* 0-510 (pixel) (default: 510) */
785 | MT9V111_IFP_AE_WINBOUNDARY_TOP(32);
786 /* 0-510 (pixel) (default: 32) */
787 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
788 MT9V111_IFPREG_AE_VWINBOUNDARY
, buf
);
789 /* Horizontal boundaries of AE measurement window
790 * for back light compensation: */
791 buf
[0] = MT9V111_IFP_AE_WINBOUNDARY_RIGHT_BLC(480)
792 /* 0-1020 (pixel) (default: 480) */
793 | MT9V111_IFP_AE_WINBOUNDARY_LEFT_BLC(160);
794 /* 0-1020 (pixel) (default: 160) */
795 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
796 MT9V111_IFPREG_AE_HWINBOUNDARY_BLC
, buf
);
797 /* Vertical boundaries of AE measurement window
798 * for back light compensation: */
799 buf
[0] = MT9V111_IFP_AE_WINBOUNDARY_BOTTOM_BLC(360)
800 /* 0-510 (pixel) (default: 360) */
801 | MT9V111_IFP_AE_WINBOUNDARY_TOP_BLC(120);
802 /* 0-510 (pixel) (default: 120) */
803 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
804 MT9V111_IFPREG_AE_VWINBOUNDARY_BLC
, buf
);
805 /* Set digital gains limit: */
806 buf
[0] = MT9V111_IFP_AE_MAXGAIN_POSTLS(64)
807 /* 0-255 (default: 64) */
808 | MT9V111_IFP_AE_MAXGAIN_PRELS(16);
809 /* 0-255 (default: 16) */
810 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
811 MT9V111_IFPREG_AE_DGAINSLIMITS
, buf
);
812 /* Read current value of IFP-register 0x06: */
813 ret2
= sn9c20x_read_i2c_data16(dev
, 1, MT9V111_IFPREG_OPMODECTL
, buf
);
815 /* Set new value for register 0x06: */
816 buf
[0] = (buf
[0] & 0xffe3) | MT9V111_IFP_AE_WIN_COMBINED
|
817 MT9V111_IFP_OPMODE_BYPASSCOLORCORR
;
818 /* NOTE: BYPASS COLOR CORRECTION HAS
819 * TO BE SET FOR PERMANENT AE ! */
820 /* Write new value to IFP-register 0x06:*/
821 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
822 MT9V111_IFPREG_OPMODECTL
, buf
);
824 if (ret
< 0 || ret2
< 0) {
825 UDIA_WARNING("One or more errors occured during "
826 "setup of AE registers.\n");
832 int mt9v111_setup_autowhitebalance(struct usb_microdia
*dev
)
837 /* Switch to IFP-register address space: */
838 ret
= mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_IFP
);
840 return -11; /* -EAGAIN */
842 buf
[0] = MT9V111_IFP_AWB_ADDON_RED(0) /* 0-255 (default: 0) */
843 | MT9V111_IFP_AWB_ADDON_BLUE(0); /* 0-255 (default: 0) */
844 ret
= sn9c20x_write_i2c_data16(dev
, 1, MT9V111_IFPREG_AWB_TINT
, buf
);
845 /* Set AWB speed and color saturation: */
846 buf
[0] = MT9V111_IFP_AWB_SATURATION_FULL
847 | MT9V111_IFP_AWB_AUTOSATLOWLIGHT_ENABLE
848 | MT9V111_IFP_AWB_DELAY(4)
849 /* 0-7 (fastest-slowest) (default: 4) */
850 | MT9V111_IFP_AWB_SPEED(4);
851 /* 0-7 (fastest-slowest) (default: 4) */
852 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
853 MT9V111_IFPREG_AWB_SPEEDCOLORSATCTL
, buf
);
854 /* Boundaries of AWB measurement window: */
855 buf
[0] = MT9V111_IFP_AWB_WINBOUNDARY_TOP(0)
856 /* 0-480 (pixel) (default: 0) */
857 | MT9V111_IFP_AWB_WINBOUNDARY_BOTTOM(480)
858 /* 0-480 (pixel) (default: 448) */
859 | MT9V111_IFP_AWB_WINBOUNDARY_LEFT(0)
860 /* 0-960 (pixel) (default: 0) */
861 | MT9V111_IFP_AWB_WINBOUNDARY_RIGHT(640);
862 /* 0-960 (pixel) (default: 640) */
863 ret
+= sn9c20x_write_i2c_data16(dev
, 1,
864 MT9V111_IFPREG_AWB_WINBOUNDARY
, buf
);
867 UDIA_WARNING("One or more errors occured during "
868 "setup of AWB registers.\n");
874 int mt9v011_set_exposure(struct usb_microdia
*dev
)
879 buf
[0] = (dev
->vsettings
.exposure
>> 12);
881 ret
|= sn9c20x_write_i2c_data(dev
, 2, 0x09, buf
);
882 /* Maybe we have to disable AE/AWB/flicker avoidence (currently not
883 * used) for MT9V111 sensor, because IFP controls this register if
884 * one of them is enabled. */
888 int mt9v111_set_exposure(struct usb_microdia
*dev
)
894 ret
= mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_SENSOR
);
897 return -11; /* -EAGAIN */
899 buf
[0] = (dev
->vsettings
.exposure
>> 12);
901 ret
|= sn9c20x_write_i2c_data(dev
, 2, 0x09, buf
);
902 /* Maybe we have to disable AE/AWB/flicker avoidence (currently not
903 * used) for MT9V111 sensor, because IFP controls this register if
904 * one of them is enabled. */
908 int mt9v011_set_hvflip(struct usb_microdia
*dev
)
913 if ((dev
->vsettings
.hflip
> 1) || (dev
->vsettings
.hflip
< 0))
915 if ((dev
->vsettings
.vflip
> 1) || (dev
->vsettings
.vflip
< 0))
918 ret
= sn9c20x_read_i2c_data(dev
, 2, 0x20, buf
);
922 if (dev
->vsettings
.hflip
) {
924 /* (MSB) set bit 15: read out from
925 * bottom to top (upside down) */
927 /* (LSB) set bit 7: readout starting 1 row later */
929 buf
[0] &= 0x7f; /* (MSB) unset bit 15: normal readout */
930 buf
[1] &= 0x7f; /* (LSB) unset bit 7: normal readout */
932 if (dev
->vsettings
.vflip
) {
934 /* (MSB) set bit 14: read out from right to left (mirrored) */
936 /* (LSB) set bit 5: readout starting 1 column later */
938 buf
[0] &= 0xbf; /* (MSB) unset bit 14: normal readout */
939 buf
[1] &= 0xdf; /* (LSB) unset bit 5: normal readout */
942 ret
= sn9c20x_write_i2c_data(dev
, 2, 0x20, buf
);
946 int mt9v111_set_hvflip(struct usb_microdia
*dev
)
951 if ((dev
->vsettings
.hflip
> 1) || (dev
->vsettings
.hflip
< 0))
953 if ((dev
->vsettings
.vflip
> 1) || (dev
->vsettings
.vflip
< 0))
957 ret
= mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_SENSOR
);
959 return -11; /* -EAGAIN */
961 ret
= sn9c20x_read_i2c_data(dev
, 2, 0x20, buf
);
965 if (dev
->vsettings
.hflip
) {
967 /* (MSB) set bit 15: read out from
968 * bottom to top (upside down) */
970 /* (LSB) set bit 7: readout starting 1 row later */
972 buf
[0] &= 0x7f; /* (MSB) unset bit 15: normal readout */
973 buf
[1] &= 0x7f; /* (LSB) unset bit 7: normal readout */
975 if (dev
->vsettings
.vflip
) {
977 /* (MSB) set bit 14: read out from right to left (mirrored) */
979 /* (LSB) set bit 5: readout starting 1 column later */
981 buf
[0] &= 0xbf; /* (MSB) unset bit 14: normal readout */
982 buf
[1] &= 0xdf; /* (LSB) unset bit 5: normal readout */
985 ret
= sn9c20x_write_i2c_data(dev
, 2, 0x20, buf
);
989 int mt9v111_set_autoexposure(struct usb_microdia
*dev
)
994 /* Switch to IFP-register address space: */
995 ret
= mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_IFP
);
997 return -11; /* -EAGAIN */
998 /* Read current value of IFP-register 0x06: */
999 ret
= sn9c20x_read_i2c_data16(dev
, 1, MT9V111_IFPREG_OPMODECTL
, buf
);
1001 UDIA_ERROR("Error: setting of auto exposure failed: "
1002 "error while reading from IFP-register 0x06\n");
1005 /* Set new value for register 0x06: */
1006 if (dev
->vsettings
.auto_exposure
== 1) {
1007 /* Enable automatic exposure: */
1008 buf
[0] |= MT9V111_IFP_OPMODE_AUTOEXPOSURE
;
1009 } else if (dev
->vsettings
.auto_exposure
== 0) {
1010 /* Disable automatic exposure: */
1011 buf
[0] &= ~MT9V111_IFP_OPMODE_AUTOEXPOSURE
;
1014 /* Write new value to IFP-register 0x06: */
1015 ret
= sn9c20x_write_i2c_data16(dev
, 1, MT9V111_IFPREG_OPMODECTL
, buf
);
1017 UDIA_ERROR("Error: setting of auto exposure failed: "
1018 "error while writing to IFP-register 0x06\n");
1024 int mt9v111_set_autowhitebalance(struct usb_microdia
*dev
)
1029 /* Switch to IFP-register address space: */
1030 ret
= mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_IFP
);
1032 return -11; /* -EAGAIN */
1033 /* Read current value of IFP-register 0x06: */
1034 ret
= sn9c20x_read_i2c_data16(dev
, 1,
1035 MT9V111_IFPREG_OPMODECTL
, buf
);
1037 UDIA_ERROR("Error: setting of auto whitebalance failed: "
1038 "error while reading from IFP-register 0x06\n");
1041 /* Set new value for register 0x06: */
1042 if (dev
->vsettings
.auto_whitebalance
== 1) {
1043 /* Enable automatic exposure: */
1044 buf
[0] |= MT9V111_IFP_OPMODE_AUTOWHITEBALANCE
;
1045 } else if (dev
->vsettings
.auto_whitebalance
== 0) {
1046 /* Disable automatic exposure: */
1047 buf
[0] &= ~MT9V111_IFP_OPMODE_AUTOWHITEBALANCE
;
1050 /* Write new value to IFP-register 0x06:*/
1051 ret
= sn9c20x_write_i2c_data16(dev
, 1,
1052 MT9V111_IFPREG_OPMODECTL
, buf
);
1054 UDIA_ERROR("Error: setting of auto whitebalance failed: "
1055 "error while writing to IFP-register 0x06\n");
1061 int mt9v111_set_autocorrections(struct usb_microdia
*dev
, int enable
)
1066 /* Switch to IFP-register address space: */
1067 ret
= mt9v111_select_address_space(dev
, MT9V111_ADDRESSSPACE_IFP
);
1069 return -11; /* -EAGAIN */
1070 /* Read current value of IFP-register 0x06: */
1071 ret
= sn9c20x_read_i2c_data16(dev
, 1,
1072 MT9V111_IFPREG_OPMODECTL
, buf
);
1074 UDIA_ERROR("Error: setting of sensor auto-correction functions "
1075 "failed: error while reading from IFP-register 0x06\n");
1078 /* Set new value for register 0x06: */
1080 buf
[0] |= MT9V111_IFP_OPMODE_APERTURECORR
|
1081 MT9V111_IFP_OPMODE_ONTHEFLYDEFECTCORR
;
1082 else if (enable
== 0)
1083 buf
[0] &= ~(MT9V111_IFP_OPMODE_APERTURECORR
|
1084 MT9V111_IFP_OPMODE_ONTHEFLYDEFECTCORR
);
1087 /* Write new value to IFP-register 0x06: */
1088 ret
= sn9c20x_write_i2c_data16(dev
, 1,
1089 MT9V111_IFPREG_OPMODECTL
, buf
);
1091 UDIA_ERROR("Error: setting of sensor auto-correction functions "
1092 "failed: error while writing to IFP-register 0x06\n");