--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * V4L2 Media Controller Driver for Freescale common i.MX5/6/7 SOC
+ *
+ * Copyright (c) 2019 Linaro Ltd
+ * Copyright (c) 2016 Mentor Graphics Inc.
+ */
+
+#include <linux/of_graph.h>
+#include <linux/of_platform.h>
+#include "imx-media.h"
+
+static const struct v4l2_async_notifier_operations imx_media_subdev_ops = {
+ .bound = imx_media_subdev_bound,
+ .complete = imx_media_probe_complete,
+};
+
+static const struct media_device_ops imx_media_md_ops = {
+ .link_notify = imx_media_link_notify,
+};
+
+struct imx_media_dev *imx_media_dev_init(struct device *dev)
+{
+ struct imx_media_dev *imxmd;
+ int ret;
+
+ imxmd = devm_kzalloc(dev, sizeof(*imxmd), GFP_KERNEL);
+ if (!imxmd)
+ return ERR_PTR(-ENOMEM);
+
+ dev_set_drvdata(dev, imxmd);
+
+ strlcpy(imxmd->md.model, "imx-media", sizeof(imxmd->md.model));
+ imxmd->md.ops = &imx_media_md_ops;
+ imxmd->md.dev = dev;
+
+ mutex_init(&imxmd->mutex);
+
+ imxmd->v4l2_dev.mdev = &imxmd->md;
+ imxmd->v4l2_dev.notify = imx_media_notify;
+ strlcpy(imxmd->v4l2_dev.name, "imx-media",
+ sizeof(imxmd->v4l2_dev.name));
+
+ media_device_init(&imxmd->md);
+
+ ret = v4l2_device_register(dev, &imxmd->v4l2_dev);
+ if (ret < 0) {
+ v4l2_err(&imxmd->v4l2_dev,
+ "Failed to register v4l2_device: %d\n", ret);
+ goto cleanup;
+ }
+
+ dev_set_drvdata(imxmd->v4l2_dev.dev, imxmd);
+
+ INIT_LIST_HEAD(&imxmd->vdev_list);
+
+ v4l2_async_notifier_init(&imxmd->notifier);
+
+ return imxmd;
+
+cleanup:
+ media_device_cleanup(&imxmd->md);
+
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(imx_media_dev_init);
+
+int imx_media_dev_notifier_register(struct imx_media_dev *imxmd)
+{
+ int ret;
+
+ /* no subdevs? just bail */
+ if (list_empty(&imxmd->notifier.asd_list)) {
+ v4l2_err(&imxmd->v4l2_dev, "no subdevs\n");
+ return -ENODEV;
+ }
+
+ /* prepare the async subdev notifier and register it */
+ imxmd->notifier.ops = &imx_media_subdev_ops;
+ ret = v4l2_async_notifier_register(&imxmd->v4l2_dev,
+ &imxmd->notifier);
+ if (ret) {
+ v4l2_err(&imxmd->v4l2_dev,
+ "v4l2_async_notifier_register failed with %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(imx_media_dev_notifier_register);
}
/* async subdev bound notifier */
-static int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
- struct v4l2_subdev *sd,
- struct v4l2_async_subdev *asd)
+int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd,
+ struct v4l2_async_subdev *asd)
{
struct imx_media_dev *imxmd = notifier2dev(notifier);
int ret = 0;
}
/* async subdev complete notifier */
-static int imx_media_probe_complete(struct v4l2_async_notifier *notifier)
+int imx_media_probe_complete(struct v4l2_async_notifier *notifier)
{
struct imx_media_dev *imxmd = notifier2dev(notifier);
int ret;
return media_device_register(&imxmd->md);
}
-static const struct v4l2_async_notifier_operations imx_media_subdev_ops = {
- .bound = imx_media_subdev_bound,
- .complete = imx_media_probe_complete,
-};
-
/*
* adds controls to a video device from an entity subdevice.
* Continues upstream from the entity's sink pads.
return ret;
}
-static int imx_media_link_notify(struct media_link *link, u32 flags,
- unsigned int notification)
+int imx_media_link_notify(struct media_link *link, u32 flags,
+ unsigned int notification)
{
struct media_entity *source = link->source->entity;
struct imx_media_pad_vdev *pad_vdev;
return ret;
}
-static const struct media_device_ops imx_media_md_ops = {
- .link_notify = imx_media_link_notify,
-};
-
-static void imx_media_notify(struct v4l2_subdev *sd,
- unsigned int notification,
- void *arg)
+void imx_media_notify(struct v4l2_subdev *sd, unsigned int notification,
+ void *arg)
{
struct media_entity *entity = &sd->entity;
int i;
struct imx_media_dev *imxmd;
int ret;
- imxmd = devm_kzalloc(dev, sizeof(*imxmd), GFP_KERNEL);
- if (!imxmd)
- return -ENOMEM;
-
- dev_set_drvdata(dev, imxmd);
-
- strscpy(imxmd->md.model, "imx-media", sizeof(imxmd->md.model));
- imxmd->md.ops = &imx_media_md_ops;
- imxmd->md.dev = dev;
-
- mutex_init(&imxmd->mutex);
-
- imxmd->v4l2_dev.mdev = &imxmd->md;
- imxmd->v4l2_dev.notify = imx_media_notify;
- strscpy(imxmd->v4l2_dev.name, "imx-media",
- sizeof(imxmd->v4l2_dev.name));
-
- media_device_init(&imxmd->md);
-
- ret = v4l2_device_register(dev, &imxmd->v4l2_dev);
- if (ret < 0) {
- v4l2_err(&imxmd->v4l2_dev,
- "Failed to register v4l2_device: %d\n", ret);
- goto cleanup;
- }
-
- dev_set_drvdata(imxmd->v4l2_dev.dev, imxmd);
-
- INIT_LIST_HEAD(&imxmd->vdev_list);
-
- v4l2_async_notifier_init(&imxmd->notifier);
+ imxmd = imx_media_dev_init(dev);
+ if (IS_ERR(imxmd))
+ return PTR_ERR(imxmd);
ret = imx_media_add_of_subdevs(imxmd, node);
if (ret) {
v4l2_err(&imxmd->v4l2_dev,
"add_of_subdevs failed with %d\n", ret);
- goto notifier_cleanup;
+ goto cleanup;
}
ret = imx_media_add_internal_subdevs(imxmd);
if (ret) {
v4l2_err(&imxmd->v4l2_dev,
"add_internal_subdevs failed with %d\n", ret);
- goto notifier_cleanup;
- }
-
- /* no subdevs? just bail */
- if (list_empty(&imxmd->notifier.asd_list)) {
- ret = -ENODEV;
- goto notifier_cleanup;
+ goto cleanup;
}
- /* prepare the async subdev notifier and register it */
- imxmd->notifier.ops = &imx_media_subdev_ops;
- ret = v4l2_async_notifier_register(&imxmd->v4l2_dev,
- &imxmd->notifier);
- if (ret) {
- v4l2_err(&imxmd->v4l2_dev,
- "v4l2_async_notifier_register failed with %d\n", ret);
+ ret = imx_media_dev_notifier_register(imxmd);
+ if (ret)
goto del_int;
- }
return 0;
del_int:
imx_media_remove_internal_subdevs(imxmd);
-notifier_cleanup:
+cleanup:
v4l2_async_notifier_cleanup(&imxmd->notifier);
v4l2_device_unregister(&imxmd->v4l2_dev);
-cleanup:
media_device_cleanup(&imxmd->md);
+
return ret;
}
v4l2_async_notifier_unregister(&imxmd->notifier);
imx_media_remove_internal_subdevs(imxmd);
v4l2_async_notifier_cleanup(&imxmd->notifier);
- v4l2_device_unregister(&imxmd->v4l2_dev);
media_device_unregister(&imxmd->md);
+ v4l2_device_unregister(&imxmd->v4l2_dev);
media_device_cleanup(&imxmd->md);
return 0;
struct fwnode_handle *fwnode,
struct platform_device *pdev);
+int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd,
+ struct v4l2_async_subdev *asd);
+int imx_media_link_notify(struct media_link *link, u32 flags,
+ unsigned int notification);
+void imx_media_notify(struct v4l2_subdev *sd, unsigned int notification,
+ void *arg);
+int imx_media_probe_complete(struct v4l2_async_notifier *notifier);
+
+struct imx_media_dev *imx_media_dev_init(struct device *dev);
+int imx_media_dev_notifier_register(struct imx_media_dev *imxmd);
+
/* imx-media-fim.c */
struct imx_media_fim;
void imx_media_fim_eof_monitor(struct imx_media_fim *fim, ktime_t timestamp);
struct v4l2_subdev *sd);
int imx_media_create_csi_of_links(struct imx_media_dev *imxmd,
struct v4l2_subdev *csi);
+int imx_media_of_add_csi(struct imx_media_dev *imxmd,
+ struct device_node *csi_np);
/* imx-media-capture.c */
struct imx_media_video_dev *