Fix SXGA support to enforce bayer format
[microdia.git] / micron.c
blobbfc9582c5e559aeb15337b60b5a4bbb9f24df827
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 "sn9c20x.h"
29 #include "sn9c20x-bridge.h"
30 #include "micron.h"
32 struct sn9c20x_i2c_regs mt9v112_init[] = {
33 {0x0d, 0x0021}, {0x0d, 0x0020}, {0xf0, 0x0000},
34 {0x34, 0xc019}, {0x0a, 0x0011}, {0x0b, 0x000b},
35 {0x20, 0x0703}, {0x35, 0x2022}, {0xf0, 0x0001},
36 {0x05, 0x0000}, {0x06, 0x340c}, {0x3b, 0x042a},
37 {0x3c, 0x0400}, {0xf0, 0x0002}, {0x2e, 0x0c58},
38 {0x5b, 0x0001}, {0xc8, 0x9f0b}, {0xf0, 0x0001},
39 {0x9b, 0x5300}, {0xf0, 0x0000}, {0x2b, 0x0020},
40 {0x2c, 0x002a}, {0x2d, 0x0032}, {0x2e, 0x0020},
41 {0x09, 0x01dc}, {0x01, 0x000c}, {0x02, 0x0020},
42 {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
43 {0x05, 0x0098}, {0x20, 0x0703}, {0x09, 0x01f2},
44 {0x2b, 0x00a0}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
45 {0x2e, 0x00a0}, {0x01, 0x000c}, {0x02, 0x0020},
46 {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
47 {0x05, 0x0098}, {0x09, 0x01c1}, {0x2b, 0x00ae},
48 {0x2c, 0x00ae}, {0x2d, 0x00ae}, {0x2e, 0x00ae},
49 {0xff, 0xffff}
52 struct sn9c20x_i2c_regs mt9v111_init[] = {
53 {0x01, 0x0004}, /* select sensor address space */
54 {0x0d, 0x0001}, /* Resets chip */
55 {0x0d, 0x0000},
56 {0x01, 0x0001}, /* select IFP address space */
57 {0x02, 0x0016}, /* ??? */
58 /* 0x03: Color Correction Register 3 */
59 /* 0x04: Color Correction Register 4 */
60 {0x03, 0x01e1}, /* ??? */
61 {0x04, 0x0281}, /* ??? */
62 /* 0x05: Aperture Correction (Sharpening) */
63 {0x05, 0x0004}, /* 100% sharpening,
64 no automatic sharpness reduction at low light: no sharpening */
65 /* 0x07: IFP Soft Reset */
66 /* 0x08: Output Format Control */
67 {0x07, 0x3002}, /* reset */
68 {0x21, 0x0000},
69 {0x25, 0x4024},
70 {0x26, 0xff03},
71 {0x27, 0xff10},
72 {0x2b, 0x7828},
73 {0x2c, 0xb43c},
74 {0x2d, 0xf0a0},
75 {0x2e, 0x0c64},
76 {0x2f, 0x0064},
77 {0x67, 0x4010},
78 {0x06, 0x301c}, /* stop AWB at the current values,
79 no auto exposure */
80 {0x08, 0x0480}, /* bypass entire image processing,
81 raw 8+2 Bayer data output directly */
82 {0x01, 0x0004}, /* select sensor address space */
83 {0x02, 0x0016}, /* start with column 22 */
84 /* 0x03: Window Height */
85 /* 0x04: Window Width */
86 {0x03, 0x01e6}, /* 486 */
87 {0x04, 0x0286}, /* 646 */
88 /* 0x05: Horizontal Blanking */
89 /* 0x06: Vertical Blanking */
90 {0x05, 0x0004}, /* 4 columns (pixel clocks) */
91 {0x06, 0x0000}, /* 0 rows */
92 /* 0x07: Output Control */
93 /* 0x08: Row Start */
94 {0x07, 0x3002}, /* normal operation + chip enable*/
95 {0x08, 0x0008}, /* row 8 */
96 /* 0x0c: Shutter Delay */
97 /* 0x0d: Reset (Soft) */
98 {0x0c, 0x0000}, /* 0 master clocks */
99 {0x0d, 0x0000}, /* return to normal operation */
100 {0x0e, 0x0000},
101 {0x0f, 0x0000},
102 {0x10, 0x0000},
103 {0x11, 0x0000},
104 /* 0x12: 2X Zoom Col Start
105 => 0x1e bit 0 must be set to activate zoom */
106 /* 0x13: 2X Zoom Row Start
107 => 0x1e bit 0 must be set to activate zoom */
108 {0x12, 0x00b0}, /* column 176 */
109 {0x13, 0x007c}, /* row 124 */
110 {0x14, 0x0000},
111 {0x15, 0x0000},
112 {0x16, 0x0000},
113 {0x17, 0x0000},
114 {0x18, 0x0000},
115 {0x19, 0x0000},
116 {0x1a, 0x0000},
117 {0x1b, 0x0000},
118 {0x1c, 0x0000},
119 {0x1d, 0x0000},
120 {0x30, 0x0000},
121 {0x30, 0x0005},
122 {0x31, 0x0000},
123 /* 0x02: Column Start */
124 /* 0x03: Window Height */
125 {0x02, 0x0016}, /* coulmn 22 */
126 {0x03, 0x01e1}, /* 481 */
127 /* 0x04: Window Width */
128 /* 0x05: Horizontal Blanking */
129 {0x04, 0x0281}, /* 641 */
130 {0x05, 0x0004}, /* 4 columns (pixel clocks) */
131 /* 0x06: Vertical Blanking */
132 /* 0x07: Output Control */
133 {0x06, 0x0000}, /* 0 rows */
134 {0x07, 0x3002}, /* normal operation + chip enable */
135 /* 0x06: Vertical Blanking */
136 {0x06, 0x002d}, /* 45 rows */
137 /* 0x05: Horizontal Blanking */
138 {0x05, 0x0004}, /* 4 columns (pixel clocks) */
139 /* 0x09: Shutter Width */
140 {0x09, 0x0064}, /* integration of 100 rows */
141 /* 0x2b: Green 1 Gain */
142 /* 0x2c: Blue Gain */
143 {0x2b, 0x00a0}, /* 32*0.03125*2 = 2 */
144 {0x2c, 0x00a0}, /* 32*0.03125*2 = 2 */
145 /* 0x2d: Red Gain */
146 /* 0x2e: Green 2 Gain */
147 {0x2d, 0x00a0}, /* 32*0.03125*2 = 2 */
148 {0x2e, 0x00a0}, /* 32*0.03125*2 = 2 */
149 /* 0x02: Column Start */
150 /* 0x03: Window Hight */
151 {0x02, 0x0016}, /* coulmn 22 */
152 {0x03, 0x01e1}, /* 481 */
153 /* 0x04: Window Width */
154 /* 0x05: Horizontal Blanking */
155 {0x04, 0x0281}, /* 641 */
156 {0x05, 0x0004}, /* 4 columns (pixel clocks) */
157 /* 0x06: Vertical Blanking */
158 /* 0x07: Output Control */
159 {0x06, 0x002d}, /* 45 rows */
160 {0x07, 0x3002}, /* RESERVED options */
161 /* Writes to0x0e: UNDOCUMENTED */
162 {0x0e, 0x0008},
163 /* 0x06: Vertical Blanking */
164 {0x06, 0x002d}, /* 45 rows */
165 /* 0x05: Horizontal Blanking */
166 {0x05, 0x0004}, /* 4 columns (pixel clocks) */
167 {0xff, 0xffff},
170 struct sn9c20x_i2c_regs mt9v011_init[] = {
171 /* 0x07: Output Control */
172 {0x07, 0x0002}, /* chip enable, normal operation */
173 /* 0x0d: Soft Reset */
174 {0x0d, 0x0001}, /* reset */
175 /* 0x0d: Soft Reset */
176 {0x0d, 0x0000}, /* resume operation */
177 /* 0x01: Row start */
178 /* 0x02: Column Start */
179 {0x01, 0x0008}, /* start with row 8 */
180 {0x02, 0x0016}, /* start with column 22 */
181 /* 0x03: Window Height */
182 /* 0x04: Window Width */
183 {0x03, 0x01e1}, /* 481 */
184 {0x04, 0x0281}, /* 641 */
185 /* 0x05: Horizontal Blanking */
186 /* 0x06: Vertical Blanking */
187 {0x05, 0x0083}, /* 131 columns (pixel clocks) */
188 {0x06, 0x0006}, /* 6 rows */
189 /* 0x0d: Soft Reset */
190 {0x0d, 0x0002}, /* UNKNOWN */
191 /* 0x0a: Pixel Clock Speed */
192 /* 0x0b: Frame Restart */
193 {0x0a, 0x0000}, /* default */
194 {0x0b, 0x0000}, /* (has no effect/no restart) */
195 /* 0x0c: Shutter Delay */
196 /* 0x0d: Soft Reset */
197 {0x0c, 0x0000}, /* 0 master clocks */
198 {0x0d, 0x0000}, /* resume operation */
199 {0x0e, 0x0000},
200 {0x0f, 0x0000},
201 {0x10, 0x0000},
202 {0x11, 0x0000},
203 /* 0x12: 2X Zoom Column Start (from MT9V111 datasheet) */
204 /* 0x13: 2X Zoom Row Start (from MT9V111 datasheet) */
205 {0x12, 0x0000},
206 /* column 0 => bit0 of reg 0x1e must be set to activate zoom */
207 {0x13, 0x0000},
208 /* row 0 => bit0 of reg 0x1e must be set to activate zoom */
209 {0x14, 0x0000},
210 {0x15, 0x0000},
211 {0x16, 0x0000},
212 {0x17, 0x0000},
213 {0x18, 0x0000},
214 {0x19, 0x0000},
215 {0x1a, 0x0000},
216 {0x1b, 0x0000},
217 {0x1c, 0x0000},
218 {0x1d, 0x0000},
219 {0x32, 0x0000},
220 /* 0x20: Read Mode */
221 {0x20, 0x1101}, /* output all frames (including bad frames) */
222 {0x21, 0x0000},
223 {0x22, 0x0000},
224 {0x23, 0x0000},
225 {0x24, 0x0000},
226 {0x25, 0x0000},
227 {0x26, 0x0000},
228 {0x27, 0x0024},
229 {0x2f, 0xf7b0},
230 {0x30, 0x0005},
231 {0x31, 0x0000},
232 {0x32, 0x0000},
233 {0x33, 0x0000},
234 {0x34, 0x0100},
235 {0x3d, 0x068f},
236 {0x40, 0x01e0},
237 {0x41, 0x00d1},
238 {0x44, 0x0082},
239 {0x5a, 0x0000},
240 {0x5b, 0x0000},
241 {0x5c, 0x0000},
242 {0x5d, 0x0000},
243 {0x5e, 0x0000},
244 {0x5f, 0xa31d},
245 {0x62, 0x0611},
246 /* 0x0a: Pixel Clock Speed */
247 {0x0a, 0x0000}, /* default */
248 /* 0x06: Vertical Blanking */
249 {0x06, 0x0029}, /* 41 rows */
250 /* 0x05: Horizontal Blanking */
251 {0x05, 0x0009}, /* 9 columns (pixel clocks) */
252 /* 0x20: Read Mode */
253 {0x20, 0x1101}, /* output all frames (including bad ones) */
254 /* 0x20: Read Mode */
255 {0x20, 0x1101}, /* output all frames (including bad ones) */
256 /* 0x09: Shutter Width */
257 {0x09, 0x0064}, /* integration of 100 rows */
258 /* 0x07: Output Control */
259 {0x07, 0x0003},
260 /* dont update changes until bit0=0, chip enable, normal operation */
261 /* 0x2b: Green 1 Gain */
262 /* 0x2c: Blue Gain */
263 {0x2b, 0x0033}, /* 51*0.03125*1 = 1.59375 */
264 {0x2c, 0x00a0}, /* 32*0.03125*2 = 2 */
265 /* 0x2d: Red Gain */
266 /* 0x2e: Green 2 Gain */
267 {0x2d, 0x00a0}, /* 32*0.03125*2 = 2 */
268 {0x2e, 0x0033}, /* 51*0.03125*1 = 1.59375 */
269 /* 0x07: Output Control */
270 {0x07, 0x0002}, /* chip enable, normal operation */
271 /* 0x0a: Pixel Clock Speed */
272 {0x06, 0x0000}, /* default */
273 /* 0x06: Vertical Blanking */
274 {0x06, 0x0029}, /* 41 rows */
275 /* 0x05: Horizontal Blanking */
276 {0x05, 0x0009}, /* 9 columns (pixel clocks) */
277 {0xff, 0xffff},
280 struct sn9c20x_i2c_regs mt9m001_init[] = {
281 {0x07, 0x0000},
282 {0x07, 0x0002},
283 {0x0d, 0x0001},
284 {0x0d, 0x0000},
285 {0x01, 0x000e},
286 {0x02, 0x0014},
287 {0x03, 0x03c1},
288 {0x04, 0x0501},
289 {0x05, 0x0083},
290 {0x06, 0x0006},
291 {0x0d, 0x0002},
292 {0x09, 0x0000},
293 {0x0a, 0x0000},
294 {0x0b, 0x0000},
295 {0x0c, 0x0000},
296 {0x11, 0x0000},
297 {0x1e, 0x8000},
298 {0x20, 0x1105},
299 {0x2b, 0x0008},
300 {0x2c, 0x0010},
301 {0x2d, 0x0014},
302 {0x2e, 0x0008},
303 {0x5f, 0x8904},
304 {0x60, 0x0000},
305 {0x61, 0x0000},
306 {0x62, 0x0498},
307 {0x63, 0x0000},
308 {0x68, 0x0000},
309 {0x20, 0x111d},
310 {0x06, 0x00f2},
311 {0x05, 0x0013},
312 {0x20, 0x511d},
313 {0x20, 0xd11d},
314 {0x09, 0x03e8},
315 {0x07, 0x0003},
316 {0x2b, 0x0010},
317 {0x2c, 0x0010},
318 {0x2d, 0x0010},
319 {0x2e, 0x0010},
320 {0x07, 0x0002},
321 {0x06, 0x00f2},
322 {0x05, 0x0013},
323 {0x09, 0x043c},
324 {0x07, 0x0003},
325 {0x2b, 0x0023},
326 {0x2c, 0x003f},
327 {0x2d, 0x003a},
328 {0x2e, 0x0023},
329 {0x07, 0x0002},
330 {0x09, 0x0879},
331 {0x07, 0x0003},
332 {0x2b, 0x0027},
333 {0x2c, 0x003f},
334 {0x2d, 0x0039},
335 {0x2e, 0x0027},
336 {0x07, 0x0002},
337 {0x09, 0x0b4c},
338 {0x07, 0x0003},
339 {0x2b, 0x0029},
340 {0x2c, 0x003f},
341 {0x2d, 0x0035},
342 {0x2e, 0x0029},
343 {0x07, 0x0002},
344 {0x09, 0x0e1f},
345 {0x07, 0x0003},
346 {0x2d, 0x0030},
347 {0x07, 0x0002},
348 {0x09, 0x103e},
349 {0x07, 0x0003},
350 {0x2d, 0x002b},
351 {0x07, 0x0002},
352 {0x09, 0x10f2},
353 {0x07, 0x0003},
354 {0x2b, 0x002a},
355 {0x2c, 0x003f},
356 {0x2d, 0x002a},
357 {0x2c, 0x002a},
358 {0x07, 0x0002},
359 {0x07, 0x0003},
360 {0x07, 0x0002},
361 {0x07, 0x0003},
362 {0x07, 0x0002},
363 {0x07, 0x0003},
364 {0x07, 0x0002},
365 {0x07, 0x0000},
368 struct sn9c20x_i2c_regs mt9m111_init[] = {
369 {0xf0, 0x0000},
370 /* Reset sensor */
371 {0x0d, 0x0008}, {0x0d, 0x0009}, {0x0d, 0x0008},
372 /* Select Page map 0x01
373 * This means all new writes now have the address prefix 0x1.
374 * Example: 0x3a becomes 0x13a. */
375 {0xf0, 0x0001},
376 /* change pixel format of both contexts */
377 {0x3a, 0x4300}, {0x9b, 0x4300},
378 /* setup AE, AWB, etc */
379 {0x06, 0x708e},
380 /* Switch back to Page map 0x00 */
381 {0xf0, 0x0000},
382 {0xff, 0xffff},
385 int mt9m111_set_exposure(struct usb_sn9c20x *dev)
387 int ret;
388 __u16 exposure, page;
390 exposure = dev->vsettings.exposure << 8;
392 ret = 0;
393 page = 0;
394 ret |= sn9c20x_write_i2c_data16(dev, 1, 0xF0, &page);
395 ret |= sn9c20x_write_i2c_data16(dev, 1, 0x09, &exposure);
397 return ret;
400 int mt9m111_set_autoexposure(struct usb_sn9c20x *dev)
402 int ret;
403 __u16 data, page;
405 ret = 0;
406 page = 1;
407 ret |= sn9c20x_write_i2c_data16(dev, 1, 0xF0, &page);
408 ret |= sn9c20x_read_i2c_data16(dev, 1, 0x06, &data);
411 if (dev->vsettings.auto_exposure == 1) {
412 data |= 0x7000;
413 } else if (dev->vsettings.auto_exposure == 0) {
414 data &= ~0x7000;
415 } else
416 return -EINVAL;
418 ret |= sn9c20x_write_i2c_data16(dev, 1, 0x06, &data);
419 page = 0;
420 ret |= sn9c20x_write_i2c_data16(dev, 1, 0xF0, &page);
422 if (ret < 0) {
423 UDIA_ERROR("Error: setting of auto exposure failed: "
424 "error while writing to IFP-register 0x06\n");
425 return ret;
427 return 0;
430 int mt9m111_set_autowhitebalance(struct usb_sn9c20x *dev)
432 int ret;
433 __u16 data, page;
435 ret = 0;
436 page = 1;
437 ret |= sn9c20x_write_i2c_data16(dev, 1, 0xF0, &page);
438 ret |= sn9c20x_read_i2c_data16(dev, 1, 0x06, &data);
440 if (dev->vsettings.auto_whitebalance == 1) {
441 data |= 0x0002;
442 } else if (dev->vsettings.auto_whitebalance == 0) {
443 data &= ~0x0002;
446 ret |= sn9c20x_write_i2c_data16(dev, 1, 0x06, &data);
447 page = 0;
448 ret |= sn9c20x_write_i2c_data16(dev, 1, 0xF0, &page);
450 return ret;
453 int mt9v111_select_address_space(struct usb_sn9c20x *dev, __u8 address_space)
455 __u8 buf[2];
456 int retI2C;
457 int k;
459 /* check if selection is valid: */
460 if ((address_space != MT9V111_ADDRESSSPACE_IFP) &&
461 (address_space != MT9V111_ADDRESSSPACE_SENSOR)) {
462 UDIA_WARNING("invalid register address space "
463 "selection for sensor MT9V111/MI0360SOC !\n");
464 return -1;
466 /* read address space slection register: */
467 k = 0;
468 retI2C = -1;
469 while ((k < 3) && (retI2C != 0)) {
470 retI2C = sn9c20x_read_i2c_data(dev, 2, 0x01, buf);
471 if (retI2C != 0 && k < 2)
472 udelay(1000);
473 k++;
475 if (retI2C != 0) {
476 UDIA_ERROR("MT9V111/MI0360SOC (I2C-slave 0x5c): "
477 "read of reg0x01 (address space selection) failed !\n");
478 return -1;
480 /* check current address space: */
481 if ((buf[0] != 0x00) || (buf[1] != address_space)) {
482 k = 0;
483 retI2C = -1;
484 while ((k < 3) && (retI2C != 0)) {
485 /* switch address space: */
486 buf[0] = 0x00; buf[1] = address_space;
487 retI2C = sn9c20x_write_i2c_data(dev, 2, 0x01, buf);
488 if (retI2C != 0 && k < 2)
489 udelay(1000);
490 k++;
492 if (retI2C != 0) {
493 if (address_space == MT9V111_ADDRESSSPACE_IFP)
494 UDIA_ERROR("MT9V111/MI0360SOC "
495 "(I2C-slave 0x5c): switch to IFP "
496 "address space failed !\n");
497 else
498 UDIA_ERROR("MT9V111/MI0360SOC "
499 "(I2C-slave 0x5c): switch to sensor "
500 "core address space failed !\n");
501 return -1;
504 return 0;
507 int mt9v011_probe(struct usb_sn9c20x *dev)
509 __u16 buf;
510 int ret = -EINVAL;
512 dev->camera.address = 0x5d;
513 ret = sn9c20x_read_i2c_data16(dev, 1, 0xff, &buf);
514 if ((ret == 0) && (buf == 0x8243))
515 ret = MT9V011_SENSOR;
517 return ret;
520 int mt9v111_probe(struct usb_sn9c20x *dev)
522 __u16 buf;
523 int ret = -EINVAL;
525 dev->camera.address = 0x5c;
526 /* Select address-space: sensor */
527 buf = 0x04;
528 ret = sn9c20x_write_i2c_data16(dev, 1, 0x01, &buf);
529 if (ret != 0)
530 return ret;
532 ret = sn9c20x_read_i2c_data16(dev, 1, 0xff, &buf);
533 if ((ret == 0) && (buf == 0x823a))
534 ret = MT9V111_SENSOR;
536 return ret;
539 int mt9v112_probe(struct usb_sn9c20x *dev)
541 int ret;
542 __u16 buf;
543 dev->camera.address = 0x5d;
544 /* Select address-space: sensor */
545 buf = 0x00;
546 ret = sn9c20x_write_i2c_data16(dev, 1, 0xf0, &buf);
547 if (ret < 0) {
548 dev->camera.address = 0x48;
549 ret = sn9c20x_write_i2c_data16(dev, 1, 0xf0, &buf);
550 if (ret < 0)
551 return ret;
555 ret = sn9c20x_read_i2c_data16(dev, 1, 0x00, &buf);
556 if ((ret == 0) && (buf == 0x1229))
557 return MT9V112_SENSOR;
559 return -EINVAL;
562 int mt9v011_set_exposure(struct usb_sn9c20x *dev)
564 int ret = 0;
565 __u16 exp;
567 exp = (dev->vsettings.exposure << 4);
568 ret |= sn9c20x_write_i2c_data16(dev, 1, 0x09, &exp);
569 /* Maybe we have to disable AE/AWB/flicker avoidence (currently not
570 * used) for MT9V111 sensor, because IFP controls this register if
571 * one of them is enabled. */
572 return ret;
575 int mt9v111_set_exposure(struct usb_sn9c20x *dev)
577 int ret = 0;
578 __u16 exp;
581 ret = mt9v111_select_address_space(dev, MT9V111_ADDRESSSPACE_SENSOR);
583 if (ret < 0)
584 return -11; /* -EAGAIN */
586 exp = (dev->vsettings.exposure << 4);
587 ret |= sn9c20x_write_i2c_data16(dev, 1, 0x09, &exp);
588 /* Maybe we have to disable AE/AWB/flicker avoidence (currently not
589 * used) for MT9V111 sensor, because IFP controls this register if
590 * one of them is enabled. */
591 return ret;
594 int mt9v011_set_hvflip(struct usb_sn9c20x *dev)
596 int ret = 0;
597 __u8 buf[2];
599 if ((dev->vsettings.hflip > 1) || (dev->vsettings.hflip < 0))
600 return -EINVAL;
601 if ((dev->vsettings.vflip > 1) || (dev->vsettings.vflip < 0))
602 return -EINVAL;
604 ret = sn9c20x_read_i2c_data(dev, 2, 0x20, buf);
605 if (ret < 0)
606 return ret;
608 if (dev->vsettings.hflip) {
609 buf[0] |= 0x80;
610 /* (MSB) set bit 15: read out from
611 * bottom to top (upside down) */
612 buf[1] |= 0x80;
613 /* (LSB) set bit 7: readout starting 1 row later */
614 } else {
615 buf[0] &= 0x7f; /* (MSB) unset bit 15: normal readout */
616 buf[1] &= 0x7f; /* (LSB) unset bit 7: normal readout */
618 if (dev->vsettings.vflip) {
619 buf[0] |= 0x40;
620 /* (MSB) set bit 14: read out from right to left (mirrored) */
621 buf[1] |= 0x20;
622 /* (LSB) set bit 5: readout starting 1 column later */
623 } else {
624 buf[0] &= 0xbf; /* (MSB) unset bit 14: normal readout */
625 buf[1] &= 0xdf; /* (LSB) unset bit 5: normal readout */
628 ret = sn9c20x_write_i2c_data(dev, 2, 0x20, buf);
629 return ret;
632 int mt9v111_set_hvflip(struct usb_sn9c20x *dev)
634 int ret = 0;
635 __u8 buf[2];
637 if ((dev->vsettings.hflip > 1) || (dev->vsettings.hflip < 0))
638 return -EINVAL;
639 if ((dev->vsettings.vflip > 1) || (dev->vsettings.vflip < 0))
640 return -EINVAL;
643 ret = mt9v111_select_address_space(dev, MT9V111_ADDRESSSPACE_SENSOR);
644 if (ret < 0)
645 return -11; /* -EAGAIN */
647 ret = sn9c20x_read_i2c_data(dev, 2, 0x20, buf);
648 if (ret < 0)
649 return ret;
651 if (dev->vsettings.hflip) {
652 buf[0] |= 0x80;
653 /* (MSB) set bit 15: read out from
654 * bottom to top (upside down) */
655 buf[1] |= 0x80;
656 /* (LSB) set bit 7: readout starting 1 row later */
657 } else {
658 buf[0] &= 0x7f; /* (MSB) unset bit 15: normal readout */
659 buf[1] &= 0x7f; /* (LSB) unset bit 7: normal readout */
661 if (dev->vsettings.vflip) {
662 buf[0] |= 0x40;
663 /* (MSB) set bit 14: read out from right to left (mirrored) */
664 buf[1] |= 0x20;
665 /* (LSB) set bit 5: readout starting 1 column later */
666 } else {
667 buf[0] &= 0xbf; /* (MSB) unset bit 14: normal readout */
668 buf[1] &= 0xdf; /* (LSB) unset bit 5: normal readout */
671 ret = sn9c20x_write_i2c_data(dev, 2, 0x20, buf);
672 return ret;
675 int mt9v111_set_autoexposure(struct usb_sn9c20x *dev)
677 __u16 buf[1];
678 int ret = 0;
680 /* Switch to IFP-register address space: */
681 ret = mt9v111_select_address_space(dev, MT9V111_ADDRESSSPACE_IFP);
682 if (ret < 0)
683 return -11; /* -EAGAIN */
684 /* Read current value of IFP-register 0x06: */
685 ret = sn9c20x_read_i2c_data16(dev, 1, MT9V111_IFPREG_OPMODECTL, buf);
686 if (ret < 0) {
687 UDIA_ERROR("Error: setting of auto exposure failed: "
688 "error while reading from IFP-register 0x06\n");
689 return ret;
692 /* Set new value for register 0x06: */
694 if (dev->vsettings.auto_exposure) {
695 buf[0] |= MT9V111_IFP_OPMODE_AUTOEXPOSURE;
696 } else {
697 buf[0] &= ~MT9V111_IFP_OPMODE_AUTOEXPOSURE;
700 /* Write new value to IFP-register 0x06: */
701 ret = sn9c20x_write_i2c_data16(dev, 1, MT9V111_IFPREG_OPMODECTL, buf);
702 if (ret < 0) {
703 UDIA_ERROR("Error: setting of auto exposure failed: "
704 "error while writing to IFP-register 0x06\n");
705 return ret;
707 return 0;
710 int mt9v111_set_autowhitebalance(struct usb_sn9c20x *dev)
712 __u16 buf[1];
713 int ret = 0;
715 /* Switch to IFP-register address space: */
716 ret = mt9v111_select_address_space(dev, MT9V111_ADDRESSSPACE_IFP);
717 if (ret < 0)
718 return -11; /* -EAGAIN */
719 /* Read current value of IFP-register 0x06: */
720 ret = sn9c20x_read_i2c_data16(dev, 1,
721 MT9V111_IFPREG_OPMODECTL, buf);
722 if (ret < 0) {
723 UDIA_ERROR("Error: setting of auto whitebalance failed: "
724 "error while reading from IFP-register 0x06\n");
725 return ret;
727 /* Set new value for register 0x06: */
728 if (dev->vsettings.auto_whitebalance == 1) {
729 /* Enable automatic exposure: */
730 buf[0] |= MT9V111_IFP_OPMODE_AUTOWHITEBALANCE;
731 } else if (dev->vsettings.auto_whitebalance == 0) {
732 /* Disable automatic exposure: */
733 buf[0] &= ~MT9V111_IFP_OPMODE_AUTOWHITEBALANCE;
734 } else
735 return -EINVAL;
736 /* Write new value to IFP-register 0x06:*/
737 ret = sn9c20x_write_i2c_data16(dev, 1,
738 MT9V111_IFPREG_OPMODECTL, buf);
739 if (ret < 0) {
740 UDIA_ERROR("Error: setting of auto whitebalance failed: "
741 "error while writing to IFP-register 0x06\n");
742 return ret;
744 return 0;
747 int mt9v112_set_hvflip(struct usb_sn9c20x *dev)
749 int ret;
750 __u16 buf;
752 /* Select address-space: sensor */
753 buf = 0x00;
754 sn9c20x_write_i2c_data16(dev, 1, 0xf0, &buf);
756 ret = sn9c20x_read_i2c_data16(dev, 1, 0x20, &buf);
757 if (ret < 0)
758 return ret;
760 if (dev->vsettings.hflip)
761 buf |= 0x0002;
762 else
763 buf &= ~0x0002;
765 if (dev->vsettings.vflip)
766 buf |= 0x0001;
767 else
768 buf &= ~0x0001;
770 ret = sn9c20x_write_i2c_data16(dev, 1, 0x20, &buf);
772 return ret;