diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/media/video/gspca/m5602/m5602_po1030.c | |
parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) |
Diffstat (limited to 'drivers/media/video/gspca/m5602/m5602_po1030.c')
-rw-r--r-- | drivers/media/video/gspca/m5602/m5602_po1030.c | 762 |
1 files changed, 762 insertions, 0 deletions
diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.c b/drivers/media/video/gspca/m5602/m5602_po1030.c new file mode 100644 index 00000000000..1febd34c2f0 --- /dev/null +++ b/drivers/media/video/gspca/m5602/m5602_po1030.c | |||
@@ -0,0 +1,762 @@ | |||
1 | /* | ||
2 | * Driver for the po1030 sensor | ||
3 | * | ||
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> | ||
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_po1030.h" | ||
20 | |||
21 | static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); | ||
22 | static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val); | ||
23 | static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val); | ||
24 | static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val); | ||
25 | static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); | ||
26 | static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); | ||
27 | static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); | ||
28 | static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); | ||
29 | static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val); | ||
30 | static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val); | ||
31 | static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); | ||
32 | static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val); | ||
33 | static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); | ||
34 | static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val); | ||
35 | static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev, | ||
36 | __s32 val); | ||
37 | static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev, | ||
38 | __s32 *val); | ||
39 | static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev, | ||
40 | __s32 val); | ||
41 | static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev, | ||
42 | __s32 *val); | ||
43 | |||
44 | static struct v4l2_pix_format po1030_modes[] = { | ||
45 | { | ||
46 | 640, | ||
47 | 480, | ||
48 | V4L2_PIX_FMT_SBGGR8, | ||
49 | V4L2_FIELD_NONE, | ||
50 | .sizeimage = 640 * 480, | ||
51 | .bytesperline = 640, | ||
52 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
53 | .priv = 2 | ||
54 | } | ||
55 | }; | ||
56 | |||
57 | static const struct ctrl po1030_ctrls[] = { | ||
58 | #define GAIN_IDX 0 | ||
59 | { | ||
60 | { | ||
61 | .id = V4L2_CID_GAIN, | ||
62 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
63 | .name = "gain", | ||
64 | .minimum = 0x00, | ||
65 | .maximum = 0x4f, | ||
66 | .step = 0x1, | ||
67 | .default_value = PO1030_GLOBAL_GAIN_DEFAULT, | ||
68 | .flags = V4L2_CTRL_FLAG_SLIDER | ||
69 | }, | ||
70 | .set = po1030_set_gain, | ||
71 | .get = po1030_get_gain | ||
72 | }, | ||
73 | #define EXPOSURE_IDX 1 | ||
74 | { | ||
75 | { | ||
76 | .id = V4L2_CID_EXPOSURE, | ||
77 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
78 | .name = "exposure", | ||
79 | .minimum = 0x00, | ||
80 | .maximum = 0x02ff, | ||
81 | .step = 0x1, | ||
82 | .default_value = PO1030_EXPOSURE_DEFAULT, | ||
83 | .flags = V4L2_CTRL_FLAG_SLIDER | ||
84 | }, | ||
85 | .set = po1030_set_exposure, | ||
86 | .get = po1030_get_exposure | ||
87 | }, | ||
88 | #define RED_BALANCE_IDX 2 | ||
89 | { | ||
90 | { | ||
91 | .id = V4L2_CID_RED_BALANCE, | ||
92 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
93 | .name = "red balance", | ||
94 | .minimum = 0x00, | ||
95 | .maximum = 0xff, | ||
96 | .step = 0x1, | ||
97 | .default_value = PO1030_RED_GAIN_DEFAULT, | ||
98 | .flags = V4L2_CTRL_FLAG_SLIDER | ||
99 | }, | ||
100 | .set = po1030_set_red_balance, | ||
101 | .get = po1030_get_red_balance | ||
102 | }, | ||
103 | #define BLUE_BALANCE_IDX 3 | ||
104 | { | ||
105 | { | ||
106 | .id = V4L2_CID_BLUE_BALANCE, | ||
107 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
108 | .name = "blue balance", | ||
109 | .minimum = 0x00, | ||
110 | .maximum = 0xff, | ||
111 | .step = 0x1, | ||
112 | .default_value = PO1030_BLUE_GAIN_DEFAULT, | ||
113 | .flags = V4L2_CTRL_FLAG_SLIDER | ||
114 | }, | ||
115 | .set = po1030_set_blue_balance, | ||
116 | .get = po1030_get_blue_balance | ||
117 | }, | ||
118 | #define HFLIP_IDX 4 | ||
119 | { | ||
120 | { | ||
121 | .id = V4L2_CID_HFLIP, | ||
122 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
123 | .name = "horizontal flip", | ||
124 | .minimum = 0, | ||
125 | .maximum = 1, | ||
126 | .step = 1, | ||
127 | .default_value = 0, | ||
128 | }, | ||
129 | .set = po1030_set_hflip, | ||
130 | .get = po1030_get_hflip | ||
131 | }, | ||
132 | #define VFLIP_IDX 5 | ||
133 | { | ||
134 | { | ||
135 | .id = V4L2_CID_VFLIP, | ||
136 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
137 | .name = "vertical flip", | ||
138 | .minimum = 0, | ||
139 | .maximum = 1, | ||
140 | .step = 1, | ||
141 | .default_value = 0, | ||
142 | }, | ||
143 | .set = po1030_set_vflip, | ||
144 | .get = po1030_get_vflip | ||
145 | }, | ||
146 | #define AUTO_WHITE_BALANCE_IDX 6 | ||
147 | { | ||
148 | { | ||
149 | .id = V4L2_CID_AUTO_WHITE_BALANCE, | ||
150 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
151 | .name = "auto white balance", | ||
152 | .minimum = 0, | ||
153 | .maximum = 1, | ||
154 | .step = 1, | ||
155 | .default_value = 0, | ||
156 | }, | ||
157 | .set = po1030_set_auto_white_balance, | ||
158 | .get = po1030_get_auto_white_balance | ||
159 | }, | ||
160 | #define AUTO_EXPOSURE_IDX 7 | ||
161 | { | ||
162 | { | ||
163 | .id = V4L2_CID_EXPOSURE_AUTO, | ||
164 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
165 | .name = "auto exposure", | ||
166 | .minimum = 0, | ||
167 | .maximum = 1, | ||
168 | .step = 1, | ||
169 | .default_value = 0, | ||
170 | }, | ||
171 | .set = po1030_set_auto_exposure, | ||
172 | .get = po1030_get_auto_exposure | ||
173 | }, | ||
174 | #define GREEN_BALANCE_IDX 8 | ||
175 | { | ||
176 | { | ||
177 | .id = M5602_V4L2_CID_GREEN_BALANCE, | ||
178 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
179 | .name = "green balance", | ||
180 | .minimum = 0x00, | ||
181 | .maximum = 0xff, | ||
182 | .step = 0x1, | ||
183 | .default_value = PO1030_GREEN_GAIN_DEFAULT, | ||
184 | .flags = V4L2_CTRL_FLAG_SLIDER | ||
185 | }, | ||
186 | .set = po1030_set_green_balance, | ||
187 | .get = po1030_get_green_balance | ||
188 | }, | ||
189 | }; | ||
190 | |||
191 | static void po1030_dump_registers(struct sd *sd); | ||
192 | |||
193 | int po1030_probe(struct sd *sd) | ||
194 | { | ||
195 | u8 dev_id_h = 0, i; | ||
196 | s32 *sensor_settings; | ||
197 | |||
198 | if (force_sensor) { | ||
199 | if (force_sensor == PO1030_SENSOR) { | ||
200 | info("Forcing a %s sensor", po1030.name); | ||
201 | goto sensor_found; | ||
202 | } | ||
203 | /* If we want to force another sensor, don't try to probe this | ||
204 | * one */ | ||
205 | return -ENODEV; | ||
206 | } | ||
207 | |||
208 | PDEBUG(D_PROBE, "Probing for a po1030 sensor"); | ||
209 | |||
210 | /* Run the pre-init to actually probe the unit */ | ||
211 | for (i = 0; i < ARRAY_SIZE(preinit_po1030); i++) { | ||
212 | u8 data = preinit_po1030[i][2]; | ||
213 | if (preinit_po1030[i][0] == SENSOR) | ||
214 | m5602_write_sensor(sd, | ||
215 | preinit_po1030[i][1], &data, 1); | ||
216 | else | ||
217 | m5602_write_bridge(sd, preinit_po1030[i][1], data); | ||
218 | } | ||
219 | |||
220 | if (m5602_read_sensor(sd, PO1030_DEVID_H, &dev_id_h, 1)) | ||
221 | return -ENODEV; | ||
222 | |||
223 | if (dev_id_h == 0x30) { | ||
224 | info("Detected a po1030 sensor"); | ||
225 | goto sensor_found; | ||
226 | } | ||
227 | return -ENODEV; | ||
228 | |||
229 | sensor_found: | ||
230 | sensor_settings = kmalloc( | ||
231 | ARRAY_SIZE(po1030_ctrls) * sizeof(s32), GFP_KERNEL); | ||
232 | if (!sensor_settings) | ||
233 | return -ENOMEM; | ||
234 | |||
235 | sd->gspca_dev.cam.cam_mode = po1030_modes; | ||
236 | sd->gspca_dev.cam.nmodes = ARRAY_SIZE(po1030_modes); | ||
237 | sd->desc->ctrls = po1030_ctrls; | ||
238 | sd->desc->nctrls = ARRAY_SIZE(po1030_ctrls); | ||
239 | |||
240 | for (i = 0; i < ARRAY_SIZE(po1030_ctrls); i++) | ||
241 | sensor_settings[i] = po1030_ctrls[i].qctrl.default_value; | ||
242 | sd->sensor_priv = sensor_settings; | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | int po1030_init(struct sd *sd) | ||
248 | { | ||
249 | s32 *sensor_settings = sd->sensor_priv; | ||
250 | int i, err = 0; | ||
251 | |||
252 | /* Init the sensor */ | ||
253 | for (i = 0; i < ARRAY_SIZE(init_po1030) && !err; i++) { | ||
254 | u8 data[2] = {0x00, 0x00}; | ||
255 | |||
256 | switch (init_po1030[i][0]) { | ||
257 | case BRIDGE: | ||
258 | err = m5602_write_bridge(sd, | ||
259 | init_po1030[i][1], | ||
260 | init_po1030[i][2]); | ||
261 | break; | ||
262 | |||
263 | case SENSOR: | ||
264 | data[0] = init_po1030[i][2]; | ||
265 | err = m5602_write_sensor(sd, | ||
266 | init_po1030[i][1], data, 1); | ||
267 | break; | ||
268 | |||
269 | default: | ||
270 | info("Invalid stream command, exiting init"); | ||
271 | return -EINVAL; | ||
272 | } | ||
273 | } | ||
274 | if (err < 0) | ||
275 | return err; | ||
276 | |||
277 | if (dump_sensor) | ||
278 | po1030_dump_registers(sd); | ||
279 | |||
280 | err = po1030_set_exposure(&sd->gspca_dev, | ||
281 | sensor_settings[EXPOSURE_IDX]); | ||
282 | if (err < 0) | ||
283 | return err; | ||
284 | |||
285 | err = po1030_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); | ||
286 | if (err < 0) | ||
287 | return err; | ||
288 | |||
289 | err = po1030_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); | ||
290 | if (err < 0) | ||
291 | return err; | ||
292 | |||
293 | err = po1030_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); | ||
294 | if (err < 0) | ||
295 | return err; | ||
296 | |||
297 | err = po1030_set_red_balance(&sd->gspca_dev, | ||
298 | sensor_settings[RED_BALANCE_IDX]); | ||
299 | if (err < 0) | ||
300 | return err; | ||
301 | |||
302 | err = po1030_set_blue_balance(&sd->gspca_dev, | ||
303 | sensor_settings[BLUE_BALANCE_IDX]); | ||
304 | if (err < 0) | ||
305 | return err; | ||
306 | |||
307 | err = po1030_set_green_balance(&sd->gspca_dev, | ||
308 | sensor_settings[GREEN_BALANCE_IDX]); | ||
309 | if (err < 0) | ||
310 | return err; | ||
311 | |||
312 | err = po1030_set_auto_white_balance(&sd->gspca_dev, | ||
313 | sensor_settings[AUTO_WHITE_BALANCE_IDX]); | ||
314 | if (err < 0) | ||
315 | return err; | ||
316 | |||
317 | err = po1030_set_auto_exposure(&sd->gspca_dev, | ||
318 | sensor_settings[AUTO_EXPOSURE_IDX]); | ||
319 | return err; | ||
320 | } | ||
321 | |||
322 | int po1030_start(struct sd *sd) | ||
323 | { | ||
324 | struct cam *cam = &sd->gspca_dev.cam; | ||
325 | int i, err = 0; | ||
326 | int width = cam->cam_mode[sd->gspca_dev.curr_mode].width; | ||
327 | int height = cam->cam_mode[sd->gspca_dev.curr_mode].height; | ||
328 | int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv; | ||
329 | u8 data; | ||
330 | |||
331 | switch (width) { | ||
332 | case 320: | ||
333 | data = PO1030_SUBSAMPLING; | ||
334 | err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1); | ||
335 | if (err < 0) | ||
336 | return err; | ||
337 | |||
338 | data = ((width + 3) >> 8) & 0xff; | ||
339 | err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1); | ||
340 | if (err < 0) | ||
341 | return err; | ||
342 | |||
343 | data = (width + 3) & 0xff; | ||
344 | err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1); | ||
345 | if (err < 0) | ||
346 | return err; | ||
347 | |||
348 | data = ((height + 1) >> 8) & 0xff; | ||
349 | err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1); | ||
350 | if (err < 0) | ||
351 | return err; | ||
352 | |||
353 | data = (height + 1) & 0xff; | ||
354 | err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1); | ||
355 | |||
356 | height += 6; | ||
357 | width -= 1; | ||
358 | break; | ||
359 | |||
360 | case 640: | ||
361 | data = 0; | ||
362 | err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1); | ||
363 | if (err < 0) | ||
364 | return err; | ||
365 | |||
366 | data = ((width + 7) >> 8) & 0xff; | ||
367 | err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1); | ||
368 | if (err < 0) | ||
369 | return err; | ||
370 | |||
371 | data = (width + 7) & 0xff; | ||
372 | err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1); | ||
373 | if (err < 0) | ||
374 | return err; | ||
375 | |||
376 | data = ((height + 3) >> 8) & 0xff; | ||
377 | err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1); | ||
378 | if (err < 0) | ||
379 | return err; | ||
380 | |||
381 | data = (height + 3) & 0xff; | ||
382 | err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1); | ||
383 | |||
384 | height += 12; | ||
385 | width -= 2; | ||
386 | break; | ||
387 | } | ||
388 | err = m5602_write_bridge(sd, M5602_XB_SENSOR_TYPE, 0x0c); | ||
389 | if (err < 0) | ||
390 | return err; | ||
391 | |||
392 | err = m5602_write_bridge(sd, M5602_XB_LINE_OF_FRAME_H, 0x81); | ||
393 | if (err < 0) | ||
394 | return err; | ||
395 | |||
396 | err = m5602_write_bridge(sd, M5602_XB_PIX_OF_LINE_H, 0x82); | ||
397 | if (err < 0) | ||
398 | return err; | ||
399 | |||
400 | err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0x01); | ||
401 | if (err < 0) | ||
402 | return err; | ||
403 | |||
404 | err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, | ||
405 | ((ver_offs >> 8) & 0xff)); | ||
406 | if (err < 0) | ||
407 | return err; | ||
408 | |||
409 | err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (ver_offs & 0xff)); | ||
410 | if (err < 0) | ||
411 | return err; | ||
412 | |||
413 | for (i = 0; i < 2 && !err; i++) | ||
414 | err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0); | ||
415 | if (err < 0) | ||
416 | return err; | ||
417 | |||
418 | err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff); | ||
419 | if (err < 0) | ||
420 | return err; | ||
421 | |||
422 | err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff)); | ||
423 | if (err < 0) | ||
424 | return err; | ||
425 | |||
426 | for (i = 0; i < 2 && !err; i++) | ||
427 | err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0); | ||
428 | |||
429 | for (i = 0; i < 2 && !err; i++) | ||
430 | err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); | ||
431 | |||
432 | for (i = 0; i < 2 && !err; i++) | ||
433 | err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0); | ||
434 | if (err < 0) | ||
435 | return err; | ||
436 | |||
437 | err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width >> 8) & 0xff); | ||
438 | if (err < 0) | ||
439 | return err; | ||
440 | |||
441 | err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width & 0xff)); | ||
442 | if (err < 0) | ||
443 | return err; | ||
444 | |||
445 | err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); | ||
446 | return err; | ||
447 | } | ||
448 | |||
449 | static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) | ||
450 | { | ||
451 | struct sd *sd = (struct sd *) gspca_dev; | ||
452 | s32 *sensor_settings = sd->sensor_priv; | ||
453 | |||
454 | *val = sensor_settings[EXPOSURE_IDX]; | ||
455 | PDEBUG(D_V4L2, "Exposure read as %d", *val); | ||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val) | ||
460 | { | ||
461 | struct sd *sd = (struct sd *) gspca_dev; | ||
462 | s32 *sensor_settings = sd->sensor_priv; | ||
463 | u8 i2c_data; | ||
464 | int err; | ||
465 | |||
466 | sensor_settings[EXPOSURE_IDX] = val; | ||
467 | PDEBUG(D_V4L2, "Set exposure to %d", val & 0xffff); | ||
468 | |||
469 | i2c_data = ((val & 0xff00) >> 8); | ||
470 | PDEBUG(D_V4L2, "Set exposure to high byte to 0x%x", | ||
471 | i2c_data); | ||
472 | |||
473 | err = m5602_write_sensor(sd, PO1030_INTEGLINES_H, | ||
474 | &i2c_data, 1); | ||
475 | if (err < 0) | ||
476 | return err; | ||
477 | |||
478 | i2c_data = (val & 0xff); | ||
479 | PDEBUG(D_V4L2, "Set exposure to low byte to 0x%x", | ||
480 | i2c_data); | ||
481 | err = m5602_write_sensor(sd, PO1030_INTEGLINES_M, | ||
482 | &i2c_data, 1); | ||
483 | |||
484 | return err; | ||
485 | } | ||
486 | |||
487 | static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val) | ||
488 | { | ||
489 | struct sd *sd = (struct sd *) gspca_dev; | ||
490 | s32 *sensor_settings = sd->sensor_priv; | ||
491 | |||
492 | *val = sensor_settings[GAIN_IDX]; | ||
493 | PDEBUG(D_V4L2, "Read global gain %d", *val); | ||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val) | ||
498 | { | ||
499 | struct sd *sd = (struct sd *) gspca_dev; | ||
500 | s32 *sensor_settings = sd->sensor_priv; | ||
501 | u8 i2c_data; | ||
502 | int err; | ||
503 | |||
504 | sensor_settings[GAIN_IDX] = val; | ||
505 | |||
506 | i2c_data = val & 0xff; | ||
507 | PDEBUG(D_V4L2, "Set global gain to %d", i2c_data); | ||
508 | err = m5602_write_sensor(sd, PO1030_GLOBALGAIN, | ||
509 | &i2c_data, 1); | ||
510 | return err; | ||
511 | } | ||
512 | |||
513 | static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) | ||
514 | { | ||
515 | struct sd *sd = (struct sd *) gspca_dev; | ||
516 | s32 *sensor_settings = sd->sensor_priv; | ||
517 | |||
518 | *val = sensor_settings[HFLIP_IDX]; | ||
519 | PDEBUG(D_V4L2, "Read hflip %d", *val); | ||
520 | |||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val) | ||
525 | { | ||
526 | struct sd *sd = (struct sd *) gspca_dev; | ||
527 | s32 *sensor_settings = sd->sensor_priv; | ||
528 | u8 i2c_data; | ||
529 | int err; | ||
530 | |||
531 | sensor_settings[HFLIP_IDX] = val; | ||
532 | |||
533 | PDEBUG(D_V4L2, "Set hflip %d", val); | ||
534 | err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1); | ||
535 | if (err < 0) | ||
536 | return err; | ||
537 | |||
538 | i2c_data = (0x7f & i2c_data) | ((val & 0x01) << 7); | ||
539 | |||
540 | err = m5602_write_sensor(sd, PO1030_CONTROL2, | ||
541 | &i2c_data, 1); | ||
542 | |||
543 | return err; | ||
544 | } | ||
545 | |||
546 | static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) | ||
547 | { | ||
548 | struct sd *sd = (struct sd *) gspca_dev; | ||
549 | s32 *sensor_settings = sd->sensor_priv; | ||
550 | |||
551 | *val = sensor_settings[VFLIP_IDX]; | ||
552 | PDEBUG(D_V4L2, "Read vflip %d", *val); | ||
553 | |||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val) | ||
558 | { | ||
559 | struct sd *sd = (struct sd *) gspca_dev; | ||
560 | s32 *sensor_settings = sd->sensor_priv; | ||
561 | u8 i2c_data; | ||
562 | int err; | ||
563 | |||
564 | sensor_settings[VFLIP_IDX] = val; | ||
565 | |||
566 | PDEBUG(D_V4L2, "Set vflip %d", val); | ||
567 | err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1); | ||
568 | if (err < 0) | ||
569 | return err; | ||
570 | |||
571 | i2c_data = (i2c_data & 0xbf) | ((val & 0x01) << 6); | ||
572 | |||
573 | err = m5602_write_sensor(sd, PO1030_CONTROL2, | ||
574 | &i2c_data, 1); | ||
575 | |||
576 | return err; | ||
577 | } | ||
578 | |||
579 | static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) | ||
580 | { | ||
581 | struct sd *sd = (struct sd *) gspca_dev; | ||
582 | s32 *sensor_settings = sd->sensor_priv; | ||
583 | |||
584 | *val = sensor_settings[RED_BALANCE_IDX]; | ||
585 | PDEBUG(D_V4L2, "Read red gain %d", *val); | ||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) | ||
590 | { | ||
591 | struct sd *sd = (struct sd *) gspca_dev; | ||
592 | s32 *sensor_settings = sd->sensor_priv; | ||
593 | u8 i2c_data; | ||
594 | int err; | ||
595 | |||
596 | sensor_settings[RED_BALANCE_IDX] = val; | ||
597 | |||
598 | i2c_data = val & 0xff; | ||
599 | PDEBUG(D_V4L2, "Set red gain to %d", i2c_data); | ||
600 | err = m5602_write_sensor(sd, PO1030_RED_GAIN, | ||
601 | &i2c_data, 1); | ||
602 | return err; | ||
603 | } | ||
604 | |||
605 | static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) | ||
606 | { | ||
607 | struct sd *sd = (struct sd *) gspca_dev; | ||
608 | s32 *sensor_settings = sd->sensor_priv; | ||
609 | |||
610 | *val = sensor_settings[BLUE_BALANCE_IDX]; | ||
611 | PDEBUG(D_V4L2, "Read blue gain %d", *val); | ||
612 | |||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) | ||
617 | { | ||
618 | struct sd *sd = (struct sd *) gspca_dev; | ||
619 | s32 *sensor_settings = sd->sensor_priv; | ||
620 | u8 i2c_data; | ||
621 | int err; | ||
622 | |||
623 | sensor_settings[BLUE_BALANCE_IDX] = val; | ||
624 | |||
625 | i2c_data = val & 0xff; | ||
626 | PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data); | ||
627 | err = m5602_write_sensor(sd, PO1030_BLUE_GAIN, | ||
628 | &i2c_data, 1); | ||
629 | |||
630 | return err; | ||
631 | } | ||
632 | |||
633 | static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val) | ||
634 | { | ||
635 | struct sd *sd = (struct sd *) gspca_dev; | ||
636 | s32 *sensor_settings = sd->sensor_priv; | ||
637 | |||
638 | *val = sensor_settings[GREEN_BALANCE_IDX]; | ||
639 | PDEBUG(D_V4L2, "Read green gain %d", *val); | ||
640 | |||
641 | return 0; | ||
642 | } | ||
643 | |||
644 | static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val) | ||
645 | { | ||
646 | struct sd *sd = (struct sd *) gspca_dev; | ||
647 | s32 *sensor_settings = sd->sensor_priv; | ||
648 | u8 i2c_data; | ||
649 | int err; | ||
650 | |||
651 | sensor_settings[GREEN_BALANCE_IDX] = val; | ||
652 | i2c_data = val & 0xff; | ||
653 | PDEBUG(D_V4L2, "Set green gain to %d", i2c_data); | ||
654 | |||
655 | err = m5602_write_sensor(sd, PO1030_GREEN_1_GAIN, | ||
656 | &i2c_data, 1); | ||
657 | if (err < 0) | ||
658 | return err; | ||
659 | |||
660 | return m5602_write_sensor(sd, PO1030_GREEN_2_GAIN, | ||
661 | &i2c_data, 1); | ||
662 | } | ||
663 | |||
664 | static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev, | ||
665 | __s32 *val) | ||
666 | { | ||
667 | struct sd *sd = (struct sd *) gspca_dev; | ||
668 | s32 *sensor_settings = sd->sensor_priv; | ||
669 | |||
670 | *val = sensor_settings[AUTO_WHITE_BALANCE_IDX]; | ||
671 | PDEBUG(D_V4L2, "Auto white balancing is %d", *val); | ||
672 | |||
673 | return 0; | ||
674 | } | ||
675 | |||
676 | static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev, | ||
677 | __s32 val) | ||
678 | { | ||
679 | struct sd *sd = (struct sd *) gspca_dev; | ||
680 | s32 *sensor_settings = sd->sensor_priv; | ||
681 | u8 i2c_data; | ||
682 | int err; | ||
683 | |||
684 | sensor_settings[AUTO_WHITE_BALANCE_IDX] = val; | ||
685 | |||
686 | err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); | ||
687 | if (err < 0) | ||
688 | return err; | ||
689 | |||
690 | PDEBUG(D_V4L2, "Set auto white balance to %d", val); | ||
691 | i2c_data = (i2c_data & 0xfe) | (val & 0x01); | ||
692 | err = m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); | ||
693 | return err; | ||
694 | } | ||
695 | |||
696 | static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev, | ||
697 | __s32 *val) | ||
698 | { | ||
699 | struct sd *sd = (struct sd *) gspca_dev; | ||
700 | s32 *sensor_settings = sd->sensor_priv; | ||
701 | |||
702 | *val = sensor_settings[AUTO_EXPOSURE_IDX]; | ||
703 | PDEBUG(D_V4L2, "Auto exposure is %d", *val); | ||
704 | return 0; | ||
705 | } | ||
706 | |||
707 | static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev, | ||
708 | __s32 val) | ||
709 | { | ||
710 | struct sd *sd = (struct sd *) gspca_dev; | ||
711 | s32 *sensor_settings = sd->sensor_priv; | ||
712 | u8 i2c_data; | ||
713 | int err; | ||
714 | |||
715 | sensor_settings[AUTO_EXPOSURE_IDX] = val; | ||
716 | err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); | ||
717 | if (err < 0) | ||
718 | return err; | ||
719 | |||
720 | PDEBUG(D_V4L2, "Set auto exposure to %d", val); | ||
721 | i2c_data = (i2c_data & 0xfd) | ((val & 0x01) << 1); | ||
722 | return m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); | ||
723 | } | ||
724 | |||
725 | void po1030_disconnect(struct sd *sd) | ||
726 | { | ||
727 | sd->sensor = NULL; | ||
728 | kfree(sd->sensor_priv); | ||
729 | } | ||
730 | |||
731 | static void po1030_dump_registers(struct sd *sd) | ||
732 | { | ||
733 | int address; | ||
734 | u8 value = 0; | ||
735 | |||
736 | info("Dumping the po1030 sensor core registers"); | ||
737 | for (address = 0; address < 0x7f; address++) { | ||
738 | m5602_read_sensor(sd, address, &value, 1); | ||
739 | info("register 0x%x contains 0x%x", | ||
740 | address, value); | ||
741 | } | ||
742 | |||
743 | info("po1030 register state dump complete"); | ||
744 | |||
745 | info("Probing for which registers that are read/write"); | ||
746 | for (address = 0; address < 0xff; address++) { | ||
747 | u8 old_value, ctrl_value; | ||
748 | u8 test_value[2] = {0xff, 0xff}; | ||
749 | |||
750 | m5602_read_sensor(sd, address, &old_value, 1); | ||
751 | m5602_write_sensor(sd, address, test_value, 1); | ||
752 | m5602_read_sensor(sd, address, &ctrl_value, 1); | ||
753 | |||
754 | if (ctrl_value == test_value[0]) | ||
755 | info("register 0x%x is writeable", address); | ||
756 | else | ||
757 | info("register 0x%x is read only", address); | ||
758 | |||
759 | /* Restore original value */ | ||
760 | m5602_write_sensor(sd, address, &old_value, 1); | ||
761 | } | ||
762 | } | ||