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 EA |
141 | } |
142 | ||
e07b14e8 | 143 | return err; |
c109f816 EA |
144 | } |
145 | ||
146 | int ov9650_power_down(struct sd *sd) | |
147 | { | |
e07b14e8 EA |
148 | int i, err = 0; |
149 | for (i = 0; i < ARRAY_SIZE(power_down_ov9650) && !err; i++) { | |
c109f816 EA |
150 | u8 data = power_down_ov9650[i][2]; |
151 | if (power_down_ov9650[i][0] == SENSOR) | |
6dc4cff0 | 152 | err = m5602_write_sensor(sd, |
c109f816 EA |
153 | power_down_ov9650[i][1], &data, 1); |
154 | else | |
082ec3b8 EA |
155 | err = m5602_write_bridge(sd, power_down_ov9650[i][1], |
156 | data); | |
c109f816 EA |
157 | } |
158 | ||
e07b14e8 | 159 | return err; |
c109f816 EA |
160 | } |
161 | ||
162 | int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) | |
163 | { | |
164 | struct sd *sd = (struct sd *) gspca_dev; | |
165 | u8 i2c_data; | |
166 | int err; | |
167 | ||
905aabaf | 168 | err = m5602_read_sensor(sd, OV9650_COM1, &i2c_data, 1); |
c109f816 EA |
169 | if (err < 0) |
170 | goto out; | |
171 | *val = i2c_data & 0x03; | |
172 | ||
905aabaf | 173 | err = m5602_read_sensor(sd, OV9650_AECH, &i2c_data, 1); |
c109f816 EA |
174 | if (err < 0) |
175 | goto out; | |
176 | *val |= (i2c_data << 2); | |
177 | ||
905aabaf | 178 | err = m5602_read_sensor(sd, OV9650_AECHM, &i2c_data, 1); |
c109f816 EA |
179 | if (err < 0) |
180 | goto out; | |
181 | *val |= (i2c_data & 0x3f) << 10; | |
182 | ||
17ea88ae | 183 | PDEBUG(D_V4L2, "Read exposure %d", *val); |
c109f816 | 184 | out: |
e07b14e8 | 185 | return err; |
c109f816 EA |
186 | } |
187 | ||
188 | int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val) | |
189 | { | |
190 | struct sd *sd = (struct sd *) gspca_dev; | |
191 | u8 i2c_data; | |
192 | int err; | |
193 | ||
17ea88ae | 194 | PDEBUG(D_V4L2, "Set exposure to %d", |
c109f816 EA |
195 | val & 0xffff); |
196 | ||
197 | /* The 6 MSBs */ | |
198 | i2c_data = (val >> 10) & 0x3f; | |
6dc4cff0 | 199 | err = m5602_write_sensor(sd, OV9650_AECHM, |
c109f816 EA |
200 | &i2c_data, 1); |
201 | if (err < 0) | |
202 | goto out; | |
203 | ||
204 | /* The 8 middle bits */ | |
205 | i2c_data = (val >> 2) & 0xff; | |
6dc4cff0 | 206 | err = m5602_write_sensor(sd, OV9650_AECH, |
c109f816 EA |
207 | &i2c_data, 1); |
208 | if (err < 0) | |
209 | goto out; | |
210 | ||
211 | /* The 2 LSBs */ | |
212 | i2c_data = val & 0x03; | |
6dc4cff0 | 213 | err = m5602_write_sensor(sd, OV9650_COM1, &i2c_data, 1); |
c109f816 EA |
214 | |
215 | out: | |
e07b14e8 | 216 | return err; |
c109f816 EA |
217 | } |
218 | ||
219 | int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val) | |
220 | { | |
221 | int err; | |
222 | u8 i2c_data; | |
223 | struct sd *sd = (struct sd *) gspca_dev; | |
224 | ||
905aabaf | 225 | m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1); |
c109f816 EA |
226 | *val = (i2c_data & 0x03) << 8; |
227 | ||
905aabaf | 228 | err = m5602_read_sensor(sd, OV9650_GAIN, &i2c_data, 1); |
c109f816 | 229 | *val |= i2c_data; |
17ea88ae | 230 | PDEBUG(D_V4L2, "Read gain %d", *val); |
e07b14e8 | 231 | return err; |
c109f816 EA |
232 | } |
233 | ||
234 | int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val) | |
235 | { | |
236 | int err; | |
237 | u8 i2c_data; | |
238 | struct sd *sd = (struct sd *) gspca_dev; | |
239 | ||
240 | /* The 2 MSB */ | |
241 | /* Read the OV9650_VREF register first to avoid | |
242 | corrupting the VREF high and low bits */ | |
905aabaf | 243 | m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1); |
c109f816 EA |
244 | /* Mask away all uninteresting bits */ |
245 | i2c_data = ((val & 0x0300) >> 2) | | |
246 | (i2c_data & 0x3F); | |
6dc4cff0 | 247 | err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1); |
c109f816 EA |
248 | |
249 | /* The 8 LSBs */ | |
250 | i2c_data = val & 0xff; | |
6dc4cff0 | 251 | err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1); |
e07b14e8 | 252 | return err; |
c109f816 EA |
253 | } |
254 | ||
255 | int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) | |
256 | { | |
257 | int err; | |
258 | u8 i2c_data; | |
259 | struct sd *sd = (struct sd *) gspca_dev; | |
260 | ||
905aabaf | 261 | err = m5602_read_sensor(sd, OV9650_RED, &i2c_data, 1); |
c109f816 EA |
262 | *val = i2c_data; |
263 | ||
17ea88ae | 264 | PDEBUG(D_V4L2, "Read red gain %d", *val); |
c109f816 | 265 | |
e07b14e8 | 266 | return err; |
c109f816 EA |
267 | } |
268 | ||
269 | int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) | |
270 | { | |
271 | int err; | |
272 | u8 i2c_data; | |
273 | struct sd *sd = (struct sd *) gspca_dev; | |
274 | ||
17ea88ae | 275 | PDEBUG(D_V4L2, "Set red gain to %d", |
c109f816 EA |
276 | val & 0xff); |
277 | ||
278 | i2c_data = val & 0xff; | |
6dc4cff0 | 279 | err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1); |
c109f816 | 280 | |
e07b14e8 | 281 | return err; |
c109f816 EA |
282 | } |
283 | ||
284 | int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) | |
285 | { | |
286 | int err; | |
287 | u8 i2c_data; | |
288 | struct sd *sd = (struct sd *) gspca_dev; | |
289 | ||
905aabaf | 290 | err = m5602_read_sensor(sd, OV9650_BLUE, &i2c_data, 1); |
c109f816 EA |
291 | *val = i2c_data; |
292 | ||
17ea88ae | 293 | PDEBUG(D_V4L2, "Read blue gain %d", *val); |
c109f816 | 294 | |
e07b14e8 | 295 | return err; |
c109f816 EA |
296 | } |
297 | ||
298 | int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) | |
299 | { | |
300 | int err; | |
301 | u8 i2c_data; | |
302 | struct sd *sd = (struct sd *) gspca_dev; | |
303 | ||
17ea88ae | 304 | PDEBUG(D_V4L2, "Set blue gain to %d", |
c109f816 EA |
305 | val & 0xff); |
306 | ||
307 | i2c_data = val & 0xff; | |
6dc4cff0 | 308 | err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1); |
c109f816 | 309 | |
e07b14e8 | 310 | return err; |
c109f816 EA |
311 | } |
312 | ||
313 | int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) | |
314 | { | |
315 | int err; | |
316 | u8 i2c_data; | |
317 | struct sd *sd = (struct sd *) gspca_dev; | |
318 | ||
905aabaf | 319 | err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1); |
c109f816 EA |
320 | if (dmi_check_system(ov9650_flip_dmi_table)) |
321 | *val = ((i2c_data & OV9650_HFLIP) >> 5) ? 0 : 1; | |
322 | else | |
323 | *val = (i2c_data & OV9650_HFLIP) >> 5; | |
17ea88ae | 324 | PDEBUG(D_V4L2, "Read horizontal flip %d", *val); |
c109f816 | 325 | |
e07b14e8 | 326 | return err; |
c109f816 EA |
327 | } |
328 | ||
329 | int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val) | |
330 | { | |
331 | int err; | |
332 | u8 i2c_data; | |
333 | struct sd *sd = (struct sd *) gspca_dev; | |
334 | ||
17ea88ae | 335 | PDEBUG(D_V4L2, "Set horizontal flip to %d", val); |
905aabaf | 336 | err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1); |
c109f816 EA |
337 | if (err < 0) |
338 | goto out; | |
339 | ||
340 | if (dmi_check_system(ov9650_flip_dmi_table)) | |
341 | i2c_data = ((i2c_data & 0xdf) | | |
e07b14e8 | 342 | (((val ? 0 : 1) & 0x01) << 5)); |
c109f816 EA |
343 | else |
344 | i2c_data = ((i2c_data & 0xdf) | | |
e07b14e8 | 345 | ((val & 0x01) << 5)); |
c109f816 | 346 | |
6dc4cff0 | 347 | err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1); |
c109f816 | 348 | out: |
e07b14e8 | 349 | return err; |
c109f816 EA |
350 | } |
351 | ||
352 | int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) | |
353 | { | |
354 | int err; | |
355 | u8 i2c_data; | |
356 | struct sd *sd = (struct sd *) gspca_dev; | |
357 | ||
905aabaf | 358 | err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1); |
c109f816 EA |
359 | if (dmi_check_system(ov9650_flip_dmi_table)) |
360 | *val = ((i2c_data & 0x10) >> 4) ? 0 : 1; | |
361 | else | |
362 | *val = (i2c_data & 0x10) >> 4; | |
17ea88ae | 363 | PDEBUG(D_V4L2, "Read vertical flip %d", *val); |
c109f816 | 364 | |
e07b14e8 | 365 | return err; |
c109f816 EA |
366 | } |
367 | ||
368 | int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val) | |
369 | { | |
370 | int err; | |
371 | u8 i2c_data; | |
372 | struct sd *sd = (struct sd *) gspca_dev; | |
373 | ||
17ea88ae | 374 | PDEBUG(D_V4L2, "Set vertical flip to %d", val); |
905aabaf | 375 | err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1); |
c109f816 EA |
376 | if (err < 0) |
377 | goto out; | |
378 | ||
379 | if (dmi_check_system(ov9650_flip_dmi_table)) | |
380 | i2c_data = ((i2c_data & 0xef) | | |
381 | (((val ? 0 : 1) & 0x01) << 4)); | |
382 | else | |
383 | i2c_data = ((i2c_data & 0xef) | | |
384 | ((val & 0x01) << 4)); | |
385 | ||
6dc4cff0 | 386 | err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1); |
c109f816 | 387 | out: |
e07b14e8 | 388 | return err; |
c109f816 EA |
389 | } |
390 | ||
391 | int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) | |
392 | { | |
393 | int err; | |
394 | u8 i2c_data; | |
395 | struct sd *sd = (struct sd *) gspca_dev; | |
396 | ||
905aabaf | 397 | err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1); |
c109f816 EA |
398 | if (err < 0) |
399 | goto out; | |
400 | *val = (i2c_data & 0x03) << 8; | |
401 | ||
905aabaf | 402 | err = m5602_read_sensor(sd, OV9650_GAIN, &i2c_data, 1); |
c109f816 | 403 | *val |= i2c_data; |
17ea88ae | 404 | PDEBUG(D_V4L2, "Read gain %d", *val); |
c109f816 | 405 | out: |
e07b14e8 | 406 | return err; |
c109f816 EA |
407 | } |
408 | ||
409 | int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val) | |
410 | { | |
411 | int err; | |
412 | u8 i2c_data; | |
413 | struct sd *sd = (struct sd *) gspca_dev; | |
414 | ||
17ea88ae | 415 | PDEBUG(D_V4L2, "Set gain to %d", val & 0x3ff); |
c109f816 EA |
416 | |
417 | /* Read the OV9650_VREF register first to avoid | |
418 | corrupting the VREF high and low bits */ | |
905aabaf | 419 | err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1); |
c109f816 EA |
420 | if (err < 0) |
421 | goto out; | |
422 | ||
423 | /* Mask away all uninteresting bits */ | |
424 | i2c_data = ((val & 0x0300) >> 2) | (i2c_data & 0x3F); | |
6dc4cff0 | 425 | err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1); |
c109f816 EA |
426 | if (err < 0) |
427 | goto out; | |
428 | ||
429 | /* The 8 LSBs */ | |
430 | i2c_data = val & 0xff; | |
6dc4cff0 | 431 | err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1); |
c109f816 EA |
432 | |
433 | out: | |
e07b14e8 | 434 | return err; |
c109f816 EA |
435 | } |
436 | ||
437 | int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val) | |
438 | { | |
439 | int err; | |
440 | u8 i2c_data; | |
441 | struct sd *sd = (struct sd *) gspca_dev; | |
442 | ||
905aabaf | 443 | err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); |
c109f816 | 444 | *val = (i2c_data & OV9650_AWB_EN) >> 1; |
17ea88ae | 445 | PDEBUG(D_V4L2, "Read auto white balance %d", *val); |
c109f816 | 446 | |
e07b14e8 | 447 | return err; |
c109f816 EA |
448 | } |
449 | ||
450 | int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val) | |
451 | { | |
452 | int err; | |
453 | u8 i2c_data; | |
454 | struct sd *sd = (struct sd *) gspca_dev; | |
455 | ||
17ea88ae | 456 | PDEBUG(D_V4L2, "Set auto white balance to %d", val); |
905aabaf | 457 | err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); |
c109f816 EA |
458 | if (err < 0) |
459 | goto out; | |
460 | ||
461 | i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1)); | |
6dc4cff0 | 462 | err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1); |
c109f816 | 463 | out: |
e07b14e8 | 464 | return err; |
c109f816 EA |
465 | } |
466 | ||
467 | int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val) | |
468 | { | |
469 | int err; | |
470 | u8 i2c_data; | |
471 | struct sd *sd = (struct sd *) gspca_dev; | |
472 | ||
905aabaf | 473 | err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); |
c109f816 | 474 | *val = (i2c_data & OV9650_AGC_EN) >> 2; |
17ea88ae | 475 | PDEBUG(D_V4L2, "Read auto gain control %d", *val); |
c109f816 | 476 | |
e07b14e8 | 477 | return err; |
c109f816 EA |
478 | } |
479 | ||
480 | int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) | |
481 | { | |
482 | int err; | |
483 | u8 i2c_data; | |
484 | struct sd *sd = (struct sd *) gspca_dev; | |
485 | ||
17ea88ae | 486 | PDEBUG(D_V4L2, "Set auto gain control to %d", val); |
905aabaf | 487 | err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); |
c109f816 EA |
488 | if (err < 0) |
489 | goto out; | |
490 | ||
491 | i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2)); | |
6dc4cff0 | 492 | err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1); |
c109f816 | 493 | out: |
e07b14e8 | 494 | return err; |
c109f816 EA |
495 | } |
496 | ||
658efb63 | 497 | static void ov9650_dump_registers(struct sd *sd) |
c109f816 EA |
498 | { |
499 | int address; | |
500 | info("Dumping the ov9650 register state"); | |
501 | for (address = 0; address < 0xa9; address++) { | |
502 | u8 value; | |
905aabaf | 503 | m5602_read_sensor(sd, address, &value, 1); |
c109f816 EA |
504 | info("register 0x%x contains 0x%x", |
505 | address, value); | |
506 | } | |
507 | ||
508 | info("ov9650 register state dump complete"); | |
509 | ||
510 | info("Probing for which registers that are read/write"); | |
511 | for (address = 0; address < 0xff; address++) { | |
512 | u8 old_value, ctrl_value; | |
513 | u8 test_value[2] = {0xff, 0xff}; | |
514 | ||
905aabaf | 515 | m5602_read_sensor(sd, address, &old_value, 1); |
6dc4cff0 | 516 | m5602_write_sensor(sd, address, test_value, 1); |
905aabaf | 517 | m5602_read_sensor(sd, address, &ctrl_value, 1); |
c109f816 EA |
518 | |
519 | if (ctrl_value == test_value[0]) | |
520 | info("register 0x%x is writeable", address); | |
521 | else | |
522 | info("register 0x%x is read only", address); | |
523 | ||
524 | /* Restore original value */ | |
6dc4cff0 | 525 | m5602_write_sensor(sd, address, &old_value, 1); |
c109f816 EA |
526 | } |
527 | } |