V4L/DVB (11526): gspca - m5602-mt9m111: Add red balance ctrl
[deliverable/linux.git] / drivers / media / video / gspca / m5602 / m5602_mt9m111.c
1 /*
2 * Driver for the mt9m111 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_mt9m111.h"
20
21 static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
22 static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
23 static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
24 static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
25 static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
26 static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val);
27 static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
28 __s32 val);
29 static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev,
30 __s32 *val);
31 static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val);
32 static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val);
33 static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
34 static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
35 static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
36 static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
37
38 static struct v4l2_pix_format mt9m111_modes[] = {
39 {
40 640,
41 480,
42 V4L2_PIX_FMT_SBGGR8,
43 V4L2_FIELD_NONE,
44 .sizeimage = 640 * 480,
45 .bytesperline = 640,
46 .colorspace = V4L2_COLORSPACE_SRGB,
47 .priv = 0
48 }
49 };
50
51 const static struct ctrl mt9m111_ctrls[] = {
52 #define VFLIP_IDX 0
53 {
54 {
55 .id = V4L2_CID_VFLIP,
56 .type = V4L2_CTRL_TYPE_BOOLEAN,
57 .name = "vertical flip",
58 .minimum = 0,
59 .maximum = 1,
60 .step = 1,
61 .default_value = 0
62 },
63 .set = mt9m111_set_vflip,
64 .get = mt9m111_get_vflip
65 },
66 #define HFLIP_IDX 1
67 {
68 {
69 .id = V4L2_CID_HFLIP,
70 .type = V4L2_CTRL_TYPE_BOOLEAN,
71 .name = "horizontal flip",
72 .minimum = 0,
73 .maximum = 1,
74 .step = 1,
75 .default_value = 0
76 },
77 .set = mt9m111_set_hflip,
78 .get = mt9m111_get_hflip
79 },
80 #define GAIN_IDX 2
81 {
82 {
83 .id = V4L2_CID_GAIN,
84 .type = V4L2_CTRL_TYPE_INTEGER,
85 .name = "gain",
86 .minimum = 0,
87 .maximum = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2,
88 .step = 1,
89 .default_value = DEFAULT_GAIN,
90 .flags = V4L2_CTRL_FLAG_SLIDER
91 },
92 .set = mt9m111_set_gain,
93 .get = mt9m111_get_gain
94 },
95 #define AUTO_WHITE_BALANCE_IDX 3
96 {
97 {
98 .id = V4L2_CID_AUTO_WHITE_BALANCE,
99 .type = V4L2_CTRL_TYPE_BOOLEAN,
100 .name = "auto white balance",
101 .minimum = 0,
102 .maximum = 1,
103 .step = 1,
104 .default_value = 0,
105 },
106 .set = mt9m111_set_auto_white_balance,
107 .get = mt9m111_get_auto_white_balance
108 },
109 #define GREEN_BALANCE_IDX 4
110 {
111 {
112 .id = M5602_V4L2_CID_GREEN_BALANCE,
113 .type = V4L2_CTRL_TYPE_INTEGER,
114 .name = "green balance",
115 .minimum = 0x00,
116 .maximum = 0x7ff,
117 .step = 0x1,
118 .default_value = MT9M111_GREEN_GAIN_DEFAULT,
119 .flags = V4L2_CTRL_FLAG_SLIDER
120 },
121 .set = mt9m111_set_green_balance,
122 .get = mt9m111_get_green_balance
123 },
124 #define BLUE_BALANCE_IDX 5
125 {
126 {
127 .id = V4L2_CID_BLUE_BALANCE,
128 .type = V4L2_CTRL_TYPE_INTEGER,
129 .name = "blue balance",
130 .minimum = 0x00,
131 .maximum = 0x7ff,
132 .step = 0x1,
133 .default_value = MT9M111_BLUE_GAIN_DEFAULT,
134 .flags = V4L2_CTRL_FLAG_SLIDER
135 },
136 .set = mt9m111_set_blue_balance,
137 .get = mt9m111_get_blue_balance
138 },
139 #define RED_BALANCE_IDX 5
140 {
141 {
142 .id = V4L2_CID_RED_BALANCE,
143 .type = V4L2_CTRL_TYPE_INTEGER,
144 .name = "red balance",
145 .minimum = 0x00,
146 .maximum = 0x7ff,
147 .step = 0x1,
148 .default_value = MT9M111_RED_GAIN_DEFAULT,
149 .flags = V4L2_CTRL_FLAG_SLIDER
150 },
151 .set = mt9m111_set_red_balance,
152 .get = mt9m111_get_red_balance
153 },
154 };
155
156 static void mt9m111_dump_registers(struct sd *sd);
157
158 int mt9m111_probe(struct sd *sd)
159 {
160 u8 data[2] = {0x00, 0x00};
161 int i;
162 s32 *sensor_settings;
163
164 if (force_sensor) {
165 if (force_sensor == MT9M111_SENSOR) {
166 info("Forcing a %s sensor", mt9m111.name);
167 goto sensor_found;
168 }
169 /* If we want to force another sensor, don't try to probe this
170 * one */
171 return -ENODEV;
172 }
173
174 info("Probing for a mt9m111 sensor");
175
176 /* Do the preinit */
177 for (i = 0; i < ARRAY_SIZE(preinit_mt9m111); i++) {
178 if (preinit_mt9m111[i][0] == BRIDGE) {
179 m5602_write_bridge(sd,
180 preinit_mt9m111[i][1],
181 preinit_mt9m111[i][2]);
182 } else {
183 data[0] = preinit_mt9m111[i][2];
184 data[1] = preinit_mt9m111[i][3];
185 m5602_write_sensor(sd,
186 preinit_mt9m111[i][1], data, 2);
187 }
188 }
189
190 if (m5602_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2))
191 return -ENODEV;
192
193 if ((data[0] == 0x14) && (data[1] == 0x3a)) {
194 info("Detected a mt9m111 sensor");
195 goto sensor_found;
196 }
197
198 return -ENODEV;
199
200 sensor_found:
201 sensor_settings = kmalloc(ARRAY_SIZE(mt9m111_ctrls) * sizeof(s32),
202 GFP_KERNEL);
203 if (!sensor_settings)
204 return -ENOMEM;
205
206 sd->gspca_dev.cam.cam_mode = mt9m111_modes;
207 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(mt9m111_modes);
208 sd->desc->ctrls = mt9m111_ctrls;
209 sd->desc->nctrls = ARRAY_SIZE(mt9m111_ctrls);
210
211 for (i = 0; i < ARRAY_SIZE(mt9m111_ctrls); i++)
212 sensor_settings[i] = mt9m111_ctrls[i].qctrl.default_value;
213 sd->sensor_priv = sensor_settings;
214
215 return 0;
216 }
217
218 int mt9m111_init(struct sd *sd)
219 {
220 int i, err = 0;
221 s32 *sensor_settings = sd->sensor_priv;
222
223 /* Init the sensor */
224 for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) {
225 u8 data[2];
226
227 if (init_mt9m111[i][0] == BRIDGE) {
228 err = m5602_write_bridge(sd,
229 init_mt9m111[i][1],
230 init_mt9m111[i][2]);
231 } else {
232 data[0] = init_mt9m111[i][2];
233 data[1] = init_mt9m111[i][3];
234 err = m5602_write_sensor(sd,
235 init_mt9m111[i][1], data, 2);
236 }
237 }
238
239 if (dump_sensor)
240 mt9m111_dump_registers(sd);
241
242 err = mt9m111_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
243 if (err < 0)
244 return err;
245
246 err = mt9m111_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
247 if (err < 0)
248 return err;
249
250 err = mt9m111_set_green_balance(&sd->gspca_dev,
251 sensor_settings[GREEN_BALANCE_IDX]);
252 if (err < 0)
253 return err;
254
255 err = mt9m111_set_blue_balance(&sd->gspca_dev,
256 sensor_settings[BLUE_BALANCE_IDX]);
257 if (err < 0)
258 return err;
259
260 err = mt9m111_set_red_balance(&sd->gspca_dev,
261 sensor_settings[RED_BALANCE_IDX]);
262 if (err < 0)
263 return err;
264
265 return mt9m111_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
266 }
267
268 void mt9m111_disconnect(struct sd *sd)
269 {
270 sd->sensor = NULL;
271 kfree(sd->sensor_priv);
272 }
273
274 static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
275 {
276 struct sd *sd = (struct sd *) gspca_dev;
277 s32 *sensor_settings = sd->sensor_priv;
278
279 *val = sensor_settings[VFLIP_IDX];
280 PDEBUG(D_V4L2, "Read vertical flip %d", *val);
281
282 return 0;
283 }
284
285 static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
286 {
287 int err;
288 u8 data[2] = {0x00, 0x00};
289 struct sd *sd = (struct sd *) gspca_dev;
290 s32 *sensor_settings = sd->sensor_priv;
291
292 PDEBUG(D_V4L2, "Set vertical flip to %d", val);
293
294 sensor_settings[VFLIP_IDX] = val;
295
296 /* Set the correct page map */
297 err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
298 if (err < 0)
299 return err;
300
301 err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
302 if (err < 0)
303 return err;
304
305 data[0] = (data[0] & 0xfe) | val;
306 err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
307 data, 2);
308 return err;
309 }
310
311 static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
312 {
313 struct sd *sd = (struct sd *) gspca_dev;
314 s32 *sensor_settings = sd->sensor_priv;
315
316 *val = sensor_settings[HFLIP_IDX];
317 PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
318
319 return 0;
320 }
321
322 static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
323 {
324 int err;
325 u8 data[2] = {0x00, 0x00};
326 struct sd *sd = (struct sd *) gspca_dev;
327 s32 *sensor_settings = sd->sensor_priv;
328
329 PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
330
331 sensor_settings[HFLIP_IDX] = val;
332 /* Set the correct page map */
333 err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
334 if (err < 0)
335 return err;
336
337 err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
338 if (err < 0)
339 return err;
340
341 data[0] = (data[0] & 0xfd) | ((val << 1) & 0x02);
342 err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
343 data, 2);
344 return err;
345 }
346
347 static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
348 {
349 struct sd *sd = (struct sd *) gspca_dev;
350 s32 *sensor_settings = sd->sensor_priv;
351
352 *val = sensor_settings[GAIN_IDX];
353 PDEBUG(D_V4L2, "Read gain %d", *val);
354
355 return 0;
356 }
357
358 static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
359 __s32 val)
360 {
361 struct sd *sd = (struct sd *) gspca_dev;
362 s32 *sensor_settings = sd->sensor_priv;
363 int err;
364 u8 data[2];
365
366 err = m5602_read_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2);
367 if (err < 0)
368 return err;
369
370 sensor_settings[AUTO_WHITE_BALANCE_IDX] = val & 0x01;
371 data[0] = ((data[0] & 0xfd) | ((val & 0x01) << 1));
372
373 err = m5602_write_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2);
374
375 PDEBUG(D_V4L2, "Set auto white balance %d", val);
376 return err;
377 }
378
379 static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev,
380 __s32 *val) {
381 struct sd *sd = (struct sd *) gspca_dev;
382 s32 *sensor_settings = sd->sensor_priv;
383
384 *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
385 PDEBUG(D_V4L2, "Read auto white balance %d", *val);
386 return 0;
387 }
388
389 static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
390 {
391 int err, tmp;
392 u8 data[2] = {0x00, 0x00};
393 struct sd *sd = (struct sd *) gspca_dev;
394 s32 *sensor_settings = sd->sensor_priv;
395
396 sensor_settings[GAIN_IDX] = val;
397
398 /* Set the correct page map */
399 err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
400 if (err < 0)
401 return err;
402
403 if (val >= INITIAL_MAX_GAIN * 2 * 2 * 2)
404 return -EINVAL;
405
406 if ((val >= INITIAL_MAX_GAIN * 2 * 2) &&
407 (val < (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2))
408 tmp = (1 << 10) | (val << 9) |
409 (val << 8) | (val / 8);
410 else if ((val >= INITIAL_MAX_GAIN * 2) &&
411 (val < INITIAL_MAX_GAIN * 2 * 2))
412 tmp = (1 << 9) | (1 << 8) | (val / 4);
413 else if ((val >= INITIAL_MAX_GAIN) &&
414 (val < INITIAL_MAX_GAIN * 2))
415 tmp = (1 << 8) | (val / 2);
416 else
417 tmp = val;
418
419 data[1] = (tmp & 0xff00) >> 8;
420 data[0] = (tmp & 0xff);
421 PDEBUG(D_V4L2, "tmp=%d, data[1]=%d, data[0]=%d", tmp,
422 data[1], data[0]);
423
424 err = m5602_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN,
425 data, 2);
426
427 return err;
428 }
429
430 static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
431 {
432 int err;
433 u8 data[2];
434 struct sd *sd = (struct sd *) gspca_dev;
435 s32 *sensor_settings = sd->sensor_priv;
436
437 sensor_settings[GREEN_BALANCE_IDX] = val;
438 data[0] = (val & 0xff);
439 data[1] = (val & 0xff00) >> 8;
440
441 PDEBUG(D_V4L2, "Set green balance %d", val);
442 err = m5602_write_sensor(sd, MT9M111_SC_GREEN_1_GAIN,
443 data, 2);
444 if (err < 0)
445 return err;
446
447 return m5602_write_sensor(sd, MT9M111_SC_GREEN_2_GAIN,
448 data, 2);
449 }
450
451 static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val)
452 {
453 struct sd *sd = (struct sd *) gspca_dev;
454 s32 *sensor_settings = sd->sensor_priv;
455
456 *val = sensor_settings[GREEN_BALANCE_IDX];
457 PDEBUG(D_V4L2, "Read green balance %d", *val);
458 return 0;
459 }
460
461 static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
462 {
463 u8 data[2];
464 struct sd *sd = (struct sd *) gspca_dev;
465 s32 *sensor_settings = sd->sensor_priv;
466
467 sensor_settings[BLUE_BALANCE_IDX] = val;
468 data[0] = (val & 0xff);
469 data[1] = (val & 0xff00) >> 8;
470
471 PDEBUG(D_V4L2, "Set blue balance %d", val);
472
473 return m5602_write_sensor(sd, MT9M111_SC_BLUE_GAIN,
474 data, 2);
475 }
476
477 static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
478 {
479 struct sd *sd = (struct sd *) gspca_dev;
480 s32 *sensor_settings = sd->sensor_priv;
481
482 *val = sensor_settings[BLUE_BALANCE_IDX];
483 PDEBUG(D_V4L2, "Read blue balance %d", *val);
484 return 0;
485 }
486
487 static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
488 {
489 u8 data[2];
490 struct sd *sd = (struct sd *) gspca_dev;
491 s32 *sensor_settings = sd->sensor_priv;
492
493 sensor_settings[RED_BALANCE_IDX] = val;
494 data[0] = (val & 0xff);
495 data[1] = (val & 0xff00) >> 8;
496
497 PDEBUG(D_V4L2, "Set red balance %d", val);
498
499 return m5602_write_sensor(sd, MT9M111_SC_RED_GAIN,
500 data, 2);
501 }
502
503 static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
504 {
505 struct sd *sd = (struct sd *) gspca_dev;
506 s32 *sensor_settings = sd->sensor_priv;
507
508 *val = sensor_settings[RED_BALANCE_IDX];
509 PDEBUG(D_V4L2, "Read red balance %d", *val);
510 return 0;
511 }
512
513 static void mt9m111_dump_registers(struct sd *sd)
514 {
515 u8 address, value[2] = {0x00, 0x00};
516
517 info("Dumping the mt9m111 register state");
518
519 info("Dumping the mt9m111 sensor core registers");
520 value[1] = MT9M111_SENSOR_CORE;
521 m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
522 for (address = 0; address < 0xff; address++) {
523 m5602_read_sensor(sd, address, value, 2);
524 info("register 0x%x contains 0x%x%x",
525 address, value[0], value[1]);
526 }
527
528 info("Dumping the mt9m111 color pipeline registers");
529 value[1] = MT9M111_COLORPIPE;
530 m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
531 for (address = 0; address < 0xff; address++) {
532 m5602_read_sensor(sd, address, value, 2);
533 info("register 0x%x contains 0x%x%x",
534 address, value[0], value[1]);
535 }
536
537 info("Dumping the mt9m111 camera control registers");
538 value[1] = MT9M111_CAMERA_CONTROL;
539 m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
540 for (address = 0; address < 0xff; address++) {
541 m5602_read_sensor(sd, address, value, 2);
542 info("register 0x%x contains 0x%x%x",
543 address, value[0], value[1]);
544 }
545
546 info("mt9m111 register state dump complete");
547 }
This page took 0.069137 seconds and 5 git commands to generate.