Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * V4L2 Media Controller Driver for Freescale i.MX5/6 SOC
0004  *
0005  * Copyright (c) 2016-2019 Mentor Graphics Inc.
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 /* async subdev bound notifier */
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         /* register the IPU internal subdevs */
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 /* async subdev complete notifier */
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     /* call the imx5/6/7 common probe completion handler */
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 /* async subdev complete notifier */
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     { /* sentinel */ }
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");