xref: /linux/drivers/media/platform/rockchip/rkcif/rkcif-interface.c (revision 24f171c7e145f43b9f187578e89b0982ce87e54c)
185411d17SMichael Riesch // SPDX-License-Identifier: GPL-2.0
285411d17SMichael Riesch /*
385411d17SMichael Riesch  * Rockchip Camera Interface (CIF) Driver
485411d17SMichael Riesch  *
585411d17SMichael Riesch  * Copyright (C) 2025 Michael Riesch <michael.riesch@wolfvision.net>
685411d17SMichael Riesch  * Copyright (C) 2025 Collabora, Ltd.
785411d17SMichael Riesch  */
885411d17SMichael Riesch 
985411d17SMichael Riesch #include <media/v4l2-common.h>
1085411d17SMichael Riesch #include <media/v4l2-fwnode.h>
1185411d17SMichael Riesch #include <media/v4l2-mc.h>
1285411d17SMichael Riesch #include <media/v4l2-subdev.h>
1385411d17SMichael Riesch 
1485411d17SMichael Riesch #include "rkcif-common.h"
1585411d17SMichael Riesch #include "rkcif-interface.h"
1685411d17SMichael Riesch 
1785411d17SMichael Riesch static inline struct rkcif_interface *to_rkcif_interface(struct v4l2_subdev *sd)
1885411d17SMichael Riesch {
1985411d17SMichael Riesch 	return container_of(sd, struct rkcif_interface, sd);
2085411d17SMichael Riesch }
2185411d17SMichael Riesch 
2285411d17SMichael Riesch static const struct media_entity_operations rkcif_interface_media_ops = {
2385411d17SMichael Riesch 	.link_validate = v4l2_subdev_link_validate,
2485411d17SMichael Riesch 	.has_pad_interdep = v4l2_subdev_has_pad_interdep,
2585411d17SMichael Riesch };
2685411d17SMichael Riesch 
2785411d17SMichael Riesch static int rkcif_interface_set_fmt(struct v4l2_subdev *sd,
2885411d17SMichael Riesch 				   struct v4l2_subdev_state *state,
2985411d17SMichael Riesch 				   struct v4l2_subdev_format *format)
3085411d17SMichael Riesch {
3185411d17SMichael Riesch 	struct rkcif_interface *interface = to_rkcif_interface(sd);
3285411d17SMichael Riesch 	const struct rkcif_input_fmt *input;
3385411d17SMichael Riesch 	struct v4l2_mbus_framefmt *sink, *src;
3485411d17SMichael Riesch 	struct v4l2_rect *crop;
3585411d17SMichael Riesch 	u32 other_pad, other_stream;
3685411d17SMichael Riesch 	int ret;
3785411d17SMichael Riesch 
3885411d17SMichael Riesch 	/* the format on the source pad always matches the sink pad */
3985411d17SMichael Riesch 	if (format->pad == RKCIF_IF_PAD_SRC)
4085411d17SMichael Riesch 		return v4l2_subdev_get_fmt(sd, state, format);
4185411d17SMichael Riesch 
4285411d17SMichael Riesch 	input = rkcif_interface_find_input_fmt(interface, true,
4385411d17SMichael Riesch 					       format->format.code);
4485411d17SMichael Riesch 	format->format.code = input->mbus_code;
4585411d17SMichael Riesch 
4685411d17SMichael Riesch 	sink = v4l2_subdev_state_get_format(state, format->pad, format->stream);
4785411d17SMichael Riesch 	if (!sink)
4885411d17SMichael Riesch 		return -EINVAL;
4985411d17SMichael Riesch 
5085411d17SMichael Riesch 	*sink = format->format;
5185411d17SMichael Riesch 
5285411d17SMichael Riesch 	/* propagate the format to the source pad */
5385411d17SMichael Riesch 	src = v4l2_subdev_state_get_opposite_stream_format(state, format->pad,
5485411d17SMichael Riesch 							   format->stream);
5585411d17SMichael Riesch 	if (!src)
5685411d17SMichael Riesch 		return -EINVAL;
5785411d17SMichael Riesch 
5885411d17SMichael Riesch 	*src = *sink;
5985411d17SMichael Riesch 
6085411d17SMichael Riesch 	ret = v4l2_subdev_routing_find_opposite_end(&state->routing,
6185411d17SMichael Riesch 						    format->pad, format->stream,
6285411d17SMichael Riesch 						    &other_pad, &other_stream);
6385411d17SMichael Riesch 	if (ret)
6485411d17SMichael Riesch 		return -EINVAL;
6585411d17SMichael Riesch 
6685411d17SMichael Riesch 	crop = v4l2_subdev_state_get_crop(state, other_pad, other_stream);
6785411d17SMichael Riesch 	if (!crop)
6885411d17SMichael Riesch 		return -EINVAL;
6985411d17SMichael Riesch 
7085411d17SMichael Riesch 	/* reset crop */
7185411d17SMichael Riesch 	crop->left = 0;
7285411d17SMichael Riesch 	crop->top = 0;
7385411d17SMichael Riesch 	crop->width = sink->width;
7485411d17SMichael Riesch 	crop->height = sink->height;
7585411d17SMichael Riesch 
7685411d17SMichael Riesch 	return 0;
7785411d17SMichael Riesch }
7885411d17SMichael Riesch 
7985411d17SMichael Riesch static int rkcif_interface_get_sel(struct v4l2_subdev *sd,
8085411d17SMichael Riesch 				   struct v4l2_subdev_state *state,
8185411d17SMichael Riesch 				   struct v4l2_subdev_selection *sel)
8285411d17SMichael Riesch {
8385411d17SMichael Riesch 	struct v4l2_mbus_framefmt *sink;
8485411d17SMichael Riesch 	struct v4l2_rect *crop;
8585411d17SMichael Riesch 	int ret = 0;
8685411d17SMichael Riesch 
8785411d17SMichael Riesch 	if (sel->pad != RKCIF_IF_PAD_SRC)
8885411d17SMichael Riesch 		return -EINVAL;
8985411d17SMichael Riesch 
9085411d17SMichael Riesch 	sink = v4l2_subdev_state_get_opposite_stream_format(state, sel->pad,
9185411d17SMichael Riesch 							    sel->stream);
9285411d17SMichael Riesch 	if (!sink)
9385411d17SMichael Riesch 		return -EINVAL;
9485411d17SMichael Riesch 
9585411d17SMichael Riesch 	crop = v4l2_subdev_state_get_crop(state, sel->pad, sel->stream);
9685411d17SMichael Riesch 	if (!crop)
9785411d17SMichael Riesch 		return -EINVAL;
9885411d17SMichael Riesch 
9985411d17SMichael Riesch 	switch (sel->target) {
10085411d17SMichael Riesch 	case V4L2_SEL_TGT_CROP_DEFAULT:
10185411d17SMichael Riesch 	case V4L2_SEL_TGT_CROP_BOUNDS:
10285411d17SMichael Riesch 		sel->r.left = 0;
10385411d17SMichael Riesch 		sel->r.top = 0;
10485411d17SMichael Riesch 		sel->r.width = sink->width;
10585411d17SMichael Riesch 		sel->r.height = sink->height;
10685411d17SMichael Riesch 		break;
10785411d17SMichael Riesch 	case V4L2_SEL_TGT_CROP:
10885411d17SMichael Riesch 		sel->r = *crop;
10985411d17SMichael Riesch 		break;
11085411d17SMichael Riesch 	default:
11185411d17SMichael Riesch 		ret = -EINVAL;
11285411d17SMichael Riesch 	}
11385411d17SMichael Riesch 
11485411d17SMichael Riesch 	return ret;
11585411d17SMichael Riesch }
11685411d17SMichael Riesch 
11785411d17SMichael Riesch static int rkcif_interface_set_sel(struct v4l2_subdev *sd,
11885411d17SMichael Riesch 				   struct v4l2_subdev_state *state,
11985411d17SMichael Riesch 				   struct v4l2_subdev_selection *sel)
12085411d17SMichael Riesch {
12185411d17SMichael Riesch 	struct v4l2_mbus_framefmt *sink, *src;
12285411d17SMichael Riesch 	struct v4l2_rect *crop;
12385411d17SMichael Riesch 
12485411d17SMichael Riesch 	if (sel->pad != RKCIF_IF_PAD_SRC || sel->target != V4L2_SEL_TGT_CROP)
12585411d17SMichael Riesch 		return -EINVAL;
12685411d17SMichael Riesch 
12785411d17SMichael Riesch 	sink = v4l2_subdev_state_get_opposite_stream_format(state, sel->pad,
12885411d17SMichael Riesch 							    sel->stream);
12985411d17SMichael Riesch 	if (!sink)
13085411d17SMichael Riesch 		return -EINVAL;
13185411d17SMichael Riesch 
13285411d17SMichael Riesch 	src = v4l2_subdev_state_get_format(state, sel->pad, sel->stream);
13385411d17SMichael Riesch 	if (!src)
13485411d17SMichael Riesch 		return -EINVAL;
13585411d17SMichael Riesch 
13685411d17SMichael Riesch 	crop = v4l2_subdev_state_get_crop(state, sel->pad, sel->stream);
13785411d17SMichael Riesch 	if (!crop)
13885411d17SMichael Riesch 		return -EINVAL;
13985411d17SMichael Riesch 
14085411d17SMichael Riesch 	*crop = sel->r;
14185411d17SMichael Riesch 
14285411d17SMichael Riesch 	src->height = sel->r.height;
14385411d17SMichael Riesch 	src->width = sel->r.width;
14485411d17SMichael Riesch 
14585411d17SMichael Riesch 	return 0;
14685411d17SMichael Riesch }
14785411d17SMichael Riesch 
14885411d17SMichael Riesch static int rkcif_interface_set_routing(struct v4l2_subdev *sd,
14985411d17SMichael Riesch 				       struct v4l2_subdev_state *state,
15085411d17SMichael Riesch 				       enum v4l2_subdev_format_whence which,
15185411d17SMichael Riesch 				       struct v4l2_subdev_krouting *routing)
15285411d17SMichael Riesch {
15385411d17SMichael Riesch 	int ret;
15485411d17SMichael Riesch 
15585411d17SMichael Riesch 	ret = v4l2_subdev_routing_validate(sd, routing,
15685411d17SMichael Riesch 					   V4L2_SUBDEV_ROUTING_ONLY_1_TO_1);
15785411d17SMichael Riesch 	if (ret)
15885411d17SMichael Riesch 		return ret;
15985411d17SMichael Riesch 
160*501802e2SMichael Riesch 	for (unsigned int i = 0; i < routing->num_routes; i++) {
161*501802e2SMichael Riesch 		const struct v4l2_subdev_route *route = &routing->routes[i];
162*501802e2SMichael Riesch 
163*501802e2SMichael Riesch 		if (route->source_stream >= RKCIF_ID_MAX)
164*501802e2SMichael Riesch 			return -EINVAL;
165*501802e2SMichael Riesch 	}
166*501802e2SMichael Riesch 
16785411d17SMichael Riesch 	ret = v4l2_subdev_set_routing(sd, state, routing);
16885411d17SMichael Riesch 
16985411d17SMichael Riesch 	return ret;
17085411d17SMichael Riesch }
17185411d17SMichael Riesch 
172*501802e2SMichael Riesch static int rkcif_interface_apply_crop(struct rkcif_stream *stream,
173*501802e2SMichael Riesch 				      struct v4l2_subdev_state *state)
174*501802e2SMichael Riesch {
175*501802e2SMichael Riesch 	struct rkcif_interface *interface = stream->interface;
176*501802e2SMichael Riesch 	struct v4l2_rect *crop;
177*501802e2SMichael Riesch 
178*501802e2SMichael Riesch 	crop = v4l2_subdev_state_get_crop(state, RKCIF_IF_PAD_SRC, stream->id);
179*501802e2SMichael Riesch 	if (!crop)
180*501802e2SMichael Riesch 		return -EINVAL;
181*501802e2SMichael Riesch 
182*501802e2SMichael Riesch 	if (interface->set_crop)
183*501802e2SMichael Riesch 		interface->set_crop(stream, crop->left, crop->top);
184*501802e2SMichael Riesch 
185*501802e2SMichael Riesch 	return 0;
186*501802e2SMichael Riesch }
187*501802e2SMichael Riesch 
18885411d17SMichael Riesch static int rkcif_interface_enable_streams(struct v4l2_subdev *sd,
18985411d17SMichael Riesch 					  struct v4l2_subdev_state *state,
19085411d17SMichael Riesch 					  u32 pad, u64 streams_mask)
19185411d17SMichael Riesch {
192*501802e2SMichael Riesch 	struct rkcif_interface *interface = to_rkcif_interface(sd);
193*501802e2SMichael Riesch 	struct rkcif_stream *stream;
194*501802e2SMichael Riesch 	struct v4l2_subdev_route *route;
19585411d17SMichael Riesch 	struct v4l2_subdev *remote_sd;
19685411d17SMichael Riesch 	struct media_pad *remote_pad;
19785411d17SMichael Riesch 	u64 mask;
19885411d17SMichael Riesch 
19985411d17SMichael Riesch 	remote_pad =
20085411d17SMichael Riesch 		media_pad_remote_pad_first(&sd->entity.pads[RKCIF_IF_PAD_SINK]);
20185411d17SMichael Riesch 	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
20285411d17SMichael Riesch 
203*501802e2SMichael Riesch 	/* DVP has one crop setting for all IDs */
204*501802e2SMichael Riesch 	if (interface->type == RKCIF_IF_DVP) {
205*501802e2SMichael Riesch 		stream = &interface->streams[RKCIF_ID0];
206*501802e2SMichael Riesch 		rkcif_interface_apply_crop(stream, state);
207*501802e2SMichael Riesch 	} else {
208*501802e2SMichael Riesch 		for_each_active_route(&state->routing, route) {
209*501802e2SMichael Riesch 			stream = &interface->streams[route->sink_stream];
210*501802e2SMichael Riesch 			rkcif_interface_apply_crop(stream, state);
211*501802e2SMichael Riesch 		}
212*501802e2SMichael Riesch 	}
213*501802e2SMichael Riesch 
21485411d17SMichael Riesch 	mask = v4l2_subdev_state_xlate_streams(state, RKCIF_IF_PAD_SINK,
21585411d17SMichael Riesch 					       RKCIF_IF_PAD_SRC, &streams_mask);
21685411d17SMichael Riesch 
21785411d17SMichael Riesch 	return v4l2_subdev_enable_streams(remote_sd, remote_pad->index, mask);
21885411d17SMichael Riesch }
21985411d17SMichael Riesch 
22085411d17SMichael Riesch static int rkcif_interface_disable_streams(struct v4l2_subdev *sd,
22185411d17SMichael Riesch 					   struct v4l2_subdev_state *state,
22285411d17SMichael Riesch 					   u32 pad, u64 streams_mask)
22385411d17SMichael Riesch {
22485411d17SMichael Riesch 	struct v4l2_subdev *remote_sd;
22585411d17SMichael Riesch 	struct media_pad *remote_pad;
22685411d17SMichael Riesch 	u64 mask;
22785411d17SMichael Riesch 
22885411d17SMichael Riesch 	remote_pad =
22985411d17SMichael Riesch 		media_pad_remote_pad_first(&sd->entity.pads[RKCIF_IF_PAD_SINK]);
23085411d17SMichael Riesch 	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
23185411d17SMichael Riesch 
23285411d17SMichael Riesch 	mask = v4l2_subdev_state_xlate_streams(state, RKCIF_IF_PAD_SINK,
23385411d17SMichael Riesch 					       RKCIF_IF_PAD_SRC, &streams_mask);
23485411d17SMichael Riesch 
23585411d17SMichael Riesch 	return v4l2_subdev_disable_streams(remote_sd, remote_pad->index, mask);
23685411d17SMichael Riesch }
23785411d17SMichael Riesch 
23885411d17SMichael Riesch static const struct v4l2_subdev_pad_ops rkcif_interface_pad_ops = {
23985411d17SMichael Riesch 	.get_fmt = v4l2_subdev_get_fmt,
24085411d17SMichael Riesch 	.set_fmt = rkcif_interface_set_fmt,
24185411d17SMichael Riesch 	.get_selection = rkcif_interface_get_sel,
24285411d17SMichael Riesch 	.set_selection = rkcif_interface_set_sel,
24385411d17SMichael Riesch 	.set_routing = rkcif_interface_set_routing,
24485411d17SMichael Riesch 	.enable_streams = rkcif_interface_enable_streams,
24585411d17SMichael Riesch 	.disable_streams = rkcif_interface_disable_streams,
24685411d17SMichael Riesch };
24785411d17SMichael Riesch 
24885411d17SMichael Riesch static const struct v4l2_subdev_ops rkcif_interface_ops = {
24985411d17SMichael Riesch 	.pad = &rkcif_interface_pad_ops,
25085411d17SMichael Riesch };
25185411d17SMichael Riesch 
25285411d17SMichael Riesch static int rkcif_interface_init_state(struct v4l2_subdev *sd,
25385411d17SMichael Riesch 				      struct v4l2_subdev_state *state)
25485411d17SMichael Riesch {
25585411d17SMichael Riesch 	struct rkcif_interface *interface = to_rkcif_interface(sd);
25685411d17SMichael Riesch 	struct v4l2_subdev_route routes[] = {
25785411d17SMichael Riesch 		{
25885411d17SMichael Riesch 			.sink_pad = RKCIF_IF_PAD_SINK,
25985411d17SMichael Riesch 			.sink_stream = 0,
26085411d17SMichael Riesch 			.source_pad = RKCIF_IF_PAD_SRC,
26185411d17SMichael Riesch 			.source_stream = 0,
26285411d17SMichael Riesch 			.flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
26385411d17SMichael Riesch 		},
26485411d17SMichael Riesch 	};
26585411d17SMichael Riesch 	struct v4l2_subdev_krouting routing = {
26685411d17SMichael Riesch 		.len_routes = ARRAY_SIZE(routes),
26785411d17SMichael Riesch 		.num_routes = ARRAY_SIZE(routes),
26885411d17SMichael Riesch 		.routes = routes,
26985411d17SMichael Riesch 	};
27085411d17SMichael Riesch 	const struct v4l2_mbus_framefmt dvp_default_format = {
27185411d17SMichael Riesch 		.width = 3840,
27285411d17SMichael Riesch 		.height = 2160,
27385411d17SMichael Riesch 		.code = MEDIA_BUS_FMT_YUYV8_1X16,
27485411d17SMichael Riesch 		.field = V4L2_FIELD_NONE,
27585411d17SMichael Riesch 		.colorspace = V4L2_COLORSPACE_REC709,
27685411d17SMichael Riesch 		.ycbcr_enc = V4L2_YCBCR_ENC_709,
27785411d17SMichael Riesch 		.quantization = V4L2_QUANTIZATION_LIM_RANGE,
27885411d17SMichael Riesch 		.xfer_func = V4L2_XFER_FUNC_NONE,
27985411d17SMichael Riesch 	};
28085411d17SMichael Riesch 	const struct v4l2_mbus_framefmt mipi_default_format = {
28185411d17SMichael Riesch 		.width = 3840,
28285411d17SMichael Riesch 		.height = 2160,
28385411d17SMichael Riesch 		.code = MEDIA_BUS_FMT_SRGGB10_1X10,
28485411d17SMichael Riesch 		.field = V4L2_FIELD_NONE,
28585411d17SMichael Riesch 		.colorspace = V4L2_COLORSPACE_RAW,
28685411d17SMichael Riesch 		.ycbcr_enc = V4L2_YCBCR_ENC_601,
28785411d17SMichael Riesch 		.quantization = V4L2_QUANTIZATION_FULL_RANGE,
28885411d17SMichael Riesch 		.xfer_func = V4L2_XFER_FUNC_NONE,
28985411d17SMichael Riesch 	};
29085411d17SMichael Riesch 	const struct v4l2_mbus_framefmt *default_format;
29185411d17SMichael Riesch 	int ret;
29285411d17SMichael Riesch 
29385411d17SMichael Riesch 	default_format = (interface->type == RKCIF_IF_DVP) ?
29485411d17SMichael Riesch 				 &dvp_default_format :
29585411d17SMichael Riesch 				 &mipi_default_format;
29685411d17SMichael Riesch 
29785411d17SMichael Riesch 	ret = v4l2_subdev_set_routing_with_fmt(sd, state, &routing,
29885411d17SMichael Riesch 					       default_format);
29985411d17SMichael Riesch 
30085411d17SMichael Riesch 	return ret;
30185411d17SMichael Riesch }
30285411d17SMichael Riesch 
30385411d17SMichael Riesch static const struct v4l2_subdev_internal_ops rkcif_interface_internal_ops = {
30485411d17SMichael Riesch 	.init_state = rkcif_interface_init_state,
30585411d17SMichael Riesch };
30685411d17SMichael Riesch 
30785411d17SMichael Riesch static int rkcif_interface_add(struct rkcif_interface *interface)
30885411d17SMichael Riesch {
30985411d17SMichael Riesch 	struct rkcif_device *rkcif = interface->rkcif;
31085411d17SMichael Riesch 	struct rkcif_remote *remote;
31185411d17SMichael Riesch 	struct v4l2_async_notifier *ntf = &rkcif->notifier;
31285411d17SMichael Riesch 	struct v4l2_fwnode_endpoint *vep = &interface->vep;
31385411d17SMichael Riesch 	struct device *dev = rkcif->dev;
31485411d17SMichael Riesch 	struct fwnode_handle *ep;
31585411d17SMichael Riesch 	u32 dvp_clk_delay = 0;
31685411d17SMichael Riesch 	int ret;
31785411d17SMichael Riesch 
31885411d17SMichael Riesch 	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), interface->index,
31985411d17SMichael Riesch 					     0, 0);
32085411d17SMichael Riesch 	if (!ep)
32185411d17SMichael Riesch 		return -ENODEV;
32285411d17SMichael Riesch 
32385411d17SMichael Riesch 	vep->bus_type = V4L2_MBUS_UNKNOWN;
32485411d17SMichael Riesch 	ret = v4l2_fwnode_endpoint_parse(ep, vep);
32585411d17SMichael Riesch 	if (ret)
32685411d17SMichael Riesch 		goto complete;
32785411d17SMichael Riesch 
32885411d17SMichael Riesch 	if (interface->type == RKCIF_IF_DVP) {
32985411d17SMichael Riesch 		if (vep->bus_type != V4L2_MBUS_BT656 &&
33085411d17SMichael Riesch 		    vep->bus_type != V4L2_MBUS_PARALLEL) {
33185411d17SMichael Riesch 			ret = dev_err_probe(dev, -EINVAL,
33285411d17SMichael Riesch 					    "unsupported bus type\n");
33385411d17SMichael Riesch 			goto complete;
33485411d17SMichael Riesch 		}
33585411d17SMichael Riesch 
33685411d17SMichael Riesch 		fwnode_property_read_u32(ep, "rockchip,dvp-clk-delay",
33785411d17SMichael Riesch 					 &dvp_clk_delay);
33885411d17SMichael Riesch 		interface->dvp.dvp_clk_delay = dvp_clk_delay;
33985411d17SMichael Riesch 	}
34085411d17SMichael Riesch 
34185411d17SMichael Riesch 	remote = v4l2_async_nf_add_fwnode_remote(ntf, ep, struct rkcif_remote);
34285411d17SMichael Riesch 	if (IS_ERR(remote)) {
34385411d17SMichael Riesch 		ret = PTR_ERR(remote);
34485411d17SMichael Riesch 		goto complete;
34585411d17SMichael Riesch 	}
34685411d17SMichael Riesch 
34785411d17SMichael Riesch 	remote->interface = interface;
34885411d17SMichael Riesch 	interface->remote = remote;
34985411d17SMichael Riesch 	interface->status = RKCIF_IF_ACTIVE;
35085411d17SMichael Riesch 	ret = 0;
35185411d17SMichael Riesch 
35285411d17SMichael Riesch complete:
35385411d17SMichael Riesch 	fwnode_handle_put(ep);
35485411d17SMichael Riesch 
35585411d17SMichael Riesch 	return ret;
35685411d17SMichael Riesch }
35785411d17SMichael Riesch 
35885411d17SMichael Riesch int rkcif_interface_register(struct rkcif_device *rkcif,
35985411d17SMichael Riesch 			     struct rkcif_interface *interface)
36085411d17SMichael Riesch {
36185411d17SMichael Riesch 	struct media_pad *pads = interface->pads;
36285411d17SMichael Riesch 	struct v4l2_subdev *sd = &interface->sd;
36385411d17SMichael Riesch 	int ret;
36485411d17SMichael Riesch 
36585411d17SMichael Riesch 	interface->rkcif = rkcif;
36685411d17SMichael Riesch 
36785411d17SMichael Riesch 	v4l2_subdev_init(sd, &rkcif_interface_ops);
36885411d17SMichael Riesch 	sd->dev = rkcif->dev;
36985411d17SMichael Riesch 	sd->entity.ops = &rkcif_interface_media_ops;
37085411d17SMichael Riesch 	sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
37185411d17SMichael Riesch 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS;
37285411d17SMichael Riesch 	sd->internal_ops = &rkcif_interface_internal_ops;
37385411d17SMichael Riesch 	sd->owner = THIS_MODULE;
37485411d17SMichael Riesch 
37585411d17SMichael Riesch 	if (interface->type == RKCIF_IF_DVP)
37685411d17SMichael Riesch 		snprintf(sd->name, sizeof(sd->name), "rkcif-dvp0");
37785411d17SMichael Riesch 	else if (interface->type == RKCIF_IF_MIPI)
37885411d17SMichael Riesch 		snprintf(sd->name, sizeof(sd->name), "rkcif-mipi%d",
37985411d17SMichael Riesch 			 interface->index - RKCIF_MIPI_BASE);
38085411d17SMichael Riesch 
38185411d17SMichael Riesch 	pads[RKCIF_IF_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
38285411d17SMichael Riesch 	pads[RKCIF_IF_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
38385411d17SMichael Riesch 	ret = media_entity_pads_init(&sd->entity, RKCIF_IF_PAD_MAX, pads);
38485411d17SMichael Riesch 	if (ret)
38585411d17SMichael Riesch 		goto err;
38685411d17SMichael Riesch 
38785411d17SMichael Riesch 	ret = v4l2_subdev_init_finalize(sd);
38885411d17SMichael Riesch 	if (ret)
38985411d17SMichael Riesch 		goto err_entity_cleanup;
39085411d17SMichael Riesch 
39185411d17SMichael Riesch 	ret = v4l2_device_register_subdev(&rkcif->v4l2_dev, sd);
39285411d17SMichael Riesch 	if (ret) {
39385411d17SMichael Riesch 		dev_err(sd->dev, "failed to register subdev\n");
39485411d17SMichael Riesch 		goto err_subdev_cleanup;
39585411d17SMichael Riesch 	}
39685411d17SMichael Riesch 
39785411d17SMichael Riesch 	ret = rkcif_interface_add(interface);
39885411d17SMichael Riesch 	if (ret)
39985411d17SMichael Riesch 		goto err_subdev_unregister;
40085411d17SMichael Riesch 
40185411d17SMichael Riesch 	return 0;
40285411d17SMichael Riesch 
40385411d17SMichael Riesch err_subdev_unregister:
40485411d17SMichael Riesch 	v4l2_device_unregister_subdev(sd);
40585411d17SMichael Riesch err_subdev_cleanup:
40685411d17SMichael Riesch 	v4l2_subdev_cleanup(sd);
40785411d17SMichael Riesch err_entity_cleanup:
40885411d17SMichael Riesch 	media_entity_cleanup(&sd->entity);
40985411d17SMichael Riesch err:
41085411d17SMichael Riesch 	return ret;
41185411d17SMichael Riesch }
41285411d17SMichael Riesch 
41385411d17SMichael Riesch void rkcif_interface_unregister(struct rkcif_interface *interface)
41485411d17SMichael Riesch {
41585411d17SMichael Riesch 	struct v4l2_subdev *sd = &interface->sd;
41685411d17SMichael Riesch 
41785411d17SMichael Riesch 	if (interface->status != RKCIF_IF_ACTIVE)
41885411d17SMichael Riesch 		return;
41985411d17SMichael Riesch 
42085411d17SMichael Riesch 	v4l2_device_unregister_subdev(sd);
42185411d17SMichael Riesch 	v4l2_subdev_cleanup(sd);
42285411d17SMichael Riesch 	media_entity_cleanup(&sd->entity);
42385411d17SMichael Riesch }
42485411d17SMichael Riesch 
42585411d17SMichael Riesch const struct rkcif_input_fmt *
42685411d17SMichael Riesch rkcif_interface_find_input_fmt(struct rkcif_interface *interface, bool ret_def,
42785411d17SMichael Riesch 			       u32 mbus_code)
42885411d17SMichael Riesch {
42985411d17SMichael Riesch 	const struct rkcif_input_fmt *fmt;
43085411d17SMichael Riesch 
43185411d17SMichael Riesch 	WARN_ON(interface->in_fmts_num == 0);
43285411d17SMichael Riesch 
43385411d17SMichael Riesch 	for (unsigned int i = 0; i < interface->in_fmts_num; i++) {
43485411d17SMichael Riesch 		fmt = &interface->in_fmts[i];
43585411d17SMichael Riesch 		if (fmt->mbus_code == mbus_code)
43685411d17SMichael Riesch 			return fmt;
43785411d17SMichael Riesch 	}
43885411d17SMichael Riesch 	if (ret_def)
43985411d17SMichael Riesch 		return &interface->in_fmts[0];
44085411d17SMichael Riesch 	else
44185411d17SMichael Riesch 		return NULL;
44285411d17SMichael Riesch }
443