aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/video/mt9v022.c265
1 files changed, 107 insertions, 158 deletions
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index 53149a73874b..7e2aeda21752 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -18,6 +18,7 @@
18#include <media/soc_mediabus.h> 18#include <media/soc_mediabus.h>
19#include <media/v4l2-subdev.h> 19#include <media/v4l2-subdev.h>
20#include <media/v4l2-chip-ident.h> 20#include <media/v4l2-chip-ident.h>
21#include <media/v4l2-ctrls.h>
21 22
22/* 23/*
23 * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c 24 * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c
@@ -101,6 +102,17 @@ static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = {
101 102
102struct mt9v022 { 103struct mt9v022 {
103 struct v4l2_subdev subdev; 104 struct v4l2_subdev subdev;
105 struct v4l2_ctrl_handler hdl;
106 struct {
107 /* exposure/auto-exposure cluster */
108 struct v4l2_ctrl *autoexposure;
109 struct v4l2_ctrl *exposure;
110 };
111 struct {
112 /* gain/auto-gain cluster */
113 struct v4l2_ctrl *autogain;
114 struct v4l2_ctrl *gain;
115 };
104 struct v4l2_rect rect; /* Sensor window */ 116 struct v4l2_rect rect; /* Sensor window */
105 const struct mt9v022_datafmt *fmt; 117 const struct mt9v022_datafmt *fmt;
106 const struct mt9v022_datafmt *fmts; 118 const struct mt9v022_datafmt *fmts;
@@ -179,6 +191,8 @@ static int mt9v022_init(struct i2c_client *client)
179 ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1); 191 ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1);
180 if (!ret) 192 if (!ret)
181 ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0); 193 ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0);
194 if (!ret)
195 return v4l2_ctrl_handler_setup(&mt9v022->hdl);
182 196
183 return ret; 197 return ret;
184} 198}
@@ -431,215 +445,117 @@ static int mt9v022_s_register(struct v4l2_subdev *sd,
431} 445}
432#endif 446#endif
433 447
434static const struct v4l2_queryctrl mt9v022_controls[] = { 448static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
435 {
436 .id = V4L2_CID_VFLIP,
437 .type = V4L2_CTRL_TYPE_BOOLEAN,
438 .name = "Flip Vertically",
439 .minimum = 0,
440 .maximum = 1,
441 .step = 1,
442 .default_value = 0,
443 }, {
444 .id = V4L2_CID_HFLIP,
445 .type = V4L2_CTRL_TYPE_BOOLEAN,
446 .name = "Flip Horizontally",
447 .minimum = 0,
448 .maximum = 1,
449 .step = 1,
450 .default_value = 0,
451 }, {
452 .id = V4L2_CID_GAIN,
453 .type = V4L2_CTRL_TYPE_INTEGER,
454 .name = "Analog Gain",
455 .minimum = 64,
456 .maximum = 127,
457 .step = 1,
458 .default_value = 64,
459 .flags = V4L2_CTRL_FLAG_SLIDER,
460 }, {
461 .id = V4L2_CID_EXPOSURE,
462 .type = V4L2_CTRL_TYPE_INTEGER,
463 .name = "Exposure",
464 .minimum = 1,
465 .maximum = 255,
466 .step = 1,
467 .default_value = 255,
468 .flags = V4L2_CTRL_FLAG_SLIDER,
469 }, {
470 .id = V4L2_CID_AUTOGAIN,
471 .type = V4L2_CTRL_TYPE_BOOLEAN,
472 .name = "Automatic Gain",
473 .minimum = 0,
474 .maximum = 1,
475 .step = 1,
476 .default_value = 1,
477 }, {
478 .id = V4L2_CID_EXPOSURE_AUTO,
479 .type = V4L2_CTRL_TYPE_BOOLEAN,
480 .name = "Automatic Exposure",
481 .minimum = 0,
482 .maximum = 1,
483 .step = 1,
484 .default_value = 1,
485 }
486};
487
488static struct soc_camera_ops mt9v022_ops = {
489 .controls = mt9v022_controls,
490 .num_controls = ARRAY_SIZE(mt9v022_controls),
491};
492
493static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
494{ 449{
450 struct mt9v022 *mt9v022 = container_of(ctrl->handler,
451 struct mt9v022, hdl);
452 struct v4l2_subdev *sd = &mt9v022->subdev;
495 struct i2c_client *client = v4l2_get_subdevdata(sd); 453 struct i2c_client *client = v4l2_get_subdevdata(sd);
496 const struct v4l2_queryctrl *qctrl; 454 struct v4l2_ctrl *gain = mt9v022->gain;
455 struct v4l2_ctrl *exp = mt9v022->exposure;
497 unsigned long range; 456 unsigned long range;
498 int data; 457 int data;
499 458
500 qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id);
501
502 switch (ctrl->id) { 459 switch (ctrl->id) {
503 case V4L2_CID_VFLIP:
504 data = reg_read(client, MT9V022_READ_MODE);
505 if (data < 0)
506 return -EIO;
507 ctrl->value = !!(data & 0x10);
508 break;
509 case V4L2_CID_HFLIP:
510 data = reg_read(client, MT9V022_READ_MODE);
511 if (data < 0)
512 return -EIO;
513 ctrl->value = !!(data & 0x20);
514 break;
515 case V4L2_CID_EXPOSURE_AUTO:
516 data = reg_read(client, MT9V022_AEC_AGC_ENABLE);
517 if (data < 0)
518 return -EIO;
519 ctrl->value = !!(data & 0x1);
520 break;
521 case V4L2_CID_AUTOGAIN: 460 case V4L2_CID_AUTOGAIN:
522 data = reg_read(client, MT9V022_AEC_AGC_ENABLE);
523 if (data < 0)
524 return -EIO;
525 ctrl->value = !!(data & 0x2);
526 break;
527 case V4L2_CID_GAIN:
528 data = reg_read(client, MT9V022_ANALOG_GAIN); 461 data = reg_read(client, MT9V022_ANALOG_GAIN);
529 if (data < 0) 462 if (data < 0)
530 return -EIO; 463 return -EIO;
531 464
532 range = qctrl->maximum - qctrl->minimum; 465 range = gain->maximum - gain->minimum;
533 ctrl->value = ((data - 16) * range + 24) / 48 + qctrl->minimum; 466 gain->val = ((data - 16) * range + 24) / 48 + gain->minimum;
534 467 return 0;
535 break; 468 case V4L2_CID_EXPOSURE_AUTO:
536 case V4L2_CID_EXPOSURE:
537 data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH); 469 data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH);
538 if (data < 0) 470 if (data < 0)
539 return -EIO; 471 return -EIO;
540 472
541 range = qctrl->maximum - qctrl->minimum; 473 range = exp->maximum - exp->minimum;
542 ctrl->value = ((data - 1) * range + 239) / 479 + qctrl->minimum; 474 exp->val = ((data - 1) * range + 239) / 479 + exp->minimum;
543 475 return 0;
544 break;
545 } 476 }
546 return 0; 477 return -EINVAL;
547} 478}
548 479
549static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) 480static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl)
550{ 481{
551 int data; 482 struct mt9v022 *mt9v022 = container_of(ctrl->handler,
483 struct mt9v022, hdl);
484 struct v4l2_subdev *sd = &mt9v022->subdev;
552 struct i2c_client *client = v4l2_get_subdevdata(sd); 485 struct i2c_client *client = v4l2_get_subdevdata(sd);
553 const struct v4l2_queryctrl *qctrl; 486 int data;
554
555 qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id);
556 if (!qctrl)
557 return -EINVAL;
558 487
559 switch (ctrl->id) { 488 switch (ctrl->id) {
560 case V4L2_CID_VFLIP: 489 case V4L2_CID_VFLIP:
561 if (ctrl->value) 490 if (ctrl->val)
562 data = reg_set(client, MT9V022_READ_MODE, 0x10); 491 data = reg_set(client, MT9V022_READ_MODE, 0x10);
563 else 492 else
564 data = reg_clear(client, MT9V022_READ_MODE, 0x10); 493 data = reg_clear(client, MT9V022_READ_MODE, 0x10);
565 if (data < 0) 494 if (data < 0)
566 return -EIO; 495 return -EIO;
567 break; 496 return 0;
568 case V4L2_CID_HFLIP: 497 case V4L2_CID_HFLIP:
569 if (ctrl->value) 498 if (ctrl->val)
570 data = reg_set(client, MT9V022_READ_MODE, 0x20); 499 data = reg_set(client, MT9V022_READ_MODE, 0x20);
571 else 500 else
572 data = reg_clear(client, MT9V022_READ_MODE, 0x20); 501 data = reg_clear(client, MT9V022_READ_MODE, 0x20);
573 if (data < 0) 502 if (data < 0)
574 return -EIO; 503 return -EIO;
575 break; 504 return 0;
576 case V4L2_CID_GAIN: 505 case V4L2_CID_AUTOGAIN:
577 /* mt9v022 has minimum == default */ 506 if (ctrl->val) {
578 if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) 507 if (reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
579 return -EINVAL; 508 return -EIO;
580 else { 509 } else {
581 unsigned long range = qctrl->maximum - qctrl->minimum; 510 struct v4l2_ctrl *gain = mt9v022->gain;
511 /* mt9v022 has minimum == default */
512 unsigned long range = gain->maximum - gain->minimum;
582 /* Valid values 16 to 64, 32 to 64 must be even. */ 513 /* Valid values 16 to 64, 32 to 64 must be even. */
583 unsigned long gain = ((ctrl->value - qctrl->minimum) * 514 unsigned long gain_val = ((gain->val - gain->minimum) *
584 48 + range / 2) / range + 16; 515 48 + range / 2) / range + 16;
585 if (gain >= 32) 516
586 gain &= ~1; 517 if (gain_val >= 32)
518 gain_val &= ~1;
519
587 /* 520 /*
588 * The user wants to set gain manually, hope, she 521 * The user wants to set gain manually, hope, she
589 * knows, what she's doing... Switch AGC off. 522 * knows, what she's doing... Switch AGC off.
590 */ 523 */
591
592 if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) 524 if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
593 return -EIO; 525 return -EIO;
594 526
595 dev_dbg(&client->dev, "Setting gain from %d to %lu\n", 527 dev_dbg(&client->dev, "Setting gain from %d to %lu\n",
596 reg_read(client, MT9V022_ANALOG_GAIN), gain); 528 reg_read(client, MT9V022_ANALOG_GAIN), gain_val);
597 if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0) 529 if (reg_write(client, MT9V022_ANALOG_GAIN, gain_val) < 0)
598 return -EIO; 530 return -EIO;
599 } 531 }
600 break; 532 return 0;
601 case V4L2_CID_EXPOSURE: 533 case V4L2_CID_EXPOSURE_AUTO:
602 /* mt9v022 has maximum == default */ 534 if (ctrl->val == V4L2_EXPOSURE_AUTO) {
603 if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) 535 data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1);
604 return -EINVAL; 536 } else {
605 else { 537 struct v4l2_ctrl *exp = mt9v022->exposure;
606 unsigned long range = qctrl->maximum - qctrl->minimum; 538 unsigned long range = exp->maximum - exp->minimum;
607 unsigned long shutter = ((ctrl->value - qctrl->minimum) * 539 unsigned long shutter = ((exp->val - exp->minimum) *
608 479 + range / 2) / range + 1; 540 479 + range / 2) / range + 1;
541
609 /* 542 /*
610 * The user wants to set shutter width manually, hope, 543 * The user wants to set shutter width manually, hope,
611 * she knows, what she's doing... Switch AEC off. 544 * she knows, what she's doing... Switch AEC off.
612 */ 545 */
613 546 data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1);
614 if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0) 547 if (data < 0)
615 return -EIO; 548 return -EIO;
616
617 dev_dbg(&client->dev, "Shutter width from %d to %lu\n", 549 dev_dbg(&client->dev, "Shutter width from %d to %lu\n",
618 reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH), 550 reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH),
619 shutter); 551 shutter);
620 if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, 552 if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
621 shutter) < 0) 553 shutter) < 0)
622 return -EIO; 554 return -EIO;
623 } 555 }
624 break; 556 return 0;
625 case V4L2_CID_AUTOGAIN:
626 if (ctrl->value)
627 data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2);
628 else
629 data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2);
630 if (data < 0)
631 return -EIO;
632 break;
633 case V4L2_CID_EXPOSURE_AUTO:
634 if (ctrl->value)
635 data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1);
636 else
637 data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1);
638 if (data < 0)
639 return -EIO;
640 break;
641 } 557 }
642 return 0; 558 return -EINVAL;
643} 559}
644 560
645/* 561/*
@@ -752,9 +668,12 @@ static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
752 return 0; 668 return 0;
753} 669}
754 670
671static const struct v4l2_ctrl_ops mt9v022_ctrl_ops = {
672 .g_volatile_ctrl = mt9v022_g_volatile_ctrl,
673 .s_ctrl = mt9v022_s_ctrl,
674};
675
755static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { 676static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = {
756 .g_ctrl = mt9v022_g_ctrl,
757 .s_ctrl = mt9v022_s_ctrl,
758 .g_chip_ident = mt9v022_g_chip_ident, 677 .g_chip_ident = mt9v022_g_chip_ident,
759#ifdef CONFIG_VIDEO_ADV_DEBUG 678#ifdef CONFIG_VIDEO_ADV_DEBUG
760 .g_register = mt9v022_g_register, 679 .g_register = mt9v022_g_register,
@@ -906,10 +825,39 @@ static int mt9v022_probe(struct i2c_client *client,
906 return -ENOMEM; 825 return -ENOMEM;
907 826
908 v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops); 827 v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops);
828 v4l2_ctrl_handler_init(&mt9v022->hdl, 6);
829 v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
830 V4L2_CID_VFLIP, 0, 1, 1, 0);
831 v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
832 V4L2_CID_HFLIP, 0, 1, 1, 0);
833 mt9v022->autogain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
834 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
835 mt9v022->gain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
836 V4L2_CID_GAIN, 0, 127, 1, 64);
837
838 /*
839 * Simulated autoexposure. If enabled, we calculate shutter width
840 * ourselves in the driver based on vertical blanking and frame width
841 */
842 mt9v022->autoexposure = v4l2_ctrl_new_std_menu(&mt9v022->hdl,
843 &mt9v022_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
844 V4L2_EXPOSURE_AUTO);
845 mt9v022->exposure = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
846 V4L2_CID_EXPOSURE, 1, 255, 1, 255);
847
848 mt9v022->subdev.ctrl_handler = &mt9v022->hdl;
849 if (mt9v022->hdl.error) {
850 int err = mt9v022->hdl.error;
851
852 kfree(mt9v022);
853 return err;
854 }
855 v4l2_ctrl_auto_cluster(2, &mt9v022->autoexposure,
856 V4L2_EXPOSURE_MANUAL, true);
857 v4l2_ctrl_auto_cluster(2, &mt9v022->autogain, 0, true);
909 858
910 mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; 859 mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT;
911 860
912 icd->ops = &mt9v022_ops;
913 /* 861 /*
914 * MT9V022 _really_ corrupts the first read out line. 862 * MT9V022 _really_ corrupts the first read out line.
915 * TODO: verify on i.MX31 863 * TODO: verify on i.MX31
@@ -922,7 +870,7 @@ static int mt9v022_probe(struct i2c_client *client,
922 870
923 ret = mt9v022_video_probe(icd, client); 871 ret = mt9v022_video_probe(icd, client);
924 if (ret) { 872 if (ret) {
925 icd->ops = NULL; 873 v4l2_ctrl_handler_free(&mt9v022->hdl);
926 kfree(mt9v022); 874 kfree(mt9v022);
927 } 875 }
928 876
@@ -934,8 +882,9 @@ static int mt9v022_remove(struct i2c_client *client)
934 struct mt9v022 *mt9v022 = to_mt9v022(client); 882 struct mt9v022 *mt9v022 = to_mt9v022(client);
935 struct soc_camera_device *icd = client->dev.platform_data; 883 struct soc_camera_device *icd = client->dev.platform_data;
936 884
937 icd->ops = NULL; 885 v4l2_device_unregister_subdev(&mt9v022->subdev);
938 mt9v022_video_remove(icd); 886 mt9v022_video_remove(icd);
887 v4l2_ctrl_handler_free(&mt9v022->hdl);
939 kfree(mt9v022); 888 kfree(mt9v022);
940 889
941 return 0; 890 return 0;