diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2011-09-12 08:52:01 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-11-03 16:28:50 -0400 |
commit | afd9690c72c3acf77b7f8731b2fcafafd3b7e29e (patch) | |
tree | c8ea648010d2c4d2be4aaa2f5543afca71f0385c | |
parent | f026671d2bbbe8b25906bd266a1164a73fdeaa7f (diff) |
[media] ov6650: convert to the control framework
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
[g.liakhovetski@gmx.de: simplified pointer arithmetic]
[jkrzyszt@tis.icnet.pl: fix a typo in the register name]
Acked-by: Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/video/ov6650.c | 381 |
1 files changed, 115 insertions, 266 deletions
diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c index 654b2f591ae..efa45132c99 100644 --- a/drivers/media/video/ov6650.c +++ b/drivers/media/video/ov6650.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <media/soc_camera.h> | 32 | #include <media/soc_camera.h> |
33 | #include <media/soc_mediabus.h> | 33 | #include <media/soc_mediabus.h> |
34 | #include <media/v4l2-chip-ident.h> | 34 | #include <media/v4l2-chip-ident.h> |
35 | #include <media/v4l2-ctrls.h> | ||
35 | 36 | ||
36 | /* Register definitions */ | 37 | /* Register definitions */ |
37 | #define REG_GAIN 0x00 /* range 00 - 3F */ | 38 | #define REG_GAIN 0x00 /* range 00 - 3F */ |
@@ -177,20 +178,23 @@ struct ov6650_reg { | |||
177 | 178 | ||
178 | struct ov6650 { | 179 | struct ov6650 { |
179 | struct v4l2_subdev subdev; | 180 | struct v4l2_subdev subdev; |
180 | 181 | struct v4l2_ctrl_handler hdl; | |
181 | int gain; | 182 | struct { |
182 | int blue; | 183 | /* exposure/autoexposure cluster */ |
183 | int red; | 184 | struct v4l2_ctrl *autoexposure; |
184 | int saturation; | 185 | struct v4l2_ctrl *exposure; |
185 | int hue; | 186 | }; |
186 | int brightness; | 187 | struct { |
187 | int exposure; | 188 | /* gain/autogain cluster */ |
188 | int gamma; | 189 | struct v4l2_ctrl *autogain; |
189 | int aec; | 190 | struct v4l2_ctrl *gain; |
190 | bool vflip; | 191 | }; |
191 | bool hflip; | 192 | struct { |
192 | bool awb; | 193 | /* blue/red/autowhitebalance cluster */ |
193 | bool agc; | 194 | struct v4l2_ctrl *autowb; |
195 | struct v4l2_ctrl *blue; | ||
196 | struct v4l2_ctrl *red; | ||
197 | }; | ||
194 | bool half_scale; /* scale down output by 2 */ | 198 | bool half_scale; /* scale down output by 2 */ |
195 | struct v4l2_rect rect; /* sensor cropping window */ | 199 | struct v4l2_rect rect; /* sensor cropping window */ |
196 | unsigned long pclk_limit; /* from host */ | 200 | unsigned long pclk_limit; /* from host */ |
@@ -210,126 +214,6 @@ static enum v4l2_mbus_pixelcode ov6650_codes[] = { | |||
210 | V4L2_MBUS_FMT_Y8_1X8, | 214 | V4L2_MBUS_FMT_Y8_1X8, |
211 | }; | 215 | }; |
212 | 216 | ||
213 | static const struct v4l2_queryctrl ov6650_controls[] = { | ||
214 | { | ||
215 | .id = V4L2_CID_AUTOGAIN, | ||
216 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
217 | .name = "AGC", | ||
218 | .minimum = 0, | ||
219 | .maximum = 1, | ||
220 | .step = 1, | ||
221 | .default_value = 1, | ||
222 | }, | ||
223 | { | ||
224 | .id = V4L2_CID_GAIN, | ||
225 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
226 | .name = "Gain", | ||
227 | .minimum = 0, | ||
228 | .maximum = 0x3f, | ||
229 | .step = 1, | ||
230 | .default_value = DEF_GAIN, | ||
231 | }, | ||
232 | { | ||
233 | .id = V4L2_CID_AUTO_WHITE_BALANCE, | ||
234 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
235 | .name = "AWB", | ||
236 | .minimum = 0, | ||
237 | .maximum = 1, | ||
238 | .step = 1, | ||
239 | .default_value = 1, | ||
240 | }, | ||
241 | { | ||
242 | .id = V4L2_CID_BLUE_BALANCE, | ||
243 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
244 | .name = "Blue", | ||
245 | .minimum = 0, | ||
246 | .maximum = 0xff, | ||
247 | .step = 1, | ||
248 | .default_value = DEF_BLUE, | ||
249 | }, | ||
250 | { | ||
251 | .id = V4L2_CID_RED_BALANCE, | ||
252 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
253 | .name = "Red", | ||
254 | .minimum = 0, | ||
255 | .maximum = 0xff, | ||
256 | .step = 1, | ||
257 | .default_value = DEF_RED, | ||
258 | }, | ||
259 | { | ||
260 | .id = V4L2_CID_SATURATION, | ||
261 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
262 | .name = "Saturation", | ||
263 | .minimum = 0, | ||
264 | .maximum = 0xf, | ||
265 | .step = 1, | ||
266 | .default_value = 0x8, | ||
267 | }, | ||
268 | { | ||
269 | .id = V4L2_CID_HUE, | ||
270 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
271 | .name = "Hue", | ||
272 | .minimum = 0, | ||
273 | .maximum = HUE_MASK, | ||
274 | .step = 1, | ||
275 | .default_value = DEF_HUE, | ||
276 | }, | ||
277 | { | ||
278 | .id = V4L2_CID_BRIGHTNESS, | ||
279 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
280 | .name = "Brightness", | ||
281 | .minimum = 0, | ||
282 | .maximum = 0xff, | ||
283 | .step = 1, | ||
284 | .default_value = 0x80, | ||
285 | }, | ||
286 | { | ||
287 | .id = V4L2_CID_EXPOSURE_AUTO, | ||
288 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
289 | .name = "AEC", | ||
290 | .minimum = 0, | ||
291 | .maximum = 3, | ||
292 | .step = 1, | ||
293 | .default_value = 0, | ||
294 | }, | ||
295 | { | ||
296 | .id = V4L2_CID_EXPOSURE, | ||
297 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
298 | .name = "Exposure", | ||
299 | .minimum = 0, | ||
300 | .maximum = 0xff, | ||
301 | .step = 1, | ||
302 | .default_value = DEF_AECH, | ||
303 | }, | ||
304 | { | ||
305 | .id = V4L2_CID_GAMMA, | ||
306 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
307 | .name = "Gamma", | ||
308 | .minimum = 0, | ||
309 | .maximum = 0xff, | ||
310 | .step = 1, | ||
311 | .default_value = 0x12, | ||
312 | }, | ||
313 | { | ||
314 | .id = V4L2_CID_VFLIP, | ||
315 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
316 | .name = "Flip Vertically", | ||
317 | .minimum = 0, | ||
318 | .maximum = 1, | ||
319 | .step = 1, | ||
320 | .default_value = 0, | ||
321 | }, | ||
322 | { | ||
323 | .id = V4L2_CID_HFLIP, | ||
324 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
325 | .name = "Flip Horizontally", | ||
326 | .minimum = 0, | ||
327 | .maximum = 1, | ||
328 | .step = 1, | ||
329 | .default_value = 0, | ||
330 | }, | ||
331 | }; | ||
332 | |||
333 | /* read a register */ | 217 | /* read a register */ |
334 | static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val) | 218 | static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val) |
335 | { | 219 | { |
@@ -420,166 +304,91 @@ static int ov6650_s_stream(struct v4l2_subdev *sd, int enable) | |||
420 | } | 304 | } |
421 | 305 | ||
422 | /* Get status of additional camera capabilities */ | 306 | /* Get status of additional camera capabilities */ |
423 | static int ov6650_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 307 | static int ov6550_g_volatile_ctrl(struct v4l2_ctrl *ctrl) |
424 | { | 308 | { |
309 | struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl); | ||
310 | struct v4l2_subdev *sd = &priv->subdev; | ||
425 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 311 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
426 | struct ov6650 *priv = to_ov6650(client); | 312 | uint8_t reg, reg2; |
427 | uint8_t reg; | ||
428 | int ret = 0; | 313 | int ret = 0; |
429 | 314 | ||
430 | switch (ctrl->id) { | 315 | switch (ctrl->id) { |
431 | case V4L2_CID_AUTOGAIN: | 316 | case V4L2_CID_AUTOGAIN: |
432 | ctrl->value = priv->agc; | 317 | ret = ov6650_reg_read(client, REG_GAIN, ®); |
433 | break; | 318 | if (!ret) |
434 | case V4L2_CID_GAIN: | 319 | priv->gain->val = reg; |
435 | if (priv->agc) { | 320 | return ret; |
436 | ret = ov6650_reg_read(client, REG_GAIN, ®); | ||
437 | ctrl->value = reg; | ||
438 | } else { | ||
439 | ctrl->value = priv->gain; | ||
440 | } | ||
441 | break; | ||
442 | case V4L2_CID_AUTO_WHITE_BALANCE: | 321 | case V4L2_CID_AUTO_WHITE_BALANCE: |
443 | ctrl->value = priv->awb; | 322 | ret = ov6650_reg_read(client, REG_BLUE, ®); |
444 | break; | 323 | if (!ret) |
445 | case V4L2_CID_BLUE_BALANCE: | 324 | ret = ov6650_reg_read(client, REG_RED, ®2); |
446 | if (priv->awb) { | 325 | if (!ret) { |
447 | ret = ov6650_reg_read(client, REG_BLUE, ®); | 326 | priv->blue->val = reg; |
448 | ctrl->value = reg; | 327 | priv->red->val = reg2; |
449 | } else { | ||
450 | ctrl->value = priv->blue; | ||
451 | } | ||
452 | break; | ||
453 | case V4L2_CID_RED_BALANCE: | ||
454 | if (priv->awb) { | ||
455 | ret = ov6650_reg_read(client, REG_RED, ®); | ||
456 | ctrl->value = reg; | ||
457 | } else { | ||
458 | ctrl->value = priv->red; | ||
459 | } | 328 | } |
460 | break; | 329 | return ret; |
461 | case V4L2_CID_SATURATION: | ||
462 | ctrl->value = priv->saturation; | ||
463 | break; | ||
464 | case V4L2_CID_HUE: | ||
465 | ctrl->value = priv->hue; | ||
466 | break; | ||
467 | case V4L2_CID_BRIGHTNESS: | ||
468 | ctrl->value = priv->brightness; | ||
469 | break; | ||
470 | case V4L2_CID_EXPOSURE_AUTO: | 330 | case V4L2_CID_EXPOSURE_AUTO: |
471 | ctrl->value = priv->aec; | 331 | ret = ov6650_reg_read(client, REG_AECH, ®); |
472 | break; | 332 | if (!ret) |
473 | case V4L2_CID_EXPOSURE: | 333 | priv->exposure->val = reg; |
474 | if (priv->aec) { | 334 | return ret; |
475 | ret = ov6650_reg_read(client, REG_AECH, ®); | ||
476 | ctrl->value = reg; | ||
477 | } else { | ||
478 | ctrl->value = priv->exposure; | ||
479 | } | ||
480 | break; | ||
481 | case V4L2_CID_GAMMA: | ||
482 | ctrl->value = priv->gamma; | ||
483 | break; | ||
484 | case V4L2_CID_VFLIP: | ||
485 | ctrl->value = priv->vflip; | ||
486 | break; | ||
487 | case V4L2_CID_HFLIP: | ||
488 | ctrl->value = priv->hflip; | ||
489 | break; | ||
490 | } | 335 | } |
491 | return ret; | 336 | return -EINVAL; |
492 | } | 337 | } |
493 | 338 | ||
494 | /* Set status of additional camera capabilities */ | 339 | /* Set status of additional camera capabilities */ |
495 | static int ov6650_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 340 | static int ov6550_s_ctrl(struct v4l2_ctrl *ctrl) |
496 | { | 341 | { |
342 | struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl); | ||
343 | struct v4l2_subdev *sd = &priv->subdev; | ||
497 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 344 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
498 | struct ov6650 *priv = to_ov6650(client); | ||
499 | int ret = 0; | 345 | int ret = 0; |
500 | 346 | ||
501 | switch (ctrl->id) { | 347 | switch (ctrl->id) { |
502 | case V4L2_CID_AUTOGAIN: | 348 | case V4L2_CID_AUTOGAIN: |
503 | ret = ov6650_reg_rmw(client, REG_COMB, | 349 | ret = ov6650_reg_rmw(client, REG_COMB, |
504 | ctrl->value ? COMB_AGC : 0, COMB_AGC); | 350 | ctrl->val ? COMB_AGC : 0, COMB_AGC); |
505 | if (!ret) | 351 | if (!ret && !ctrl->val) |
506 | priv->agc = ctrl->value; | 352 | ret = ov6650_reg_write(client, REG_GAIN, priv->gain->val); |
507 | break; | 353 | return ret; |
508 | case V4L2_CID_GAIN: | ||
509 | ret = ov6650_reg_write(client, REG_GAIN, ctrl->value); | ||
510 | if (!ret) | ||
511 | priv->gain = ctrl->value; | ||
512 | break; | ||
513 | case V4L2_CID_AUTO_WHITE_BALANCE: | 354 | case V4L2_CID_AUTO_WHITE_BALANCE: |
514 | ret = ov6650_reg_rmw(client, REG_COMB, | 355 | ret = ov6650_reg_rmw(client, REG_COMB, |
515 | ctrl->value ? COMB_AWB : 0, COMB_AWB); | 356 | ctrl->val ? COMB_AWB : 0, COMB_AWB); |
516 | if (!ret) | 357 | if (!ret && !ctrl->val) { |
517 | priv->awb = ctrl->value; | 358 | ret = ov6650_reg_write(client, REG_BLUE, priv->blue->val); |
518 | break; | 359 | if (!ret) |
519 | case V4L2_CID_BLUE_BALANCE: | 360 | ret = ov6650_reg_write(client, REG_RED, |
520 | ret = ov6650_reg_write(client, REG_BLUE, ctrl->value); | 361 | priv->red->val); |
521 | if (!ret) | 362 | } |
522 | priv->blue = ctrl->value; | 363 | return ret; |
523 | break; | ||
524 | case V4L2_CID_RED_BALANCE: | ||
525 | ret = ov6650_reg_write(client, REG_RED, ctrl->value); | ||
526 | if (!ret) | ||
527 | priv->red = ctrl->value; | ||
528 | break; | ||
529 | case V4L2_CID_SATURATION: | 364 | case V4L2_CID_SATURATION: |
530 | ret = ov6650_reg_rmw(client, REG_SAT, SET_SAT(ctrl->value), | 365 | return ov6650_reg_rmw(client, REG_SAT, SET_SAT(ctrl->val), |
531 | SAT_MASK); | 366 | SAT_MASK); |
532 | if (!ret) | ||
533 | priv->saturation = ctrl->value; | ||
534 | break; | ||
535 | case V4L2_CID_HUE: | 367 | case V4L2_CID_HUE: |
536 | ret = ov6650_reg_rmw(client, REG_HUE, SET_HUE(ctrl->value), | 368 | return ov6650_reg_rmw(client, REG_HUE, SET_HUE(ctrl->val), |
537 | HUE_MASK); | 369 | HUE_MASK); |
538 | if (!ret) | ||
539 | priv->hue = ctrl->value; | ||
540 | break; | ||
541 | case V4L2_CID_BRIGHTNESS: | 370 | case V4L2_CID_BRIGHTNESS: |
542 | ret = ov6650_reg_write(client, REG_BRT, ctrl->value); | 371 | return ov6650_reg_write(client, REG_BRT, ctrl->val); |
543 | if (!ret) | ||
544 | priv->brightness = ctrl->value; | ||
545 | break; | ||
546 | case V4L2_CID_EXPOSURE_AUTO: | 372 | case V4L2_CID_EXPOSURE_AUTO: |
547 | switch (ctrl->value) { | 373 | if (ctrl->val == V4L2_EXPOSURE_AUTO) |
548 | case V4L2_EXPOSURE_AUTO: | ||
549 | ret = ov6650_reg_rmw(client, REG_COMB, COMB_AEC, 0); | 374 | ret = ov6650_reg_rmw(client, REG_COMB, COMB_AEC, 0); |
550 | break; | 375 | else |
551 | default: | ||
552 | ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_AEC); | 376 | ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_AEC); |
553 | break; | 377 | if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) |
554 | } | 378 | ret = ov6650_reg_write(client, REG_AECH, |
555 | if (!ret) | 379 | priv->exposure->val); |
556 | priv->aec = ctrl->value; | 380 | return ret; |
557 | break; | ||
558 | case V4L2_CID_EXPOSURE: | ||
559 | ret = ov6650_reg_write(client, REG_AECH, ctrl->value); | ||
560 | if (!ret) | ||
561 | priv->exposure = ctrl->value; | ||
562 | break; | ||
563 | case V4L2_CID_GAMMA: | 381 | case V4L2_CID_GAMMA: |
564 | ret = ov6650_reg_write(client, REG_GAM1, ctrl->value); | 382 | return ov6650_reg_write(client, REG_GAM1, ctrl->val); |
565 | if (!ret) | ||
566 | priv->gamma = ctrl->value; | ||
567 | break; | ||
568 | case V4L2_CID_VFLIP: | 383 | case V4L2_CID_VFLIP: |
569 | ret = ov6650_reg_rmw(client, REG_COMB, | 384 | return ov6650_reg_rmw(client, REG_COMB, |
570 | ctrl->value ? COMB_FLIP_V : 0, COMB_FLIP_V); | 385 | ctrl->val ? COMB_FLIP_V : 0, COMB_FLIP_V); |
571 | if (!ret) | ||
572 | priv->vflip = ctrl->value; | ||
573 | break; | ||
574 | case V4L2_CID_HFLIP: | 386 | case V4L2_CID_HFLIP: |
575 | ret = ov6650_reg_rmw(client, REG_COMB, | 387 | return ov6650_reg_rmw(client, REG_COMB, |
576 | ctrl->value ? COMB_FLIP_H : 0, COMB_FLIP_H); | 388 | ctrl->val ? COMB_FLIP_H : 0, COMB_FLIP_H); |
577 | if (!ret) | ||
578 | priv->hflip = ctrl->value; | ||
579 | break; | ||
580 | } | 389 | } |
581 | 390 | ||
582 | return ret; | 391 | return -EINVAL; |
583 | } | 392 | } |
584 | 393 | ||
585 | /* Get chip identification */ | 394 | /* Get chip identification */ |
@@ -1048,14 +857,12 @@ static int ov6650_video_probe(struct soc_camera_device *icd, | |||
1048 | return ret; | 857 | return ret; |
1049 | } | 858 | } |
1050 | 859 | ||
1051 | static struct soc_camera_ops ov6650_ops = { | 860 | static const struct v4l2_ctrl_ops ov6550_ctrl_ops = { |
1052 | .controls = ov6650_controls, | 861 | .g_volatile_ctrl = ov6550_g_volatile_ctrl, |
1053 | .num_controls = ARRAY_SIZE(ov6650_controls), | 862 | .s_ctrl = ov6550_s_ctrl, |
1054 | }; | 863 | }; |
1055 | 864 | ||
1056 | static struct v4l2_subdev_core_ops ov6650_core_ops = { | 865 | static struct v4l2_subdev_core_ops ov6650_core_ops = { |
1057 | .g_ctrl = ov6650_g_ctrl, | ||
1058 | .s_ctrl = ov6650_s_ctrl, | ||
1059 | .g_chip_ident = ov6650_g_chip_ident, | 866 | .g_chip_ident = ov6650_g_chip_ident, |
1060 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 867 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1061 | .g_register = ov6650_get_register, | 868 | .g_register = ov6650_get_register, |
@@ -1164,8 +971,46 @@ static int ov6650_probe(struct i2c_client *client, | |||
1164 | } | 971 | } |
1165 | 972 | ||
1166 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov6650_subdev_ops); | 973 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov6650_subdev_ops); |
974 | v4l2_ctrl_handler_init(&priv->hdl, 13); | ||
975 | v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
976 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
977 | v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
978 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
979 | priv->autogain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
980 | V4L2_CID_AUTOGAIN, 0, 1, 1, 1); | ||
981 | priv->gain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
982 | V4L2_CID_GAIN, 0, 0x3f, 1, DEF_GAIN); | ||
983 | priv->autowb = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
984 | V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); | ||
985 | priv->blue = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
986 | V4L2_CID_BLUE_BALANCE, 0, 0xff, 1, DEF_BLUE); | ||
987 | priv->red = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
988 | V4L2_CID_RED_BALANCE, 0, 0xff, 1, DEF_RED); | ||
989 | v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
990 | V4L2_CID_SATURATION, 0, 0xf, 1, 0x8); | ||
991 | v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
992 | V4L2_CID_HUE, 0, HUE_MASK, 1, DEF_HUE); | ||
993 | v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
994 | V4L2_CID_BRIGHTNESS, 0, 0xff, 1, 0x80); | ||
995 | priv->autoexposure = v4l2_ctrl_new_std_menu(&priv->hdl, | ||
996 | &ov6550_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, | ||
997 | V4L2_EXPOSURE_AUTO); | ||
998 | priv->exposure = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
999 | V4L2_CID_EXPOSURE, 0, 0xff, 1, DEF_AECH); | ||
1000 | v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
1001 | V4L2_CID_GAMMA, 0, 0xff, 1, 0x12); | ||
1002 | |||
1003 | priv->subdev.ctrl_handler = &priv->hdl; | ||
1004 | if (priv->hdl.error) { | ||
1005 | int err = priv->hdl.error; | ||
1167 | 1006 | ||
1168 | icd->ops = &ov6650_ops; | 1007 | kfree(priv); |
1008 | return err; | ||
1009 | } | ||
1010 | v4l2_ctrl_auto_cluster(2, &priv->autogain, 0, true); | ||
1011 | v4l2_ctrl_auto_cluster(3, &priv->autowb, 0, true); | ||
1012 | v4l2_ctrl_auto_cluster(2, &priv->autoexposure, | ||
1013 | V4L2_EXPOSURE_MANUAL, true); | ||
1169 | 1014 | ||
1170 | priv->rect.left = DEF_HSTRT << 1; | 1015 | priv->rect.left = DEF_HSTRT << 1; |
1171 | priv->rect.top = DEF_VSTRT << 1; | 1016 | priv->rect.top = DEF_VSTRT << 1; |
@@ -1176,9 +1021,11 @@ static int ov6650_probe(struct i2c_client *client, | |||
1176 | priv->colorspace = V4L2_COLORSPACE_JPEG; | 1021 | priv->colorspace = V4L2_COLORSPACE_JPEG; |
1177 | 1022 | ||
1178 | ret = ov6650_video_probe(icd, client); | 1023 | ret = ov6650_video_probe(icd, client); |
1024 | if (!ret) | ||
1025 | ret = v4l2_ctrl_handler_setup(&priv->hdl); | ||
1179 | 1026 | ||
1180 | if (ret) { | 1027 | if (ret) { |
1181 | icd->ops = NULL; | 1028 | v4l2_ctrl_handler_free(&priv->hdl); |
1182 | kfree(priv); | 1029 | kfree(priv); |
1183 | } | 1030 | } |
1184 | 1031 | ||
@@ -1189,6 +1036,8 @@ static int ov6650_remove(struct i2c_client *client) | |||
1189 | { | 1036 | { |
1190 | struct ov6650 *priv = to_ov6650(client); | 1037 | struct ov6650 *priv = to_ov6650(client); |
1191 | 1038 | ||
1039 | v4l2_device_unregister_subdev(&priv->subdev); | ||
1040 | v4l2_ctrl_handler_free(&priv->hdl); | ||
1192 | kfree(priv); | 1041 | kfree(priv); |
1193 | return 0; | 1042 | return 0; |
1194 | } | 1043 | } |