^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * video stream multiplexer controlled via mux control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2013 Pengutronix, Sascha Hauer <kernel@pengutronix.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2016-2017 Pengutronix, Philipp Zabel <kernel@pengutronix.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/mux/consumer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/of_graph.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <media/v4l2-async.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <media/v4l2-device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <media/v4l2-fwnode.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <media/v4l2-mc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <media/v4l2-subdev.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct video_mux {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct v4l2_subdev subdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct v4l2_async_notifier notifier;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) struct media_pad *pads;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct v4l2_mbus_framefmt *format_mbus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) struct mux_control *mux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct mutex lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) int active;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static const struct v4l2_mbus_framefmt video_mux_format_mbus_default = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) .width = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) .height = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) .code = MEDIA_BUS_FMT_Y8_1X8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) .field = V4L2_FIELD_NONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static inline struct video_mux *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) notifier_to_video_mux(struct v4l2_async_notifier *n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) return container_of(n, struct video_mux, notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static inline struct video_mux *v4l2_subdev_to_video_mux(struct v4l2_subdev *sd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) return container_of(sd, struct video_mux, subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static int video_mux_link_setup(struct media_entity *entity,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) const struct media_pad *local,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) const struct media_pad *remote, u32 flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct video_mux *vmux = v4l2_subdev_to_video_mux(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) u16 source_pad = entity->num_pads - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * The mux state is determined by the enabled sink pad link.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * Enabling or disabling the source pad link has no effect.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (local->flags & MEDIA_PAD_FL_SOURCE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) dev_dbg(sd->dev, "link setup '%s':%d->'%s':%d[%d]",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) remote->entity->name, remote->index, local->entity->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) local->index, flags & MEDIA_LNK_FL_ENABLED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) mutex_lock(&vmux->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) if (flags & MEDIA_LNK_FL_ENABLED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (vmux->active == local->index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if (vmux->active >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) ret = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) dev_dbg(sd->dev, "setting %d active\n", local->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) ret = mux_control_try_select(vmux->mux, local->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) vmux->active = local->index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) /* Propagate the active format to the source */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) vmux->format_mbus[source_pad] = vmux->format_mbus[vmux->active];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (vmux->active != local->index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) dev_dbg(sd->dev, "going inactive\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) mux_control_deselect(vmux->mux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) vmux->active = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) mutex_unlock(&vmux->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) static const struct media_entity_operations video_mux_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) .link_setup = video_mux_link_setup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) .link_validate = v4l2_subdev_link_validate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) .get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) static int video_mux_s_stream(struct v4l2_subdev *sd, int enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) struct video_mux *vmux = v4l2_subdev_to_video_mux(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) struct v4l2_subdev *upstream_sd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) struct media_pad *pad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (vmux->active == -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) dev_err(sd->dev, "Can not start streaming on inactive mux\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) pad = media_entity_remote_pad(&sd->entity.pads[vmux->active]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (!pad) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) dev_err(sd->dev, "Failed to find remote source pad\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) return -ENOLINK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (!is_media_entity_v4l2_subdev(pad->entity)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) dev_err(sd->dev, "Upstream entity is not a v4l2 subdev\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) upstream_sd = media_entity_to_v4l2_subdev(pad->entity);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) return v4l2_subdev_call(upstream_sd, video, s_stream, enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) static const struct v4l2_subdev_video_ops video_mux_subdev_video_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) .s_stream = video_mux_s_stream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) static struct v4l2_mbus_framefmt *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) __video_mux_get_pad_format(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) struct v4l2_subdev_pad_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) unsigned int pad, u32 which)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) struct video_mux *vmux = v4l2_subdev_to_video_mux(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) switch (which) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) case V4L2_SUBDEV_FORMAT_TRY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return v4l2_subdev_get_try_format(sd, cfg, pad);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) case V4L2_SUBDEV_FORMAT_ACTIVE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return &vmux->format_mbus[pad];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) static int video_mux_get_format(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) struct v4l2_subdev_pad_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) struct v4l2_subdev_format *sdformat)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) struct video_mux *vmux = v4l2_subdev_to_video_mux(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) mutex_lock(&vmux->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) sdformat->format = *__video_mux_get_pad_format(sd, cfg, sdformat->pad,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) sdformat->which);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) mutex_unlock(&vmux->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static int video_mux_set_format(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) struct v4l2_subdev_pad_config *cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) struct v4l2_subdev_format *sdformat)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) struct video_mux *vmux = v4l2_subdev_to_video_mux(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) struct v4l2_mbus_framefmt *mbusformat, *source_mbusformat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) struct media_pad *pad = &vmux->pads[sdformat->pad];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) u16 source_pad = sd->entity.num_pads - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) mbusformat = __video_mux_get_pad_format(sd, cfg, sdformat->pad,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) sdformat->which);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) if (!mbusformat)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) source_mbusformat = __video_mux_get_pad_format(sd, cfg, source_pad,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) sdformat->which);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if (!source_mbusformat)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) /* No size limitations except V4L2 compliance requirements */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) v4l_bound_align_image(&sdformat->format.width, 1, 65536, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) &sdformat->format.height, 1, 65536, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) /* All formats except LVDS and vendor specific formats are acceptable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) switch (sdformat->format.code) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) case MEDIA_BUS_FMT_RGB444_1X12:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) case MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) case MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) case MEDIA_BUS_FMT_RGB565_1X16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) case MEDIA_BUS_FMT_BGR565_2X8_BE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) case MEDIA_BUS_FMT_BGR565_2X8_LE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) case MEDIA_BUS_FMT_RGB565_2X8_BE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) case MEDIA_BUS_FMT_RGB565_2X8_LE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) case MEDIA_BUS_FMT_RGB666_1X18:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) case MEDIA_BUS_FMT_RBG888_1X24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) case MEDIA_BUS_FMT_BGR888_1X24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) case MEDIA_BUS_FMT_GBR888_1X24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) case MEDIA_BUS_FMT_RGB888_1X24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) case MEDIA_BUS_FMT_RGB888_2X12_BE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) case MEDIA_BUS_FMT_RGB888_2X12_LE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) case MEDIA_BUS_FMT_ARGB8888_1X32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) case MEDIA_BUS_FMT_RGB888_1X32_PADHI:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) case MEDIA_BUS_FMT_RGB101010_1X30:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) case MEDIA_BUS_FMT_RGB121212_1X36:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) case MEDIA_BUS_FMT_RGB161616_1X48:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) case MEDIA_BUS_FMT_Y8_1X8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) case MEDIA_BUS_FMT_UV8_1X8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) case MEDIA_BUS_FMT_UYVY8_1_5X8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) case MEDIA_BUS_FMT_VYUY8_1_5X8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) case MEDIA_BUS_FMT_YUYV8_1_5X8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) case MEDIA_BUS_FMT_YVYU8_1_5X8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) case MEDIA_BUS_FMT_UYVY8_2X8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) case MEDIA_BUS_FMT_VYUY8_2X8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) case MEDIA_BUS_FMT_YUYV8_2X8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) case MEDIA_BUS_FMT_YVYU8_2X8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) case MEDIA_BUS_FMT_Y10_1X10:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) case MEDIA_BUS_FMT_UYVY10_2X10:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) case MEDIA_BUS_FMT_VYUY10_2X10:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) case MEDIA_BUS_FMT_YUYV10_2X10:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) case MEDIA_BUS_FMT_YVYU10_2X10:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) case MEDIA_BUS_FMT_Y12_1X12:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) case MEDIA_BUS_FMT_UYVY12_2X12:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) case MEDIA_BUS_FMT_VYUY12_2X12:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) case MEDIA_BUS_FMT_YUYV12_2X12:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) case MEDIA_BUS_FMT_YVYU12_2X12:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) case MEDIA_BUS_FMT_UYVY8_1X16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) case MEDIA_BUS_FMT_VYUY8_1X16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) case MEDIA_BUS_FMT_YUYV8_1X16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) case MEDIA_BUS_FMT_YVYU8_1X16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) case MEDIA_BUS_FMT_YDYUYDYV8_1X16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) case MEDIA_BUS_FMT_UYVY10_1X20:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) case MEDIA_BUS_FMT_VYUY10_1X20:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) case MEDIA_BUS_FMT_YUYV10_1X20:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) case MEDIA_BUS_FMT_YVYU10_1X20:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) case MEDIA_BUS_FMT_VUY8_1X24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) case MEDIA_BUS_FMT_YUV8_1X24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) case MEDIA_BUS_FMT_UYVY12_1X24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) case MEDIA_BUS_FMT_VYUY12_1X24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) case MEDIA_BUS_FMT_YUYV12_1X24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) case MEDIA_BUS_FMT_YVYU12_1X24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) case MEDIA_BUS_FMT_YUV10_1X30:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) case MEDIA_BUS_FMT_AYUV8_1X32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) case MEDIA_BUS_FMT_YUV12_1X36:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) case MEDIA_BUS_FMT_YUV16_1X48:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) case MEDIA_BUS_FMT_JPEG_1X8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) case MEDIA_BUS_FMT_AHSV8888_1X32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) case MEDIA_BUS_FMT_SBGGR8_1X8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) case MEDIA_BUS_FMT_SGBRG8_1X8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) case MEDIA_BUS_FMT_SGRBG8_1X8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) case MEDIA_BUS_FMT_SRGGB8_1X8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) case MEDIA_BUS_FMT_SBGGR10_1X10:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) case MEDIA_BUS_FMT_SGBRG10_1X10:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) case MEDIA_BUS_FMT_SGRBG10_1X10:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) case MEDIA_BUS_FMT_SRGGB10_1X10:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) case MEDIA_BUS_FMT_SBGGR12_1X12:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) case MEDIA_BUS_FMT_SGBRG12_1X12:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) case MEDIA_BUS_FMT_SGRBG12_1X12:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) case MEDIA_BUS_FMT_SRGGB12_1X12:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) case MEDIA_BUS_FMT_SBGGR14_1X14:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) case MEDIA_BUS_FMT_SGBRG14_1X14:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) case MEDIA_BUS_FMT_SGRBG14_1X14:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) case MEDIA_BUS_FMT_SRGGB14_1X14:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) case MEDIA_BUS_FMT_SBGGR16_1X16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) case MEDIA_BUS_FMT_SGBRG16_1X16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) case MEDIA_BUS_FMT_SGRBG16_1X16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) case MEDIA_BUS_FMT_SRGGB16_1X16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) sdformat->format.code = MEDIA_BUS_FMT_Y8_1X8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) if (sdformat->format.field == V4L2_FIELD_ANY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) sdformat->format.field = V4L2_FIELD_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) mutex_lock(&vmux->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) /* Source pad mirrors active sink pad, no limitations on sink pads */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) if ((pad->flags & MEDIA_PAD_FL_SOURCE) && vmux->active >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) sdformat->format = vmux->format_mbus[vmux->active];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) *mbusformat = sdformat->format;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) /* Propagate the format from an active sink to source */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) if ((pad->flags & MEDIA_PAD_FL_SINK) && (pad->index == vmux->active))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) *source_mbusformat = sdformat->format;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) mutex_unlock(&vmux->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) static int video_mux_init_cfg(struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) struct v4l2_subdev_pad_config *cfg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) struct video_mux *vmux = v4l2_subdev_to_video_mux(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) struct v4l2_mbus_framefmt *mbusformat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) mutex_lock(&vmux->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) for (i = 0; i < sd->entity.num_pads; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) mbusformat = v4l2_subdev_get_try_format(sd, cfg, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) *mbusformat = video_mux_format_mbus_default;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) mutex_unlock(&vmux->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) static const struct v4l2_subdev_pad_ops video_mux_pad_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) .init_cfg = video_mux_init_cfg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) .get_fmt = video_mux_get_format,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) .set_fmt = video_mux_set_format,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) static const struct v4l2_subdev_ops video_mux_subdev_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) .pad = &video_mux_pad_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) .video = &video_mux_subdev_video_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) static int video_mux_notify_bound(struct v4l2_async_notifier *notifier,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) struct v4l2_subdev *sd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) struct v4l2_async_subdev *asd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) struct video_mux *vmux = notifier_to_video_mux(notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) return v4l2_create_fwnode_links(sd, &vmux->subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) static const struct v4l2_async_notifier_operations video_mux_notify_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) .bound = video_mux_notify_bound,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) static int video_mux_async_register(struct video_mux *vmux,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) unsigned int num_input_pads)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) v4l2_async_notifier_init(&vmux->notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) for (i = 0; i < num_input_pads; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) struct v4l2_async_subdev *asd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) struct fwnode_handle *ep, *remote_ep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) ep = fwnode_graph_get_endpoint_by_id(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) dev_fwnode(vmux->subdev.dev), i, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) FWNODE_GRAPH_ENDPOINT_NEXT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) if (!ep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) /* Skip dangling endpoints for backwards compatibility */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) remote_ep = fwnode_graph_get_remote_endpoint(ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) if (!remote_ep) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) fwnode_handle_put(ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) fwnode_handle_put(remote_ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) asd = v4l2_async_notifier_add_fwnode_remote_subdev(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) &vmux->notifier, ep, sizeof(*asd));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) fwnode_handle_put(ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) if (IS_ERR(asd)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) ret = PTR_ERR(asd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) /* OK if asd already exists */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) if (ret != -EEXIST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) vmux->notifier.ops = &video_mux_notify_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) ret = v4l2_async_subdev_notifier_register(&vmux->subdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) &vmux->notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) return v4l2_async_register_subdev(&vmux->subdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) static int video_mux_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) struct device_node *np = pdev->dev.of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) struct device_node *ep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) struct video_mux *vmux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) unsigned int num_pads = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) vmux = devm_kzalloc(dev, sizeof(*vmux), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) if (!vmux)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) platform_set_drvdata(pdev, vmux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) v4l2_subdev_init(&vmux->subdev, &video_mux_subdev_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) snprintf(vmux->subdev.name, sizeof(vmux->subdev.name), "%pOFn", np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) vmux->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) vmux->subdev.dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) * The largest numbered port is the output port. It determines
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) * total number of pads.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) for_each_endpoint_of_node(np, ep) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) struct of_endpoint endpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) of_graph_parse_endpoint(ep, &endpoint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) num_pads = max(num_pads, endpoint.port + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) if (num_pads < 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) dev_err(dev, "Not enough ports %d\n", num_pads);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) vmux->mux = devm_mux_control_get(dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) if (IS_ERR(vmux->mux)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) ret = PTR_ERR(vmux->mux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) if (ret != -EPROBE_DEFER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) dev_err(dev, "Failed to get mux: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) mutex_init(&vmux->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) vmux->active = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) vmux->pads = devm_kcalloc(dev, num_pads, sizeof(*vmux->pads),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) if (!vmux->pads)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) vmux->format_mbus = devm_kcalloc(dev, num_pads,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) sizeof(*vmux->format_mbus),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) if (!vmux->format_mbus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) for (i = 0; i < num_pads; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) vmux->pads[i].flags = (i < num_pads - 1) ? MEDIA_PAD_FL_SINK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) : MEDIA_PAD_FL_SOURCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) vmux->format_mbus[i] = video_mux_format_mbus_default;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) vmux->subdev.entity.function = MEDIA_ENT_F_VID_MUX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) ret = media_entity_pads_init(&vmux->subdev.entity, num_pads,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) vmux->pads);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) vmux->subdev.entity.ops = &video_mux_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) ret = video_mux_async_register(vmux, num_pads - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) v4l2_async_notifier_unregister(&vmux->notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) v4l2_async_notifier_cleanup(&vmux->notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) static int video_mux_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) struct video_mux *vmux = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) struct v4l2_subdev *sd = &vmux->subdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) v4l2_async_notifier_unregister(&vmux->notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) v4l2_async_notifier_cleanup(&vmux->notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) v4l2_async_unregister_subdev(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) media_entity_cleanup(&sd->entity);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) static const struct of_device_id video_mux_dt_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) { .compatible = "video-mux", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) { /* sentinel */ }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) MODULE_DEVICE_TABLE(of, video_mux_dt_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) static struct platform_driver video_mux_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) .probe = video_mux_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) .remove = video_mux_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) .of_match_table = video_mux_dt_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) .name = "video-mux",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) module_platform_driver(video_mux_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) MODULE_DESCRIPTION("video stream multiplexer");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) MODULE_AUTHOR("Sascha Hauer, Pengutronix");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) MODULE_AUTHOR("Philipp Zabel, Pengutronix");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) MODULE_LICENSE("GPL");