Rework sensor detection.
[microdia.git] / micron.c
blobc90278f90754ec60b1a744c5a72084d09ad0dc29
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 mt9v111_init[] = {
33 {0x01, 0x0004}, /* select sensor address space */
34 {0x0d, 0x0001}, /* Resets chip */
35 {0x0d, 0x0000},
36 {0x01, 0x0001}, /* select IFP address space */
37 {0x02, 0x0016}, /* ??? */
38 /* 0x03: Color Correction Register 3 */
39 /* 0x04: Color Correction Register 4 */
40 {0x03, 0x01e1}, /* ??? */
41 {0x04, 0x0281}, /* ??? */
42 /* 0x05: Aperture Correction (Sharpening) */
43 {0x05, 0x0004}, /* 100% sharpening,
44 no automatic sharpness reduction at low light: no sharpening */
45 /* 0x07: IFP Soft Reset */
46 /* 0x08: Output Format Control */
47 {0x07, 0x3002}, /* reset */
48 {0x21, 0x0000},
49 {0x25, 0x4024},
50 {0x26, 0xff03},
51 {0x27, 0xff10},
52 {0x2b, 0x7828},
53 {0x2c, 0xb43c},
54 {0x2d, 0xf0a0},
55 {0x2e, 0x0c64},
56 {0x2f, 0x0064},
57 {0x67, 0x4010},
58 {0x06, 0x301c}, /* stop AWB at the current values,
59 no auto exposure */
60 {0x08, 0x0480}, /* bypass entire image processing,
61 raw 8+2 Bayer data output directly */
62 {0x01, 0x0004}, /* select sensor address space */
63 {0x02, 0x0016}, /* start with column 22 */
64 /* 0x03: Window Height */
65 /* 0x04: Window Width */
66 {0x03, 0x01e6}, /* 486 */
67 {0x04, 0x0286}, /* 646 */
68 /* 0x05: Horizontal Blanking */
69 /* 0x06: Vertical Blanking */
70 {0x05, 0x0004}, /* 4 columns (pixel clocks) */
71 {0x06, 0x0000}, /* 0 rows */
72 /* 0x07: Output Control */
73 /* 0x08: Row Start */
74 {0x07, 0x3002}, /* normal operation + chip enable*/
75 {0x08, 0x0008}, /* row 8 */
76 /* 0x0c: Shutter Delay */
77 /* 0x0d: Reset (Soft) */
78 {0x0c, 0x0000}, /* 0 master clocks */
79 {0x0d, 0x0000}, /* return to normal operation */
80 {0x0e, 0x0000},
81 {0x0f, 0x0000},
82 {0x10, 0x0000},
83 {0x11, 0x0000},
84 /* 0x12: 2X Zoom Col Start
85 => 0x1e bit 0 must be set to activate zoom */
86 /* 0x13: 2X Zoom Row Start
87 => 0x1e bit 0 must be set to activate zoom */
88 {0x12, 0x00b0}, /* column 176 */
89 {0x13, 0x007c}, /* row 124 */
90 {0x14, 0x0000},
91 {0x15, 0x0000},
92 {0x16, 0x0000},
93 {0x17, 0x0000},
94 {0x18, 0x0000},
95 {0x19, 0x0000},
96 {0x1a, 0x0000},
97 {0x1b, 0x0000},
98 {0x1c, 0x0000},
99 {0x1d, 0x0000},
100 {0x30, 0x0000},
101 {0x30, 0x0005},
102 {0x31, 0x0000},
103 /* 0x02: Column Start */
104 /* 0x03: Window Height */
105 {0x02, 0x0016}, /* coulmn 22 */
106 {0x03, 0x01e1}, /* 481 */
107 /* 0x04: Window Width */
108 /* 0x05: Horizontal Blanking */
109 {0x04, 0x0281}, /* 641 */
110 {0x05, 0x0004}, /* 4 columns (pixel clocks) */
111 /* 0x06: Vertical Blanking */
112 /* 0x07: Output Control */
113 {0x06, 0x0000}, /* 0 rows */
114 {0x07, 0x3002}, /* normal operation + chip enable */
115 /* 0x06: Vertical Blanking */
116 {0x06, 0x002d}, /* 45 rows */
117 /* 0x05: Horizontal Blanking */
118 {0x05, 0x0004}, /* 4 columns (pixel clocks) */
119 /* 0x09: Shutter Width */
120 {0x09, 0x0064}, /* integration of 100 rows */
121 /* 0x2b: Green 1 Gain */
122 /* 0x2c: Blue Gain */
123 {0x2b, 0x00a0}, /* 32*0.03125*2 = 2 */
124 {0x2c, 0x00a0}, /* 32*0.03125*2 = 2 */
125 /* 0x2d: Red Gain */
126 /* 0x2e: Green 2 Gain */
127 {0x2d, 0x00a0}, /* 32*0.03125*2 = 2 */
128 {0x2e, 0x00a0}, /* 32*0.03125*2 = 2 */
129 /* 0x02: Column Start */
130 /* 0x03: Window Hight */
131 {0x02, 0x0016}, /* coulmn 22 */
132 {0x03, 0x01e1}, /* 481 */
133 /* 0x04: Window Width */
134 /* 0x05: Horizontal Blanking */
135 {0x04, 0x0281}, /* 641 */
136 {0x05, 0x0004}, /* 4 columns (pixel clocks) */
137 /* 0x06: Vertical Blanking */
138 /* 0x07: Output Control */
139 {0x06, 0x002d}, /* 45 rows */
140 {0x07, 0x3002}, /* RESERVED options */
141 /* Writes to0x0e: UNDOCUMENTED */
142 {0x0e, 0x0008},
143 /* 0x06: Vertical Blanking */
144 {0x06, 0x002d}, /* 45 rows */
145 /* 0x05: Horizontal Blanking */
146 {0x05, 0x0004}, /* 4 columns (pixel clocks) */
147 {0xff, 0xffff},
150 struct sn9c20x_i2c_regs mt9v011_init[] = {
151 /* 0x07: Output Control */
152 {0x07, 0x0002}, /* chip enable, normal operation */
153 /* 0x0d: Soft Reset */
154 {0x0d, 0x0001}, /* reset */
155 /* 0x0d: Soft Reset */
156 {0x0d, 0x0000}, /* resume operation */
157 /* 0x01: Row start */
158 /* 0x02: Column Start */
159 {0x01, 0x0008}, /* start with row 8 */
160 {0x02, 0x0016}, /* start with column 22 */
161 /* 0x03: Window Height */
162 /* 0x04: Window Width */
163 {0x03, 0x01e1}, /* 481 */
164 {0x04, 0x0281}, /* 641 */
165 /* 0x05: Horizontal Blanking */
166 /* 0x06: Vertical Blanking */
167 {0x05, 0x0083}, /* 131 columns (pixel clocks) */
168 {0x06, 0x0006}, /* 6 rows */
169 /* 0x0d: Soft Reset */
170 {0x0d, 0x0002}, /* UNKNOWN */
171 /* 0x0a: Pixel Clock Speed */
172 /* 0x0b: Frame Restart */
173 {0x0a, 0x0000}, /* default */
174 {0x0b, 0x0000}, /* (has no effect/no restart) */
175 /* 0x0c: Shutter Delay */
176 /* 0x0d: Soft Reset */
177 {0x0c, 0x0000}, /* 0 master clocks */
178 {0x0d, 0x0000}, /* resume operation */
179 {0x0e, 0x0000},
180 {0x0f, 0x0000},
181 {0x10, 0x0000},
182 {0x11, 0x0000},
183 /* 0x12: 2X Zoom Column Start (from MT9V111 datasheet) */
184 /* 0x13: 2X Zoom Row Start (from MT9V111 datasheet) */
185 {0x12, 0x0000},
186 /* column 0 => bit0 of reg 0x1e must be set to activate zoom */
187 {0x13, 0x0000},
188 /* row 0 => bit0 of reg 0x1e must be set to activate zoom */
189 {0x14, 0x0000},
190 {0x15, 0x0000},
191 {0x16, 0x0000},
192 {0x17, 0x0000},
193 {0x18, 0x0000},
194 {0x19, 0x0000},
195 {0x1a, 0x0000},
196 {0x1b, 0x0000},
197 {0x1c, 0x0000},
198 {0x1d, 0x0000},
199 {0x32, 0x0000},
200 /* 0x20: Read Mode */
201 {0x20, 0x1101}, /* output all frames (including bad frames) */
202 {0x21, 0x0000},
203 {0x22, 0x0000},
204 {0x23, 0x0000},
205 {0x24, 0x0000},
206 {0x25, 0x0000},
207 {0x26, 0x0000},
208 {0x27, 0x0024},
209 {0x2f, 0xf7b0},
210 {0x30, 0x0005},
211 {0x31, 0x0000},
212 {0x32, 0x0000},
213 {0x33, 0x0000},
214 {0x34, 0x0100},
215 {0x3d, 0x068f},
216 {0x40, 0x01e0},
217 {0x41, 0x00d1},
218 {0x44, 0x0082},
219 {0x5a, 0x0000},
220 {0x5b, 0x0000},
221 {0x5c, 0x0000},
222 {0x5d, 0x0000},
223 {0x5e, 0x0000},
224 {0x5f, 0xa31d},
225 {0x62, 0x0611},
226 /* 0x0a: Pixel Clock Speed */
227 {0x0a, 0x0000}, /* default */
228 /* 0x06: Vertical Blanking */
229 {0x06, 0x0029}, /* 41 rows */
230 /* 0x05: Horizontal Blanking */
231 {0x05, 0x0009}, /* 9 columns (pixel clocks) */
232 /* 0x20: Read Mode */
233 {0x20, 0x1101}, /* output all frames (including bad ones) */
234 /* 0x20: Read Mode */
235 {0x20, 0x1101}, /* output all frames (including bad ones) */
236 /* 0x09: Shutter Width */
237 {0x09, 0x0064}, /* integration of 100 rows */
238 /* 0x07: Output Control */
239 {0x07, 0x0003},
240 /* dont update changes until bit0=0, chip enable, normal operation */
241 /* 0x2b: Green 1 Gain */
242 /* 0x2c: Blue Gain */
243 {0x2b, 0x0033}, /* 51*0.03125*1 = 1.59375 */
244 {0x2c, 0x00a0}, /* 32*0.03125*2 = 2 */
245 /* 0x2d: Red Gain */
246 /* 0x2e: Green 2 Gain */
247 {0x2d, 0x00a0}, /* 32*0.03125*2 = 2 */
248 {0x2e, 0x0033}, /* 51*0.03125*1 = 1.59375 */
249 /* 0x07: Output Control */
250 {0x07, 0x0002}, /* chip enable, normal operation */
251 /* 0x0a: Pixel Clock Speed */
252 {0x06, 0x0000}, /* default */
253 /* 0x06: Vertical Blanking */
254 {0x06, 0x0029}, /* 41 rows */
255 /* 0x05: Horizontal Blanking */
256 {0x05, 0x0009}, /* 9 columns (pixel clocks) */
257 {0xff, 0xffff},
260 struct sn9c20x_i2c_regs mt9m111_init[] = {
261 {0xf0, 0x0000},
262 /* Reset sensor */
263 {0x0d, 0x0008},
264 {0x0d, 0x0009},
265 {0x0d, 0x0008},
266 /* Select Page map 0x01
267 * This means all new writes now have the address prefix 0x1.
268 * Example: 0x3a becomes 0x13a. */
269 {0xf0, 0x0001},
270 /** Select output format:
271 * - output raw bayer (8+2 bit)
272 * FIXME: There are nearly all YUV and RGB variants possible.
273 * Maybe we should use them.
275 {0x3a, 0x7300},
276 /* measure atoexposure through a mix of both possible windows */
277 {0x06, 0x308c},
278 /* Switch back to Page map 0x00 */
279 {0xf0, 0x0000},
280 /* The following set the resoutiona and window size.
281 * It's a bit more than SXGA.
282 * VSTART */
283 {0x01, 0x000e},
284 /* HSTART */
285 {0x02, 0x0014},
286 /* VSIZE */
287 {0x03, 0x03c4},
288 /* HSIZE */
289 {0x04, 0x0514},
290 /* Blanking */
291 {0xc8, 0x0003},
292 {0x0a, 0x0001},
293 {0x06, 0x0029},
294 {0x05, 0x0072},
295 {0x20, 0x0000},
296 {0x20, 0x0000},
297 /* Shutter width */
298 {0x09, 0x0190},
299 /* Protect settings */
300 {0x0d, 0x8008},
301 /* Green 1 gain */
302 {0x2b, 0x0188},
303 /* Blue gain */
304 {0x2c, 0x0188},
305 /* Red gain */
306 {0x2d, 0x0188},
307 /* Green 2 gain */
308 {0x2e, 0x0188},
309 /* Blanking (again?) */
310 {0x0a, 0x0001},
311 {0x06, 0x0029},
312 {0x05, 0x0072},
313 {0xff, 0xffff},
316 struct sn9c20x_i2c_regs mt9m001_init[] = {
317 {0x07, 0x0000}, {0x07, 0x0002}, {0x0d, 0x0001}, {0x0d, 0x0000},
318 {0x01, 0x000e}, {0x02, 0x0014}, {0x03, 0x03c1}, {0x04, 0x0501},
319 {0x05, 0x0083}, {0x06, 0x0006}, {0x0d, 0x0002}, {0x09, 0x0000},
320 {0x0a, 0x0000}, {0x0b, 0x0000}, {0x0c, 0x0000}, {0x11, 0x0000},
321 {0x1e, 0x8000}, {0x20, 0x1105}, {0x2b, 0x0008}, {0x2c, 0x0010},
322 {0x2d, 0x0014}, {0x2e, 0x0008}, {0x5f, 0x8904}, {0x60, 0x0000},
323 {0x61, 0x0000}, {0x62, 0x0498}, {0x63, 0x0000}, {0x68, 0x0000},
324 {0x20, 0x111d}, {0x06, 0x00f2}, {0x05, 0x0013}, {0x20, 0x111d},
325 {0x20, 0x111d}, {0x07, 0x0003}, {0x2b, 0x0010}, {0x2c, 0x0010},
326 {0x2d, 0x0010}, {0x2e, 0x0010}, {0x07, 0x0002}, {0x07, 0x0003},
327 {0x2c, 0x001d}, {0x2d, 0x001d}, {0x07, 0x0002}, {0x06, 0x00f2},
328 {0x05, 0x0013}, {0x09, 0x0387}, {0x07, 0x0003}, {0x2b, 0x0028},
329 {0x2c, 0x003f}, {0x2d, 0x003f}, {0x2e, 0x0028}, {0x07, 0x0002},
330 {0x09, 0x04f1}, {0x07, 0x0003}, {0x2b, 0x0024}, {0x2c, 0x0039},
331 {0x2d, 0x0039}, {0x2e, 0x0024}, {0x07, 0x0002}, {0xff, 0xffff},
334 int mt9v111_select_address_space(struct usb_sn9c20x *dev, __u8 address_space)
336 __u8 buf[2];
337 int retI2C;
338 int k;
340 /* check if selection is valid: */
341 if ((address_space != MT9V111_ADDRESSSPACE_IFP) &&
342 (address_space != MT9V111_ADDRESSSPACE_SENSOR)) {
343 UDIA_WARNING("invalid register address space "
344 "selection for sensor MT9V111/MI0360SOC !\n");
345 return -1;
347 /* read address space slection register: */
348 k = 0;
349 retI2C = -1;
350 while ((k < 3) && (retI2C != 0)) {
351 retI2C = sn9c20x_read_i2c_data(dev, 2, 0x01, buf);
352 if (retI2C != 0 && k < 2)
353 udelay(1000);
354 k++;
356 if (retI2C != 0) {
357 UDIA_ERROR("MT9V111/MI0360SOC (I2C-slave 0x5c): "
358 "read of reg0x01 (address space selection) failed !\n");
359 return -1;
361 /* check current address space: */
362 if ((buf[0] != 0x00) || (buf[1] != address_space)) {
363 k = 0;
364 retI2C = -1;
365 while ((k < 3) && (retI2C != 0)) {
366 /* switch address space: */
367 buf[0] = 0x00; buf[1] = address_space;
368 retI2C = sn9c20x_write_i2c_data(dev, 2, 0x01, buf);
369 if (retI2C != 0 && k < 2)
370 udelay(1000);
371 k++;
373 if (retI2C != 0) {
374 if (address_space == MT9V111_ADDRESSSPACE_IFP)
375 UDIA_ERROR("MT9V111/MI0360SOC "
376 "(I2C-slave 0x5c): switch to IFP "
377 "address space failed !\n");
378 else
379 UDIA_ERROR("MT9V111/MI0360SOC "
380 "(I2C-slave 0x5c): switch to sensor "
381 "core address space failed !\n");
382 return -1;
385 return 0;
388 int mt9v011_probe(struct usb_sn9c20x *dev)
390 __u16 buf;
391 int ret = -EINVAL;
393 dev->camera.address = 0x5d;
394 ret = sn9c20x_read_i2c_data16(dev, 2, 0xff, &buf);
395 if ((ret == 0) && (buf == 0x8243))
396 ret = MT9V011_SENSOR;
398 return ret;
401 int mt9v111_probe(struct usb_sn9c20x *dev)
403 __u16 buf;
404 int ret = -EINVAL;
406 dev->camera.address = 0x5c;
407 /* Select address-space: sensor */
408 buf = 0x04;
409 ret = sn9c20x_write_i2c_data16(dev, 2, 0x01, &buf);
410 if (ret != 0)
411 return ret;
413 ret = sn9c20x_read_i2c_data16(dev, 2, 0xff, &buf);
414 if ((ret == 0) && (buf == 0x823a))
415 ret = MT9V111_SENSOR;
417 return ret;
420 int mt9v011_set_exposure(struct usb_sn9c20x *dev)
422 int ret = 0;
423 __u8 buf[2];
425 buf[0] = (dev->vsettings.exposure >> 4);
426 buf[1] = 0;
427 ret |= sn9c20x_write_i2c_data(dev, 2, 0x09, buf);
428 /* Maybe we have to disable AE/AWB/flicker avoidence (currently not
429 * used) for MT9V111 sensor, because IFP controls this register if
430 * one of them is enabled. */
431 return ret;
434 int mt9v111_set_exposure(struct usb_sn9c20x *dev)
436 int ret = 0;
437 __u8 buf[2];
440 ret = mt9v111_select_address_space(dev, MT9V111_ADDRESSSPACE_SENSOR);
442 if (ret < 0)
443 return -11; /* -EAGAIN */
445 buf[0] = (dev->vsettings.exposure >> 4);
446 buf[1] = 0;
447 ret |= sn9c20x_write_i2c_data(dev, 2, 0x09, buf);
448 /* Maybe we have to disable AE/AWB/flicker avoidence (currently not
449 * used) for MT9V111 sensor, because IFP controls this register if
450 * one of them is enabled. */
451 return ret;
454 int mt9v011_set_hvflip(struct usb_sn9c20x *dev)
456 int ret = 0;
457 __u8 buf[2];
459 if ((dev->vsettings.hflip > 1) || (dev->vsettings.hflip < 0))
460 return -EINVAL;
461 if ((dev->vsettings.vflip > 1) || (dev->vsettings.vflip < 0))
462 return -EINVAL;
464 ret = sn9c20x_read_i2c_data(dev, 2, 0x20, buf);
465 if (ret < 0)
466 return ret;
468 if (dev->vsettings.hflip) {
469 buf[0] |= 0x80;
470 /* (MSB) set bit 15: read out from
471 * bottom to top (upside down) */
472 buf[1] |= 0x80;
473 /* (LSB) set bit 7: readout starting 1 row later */
474 } else {
475 buf[0] &= 0x7f; /* (MSB) unset bit 15: normal readout */
476 buf[1] &= 0x7f; /* (LSB) unset bit 7: normal readout */
478 if (dev->vsettings.vflip) {
479 buf[0] |= 0x40;
480 /* (MSB) set bit 14: read out from right to left (mirrored) */
481 buf[1] |= 0x20;
482 /* (LSB) set bit 5: readout starting 1 column later */
483 } else {
484 buf[0] &= 0xbf; /* (MSB) unset bit 14: normal readout */
485 buf[1] &= 0xdf; /* (LSB) unset bit 5: normal readout */
488 ret = sn9c20x_write_i2c_data(dev, 2, 0x20, buf);
489 return ret;
492 int mt9v111_set_hvflip(struct usb_sn9c20x *dev)
494 int ret = 0;
495 __u8 buf[2];
497 if ((dev->vsettings.hflip > 1) || (dev->vsettings.hflip < 0))
498 return -EINVAL;
499 if ((dev->vsettings.vflip > 1) || (dev->vsettings.vflip < 0))
500 return -EINVAL;
503 ret = mt9v111_select_address_space(dev, MT9V111_ADDRESSSPACE_SENSOR);
504 if (ret < 0)
505 return -11; /* -EAGAIN */
507 ret = sn9c20x_read_i2c_data(dev, 2, 0x20, buf);
508 if (ret < 0)
509 return ret;
511 if (dev->vsettings.hflip) {
512 buf[0] |= 0x80;
513 /* (MSB) set bit 15: read out from
514 * bottom to top (upside down) */
515 buf[1] |= 0x80;
516 /* (LSB) set bit 7: readout starting 1 row later */
517 } else {
518 buf[0] &= 0x7f; /* (MSB) unset bit 15: normal readout */
519 buf[1] &= 0x7f; /* (LSB) unset bit 7: normal readout */
521 if (dev->vsettings.vflip) {
522 buf[0] |= 0x40;
523 /* (MSB) set bit 14: read out from right to left (mirrored) */
524 buf[1] |= 0x20;
525 /* (LSB) set bit 5: readout starting 1 column later */
526 } else {
527 buf[0] &= 0xbf; /* (MSB) unset bit 14: normal readout */
528 buf[1] &= 0xdf; /* (LSB) unset bit 5: normal readout */
531 ret = sn9c20x_write_i2c_data(dev, 2, 0x20, buf);
532 return ret;
535 int mt9v111_set_autoexposure(struct usb_sn9c20x *dev)
537 __u16 buf[1];
538 int ret = 0;
540 /* Switch to IFP-register address space: */
541 ret = mt9v111_select_address_space(dev, MT9V111_ADDRESSSPACE_IFP);
542 if (ret < 0)
543 return -11; /* -EAGAIN */
544 /* Read current value of IFP-register 0x06: */
545 ret = sn9c20x_read_i2c_data16(dev, 1, MT9V111_IFPREG_OPMODECTL, buf);
546 if (ret < 0) {
547 UDIA_ERROR("Error: setting of auto exposure failed: "
548 "error while reading from IFP-register 0x06\n");
549 return ret;
552 /* Set new value for register 0x06: */
553 switch (dev->vsettings.auto_exposure) {
554 case V4L2_EXPOSURE_AUTO:
555 buf[0] |= MT9V111_IFP_OPMODE_AUTOEXPOSURE;
556 break;
557 case V4L2_EXPOSURE_MANUAL:
558 buf[0] &= ~MT9V111_IFP_OPMODE_AUTOEXPOSURE;
559 break;
560 case V4L2_EXPOSURE_SHUTTER_PRIORITY:
561 buf[0] &= ~MT9V111_IFP_OPMODE_AUTOEXPOSURE;
562 break;
563 case V4L2_EXPOSURE_APERTURE_PRIORITY:
564 buf[0] |= MT9V111_IFP_OPMODE_AUTOEXPOSURE;
565 break;
566 default:
567 return -EINVAL;
569 /* Write new value to IFP-register 0x06: */
570 ret = sn9c20x_write_i2c_data16(dev, 1, MT9V111_IFPREG_OPMODECTL, buf);
571 if (ret < 0) {
572 UDIA_ERROR("Error: setting of auto exposure failed: "
573 "error while writing to IFP-register 0x06\n");
574 return ret;
576 return 0;
579 int mt9v111_set_autowhitebalance(struct usb_sn9c20x *dev)
581 __u16 buf[1];
582 int ret = 0;
584 /* Switch to IFP-register address space: */
585 ret = mt9v111_select_address_space(dev, MT9V111_ADDRESSSPACE_IFP);
586 if (ret < 0)
587 return -11; /* -EAGAIN */
588 /* Read current value of IFP-register 0x06: */
589 ret = sn9c20x_read_i2c_data16(dev, 1,
590 MT9V111_IFPREG_OPMODECTL, buf);
591 if (ret < 0) {
592 UDIA_ERROR("Error: setting of auto whitebalance failed: "
593 "error while reading from IFP-register 0x06\n");
594 return ret;
596 /* Set new value for register 0x06: */
597 if (dev->vsettings.auto_whitebalance == 1) {
598 /* Enable automatic exposure: */
599 buf[0] |= MT9V111_IFP_OPMODE_AUTOWHITEBALANCE;
600 } else if (dev->vsettings.auto_whitebalance == 0) {
601 /* Disable automatic exposure: */
602 buf[0] &= ~MT9V111_IFP_OPMODE_AUTOWHITEBALANCE;
603 } else
604 return -EINVAL;
605 /* Write new value to IFP-register 0x06:*/
606 ret = sn9c20x_write_i2c_data16(dev, 1,
607 MT9V111_IFPREG_OPMODECTL, buf);
608 if (ret < 0) {
609 UDIA_ERROR("Error: setting of auto whitebalance failed: "
610 "error while writing to IFP-register 0x06\n");
611 return ret;
613 return 0;