diff options
-rw-r--r-- | drivers/media/video/mt9t031.c | 252 |
1 files changed, 86 insertions, 166 deletions
diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 25fb833f6f2c..7ce37990a446 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <media/soc_mediabus.h> | 19 | #include <media/soc_mediabus.h> |
20 | #include <media/v4l2-chip-ident.h> | 20 | #include <media/v4l2-chip-ident.h> |
21 | #include <media/v4l2-subdev.h> | 21 | #include <media/v4l2-subdev.h> |
22 | #include <media/v4l2-ctrls.h> | ||
22 | 23 | ||
23 | /* | 24 | /* |
24 | * mt9t031 i2c address 0x5d | 25 | * mt9t031 i2c address 0x5d |
@@ -60,14 +61,18 @@ | |||
60 | 61 | ||
61 | struct mt9t031 { | 62 | struct mt9t031 { |
62 | struct v4l2_subdev subdev; | 63 | struct v4l2_subdev subdev; |
64 | struct v4l2_ctrl_handler hdl; | ||
65 | struct { | ||
66 | /* exposure/auto-exposure cluster */ | ||
67 | struct v4l2_ctrl *autoexposure; | ||
68 | struct v4l2_ctrl *exposure; | ||
69 | }; | ||
63 | struct v4l2_rect rect; /* Sensor window */ | 70 | struct v4l2_rect rect; /* Sensor window */ |
64 | int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */ | 71 | int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */ |
65 | u16 xskip; | 72 | u16 xskip; |
66 | u16 yskip; | 73 | u16 yskip; |
67 | unsigned int gain; | 74 | unsigned int total_h; |
68 | unsigned short y_skip_top; /* Lines to skip at the top */ | 75 | unsigned short y_skip_top; /* Lines to skip at the top */ |
69 | unsigned int exposure; | ||
70 | unsigned char autoexposure; | ||
71 | }; | 76 | }; |
72 | 77 | ||
73 | static struct mt9t031 *to_mt9t031(const struct i2c_client *client) | 78 | static struct mt9t031 *to_mt9t031(const struct i2c_client *client) |
@@ -175,69 +180,6 @@ static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable) | |||
175 | return 0; | 180 | return 0; |
176 | } | 181 | } |
177 | 182 | ||
178 | enum { | ||
179 | MT9T031_CTRL_VFLIP, | ||
180 | MT9T031_CTRL_HFLIP, | ||
181 | MT9T031_CTRL_GAIN, | ||
182 | MT9T031_CTRL_EXPOSURE, | ||
183 | MT9T031_CTRL_EXPOSURE_AUTO, | ||
184 | }; | ||
185 | |||
186 | static const struct v4l2_queryctrl mt9t031_controls[] = { | ||
187 | [MT9T031_CTRL_VFLIP] = { | ||
188 | .id = V4L2_CID_VFLIP, | ||
189 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
190 | .name = "Flip Vertically", | ||
191 | .minimum = 0, | ||
192 | .maximum = 1, | ||
193 | .step = 1, | ||
194 | .default_value = 0, | ||
195 | }, | ||
196 | [MT9T031_CTRL_HFLIP] = { | ||
197 | .id = V4L2_CID_HFLIP, | ||
198 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
199 | .name = "Flip Horizontally", | ||
200 | .minimum = 0, | ||
201 | .maximum = 1, | ||
202 | .step = 1, | ||
203 | .default_value = 0, | ||
204 | }, | ||
205 | [MT9T031_CTRL_GAIN] = { | ||
206 | .id = V4L2_CID_GAIN, | ||
207 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
208 | .name = "Gain", | ||
209 | .minimum = 0, | ||
210 | .maximum = 127, | ||
211 | .step = 1, | ||
212 | .default_value = 64, | ||
213 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
214 | }, | ||
215 | [MT9T031_CTRL_EXPOSURE] = { | ||
216 | .id = V4L2_CID_EXPOSURE, | ||
217 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
218 | .name = "Exposure", | ||
219 | .minimum = 1, | ||
220 | .maximum = 255, | ||
221 | .step = 1, | ||
222 | .default_value = 255, | ||
223 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
224 | }, | ||
225 | [MT9T031_CTRL_EXPOSURE_AUTO] = { | ||
226 | .id = V4L2_CID_EXPOSURE_AUTO, | ||
227 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
228 | .name = "Automatic Exposure", | ||
229 | .minimum = 0, | ||
230 | .maximum = 1, | ||
231 | .step = 1, | ||
232 | .default_value = 1, | ||
233 | } | ||
234 | }; | ||
235 | |||
236 | static struct soc_camera_ops mt9t031_ops = { | ||
237 | .controls = mt9t031_controls, | ||
238 | .num_controls = ARRAY_SIZE(mt9t031_controls), | ||
239 | }; | ||
240 | |||
241 | /* target must be _even_ */ | 183 | /* target must be _even_ */ |
242 | static u16 mt9t031_skip(s32 *source, s32 target, s32 max) | 184 | static u16 mt9t031_skip(s32 *source, s32 target, s32 max) |
243 | { | 185 | { |
@@ -334,17 +276,10 @@ static int mt9t031_set_params(struct i2c_client *client, | |||
334 | if (ret >= 0) | 276 | if (ret >= 0) |
335 | ret = reg_write(client, MT9T031_WINDOW_HEIGHT, | 277 | ret = reg_write(client, MT9T031_WINDOW_HEIGHT, |
336 | rect->height + mt9t031->y_skip_top - 1); | 278 | rect->height + mt9t031->y_skip_top - 1); |
337 | if (ret >= 0 && mt9t031->autoexposure) { | 279 | if (ret >= 0 && v4l2_ctrl_g_ctrl(mt9t031->autoexposure) == V4L2_EXPOSURE_AUTO) { |
338 | unsigned int total_h = rect->height + mt9t031->y_skip_top + vblank; | 280 | mt9t031->total_h = rect->height + mt9t031->y_skip_top + vblank; |
339 | ret = set_shutter(client, total_h); | 281 | |
340 | if (ret >= 0) { | 282 | ret = set_shutter(client, mt9t031->total_h); |
341 | const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; | ||
342 | const struct v4l2_queryctrl *qctrl = | ||
343 | &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; | ||
344 | mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * | ||
345 | (qctrl->maximum - qctrl->minimum)) / | ||
346 | shutter_max + qctrl->minimum; | ||
347 | } | ||
348 | } | 283 | } |
349 | 284 | ||
350 | /* Re-enable register update, commit all changes */ | 285 | /* Re-enable register update, commit all changes */ |
@@ -513,71 +448,57 @@ static int mt9t031_s_register(struct v4l2_subdev *sd, | |||
513 | } | 448 | } |
514 | #endif | 449 | #endif |
515 | 450 | ||
516 | static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 451 | static int mt9t031_g_volatile_ctrl(struct v4l2_ctrl *ctrl) |
517 | { | 452 | { |
518 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 453 | struct mt9t031 *mt9t031 = container_of(ctrl->handler, |
519 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 454 | struct mt9t031, hdl); |
520 | int data; | 455 | const u32 shutter_max = MT9T031_MAX_HEIGHT + MT9T031_VERTICAL_BLANK; |
456 | s32 min, max; | ||
521 | 457 | ||
522 | switch (ctrl->id) { | 458 | switch (ctrl->id) { |
523 | case V4L2_CID_VFLIP: | ||
524 | data = reg_read(client, MT9T031_READ_MODE_2); | ||
525 | if (data < 0) | ||
526 | return -EIO; | ||
527 | ctrl->value = !!(data & 0x8000); | ||
528 | break; | ||
529 | case V4L2_CID_HFLIP: | ||
530 | data = reg_read(client, MT9T031_READ_MODE_2); | ||
531 | if (data < 0) | ||
532 | return -EIO; | ||
533 | ctrl->value = !!(data & 0x4000); | ||
534 | break; | ||
535 | case V4L2_CID_EXPOSURE_AUTO: | 459 | case V4L2_CID_EXPOSURE_AUTO: |
536 | ctrl->value = mt9t031->autoexposure; | 460 | min = mt9t031->exposure->minimum; |
537 | break; | 461 | max = mt9t031->exposure->maximum; |
538 | case V4L2_CID_GAIN: | 462 | mt9t031->exposure->val = |
539 | ctrl->value = mt9t031->gain; | 463 | (shutter_max / 2 + (mt9t031->total_h - 1) * (max - min)) |
540 | break; | 464 | / shutter_max + min; |
541 | case V4L2_CID_EXPOSURE: | ||
542 | ctrl->value = mt9t031->exposure; | ||
543 | break; | 465 | break; |
544 | } | 466 | } |
545 | return 0; | 467 | return 0; |
546 | } | 468 | } |
547 | 469 | ||
548 | static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 470 | static int mt9t031_s_ctrl(struct v4l2_ctrl *ctrl) |
549 | { | 471 | { |
472 | struct mt9t031 *mt9t031 = container_of(ctrl->handler, | ||
473 | struct mt9t031, hdl); | ||
474 | struct v4l2_subdev *sd = &mt9t031->subdev; | ||
550 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 475 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
551 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 476 | struct v4l2_ctrl *exp = mt9t031->exposure; |
552 | const struct v4l2_queryctrl *qctrl; | ||
553 | int data; | 477 | int data; |
554 | 478 | ||
555 | switch (ctrl->id) { | 479 | switch (ctrl->id) { |
556 | case V4L2_CID_VFLIP: | 480 | case V4L2_CID_VFLIP: |
557 | if (ctrl->value) | 481 | if (ctrl->val) |
558 | data = reg_set(client, MT9T031_READ_MODE_2, 0x8000); | 482 | data = reg_set(client, MT9T031_READ_MODE_2, 0x8000); |
559 | else | 483 | else |
560 | data = reg_clear(client, MT9T031_READ_MODE_2, 0x8000); | 484 | data = reg_clear(client, MT9T031_READ_MODE_2, 0x8000); |
561 | if (data < 0) | 485 | if (data < 0) |
562 | return -EIO; | 486 | return -EIO; |
563 | break; | 487 | return 0; |
564 | case V4L2_CID_HFLIP: | 488 | case V4L2_CID_HFLIP: |
565 | if (ctrl->value) | 489 | if (ctrl->val) |
566 | data = reg_set(client, MT9T031_READ_MODE_2, 0x4000); | 490 | data = reg_set(client, MT9T031_READ_MODE_2, 0x4000); |
567 | else | 491 | else |
568 | data = reg_clear(client, MT9T031_READ_MODE_2, 0x4000); | 492 | data = reg_clear(client, MT9T031_READ_MODE_2, 0x4000); |
569 | if (data < 0) | 493 | if (data < 0) |
570 | return -EIO; | 494 | return -EIO; |
571 | break; | 495 | return 0; |
572 | case V4L2_CID_GAIN: | 496 | case V4L2_CID_GAIN: |
573 | qctrl = &mt9t031_controls[MT9T031_CTRL_GAIN]; | ||
574 | if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) | ||
575 | return -EINVAL; | ||
576 | /* See Datasheet Table 7, Gain settings. */ | 497 | /* See Datasheet Table 7, Gain settings. */ |
577 | if (ctrl->value <= qctrl->default_value) { | 498 | if (ctrl->val <= ctrl->default_value) { |
578 | /* Pack it into 0..1 step 0.125, register values 0..8 */ | 499 | /* Pack it into 0..1 step 0.125, register values 0..8 */ |
579 | unsigned long range = qctrl->default_value - qctrl->minimum; | 500 | unsigned long range = ctrl->default_value - ctrl->minimum; |
580 | data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; | 501 | data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range; |
581 | 502 | ||
582 | dev_dbg(&client->dev, "Setting gain %d\n", data); | 503 | dev_dbg(&client->dev, "Setting gain %d\n", data); |
583 | data = reg_write(client, MT9T031_GLOBAL_GAIN, data); | 504 | data = reg_write(client, MT9T031_GLOBAL_GAIN, data); |
@@ -586,9 +507,9 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
586 | } else { | 507 | } else { |
587 | /* Pack it into 1.125..128 variable step, register values 9..0x7860 */ | 508 | /* Pack it into 1.125..128 variable step, register values 9..0x7860 */ |
588 | /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ | 509 | /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ |
589 | unsigned long range = qctrl->maximum - qctrl->default_value - 1; | 510 | unsigned long range = ctrl->maximum - ctrl->default_value - 1; |
590 | /* calculated gain: map 65..127 to 9..1024 step 0.125 */ | 511 | /* calculated gain: map 65..127 to 9..1024 step 0.125 */ |
591 | unsigned long gain = ((ctrl->value - qctrl->default_value - 1) * | 512 | unsigned long gain = ((ctrl->val - ctrl->default_value - 1) * |
592 | 1015 + range / 2) / range + 9; | 513 | 1015 + range / 2) / range + 9; |
593 | 514 | ||
594 | if (gain <= 32) /* calculated gain 9..32 -> 9..32 */ | 515 | if (gain <= 32) /* calculated gain 9..32 -> 9..32 */ |
@@ -605,19 +526,13 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
605 | if (data < 0) | 526 | if (data < 0) |
606 | return -EIO; | 527 | return -EIO; |
607 | } | 528 | } |
529 | return 0; | ||
608 | 530 | ||
609 | /* Success */ | 531 | case V4L2_CID_EXPOSURE_AUTO: |
610 | mt9t031->gain = ctrl->value; | 532 | if (ctrl->val == V4L2_EXPOSURE_MANUAL) { |
611 | break; | 533 | unsigned int range = exp->maximum - exp->minimum; |
612 | case V4L2_CID_EXPOSURE: | 534 | unsigned int shutter = ((exp->val - exp->minimum) * 1048 + |
613 | qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; | 535 | range / 2) / range + 1; |
614 | /* mt9t031 has maximum == default */ | ||
615 | if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) | ||
616 | return -EINVAL; | ||
617 | else { | ||
618 | const unsigned long range = qctrl->maximum - qctrl->minimum; | ||
619 | const u32 shutter = ((ctrl->value - qctrl->minimum) * 1048 + | ||
620 | range / 2) / range + 1; | ||
621 | u32 old; | 536 | u32 old; |
622 | 537 | ||
623 | get_shutter(client, &old); | 538 | get_shutter(client, &old); |
@@ -625,27 +540,15 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
625 | old, shutter); | 540 | old, shutter); |
626 | if (set_shutter(client, shutter) < 0) | 541 | if (set_shutter(client, shutter) < 0) |
627 | return -EIO; | 542 | return -EIO; |
628 | mt9t031->exposure = ctrl->value; | 543 | } else { |
629 | mt9t031->autoexposure = 0; | ||
630 | } | ||
631 | break; | ||
632 | case V4L2_CID_EXPOSURE_AUTO: | ||
633 | if (ctrl->value) { | ||
634 | const u16 vblank = MT9T031_VERTICAL_BLANK; | 544 | const u16 vblank = MT9T031_VERTICAL_BLANK; |
635 | const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; | 545 | mt9t031->total_h = mt9t031->rect.height + |
636 | unsigned int total_h = mt9t031->rect.height + | ||
637 | mt9t031->y_skip_top + vblank; | 546 | mt9t031->y_skip_top + vblank; |
638 | 547 | ||
639 | if (set_shutter(client, total_h) < 0) | 548 | if (set_shutter(client, mt9t031->total_h) < 0) |
640 | return -EIO; | 549 | return -EIO; |
641 | qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; | 550 | } |
642 | mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * | 551 | return 0; |
643 | (qctrl->maximum - qctrl->minimum)) / | ||
644 | shutter_max + qctrl->minimum; | ||
645 | mt9t031->autoexposure = 1; | ||
646 | } else | ||
647 | mt9t031->autoexposure = 0; | ||
648 | break; | ||
649 | default: | 552 | default: |
650 | return -EINVAL; | 553 | return -EINVAL; |
651 | } | 554 | } |
@@ -735,15 +638,12 @@ static int mt9t031_video_probe(struct i2c_client *client) | |||
735 | dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data); | 638 | dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data); |
736 | 639 | ||
737 | ret = mt9t031_idle(client); | 640 | ret = mt9t031_idle(client); |
738 | if (ret < 0) | 641 | if (ret < 0) { |
739 | dev_err(&client->dev, "Failed to initialise the camera\n"); | 642 | dev_err(&client->dev, "Failed to initialise the camera\n"); |
740 | else | 643 | } else { |
741 | vdev->dev.type = &mt9t031_dev_type; | 644 | vdev->dev.type = &mt9t031_dev_type; |
742 | 645 | v4l2_ctrl_handler_setup(&mt9t031->hdl); | |
743 | /* mt9t031_idle() has reset the chip to default. */ | 646 | } |
744 | mt9t031->exposure = 255; | ||
745 | mt9t031->gain = 64; | ||
746 | |||
747 | return ret; | 647 | return ret; |
748 | } | 648 | } |
749 | 649 | ||
@@ -757,9 +657,12 @@ static int mt9t031_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) | |||
757 | return 0; | 657 | return 0; |
758 | } | 658 | } |
759 | 659 | ||
660 | static const struct v4l2_ctrl_ops mt9t031_ctrl_ops = { | ||
661 | .g_volatile_ctrl = mt9t031_g_volatile_ctrl, | ||
662 | .s_ctrl = mt9t031_s_ctrl, | ||
663 | }; | ||
664 | |||
760 | static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { | 665 | static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { |
761 | .g_ctrl = mt9t031_g_ctrl, | ||
762 | .s_ctrl = mt9t031_s_ctrl, | ||
763 | .g_chip_ident = mt9t031_g_chip_ident, | 666 | .g_chip_ident = mt9t031_g_chip_ident, |
764 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 667 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
765 | .g_register = mt9t031_g_register, | 668 | .g_register = mt9t031_g_register, |
@@ -844,8 +747,6 @@ static int mt9t031_probe(struct i2c_client *client, | |||
844 | dev_err(&client->dev, "MT9T031 driver needs platform data\n"); | 747 | dev_err(&client->dev, "MT9T031 driver needs platform data\n"); |
845 | return -EINVAL; | 748 | return -EINVAL; |
846 | } | 749 | } |
847 | |||
848 | icd->ops = &mt9t031_ops; | ||
849 | } | 750 | } |
850 | 751 | ||
851 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { | 752 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { |
@@ -859,6 +760,33 @@ static int mt9t031_probe(struct i2c_client *client, | |||
859 | return -ENOMEM; | 760 | return -ENOMEM; |
860 | 761 | ||
861 | v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops); | 762 | v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops); |
763 | v4l2_ctrl_handler_init(&mt9t031->hdl, 5); | ||
764 | v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, | ||
765 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
766 | v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, | ||
767 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
768 | v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, | ||
769 | V4L2_CID_GAIN, 0, 127, 1, 64); | ||
770 | |||
771 | /* | ||
772 | * Simulated autoexposure. If enabled, we calculate shutter width | ||
773 | * ourselves in the driver based on vertical blanking and frame width | ||
774 | */ | ||
775 | mt9t031->autoexposure = v4l2_ctrl_new_std_menu(&mt9t031->hdl, | ||
776 | &mt9t031_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, | ||
777 | V4L2_EXPOSURE_AUTO); | ||
778 | mt9t031->exposure = v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, | ||
779 | V4L2_CID_EXPOSURE, 1, 255, 1, 255); | ||
780 | |||
781 | mt9t031->subdev.ctrl_handler = &mt9t031->hdl; | ||
782 | if (mt9t031->hdl.error) { | ||
783 | int err = mt9t031->hdl.error; | ||
784 | |||
785 | kfree(mt9t031); | ||
786 | return err; | ||
787 | } | ||
788 | v4l2_ctrl_auto_cluster(2, &mt9t031->autoexposure, | ||
789 | V4L2_EXPOSURE_MANUAL, true); | ||
862 | 790 | ||
863 | mt9t031->y_skip_top = 0; | 791 | mt9t031->y_skip_top = 0; |
864 | mt9t031->rect.left = MT9T031_COLUMN_SKIP; | 792 | mt9t031->rect.left = MT9T031_COLUMN_SKIP; |
@@ -866,12 +794,6 @@ static int mt9t031_probe(struct i2c_client *client, | |||
866 | mt9t031->rect.width = MT9T031_MAX_WIDTH; | 794 | mt9t031->rect.width = MT9T031_MAX_WIDTH; |
867 | mt9t031->rect.height = MT9T031_MAX_HEIGHT; | 795 | mt9t031->rect.height = MT9T031_MAX_HEIGHT; |
868 | 796 | ||
869 | /* | ||
870 | * Simulated autoexposure. If enabled, we calculate shutter width | ||
871 | * ourselves in the driver based on vertical blanking and frame width | ||
872 | */ | ||
873 | mt9t031->autoexposure = 1; | ||
874 | |||
875 | mt9t031->xskip = 1; | 797 | mt9t031->xskip = 1; |
876 | mt9t031->yskip = 1; | 798 | mt9t031->yskip = 1; |
877 | 799 | ||
@@ -882,8 +804,7 @@ static int mt9t031_probe(struct i2c_client *client, | |||
882 | mt9t031_disable(client); | 804 | mt9t031_disable(client); |
883 | 805 | ||
884 | if (ret) { | 806 | if (ret) { |
885 | if (icd) | 807 | v4l2_ctrl_handler_free(&mt9t031->hdl); |
886 | icd->ops = NULL; | ||
887 | kfree(mt9t031); | 808 | kfree(mt9t031); |
888 | } | 809 | } |
889 | 810 | ||
@@ -893,10 +814,9 @@ static int mt9t031_probe(struct i2c_client *client, | |||
893 | static int mt9t031_remove(struct i2c_client *client) | 814 | static int mt9t031_remove(struct i2c_client *client) |
894 | { | 815 | { |
895 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 816 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
896 | struct soc_camera_device *icd = client->dev.platform_data; | ||
897 | 817 | ||
898 | if (icd) | 818 | v4l2_device_unregister_subdev(&mt9t031->subdev); |
899 | icd->ops = NULL; | 819 | v4l2_ctrl_handler_free(&mt9t031->hdl); |
900 | kfree(mt9t031); | 820 | kfree(mt9t031); |
901 | 821 | ||
902 | return 0; | 822 | return 0; |