blob: d8f776684b62f42842cf3385b121364ae5bd27c4 [file] [log] [blame]
Erik Andrenc109f812008-10-01 04:51:53 -03001/*
2 * Driver for the ov9650 sensor
3 *
Erik Andren0c505e682008-10-16 16:43:16 -03004 * Copyright (C) 2008 Erik Andrén
Erik Andrenc109f812008-10-01 04:51:53 -03005 * 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
Erik Andr?ncf811d52009-04-03 02:49:10 -030021static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
22static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
23static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
24static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val);
25static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
26static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
27static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
28static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
29static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
30static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
31static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
32static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
33static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
34 __s32 *val);
35static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
36 __s32 val);
37static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
38static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
Erik Andr?n9ae16572009-01-13 03:57:57 -030039static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val);
40static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val);
Erik Andr?ncf811d52009-04-03 02:49:10 -030041
Erik Andrén30881ab2008-11-18 14:36:53 -030042/* Vertically and horizontally flips the image if matched, needed for machines
43 where the sensor is mounted upside down */
44static
45 const
46 struct dmi_system_id ov9650_flip_dmi_table[] = {
47 {
Johannes Klug201a8a62009-01-25 15:25:44 -030048 .ident = "ASUS A6VA",
49 .matches = {
50 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
51 DMI_MATCH(DMI_PRODUCT_NAME, "A6VA")
52 }
53 },
54 {
55
Erik Andrén30881ab2008-11-18 14:36:53 -030056 .ident = "ASUS A6VC",
57 .matches = {
58 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
59 DMI_MATCH(DMI_PRODUCT_NAME, "A6VC")
60 }
61 },
62 {
63 .ident = "ASUS A6VM",
64 .matches = {
65 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
66 DMI_MATCH(DMI_PRODUCT_NAME, "A6VM")
67 }
68 },
69 {
70 .ident = "ASUS A6JC",
71 .matches = {
72 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
73 DMI_MATCH(DMI_PRODUCT_NAME, "A6JC")
74 }
75 },
76 {
Erik Andrén3efb6bd2008-11-25 03:15:15 -030077 .ident = "ASUS A6Ja",
78 .matches = {
79 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
80 DMI_MATCH(DMI_PRODUCT_NAME, "A6J")
81 }
82 },
83 {
Erik Andrén30881ab2008-11-18 14:36:53 -030084 .ident = "ASUS A6Kt",
85 .matches = {
86 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
87 DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt")
88 }
89 },
Erik Andrén7e08e662008-12-19 03:29:31 -030090 {
91 .ident = "Alienware Aurora m9700",
92 .matches = {
93 DMI_MATCH(DMI_SYS_VENDOR, "alienware"),
94 DMI_MATCH(DMI_PRODUCT_NAME, "Aurora m9700")
95 }
96 },
Erik Andr?n7460f522009-01-04 04:52:50 -030097 {}
Erik Andrén30881ab2008-11-18 14:36:53 -030098};
99
Erik Andr?ne17cc082008-12-30 17:06:55 -0300100const static struct ctrl ov9650_ctrls[] = {
Erik Andr?nbe63b722009-01-03 13:58:12 -0300101#define EXPOSURE_IDX 0
Erik Andr?ne17cc082008-12-30 17:06:55 -0300102 {
103 {
104 .id = V4L2_CID_EXPOSURE,
105 .type = V4L2_CTRL_TYPE_INTEGER,
106 .name = "exposure",
107 .minimum = 0x00,
Erik Andr?n7136e702008-12-31 07:25:42 -0300108 .maximum = 0x1ff,
109 .step = 0x4,
Erik Andr?ne17cc082008-12-30 17:06:55 -0300110 .default_value = EXPOSURE_DEFAULT,
111 .flags = V4L2_CTRL_FLAG_SLIDER
112 },
113 .set = ov9650_set_exposure,
114 .get = ov9650_get_exposure
Erik Andr?nbe63b722009-01-03 13:58:12 -0300115 },
116#define GAIN_IDX 1
117 {
Erik Andr?ne17cc082008-12-30 17:06:55 -0300118 {
119 .id = V4L2_CID_GAIN,
120 .type = V4L2_CTRL_TYPE_INTEGER,
121 .name = "gain",
122 .minimum = 0x00,
123 .maximum = 0x3ff,
124 .step = 0x1,
125 .default_value = GAIN_DEFAULT,
126 .flags = V4L2_CTRL_FLAG_SLIDER
127 },
128 .set = ov9650_set_gain,
129 .get = ov9650_get_gain
Erik Andr?nbe63b722009-01-03 13:58:12 -0300130 },
131#define RED_BALANCE_IDX 2
132 {
Erik Andr?ne17cc082008-12-30 17:06:55 -0300133 {
134 .type = V4L2_CTRL_TYPE_INTEGER,
135 .name = "red balance",
136 .minimum = 0x00,
137 .maximum = 0xff,
138 .step = 0x1,
139 .default_value = RED_GAIN_DEFAULT,
140 .flags = V4L2_CTRL_FLAG_SLIDER
141 },
142 .set = ov9650_set_red_balance,
143 .get = ov9650_get_red_balance
Erik Andr?nbe63b722009-01-03 13:58:12 -0300144 },
145#define BLUE_BALANCE_IDX 3
146 {
Erik Andr?ne17cc082008-12-30 17:06:55 -0300147 {
148 .type = V4L2_CTRL_TYPE_INTEGER,
149 .name = "blue balance",
150 .minimum = 0x00,
151 .maximum = 0xff,
152 .step = 0x1,
153 .default_value = BLUE_GAIN_DEFAULT,
154 .flags = V4L2_CTRL_FLAG_SLIDER
155 },
156 .set = ov9650_set_blue_balance,
157 .get = ov9650_get_blue_balance
Erik Andr?nbe63b722009-01-03 13:58:12 -0300158 },
159#define HFLIP_IDX 4
160 {
Erik Andr?ne17cc082008-12-30 17:06:55 -0300161 {
162 .id = V4L2_CID_HFLIP,
163 .type = V4L2_CTRL_TYPE_BOOLEAN,
164 .name = "horizontal flip",
165 .minimum = 0,
166 .maximum = 1,
167 .step = 1,
168 .default_value = 0
169 },
170 .set = ov9650_set_hflip,
171 .get = ov9650_get_hflip
Erik Andr?nbe63b722009-01-03 13:58:12 -0300172 },
173#define VFLIP_IDX 5
174 {
Erik Andr?ne17cc082008-12-30 17:06:55 -0300175 {
176 .id = V4L2_CID_VFLIP,
177 .type = V4L2_CTRL_TYPE_BOOLEAN,
178 .name = "vertical flip",
179 .minimum = 0,
180 .maximum = 1,
181 .step = 1,
182 .default_value = 0
183 },
184 .set = ov9650_set_vflip,
185 .get = ov9650_get_vflip
Erik Andr?nbe63b722009-01-03 13:58:12 -0300186 },
187#define AUTO_WHITE_BALANCE_IDX 6
188 {
Erik Andr?ne17cc082008-12-30 17:06:55 -0300189 {
190 .id = V4L2_CID_AUTO_WHITE_BALANCE,
191 .type = V4L2_CTRL_TYPE_BOOLEAN,
192 .name = "auto white balance",
193 .minimum = 0,
194 .maximum = 1,
195 .step = 1,
Erik Andr?n5a0489b2008-12-31 06:36:52 -0300196 .default_value = 1
Erik Andr?ne17cc082008-12-30 17:06:55 -0300197 },
198 .set = ov9650_set_auto_white_balance,
199 .get = ov9650_get_auto_white_balance
Erik Andr?nbe63b722009-01-03 13:58:12 -0300200 },
201#define AUTO_GAIN_CTRL_IDX 7
202 {
Erik Andr?ne17cc082008-12-30 17:06:55 -0300203 {
204 .id = V4L2_CID_AUTOGAIN,
205 .type = V4L2_CTRL_TYPE_BOOLEAN,
206 .name = "auto gain control",
207 .minimum = 0,
208 .maximum = 1,
209 .step = 1,
Erik Andr?n8a38c642008-12-31 04:49:33 -0300210 .default_value = 1
Erik Andr?ne17cc082008-12-30 17:06:55 -0300211 },
212 .set = ov9650_set_auto_gain,
213 .get = ov9650_get_auto_gain
Erik Andr?n9ae16572009-01-13 03:57:57 -0300214 },
215#define AUTO_EXPOSURE_IDX 8
216 {
217 {
218 .id = V4L2_CID_EXPOSURE_AUTO,
219 .type = V4L2_CTRL_TYPE_BOOLEAN,
220 .name = "auto exposure",
221 .minimum = 0,
222 .maximum = 1,
223 .step = 1,
224 .default_value = 1
225 },
226 .set = ov9650_set_auto_exposure,
227 .get = ov9650_get_auto_exposure
Erik Andr?ne17cc082008-12-30 17:06:55 -0300228 }
Erik Andr?n9ae16572009-01-13 03:57:57 -0300229
Erik Andr?ne17cc082008-12-30 17:06:55 -0300230};
231
Erik Andr?n74cadfe2008-12-30 16:48:42 -0300232static struct v4l2_pix_format ov9650_modes[] = {
233 {
234 176,
235 144,
236 V4L2_PIX_FMT_SBGGR8,
237 V4L2_FIELD_NONE,
238 .sizeimage =
239 176 * 144,
240 .bytesperline = 176,
241 .colorspace = V4L2_COLORSPACE_SRGB,
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300242 .priv = 9
Erik Andr?n74cadfe2008-12-30 16:48:42 -0300243 }, {
244 320,
245 240,
246 V4L2_PIX_FMT_SBGGR8,
247 V4L2_FIELD_NONE,
248 .sizeimage =
249 320 * 240,
250 .bytesperline = 320,
251 .colorspace = V4L2_COLORSPACE_SRGB,
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300252 .priv = 8
Erik Andr?n74cadfe2008-12-30 16:48:42 -0300253 }, {
254 352,
255 288,
256 V4L2_PIX_FMT_SBGGR8,
257 V4L2_FIELD_NONE,
258 .sizeimage =
259 352 * 288,
260 .bytesperline = 352,
261 .colorspace = V4L2_COLORSPACE_SRGB,
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300262 .priv = 9
Erik Andr?n74cadfe2008-12-30 16:48:42 -0300263 }, {
264 640,
265 480,
266 V4L2_PIX_FMT_SBGGR8,
267 V4L2_FIELD_NONE,
268 .sizeimage =
269 640 * 480,
270 .bytesperline = 640,
271 .colorspace = V4L2_COLORSPACE_SRGB,
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300272 .priv = 9
Erik Andr?n74cadfe2008-12-30 16:48:42 -0300273 }
274};
275
Erik Andrén658efb62008-11-24 14:21:29 -0300276static void ov9650_dump_registers(struct sd *sd);
277
Erik Andrenc109f812008-10-01 04:51:53 -0300278int ov9650_probe(struct sd *sd)
279{
Erik Andr?n6b055502009-01-02 17:58:08 -0300280 int err = 0;
Erik Andrenc109f812008-10-01 04:51:53 -0300281 u8 prod_id = 0, ver_id = 0, i;
Erik Andr?nd9c700d2009-01-03 12:10:11 -0300282 s32 *sensor_settings;
Erik Andrenc109f812008-10-01 04:51:53 -0300283
284 if (force_sensor) {
285 if (force_sensor == OV9650_SENSOR) {
286 info("Forcing an %s sensor", ov9650.name);
287 goto sensor_found;
288 }
289 /* If we want to force another sensor,
290 don't try to probe this one */
291 return -ENODEV;
292 }
293
294 info("Probing for an ov9650 sensor");
295
Erik Andr?n7460f522009-01-04 04:52:50 -0300296 /* Run the pre-init before probing the sensor */
Erik Andr?n6b055502009-01-02 17:58:08 -0300297 for (i = 0; i < ARRAY_SIZE(preinit_ov9650) && !err; i++) {
Erik Andrenc109f812008-10-01 04:51:53 -0300298 u8 data = preinit_ov9650[i][2];
299 if (preinit_ov9650[i][0] == SENSOR)
Erik Andr?n6b055502009-01-02 17:58:08 -0300300 err = m5602_write_sensor(sd,
Erik Andr?nd9c700d2009-01-03 12:10:11 -0300301 preinit_ov9650[i][1], &data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300302 else
Erik Andr?nd9c700d2009-01-03 12:10:11 -0300303 err = m5602_write_bridge(sd,
304 preinit_ov9650[i][1], data);
Erik Andrenc109f812008-10-01 04:51:53 -0300305 }
306
Erik Andr?n6b055502009-01-02 17:58:08 -0300307 if (err < 0)
308 return err;
309
Erik Andrén905aaba2008-11-27 13:42:45 -0300310 if (m5602_read_sensor(sd, OV9650_PID, &prod_id, 1))
Erik Andrenc109f812008-10-01 04:51:53 -0300311 return -ENODEV;
312
Erik Andrén905aaba2008-11-27 13:42:45 -0300313 if (m5602_read_sensor(sd, OV9650_VER, &ver_id, 1))
Erik Andrenc109f812008-10-01 04:51:53 -0300314 return -ENODEV;
315
316 if ((prod_id == 0x96) && (ver_id == 0x52)) {
317 info("Detected an ov9650 sensor");
318 goto sensor_found;
319 }
Erik Andrenc109f812008-10-01 04:51:53 -0300320 return -ENODEV;
321
322sensor_found:
Erik Andr?nd9c700d2009-01-03 12:10:11 -0300323 sensor_settings = kmalloc(
324 ARRAY_SIZE(ov9650_ctrls) * sizeof(s32), GFP_KERNEL);
325 if (!sensor_settings)
326 return -ENOMEM;
327
Erik Andr?n74cadfe2008-12-30 16:48:42 -0300328 sd->gspca_dev.cam.cam_mode = ov9650_modes;
329 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov9650_modes);
Erik Andr?ne17cc082008-12-30 17:06:55 -0300330 sd->desc->ctrls = ov9650_ctrls;
Erik Andr?ne4cc4fc2008-12-30 15:27:17 -0300331 sd->desc->nctrls = ARRAY_SIZE(ov9650_ctrls);
Erik Andr?nd9c700d2009-01-03 12:10:11 -0300332
333 for (i = 0; i < ARRAY_SIZE(ov9650_ctrls); i++)
334 sensor_settings[i] = ov9650_ctrls[i].qctrl.default_value;
335 sd->sensor_priv = sensor_settings;
Erik Andrenc109f812008-10-01 04:51:53 -0300336 return 0;
337}
338
339int ov9650_init(struct sd *sd)
340{
341 int i, err = 0;
342 u8 data;
Erik Andr?n7460f522009-01-04 04:52:50 -0300343 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300344
345 if (dump_sensor)
346 ov9650_dump_registers(sd);
347
348 for (i = 0; i < ARRAY_SIZE(init_ov9650) && !err; i++) {
349 data = init_ov9650[i][2];
350 if (init_ov9650[i][0] == SENSOR)
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300351 err = m5602_write_sensor(sd, init_ov9650[i][1],
Erik Andrenc109f812008-10-01 04:51:53 -0300352 &data, 1);
353 else
354 err = m5602_write_bridge(sd, init_ov9650[i][1], data);
355 }
356
Erik Andr?ncf811d52009-04-03 02:49:10 -0300357 err = ov9650_set_exposure(&sd->gspca_dev,
358 sensor_settings[EXPOSURE_IDX]);
Erik Andr?n7460f522009-01-04 04:52:50 -0300359 if (err < 0)
360 return err;
361
362 err = ov9650_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
363 if (err < 0)
364 return err;
365
Erik Andr?ncf811d52009-04-03 02:49:10 -0300366 err = ov9650_set_red_balance(&sd->gspca_dev,
367 sensor_settings[RED_BALANCE_IDX]);
Erik Andr?n7460f522009-01-04 04:52:50 -0300368 if (err < 0)
369 return err;
370
Erik Andr?ncf811d52009-04-03 02:49:10 -0300371 err = ov9650_set_blue_balance(&sd->gspca_dev,
372 sensor_settings[BLUE_BALANCE_IDX]);
Erik Andr?n7460f522009-01-04 04:52:50 -0300373 if (err < 0)
374 return err;
375
376 err = ov9650_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
377 if (err < 0)
378 return err;
379
380 err = ov9650_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
381 if (err < 0)
382 return err;
383
Erik Andr?n9ae16572009-01-13 03:57:57 -0300384 err = ov9650_set_auto_exposure(&sd->gspca_dev,
385 sensor_settings[AUTO_EXPOSURE_IDX]);
386 if (err < 0)
387 return err;
388
Erik Andr?ncf811d52009-04-03 02:49:10 -0300389 err = ov9650_set_auto_white_balance(&sd->gspca_dev,
390 sensor_settings[AUTO_WHITE_BALANCE_IDX]);
Erik Andr?n7460f522009-01-04 04:52:50 -0300391 if (err < 0)
392 return err;
393
Erik Andr?ncf811d52009-04-03 02:49:10 -0300394 err = ov9650_set_auto_gain(&sd->gspca_dev,
Erik Andr?n9ae16572009-01-13 03:57:57 -0300395 sensor_settings[AUTO_GAIN_CTRL_IDX]);
Erik Andréne07b14e2008-11-20 03:54:43 -0300396 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300397}
398
Erik Andrén082aa892008-12-21 18:07:59 -0300399int ov9650_start(struct sd *sd)
400{
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300401 u8 data;
Erik Andrén082aa892008-12-21 18:07:59 -0300402 int i, err = 0;
403 struct cam *cam = &sd->gspca_dev.cam;
Erik Andr?nbe63b722009-01-03 13:58:12 -0300404 s32 *sensor_settings = sd->sensor_priv;
405
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300406 int width = cam->cam_mode[sd->gspca_dev.curr_mode].width;
407 int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
408 int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
409 int hor_offs = OV9650_LEFT_OFFSET;
410
Erik Andr?n6f02d762009-01-06 12:58:50 -0300411 if ((!dmi_check_system(ov9650_flip_dmi_table) &&
412 sensor_settings[VFLIP_IDX]) ||
413 (dmi_check_system(ov9650_flip_dmi_table) &&
414 !sensor_settings[VFLIP_IDX]))
Erik Andr?nbe63b722009-01-03 13:58:12 -0300415 ver_offs--;
416
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300417 if (width <= 320)
418 hor_offs /= 2;
Erik Andrén082aa892008-12-21 18:07:59 -0300419
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300420 /* Synthesize the vsync/hsync setup */
Erik Andr?n3d3ec922008-12-29 12:49:25 -0300421 for (i = 0; i < ARRAY_SIZE(res_init_ov9650) && !err; i++) {
422 if (res_init_ov9650[i][0] == BRIDGE)
Erik Andr?n4eecb1762008-12-30 15:29:48 -0300423 err = m5602_write_bridge(sd, res_init_ov9650[i][1],
424 res_init_ov9650[i][2]);
Erik Andr?n3d3ec922008-12-29 12:49:25 -0300425 else if (res_init_ov9650[i][0] == SENSOR) {
426 u8 data = res_init_ov9650[i][2];
Erik Andr?n4eecb1762008-12-30 15:29:48 -0300427 err = m5602_write_sensor(sd,
428 res_init_ov9650[i][1], &data, 1);
Erik Andr?n3d3ec922008-12-29 12:49:25 -0300429 }
430 }
Erik Andrén27b1e4c2008-12-23 18:06:37 -0300431 if (err < 0)
432 return err;
433
Erik Andr?nd9c700d2009-01-03 12:10:11 -0300434 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA,
435 ((ver_offs >> 8) & 0xff));
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300436 if (err < 0)
437 return err;
438
439 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (ver_offs & 0xff));
440 if (err < 0)
441 return err;
442
443 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
444 if (err < 0)
445 return err;
446
447 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff);
448 if (err < 0)
449 return err;
450
451 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff));
452 if (err < 0)
453 return err;
454
Erik Andr?nd9c700d2009-01-03 12:10:11 -0300455 for (i = 0; i < 2 && !err; i++)
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300456 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300457 if (err < 0)
458 return err;
459
Erik Andr?nb05a4ad2009-01-19 14:02:28 -0300460 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
461 if (err < 0)
462 return err;
463
464 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2);
465 if (err < 0)
466 return err;
467
Erik Andr?nd9c700d2009-01-03 12:10:11 -0300468 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
469 (hor_offs >> 8) & 0xff);
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300470 if (err < 0)
471 return err;
472
473 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, hor_offs & 0xff);
474 if (err < 0)
475 return err;
476
Erik Andr?nd9c700d2009-01-03 12:10:11 -0300477 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
478 ((width + hor_offs) >> 8) & 0xff);
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300479 if (err < 0)
480 return err;
481
Erik Andr?nd9c700d2009-01-03 12:10:11 -0300482 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
483 ((width + hor_offs) & 0xff));
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300484 if (err < 0)
485 return err;
486
Erik Andr?nb05a4ad2009-01-19 14:02:28 -0300487 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
488 if (err < 0)
489 return err;
490
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300491 switch (width) {
Erik Andrén082aa892008-12-21 18:07:59 -0300492 case 640:
493 PDEBUG(D_V4L2, "Configuring camera for VGA mode");
494
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300495 data = OV9650_VGA_SELECT | OV9650_RGB_SELECT |
496 OV9650_RAW_RGB_SELECT;
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300497 err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
Erik Andrén082aa892008-12-21 18:07:59 -0300498 break;
Erik Andrén3b2f3322008-12-22 16:06:29 -0300499
Erik Andrén03f46de2008-12-23 17:07:58 -0300500 case 352:
501 PDEBUG(D_V4L2, "Configuring camera for CIF mode");
502
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300503 data = OV9650_CIF_SELECT | OV9650_RGB_SELECT |
504 OV9650_RAW_RGB_SELECT;
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300505 err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
Erik Andrén03f46de2008-12-23 17:07:58 -0300506 break;
507
Erik Andrén3b2f3322008-12-22 16:06:29 -0300508 case 320:
509 PDEBUG(D_V4L2, "Configuring camera for QVGA mode");
510
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300511 data = OV9650_QVGA_SELECT | OV9650_RGB_SELECT |
512 OV9650_RAW_RGB_SELECT;
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300513 err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
Erik Andrén3b2f3322008-12-22 16:06:29 -0300514 break;
Erik Andr?ne31f9dd2008-12-27 13:30:10 -0300515
516 case 176:
517 PDEBUG(D_V4L2, "Configuring camera for QCIF mode");
518
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300519 data = OV9650_QCIF_SELECT | OV9650_RGB_SELECT |
520 OV9650_RAW_RGB_SELECT;
Erik Andr?nbd99ffb2009-01-03 10:55:52 -0300521 err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
522 break;
Erik Andrén082aa892008-12-21 18:07:59 -0300523 }
524 return err;
525}
526
Erik Andr?n3d3ec922008-12-29 12:49:25 -0300527int ov9650_stop(struct sd *sd)
528{
529 u8 data = OV9650_SOFT_SLEEP | OV9650_OUTPUT_DRIVE_2X;
530 return m5602_write_sensor(sd, OV9650_COM2, &data, 1);
531}
532
Erik Andr?nd9c700d2009-01-03 12:10:11 -0300533void ov9650_disconnect(struct sd *sd)
534{
535 ov9650_stop(sd);
Erik Andr?nd9c700d2009-01-03 12:10:11 -0300536
537 sd->sensor = NULL;
Erik Andr?nd9c700d2009-01-03 12:10:11 -0300538 kfree(sd->sensor_priv);
539}
540
Erik Andr?ncf811d52009-04-03 02:49:10 -0300541static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
Erik Andrenc109f812008-10-01 04:51:53 -0300542{
543 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?nbe63b722009-01-03 13:58:12 -0300544 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300545
Erik Andr?nbe63b722009-01-03 13:58:12 -0300546 *val = sensor_settings[EXPOSURE_IDX];
Erik Andren17ea88a2008-10-16 16:46:07 -0300547 PDEBUG(D_V4L2, "Read exposure %d", *val);
Erik Andr?nbe63b722009-01-03 13:58:12 -0300548 return 0;
Erik Andrenc109f812008-10-01 04:51:53 -0300549}
550
Erik Andr?ncf811d52009-04-03 02:49:10 -0300551static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
Erik Andrenc109f812008-10-01 04:51:53 -0300552{
553 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?nbe63b722009-01-03 13:58:12 -0300554 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300555 u8 i2c_data;
556 int err;
557
Erik Andr?nbe63b722009-01-03 13:58:12 -0300558 PDEBUG(D_V4L2, "Set exposure to %d", val);
559
560 sensor_settings[EXPOSURE_IDX] = val;
Erik Andrenc109f812008-10-01 04:51:53 -0300561 /* The 6 MSBs */
562 i2c_data = (val >> 10) & 0x3f;
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300563 err = m5602_write_sensor(sd, OV9650_AECHM,
Erik Andrenc109f812008-10-01 04:51:53 -0300564 &i2c_data, 1);
565 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300566 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300567
568 /* The 8 middle bits */
569 i2c_data = (val >> 2) & 0xff;
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300570 err = m5602_write_sensor(sd, OV9650_AECH,
Erik Andrenc109f812008-10-01 04:51:53 -0300571 &i2c_data, 1);
572 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300573 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300574
575 /* The 2 LSBs */
576 i2c_data = val & 0x03;
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300577 err = m5602_write_sensor(sd, OV9650_COM1, &i2c_data, 1);
Erik Andréne07b14e2008-11-20 03:54:43 -0300578 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300579}
580
Erik Andr?ncf811d52009-04-03 02:49:10 -0300581static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
Erik Andrenc109f812008-10-01 04:51:53 -0300582{
Erik Andrenc109f812008-10-01 04:51:53 -0300583 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?nbe63b722009-01-03 13:58:12 -0300584 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300585
Erik Andr?nbe63b722009-01-03 13:58:12 -0300586 *val = sensor_settings[GAIN_IDX];
Erik Andren17ea88a2008-10-16 16:46:07 -0300587 PDEBUG(D_V4L2, "Read gain %d", *val);
Erik Andr?nbe63b722009-01-03 13:58:12 -0300588 return 0;
Erik Andrenc109f812008-10-01 04:51:53 -0300589}
590
Erik Andr?ncf811d52009-04-03 02:49:10 -0300591static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
Erik Andrenc109f812008-10-01 04:51:53 -0300592{
593 int err;
594 u8 i2c_data;
595 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?nbe63b722009-01-03 13:58:12 -0300596 s32 *sensor_settings = sd->sensor_priv;
597
598 PDEBUG(D_V4L2, "Setting gain to %d", val);
599
600 sensor_settings[GAIN_IDX] = val;
Erik Andrenc109f812008-10-01 04:51:53 -0300601
602 /* The 2 MSB */
603 /* Read the OV9650_VREF register first to avoid
604 corrupting the VREF high and low bits */
Erik Andr?n6b055502009-01-02 17:58:08 -0300605 err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
606 if (err < 0)
607 return err;
608
Erik Andrenc109f812008-10-01 04:51:53 -0300609 /* Mask away all uninteresting bits */
610 i2c_data = ((val & 0x0300) >> 2) |
611 (i2c_data & 0x3F);
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300612 err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
Erik Andr?n6b055502009-01-02 17:58:08 -0300613 if (err < 0)
614 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300615
616 /* The 8 LSBs */
617 i2c_data = val & 0xff;
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300618 err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1);
Erik Andréne07b14e2008-11-20 03:54:43 -0300619 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300620}
621
Erik Andr?ncf811d52009-04-03 02:49:10 -0300622static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
Erik Andrenc109f812008-10-01 04:51:53 -0300623{
Erik Andrenc109f812008-10-01 04:51:53 -0300624 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?nbe63b722009-01-03 13:58:12 -0300625 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300626
Erik Andr?nbe63b722009-01-03 13:58:12 -0300627 *val = sensor_settings[RED_BALANCE_IDX];
Erik Andren17ea88a2008-10-16 16:46:07 -0300628 PDEBUG(D_V4L2, "Read red gain %d", *val);
Erik Andr?nbe63b722009-01-03 13:58:12 -0300629 return 0;
Erik Andrenc109f812008-10-01 04:51:53 -0300630}
631
Erik Andr?ncf811d52009-04-03 02:49:10 -0300632static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
Erik Andrenc109f812008-10-01 04:51:53 -0300633{
634 int err;
635 u8 i2c_data;
636 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?nbe63b722009-01-03 13:58:12 -0300637 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300638
Erik Andr?nbe63b722009-01-03 13:58:12 -0300639 PDEBUG(D_V4L2, "Set red gain to %d", val);
640
641 sensor_settings[RED_BALANCE_IDX] = val;
Erik Andrenc109f812008-10-01 04:51:53 -0300642
643 i2c_data = val & 0xff;
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300644 err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1);
Erik Andréne07b14e2008-11-20 03:54:43 -0300645 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300646}
647
Erik Andr?ncf811d52009-04-03 02:49:10 -0300648static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
Erik Andrenc109f812008-10-01 04:51:53 -0300649{
Erik Andrenc109f812008-10-01 04:51:53 -0300650 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?nbe63b722009-01-03 13:58:12 -0300651 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300652
Erik Andr?nbe63b722009-01-03 13:58:12 -0300653 *val = sensor_settings[BLUE_BALANCE_IDX];
Erik Andren17ea88a2008-10-16 16:46:07 -0300654 PDEBUG(D_V4L2, "Read blue gain %d", *val);
Erik Andrenc109f812008-10-01 04:51:53 -0300655
Erik Andr?nbe63b722009-01-03 13:58:12 -0300656 return 0;
Erik Andrenc109f812008-10-01 04:51:53 -0300657}
658
Erik Andr?ncf811d52009-04-03 02:49:10 -0300659static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
Erik Andrenc109f812008-10-01 04:51:53 -0300660{
661 int err;
662 u8 i2c_data;
663 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?nbe63b722009-01-03 13:58:12 -0300664 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300665
Erik Andr?nbe63b722009-01-03 13:58:12 -0300666 PDEBUG(D_V4L2, "Set blue gain to %d", val);
667
668 sensor_settings[BLUE_BALANCE_IDX] = val;
Erik Andrenc109f812008-10-01 04:51:53 -0300669
670 i2c_data = val & 0xff;
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300671 err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1);
Erik Andréne07b14e2008-11-20 03:54:43 -0300672 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300673}
674
Erik Andr?ncf811d52009-04-03 02:49:10 -0300675static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
Erik Andrenc109f812008-10-01 04:51:53 -0300676{
Erik Andrenc109f812008-10-01 04:51:53 -0300677 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?nbe63b722009-01-03 13:58:12 -0300678 s32 *sensor_settings = sd->sensor_priv;
Erik Andr?n3c19a952009-01-04 07:35:27 -0300679
Erik Andr?nbe63b722009-01-03 13:58:12 -0300680 *val = sensor_settings[HFLIP_IDX];
Erik Andren17ea88a2008-10-16 16:46:07 -0300681 PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
Erik Andr?nbe63b722009-01-03 13:58:12 -0300682 return 0;
Erik Andrenc109f812008-10-01 04:51:53 -0300683}
684
Erik Andr?ncf811d52009-04-03 02:49:10 -0300685static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
Erik Andrenc109f812008-10-01 04:51:53 -0300686{
687 int err;
688 u8 i2c_data;
689 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?nbe63b722009-01-03 13:58:12 -0300690 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300691
Erik Andren17ea88a2008-10-16 16:46:07 -0300692 PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
Erik Andr?nbe63b722009-01-03 13:58:12 -0300693
694 sensor_settings[HFLIP_IDX] = val;
Erik Andr?n6f02d762009-01-06 12:58:50 -0300695
696 if (!dmi_check_system(ov9650_flip_dmi_table))
Erik Andr?ncf811d52009-04-03 02:49:10 -0300697 i2c_data = ((val & 0x01) << 5) |
698 (sensor_settings[VFLIP_IDX] << 4);
Erik Andr?n6f02d762009-01-06 12:58:50 -0300699 else
Erik Andr?ncf811d52009-04-03 02:49:10 -0300700 i2c_data = ((val & 0x01) << 5) |
701 (!sensor_settings[VFLIP_IDX] << 4);
Erik Andr?n6f02d762009-01-06 12:58:50 -0300702
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300703 err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
Erik Andr?n051781b2008-12-27 12:28:00 -0300704
Erik Andréne07b14e2008-11-20 03:54:43 -0300705 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300706}
707
Erik Andr?ncf811d52009-04-03 02:49:10 -0300708static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
Erik Andrenc109f812008-10-01 04:51:53 -0300709{
Erik Andrenc109f812008-10-01 04:51:53 -0300710 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?nbe63b722009-01-03 13:58:12 -0300711 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300712
Erik Andr?nbe63b722009-01-03 13:58:12 -0300713 *val = sensor_settings[VFLIP_IDX];
Erik Andren17ea88a2008-10-16 16:46:07 -0300714 PDEBUG(D_V4L2, "Read vertical flip %d", *val);
Erik Andrenc109f812008-10-01 04:51:53 -0300715
Erik Andr?nbe63b722009-01-03 13:58:12 -0300716 return 0;
Erik Andrenc109f812008-10-01 04:51:53 -0300717}
718
Erik Andr?ncf811d52009-04-03 02:49:10 -0300719static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
Erik Andrenc109f812008-10-01 04:51:53 -0300720{
721 int err;
722 u8 i2c_data;
723 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?nbe63b722009-01-03 13:58:12 -0300724 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300725
Erik Andren17ea88a2008-10-16 16:46:07 -0300726 PDEBUG(D_V4L2, "Set vertical flip to %d", val);
Erik Andr?nbe63b722009-01-03 13:58:12 -0300727 sensor_settings[VFLIP_IDX] = val;
Erik Andrenc109f812008-10-01 04:51:53 -0300728
Erik Andr?n6f02d762009-01-06 12:58:50 -0300729 if (dmi_check_system(ov9650_flip_dmi_table))
730 val = !val;
731
Erik Andr?n5196d7c2009-01-04 07:28:42 -0300732 i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5);
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300733 err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
Erik Andr?nbe63b722009-01-03 13:58:12 -0300734 if (err < 0)
735 return err;
736
Erik Andr?n5196d7c2009-01-04 07:28:42 -0300737 /* When vflip is toggled we need to readjust the bridge hsync/vsync */
Erik Andr?nbe63b722009-01-03 13:58:12 -0300738 if (gspca_dev->streaming)
739 err = ov9650_start(sd);
740
Erik Andréne07b14e2008-11-20 03:54:43 -0300741 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300742}
743
Erik Andr?n9ae16572009-01-13 03:57:57 -0300744static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val)
745{
746 struct sd *sd = (struct sd *) gspca_dev;
747 s32 *sensor_settings = sd->sensor_priv;
748
749 *val = sensor_settings[AUTO_EXPOSURE_IDX];
750 PDEBUG(D_V4L2, "Read auto exposure control %d", *val);
751 return 0;
752}
753
754static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev,
755 __s32 val)
756{
757 int err;
758 u8 i2c_data;
759 struct sd *sd = (struct sd *) gspca_dev;
760 s32 *sensor_settings = sd->sensor_priv;
761
762 PDEBUG(D_V4L2, "Set auto exposure control to %d", val);
763
764 sensor_settings[AUTO_EXPOSURE_IDX] = val;
765 err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
766 if (err < 0)
767 return err;
768
769 i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
770
771 return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
772}
773
Erik Andr?ncf811d52009-04-03 02:49:10 -0300774static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
775 __s32 *val)
Erik Andrenc109f812008-10-01 04:51:53 -0300776{
Erik Andrenc109f812008-10-01 04:51:53 -0300777 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?nbe63b722009-01-03 13:58:12 -0300778 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300779
Erik Andr?nbe63b722009-01-03 13:58:12 -0300780 *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
781 return 0;
Erik Andrenc109f812008-10-01 04:51:53 -0300782}
783
Erik Andr?ncf811d52009-04-03 02:49:10 -0300784static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
785 __s32 val)
Erik Andrenc109f812008-10-01 04:51:53 -0300786{
787 int err;
788 u8 i2c_data;
789 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?nbe63b722009-01-03 13:58:12 -0300790 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300791
Erik Andren17ea88a2008-10-16 16:46:07 -0300792 PDEBUG(D_V4L2, "Set auto white balance to %d", val);
Erik Andr?nbe63b722009-01-03 13:58:12 -0300793
794 sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
Erik Andrén905aaba2008-11-27 13:42:45 -0300795 err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300796 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300797 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300798
799 i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1));
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300800 err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
Erik Andr?n051781b2008-12-27 12:28:00 -0300801
Erik Andréne07b14e2008-11-20 03:54:43 -0300802 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300803}
804
Erik Andr?ncf811d52009-04-03 02:49:10 -0300805static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
Erik Andrenc109f812008-10-01 04:51:53 -0300806{
Erik Andrenc109f812008-10-01 04:51:53 -0300807 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?nbe63b722009-01-03 13:58:12 -0300808 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300809
Erik Andr?nbe63b722009-01-03 13:58:12 -0300810 *val = sensor_settings[AUTO_GAIN_CTRL_IDX];
Erik Andren17ea88a2008-10-16 16:46:07 -0300811 PDEBUG(D_V4L2, "Read auto gain control %d", *val);
Erik Andr?nbe63b722009-01-03 13:58:12 -0300812 return 0;
Erik Andrenc109f812008-10-01 04:51:53 -0300813}
814
Erik Andr?ncf811d52009-04-03 02:49:10 -0300815static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
Erik Andrenc109f812008-10-01 04:51:53 -0300816{
817 int err;
818 u8 i2c_data;
819 struct sd *sd = (struct sd *) gspca_dev;
Erik Andr?nbe63b722009-01-03 13:58:12 -0300820 s32 *sensor_settings = sd->sensor_priv;
Erik Andrenc109f812008-10-01 04:51:53 -0300821
Erik Andren17ea88a2008-10-16 16:46:07 -0300822 PDEBUG(D_V4L2, "Set auto gain control to %d", val);
Erik Andr?nbe63b722009-01-03 13:58:12 -0300823
824 sensor_settings[AUTO_GAIN_CTRL_IDX] = val;
Erik Andrén905aaba2008-11-27 13:42:45 -0300825 err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300826 if (err < 0)
Erik Andr?n051781b2008-12-27 12:28:00 -0300827 return err;
Erik Andrenc109f812008-10-01 04:51:53 -0300828
829 i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2));
Erik Andr?n051781b2008-12-27 12:28:00 -0300830
Erik Andr?n9ae16572009-01-13 03:57:57 -0300831 return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300832}
833
Erik Andrén658efb62008-11-24 14:21:29 -0300834static void ov9650_dump_registers(struct sd *sd)
Erik Andrenc109f812008-10-01 04:51:53 -0300835{
836 int address;
837 info("Dumping the ov9650 register state");
838 for (address = 0; address < 0xa9; address++) {
839 u8 value;
Erik Andrén905aaba2008-11-27 13:42:45 -0300840 m5602_read_sensor(sd, address, &value, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300841 info("register 0x%x contains 0x%x",
842 address, value);
843 }
844
845 info("ov9650 register state dump complete");
846
847 info("Probing for which registers that are read/write");
848 for (address = 0; address < 0xff; address++) {
849 u8 old_value, ctrl_value;
850 u8 test_value[2] = {0xff, 0xff};
851
Erik Andrén905aaba2008-11-27 13:42:45 -0300852 m5602_read_sensor(sd, address, &old_value, 1);
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300853 m5602_write_sensor(sd, address, test_value, 1);
Erik Andrén905aaba2008-11-27 13:42:45 -0300854 m5602_read_sensor(sd, address, &ctrl_value, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300855
856 if (ctrl_value == test_value[0])
857 info("register 0x%x is writeable", address);
858 else
859 info("register 0x%x is read only", address);
860
861 /* Restore original value */
Erik Andrén6dc4cff2008-11-26 04:08:10 -0300862 m5602_write_sensor(sd, address, &old_value, 1);
Erik Andrenc109f812008-10-01 04:51:53 -0300863 }
864}