0001
0002
0003
0004
0005
0006
0007 #include <linux/fs.h>
0008 #include <linux/module.h>
0009 #include <linux/platform_device.h>
0010 #include <media/v4l2-async.h>
0011 #include <media/v4l2-event.h>
0012 #include <media/imx.h>
0013 #include "imx-media.h"
0014
0015 static inline struct imx_media_dev *notifier2dev(struct v4l2_async_notifier *n)
0016 {
0017 return container_of(n, struct imx_media_dev, notifier);
0018 }
0019
0020
0021 static int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
0022 struct v4l2_subdev *sd,
0023 struct v4l2_async_subdev *asd)
0024 {
0025 struct imx_media_dev *imxmd = notifier2dev(notifier);
0026 int ret;
0027
0028 if (sd->grp_id & IMX_MEDIA_GRP_ID_IPU_CSI) {
0029
0030 ret = imx_media_register_ipu_internal_subdevs(imxmd, sd);
0031 if (ret)
0032 return ret;
0033 }
0034
0035 dev_dbg(imxmd->md.dev, "subdev %s bound\n", sd->name);
0036
0037 return 0;
0038 }
0039
0040
0041 static int imx6_media_probe_complete(struct v4l2_async_notifier *notifier)
0042 {
0043 struct imx_media_dev *imxmd = notifier2dev(notifier);
0044 int ret;
0045
0046
0047 ret = imx_media_probe_complete(notifier);
0048 if (ret)
0049 return ret;
0050
0051 mutex_lock(&imxmd->mutex);
0052
0053 imxmd->m2m_vdev = imx_media_csc_scaler_device_init(imxmd);
0054 if (IS_ERR(imxmd->m2m_vdev)) {
0055 ret = PTR_ERR(imxmd->m2m_vdev);
0056 imxmd->m2m_vdev = NULL;
0057 goto unlock;
0058 }
0059
0060 ret = imx_media_csc_scaler_device_register(imxmd->m2m_vdev);
0061 unlock:
0062 mutex_unlock(&imxmd->mutex);
0063 return ret;
0064 }
0065
0066
0067 static const struct v4l2_async_notifier_operations imx_media_notifier_ops = {
0068 .bound = imx_media_subdev_bound,
0069 .complete = imx6_media_probe_complete,
0070 };
0071
0072 static int imx_media_probe(struct platform_device *pdev)
0073 {
0074 struct device *dev = &pdev->dev;
0075 struct device_node *node = dev->of_node;
0076 struct imx_media_dev *imxmd;
0077 int ret;
0078
0079 imxmd = imx_media_dev_init(dev, NULL);
0080 if (IS_ERR(imxmd))
0081 return PTR_ERR(imxmd);
0082
0083 ret = imx_media_add_of_subdevs(imxmd, node);
0084 if (ret) {
0085 v4l2_err(&imxmd->v4l2_dev,
0086 "add_of_subdevs failed with %d\n", ret);
0087 goto cleanup;
0088 }
0089
0090 ret = imx_media_dev_notifier_register(imxmd, &imx_media_notifier_ops);
0091 if (ret)
0092 goto cleanup;
0093
0094 return 0;
0095
0096 cleanup:
0097 v4l2_async_nf_cleanup(&imxmd->notifier);
0098 v4l2_device_unregister(&imxmd->v4l2_dev);
0099 media_device_cleanup(&imxmd->md);
0100
0101 return ret;
0102 }
0103
0104 static int imx_media_remove(struct platform_device *pdev)
0105 {
0106 struct imx_media_dev *imxmd =
0107 (struct imx_media_dev *)platform_get_drvdata(pdev);
0108
0109 v4l2_info(&imxmd->v4l2_dev, "Removing imx-media\n");
0110
0111 if (imxmd->m2m_vdev) {
0112 imx_media_csc_scaler_device_unregister(imxmd->m2m_vdev);
0113 imxmd->m2m_vdev = NULL;
0114 }
0115
0116 v4l2_async_nf_unregister(&imxmd->notifier);
0117 imx_media_unregister_ipu_internal_subdevs(imxmd);
0118 v4l2_async_nf_cleanup(&imxmd->notifier);
0119 media_device_unregister(&imxmd->md);
0120 v4l2_device_unregister(&imxmd->v4l2_dev);
0121 media_device_cleanup(&imxmd->md);
0122
0123 return 0;
0124 }
0125
0126 static const struct of_device_id imx_media_dt_ids[] = {
0127 { .compatible = "fsl,imx-capture-subsystem" },
0128 { }
0129 };
0130 MODULE_DEVICE_TABLE(of, imx_media_dt_ids);
0131
0132 static struct platform_driver imx_media_pdrv = {
0133 .probe = imx_media_probe,
0134 .remove = imx_media_remove,
0135 .driver = {
0136 .name = "imx-media",
0137 .of_match_table = imx_media_dt_ids,
0138 },
0139 };
0140
0141 module_platform_driver(imx_media_pdrv);
0142
0143 MODULE_DESCRIPTION("i.MX5/6 v4l2 media controller driver");
0144 MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
0145 MODULE_LICENSE("GPL");