aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/media/platform/video-mux.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/video-mux.c')
-rw-r--r--drivers/media/platform/video-mux.c87
1 files changed, 66 insertions, 21 deletions
diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c
index ddd0e338f9e4..53570250a25d 100644
--- a/drivers/media/platform/video-mux.c
+++ b/drivers/media/platform/video-mux.c
@@ -17,10 +17,12 @@
#include <media/v4l2-async.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mc.h>
#include <media/v4l2-subdev.h>
struct video_mux {
struct v4l2_subdev subdev;
+ struct v4l2_async_notifier notifier;
struct media_pad *pads;
struct v4l2_mbus_framefmt *format_mbus;
struct mux_control *mux;
@@ -35,6 +37,12 @@ static const struct v4l2_mbus_framefmt video_mux_format_mbus_default = {
.field = V4L2_FIELD_NONE,
};
+static inline struct video_mux *
+notifier_to_video_mux(struct v4l2_async_notifier *n)
+{
+ return container_of(n, struct video_mux, notifier);
+}
+
static inline struct video_mux *v4l2_subdev_to_video_mux(struct v4l2_subdev *sd)
{
return container_of(sd, struct video_mux, subdev);
@@ -96,6 +104,7 @@ out:
static const struct media_entity_operations video_mux_ops = {
.link_setup = video_mux_link_setup,
.link_validate = v4l2_subdev_link_validate,
+ .get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1,
};
static int video_mux_s_stream(struct v4l2_subdev *sd, int enable)
@@ -330,36 +339,64 @@ static const struct v4l2_subdev_ops video_mux_subdev_ops = {
.video = &video_mux_subdev_video_ops,
};
-static int video_mux_parse_endpoint(struct device *dev,
- struct v4l2_fwnode_endpoint *vep,
- struct v4l2_async_subdev *asd)
+static int video_mux_notify_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd,
+ struct v4l2_async_subdev *asd)
{
- /*
- * it's not an error if remote is missing on a video-mux
- * input port, return -ENOTCONN to skip this endpoint with
- * no error.
- */
- return fwnode_device_is_available(asd->match.fwnode) ? 0 : -ENOTCONN;
+ struct video_mux *vmux = notifier_to_video_mux(notifier);
+
+ return v4l2_create_fwnode_links(sd, &vmux->subdev);
}
+static const struct v4l2_async_notifier_operations video_mux_notify_ops = {
+ .bound = video_mux_notify_bound,
+};
+
static int video_mux_async_register(struct video_mux *vmux,
unsigned int num_input_pads)
{
- unsigned int i, *ports;
+ unsigned int i;
int ret;
- ports = kcalloc(num_input_pads, sizeof(*ports), GFP_KERNEL);
- if (!ports)
- return -ENOMEM;
- for (i = 0; i < num_input_pads; i++)
- ports[i] = i;
+ v4l2_async_notifier_init(&vmux->notifier);
- ret = v4l2_async_register_fwnode_subdev(
- &vmux->subdev, sizeof(struct v4l2_async_subdev),
- ports, num_input_pads, video_mux_parse_endpoint);
+ for (i = 0; i < num_input_pads; i++) {
+ struct v4l2_async_subdev *asd;
+ struct fwnode_handle *ep;
- kfree(ports);
- return ret;
+ ep = fwnode_graph_get_endpoint_by_id(
+ dev_fwnode(vmux->subdev.dev), i, 0,
+ FWNODE_GRAPH_ENDPOINT_NEXT);
+ if (!ep)
+ continue;
+
+ asd = kzalloc(sizeof(*asd), GFP_KERNEL);
+ if (!asd) {
+ fwnode_handle_put(ep);
+ return -ENOMEM;
+ }
+
+ ret = v4l2_async_notifier_add_fwnode_remote_subdev(
+ &vmux->notifier, ep, asd);
+
+ fwnode_handle_put(ep);
+
+ if (ret) {
+ kfree(asd);
+ /* OK if asd already exists */
+ if (ret != -EEXIST)
+ return ret;
+ }
+ }
+
+ vmux->notifier.ops = &video_mux_notify_ops;
+
+ ret = v4l2_async_subdev_notifier_register(&vmux->subdev,
+ &vmux->notifier);
+ if (ret)
+ return ret;
+
+ return v4l2_async_register_subdev(&vmux->subdev);
}
static int video_mux_probe(struct platform_device *pdev)
@@ -434,7 +471,13 @@ static int video_mux_probe(struct platform_device *pdev)
vmux->subdev.entity.ops = &video_mux_ops;
- return video_mux_async_register(vmux, num_pads - 1);
+ ret = video_mux_async_register(vmux, num_pads - 1);
+ if (ret) {
+ v4l2_async_notifier_unregister(&vmux->notifier);
+ v4l2_async_notifier_cleanup(&vmux->notifier);
+ }
+
+ return ret;
}
static int video_mux_remove(struct platform_device *pdev)
@@ -442,6 +485,8 @@ static int video_mux_remove(struct platform_device *pdev)
struct video_mux *vmux = platform_get_drvdata(pdev);
struct v4l2_subdev *sd = &vmux->subdev;
+ v4l2_async_notifier_unregister(&vmux->notifier);
+ v4l2_async_notifier_cleanup(&vmux->notifier);
v4l2_async_unregister_subdev(sd);
media_entity_cleanup(&sd->entity);