aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/ov6650.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/ov6650.c')
-rw-r--r--drivers/media/video/ov6650.c504
1 files changed, 173 insertions, 331 deletions
diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c
index 456d9ad9ae5a..d5b057207a7b 100644
--- a/drivers/media/video/ov6650.c
+++ b/drivers/media/video/ov6650.c
@@ -28,10 +28,11 @@
28#include <linux/delay.h> 28#include <linux/delay.h>
29#include <linux/i2c.h> 29#include <linux/i2c.h>
30#include <linux/slab.h> 30#include <linux/slab.h>
31#include <linux/v4l2-mediabus.h>
31 32
32#include <media/soc_camera.h> 33#include <media/soc_camera.h>
33#include <media/v4l2-chip-ident.h> 34#include <media/v4l2-chip-ident.h>
34 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
178struct ov6650 { 179struct 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
213static 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 */
334static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val) 218static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val)
335{ 219{
@@ -419,213 +303,90 @@ static int ov6650_s_stream(struct v4l2_subdev *sd, int enable)
419 return 0; 303 return 0;
420} 304}
421 305
422/* Alter bus settings on camera side */
423static int ov6650_set_bus_param(struct soc_camera_device *icd,
424 unsigned long flags)
425{
426 struct soc_camera_link *icl = to_soc_camera_link(icd);
427 struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
428 int ret;
429
430 flags = soc_camera_apply_sensor_flags(icl, flags);
431
432 if (flags & SOCAM_PCLK_SAMPLE_RISING)
433 ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_PCLK_RISING, 0);
434 else
435 ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_PCLK_RISING);
436 if (ret)
437 return ret;
438
439 if (flags & SOCAM_HSYNC_ACTIVE_LOW)
440 ret = ov6650_reg_rmw(client, REG_COMF, COMF_HREF_LOW, 0);
441 else
442 ret = ov6650_reg_rmw(client, REG_COMF, 0, COMF_HREF_LOW);
443 if (ret)
444 return ret;
445
446 if (flags & SOCAM_VSYNC_ACTIVE_HIGH)
447 ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_VSYNC_HIGH, 0);
448 else
449 ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_VSYNC_HIGH);
450
451 return ret;
452}
453
454/* Request bus settings on camera side */
455static unsigned long ov6650_query_bus_param(struct soc_camera_device *icd)
456{
457 struct soc_camera_link *icl = to_soc_camera_link(icd);
458
459 unsigned long flags = SOCAM_MASTER |
460 SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING |
461 SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW |
462 SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |
463 SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8;
464
465 return soc_camera_apply_sensor_flags(icl, flags);
466}
467
468/* Get status of additional camera capabilities */ 306/* Get status of additional camera capabilities */
469static int ov6650_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) 307static int ov6550_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
470{ 308{
309 struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl);
310 struct v4l2_subdev *sd = &priv->subdev;
471 struct i2c_client *client = v4l2_get_subdevdata(sd); 311 struct i2c_client *client = v4l2_get_subdevdata(sd);
472 struct ov6650 *priv = to_ov6650(client); 312 uint8_t reg, reg2;
473 uint8_t reg; 313 int ret;
474 int ret = 0;
475 314
476 switch (ctrl->id) { 315 switch (ctrl->id) {
477 case V4L2_CID_AUTOGAIN: 316 case V4L2_CID_AUTOGAIN:
478 ctrl->value = priv->agc; 317 ret = ov6650_reg_read(client, REG_GAIN, &reg);
479 break; 318 if (!ret)
480 case V4L2_CID_GAIN: 319 priv->gain->val = reg;
481 if (priv->agc) { 320 return ret;
482 ret = ov6650_reg_read(client, REG_GAIN, &reg);
483 ctrl->value = reg;
484 } else {
485 ctrl->value = priv->gain;
486 }
487 break;
488 case V4L2_CID_AUTO_WHITE_BALANCE: 321 case V4L2_CID_AUTO_WHITE_BALANCE:
489 ctrl->value = priv->awb; 322 ret = ov6650_reg_read(client, REG_BLUE, &reg);
490 break; 323 if (!ret)
491 case V4L2_CID_BLUE_BALANCE: 324 ret = ov6650_reg_read(client, REG_RED, &reg2);
492 if (priv->awb) { 325 if (!ret) {
493 ret = ov6650_reg_read(client, REG_BLUE, &reg); 326 priv->blue->val = reg;
494 ctrl->value = reg; 327 priv->red->val = reg2;
495 } else {
496 ctrl->value = priv->blue;
497 }
498 break;
499 case V4L2_CID_RED_BALANCE:
500 if (priv->awb) {
501 ret = ov6650_reg_read(client, REG_RED, &reg);
502 ctrl->value = reg;
503 } else {
504 ctrl->value = priv->red;
505 } 328 }
506 break; 329 return ret;
507 case V4L2_CID_SATURATION:
508 ctrl->value = priv->saturation;
509 break;
510 case V4L2_CID_HUE:
511 ctrl->value = priv->hue;
512 break;
513 case V4L2_CID_BRIGHTNESS:
514 ctrl->value = priv->brightness;
515 break;
516 case V4L2_CID_EXPOSURE_AUTO: 330 case V4L2_CID_EXPOSURE_AUTO:
517 ctrl->value = priv->aec; 331 ret = ov6650_reg_read(client, REG_AECH, &reg);
518 break; 332 if (!ret)
519 case V4L2_CID_EXPOSURE: 333 priv->exposure->val = reg;
520 if (priv->aec) { 334 return ret;
521 ret = ov6650_reg_read(client, REG_AECH, &reg);
522 ctrl->value = reg;
523 } else {
524 ctrl->value = priv->exposure;
525 }
526 break;
527 case V4L2_CID_GAMMA:
528 ctrl->value = priv->gamma;
529 break;
530 case V4L2_CID_VFLIP:
531 ctrl->value = priv->vflip;
532 break;
533 case V4L2_CID_HFLIP:
534 ctrl->value = priv->hflip;
535 break;
536 } 335 }
537 return ret; 336 return -EINVAL;
538} 337}
539 338
540/* Set status of additional camera capabilities */ 339/* Set status of additional camera capabilities */
541static int ov6650_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) 340static int ov6550_s_ctrl(struct v4l2_ctrl *ctrl)
542{ 341{
342 struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl);
343 struct v4l2_subdev *sd = &priv->subdev;
543 struct i2c_client *client = v4l2_get_subdevdata(sd); 344 struct i2c_client *client = v4l2_get_subdevdata(sd);
544 struct ov6650 *priv = to_ov6650(client); 345 int ret;
545 int ret = 0;
546 346
547 switch (ctrl->id) { 347 switch (ctrl->id) {
548 case V4L2_CID_AUTOGAIN: 348 case V4L2_CID_AUTOGAIN:
549 ret = ov6650_reg_rmw(client, REG_COMB, 349 ret = ov6650_reg_rmw(client, REG_COMB,
550 ctrl->value ? COMB_AGC : 0, COMB_AGC); 350 ctrl->val ? COMB_AGC : 0, COMB_AGC);
551 if (!ret) 351 if (!ret && !ctrl->val)
552 priv->agc = ctrl->value; 352 ret = ov6650_reg_write(client, REG_GAIN, priv->gain->val);
553 break; 353 return ret;
554 case V4L2_CID_GAIN:
555 ret = ov6650_reg_write(client, REG_GAIN, ctrl->value);
556 if (!ret)
557 priv->gain = ctrl->value;
558 break;
559 case V4L2_CID_AUTO_WHITE_BALANCE: 354 case V4L2_CID_AUTO_WHITE_BALANCE:
560 ret = ov6650_reg_rmw(client, REG_COMB, 355 ret = ov6650_reg_rmw(client, REG_COMB,
561 ctrl->value ? COMB_AWB : 0, COMB_AWB); 356 ctrl->val ? COMB_AWB : 0, COMB_AWB);
562 if (!ret) 357 if (!ret && !ctrl->val) {
563 priv->awb = ctrl->value; 358 ret = ov6650_reg_write(client, REG_BLUE, priv->blue->val);
564 break; 359 if (!ret)
565 case V4L2_CID_BLUE_BALANCE: 360 ret = ov6650_reg_write(client, REG_RED,
566 ret = ov6650_reg_write(client, REG_BLUE, ctrl->value); 361 priv->red->val);
567 if (!ret) 362 }
568 priv->blue = ctrl->value; 363 return ret;
569 break;
570 case V4L2_CID_RED_BALANCE:
571 ret = ov6650_reg_write(client, REG_RED, ctrl->value);
572 if (!ret)
573 priv->red = ctrl->value;
574 break;
575 case V4L2_CID_SATURATION: 364 case V4L2_CID_SATURATION:
576 ret = ov6650_reg_rmw(client, REG_SAT, SET_SAT(ctrl->value), 365 return ov6650_reg_rmw(client, REG_SAT, SET_SAT(ctrl->val),
577 SAT_MASK); 366 SAT_MASK);
578 if (!ret)
579 priv->saturation = ctrl->value;
580 break;
581 case V4L2_CID_HUE: 367 case V4L2_CID_HUE:
582 ret = ov6650_reg_rmw(client, REG_HUE, SET_HUE(ctrl->value), 368 return ov6650_reg_rmw(client, REG_HUE, SET_HUE(ctrl->val),
583 HUE_MASK); 369 HUE_MASK);
584 if (!ret)
585 priv->hue = ctrl->value;
586 break;
587 case V4L2_CID_BRIGHTNESS: 370 case V4L2_CID_BRIGHTNESS:
588 ret = ov6650_reg_write(client, REG_BRT, ctrl->value); 371 return ov6650_reg_write(client, REG_BRT, ctrl->val);
589 if (!ret)
590 priv->brightness = ctrl->value;
591 break;
592 case V4L2_CID_EXPOSURE_AUTO: 372 case V4L2_CID_EXPOSURE_AUTO:
593 switch (ctrl->value) { 373 ret = ov6650_reg_rmw(client, REG_COMB, ctrl->val ==
594 case V4L2_EXPOSURE_AUTO: 374 V4L2_EXPOSURE_AUTO ? COMB_AEC : 0, COMB_AEC);
595 ret = ov6650_reg_rmw(client, REG_COMB, COMB_AEC, 0); 375 if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL)
596 break; 376 ret = ov6650_reg_write(client, REG_AECH,
597 default: 377 priv->exposure->val);
598 ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_AEC); 378 return ret;
599 break;
600 }
601 if (!ret)
602 priv->aec = ctrl->value;
603 break;
604 case V4L2_CID_EXPOSURE:
605 ret = ov6650_reg_write(client, REG_AECH, ctrl->value);
606 if (!ret)
607 priv->exposure = ctrl->value;
608 break;
609 case V4L2_CID_GAMMA: 379 case V4L2_CID_GAMMA:
610 ret = ov6650_reg_write(client, REG_GAM1, ctrl->value); 380 return ov6650_reg_write(client, REG_GAM1, ctrl->val);
611 if (!ret)
612 priv->gamma = ctrl->value;
613 break;
614 case V4L2_CID_VFLIP: 381 case V4L2_CID_VFLIP:
615 ret = ov6650_reg_rmw(client, REG_COMB, 382 return ov6650_reg_rmw(client, REG_COMB,
616 ctrl->value ? COMB_FLIP_V : 0, COMB_FLIP_V); 383 ctrl->val ? COMB_FLIP_V : 0, COMB_FLIP_V);
617 if (!ret)
618 priv->vflip = ctrl->value;
619 break;
620 case V4L2_CID_HFLIP: 384 case V4L2_CID_HFLIP:
621 ret = ov6650_reg_rmw(client, REG_COMB, 385 return ov6650_reg_rmw(client, REG_COMB,
622 ctrl->value ? COMB_FLIP_H : 0, COMB_FLIP_H); 386 ctrl->val ? COMB_FLIP_H : 0, COMB_FLIP_H);
623 if (!ret)
624 priv->hflip = ctrl->value;
625 break;
626 } 387 }
627 388
628 return ret; 389 return -EINVAL;
629} 390}
630 391
631/* Get chip identification */ 392/* Get chip identification */
@@ -778,7 +539,7 @@ static u8 to_clkrc(struct v4l2_fract *timeperframe,
778static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) 539static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
779{ 540{
780 struct i2c_client *client = v4l2_get_subdevdata(sd); 541 struct i2c_client *client = v4l2_get_subdevdata(sd);
781 struct soc_camera_device *icd = client->dev.platform_data; 542 struct soc_camera_device *icd = (struct soc_camera_device *)sd->grp_id;
782 struct soc_camera_sense *sense = icd->sense; 543 struct soc_camera_sense *sense = icd->sense;
783 struct ov6650 *priv = to_ov6650(client); 544 struct ov6650 *priv = to_ov6650(client);
784 bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect); 545 bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect);
@@ -1057,8 +818,7 @@ static int ov6650_prog_dflt(struct i2c_client *client)
1057 return ret; 818 return ret;
1058} 819}
1059 820
1060static int ov6650_video_probe(struct soc_camera_device *icd, 821static int ov6650_video_probe(struct i2c_client *client)
1061 struct i2c_client *client)
1062{ 822{
1063 u8 pidh, pidl, midh, midl; 823 u8 pidh, pidl, midh, midl;
1064 int ret = 0; 824 int ret = 0;
@@ -1094,16 +854,12 @@ static int ov6650_video_probe(struct soc_camera_device *icd,
1094 return ret; 854 return ret;
1095} 855}
1096 856
1097static struct soc_camera_ops ov6650_ops = { 857static const struct v4l2_ctrl_ops ov6550_ctrl_ops = {
1098 .set_bus_param = ov6650_set_bus_param, 858 .g_volatile_ctrl = ov6550_g_volatile_ctrl,
1099 .query_bus_param = ov6650_query_bus_param, 859 .s_ctrl = ov6550_s_ctrl,
1100 .controls = ov6650_controls,
1101 .num_controls = ARRAY_SIZE(ov6650_controls),
1102}; 860};
1103 861
1104static struct v4l2_subdev_core_ops ov6650_core_ops = { 862static struct v4l2_subdev_core_ops ov6650_core_ops = {
1105 .g_ctrl = ov6650_g_ctrl,
1106 .s_ctrl = ov6650_s_ctrl,
1107 .g_chip_ident = ov6650_g_chip_ident, 863 .g_chip_ident = ov6650_g_chip_ident,
1108#ifdef CONFIG_VIDEO_ADV_DEBUG 864#ifdef CONFIG_VIDEO_ADV_DEBUG
1109 .g_register = ov6650_get_register, 865 .g_register = ov6650_get_register,
@@ -1111,6 +867,55 @@ static struct v4l2_subdev_core_ops ov6650_core_ops = {
1111#endif 867#endif
1112}; 868};
1113 869
870/* Request bus settings on camera side */
871static int ov6650_g_mbus_config(struct v4l2_subdev *sd,
872 struct v4l2_mbus_config *cfg)
873{
874 struct i2c_client *client = v4l2_get_subdevdata(sd);
875 struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
876
877 cfg->flags = V4L2_MBUS_MASTER |
878 V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
879 V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW |
880 V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW |
881 V4L2_MBUS_DATA_ACTIVE_HIGH;
882 cfg->type = V4L2_MBUS_PARALLEL;
883 cfg->flags = soc_camera_apply_board_flags(icl, cfg);
884
885 return 0;
886}
887
888/* Alter bus settings on camera side */
889static int ov6650_s_mbus_config(struct v4l2_subdev *sd,
890 const struct v4l2_mbus_config *cfg)
891{
892 struct i2c_client *client = v4l2_get_subdevdata(sd);
893 struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
894 unsigned long flags = soc_camera_apply_board_flags(icl, cfg);
895 int ret;
896
897 if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
898 ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_PCLK_RISING, 0);
899 else
900 ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_PCLK_RISING);
901 if (ret)
902 return ret;
903
904 if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
905 ret = ov6650_reg_rmw(client, REG_COMF, COMF_HREF_LOW, 0);
906 else
907 ret = ov6650_reg_rmw(client, REG_COMF, 0, COMF_HREF_LOW);
908 if (ret)
909 return ret;
910
911 if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
912 ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_VSYNC_HIGH, 0);
913 else
914 ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_VSYNC_HIGH);
915
916 return ret;
917}
918
1114static struct v4l2_subdev_video_ops ov6650_video_ops = { 919static struct v4l2_subdev_video_ops ov6650_video_ops = {
1115 .s_stream = ov6650_s_stream, 920 .s_stream = ov6650_s_stream,
1116 .g_mbus_fmt = ov6650_g_fmt, 921 .g_mbus_fmt = ov6650_g_fmt,
@@ -1122,6 +927,8 @@ static struct v4l2_subdev_video_ops ov6650_video_ops = {
1122 .s_crop = ov6650_s_crop, 927 .s_crop = ov6650_s_crop,
1123 .g_parm = ov6650_g_parm, 928 .g_parm = ov6650_g_parm,
1124 .s_parm = ov6650_s_parm, 929 .s_parm = ov6650_s_parm,
930 .g_mbus_config = ov6650_g_mbus_config,
931 .s_mbus_config = ov6650_s_mbus_config,
1125}; 932};
1126 933
1127static struct v4l2_subdev_ops ov6650_subdev_ops = { 934static struct v4l2_subdev_ops ov6650_subdev_ops = {
@@ -1136,16 +943,9 @@ static int ov6650_probe(struct i2c_client *client,
1136 const struct i2c_device_id *did) 943 const struct i2c_device_id *did)
1137{ 944{
1138 struct ov6650 *priv; 945 struct ov6650 *priv;
1139 struct soc_camera_device *icd = client->dev.platform_data; 946 struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
1140 struct soc_camera_link *icl;
1141 int ret; 947 int ret;
1142 948
1143 if (!icd) {
1144 dev_err(&client->dev, "Missing soc-camera data!\n");
1145 return -EINVAL;
1146 }
1147
1148 icl = to_soc_camera_link(icd);
1149 if (!icl) { 949 if (!icl) {
1150 dev_err(&client->dev, "Missing platform_data for driver\n"); 950 dev_err(&client->dev, "Missing platform_data for driver\n");
1151 return -EINVAL; 951 return -EINVAL;
@@ -1159,8 +959,46 @@ static int ov6650_probe(struct i2c_client *client,
1159 } 959 }
1160 960
1161 v4l2_i2c_subdev_init(&priv->subdev, client, &ov6650_subdev_ops); 961 v4l2_i2c_subdev_init(&priv->subdev, client, &ov6650_subdev_ops);
962 v4l2_ctrl_handler_init(&priv->hdl, 13);
963 v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
964 V4L2_CID_VFLIP, 0, 1, 1, 0);
965 v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
966 V4L2_CID_HFLIP, 0, 1, 1, 0);
967 priv->autogain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
968 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
969 priv->gain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
970 V4L2_CID_GAIN, 0, 0x3f, 1, DEF_GAIN);
971 priv->autowb = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
972 V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
973 priv->blue = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
974 V4L2_CID_BLUE_BALANCE, 0, 0xff, 1, DEF_BLUE);
975 priv->red = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
976 V4L2_CID_RED_BALANCE, 0, 0xff, 1, DEF_RED);
977 v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
978 V4L2_CID_SATURATION, 0, 0xf, 1, 0x8);
979 v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
980 V4L2_CID_HUE, 0, HUE_MASK, 1, DEF_HUE);
981 v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
982 V4L2_CID_BRIGHTNESS, 0, 0xff, 1, 0x80);
983 priv->autoexposure = v4l2_ctrl_new_std_menu(&priv->hdl,
984 &ov6550_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
985 V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO);
986 priv->exposure = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
987 V4L2_CID_EXPOSURE, 0, 0xff, 1, DEF_AECH);
988 v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops,
989 V4L2_CID_GAMMA, 0, 0xff, 1, 0x12);
990
991 priv->subdev.ctrl_handler = &priv->hdl;
992 if (priv->hdl.error) {
993 int err = priv->hdl.error;
1162 994
1163 icd->ops = &ov6650_ops; 995 kfree(priv);
996 return err;
997 }
998 v4l2_ctrl_auto_cluster(2, &priv->autogain, 0, true);
999 v4l2_ctrl_auto_cluster(3, &priv->autowb, 0, true);
1000 v4l2_ctrl_auto_cluster(2, &priv->autoexposure,
1001 V4L2_EXPOSURE_MANUAL, true);
1164 1002
1165 priv->rect.left = DEF_HSTRT << 1; 1003 priv->rect.left = DEF_HSTRT << 1;
1166 priv->rect.top = DEF_VSTRT << 1; 1004 priv->rect.top = DEF_VSTRT << 1;
@@ -1170,10 +1008,12 @@ static int ov6650_probe(struct i2c_client *client,
1170 priv->code = V4L2_MBUS_FMT_YUYV8_2X8; 1008 priv->code = V4L2_MBUS_FMT_YUYV8_2X8;
1171 priv->colorspace = V4L2_COLORSPACE_JPEG; 1009 priv->colorspace = V4L2_COLORSPACE_JPEG;
1172 1010
1173 ret = ov6650_video_probe(icd, client); 1011 ret = ov6650_video_probe(client);
1012 if (!ret)
1013 ret = v4l2_ctrl_handler_setup(&priv->hdl);
1174 1014
1175 if (ret) { 1015 if (ret) {
1176 icd->ops = NULL; 1016 v4l2_ctrl_handler_free(&priv->hdl);
1177 kfree(priv); 1017 kfree(priv);
1178 } 1018 }
1179 1019
@@ -1184,6 +1024,8 @@ static int ov6650_remove(struct i2c_client *client)
1184{ 1024{
1185 struct ov6650 *priv = to_ov6650(client); 1025 struct ov6650 *priv = to_ov6650(client);
1186 1026
1027 v4l2_device_unregister_subdev(&priv->subdev);
1028 v4l2_ctrl_handler_free(&priv->hdl);
1187 kfree(priv); 1029 kfree(priv);
1188 return 0; 1030 return 0;
1189} 1031}