Commit | Line | Data |
---|---|---|
c109f816 EA |
1 | /* |
2 | * Driver for the ov9650 sensor | |
3 | * | |
0c505e68 | 4 | * Copyright (C) 2008 Erik Andrén |
c109f816 EA |
5 | * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. |
6 | * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br> | |
7 | * | |
8 | * Portions of code to USB interface and ALi driver software, | |
9 | * Copyright (c) 2006 Willem Duinker | |
10 | * v4l2 interface modeled after the V4L2 driver | |
11 | * for SN9C10x PC Camera Controllers | |
12 | * | |
13 | * This program is free software; you can redistribute it and/or | |
14 | * modify it under the terms of the GNU General Public License as | |
15 | * published by the Free Software Foundation, version 2. | |
16 | * | |
17 | */ | |
18 | ||
19 | #include "m5602_ov9650.h" | |
20 | ||
30881ab7 EA |
21 | /* Vertically and horizontally flips the image if matched, needed for machines |
22 | where the sensor is mounted upside down */ | |
23 | static | |
24 | const | |
25 | struct dmi_system_id ov9650_flip_dmi_table[] = { | |
26 | { | |
27 | .ident = "ASUS A6VC", | |
28 | .matches = { | |
29 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), | |
30 | DMI_MATCH(DMI_PRODUCT_NAME, "A6VC") | |
31 | } | |
32 | }, | |
33 | { | |
34 | .ident = "ASUS A6VM", | |
35 | .matches = { | |
36 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), | |
37 | DMI_MATCH(DMI_PRODUCT_NAME, "A6VM") | |
38 | } | |
39 | }, | |
40 | { | |
41 | .ident = "ASUS A6JC", | |
42 | .matches = { | |
43 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), | |
44 | DMI_MATCH(DMI_PRODUCT_NAME, "A6JC") | |
45 | } | |
46 | }, | |
3efb6bda EA |
47 | { |
48 | .ident = "ASUS A6Ja", | |
49 | .matches = { | |
50 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), | |
51 | DMI_MATCH(DMI_PRODUCT_NAME, "A6J") | |
52 | } | |
53 | }, | |
30881ab7 EA |
54 | { |
55 | .ident = "ASUS A6Kt", | |
56 | .matches = { | |
57 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), | |
58 | DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt") | |
59 | } | |
60 | }, | |
7e08e66a EA |
61 | { |
62 | .ident = "Alienware Aurora m9700", | |
63 | .matches = { | |
64 | DMI_MATCH(DMI_SYS_VENDOR, "alienware"), | |
65 | DMI_MATCH(DMI_PRODUCT_NAME, "Aurora m9700") | |
66 | } | |
67 | }, | |
30881ab7 EA |
68 | { } |
69 | }; | |
70 | ||
658efb63 EA |
71 | static void ov9650_dump_registers(struct sd *sd); |
72 | ||
c109f816 EA |
73 | int ov9650_probe(struct sd *sd) |
74 | { | |
75 | u8 prod_id = 0, ver_id = 0, i; | |
76 | ||
77 | if (force_sensor) { | |
78 | if (force_sensor == OV9650_SENSOR) { | |
79 | info("Forcing an %s sensor", ov9650.name); | |
80 | goto sensor_found; | |
81 | } | |
82 | /* If we want to force another sensor, | |
83 | don't try to probe this one */ | |
84 | return -ENODEV; | |
85 | } | |
86 | ||
87 | info("Probing for an ov9650 sensor"); | |
88 | ||
89 | /* Run the pre-init to actually probe the unit */ | |
90 | for (i = 0; i < ARRAY_SIZE(preinit_ov9650); i++) { | |
91 | u8 data = preinit_ov9650[i][2]; | |
92 | if (preinit_ov9650[i][0] == SENSOR) | |
6dc4cff0 | 93 | m5602_write_sensor(sd, |
c109f816 EA |
94 | preinit_ov9650[i][1], &data, 1); |
95 | else | |
96 | m5602_write_bridge(sd, preinit_ov9650[i][1], data); | |
97 | } | |
98 | ||
905aabaf | 99 | if (m5602_read_sensor(sd, OV9650_PID, &prod_id, 1)) |
c109f816 EA |
100 | return -ENODEV; |
101 | ||
905aabaf | 102 | if (m5602_read_sensor(sd, OV9650_VER, &ver_id, 1)) |
c109f816 EA |
103 | return -ENODEV; |
104 | ||
105 | if ((prod_id == 0x96) && (ver_id == 0x52)) { | |
106 | info("Detected an ov9650 sensor"); | |
107 | goto sensor_found; | |
108 | } | |
109 | ||
110 | return -ENODEV; | |
111 | ||
112 | sensor_found: | |
113 | sd->gspca_dev.cam.cam_mode = ov9650.modes; | |
114 | sd->gspca_dev.cam.nmodes = ov9650.nmodes; | |
d2d7e9ae EA |
115 | sd->desc->ctrls = ov9650.ctrls; |
116 | sd->desc->nctrls = ov9650.nctrls; | |
c109f816 EA |
117 | return 0; |
118 | } | |
119 | ||
120 | int ov9650_init(struct sd *sd) | |
121 | { | |
122 | int i, err = 0; | |
123 | u8 data; | |
124 | ||
125 | if (dump_sensor) | |
126 | ov9650_dump_registers(sd); | |
127 | ||
128 | for (i = 0; i < ARRAY_SIZE(init_ov9650) && !err; i++) { | |
129 | data = init_ov9650[i][2]; | |
130 | if (init_ov9650[i][0] == SENSOR) | |
6dc4cff0 | 131 | err = m5602_write_sensor(sd, init_ov9650[i][1], |
c109f816 EA |
132 | &data, 1); |
133 | else | |
134 | err = m5602_write_bridge(sd, init_ov9650[i][1], data); | |
135 | } | |
136 | ||
e07b14e8 | 137 | if (dmi_check_system(ov9650_flip_dmi_table) && !err) { |
c109f816 EA |
138 | info("vflip quirk active"); |
139 | data = 0x30; | |
6dc4cff0 | 140 | err = m5602_write_sensor(sd, OV9650_MVFP, &data, 1); |
c109f816 | 141 | } |
e07b14e8 | 142 | return err; |
c109f816 EA |
143 | } |
144 | ||
082aa893 EA |
145 | int ov9650_start(struct sd *sd) |
146 | { | |
147 | int i, err = 0; | |
148 | struct cam *cam = &sd->gspca_dev.cam; | |
149 | ||
27b1e4ca EA |
150 | for (i = 0; i < ARRAY_SIZE(res_init_ov9650) && !err; i++) { |
151 | u8 data = res_init_ov9650[i][1]; | |
152 | err = m5602_write_bridge(sd, res_init_ov9650[i][0], data); | |
153 | } | |
154 | if (err < 0) | |
155 | return err; | |
156 | ||
082aa893 EA |
157 | switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) |
158 | { | |
082aa893 EA |
159 | case 640: |
160 | PDEBUG(D_V4L2, "Configuring camera for VGA mode"); | |
161 | ||
162 | for (i = 0; i < ARRAY_SIZE(VGA_ov9650) && !err; i++) { | |
163 | u8 data = VGA_ov9650[i][2]; | |
164 | if (VGA_ov9650[i][0] == SENSOR) | |
165 | err = m5602_write_sensor(sd, | |
166 | VGA_ov9650[i][1], &data, 1); | |
167 | else | |
168 | err = m5602_write_bridge(sd, VGA_ov9650[i][1], data); | |
169 | } | |
170 | break; | |
3b2f3327 | 171 | |
03f46de9 EA |
172 | case 352: |
173 | PDEBUG(D_V4L2, "Configuring camera for CIF mode"); | |
174 | ||
175 | for (i = 0; i < ARRAY_SIZE(CIF_ov9650) && !err; i++) { | |
176 | u8 data = CIF_ov9650[i][2]; | |
177 | if (CIF_ov9650[i][0] == SENSOR) | |
178 | err = m5602_write_sensor(sd, | |
179 | CIF_ov9650[i][1], &data, 1); | |
180 | else | |
181 | err = m5602_write_bridge(sd, CIF_ov9650[i][1], data); | |
182 | } | |
183 | break; | |
184 | ||
3b2f3327 EA |
185 | case 320: |
186 | PDEBUG(D_V4L2, "Configuring camera for QVGA mode"); | |
187 | ||
188 | for (i = 0; i < ARRAY_SIZE(QVGA_ov9650) && !err; i++) { | |
189 | u8 data = QVGA_ov9650[i][2]; | |
190 | if (QVGA_ov9650[i][0] == SENSOR) | |
191 | err = m5602_write_sensor(sd, | |
192 | QVGA_ov9650[i][1], &data, 1); | |
193 | else | |
194 | err = m5602_write_bridge(sd, QVGA_ov9650[i][1], data); | |
195 | } | |
196 | break; | |
082aa893 EA |
197 | } |
198 | return err; | |
199 | } | |
200 | ||
c109f816 EA |
201 | int ov9650_power_down(struct sd *sd) |
202 | { | |
e07b14e8 EA |
203 | int i, err = 0; |
204 | for (i = 0; i < ARRAY_SIZE(power_down_ov9650) && !err; i++) { | |
c109f816 EA |
205 | u8 data = power_down_ov9650[i][2]; |
206 | if (power_down_ov9650[i][0] == SENSOR) | |
6dc4cff0 | 207 | err = m5602_write_sensor(sd, |
c109f816 EA |
208 | power_down_ov9650[i][1], &data, 1); |
209 | else | |
082ec3b8 EA |
210 | err = m5602_write_bridge(sd, power_down_ov9650[i][1], |
211 | data); | |
c109f816 EA |
212 | } |
213 | ||
e07b14e8 | 214 | return err; |
c109f816 EA |
215 | } |
216 | ||
217 | int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) | |
218 | { | |
219 | struct sd *sd = (struct sd *) gspca_dev; | |
220 | u8 i2c_data; | |
221 | int err; | |
222 | ||
905aabaf | 223 | err = m5602_read_sensor(sd, OV9650_COM1, &i2c_data, 1); |
c109f816 | 224 | if (err < 0) |
051781b3 | 225 | return err; |
c109f816 EA |
226 | *val = i2c_data & 0x03; |
227 | ||
905aabaf | 228 | err = m5602_read_sensor(sd, OV9650_AECH, &i2c_data, 1); |
c109f816 | 229 | if (err < 0) |
051781b3 | 230 | return err; |
c109f816 EA |
231 | *val |= (i2c_data << 2); |
232 | ||
905aabaf | 233 | err = m5602_read_sensor(sd, OV9650_AECHM, &i2c_data, 1); |
c109f816 | 234 | if (err < 0) |
051781b3 | 235 | return err; |
c109f816 EA |
236 | *val |= (i2c_data & 0x3f) << 10; |
237 | ||
17ea88ae | 238 | PDEBUG(D_V4L2, "Read exposure %d", *val); |
051781b3 | 239 | |
e07b14e8 | 240 | return err; |
c109f816 EA |
241 | } |
242 | ||
243 | int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val) | |
244 | { | |
245 | struct sd *sd = (struct sd *) gspca_dev; | |
246 | u8 i2c_data; | |
247 | int err; | |
248 | ||
17ea88ae | 249 | PDEBUG(D_V4L2, "Set exposure to %d", |
c109f816 EA |
250 | val & 0xffff); |
251 | ||
252 | /* The 6 MSBs */ | |
253 | i2c_data = (val >> 10) & 0x3f; | |
6dc4cff0 | 254 | err = m5602_write_sensor(sd, OV9650_AECHM, |
c109f816 EA |
255 | &i2c_data, 1); |
256 | if (err < 0) | |
051781b3 | 257 | return err; |
c109f816 EA |
258 | |
259 | /* The 8 middle bits */ | |
260 | i2c_data = (val >> 2) & 0xff; | |
6dc4cff0 | 261 | err = m5602_write_sensor(sd, OV9650_AECH, |
c109f816 EA |
262 | &i2c_data, 1); |
263 | if (err < 0) | |
051781b3 | 264 | return err; |
c109f816 EA |
265 | |
266 | /* The 2 LSBs */ | |
267 | i2c_data = val & 0x03; | |
6dc4cff0 | 268 | err = m5602_write_sensor(sd, OV9650_COM1, &i2c_data, 1); |
c109f816 | 269 | |
e07b14e8 | 270 | return err; |
c109f816 EA |
271 | } |
272 | ||
273 | int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val) | |
274 | { | |
275 | int err; | |
276 | u8 i2c_data; | |
277 | struct sd *sd = (struct sd *) gspca_dev; | |
278 | ||
905aabaf | 279 | m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1); |
c109f816 EA |
280 | *val = (i2c_data & 0x03) << 8; |
281 | ||
905aabaf | 282 | err = m5602_read_sensor(sd, OV9650_GAIN, &i2c_data, 1); |
c109f816 | 283 | *val |= i2c_data; |
17ea88ae | 284 | PDEBUG(D_V4L2, "Read gain %d", *val); |
e07b14e8 | 285 | return err; |
c109f816 EA |
286 | } |
287 | ||
288 | int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val) | |
289 | { | |
290 | int err; | |
291 | u8 i2c_data; | |
292 | struct sd *sd = (struct sd *) gspca_dev; | |
293 | ||
294 | /* The 2 MSB */ | |
295 | /* Read the OV9650_VREF register first to avoid | |
296 | corrupting the VREF high and low bits */ | |
905aabaf | 297 | m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1); |
c109f816 EA |
298 | /* Mask away all uninteresting bits */ |
299 | i2c_data = ((val & 0x0300) >> 2) | | |
300 | (i2c_data & 0x3F); | |
6dc4cff0 | 301 | err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1); |
c109f816 EA |
302 | |
303 | /* The 8 LSBs */ | |
304 | i2c_data = val & 0xff; | |
6dc4cff0 | 305 | err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1); |
e07b14e8 | 306 | return err; |
c109f816 EA |
307 | } |
308 | ||
309 | int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) | |
310 | { | |
311 | int err; | |
312 | u8 i2c_data; | |
313 | struct sd *sd = (struct sd *) gspca_dev; | |
314 | ||
905aabaf | 315 | err = m5602_read_sensor(sd, OV9650_RED, &i2c_data, 1); |
c109f816 EA |
316 | *val = i2c_data; |
317 | ||
17ea88ae | 318 | PDEBUG(D_V4L2, "Read red gain %d", *val); |
c109f816 | 319 | |
e07b14e8 | 320 | return err; |
c109f816 EA |
321 | } |
322 | ||
323 | int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) | |
324 | { | |
325 | int err; | |
326 | u8 i2c_data; | |
327 | struct sd *sd = (struct sd *) gspca_dev; | |
328 | ||
17ea88ae | 329 | PDEBUG(D_V4L2, "Set red gain to %d", |
c109f816 EA |
330 | val & 0xff); |
331 | ||
332 | i2c_data = val & 0xff; | |
6dc4cff0 | 333 | err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1); |
c109f816 | 334 | |
e07b14e8 | 335 | return err; |
c109f816 EA |
336 | } |
337 | ||
338 | int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) | |
339 | { | |
340 | int err; | |
341 | u8 i2c_data; | |
342 | struct sd *sd = (struct sd *) gspca_dev; | |
343 | ||
905aabaf | 344 | err = m5602_read_sensor(sd, OV9650_BLUE, &i2c_data, 1); |
c109f816 EA |
345 | *val = i2c_data; |
346 | ||
17ea88ae | 347 | PDEBUG(D_V4L2, "Read blue gain %d", *val); |
c109f816 | 348 | |
e07b14e8 | 349 | return err; |
c109f816 EA |
350 | } |
351 | ||
352 | int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) | |
353 | { | |
354 | int err; | |
355 | u8 i2c_data; | |
356 | struct sd *sd = (struct sd *) gspca_dev; | |
357 | ||
17ea88ae | 358 | PDEBUG(D_V4L2, "Set blue gain to %d", |
c109f816 EA |
359 | val & 0xff); |
360 | ||
361 | i2c_data = val & 0xff; | |
6dc4cff0 | 362 | err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1); |
c109f816 | 363 | |
e07b14e8 | 364 | return err; |
c109f816 EA |
365 | } |
366 | ||
367 | int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) | |
368 | { | |
369 | int err; | |
370 | u8 i2c_data; | |
371 | struct sd *sd = (struct sd *) gspca_dev; | |
372 | ||
905aabaf | 373 | err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1); |
c109f816 EA |
374 | if (dmi_check_system(ov9650_flip_dmi_table)) |
375 | *val = ((i2c_data & OV9650_HFLIP) >> 5) ? 0 : 1; | |
376 | else | |
377 | *val = (i2c_data & OV9650_HFLIP) >> 5; | |
17ea88ae | 378 | PDEBUG(D_V4L2, "Read horizontal flip %d", *val); |
c109f816 | 379 | |
e07b14e8 | 380 | return err; |
c109f816 EA |
381 | } |
382 | ||
383 | int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val) | |
384 | { | |
385 | int err; | |
386 | u8 i2c_data; | |
387 | struct sd *sd = (struct sd *) gspca_dev; | |
388 | ||
17ea88ae | 389 | PDEBUG(D_V4L2, "Set horizontal flip to %d", val); |
905aabaf | 390 | err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1); |
c109f816 | 391 | if (err < 0) |
051781b3 | 392 | return err; |
c109f816 EA |
393 | |
394 | if (dmi_check_system(ov9650_flip_dmi_table)) | |
395 | i2c_data = ((i2c_data & 0xdf) | | |
e07b14e8 | 396 | (((val ? 0 : 1) & 0x01) << 5)); |
c109f816 EA |
397 | else |
398 | i2c_data = ((i2c_data & 0xdf) | | |
e07b14e8 | 399 | ((val & 0x01) << 5)); |
c109f816 | 400 | |
6dc4cff0 | 401 | err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1); |
051781b3 | 402 | |
e07b14e8 | 403 | return err; |
c109f816 EA |
404 | } |
405 | ||
406 | int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) | |
407 | { | |
408 | int err; | |
409 | u8 i2c_data; | |
410 | struct sd *sd = (struct sd *) gspca_dev; | |
411 | ||
905aabaf | 412 | err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1); |
c109f816 EA |
413 | if (dmi_check_system(ov9650_flip_dmi_table)) |
414 | *val = ((i2c_data & 0x10) >> 4) ? 0 : 1; | |
415 | else | |
416 | *val = (i2c_data & 0x10) >> 4; | |
17ea88ae | 417 | PDEBUG(D_V4L2, "Read vertical flip %d", *val); |
c109f816 | 418 | |
e07b14e8 | 419 | return err; |
c109f816 EA |
420 | } |
421 | ||
422 | int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val) | |
423 | { | |
424 | int err; | |
425 | u8 i2c_data; | |
426 | struct sd *sd = (struct sd *) gspca_dev; | |
427 | ||
17ea88ae | 428 | PDEBUG(D_V4L2, "Set vertical flip to %d", val); |
905aabaf | 429 | err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1); |
c109f816 | 430 | if (err < 0) |
051781b3 | 431 | return err; |
c109f816 EA |
432 | |
433 | if (dmi_check_system(ov9650_flip_dmi_table)) | |
434 | i2c_data = ((i2c_data & 0xef) | | |
435 | (((val ? 0 : 1) & 0x01) << 4)); | |
436 | else | |
437 | i2c_data = ((i2c_data & 0xef) | | |
438 | ((val & 0x01) << 4)); | |
439 | ||
6dc4cff0 | 440 | err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1); |
051781b3 | 441 | |
e07b14e8 | 442 | return err; |
c109f816 EA |
443 | } |
444 | ||
445 | int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) | |
446 | { | |
447 | int err; | |
448 | u8 i2c_data; | |
449 | struct sd *sd = (struct sd *) gspca_dev; | |
450 | ||
905aabaf | 451 | err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1); |
c109f816 | 452 | if (err < 0) |
051781b3 | 453 | return err; |
c109f816 EA |
454 | *val = (i2c_data & 0x03) << 8; |
455 | ||
905aabaf | 456 | err = m5602_read_sensor(sd, OV9650_GAIN, &i2c_data, 1); |
c109f816 | 457 | *val |= i2c_data; |
17ea88ae | 458 | PDEBUG(D_V4L2, "Read gain %d", *val); |
051781b3 | 459 | |
e07b14e8 | 460 | return err; |
c109f816 EA |
461 | } |
462 | ||
463 | int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val) | |
464 | { | |
465 | int err; | |
466 | u8 i2c_data; | |
467 | struct sd *sd = (struct sd *) gspca_dev; | |
468 | ||
17ea88ae | 469 | PDEBUG(D_V4L2, "Set gain to %d", val & 0x3ff); |
c109f816 EA |
470 | |
471 | /* Read the OV9650_VREF register first to avoid | |
472 | corrupting the VREF high and low bits */ | |
905aabaf | 473 | err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1); |
c109f816 | 474 | if (err < 0) |
051781b3 | 475 | return err; |
c109f816 EA |
476 | |
477 | /* Mask away all uninteresting bits */ | |
478 | i2c_data = ((val & 0x0300) >> 2) | (i2c_data & 0x3F); | |
6dc4cff0 | 479 | err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1); |
c109f816 | 480 | if (err < 0) |
051781b3 | 481 | return err; |
c109f816 EA |
482 | |
483 | /* The 8 LSBs */ | |
484 | i2c_data = val & 0xff; | |
6dc4cff0 | 485 | err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1); |
c109f816 | 486 | |
e07b14e8 | 487 | return err; |
c109f816 EA |
488 | } |
489 | ||
490 | int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val) | |
491 | { | |
492 | int err; | |
493 | u8 i2c_data; | |
494 | struct sd *sd = (struct sd *) gspca_dev; | |
495 | ||
905aabaf | 496 | err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); |
c109f816 | 497 | *val = (i2c_data & OV9650_AWB_EN) >> 1; |
17ea88ae | 498 | PDEBUG(D_V4L2, "Read auto white balance %d", *val); |
c109f816 | 499 | |
e07b14e8 | 500 | return err; |
c109f816 EA |
501 | } |
502 | ||
503 | int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val) | |
504 | { | |
505 | int err; | |
506 | u8 i2c_data; | |
507 | struct sd *sd = (struct sd *) gspca_dev; | |
508 | ||
17ea88ae | 509 | PDEBUG(D_V4L2, "Set auto white balance to %d", val); |
905aabaf | 510 | err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); |
c109f816 | 511 | if (err < 0) |
051781b3 | 512 | return err; |
c109f816 EA |
513 | |
514 | i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1)); | |
6dc4cff0 | 515 | err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1); |
051781b3 | 516 | |
e07b14e8 | 517 | return err; |
c109f816 EA |
518 | } |
519 | ||
520 | int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val) | |
521 | { | |
522 | int err; | |
523 | u8 i2c_data; | |
524 | struct sd *sd = (struct sd *) gspca_dev; | |
525 | ||
905aabaf | 526 | err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); |
c109f816 | 527 | *val = (i2c_data & OV9650_AGC_EN) >> 2; |
17ea88ae | 528 | PDEBUG(D_V4L2, "Read auto gain control %d", *val); |
c109f816 | 529 | |
e07b14e8 | 530 | return err; |
c109f816 EA |
531 | } |
532 | ||
533 | int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) | |
534 | { | |
535 | int err; | |
536 | u8 i2c_data; | |
537 | struct sd *sd = (struct sd *) gspca_dev; | |
538 | ||
17ea88ae | 539 | PDEBUG(D_V4L2, "Set auto gain control to %d", val); |
905aabaf | 540 | err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); |
c109f816 | 541 | if (err < 0) |
051781b3 | 542 | return err; |
c109f816 EA |
543 | |
544 | i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2)); | |
6dc4cff0 | 545 | err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1); |
051781b3 | 546 | |
e07b14e8 | 547 | return err; |
c109f816 EA |
548 | } |
549 | ||
658efb63 | 550 | static void ov9650_dump_registers(struct sd *sd) |
c109f816 EA |
551 | { |
552 | int address; | |
553 | info("Dumping the ov9650 register state"); | |
554 | for (address = 0; address < 0xa9; address++) { | |
555 | u8 value; | |
905aabaf | 556 | m5602_read_sensor(sd, address, &value, 1); |
c109f816 EA |
557 | info("register 0x%x contains 0x%x", |
558 | address, value); | |
559 | } | |
560 | ||
561 | info("ov9650 register state dump complete"); | |
562 | ||
563 | info("Probing for which registers that are read/write"); | |
564 | for (address = 0; address < 0xff; address++) { | |
565 | u8 old_value, ctrl_value; | |
566 | u8 test_value[2] = {0xff, 0xff}; | |
567 | ||
905aabaf | 568 | m5602_read_sensor(sd, address, &old_value, 1); |
6dc4cff0 | 569 | m5602_write_sensor(sd, address, test_value, 1); |
905aabaf | 570 | m5602_read_sensor(sd, address, &ctrl_value, 1); |
c109f816 EA |
571 | |
572 | if (ctrl_value == test_value[0]) | |
573 | info("register 0x%x is writeable", address); | |
574 | else | |
575 | info("register 0x%x is read only", address); | |
576 | ||
577 | /* Restore original value */ | |
6dc4cff0 | 578 | m5602_write_sensor(sd, address, &old_value, 1); |
c109f816 EA |
579 | } |
580 | } |