diff options
Diffstat (limited to 'drivers/media/video/ov9640.c')
-rw-r--r-- | drivers/media/video/ov9640.c | 186 |
1 files changed, 60 insertions, 126 deletions
diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c index 3681a6ff081..a4f99797eb5 100644 --- a/drivers/media/video/ov9640.c +++ b/drivers/media/video/ov9640.c | |||
@@ -24,10 +24,13 @@ | |||
24 | #include <linux/i2c.h> | 24 | #include <linux/i2c.h> |
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
27 | #include <linux/v4l2-mediabus.h> | ||
27 | #include <linux/videodev2.h> | 28 | #include <linux/videodev2.h> |
29 | |||
30 | #include <media/soc_camera.h> | ||
28 | #include <media/v4l2-chip-ident.h> | 31 | #include <media/v4l2-chip-ident.h> |
29 | #include <media/v4l2-common.h> | 32 | #include <media/v4l2-common.h> |
30 | #include <media/soc_camera.h> | 33 | #include <media/v4l2-ctrls.h> |
31 | 34 | ||
32 | #include "ov9640.h" | 35 | #include "ov9640.h" |
33 | 36 | ||
@@ -162,27 +165,6 @@ static enum v4l2_mbus_pixelcode ov9640_codes[] = { | |||
162 | V4L2_MBUS_FMT_RGB565_2X8_LE, | 165 | V4L2_MBUS_FMT_RGB565_2X8_LE, |
163 | }; | 166 | }; |
164 | 167 | ||
165 | static const struct v4l2_queryctrl ov9640_controls[] = { | ||
166 | { | ||
167 | .id = V4L2_CID_VFLIP, | ||
168 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
169 | .name = "Flip Vertically", | ||
170 | .minimum = 0, | ||
171 | .maximum = 1, | ||
172 | .step = 1, | ||
173 | .default_value = 0, | ||
174 | }, | ||
175 | { | ||
176 | .id = V4L2_CID_HFLIP, | ||
177 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
178 | .name = "Flip Horizontally", | ||
179 | .minimum = 0, | ||
180 | .maximum = 1, | ||
181 | .step = 1, | ||
182 | .default_value = 0, | ||
183 | }, | ||
184 | }; | ||
185 | |||
186 | /* read a register */ | 168 | /* read a register */ |
187 | static int ov9640_reg_read(struct i2c_client *client, u8 reg, u8 *val) | 169 | static int ov9640_reg_read(struct i2c_client *client, u8 reg, u8 *val) |
188 | { | 170 | { |
@@ -284,75 +266,25 @@ static int ov9640_s_stream(struct v4l2_subdev *sd, int enable) | |||
284 | return 0; | 266 | return 0; |
285 | } | 267 | } |
286 | 268 | ||
287 | /* Alter bus settings on camera side */ | ||
288 | static int ov9640_set_bus_param(struct soc_camera_device *icd, | ||
289 | unsigned long flags) | ||
290 | { | ||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | /* Request bus settings on camera side */ | ||
295 | static unsigned long ov9640_query_bus_param(struct soc_camera_device *icd) | ||
296 | { | ||
297 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
298 | |||
299 | /* | ||
300 | * REVISIT: the camera probably can do 10 bit transfers, but I don't | ||
301 | * have those pins connected on my hardware. | ||
302 | */ | ||
303 | unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | | ||
304 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | | ||
305 | SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; | ||
306 | |||
307 | return soc_camera_apply_sensor_flags(icl, flags); | ||
308 | } | ||
309 | |||
310 | /* Get status of additional camera capabilities */ | ||
311 | static int ov9640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
312 | { | ||
313 | struct ov9640_priv *priv = to_ov9640_sensor(sd); | ||
314 | |||
315 | switch (ctrl->id) { | ||
316 | case V4L2_CID_VFLIP: | ||
317 | ctrl->value = priv->flag_vflip; | ||
318 | break; | ||
319 | case V4L2_CID_HFLIP: | ||
320 | ctrl->value = priv->flag_hflip; | ||
321 | break; | ||
322 | } | ||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | /* Set status of additional camera capabilities */ | 269 | /* Set status of additional camera capabilities */ |
327 | static int ov9640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 270 | static int ov9640_s_ctrl(struct v4l2_ctrl *ctrl) |
328 | { | 271 | { |
329 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 272 | struct ov9640_priv *priv = container_of(ctrl->handler, struct ov9640_priv, hdl); |
330 | struct ov9640_priv *priv = to_ov9640_sensor(sd); | 273 | struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); |
331 | |||
332 | int ret = 0; | ||
333 | 274 | ||
334 | switch (ctrl->id) { | 275 | switch (ctrl->id) { |
335 | case V4L2_CID_VFLIP: | 276 | case V4L2_CID_VFLIP: |
336 | priv->flag_vflip = ctrl->value; | 277 | if (ctrl->val) |
337 | if (ctrl->value) | 278 | return ov9640_reg_rmw(client, OV9640_MVFP, |
338 | ret = ov9640_reg_rmw(client, OV9640_MVFP, | ||
339 | OV9640_MVFP_V, 0); | 279 | OV9640_MVFP_V, 0); |
340 | else | 280 | return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_V); |
341 | ret = ov9640_reg_rmw(client, OV9640_MVFP, | ||
342 | 0, OV9640_MVFP_V); | ||
343 | break; | ||
344 | case V4L2_CID_HFLIP: | 281 | case V4L2_CID_HFLIP: |
345 | priv->flag_hflip = ctrl->value; | 282 | if (ctrl->val) |
346 | if (ctrl->value) | 283 | return ov9640_reg_rmw(client, OV9640_MVFP, |
347 | ret = ov9640_reg_rmw(client, OV9640_MVFP, | ||
348 | OV9640_MVFP_H, 0); | 284 | OV9640_MVFP_H, 0); |
349 | else | 285 | return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_H); |
350 | ret = ov9640_reg_rmw(client, OV9640_MVFP, | ||
351 | 0, OV9640_MVFP_H); | ||
352 | break; | ||
353 | } | 286 | } |
354 | 287 | return -EINVAL; | |
355 | return ret; | ||
356 | } | 288 | } |
357 | 289 | ||
358 | /* Get chip identification */ | 290 | /* Get chip identification */ |
@@ -646,10 +578,7 @@ static int ov9640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
646 | return 0; | 578 | return 0; |
647 | } | 579 | } |
648 | 580 | ||
649 | 581 | static int ov9640_video_probe(struct i2c_client *client) | |
650 | |||
651 | static int ov9640_video_probe(struct soc_camera_device *icd, | ||
652 | struct i2c_client *client) | ||
653 | { | 582 | { |
654 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 583 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
655 | struct ov9640_priv *priv = to_ov9640_sensor(sd); | 584 | struct ov9640_priv *priv = to_ov9640_sensor(sd); |
@@ -657,29 +586,19 @@ static int ov9640_video_probe(struct soc_camera_device *icd, | |||
657 | const char *devname; | 586 | const char *devname; |
658 | int ret = 0; | 587 | int ret = 0; |
659 | 588 | ||
660 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
661 | BUG_ON(!icd->parent || | ||
662 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
663 | |||
664 | /* | 589 | /* |
665 | * check and show product ID and manufacturer ID | 590 | * check and show product ID and manufacturer ID |
666 | */ | 591 | */ |
667 | 592 | ||
668 | ret = ov9640_reg_read(client, OV9640_PID, &pid); | 593 | ret = ov9640_reg_read(client, OV9640_PID, &pid); |
594 | if (!ret) | ||
595 | ret = ov9640_reg_read(client, OV9640_VER, &ver); | ||
596 | if (!ret) | ||
597 | ret = ov9640_reg_read(client, OV9640_MIDH, &midh); | ||
598 | if (!ret) | ||
599 | ret = ov9640_reg_read(client, OV9640_MIDL, &midl); | ||
669 | if (ret) | 600 | if (ret) |
670 | goto err; | 601 | return ret; |
671 | |||
672 | ret = ov9640_reg_read(client, OV9640_VER, &ver); | ||
673 | if (ret) | ||
674 | goto err; | ||
675 | |||
676 | ret = ov9640_reg_read(client, OV9640_MIDH, &midh); | ||
677 | if (ret) | ||
678 | goto err; | ||
679 | |||
680 | ret = ov9640_reg_read(client, OV9640_MIDL, &midl); | ||
681 | if (ret) | ||
682 | goto err; | ||
683 | 602 | ||
684 | switch (VERSION(pid, ver)) { | 603 | switch (VERSION(pid, ver)) { |
685 | case OV9640_V2: | 604 | case OV9640_V2: |
@@ -693,27 +612,20 @@ static int ov9640_video_probe(struct soc_camera_device *icd, | |||
693 | break; | 612 | break; |
694 | default: | 613 | default: |
695 | dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver); | 614 | dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver); |
696 | ret = -ENODEV; | 615 | return -ENODEV; |
697 | goto err; | ||
698 | } | 616 | } |
699 | 617 | ||
700 | dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", | 618 | dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", |
701 | devname, pid, ver, midh, midl); | 619 | devname, pid, ver, midh, midl); |
702 | 620 | ||
703 | err: | 621 | return v4l2_ctrl_handler_setup(&priv->hdl); |
704 | return ret; | ||
705 | } | 622 | } |
706 | 623 | ||
707 | static struct soc_camera_ops ov9640_ops = { | 624 | static const struct v4l2_ctrl_ops ov9640_ctrl_ops = { |
708 | .set_bus_param = ov9640_set_bus_param, | 625 | .s_ctrl = ov9640_s_ctrl, |
709 | .query_bus_param = ov9640_query_bus_param, | ||
710 | .controls = ov9640_controls, | ||
711 | .num_controls = ARRAY_SIZE(ov9640_controls), | ||
712 | }; | 626 | }; |
713 | 627 | ||
714 | static struct v4l2_subdev_core_ops ov9640_core_ops = { | 628 | static struct v4l2_subdev_core_ops ov9640_core_ops = { |
715 | .g_ctrl = ov9640_g_ctrl, | ||
716 | .s_ctrl = ov9640_s_ctrl, | ||
717 | .g_chip_ident = ov9640_g_chip_ident, | 629 | .g_chip_ident = ov9640_g_chip_ident, |
718 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 630 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
719 | .g_register = ov9640_get_register, | 631 | .g_register = ov9640_get_register, |
@@ -722,6 +634,22 @@ static struct v4l2_subdev_core_ops ov9640_core_ops = { | |||
722 | 634 | ||
723 | }; | 635 | }; |
724 | 636 | ||
637 | /* Request bus settings on camera side */ | ||
638 | static int ov9640_g_mbus_config(struct v4l2_subdev *sd, | ||
639 | struct v4l2_mbus_config *cfg) | ||
640 | { | ||
641 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
642 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
643 | |||
644 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | | ||
645 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | | ||
646 | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
647 | cfg->type = V4L2_MBUS_PARALLEL; | ||
648 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
649 | |||
650 | return 0; | ||
651 | } | ||
652 | |||
725 | static struct v4l2_subdev_video_ops ov9640_video_ops = { | 653 | static struct v4l2_subdev_video_ops ov9640_video_ops = { |
726 | .s_stream = ov9640_s_stream, | 654 | .s_stream = ov9640_s_stream, |
727 | .s_mbus_fmt = ov9640_s_fmt, | 655 | .s_mbus_fmt = ov9640_s_fmt, |
@@ -729,7 +657,7 @@ static struct v4l2_subdev_video_ops ov9640_video_ops = { | |||
729 | .enum_mbus_fmt = ov9640_enum_fmt, | 657 | .enum_mbus_fmt = ov9640_enum_fmt, |
730 | .cropcap = ov9640_cropcap, | 658 | .cropcap = ov9640_cropcap, |
731 | .g_crop = ov9640_g_crop, | 659 | .g_crop = ov9640_g_crop, |
732 | 660 | .g_mbus_config = ov9640_g_mbus_config, | |
733 | }; | 661 | }; |
734 | 662 | ||
735 | static struct v4l2_subdev_ops ov9640_subdev_ops = { | 663 | static struct v4l2_subdev_ops ov9640_subdev_ops = { |
@@ -744,16 +672,9 @@ static int ov9640_probe(struct i2c_client *client, | |||
744 | const struct i2c_device_id *did) | 672 | const struct i2c_device_id *did) |
745 | { | 673 | { |
746 | struct ov9640_priv *priv; | 674 | struct ov9640_priv *priv; |
747 | struct soc_camera_device *icd = client->dev.platform_data; | 675 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
748 | struct soc_camera_link *icl; | ||
749 | int ret; | 676 | int ret; |
750 | 677 | ||
751 | if (!icd) { | ||
752 | dev_err(&client->dev, "Missing soc-camera data!\n"); | ||
753 | return -EINVAL; | ||
754 | } | ||
755 | |||
756 | icl = to_soc_camera_link(icd); | ||
757 | if (!icl) { | 678 | if (!icl) { |
758 | dev_err(&client->dev, "Missing platform_data for driver\n"); | 679 | dev_err(&client->dev, "Missing platform_data for driver\n"); |
759 | return -EINVAL; | 680 | return -EINVAL; |
@@ -768,12 +689,23 @@ static int ov9640_probe(struct i2c_client *client, | |||
768 | 689 | ||
769 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops); | 690 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops); |
770 | 691 | ||
771 | icd->ops = &ov9640_ops; | 692 | v4l2_ctrl_handler_init(&priv->hdl, 2); |
693 | v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops, | ||
694 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
695 | v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops, | ||
696 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
697 | priv->subdev.ctrl_handler = &priv->hdl; | ||
698 | if (priv->hdl.error) { | ||
699 | int err = priv->hdl.error; | ||
700 | |||
701 | kfree(priv); | ||
702 | return err; | ||
703 | } | ||
772 | 704 | ||
773 | ret = ov9640_video_probe(icd, client); | 705 | ret = ov9640_video_probe(client); |
774 | 706 | ||
775 | if (ret) { | 707 | if (ret) { |
776 | icd->ops = NULL; | 708 | v4l2_ctrl_handler_free(&priv->hdl); |
777 | kfree(priv); | 709 | kfree(priv); |
778 | } | 710 | } |
779 | 711 | ||
@@ -785,6 +717,8 @@ static int ov9640_remove(struct i2c_client *client) | |||
785 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 717 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
786 | struct ov9640_priv *priv = to_ov9640_sensor(sd); | 718 | struct ov9640_priv *priv = to_ov9640_sensor(sd); |
787 | 719 | ||
720 | v4l2_device_unregister_subdev(&priv->subdev); | ||
721 | v4l2_ctrl_handler_free(&priv->hdl); | ||
788 | kfree(priv); | 722 | kfree(priv); |
789 | return 0; | 723 | return 0; |
790 | } | 724 | } |