V4L/DVB (11466): gspca - m5602: Let all ctrls on all sensors be static
[linux-2.6-xlnx.git] / drivers / media / video / gspca / m5602 / m5602_ov9650.c
blob8d830afcedb3e83eb39384317515669d0698d90f
1 /*
2 * Driver for the ov9650 sensor
4 * Copyright (C) 2008 Erik Andrén
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>
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
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.
19 #include "m5602_ov9650.h"
21 static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
22 static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
23 static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
24 static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val);
25 static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
26 static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
27 static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
28 static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
29 static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
30 static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
31 static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
32 static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
33 static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
34 __s32 *val);
35 static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
36 __s32 val);
37 static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
38 static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
40 /* Vertically and horizontally flips the image if matched, needed for machines
41 where the sensor is mounted upside down */
42 static
43 const
44 struct dmi_system_id ov9650_flip_dmi_table[] = {
46 .ident = "ASUS A6VC",
47 .matches = {
48 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
49 DMI_MATCH(DMI_PRODUCT_NAME, "A6VC")
53 .ident = "ASUS A6VM",
54 .matches = {
55 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
56 DMI_MATCH(DMI_PRODUCT_NAME, "A6VM")
60 .ident = "ASUS A6JC",
61 .matches = {
62 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
63 DMI_MATCH(DMI_PRODUCT_NAME, "A6JC")
67 .ident = "ASUS A6Ja",
68 .matches = {
69 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
70 DMI_MATCH(DMI_PRODUCT_NAME, "A6J")
74 .ident = "ASUS A6Kt",
75 .matches = {
76 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
77 DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt")
81 .ident = "Alienware Aurora m9700",
82 .matches = {
83 DMI_MATCH(DMI_SYS_VENDOR, "alienware"),
84 DMI_MATCH(DMI_PRODUCT_NAME, "Aurora m9700")
90 const static struct ctrl ov9650_ctrls[] = {
91 #define EXPOSURE_IDX 0
94 .id = V4L2_CID_EXPOSURE,
95 .type = V4L2_CTRL_TYPE_INTEGER,
96 .name = "exposure",
97 .minimum = 0x00,
98 .maximum = 0x1ff,
99 .step = 0x4,
100 .default_value = EXPOSURE_DEFAULT,
101 .flags = V4L2_CTRL_FLAG_SLIDER
103 .set = ov9650_set_exposure,
104 .get = ov9650_get_exposure
106 #define GAIN_IDX 1
109 .id = V4L2_CID_GAIN,
110 .type = V4L2_CTRL_TYPE_INTEGER,
111 .name = "gain",
112 .minimum = 0x00,
113 .maximum = 0x3ff,
114 .step = 0x1,
115 .default_value = GAIN_DEFAULT,
116 .flags = V4L2_CTRL_FLAG_SLIDER
118 .set = ov9650_set_gain,
119 .get = ov9650_get_gain
121 #define RED_BALANCE_IDX 2
124 .type = V4L2_CTRL_TYPE_INTEGER,
125 .name = "red balance",
126 .minimum = 0x00,
127 .maximum = 0xff,
128 .step = 0x1,
129 .default_value = RED_GAIN_DEFAULT,
130 .flags = V4L2_CTRL_FLAG_SLIDER
132 .set = ov9650_set_red_balance,
133 .get = ov9650_get_red_balance
135 #define BLUE_BALANCE_IDX 3
138 .type = V4L2_CTRL_TYPE_INTEGER,
139 .name = "blue balance",
140 .minimum = 0x00,
141 .maximum = 0xff,
142 .step = 0x1,
143 .default_value = BLUE_GAIN_DEFAULT,
144 .flags = V4L2_CTRL_FLAG_SLIDER
146 .set = ov9650_set_blue_balance,
147 .get = ov9650_get_blue_balance
149 #define HFLIP_IDX 4
152 .id = V4L2_CID_HFLIP,
153 .type = V4L2_CTRL_TYPE_BOOLEAN,
154 .name = "horizontal flip",
155 .minimum = 0,
156 .maximum = 1,
157 .step = 1,
158 .default_value = 0
160 .set = ov9650_set_hflip,
161 .get = ov9650_get_hflip
163 #define VFLIP_IDX 5
166 .id = V4L2_CID_VFLIP,
167 .type = V4L2_CTRL_TYPE_BOOLEAN,
168 .name = "vertical flip",
169 .minimum = 0,
170 .maximum = 1,
171 .step = 1,
172 .default_value = 0
174 .set = ov9650_set_vflip,
175 .get = ov9650_get_vflip
177 #define AUTO_WHITE_BALANCE_IDX 6
180 .id = V4L2_CID_AUTO_WHITE_BALANCE,
181 .type = V4L2_CTRL_TYPE_BOOLEAN,
182 .name = "auto white balance",
183 .minimum = 0,
184 .maximum = 1,
185 .step = 1,
186 .default_value = 1
188 .set = ov9650_set_auto_white_balance,
189 .get = ov9650_get_auto_white_balance
191 #define AUTO_GAIN_CTRL_IDX 7
194 .id = V4L2_CID_AUTOGAIN,
195 .type = V4L2_CTRL_TYPE_BOOLEAN,
196 .name = "auto gain control",
197 .minimum = 0,
198 .maximum = 1,
199 .step = 1,
200 .default_value = 1
202 .set = ov9650_set_auto_gain,
203 .get = ov9650_get_auto_gain
207 static struct v4l2_pix_format ov9650_modes[] = {
209 176,
210 144,
211 V4L2_PIX_FMT_SBGGR8,
212 V4L2_FIELD_NONE,
213 .sizeimage =
214 176 * 144,
215 .bytesperline = 176,
216 .colorspace = V4L2_COLORSPACE_SRGB,
217 .priv = 9
218 }, {
219 320,
220 240,
221 V4L2_PIX_FMT_SBGGR8,
222 V4L2_FIELD_NONE,
223 .sizeimage =
224 320 * 240,
225 .bytesperline = 320,
226 .colorspace = V4L2_COLORSPACE_SRGB,
227 .priv = 8
228 }, {
229 352,
230 288,
231 V4L2_PIX_FMT_SBGGR8,
232 V4L2_FIELD_NONE,
233 .sizeimage =
234 352 * 288,
235 .bytesperline = 352,
236 .colorspace = V4L2_COLORSPACE_SRGB,
237 .priv = 9
238 }, {
239 640,
240 480,
241 V4L2_PIX_FMT_SBGGR8,
242 V4L2_FIELD_NONE,
243 .sizeimage =
244 640 * 480,
245 .bytesperline = 640,
246 .colorspace = V4L2_COLORSPACE_SRGB,
247 .priv = 9
251 static void ov9650_dump_registers(struct sd *sd);
253 int ov9650_probe(struct sd *sd)
255 int err = 0;
256 u8 prod_id = 0, ver_id = 0, i;
257 s32 *sensor_settings;
259 if (force_sensor) {
260 if (force_sensor == OV9650_SENSOR) {
261 info("Forcing an %s sensor", ov9650.name);
262 goto sensor_found;
264 /* If we want to force another sensor,
265 don't try to probe this one */
266 return -ENODEV;
269 info("Probing for an ov9650 sensor");
271 /* Run the pre-init before probing the sensor */
272 for (i = 0; i < ARRAY_SIZE(preinit_ov9650) && !err; i++) {
273 u8 data = preinit_ov9650[i][2];
274 if (preinit_ov9650[i][0] == SENSOR)
275 err = m5602_write_sensor(sd,
276 preinit_ov9650[i][1], &data, 1);
277 else
278 err = m5602_write_bridge(sd,
279 preinit_ov9650[i][1], data);
282 if (err < 0)
283 return err;
285 if (m5602_read_sensor(sd, OV9650_PID, &prod_id, 1))
286 return -ENODEV;
288 if (m5602_read_sensor(sd, OV9650_VER, &ver_id, 1))
289 return -ENODEV;
291 if ((prod_id == 0x96) && (ver_id == 0x52)) {
292 info("Detected an ov9650 sensor");
293 goto sensor_found;
295 return -ENODEV;
297 sensor_found:
298 sensor_settings = kmalloc(
299 ARRAY_SIZE(ov9650_ctrls) * sizeof(s32), GFP_KERNEL);
300 if (!sensor_settings)
301 return -ENOMEM;
303 sd->gspca_dev.cam.cam_mode = ov9650_modes;
304 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov9650_modes);
305 sd->desc->ctrls = ov9650_ctrls;
306 sd->desc->nctrls = ARRAY_SIZE(ov9650_ctrls);
308 for (i = 0; i < ARRAY_SIZE(ov9650_ctrls); i++)
309 sensor_settings[i] = ov9650_ctrls[i].qctrl.default_value;
310 sd->sensor_priv = sensor_settings;
311 return 0;
314 int ov9650_init(struct sd *sd)
316 int i, err = 0;
317 u8 data;
318 s32 *sensor_settings = sd->sensor_priv;
320 if (dump_sensor)
321 ov9650_dump_registers(sd);
323 for (i = 0; i < ARRAY_SIZE(init_ov9650) && !err; i++) {
324 data = init_ov9650[i][2];
325 if (init_ov9650[i][0] == SENSOR)
326 err = m5602_write_sensor(sd, init_ov9650[i][1],
327 &data, 1);
328 else
329 err = m5602_write_bridge(sd, init_ov9650[i][1], data);
332 err = ov9650_set_exposure(&sd->gspca_dev,
333 sensor_settings[EXPOSURE_IDX]);
334 if (err < 0)
335 return err;
337 err = ov9650_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
338 if (err < 0)
339 return err;
341 err = ov9650_set_red_balance(&sd->gspca_dev,
342 sensor_settings[RED_BALANCE_IDX]);
343 if (err < 0)
344 return err;
346 err = ov9650_set_blue_balance(&sd->gspca_dev,
347 sensor_settings[BLUE_BALANCE_IDX]);
348 if (err < 0)
349 return err;
351 err = ov9650_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
352 if (err < 0)
353 return err;
355 err = ov9650_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
356 if (err < 0)
357 return err;
359 err = ov9650_set_auto_white_balance(&sd->gspca_dev,
360 sensor_settings[AUTO_WHITE_BALANCE_IDX]);
361 if (err < 0)
362 return err;
364 err = ov9650_set_auto_gain(&sd->gspca_dev,
365 sensor_settings[AUTO_GAIN_CTRL_IDX]);
366 return err;
369 int ov9650_start(struct sd *sd)
371 u8 data;
372 int i, err = 0;
373 struct cam *cam = &sd->gspca_dev.cam;
374 s32 *sensor_settings = sd->sensor_priv;
376 int width = cam->cam_mode[sd->gspca_dev.curr_mode].width;
377 int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
378 int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
379 int hor_offs = OV9650_LEFT_OFFSET;
381 if ((!dmi_check_system(ov9650_flip_dmi_table) &&
382 sensor_settings[VFLIP_IDX]) ||
383 (dmi_check_system(ov9650_flip_dmi_table) &&
384 !sensor_settings[VFLIP_IDX]))
385 ver_offs--;
387 if (width <= 320)
388 hor_offs /= 2;
390 /* Synthesize the vsync/hsync setup */
391 for (i = 0; i < ARRAY_SIZE(res_init_ov9650) && !err; i++) {
392 if (res_init_ov9650[i][0] == BRIDGE)
393 err = m5602_write_bridge(sd, res_init_ov9650[i][1],
394 res_init_ov9650[i][2]);
395 else if (res_init_ov9650[i][0] == SENSOR) {
396 u8 data = res_init_ov9650[i][2];
397 err = m5602_write_sensor(sd,
398 res_init_ov9650[i][1], &data, 1);
401 if (err < 0)
402 return err;
404 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA,
405 ((ver_offs >> 8) & 0xff));
406 if (err < 0)
407 return err;
409 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (ver_offs & 0xff));
410 if (err < 0)
411 return err;
413 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
414 if (err < 0)
415 return err;
417 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff);
418 if (err < 0)
419 return err;
421 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff));
422 if (err < 0)
423 return err;
425 for (i = 0; i < 2 && !err; i++)
426 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
427 if (err < 0)
428 return err;
430 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
431 (hor_offs >> 8) & 0xff);
432 if (err < 0)
433 return err;
435 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, hor_offs & 0xff);
436 if (err < 0)
437 return err;
439 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
440 ((width + hor_offs) >> 8) & 0xff);
441 if (err < 0)
442 return err;
444 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
445 ((width + hor_offs) & 0xff));
446 if (err < 0)
447 return err;
449 switch (width) {
450 case 640:
451 PDEBUG(D_V4L2, "Configuring camera for VGA mode");
453 data = OV9650_VGA_SELECT | OV9650_RGB_SELECT |
454 OV9650_RAW_RGB_SELECT;
455 err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
456 break;
458 case 352:
459 PDEBUG(D_V4L2, "Configuring camera for CIF mode");
461 data = OV9650_CIF_SELECT | OV9650_RGB_SELECT |
462 OV9650_RAW_RGB_SELECT;
463 err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
464 break;
466 case 320:
467 PDEBUG(D_V4L2, "Configuring camera for QVGA mode");
469 data = OV9650_QVGA_SELECT | OV9650_RGB_SELECT |
470 OV9650_RAW_RGB_SELECT;
471 err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
472 break;
474 case 176:
475 PDEBUG(D_V4L2, "Configuring camera for QCIF mode");
477 data = OV9650_QCIF_SELECT | OV9650_RGB_SELECT |
478 OV9650_RAW_RGB_SELECT;
479 err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
480 break;
482 return err;
485 int ov9650_stop(struct sd *sd)
487 u8 data = OV9650_SOFT_SLEEP | OV9650_OUTPUT_DRIVE_2X;
488 return m5602_write_sensor(sd, OV9650_COM2, &data, 1);
491 void ov9650_disconnect(struct sd *sd)
493 ov9650_stop(sd);
495 sd->sensor = NULL;
496 kfree(sd->sensor_priv);
499 static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
501 struct sd *sd = (struct sd *) gspca_dev;
502 s32 *sensor_settings = sd->sensor_priv;
504 *val = sensor_settings[EXPOSURE_IDX];
505 PDEBUG(D_V4L2, "Read exposure %d", *val);
506 return 0;
509 static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
511 struct sd *sd = (struct sd *) gspca_dev;
512 s32 *sensor_settings = sd->sensor_priv;
513 u8 i2c_data;
514 int err;
516 PDEBUG(D_V4L2, "Set exposure to %d", val);
518 sensor_settings[EXPOSURE_IDX] = val;
519 /* The 6 MSBs */
520 i2c_data = (val >> 10) & 0x3f;
521 err = m5602_write_sensor(sd, OV9650_AECHM,
522 &i2c_data, 1);
523 if (err < 0)
524 return err;
526 /* The 8 middle bits */
527 i2c_data = (val >> 2) & 0xff;
528 err = m5602_write_sensor(sd, OV9650_AECH,
529 &i2c_data, 1);
530 if (err < 0)
531 return err;
533 /* The 2 LSBs */
534 i2c_data = val & 0x03;
535 err = m5602_write_sensor(sd, OV9650_COM1, &i2c_data, 1);
536 return err;
539 static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
541 struct sd *sd = (struct sd *) gspca_dev;
542 s32 *sensor_settings = sd->sensor_priv;
544 *val = sensor_settings[GAIN_IDX];
545 PDEBUG(D_V4L2, "Read gain %d", *val);
546 return 0;
549 static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
551 int err;
552 u8 i2c_data;
553 struct sd *sd = (struct sd *) gspca_dev;
554 s32 *sensor_settings = sd->sensor_priv;
556 PDEBUG(D_V4L2, "Setting gain to %d", val);
558 sensor_settings[GAIN_IDX] = val;
560 /* The 2 MSB */
561 /* Read the OV9650_VREF register first to avoid
562 corrupting the VREF high and low bits */
563 err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
564 if (err < 0)
565 return err;
567 /* Mask away all uninteresting bits */
568 i2c_data = ((val & 0x0300) >> 2) |
569 (i2c_data & 0x3F);
570 err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
571 if (err < 0)
572 return err;
574 /* The 8 LSBs */
575 i2c_data = val & 0xff;
576 err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1);
577 return err;
580 static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
582 struct sd *sd = (struct sd *) gspca_dev;
583 s32 *sensor_settings = sd->sensor_priv;
585 *val = sensor_settings[RED_BALANCE_IDX];
586 PDEBUG(D_V4L2, "Read red gain %d", *val);
587 return 0;
590 static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
592 int err;
593 u8 i2c_data;
594 struct sd *sd = (struct sd *) gspca_dev;
595 s32 *sensor_settings = sd->sensor_priv;
597 PDEBUG(D_V4L2, "Set red gain to %d", val);
599 sensor_settings[RED_BALANCE_IDX] = val;
601 i2c_data = val & 0xff;
602 err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1);
603 return err;
606 static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
608 struct sd *sd = (struct sd *) gspca_dev;
609 s32 *sensor_settings = sd->sensor_priv;
611 *val = sensor_settings[BLUE_BALANCE_IDX];
612 PDEBUG(D_V4L2, "Read blue gain %d", *val);
614 return 0;
617 static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
619 int err;
620 u8 i2c_data;
621 struct sd *sd = (struct sd *) gspca_dev;
622 s32 *sensor_settings = sd->sensor_priv;
624 PDEBUG(D_V4L2, "Set blue gain to %d", val);
626 sensor_settings[BLUE_BALANCE_IDX] = val;
628 i2c_data = val & 0xff;
629 err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1);
630 return err;
633 static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
635 struct sd *sd = (struct sd *) gspca_dev;
636 s32 *sensor_settings = sd->sensor_priv;
638 *val = sensor_settings[HFLIP_IDX];
639 PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
640 return 0;
643 static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
645 int err;
646 u8 i2c_data;
647 struct sd *sd = (struct sd *) gspca_dev;
648 s32 *sensor_settings = sd->sensor_priv;
650 PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
652 sensor_settings[HFLIP_IDX] = val;
654 if (!dmi_check_system(ov9650_flip_dmi_table))
655 i2c_data = ((val & 0x01) << 5) |
656 (sensor_settings[VFLIP_IDX] << 4);
657 else
658 i2c_data = ((val & 0x01) << 5) |
659 (!sensor_settings[VFLIP_IDX] << 4);
661 err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
663 return err;
666 static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
668 struct sd *sd = (struct sd *) gspca_dev;
669 s32 *sensor_settings = sd->sensor_priv;
671 *val = sensor_settings[VFLIP_IDX];
672 PDEBUG(D_V4L2, "Read vertical flip %d", *val);
674 return 0;
677 static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
679 int err;
680 u8 i2c_data;
681 struct sd *sd = (struct sd *) gspca_dev;
682 s32 *sensor_settings = sd->sensor_priv;
684 PDEBUG(D_V4L2, "Set vertical flip to %d", val);
685 sensor_settings[VFLIP_IDX] = val;
687 if (dmi_check_system(ov9650_flip_dmi_table))
688 val = !val;
690 i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5);
691 err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
692 if (err < 0)
693 return err;
695 /* When vflip is toggled we need to readjust the bridge hsync/vsync */
696 if (gspca_dev->streaming)
697 err = ov9650_start(sd);
699 return err;
702 static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
703 __s32 *val)
705 struct sd *sd = (struct sd *) gspca_dev;
706 s32 *sensor_settings = sd->sensor_priv;
708 *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
709 return 0;
712 static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
713 __s32 val)
715 int err;
716 u8 i2c_data;
717 struct sd *sd = (struct sd *) gspca_dev;
718 s32 *sensor_settings = sd->sensor_priv;
720 PDEBUG(D_V4L2, "Set auto white balance to %d", val);
722 sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
723 err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
724 if (err < 0)
725 return err;
727 i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1));
728 err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
730 return err;
733 static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
735 struct sd *sd = (struct sd *) gspca_dev;
736 s32 *sensor_settings = sd->sensor_priv;
738 *val = sensor_settings[AUTO_GAIN_CTRL_IDX];
739 PDEBUG(D_V4L2, "Read auto gain control %d", *val);
740 return 0;
743 static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
745 int err;
746 u8 i2c_data;
747 struct sd *sd = (struct sd *) gspca_dev;
748 s32 *sensor_settings = sd->sensor_priv;
750 PDEBUG(D_V4L2, "Set auto gain control to %d", val);
752 sensor_settings[AUTO_GAIN_CTRL_IDX] = val;
753 err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
754 if (err < 0)
755 return err;
757 i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2));
758 err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
760 return err;
763 static void ov9650_dump_registers(struct sd *sd)
765 int address;
766 info("Dumping the ov9650 register state");
767 for (address = 0; address < 0xa9; address++) {
768 u8 value;
769 m5602_read_sensor(sd, address, &value, 1);
770 info("register 0x%x contains 0x%x",
771 address, value);
774 info("ov9650 register state dump complete");
776 info("Probing for which registers that are read/write");
777 for (address = 0; address < 0xff; address++) {
778 u8 old_value, ctrl_value;
779 u8 test_value[2] = {0xff, 0xff};
781 m5602_read_sensor(sd, address, &old_value, 1);
782 m5602_write_sensor(sd, address, test_value, 1);
783 m5602_read_sensor(sd, address, &ctrl_value, 1);
785 if (ctrl_value == test_value[0])
786 info("register 0x%x is writeable", address);
787 else
788 info("register 0x%x is read only", address);
790 /* Restore original value */
791 m5602_write_sensor(sd, address, &old_value, 1);