diff options
Diffstat (limited to 'drivers/media/video/mt9v022.c')
-rw-r--r-- | drivers/media/video/mt9v022.c | 119 |
1 files changed, 60 insertions, 59 deletions
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index dbdcc86ae50d..959cc299f1ae 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c | |||
@@ -85,8 +85,6 @@ static const struct soc_camera_data_format mt9v022_monochrome_formats[] = { | |||
85 | }; | 85 | }; |
86 | 86 | ||
87 | struct mt9v022 { | 87 | struct mt9v022 { |
88 | struct i2c_client *client; | ||
89 | struct soc_camera_device icd; | ||
90 | int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ | 88 | int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ |
91 | u16 chip_control; | 89 | u16 chip_control; |
92 | }; | 90 | }; |
@@ -127,9 +125,9 @@ static int reg_clear(struct i2c_client *client, const u8 reg, | |||
127 | 125 | ||
128 | static int mt9v022_init(struct soc_camera_device *icd) | 126 | static int mt9v022_init(struct soc_camera_device *icd) |
129 | { | 127 | { |
130 | struct i2c_client *client = to_i2c_client(icd->control); | 128 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
131 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 129 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
132 | struct soc_camera_link *icl = client->dev.platform_data; | 130 | struct mt9v022 *mt9v022 = i2c_get_clientdata(client); |
133 | int ret; | 131 | int ret; |
134 | 132 | ||
135 | if (icl->power) { | 133 | if (icl->power) { |
@@ -173,19 +171,19 @@ static int mt9v022_init(struct soc_camera_device *icd) | |||
173 | 171 | ||
174 | static int mt9v022_release(struct soc_camera_device *icd) | 172 | static int mt9v022_release(struct soc_camera_device *icd) |
175 | { | 173 | { |
176 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 174 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
177 | struct soc_camera_link *icl = mt9v022->client->dev.platform_data; | 175 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
178 | 176 | ||
179 | if (icl->power) | 177 | if (icl->power) |
180 | icl->power(&mt9v022->client->dev, 0); | 178 | icl->power(&client->dev, 0); |
181 | 179 | ||
182 | return 0; | 180 | return 0; |
183 | } | 181 | } |
184 | 182 | ||
185 | static int mt9v022_start_capture(struct soc_camera_device *icd) | 183 | static int mt9v022_start_capture(struct soc_camera_device *icd) |
186 | { | 184 | { |
187 | struct i2c_client *client = to_i2c_client(icd->control); | 185 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
188 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 186 | struct mt9v022 *mt9v022 = i2c_get_clientdata(client); |
189 | /* Switch to master "normal" mode */ | 187 | /* Switch to master "normal" mode */ |
190 | mt9v022->chip_control &= ~0x10; | 188 | mt9v022->chip_control &= ~0x10; |
191 | if (reg_write(client, MT9V022_CHIP_CONTROL, | 189 | if (reg_write(client, MT9V022_CHIP_CONTROL, |
@@ -196,8 +194,8 @@ static int mt9v022_start_capture(struct soc_camera_device *icd) | |||
196 | 194 | ||
197 | static int mt9v022_stop_capture(struct soc_camera_device *icd) | 195 | static int mt9v022_stop_capture(struct soc_camera_device *icd) |
198 | { | 196 | { |
199 | struct i2c_client *client = to_i2c_client(icd->control); | 197 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
200 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 198 | struct mt9v022 *mt9v022 = i2c_get_clientdata(client); |
201 | /* Switch to snapshot mode */ | 199 | /* Switch to snapshot mode */ |
202 | mt9v022->chip_control |= 0x10; | 200 | mt9v022->chip_control |= 0x10; |
203 | if (reg_write(client, MT9V022_CHIP_CONTROL, | 201 | if (reg_write(client, MT9V022_CHIP_CONTROL, |
@@ -209,9 +207,9 @@ static int mt9v022_stop_capture(struct soc_camera_device *icd) | |||
209 | static int mt9v022_set_bus_param(struct soc_camera_device *icd, | 207 | static int mt9v022_set_bus_param(struct soc_camera_device *icd, |
210 | unsigned long flags) | 208 | unsigned long flags) |
211 | { | 209 | { |
212 | struct i2c_client *client = to_i2c_client(icd->control); | 210 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
213 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 211 | struct mt9v022 *mt9v022 = i2c_get_clientdata(client); |
214 | struct soc_camera_link *icl = client->dev.platform_data; | 212 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
215 | unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK; | 213 | unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK; |
216 | int ret; | 214 | int ret; |
217 | u16 pixclk = 0; | 215 | u16 pixclk = 0; |
@@ -263,8 +261,7 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd, | |||
263 | 261 | ||
264 | static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) | 262 | static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) |
265 | { | 263 | { |
266 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 264 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
267 | struct soc_camera_link *icl = mt9v022->client->dev.platform_data; | ||
268 | unsigned int width_flag; | 265 | unsigned int width_flag; |
269 | 266 | ||
270 | if (icl->query_bus_param) | 267 | if (icl->query_bus_param) |
@@ -283,7 +280,7 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) | |||
283 | static int mt9v022_set_crop(struct soc_camera_device *icd, | 280 | static int mt9v022_set_crop(struct soc_camera_device *icd, |
284 | struct v4l2_rect *rect) | 281 | struct v4l2_rect *rect) |
285 | { | 282 | { |
286 | struct i2c_client *client = to_i2c_client(icd->control); | 283 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
287 | int ret; | 284 | int ret; |
288 | 285 | ||
289 | /* Like in example app. Contradicts the datasheet though */ | 286 | /* Like in example app. Contradicts the datasheet though */ |
@@ -326,7 +323,8 @@ static int mt9v022_set_crop(struct soc_camera_device *icd, | |||
326 | static int mt9v022_set_fmt(struct soc_camera_device *icd, | 323 | static int mt9v022_set_fmt(struct soc_camera_device *icd, |
327 | struct v4l2_format *f) | 324 | struct v4l2_format *f) |
328 | { | 325 | { |
329 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 326 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
327 | struct mt9v022 *mt9v022 = i2c_get_clientdata(client); | ||
330 | struct v4l2_pix_format *pix = &f->fmt.pix; | 328 | struct v4l2_pix_format *pix = &f->fmt.pix; |
331 | struct v4l2_rect rect = { | 329 | struct v4l2_rect rect = { |
332 | .left = icd->x_current, | 330 | .left = icd->x_current, |
@@ -374,12 +372,13 @@ static int mt9v022_try_fmt(struct soc_camera_device *icd, | |||
374 | static int mt9v022_get_chip_id(struct soc_camera_device *icd, | 372 | static int mt9v022_get_chip_id(struct soc_camera_device *icd, |
375 | struct v4l2_dbg_chip_ident *id) | 373 | struct v4l2_dbg_chip_ident *id) |
376 | { | 374 | { |
377 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 375 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
376 | struct mt9v022 *mt9v022 = i2c_get_clientdata(client); | ||
378 | 377 | ||
379 | if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) | 378 | if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) |
380 | return -EINVAL; | 379 | return -EINVAL; |
381 | 380 | ||
382 | if (id->match.addr != mt9v022->client->addr) | 381 | if (id->match.addr != client->addr) |
383 | return -ENODEV; | 382 | return -ENODEV; |
384 | 383 | ||
385 | id->ident = mt9v022->model; | 384 | id->ident = mt9v022->model; |
@@ -392,7 +391,7 @@ static int mt9v022_get_chip_id(struct soc_camera_device *icd, | |||
392 | static int mt9v022_get_register(struct soc_camera_device *icd, | 391 | static int mt9v022_get_register(struct soc_camera_device *icd, |
393 | struct v4l2_dbg_register *reg) | 392 | struct v4l2_dbg_register *reg) |
394 | { | 393 | { |
395 | struct i2c_client *client = to_i2c_client(icd->control); | 394 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
396 | 395 | ||
397 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) | 396 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) |
398 | return -EINVAL; | 397 | return -EINVAL; |
@@ -412,7 +411,7 @@ static int mt9v022_get_register(struct soc_camera_device *icd, | |||
412 | static int mt9v022_set_register(struct soc_camera_device *icd, | 411 | static int mt9v022_set_register(struct soc_camera_device *icd, |
413 | struct v4l2_dbg_register *reg) | 412 | struct v4l2_dbg_register *reg) |
414 | { | 413 | { |
415 | struct i2c_client *client = to_i2c_client(icd->control); | 414 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
416 | 415 | ||
417 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) | 416 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) |
418 | return -EINVAL; | 417 | return -EINVAL; |
@@ -481,15 +480,11 @@ static const struct v4l2_queryctrl mt9v022_controls[] = { | |||
481 | } | 480 | } |
482 | }; | 481 | }; |
483 | 482 | ||
484 | static int mt9v022_video_probe(struct soc_camera_device *); | ||
485 | static void mt9v022_video_remove(struct soc_camera_device *); | ||
486 | static int mt9v022_get_control(struct soc_camera_device *, struct v4l2_control *); | 483 | static int mt9v022_get_control(struct soc_camera_device *, struct v4l2_control *); |
487 | static int mt9v022_set_control(struct soc_camera_device *, struct v4l2_control *); | 484 | static int mt9v022_set_control(struct soc_camera_device *, struct v4l2_control *); |
488 | 485 | ||
489 | static struct soc_camera_ops mt9v022_ops = { | 486 | static struct soc_camera_ops mt9v022_ops = { |
490 | .owner = THIS_MODULE, | 487 | .owner = THIS_MODULE, |
491 | .probe = mt9v022_video_probe, | ||
492 | .remove = mt9v022_video_remove, | ||
493 | .init = mt9v022_init, | 488 | .init = mt9v022_init, |
494 | .release = mt9v022_release, | 489 | .release = mt9v022_release, |
495 | .start_capture = mt9v022_start_capture, | 490 | .start_capture = mt9v022_start_capture, |
@@ -513,7 +508,7 @@ static struct soc_camera_ops mt9v022_ops = { | |||
513 | static int mt9v022_get_control(struct soc_camera_device *icd, | 508 | static int mt9v022_get_control(struct soc_camera_device *icd, |
514 | struct v4l2_control *ctrl) | 509 | struct v4l2_control *ctrl) |
515 | { | 510 | { |
516 | struct i2c_client *client = to_i2c_client(icd->control); | 511 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
517 | int data; | 512 | int data; |
518 | 513 | ||
519 | switch (ctrl->id) { | 514 | switch (ctrl->id) { |
@@ -549,7 +544,7 @@ static int mt9v022_set_control(struct soc_camera_device *icd, | |||
549 | struct v4l2_control *ctrl) | 544 | struct v4l2_control *ctrl) |
550 | { | 545 | { |
551 | int data; | 546 | int data; |
552 | struct i2c_client *client = to_i2c_client(icd->control); | 547 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
553 | const struct v4l2_queryctrl *qctrl; | 548 | const struct v4l2_queryctrl *qctrl; |
554 | 549 | ||
555 | qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); | 550 | qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); |
@@ -646,11 +641,11 @@ static int mt9v022_set_control(struct soc_camera_device *icd, | |||
646 | 641 | ||
647 | /* Interface active, can use i2c. If it fails, it can indeed mean, that | 642 | /* Interface active, can use i2c. If it fails, it can indeed mean, that |
648 | * this wasn't our capture interface, so, we wait for the right one */ | 643 | * this wasn't our capture interface, so, we wait for the right one */ |
649 | static int mt9v022_video_probe(struct soc_camera_device *icd) | 644 | static int mt9v022_video_probe(struct soc_camera_device *icd, |
645 | struct i2c_client *client) | ||
650 | { | 646 | { |
651 | struct i2c_client *client = to_i2c_client(icd->control); | 647 | struct mt9v022 *mt9v022 = i2c_get_clientdata(client); |
652 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 648 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
653 | struct soc_camera_link *icl = client->dev.platform_data; | ||
654 | s32 data; | 649 | s32 data; |
655 | int ret; | 650 | int ret; |
656 | unsigned long flags; | 651 | unsigned long flags; |
@@ -659,6 +654,11 @@ static int mt9v022_video_probe(struct soc_camera_device *icd) | |||
659 | to_soc_camera_host(icd->dev.parent)->nr != icd->iface) | 654 | to_soc_camera_host(icd->dev.parent)->nr != icd->iface) |
660 | return -ENODEV; | 655 | return -ENODEV; |
661 | 656 | ||
657 | /* Switch master clock on */ | ||
658 | ret = soc_camera_video_start(icd, &client->dev); | ||
659 | if (ret) | ||
660 | return ret; | ||
661 | |||
662 | /* Read out the chip version register */ | 662 | /* Read out the chip version register */ |
663 | data = reg_read(client, MT9V022_CHIP_VERSION); | 663 | data = reg_read(client, MT9V022_CHIP_VERSION); |
664 | 664 | ||
@@ -678,6 +678,8 @@ static int mt9v022_video_probe(struct soc_camera_device *icd) | |||
678 | udelay(200); | 678 | udelay(200); |
679 | if (reg_read(client, MT9V022_RESET)) { | 679 | if (reg_read(client, MT9V022_RESET)) { |
680 | dev_err(&icd->dev, "Resetting MT9V022 failed!\n"); | 680 | dev_err(&icd->dev, "Resetting MT9V022 failed!\n"); |
681 | if (ret > 0) | ||
682 | ret = -EIO; | ||
681 | goto ei2c; | 683 | goto ei2c; |
682 | } | 684 | } |
683 | 685 | ||
@@ -694,7 +696,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd) | |||
694 | } | 696 | } |
695 | 697 | ||
696 | if (ret < 0) | 698 | if (ret < 0) |
697 | goto eisis; | 699 | goto ei2c; |
698 | 700 | ||
699 | icd->num_formats = 0; | 701 | icd->num_formats = 0; |
700 | 702 | ||
@@ -716,29 +718,23 @@ static int mt9v022_video_probe(struct soc_camera_device *icd) | |||
716 | if (flags & SOCAM_DATAWIDTH_8) | 718 | if (flags & SOCAM_DATAWIDTH_8) |
717 | icd->num_formats++; | 719 | icd->num_formats++; |
718 | 720 | ||
719 | ret = soc_camera_video_start(icd); | ||
720 | if (ret < 0) | ||
721 | goto eisis; | ||
722 | |||
723 | dev_info(&icd->dev, "Detected a MT9V022 chip ID %x, %s sensor\n", | 721 | dev_info(&icd->dev, "Detected a MT9V022 chip ID %x, %s sensor\n", |
724 | data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ? | 722 | data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ? |
725 | "monochrome" : "colour"); | 723 | "monochrome" : "colour"); |
726 | 724 | ||
727 | return 0; | ||
728 | |||
729 | eisis: | ||
730 | ei2c: | 725 | ei2c: |
726 | soc_camera_video_stop(icd); | ||
727 | |||
731 | return ret; | 728 | return ret; |
732 | } | 729 | } |
733 | 730 | ||
734 | static void mt9v022_video_remove(struct soc_camera_device *icd) | 731 | static void mt9v022_video_remove(struct soc_camera_device *icd) |
735 | { | 732 | { |
736 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 733 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
737 | struct soc_camera_link *icl = mt9v022->client->dev.platform_data; | 734 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
738 | 735 | ||
739 | dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9v022->client->addr, | 736 | dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", client->addr, |
740 | icd->dev.parent, icd->vdev); | 737 | icd->dev.parent, icd->vdev); |
741 | soc_camera_video_stop(icd); | ||
742 | if (icl->free_bus) | 738 | if (icl->free_bus) |
743 | icl->free_bus(icl); | 739 | icl->free_bus(icl); |
744 | } | 740 | } |
@@ -747,11 +743,17 @@ static int mt9v022_probe(struct i2c_client *client, | |||
747 | const struct i2c_device_id *did) | 743 | const struct i2c_device_id *did) |
748 | { | 744 | { |
749 | struct mt9v022 *mt9v022; | 745 | struct mt9v022 *mt9v022; |
750 | struct soc_camera_device *icd; | 746 | struct soc_camera_device *icd = client->dev.platform_data; |
751 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 747 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
752 | struct soc_camera_link *icl = client->dev.platform_data; | 748 | struct soc_camera_link *icl; |
753 | int ret; | 749 | int ret; |
754 | 750 | ||
751 | if (!icd) { | ||
752 | dev_err(&client->dev, "MT9V022: missing soc-camera data!\n"); | ||
753 | return -EINVAL; | ||
754 | } | ||
755 | |||
756 | icl = to_soc_camera_link(icd); | ||
755 | if (!icl) { | 757 | if (!icl) { |
756 | dev_err(&client->dev, "MT9V022 driver needs platform data\n"); | 758 | dev_err(&client->dev, "MT9V022 driver needs platform data\n"); |
757 | return -EINVAL; | 759 | return -EINVAL; |
@@ -768,12 +770,9 @@ static int mt9v022_probe(struct i2c_client *client, | |||
768 | return -ENOMEM; | 770 | return -ENOMEM; |
769 | 771 | ||
770 | mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; | 772 | mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; |
771 | mt9v022->client = client; | ||
772 | i2c_set_clientdata(client, mt9v022); | 773 | i2c_set_clientdata(client, mt9v022); |
773 | 774 | ||
774 | icd = &mt9v022->icd; | ||
775 | icd->ops = &mt9v022_ops; | 775 | icd->ops = &mt9v022_ops; |
776 | icd->control = &client->dev; | ||
777 | icd->x_min = 1; | 776 | icd->x_min = 1; |
778 | icd->y_min = 4; | 777 | icd->y_min = 4; |
779 | icd->x_current = 1; | 778 | icd->x_current = 1; |
@@ -783,24 +782,26 @@ static int mt9v022_probe(struct i2c_client *client, | |||
783 | icd->height_min = 32; | 782 | icd->height_min = 32; |
784 | icd->height_max = 480; | 783 | icd->height_max = 480; |
785 | icd->y_skip_top = 1; | 784 | icd->y_skip_top = 1; |
786 | icd->iface = icl->bus_id; | ||
787 | |||
788 | ret = soc_camera_device_register(icd); | ||
789 | if (ret) | ||
790 | goto eisdr; | ||
791 | 785 | ||
792 | return 0; | 786 | ret = mt9v022_video_probe(icd, client); |
787 | if (ret) { | ||
788 | icd->ops = NULL; | ||
789 | i2c_set_clientdata(client, NULL); | ||
790 | kfree(mt9v022); | ||
791 | } | ||
793 | 792 | ||
794 | eisdr: | ||
795 | kfree(mt9v022); | ||
796 | return ret; | 793 | return ret; |
797 | } | 794 | } |
798 | 795 | ||
799 | static int mt9v022_remove(struct i2c_client *client) | 796 | static int mt9v022_remove(struct i2c_client *client) |
800 | { | 797 | { |
801 | struct mt9v022 *mt9v022 = i2c_get_clientdata(client); | 798 | struct mt9v022 *mt9v022 = i2c_get_clientdata(client); |
799 | struct soc_camera_device *icd = client->dev.platform_data; | ||
802 | 800 | ||
803 | soc_camera_device_unregister(&mt9v022->icd); | 801 | icd->ops = NULL; |
802 | mt9v022_video_remove(icd); | ||
803 | i2c_set_clientdata(client, NULL); | ||
804 | client->driver = NULL; | ||
804 | kfree(mt9v022); | 805 | kfree(mt9v022); |
805 | 806 | ||
806 | return 0; | 807 | return 0; |