aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2011-09-07 05:04:30 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-11-03 16:28:52 -0400
commit2dd7d29c783db1efa875e585770feb2cd7aaaf32 (patch)
tree5b8f487fa4cb5eb14df7ae422d6d8099a0741977 /drivers
parent34e181c5211f106f1d464e9bcb50bb88398126e2 (diff)
[media] mt9m001: convert to the control framework
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> [g.liakhovetski@gmx.de: simplified pointer arithmetic] Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/mt9m001.c218
1 files changed, 77 insertions, 141 deletions
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
index 3555e853e5c..42bb3c89cfe 100644
--- a/drivers/media/video/mt9m001.c
+++ b/drivers/media/video/mt9m001.c
@@ -17,6 +17,7 @@
17#include <media/soc_mediabus.h> 17#include <media/soc_mediabus.h>
18#include <media/v4l2-subdev.h> 18#include <media/v4l2-subdev.h>
19#include <media/v4l2-chip-ident.h> 19#include <media/v4l2-chip-ident.h>
20#include <media/v4l2-ctrls.h>
20 21
21/* 22/*
22 * mt9m001 i2c address 0x5d 23 * mt9m001 i2c address 0x5d
@@ -85,15 +86,19 @@ static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = {
85 86
86struct mt9m001 { 87struct mt9m001 {
87 struct v4l2_subdev subdev; 88 struct v4l2_subdev subdev;
89 struct v4l2_ctrl_handler hdl;
90 struct {
91 /* exposure/auto-exposure cluster */
92 struct v4l2_ctrl *autoexposure;
93 struct v4l2_ctrl *exposure;
94 };
88 struct v4l2_rect rect; /* Sensor window */ 95 struct v4l2_rect rect; /* Sensor window */
89 const struct mt9m001_datafmt *fmt; 96 const struct mt9m001_datafmt *fmt;
90 const struct mt9m001_datafmt *fmts; 97 const struct mt9m001_datafmt *fmts;
91 int num_fmts; 98 int num_fmts;
92 int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */ 99 int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
93 unsigned int gain; 100 unsigned int total_h;
94 unsigned int exposure;
95 unsigned short y_skip_top; /* Lines to skip at the top */ 101 unsigned short y_skip_top; /* Lines to skip at the top */
96 unsigned char autoexposure;
97}; 102};
98 103
99static struct mt9m001 *to_mt9m001(const struct i2c_client *client) 104static struct mt9m001 *to_mt9m001(const struct i2c_client *client)
@@ -171,10 +176,8 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
171 struct i2c_client *client = v4l2_get_subdevdata(sd); 176 struct i2c_client *client = v4l2_get_subdevdata(sd);
172 struct mt9m001 *mt9m001 = to_mt9m001(client); 177 struct mt9m001 *mt9m001 = to_mt9m001(client);
173 struct v4l2_rect rect = a->c; 178 struct v4l2_rect rect = a->c;
174 struct soc_camera_device *icd = client->dev.platform_data;
175 int ret; 179 int ret;
176 const u16 hblank = 9, vblank = 25; 180 const u16 hblank = 9, vblank = 25;
177 unsigned int total_h;
178 181
179 if (mt9m001->fmts == mt9m001_colour_fmts) 182 if (mt9m001->fmts == mt9m001_colour_fmts)
180 /* 183 /*
@@ -193,7 +196,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
193 soc_camera_limit_side(&rect.top, &rect.height, 196 soc_camera_limit_side(&rect.top, &rect.height,
194 MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT); 197 MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT);
195 198
196 total_h = rect.height + mt9m001->y_skip_top + vblank; 199 mt9m001->total_h = rect.height + mt9m001->y_skip_top + vblank;
197 200
198 /* Blanking and start values - default... */ 201 /* Blanking and start values - default... */
199 ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank); 202 ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank);
@@ -213,17 +216,8 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
213 if (!ret) 216 if (!ret)
214 ret = reg_write(client, MT9M001_WINDOW_HEIGHT, 217 ret = reg_write(client, MT9M001_WINDOW_HEIGHT,
215 rect.height + mt9m001->y_skip_top - 1); 218 rect.height + mt9m001->y_skip_top - 1);
216 if (!ret && mt9m001->autoexposure) { 219 if (!ret && v4l2_ctrl_g_ctrl(mt9m001->autoexposure) == V4L2_EXPOSURE_AUTO)
217 ret = reg_write(client, MT9M001_SHUTTER_WIDTH, total_h); 220 ret = reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h);
218 if (!ret) {
219 const struct v4l2_queryctrl *qctrl =
220 soc_camera_find_qctrl(icd->ops,
221 V4L2_CID_EXPOSURE);
222 mt9m001->exposure = (524 + (total_h - 1) *
223 (qctrl->maximum - qctrl->minimum)) /
224 1048 + qctrl->minimum;
225 }
226 }
227 221
228 if (!ret) 222 if (!ret)
229 mt9m001->rect = rect; 223 mt9m001->rect = rect;
@@ -383,105 +377,48 @@ static int mt9m001_s_register(struct v4l2_subdev *sd,
383} 377}
384#endif 378#endif
385 379
386static const struct v4l2_queryctrl mt9m001_controls[] = { 380static int mt9m001_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
387 {
388 .id = V4L2_CID_VFLIP,
389 .type = V4L2_CTRL_TYPE_BOOLEAN,
390 .name = "Flip Vertically",
391 .minimum = 0,
392 .maximum = 1,
393 .step = 1,
394 .default_value = 0,
395 }, {
396 .id = V4L2_CID_GAIN,
397 .type = V4L2_CTRL_TYPE_INTEGER,
398 .name = "Gain",
399 .minimum = 0,
400 .maximum = 127,
401 .step = 1,
402 .default_value = 64,
403 .flags = V4L2_CTRL_FLAG_SLIDER,
404 }, {
405 .id = V4L2_CID_EXPOSURE,
406 .type = V4L2_CTRL_TYPE_INTEGER,
407 .name = "Exposure",
408 .minimum = 1,
409 .maximum = 255,
410 .step = 1,
411 .default_value = 255,
412 .flags = V4L2_CTRL_FLAG_SLIDER,
413 }, {
414 .id = V4L2_CID_EXPOSURE_AUTO,
415 .type = V4L2_CTRL_TYPE_BOOLEAN,
416 .name = "Automatic Exposure",
417 .minimum = 0,
418 .maximum = 1,
419 .step = 1,
420 .default_value = 1,
421 }
422};
423
424static struct soc_camera_ops mt9m001_ops = {
425 .controls = mt9m001_controls,
426 .num_controls = ARRAY_SIZE(mt9m001_controls),
427};
428
429static int mt9m001_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
430{ 381{
431 struct i2c_client *client = v4l2_get_subdevdata(sd); 382 struct mt9m001 *mt9m001 = container_of(ctrl->handler,
432 struct mt9m001 *mt9m001 = to_mt9m001(client); 383 struct mt9m001, hdl);
433 int data; 384 s32 min, max;
434 385
435 switch (ctrl->id) { 386 switch (ctrl->id) {
436 case V4L2_CID_VFLIP:
437 data = reg_read(client, MT9M001_READ_OPTIONS2);
438 if (data < 0)
439 return -EIO;
440 ctrl->value = !!(data & 0x8000);
441 break;
442 case V4L2_CID_EXPOSURE_AUTO: 387 case V4L2_CID_EXPOSURE_AUTO:
443 ctrl->value = mt9m001->autoexposure; 388 min = mt9m001->exposure->minimum;
444 break; 389 max = mt9m001->exposure->maximum;
445 case V4L2_CID_GAIN: 390 mt9m001->exposure->val =
446 ctrl->value = mt9m001->gain; 391 (524 + (mt9m001->total_h - 1) * (max - min)) / 1048 + min;
447 break;
448 case V4L2_CID_EXPOSURE:
449 ctrl->value = mt9m001->exposure;
450 break; 392 break;
451 } 393 }
452 return 0; 394 return 0;
453} 395}
454 396
455static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) 397static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl)
456{ 398{
399 struct mt9m001 *mt9m001 = container_of(ctrl->handler,
400 struct mt9m001, hdl);
401 struct v4l2_subdev *sd = &mt9m001->subdev;
457 struct i2c_client *client = v4l2_get_subdevdata(sd); 402 struct i2c_client *client = v4l2_get_subdevdata(sd);
458 struct mt9m001 *mt9m001 = to_mt9m001(client); 403 struct v4l2_ctrl *exp = mt9m001->exposure;
459 struct soc_camera_device *icd = client->dev.platform_data;
460 const struct v4l2_queryctrl *qctrl;
461 int data; 404 int data;
462 405
463 qctrl = soc_camera_find_qctrl(&mt9m001_ops, ctrl->id);
464
465 if (!qctrl)
466 return -EINVAL;
467
468 switch (ctrl->id) { 406 switch (ctrl->id) {
469 case V4L2_CID_VFLIP: 407 case V4L2_CID_VFLIP:
470 if (ctrl->value) 408 if (ctrl->val)
471 data = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000); 409 data = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000);
472 else 410 else
473 data = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000); 411 data = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000);
474 if (data < 0) 412 if (data < 0)
475 return -EIO; 413 return -EIO;
476 break; 414 return 0;
415
477 case V4L2_CID_GAIN: 416 case V4L2_CID_GAIN:
478 if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
479 return -EINVAL;
480 /* See Datasheet Table 7, Gain settings. */ 417 /* See Datasheet Table 7, Gain settings. */
481 if (ctrl->value <= qctrl->default_value) { 418 if (ctrl->val <= ctrl->default_value) {
482 /* Pack it into 0..1 step 0.125, register values 0..8 */ 419 /* Pack it into 0..1 step 0.125, register values 0..8 */
483 unsigned long range = qctrl->default_value - qctrl->minimum; 420 unsigned long range = ctrl->default_value - ctrl->minimum;
484 data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; 421 data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range;
485 422
486 dev_dbg(&client->dev, "Setting gain %d\n", data); 423 dev_dbg(&client->dev, "Setting gain %d\n", data);
487 data = reg_write(client, MT9M001_GLOBAL_GAIN, data); 424 data = reg_write(client, MT9M001_GLOBAL_GAIN, data);
@@ -490,8 +427,8 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
490 } else { 427 } else {
491 /* Pack it into 1.125..15 variable step, register values 9..67 */ 428 /* Pack it into 1.125..15 variable step, register values 9..67 */
492 /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ 429 /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
493 unsigned long range = qctrl->maximum - qctrl->default_value - 1; 430 unsigned long range = ctrl->maximum - ctrl->default_value - 1;
494 unsigned long gain = ((ctrl->value - qctrl->default_value - 1) * 431 unsigned long gain = ((ctrl->val - ctrl->default_value - 1) *
495 111 + range / 2) / range + 9; 432 111 + range / 2) / range + 9;
496 433
497 if (gain <= 32) 434 if (gain <= 32)
@@ -507,47 +444,30 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
507 if (data < 0) 444 if (data < 0)
508 return -EIO; 445 return -EIO;
509 } 446 }
447 return 0;
510 448
511 /* Success */ 449 case V4L2_CID_EXPOSURE_AUTO:
512 mt9m001->gain = ctrl->value; 450 if (ctrl->val == V4L2_EXPOSURE_MANUAL) {
513 break; 451 unsigned long range = exp->maximum - exp->minimum;
514 case V4L2_CID_EXPOSURE: 452 unsigned long shutter = ((exp->val - exp->minimum) * 1048 +
515 /* mt9m001 has maximum == default */
516 if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
517 return -EINVAL;
518 else {
519 unsigned long range = qctrl->maximum - qctrl->minimum;
520 unsigned long shutter = ((ctrl->value - qctrl->minimum) * 1048 +
521 range / 2) / range + 1; 453 range / 2) / range + 1;
522 454
523 dev_dbg(&client->dev, 455 dev_dbg(&client->dev,
524 "Setting shutter width from %d to %lu\n", 456 "Setting shutter width from %d to %lu\n",
525 reg_read(client, MT9M001_SHUTTER_WIDTH), 457 reg_read(client, MT9M001_SHUTTER_WIDTH), shutter);
526 shutter);
527 if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0) 458 if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0)
528 return -EIO; 459 return -EIO;
529 mt9m001->exposure = ctrl->value; 460 } else {
530 mt9m001->autoexposure = 0;
531 }
532 break;
533 case V4L2_CID_EXPOSURE_AUTO:
534 if (ctrl->value) {
535 const u16 vblank = 25; 461 const u16 vblank = 25;
536 unsigned int total_h = mt9m001->rect.height + 462
463 mt9m001->total_h = mt9m001->rect.height +
537 mt9m001->y_skip_top + vblank; 464 mt9m001->y_skip_top + vblank;
538 if (reg_write(client, MT9M001_SHUTTER_WIDTH, 465 if (reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h) < 0)
539 total_h) < 0)
540 return -EIO; 466 return -EIO;
541 qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); 467 }
542 mt9m001->exposure = (524 + (total_h - 1) * 468 return 0;
543 (qctrl->maximum - qctrl->minimum)) /
544 1048 + qctrl->minimum;
545 mt9m001->autoexposure = 1;
546 } else
547 mt9m001->autoexposure = 0;
548 break;
549 } 469 }
550 return 0; 470 return -EINVAL;
551} 471}
552 472
553/* 473/*
@@ -621,10 +541,7 @@ static int mt9m001_video_probe(struct soc_camera_device *icd,
621 dev_err(&client->dev, "Failed to initialise the camera\n"); 541 dev_err(&client->dev, "Failed to initialise the camera\n");
622 542
623 /* mt9m001_init() has reset the chip, returning registers to defaults */ 543 /* mt9m001_init() has reset the chip, returning registers to defaults */
624 mt9m001->gain = 64; 544 return v4l2_ctrl_handler_setup(&mt9m001->hdl);
625 mt9m001->exposure = 255;
626
627 return ret;
628} 545}
629 546
630static void mt9m001_video_remove(struct soc_camera_device *icd) 547static void mt9m001_video_remove(struct soc_camera_device *icd)
@@ -647,9 +564,12 @@ static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
647 return 0; 564 return 0;
648} 565}
649 566
567static const struct v4l2_ctrl_ops mt9m001_ctrl_ops = {
568 .g_volatile_ctrl = mt9m001_g_volatile_ctrl,
569 .s_ctrl = mt9m001_s_ctrl,
570};
571
650static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { 572static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = {
651 .g_ctrl = mt9m001_g_ctrl,
652 .s_ctrl = mt9m001_s_ctrl,
653 .g_chip_ident = mt9m001_g_chip_ident, 573 .g_chip_ident = mt9m001_g_chip_ident,
654#ifdef CONFIG_VIDEO_ADV_DEBUG 574#ifdef CONFIG_VIDEO_ADV_DEBUG
655 .g_register = mt9m001_g_register, 575 .g_register = mt9m001_g_register,
@@ -765,25 +685,40 @@ static int mt9m001_probe(struct i2c_client *client,
765 return -ENOMEM; 685 return -ENOMEM;
766 686
767 v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops); 687 v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops);
688 v4l2_ctrl_handler_init(&mt9m001->hdl, 4);
689 v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops,
690 V4L2_CID_VFLIP, 0, 1, 1, 0);
691 v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops,
692 V4L2_CID_GAIN, 0, 127, 1, 64);
693 mt9m001->exposure = v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops,
694 V4L2_CID_EXPOSURE, 1, 255, 1, 255);
695 /*
696 * Simulated autoexposure. If enabled, we calculate shutter width
697 * ourselves in the driver based on vertical blanking and frame width
698 */
699 mt9m001->autoexposure = v4l2_ctrl_new_std_menu(&mt9m001->hdl,
700 &mt9m001_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
701 V4L2_EXPOSURE_AUTO);
702 mt9m001->subdev.ctrl_handler = &mt9m001->hdl;
703 if (mt9m001->hdl.error) {
704 int err = mt9m001->hdl.error;
768 705
769 /* Second stage probe - when a capture adapter is there */ 706 kfree(mt9m001);
770 icd->ops = &mt9m001_ops; 707 return err;
708 }
709 v4l2_ctrl_auto_cluster(2, &mt9m001->autoexposure,
710 V4L2_EXPOSURE_MANUAL, true);
771 711
712 /* Second stage probe - when a capture adapter is there */
772 mt9m001->y_skip_top = 0; 713 mt9m001->y_skip_top = 0;
773 mt9m001->rect.left = MT9M001_COLUMN_SKIP; 714 mt9m001->rect.left = MT9M001_COLUMN_SKIP;
774 mt9m001->rect.top = MT9M001_ROW_SKIP; 715 mt9m001->rect.top = MT9M001_ROW_SKIP;
775 mt9m001->rect.width = MT9M001_MAX_WIDTH; 716 mt9m001->rect.width = MT9M001_MAX_WIDTH;
776 mt9m001->rect.height = MT9M001_MAX_HEIGHT; 717 mt9m001->rect.height = MT9M001_MAX_HEIGHT;
777 718
778 /*
779 * Simulated autoexposure. If enabled, we calculate shutter width
780 * ourselves in the driver based on vertical blanking and frame width
781 */
782 mt9m001->autoexposure = 1;
783
784 ret = mt9m001_video_probe(icd, client); 719 ret = mt9m001_video_probe(icd, client);
785 if (ret) { 720 if (ret) {
786 icd->ops = NULL; 721 v4l2_ctrl_handler_free(&mt9m001->hdl);
787 kfree(mt9m001); 722 kfree(mt9m001);
788 } 723 }
789 724
@@ -795,7 +730,8 @@ static int mt9m001_remove(struct i2c_client *client)
795 struct mt9m001 *mt9m001 = to_mt9m001(client); 730 struct mt9m001 *mt9m001 = to_mt9m001(client);
796 struct soc_camera_device *icd = client->dev.platform_data; 731 struct soc_camera_device *icd = client->dev.platform_data;
797 732
798 icd->ops = NULL; 733 v4l2_device_unregister_subdev(&mt9m001->subdev);
734 v4l2_ctrl_handler_free(&mt9m001->hdl);
799 mt9m001_video_remove(icd); 735 mt9m001_video_remove(icd);
800 kfree(mt9m001); 736 kfree(mt9m001);
801 737