diff options
Diffstat (limited to 'drivers/media/video/mt9v022.c')
-rw-r--r-- | drivers/media/video/mt9v022.c | 448 |
1 files changed, 186 insertions, 262 deletions
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 51b0fccbfe7..690ee0d42ee 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c | |||
@@ -13,10 +13,13 @@ | |||
13 | #include <linux/i2c.h> | 13 | #include <linux/i2c.h> |
14 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
15 | #include <linux/log2.h> | 15 | #include <linux/log2.h> |
16 | #include <linux/module.h> | ||
16 | 17 | ||
18 | #include <media/soc_camera.h> | ||
19 | #include <media/soc_mediabus.h> | ||
17 | #include <media/v4l2-subdev.h> | 20 | #include <media/v4l2-subdev.h> |
18 | #include <media/v4l2-chip-ident.h> | 21 | #include <media/v4l2-chip-ident.h> |
19 | #include <media/soc_camera.h> | 22 | #include <media/v4l2-ctrls.h> |
20 | 23 | ||
21 | /* | 24 | /* |
22 | * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c | 25 | * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c |
@@ -100,6 +103,17 @@ static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = { | |||
100 | 103 | ||
101 | struct mt9v022 { | 104 | struct mt9v022 { |
102 | struct v4l2_subdev subdev; | 105 | struct v4l2_subdev subdev; |
106 | struct v4l2_ctrl_handler hdl; | ||
107 | struct { | ||
108 | /* exposure/auto-exposure cluster */ | ||
109 | struct v4l2_ctrl *autoexposure; | ||
110 | struct v4l2_ctrl *exposure; | ||
111 | }; | ||
112 | struct { | ||
113 | /* gain/auto-gain cluster */ | ||
114 | struct v4l2_ctrl *autogain; | ||
115 | struct v4l2_ctrl *gain; | ||
116 | }; | ||
103 | struct v4l2_rect rect; /* Sensor window */ | 117 | struct v4l2_rect rect; /* Sensor window */ |
104 | const struct mt9v022_datafmt *fmt; | 118 | const struct mt9v022_datafmt *fmt; |
105 | const struct mt9v022_datafmt *fmts; | 119 | const struct mt9v022_datafmt *fmts; |
@@ -178,6 +192,8 @@ static int mt9v022_init(struct i2c_client *client) | |||
178 | ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1); | 192 | ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1); |
179 | if (!ret) | 193 | if (!ret) |
180 | ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0); | 194 | ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0); |
195 | if (!ret) | ||
196 | return v4l2_ctrl_handler_setup(&mt9v022->hdl); | ||
181 | 197 | ||
182 | return ret; | 198 | return ret; |
183 | } | 199 | } |
@@ -199,78 +215,6 @@ static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable) | |||
199 | return 0; | 215 | return 0; |
200 | } | 216 | } |
201 | 217 | ||
202 | static int mt9v022_set_bus_param(struct soc_camera_device *icd, | ||
203 | unsigned long flags) | ||
204 | { | ||
205 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | ||
206 | struct mt9v022 *mt9v022 = to_mt9v022(client); | ||
207 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
208 | unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK; | ||
209 | int ret; | ||
210 | u16 pixclk = 0; | ||
211 | |||
212 | /* Only one width bit may be set */ | ||
213 | if (!is_power_of_2(width_flag)) | ||
214 | return -EINVAL; | ||
215 | |||
216 | if (icl->set_bus_param) { | ||
217 | ret = icl->set_bus_param(icl, width_flag); | ||
218 | if (ret) | ||
219 | return ret; | ||
220 | } else { | ||
221 | /* | ||
222 | * Without board specific bus width settings we only support the | ||
223 | * sensors native bus width | ||
224 | */ | ||
225 | if (width_flag != SOCAM_DATAWIDTH_10) | ||
226 | return -EINVAL; | ||
227 | } | ||
228 | |||
229 | flags = soc_camera_apply_sensor_flags(icl, flags); | ||
230 | |||
231 | if (flags & SOCAM_PCLK_SAMPLE_FALLING) | ||
232 | pixclk |= 0x10; | ||
233 | |||
234 | if (!(flags & SOCAM_HSYNC_ACTIVE_HIGH)) | ||
235 | pixclk |= 0x1; | ||
236 | |||
237 | if (!(flags & SOCAM_VSYNC_ACTIVE_HIGH)) | ||
238 | pixclk |= 0x2; | ||
239 | |||
240 | ret = reg_write(client, MT9V022_PIXCLK_FV_LV, pixclk); | ||
241 | if (ret < 0) | ||
242 | return ret; | ||
243 | |||
244 | if (!(flags & SOCAM_MASTER)) | ||
245 | mt9v022->chip_control &= ~0x8; | ||
246 | |||
247 | ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); | ||
248 | if (ret < 0) | ||
249 | return ret; | ||
250 | |||
251 | dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n", | ||
252 | pixclk, mt9v022->chip_control); | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) | ||
258 | { | ||
259 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
260 | unsigned int flags = SOCAM_MASTER | SOCAM_SLAVE | | ||
261 | SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | | ||
262 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW | | ||
263 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW | | ||
264 | SOCAM_DATA_ACTIVE_HIGH; | ||
265 | |||
266 | if (icl->query_bus_param) | ||
267 | flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK; | ||
268 | else | ||
269 | flags |= SOCAM_DATAWIDTH_10; | ||
270 | |||
271 | return soc_camera_apply_sensor_flags(icl, flags); | ||
272 | } | ||
273 | |||
274 | static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 218 | static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
275 | { | 219 | { |
276 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 220 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
@@ -389,7 +333,7 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, | |||
389 | 333 | ||
390 | /* | 334 | /* |
391 | * The caller provides a supported format, as verified per call to | 335 | * The caller provides a supported format, as verified per call to |
392 | * icd->try_fmt(), datawidth is from our supported format list | 336 | * .try_mbus_fmt(), datawidth is from our supported format list |
393 | */ | 337 | */ |
394 | switch (mf->code) { | 338 | switch (mf->code) { |
395 | case V4L2_MBUS_FMT_Y8_1X8: | 339 | case V4L2_MBUS_FMT_Y8_1X8: |
@@ -502,236 +446,131 @@ static int mt9v022_s_register(struct v4l2_subdev *sd, | |||
502 | } | 446 | } |
503 | #endif | 447 | #endif |
504 | 448 | ||
505 | static const struct v4l2_queryctrl mt9v022_controls[] = { | 449 | static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl) |
506 | { | ||
507 | .id = V4L2_CID_VFLIP, | ||
508 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
509 | .name = "Flip Vertically", | ||
510 | .minimum = 0, | ||
511 | .maximum = 1, | ||
512 | .step = 1, | ||
513 | .default_value = 0, | ||
514 | }, { | ||
515 | .id = V4L2_CID_HFLIP, | ||
516 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
517 | .name = "Flip Horizontally", | ||
518 | .minimum = 0, | ||
519 | .maximum = 1, | ||
520 | .step = 1, | ||
521 | .default_value = 0, | ||
522 | }, { | ||
523 | .id = V4L2_CID_GAIN, | ||
524 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
525 | .name = "Analog Gain", | ||
526 | .minimum = 64, | ||
527 | .maximum = 127, | ||
528 | .step = 1, | ||
529 | .default_value = 64, | ||
530 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
531 | }, { | ||
532 | .id = V4L2_CID_EXPOSURE, | ||
533 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
534 | .name = "Exposure", | ||
535 | .minimum = 1, | ||
536 | .maximum = 255, | ||
537 | .step = 1, | ||
538 | .default_value = 255, | ||
539 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
540 | }, { | ||
541 | .id = V4L2_CID_AUTOGAIN, | ||
542 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
543 | .name = "Automatic Gain", | ||
544 | .minimum = 0, | ||
545 | .maximum = 1, | ||
546 | .step = 1, | ||
547 | .default_value = 1, | ||
548 | }, { | ||
549 | .id = V4L2_CID_EXPOSURE_AUTO, | ||
550 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
551 | .name = "Automatic Exposure", | ||
552 | .minimum = 0, | ||
553 | .maximum = 1, | ||
554 | .step = 1, | ||
555 | .default_value = 1, | ||
556 | } | ||
557 | }; | ||
558 | |||
559 | static struct soc_camera_ops mt9v022_ops = { | ||
560 | .set_bus_param = mt9v022_set_bus_param, | ||
561 | .query_bus_param = mt9v022_query_bus_param, | ||
562 | .controls = mt9v022_controls, | ||
563 | .num_controls = ARRAY_SIZE(mt9v022_controls), | ||
564 | }; | ||
565 | |||
566 | static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
567 | { | 450 | { |
451 | struct mt9v022 *mt9v022 = container_of(ctrl->handler, | ||
452 | struct mt9v022, hdl); | ||
453 | struct v4l2_subdev *sd = &mt9v022->subdev; | ||
568 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 454 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
569 | const struct v4l2_queryctrl *qctrl; | 455 | struct v4l2_ctrl *gain = mt9v022->gain; |
456 | struct v4l2_ctrl *exp = mt9v022->exposure; | ||
570 | unsigned long range; | 457 | unsigned long range; |
571 | int data; | 458 | int data; |
572 | 459 | ||
573 | qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); | ||
574 | |||
575 | switch (ctrl->id) { | 460 | switch (ctrl->id) { |
576 | case V4L2_CID_VFLIP: | ||
577 | data = reg_read(client, MT9V022_READ_MODE); | ||
578 | if (data < 0) | ||
579 | return -EIO; | ||
580 | ctrl->value = !!(data & 0x10); | ||
581 | break; | ||
582 | case V4L2_CID_HFLIP: | ||
583 | data = reg_read(client, MT9V022_READ_MODE); | ||
584 | if (data < 0) | ||
585 | return -EIO; | ||
586 | ctrl->value = !!(data & 0x20); | ||
587 | break; | ||
588 | case V4L2_CID_EXPOSURE_AUTO: | ||
589 | data = reg_read(client, MT9V022_AEC_AGC_ENABLE); | ||
590 | if (data < 0) | ||
591 | return -EIO; | ||
592 | ctrl->value = !!(data & 0x1); | ||
593 | break; | ||
594 | case V4L2_CID_AUTOGAIN: | 461 | case V4L2_CID_AUTOGAIN: |
595 | data = reg_read(client, MT9V022_AEC_AGC_ENABLE); | ||
596 | if (data < 0) | ||
597 | return -EIO; | ||
598 | ctrl->value = !!(data & 0x2); | ||
599 | break; | ||
600 | case V4L2_CID_GAIN: | ||
601 | data = reg_read(client, MT9V022_ANALOG_GAIN); | 462 | data = reg_read(client, MT9V022_ANALOG_GAIN); |
602 | if (data < 0) | 463 | if (data < 0) |
603 | return -EIO; | 464 | return -EIO; |
604 | 465 | ||
605 | range = qctrl->maximum - qctrl->minimum; | 466 | range = gain->maximum - gain->minimum; |
606 | ctrl->value = ((data - 16) * range + 24) / 48 + qctrl->minimum; | 467 | gain->val = ((data - 16) * range + 24) / 48 + gain->minimum; |
607 | 468 | return 0; | |
608 | break; | 469 | case V4L2_CID_EXPOSURE_AUTO: |
609 | case V4L2_CID_EXPOSURE: | ||
610 | data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH); | 470 | data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH); |
611 | if (data < 0) | 471 | if (data < 0) |
612 | return -EIO; | 472 | return -EIO; |
613 | 473 | ||
614 | range = qctrl->maximum - qctrl->minimum; | 474 | range = exp->maximum - exp->minimum; |
615 | ctrl->value = ((data - 1) * range + 239) / 479 + qctrl->minimum; | 475 | exp->val = ((data - 1) * range + 239) / 479 + exp->minimum; |
616 | 476 | return 0; | |
617 | break; | ||
618 | } | 477 | } |
619 | return 0; | 478 | return -EINVAL; |
620 | } | 479 | } |
621 | 480 | ||
622 | static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 481 | static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl) |
623 | { | 482 | { |
624 | int data; | 483 | struct mt9v022 *mt9v022 = container_of(ctrl->handler, |
484 | struct mt9v022, hdl); | ||
485 | struct v4l2_subdev *sd = &mt9v022->subdev; | ||
625 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 486 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
626 | const struct v4l2_queryctrl *qctrl; | 487 | int data; |
627 | |||
628 | qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); | ||
629 | if (!qctrl) | ||
630 | return -EINVAL; | ||
631 | 488 | ||
632 | switch (ctrl->id) { | 489 | switch (ctrl->id) { |
633 | case V4L2_CID_VFLIP: | 490 | case V4L2_CID_VFLIP: |
634 | if (ctrl->value) | 491 | if (ctrl->val) |
635 | data = reg_set(client, MT9V022_READ_MODE, 0x10); | 492 | data = reg_set(client, MT9V022_READ_MODE, 0x10); |
636 | else | 493 | else |
637 | data = reg_clear(client, MT9V022_READ_MODE, 0x10); | 494 | data = reg_clear(client, MT9V022_READ_MODE, 0x10); |
638 | if (data < 0) | 495 | if (data < 0) |
639 | return -EIO; | 496 | return -EIO; |
640 | break; | 497 | return 0; |
641 | case V4L2_CID_HFLIP: | 498 | case V4L2_CID_HFLIP: |
642 | if (ctrl->value) | 499 | if (ctrl->val) |
643 | data = reg_set(client, MT9V022_READ_MODE, 0x20); | 500 | data = reg_set(client, MT9V022_READ_MODE, 0x20); |
644 | else | 501 | else |
645 | data = reg_clear(client, MT9V022_READ_MODE, 0x20); | 502 | data = reg_clear(client, MT9V022_READ_MODE, 0x20); |
646 | if (data < 0) | 503 | if (data < 0) |
647 | return -EIO; | 504 | return -EIO; |
648 | break; | 505 | return 0; |
649 | case V4L2_CID_GAIN: | 506 | case V4L2_CID_AUTOGAIN: |
650 | /* mt9v022 has minimum == default */ | 507 | if (ctrl->val) { |
651 | if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) | 508 | if (reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) |
652 | return -EINVAL; | 509 | return -EIO; |
653 | else { | 510 | } else { |
654 | unsigned long range = qctrl->maximum - qctrl->minimum; | 511 | struct v4l2_ctrl *gain = mt9v022->gain; |
512 | /* mt9v022 has minimum == default */ | ||
513 | unsigned long range = gain->maximum - gain->minimum; | ||
655 | /* Valid values 16 to 64, 32 to 64 must be even. */ | 514 | /* Valid values 16 to 64, 32 to 64 must be even. */ |
656 | unsigned long gain = ((ctrl->value - qctrl->minimum) * | 515 | unsigned long gain_val = ((gain->val - gain->minimum) * |
657 | 48 + range / 2) / range + 16; | 516 | 48 + range / 2) / range + 16; |
658 | if (gain >= 32) | 517 | |
659 | gain &= ~1; | 518 | if (gain_val >= 32) |
519 | gain_val &= ~1; | ||
520 | |||
660 | /* | 521 | /* |
661 | * The user wants to set gain manually, hope, she | 522 | * The user wants to set gain manually, hope, she |
662 | * knows, what she's doing... Switch AGC off. | 523 | * knows, what she's doing... Switch AGC off. |
663 | */ | 524 | */ |
664 | |||
665 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) | 525 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) |
666 | return -EIO; | 526 | return -EIO; |
667 | 527 | ||
668 | dev_dbg(&client->dev, "Setting gain from %d to %lu\n", | 528 | dev_dbg(&client->dev, "Setting gain from %d to %lu\n", |
669 | reg_read(client, MT9V022_ANALOG_GAIN), gain); | 529 | reg_read(client, MT9V022_ANALOG_GAIN), gain_val); |
670 | if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0) | 530 | if (reg_write(client, MT9V022_ANALOG_GAIN, gain_val) < 0) |
671 | return -EIO; | 531 | return -EIO; |
672 | } | 532 | } |
673 | break; | 533 | return 0; |
674 | case V4L2_CID_EXPOSURE: | 534 | case V4L2_CID_EXPOSURE_AUTO: |
675 | /* mt9v022 has maximum == default */ | 535 | if (ctrl->val == V4L2_EXPOSURE_AUTO) { |
676 | if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) | 536 | data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1); |
677 | return -EINVAL; | 537 | } else { |
678 | else { | 538 | struct v4l2_ctrl *exp = mt9v022->exposure; |
679 | unsigned long range = qctrl->maximum - qctrl->minimum; | 539 | unsigned long range = exp->maximum - exp->minimum; |
680 | unsigned long shutter = ((ctrl->value - qctrl->minimum) * | 540 | unsigned long shutter = ((exp->val - exp->minimum) * |
681 | 479 + range / 2) / range + 1; | 541 | 479 + range / 2) / range + 1; |
542 | |||
682 | /* | 543 | /* |
683 | * The user wants to set shutter width manually, hope, | 544 | * The user wants to set shutter width manually, hope, |
684 | * she knows, what she's doing... Switch AEC off. | 545 | * she knows, what she's doing... Switch AEC off. |
685 | */ | 546 | */ |
686 | 547 | data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1); | |
687 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0) | 548 | if (data < 0) |
688 | return -EIO; | 549 | return -EIO; |
689 | |||
690 | dev_dbg(&client->dev, "Shutter width from %d to %lu\n", | 550 | dev_dbg(&client->dev, "Shutter width from %d to %lu\n", |
691 | reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH), | 551 | reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH), |
692 | shutter); | 552 | shutter); |
693 | if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, | 553 | if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, |
694 | shutter) < 0) | 554 | shutter) < 0) |
695 | return -EIO; | 555 | return -EIO; |
696 | } | 556 | } |
697 | break; | 557 | return 0; |
698 | case V4L2_CID_AUTOGAIN: | ||
699 | if (ctrl->value) | ||
700 | data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2); | ||
701 | else | ||
702 | data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2); | ||
703 | if (data < 0) | ||
704 | return -EIO; | ||
705 | break; | ||
706 | case V4L2_CID_EXPOSURE_AUTO: | ||
707 | if (ctrl->value) | ||
708 | data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1); | ||
709 | else | ||
710 | data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1); | ||
711 | if (data < 0) | ||
712 | return -EIO; | ||
713 | break; | ||
714 | } | 558 | } |
715 | return 0; | 559 | return -EINVAL; |
716 | } | 560 | } |
717 | 561 | ||
718 | /* | 562 | /* |
719 | * Interface active, can use i2c. If it fails, it can indeed mean, that | 563 | * Interface active, can use i2c. If it fails, it can indeed mean, that |
720 | * this wasn't our capture interface, so, we wait for the right one | 564 | * this wasn't our capture interface, so, we wait for the right one |
721 | */ | 565 | */ |
722 | static int mt9v022_video_probe(struct soc_camera_device *icd, | 566 | static int mt9v022_video_probe(struct i2c_client *client) |
723 | struct i2c_client *client) | ||
724 | { | 567 | { |
725 | struct mt9v022 *mt9v022 = to_mt9v022(client); | 568 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
726 | struct soc_camera_link *icl = to_soc_camera_link(icd); | 569 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
727 | s32 data; | 570 | s32 data; |
728 | int ret; | 571 | int ret; |
729 | unsigned long flags; | 572 | unsigned long flags; |
730 | 573 | ||
731 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
732 | BUG_ON(!icd->parent || | ||
733 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
734 | |||
735 | /* Read out the chip version register */ | 574 | /* Read out the chip version register */ |
736 | data = reg_read(client, MT9V022_CHIP_VERSION); | 575 | data = reg_read(client, MT9V022_CHIP_VERSION); |
737 | 576 | ||
@@ -805,16 +644,6 @@ ei2c: | |||
805 | return ret; | 644 | return ret; |
806 | } | 645 | } |
807 | 646 | ||
808 | static void mt9v022_video_remove(struct soc_camera_device *icd) | ||
809 | { | ||
810 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
811 | |||
812 | dev_dbg(icd->pdev, "Video removed: %p, %p\n", | ||
813 | icd->parent, icd->vdev); | ||
814 | if (icl->free_bus) | ||
815 | icl->free_bus(icl); | ||
816 | } | ||
817 | |||
818 | static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) | 647 | static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) |
819 | { | 648 | { |
820 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 649 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
@@ -825,9 +654,12 @@ static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) | |||
825 | return 0; | 654 | return 0; |
826 | } | 655 | } |
827 | 656 | ||
657 | static const struct v4l2_ctrl_ops mt9v022_ctrl_ops = { | ||
658 | .g_volatile_ctrl = mt9v022_g_volatile_ctrl, | ||
659 | .s_ctrl = mt9v022_s_ctrl, | ||
660 | }; | ||
661 | |||
828 | static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { | 662 | static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { |
829 | .g_ctrl = mt9v022_g_ctrl, | ||
830 | .s_ctrl = mt9v022_s_ctrl, | ||
831 | .g_chip_ident = mt9v022_g_chip_ident, | 663 | .g_chip_ident = mt9v022_g_chip_ident, |
832 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 664 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
833 | .g_register = mt9v022_g_register, | 665 | .g_register = mt9v022_g_register, |
@@ -848,6 +680,72 @@ static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index, | |||
848 | return 0; | 680 | return 0; |
849 | } | 681 | } |
850 | 682 | ||
683 | static int mt9v022_g_mbus_config(struct v4l2_subdev *sd, | ||
684 | struct v4l2_mbus_config *cfg) | ||
685 | { | ||
686 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
687 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
688 | |||
689 | cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE | | ||
690 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | | ||
691 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW | | ||
692 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | | ||
693 | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
694 | cfg->type = V4L2_MBUS_PARALLEL; | ||
695 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
696 | |||
697 | return 0; | ||
698 | } | ||
699 | |||
700 | static int mt9v022_s_mbus_config(struct v4l2_subdev *sd, | ||
701 | const struct v4l2_mbus_config *cfg) | ||
702 | { | ||
703 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
704 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
705 | struct mt9v022 *mt9v022 = to_mt9v022(client); | ||
706 | unsigned long flags = soc_camera_apply_board_flags(icl, cfg); | ||
707 | unsigned int bps = soc_mbus_get_fmtdesc(mt9v022->fmt->code)->bits_per_sample; | ||
708 | int ret; | ||
709 | u16 pixclk = 0; | ||
710 | |||
711 | if (icl->set_bus_param) { | ||
712 | ret = icl->set_bus_param(icl, 1 << (bps - 1)); | ||
713 | if (ret) | ||
714 | return ret; | ||
715 | } else if (bps != 10) { | ||
716 | /* | ||
717 | * Without board specific bus width settings we only support the | ||
718 | * sensors native bus width | ||
719 | */ | ||
720 | return -EINVAL; | ||
721 | } | ||
722 | |||
723 | if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) | ||
724 | pixclk |= 0x10; | ||
725 | |||
726 | if (!(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)) | ||
727 | pixclk |= 0x1; | ||
728 | |||
729 | if (!(flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)) | ||
730 | pixclk |= 0x2; | ||
731 | |||
732 | ret = reg_write(client, MT9V022_PIXCLK_FV_LV, pixclk); | ||
733 | if (ret < 0) | ||
734 | return ret; | ||
735 | |||
736 | if (!(flags & V4L2_MBUS_MASTER)) | ||
737 | mt9v022->chip_control &= ~0x8; | ||
738 | |||
739 | ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); | ||
740 | if (ret < 0) | ||
741 | return ret; | ||
742 | |||
743 | dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n", | ||
744 | pixclk, mt9v022->chip_control); | ||
745 | |||
746 | return 0; | ||
747 | } | ||
748 | |||
851 | static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { | 749 | static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { |
852 | .s_stream = mt9v022_s_stream, | 750 | .s_stream = mt9v022_s_stream, |
853 | .s_mbus_fmt = mt9v022_s_fmt, | 751 | .s_mbus_fmt = mt9v022_s_fmt, |
@@ -857,6 +755,8 @@ static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { | |||
857 | .g_crop = mt9v022_g_crop, | 755 | .g_crop = mt9v022_g_crop, |
858 | .cropcap = mt9v022_cropcap, | 756 | .cropcap = mt9v022_cropcap, |
859 | .enum_mbus_fmt = mt9v022_enum_fmt, | 757 | .enum_mbus_fmt = mt9v022_enum_fmt, |
758 | .g_mbus_config = mt9v022_g_mbus_config, | ||
759 | .s_mbus_config = mt9v022_s_mbus_config, | ||
860 | }; | 760 | }; |
861 | 761 | ||
862 | static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = { | 762 | static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = { |
@@ -873,17 +773,10 @@ static int mt9v022_probe(struct i2c_client *client, | |||
873 | const struct i2c_device_id *did) | 773 | const struct i2c_device_id *did) |
874 | { | 774 | { |
875 | struct mt9v022 *mt9v022; | 775 | struct mt9v022 *mt9v022; |
876 | struct soc_camera_device *icd = client->dev.platform_data; | 776 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
877 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 777 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
878 | struct soc_camera_link *icl; | ||
879 | int ret; | 778 | int ret; |
880 | 779 | ||
881 | if (!icd) { | ||
882 | dev_err(&client->dev, "MT9V022: missing soc-camera data!\n"); | ||
883 | return -EINVAL; | ||
884 | } | ||
885 | |||
886 | icl = to_soc_camera_link(icd); | ||
887 | if (!icl) { | 780 | if (!icl) { |
888 | dev_err(&client->dev, "MT9V022 driver needs platform data\n"); | 781 | dev_err(&client->dev, "MT9V022 driver needs platform data\n"); |
889 | return -EINVAL; | 782 | return -EINVAL; |
@@ -900,10 +793,39 @@ static int mt9v022_probe(struct i2c_client *client, | |||
900 | return -ENOMEM; | 793 | return -ENOMEM; |
901 | 794 | ||
902 | v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops); | 795 | v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops); |
796 | v4l2_ctrl_handler_init(&mt9v022->hdl, 6); | ||
797 | v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, | ||
798 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
799 | v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, | ||
800 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
801 | mt9v022->autogain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, | ||
802 | V4L2_CID_AUTOGAIN, 0, 1, 1, 1); | ||
803 | mt9v022->gain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, | ||
804 | V4L2_CID_GAIN, 0, 127, 1, 64); | ||
805 | |||
806 | /* | ||
807 | * Simulated autoexposure. If enabled, we calculate shutter width | ||
808 | * ourselves in the driver based on vertical blanking and frame width | ||
809 | */ | ||
810 | mt9v022->autoexposure = v4l2_ctrl_new_std_menu(&mt9v022->hdl, | ||
811 | &mt9v022_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, | ||
812 | V4L2_EXPOSURE_AUTO); | ||
813 | mt9v022->exposure = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, | ||
814 | V4L2_CID_EXPOSURE, 1, 255, 1, 255); | ||
815 | |||
816 | mt9v022->subdev.ctrl_handler = &mt9v022->hdl; | ||
817 | if (mt9v022->hdl.error) { | ||
818 | int err = mt9v022->hdl.error; | ||
819 | |||
820 | kfree(mt9v022); | ||
821 | return err; | ||
822 | } | ||
823 | v4l2_ctrl_auto_cluster(2, &mt9v022->autoexposure, | ||
824 | V4L2_EXPOSURE_MANUAL, true); | ||
825 | v4l2_ctrl_auto_cluster(2, &mt9v022->autogain, 0, true); | ||
903 | 826 | ||
904 | mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; | 827 | mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; |
905 | 828 | ||
906 | icd->ops = &mt9v022_ops; | ||
907 | /* | 829 | /* |
908 | * MT9V022 _really_ corrupts the first read out line. | 830 | * MT9V022 _really_ corrupts the first read out line. |
909 | * TODO: verify on i.MX31 | 831 | * TODO: verify on i.MX31 |
@@ -914,9 +836,9 @@ static int mt9v022_probe(struct i2c_client *client, | |||
914 | mt9v022->rect.width = MT9V022_MAX_WIDTH; | 836 | mt9v022->rect.width = MT9V022_MAX_WIDTH; |
915 | mt9v022->rect.height = MT9V022_MAX_HEIGHT; | 837 | mt9v022->rect.height = MT9V022_MAX_HEIGHT; |
916 | 838 | ||
917 | ret = mt9v022_video_probe(icd, client); | 839 | ret = mt9v022_video_probe(client); |
918 | if (ret) { | 840 | if (ret) { |
919 | icd->ops = NULL; | 841 | v4l2_ctrl_handler_free(&mt9v022->hdl); |
920 | kfree(mt9v022); | 842 | kfree(mt9v022); |
921 | } | 843 | } |
922 | 844 | ||
@@ -926,10 +848,12 @@ static int mt9v022_probe(struct i2c_client *client, | |||
926 | static int mt9v022_remove(struct i2c_client *client) | 848 | static int mt9v022_remove(struct i2c_client *client) |
927 | { | 849 | { |
928 | struct mt9v022 *mt9v022 = to_mt9v022(client); | 850 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
929 | struct soc_camera_device *icd = client->dev.platform_data; | 851 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
930 | 852 | ||
931 | icd->ops = NULL; | 853 | v4l2_device_unregister_subdev(&mt9v022->subdev); |
932 | mt9v022_video_remove(icd); | 854 | if (icl->free_bus) |
855 | icl->free_bus(icl); | ||
856 | v4l2_ctrl_handler_free(&mt9v022->hdl); | ||
933 | kfree(mt9v022); | 857 | kfree(mt9v022); |
934 | 858 | ||
935 | return 0; | 859 | return 0; |