107fc05bdSLad Prabhakar // SPDX-License-Identifier: GPL-2.0
207fc05bdSLad Prabhakar /*
307fc05bdSLad Prabhakar * Driver for Renesas RZ/G2L CRU
407fc05bdSLad Prabhakar *
507fc05bdSLad Prabhakar * Copyright (C) 2022 Renesas Electronics Corp.
607fc05bdSLad Prabhakar */
707fc05bdSLad Prabhakar
89c7fa014SBiju Das #include <linux/delay.h>
9b56dccafSLad Prabhakar #include <media/mipi-csi2.h>
10b56dccafSLad Prabhakar
1107fc05bdSLad Prabhakar #include "rzg2l-cru.h"
12c0fc8dd0SLad Prabhakar #include "rzg2l-cru-regs.h"
1307fc05bdSLad Prabhakar
1407fc05bdSLad Prabhakar static const struct rzg2l_cru_ip_format rzg2l_cru_ip_formats[] = {
15b56dccafSLad Prabhakar {
16b56dccafSLad Prabhakar .codes = {
17b56dccafSLad Prabhakar MEDIA_BUS_FMT_UYVY8_1X16,
188853467cSLad Prabhakar },
198853467cSLad Prabhakar .datatype = MIPI_CSI2_DT_YUV422_8B,
20c6ed80fdSLad Prabhakar .format = V4L2_PIX_FMT_UYVY,
212269e399SLad Prabhakar .icndmr = ICnDMR_YCMODE_UYVY,
22b56dccafSLad Prabhakar .yuv = true,
230477b086SLad Prabhakar },
240477b086SLad Prabhakar {
250477b086SLad Prabhakar .codes = {
260477b086SLad Prabhakar MEDIA_BUS_FMT_SBGGR8_1X8,
270477b086SLad Prabhakar },
280477b086SLad Prabhakar .format = V4L2_PIX_FMT_SBGGR8,
292269e399SLad Prabhakar .datatype = MIPI_CSI2_DT_RAW8,
300477b086SLad Prabhakar .icndmr = 0,
310477b086SLad Prabhakar .yuv = false,
320477b086SLad Prabhakar },
330477b086SLad Prabhakar {
340477b086SLad Prabhakar .codes = {
350477b086SLad Prabhakar MEDIA_BUS_FMT_SGBRG8_1X8,
360477b086SLad Prabhakar },
372269e399SLad Prabhakar .format = V4L2_PIX_FMT_SGBRG8,
380477b086SLad Prabhakar .datatype = MIPI_CSI2_DT_RAW8,
390477b086SLad Prabhakar .icndmr = 0,
400477b086SLad Prabhakar .yuv = false,
410477b086SLad Prabhakar },
420477b086SLad Prabhakar {
430477b086SLad Prabhakar .codes = {
440477b086SLad Prabhakar MEDIA_BUS_FMT_SGRBG8_1X8,
452269e399SLad Prabhakar },
460477b086SLad Prabhakar .format = V4L2_PIX_FMT_SGRBG8,
470477b086SLad Prabhakar .datatype = MIPI_CSI2_DT_RAW8,
480477b086SLad Prabhakar .icndmr = 0,
490477b086SLad Prabhakar .yuv = false,
500477b086SLad Prabhakar },
510477b086SLad Prabhakar {
520477b086SLad Prabhakar .codes = {
532269e399SLad Prabhakar MEDIA_BUS_FMT_SRGGB8_1X8,
540477b086SLad Prabhakar },
5507fc05bdSLad Prabhakar .format = V4L2_PIX_FMT_SRGGB8,
5607fc05bdSLad Prabhakar .datatype = MIPI_CSI2_DT_RAW8,
57b56dccafSLad Prabhakar .icndmr = 0,
5807fc05bdSLad Prabhakar .yuv = false,
5907fc05bdSLad Prabhakar },
6007fc05bdSLad Prabhakar {
6107fc05bdSLad Prabhakar .codes = {
6207fc05bdSLad Prabhakar MEDIA_BUS_FMT_SBGGR10_1X10,
6307fc05bdSLad Prabhakar MEDIA_BUS_FMT_SGBRG10_1X10,
6407fc05bdSLad Prabhakar MEDIA_BUS_FMT_SGRBG10_1X10,
6507fc05bdSLad Prabhakar MEDIA_BUS_FMT_SRGGB10_1X10
6607fc05bdSLad Prabhakar },
6707fc05bdSLad Prabhakar .format = V4L2_PIX_FMT_RAW_CRU10,
688853467cSLad Prabhakar .datatype = MIPI_CSI2_DT_RAW10,
698853467cSLad Prabhakar .icndmr = 0,
708853467cSLad Prabhakar .yuv = false,
718853467cSLad Prabhakar },
728853467cSLad Prabhakar {
738853467cSLad Prabhakar .codes = {
748853467cSLad Prabhakar MEDIA_BUS_FMT_SBGGR12_1X12,
758853467cSLad Prabhakar MEDIA_BUS_FMT_SGBRG12_1X12,
768853467cSLad Prabhakar MEDIA_BUS_FMT_SGRBG12_1X12,
778853467cSLad Prabhakar MEDIA_BUS_FMT_SRGGB12_1X12
788853467cSLad Prabhakar },
798853467cSLad Prabhakar .format = V4L2_PIX_FMT_RAW_CRU12,
808853467cSLad Prabhakar .datatype = MIPI_CSI2_DT_RAW12,
818853467cSLad Prabhakar .icndmr = 0,
828853467cSLad Prabhakar .yuv = false,
838853467cSLad Prabhakar },
848853467cSLad Prabhakar {
858853467cSLad Prabhakar .codes = {
868853467cSLad Prabhakar MEDIA_BUS_FMT_SBGGR14_1X14,
878853467cSLad Prabhakar MEDIA_BUS_FMT_SGBRG14_1X14,
8807fc05bdSLad Prabhakar MEDIA_BUS_FMT_SGRBG14_1X14,
8907fc05bdSLad Prabhakar MEDIA_BUS_FMT_SRGGB14_1X14
9007fc05bdSLad Prabhakar },
9107fc05bdSLad Prabhakar .format = V4L2_PIX_FMT_RAW_CRU14,
9207fc05bdSLad Prabhakar .datatype = MIPI_CSI2_DT_RAW14,
9307fc05bdSLad Prabhakar .icndmr = 0,
94bc0e8d91SSakari Ailus .yuv = false,
9507fc05bdSLad Prabhakar },
9607fc05bdSLad Prabhakar };
9707fc05bdSLad Prabhakar
rzg2l_cru_ip_code_to_fmt(unsigned int code)9807fc05bdSLad Prabhakar const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int code)
9907fc05bdSLad Prabhakar {
10007fc05bdSLad Prabhakar unsigned int i, j;
10107fc05bdSLad Prabhakar
10207fc05bdSLad Prabhakar for (i = 0; i < ARRAY_SIZE(rzg2l_cru_ip_formats); i++) {
10307fc05bdSLad Prabhakar for (j = 0; j < ARRAY_SIZE(rzg2l_cru_ip_formats[i].codes); j++) {
10407fc05bdSLad Prabhakar if (rzg2l_cru_ip_formats[i].codes[j] == code)
10507fc05bdSLad Prabhakar return &rzg2l_cru_ip_formats[i];
10607fc05bdSLad Prabhakar }
10707fc05bdSLad Prabhakar }
10807fc05bdSLad Prabhakar
10907fc05bdSLad Prabhakar return NULL;
11007fc05bdSLad Prabhakar }
11107fc05bdSLad Prabhakar
rzg2l_cru_ip_format_to_fmt(u32 format)11207fc05bdSLad Prabhakar const struct rzg2l_cru_ip_format *rzg2l_cru_ip_format_to_fmt(u32 format)
11307fc05bdSLad Prabhakar {
11407fc05bdSLad Prabhakar unsigned int i;
11507fc05bdSLad Prabhakar
11607fc05bdSLad Prabhakar for (i = 0; i < ARRAY_SIZE(rzg2l_cru_ip_formats); i++) {
11707fc05bdSLad Prabhakar if (rzg2l_cru_ip_formats[i].format == format)
11807fc05bdSLad Prabhakar return &rzg2l_cru_ip_formats[i];
11907fc05bdSLad Prabhakar }
12007fc05bdSLad Prabhakar
12107fc05bdSLad Prabhakar return NULL;
12207fc05bdSLad Prabhakar }
12307fc05bdSLad Prabhakar
rzg2l_cru_ip_index_to_fmt(u32 index)12407fc05bdSLad Prabhakar const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index)
12507fc05bdSLad Prabhakar {
1269c7fa014SBiju Das if (index >= ARRAY_SIZE(rzg2l_cru_ip_formats))
1279c7fa014SBiju Das return NULL;
12807fc05bdSLad Prabhakar
12907fc05bdSLad Prabhakar return &rzg2l_cru_ip_formats[index];
13007fc05bdSLad Prabhakar }
13107fc05bdSLad Prabhakar
rzg2l_cru_ip_fmt_supports_mbus_code(const struct rzg2l_cru_ip_format * fmt,unsigned int code)13207fc05bdSLad Prabhakar bool rzg2l_cru_ip_fmt_supports_mbus_code(const struct rzg2l_cru_ip_format *fmt,
13307fc05bdSLad Prabhakar unsigned int code)
13407fc05bdSLad Prabhakar {
135fdc7bd5bSBiju Das unsigned int i;
13607fc05bdSLad Prabhakar
13707fc05bdSLad Prabhakar for (i = 0; i < ARRAY_SIZE(fmt->codes); i++)
13807fc05bdSLad Prabhakar if (fmt->codes[i] == code)
13907fc05bdSLad Prabhakar return true;
14007fc05bdSLad Prabhakar
14107fc05bdSLad Prabhakar return false;
14207fc05bdSLad Prabhakar }
rzg2l_cru_ip_get_src_fmt(struct rzg2l_cru_dev * cru)14307fc05bdSLad Prabhakar struct v4l2_mbus_framefmt *rzg2l_cru_ip_get_src_fmt(struct rzg2l_cru_dev *cru)
14407fc05bdSLad Prabhakar {
14507fc05bdSLad Prabhakar struct v4l2_subdev_state *state;
14607fc05bdSLad Prabhakar struct v4l2_mbus_framefmt *fmt;
14707fc05bdSLad Prabhakar
14807fc05bdSLad Prabhakar state = v4l2_subdev_lock_and_get_active_state(&cru->ip.subdev);
14907fc05bdSLad Prabhakar fmt = v4l2_subdev_state_get_format(state, 1);
15007fc05bdSLad Prabhakar v4l2_subdev_unlock_state(state);
151*5f5ed645SLad Prabhakar
152*5f5ed645SLad Prabhakar return fmt;
15307fc05bdSLad Prabhakar }
15407fc05bdSLad Prabhakar
rzg2l_cru_ip_s_stream(struct v4l2_subdev * sd,int enable)15507fc05bdSLad Prabhakar static int rzg2l_cru_ip_s_stream(struct v4l2_subdev *sd, int enable)
156bc0e8d91SSakari Ailus {
15707fc05bdSLad Prabhakar struct rzg2l_cru_dev *cru;
15807fc05bdSLad Prabhakar int s_stream_ret = 0;
15907fc05bdSLad Prabhakar int ret;
16007fc05bdSLad Prabhakar
16107fc05bdSLad Prabhakar cru = v4l2_get_subdevdata(sd);
162bc0e8d91SSakari Ailus
16307fc05bdSLad Prabhakar if (!enable) {
16407fc05bdSLad Prabhakar ret = v4l2_subdev_call(cru->ip.remote, video, s_stream, enable);
16507fc05bdSLad Prabhakar if (ret)
16607fc05bdSLad Prabhakar s_stream_ret = ret;
16707fc05bdSLad Prabhakar
16807fc05bdSLad Prabhakar ret = v4l2_subdev_call(cru->ip.remote, video, post_streamoff);
16907fc05bdSLad Prabhakar if (ret == -ENOIOCTLCMD)
17007fc05bdSLad Prabhakar ret = 0;
17107fc05bdSLad Prabhakar if (ret && !s_stream_ret)
17207fc05bdSLad Prabhakar s_stream_ret = ret;
17307fc05bdSLad Prabhakar rzg2l_cru_stop_image_processing(cru);
17407fc05bdSLad Prabhakar } else {
175*5f5ed645SLad Prabhakar ret = v4l2_subdev_call(cru->ip.remote, video, pre_streamon, 0);
17607fc05bdSLad Prabhakar if (ret == -ENOIOCTLCMD)
177*5f5ed645SLad Prabhakar ret = 0;
17807fc05bdSLad Prabhakar if (ret)
17907fc05bdSLad Prabhakar return ret;
18007fc05bdSLad Prabhakar
18107fc05bdSLad Prabhakar fsleep(1000);
18207fc05bdSLad Prabhakar
18307fc05bdSLad Prabhakar ret = rzg2l_cru_start_image_processing(cru);
18407fc05bdSLad Prabhakar if (ret) {
18507fc05bdSLad Prabhakar v4l2_subdev_call(cru->ip.remote, video, post_streamoff);
18607fc05bdSLad Prabhakar return ret;
18707fc05bdSLad Prabhakar }
18807fc05bdSLad Prabhakar
18907fc05bdSLad Prabhakar ret = v4l2_subdev_call(cru->ip.remote, video, s_stream, enable);
19007fc05bdSLad Prabhakar if (!ret || ret == -ENOIOCTLCMD)
19107fc05bdSLad Prabhakar return 0;
19207fc05bdSLad Prabhakar
19307fc05bdSLad Prabhakar s_stream_ret = ret;
19407fc05bdSLad Prabhakar
19507fc05bdSLad Prabhakar v4l2_subdev_call(cru->ip.remote, video, post_streamoff);
19607fc05bdSLad Prabhakar rzg2l_cru_stop_image_processing(cru);
19707fc05bdSLad Prabhakar }
19807fc05bdSLad Prabhakar
19907fc05bdSLad Prabhakar return s_stream_ret;
20007fc05bdSLad Prabhakar }
20107fc05bdSLad Prabhakar
rzg2l_cru_ip_set_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * state,struct v4l2_subdev_format * fmt)202*5f5ed645SLad Prabhakar static int rzg2l_cru_ip_set_format(struct v4l2_subdev *sd,
203*5f5ed645SLad Prabhakar struct v4l2_subdev_state *state,
204*5f5ed645SLad Prabhakar struct v4l2_subdev_format *fmt)
20507fc05bdSLad Prabhakar {
20607fc05bdSLad Prabhakar struct rzg2l_cru_dev *cru = v4l2_get_subdevdata(sd);
20707fc05bdSLad Prabhakar const struct rzg2l_cru_info *info = cru->info;
208ec37ac1aSLad Prabhakar struct v4l2_mbus_framefmt *src_format;
20907fc05bdSLad Prabhakar struct v4l2_mbus_framefmt *sink_format;
21007fc05bdSLad Prabhakar
21107fc05bdSLad Prabhakar src_format = v4l2_subdev_state_get_format(state, RZG2L_CRU_IP_SOURCE);
21207fc05bdSLad Prabhakar if (fmt->pad == RZG2L_CRU_IP_SOURCE) {
213*5f5ed645SLad Prabhakar fmt->format = *src_format;
214*5f5ed645SLad Prabhakar return 0;
21507fc05bdSLad Prabhakar }
21607fc05bdSLad Prabhakar
21707fc05bdSLad Prabhakar sink_format = v4l2_subdev_state_get_format(state, fmt->pad);
21807fc05bdSLad Prabhakar
2195755be5fSLaurent Pinchart if (!rzg2l_cru_ip_code_to_fmt(fmt->format.code))
22007fc05bdSLad Prabhakar sink_format->code = rzg2l_cru_ip_formats[0].codes[0];
22107fc05bdSLad Prabhakar else
22207fc05bdSLad Prabhakar sink_format->code = fmt->format.code;
22307fc05bdSLad Prabhakar
22407fc05bdSLad Prabhakar sink_format->field = V4L2_FIELD_NONE;
22507fc05bdSLad Prabhakar sink_format->colorspace = fmt->format.colorspace;
22607fc05bdSLad Prabhakar sink_format->xfer_func = fmt->format.xfer_func;
22707fc05bdSLad Prabhakar sink_format->ycbcr_enc = fmt->format.ycbcr_enc;
22807fc05bdSLad Prabhakar sink_format->quantization = fmt->format.quantization;
22907fc05bdSLad Prabhakar sink_format->width = clamp_t(u32, fmt->format.width,
23007fc05bdSLad Prabhakar RZG2L_CRU_MIN_INPUT_WIDTH, info->max_width);
23107fc05bdSLad Prabhakar sink_format->height = clamp_t(u32, fmt->format.height,
23207fc05bdSLad Prabhakar RZG2L_CRU_MIN_INPUT_HEIGHT, info->max_height);
23307fc05bdSLad Prabhakar
23407fc05bdSLad Prabhakar fmt->format = *sink_format;
23507fc05bdSLad Prabhakar
23607fc05bdSLad Prabhakar /* propagate format to source pad */
23707fc05bdSLad Prabhakar *src_format = *sink_format;
23807fc05bdSLad Prabhakar
23907fc05bdSLad Prabhakar return 0;
24007fc05bdSLad Prabhakar }
24107fc05bdSLad Prabhakar
rzg2l_cru_ip_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * state,struct v4l2_subdev_mbus_code_enum * code)24207fc05bdSLad Prabhakar static int rzg2l_cru_ip_enum_mbus_code(struct v4l2_subdev *sd,
24307fc05bdSLad Prabhakar struct v4l2_subdev_state *state,
24407fc05bdSLad Prabhakar struct v4l2_subdev_mbus_code_enum *code)
24507fc05bdSLad Prabhakar {
24607fc05bdSLad Prabhakar unsigned int index = code->index;
24707fc05bdSLad Prabhakar unsigned int i, j;
24807fc05bdSLad Prabhakar
24907fc05bdSLad Prabhakar for (i = 0; i < ARRAY_SIZE(rzg2l_cru_ip_formats); i++) {
25007fc05bdSLad Prabhakar const struct rzg2l_cru_ip_format *fmt = &rzg2l_cru_ip_formats[i];
25107fc05bdSLad Prabhakar
2525755be5fSLaurent Pinchart for (j = 0; j < ARRAY_SIZE(fmt->codes); j++) {
2535755be5fSLaurent Pinchart if (!fmt->codes[j])
2545755be5fSLaurent Pinchart continue;
2555755be5fSLaurent Pinchart
25607fc05bdSLad Prabhakar if (!index) {
25707fc05bdSLad Prabhakar code->code = fmt->codes[j];
25807fc05bdSLad Prabhakar return 0;
25907fc05bdSLad Prabhakar }
26007fc05bdSLad Prabhakar
26107fc05bdSLad Prabhakar index--;
26207fc05bdSLad Prabhakar }
26307fc05bdSLad Prabhakar }
26407fc05bdSLad Prabhakar
26507fc05bdSLad Prabhakar return -EINVAL;
26607fc05bdSLad Prabhakar }
2675755be5fSLaurent Pinchart
rzg2l_cru_ip_enum_frame_size(struct v4l2_subdev * sd,struct v4l2_subdev_state * state,struct v4l2_subdev_frame_size_enum * fse)26807fc05bdSLad Prabhakar static int rzg2l_cru_ip_enum_frame_size(struct v4l2_subdev *sd,
26907fc05bdSLad Prabhakar struct v4l2_subdev_state *state,
27007fc05bdSLad Prabhakar struct v4l2_subdev_frame_size_enum *fse)
27107fc05bdSLad Prabhakar {
27207fc05bdSLad Prabhakar struct rzg2l_cru_dev *cru = v4l2_get_subdevdata(sd);
27307fc05bdSLad Prabhakar const struct rzg2l_cru_info *info = cru->info;
27407fc05bdSLad Prabhakar
27507fc05bdSLad Prabhakar if (fse->index != 0)
276ad982f85SLad Prabhakar return -EINVAL;
277ad982f85SLad Prabhakar
278ad982f85SLad Prabhakar if (!rzg2l_cru_ip_code_to_fmt(fse->code))
279ad982f85SLad Prabhakar return -EINVAL;
28007fc05bdSLad Prabhakar
28107fc05bdSLad Prabhakar fse->min_width = RZG2L_CRU_MIN_INPUT_WIDTH;
28207fc05bdSLad Prabhakar fse->min_height = RZG2L_CRU_MIN_INPUT_HEIGHT;
28307fc05bdSLad Prabhakar fse->max_width = info->max_width;
28407fc05bdSLad Prabhakar fse->max_height = info->max_height;
28507fc05bdSLad Prabhakar
28607fc05bdSLad Prabhakar return 0;
28707fc05bdSLad Prabhakar }
28807fc05bdSLad Prabhakar
rzg2l_cru_ip_init_state(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state)28907fc05bdSLad Prabhakar static int rzg2l_cru_ip_init_state(struct v4l2_subdev *sd,
29007fc05bdSLad Prabhakar struct v4l2_subdev_state *sd_state)
29107fc05bdSLad Prabhakar {
29207fc05bdSLad Prabhakar struct v4l2_subdev_format fmt = { .pad = RZG2L_CRU_IP_SINK, };
29307fc05bdSLad Prabhakar
29407fc05bdSLad Prabhakar fmt.format.width = RZG2L_CRU_MIN_INPUT_WIDTH;
29507fc05bdSLad Prabhakar fmt.format.height = RZG2L_CRU_MIN_INPUT_HEIGHT;
29607fc05bdSLad Prabhakar fmt.format.field = V4L2_FIELD_NONE;
29707fc05bdSLad Prabhakar fmt.format.code = MEDIA_BUS_FMT_UYVY8_1X16;
29807fc05bdSLad Prabhakar fmt.format.colorspace = V4L2_COLORSPACE_SRGB;
29907fc05bdSLad Prabhakar fmt.format.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
30007fc05bdSLad Prabhakar fmt.format.quantization = V4L2_QUANTIZATION_DEFAULT;
30107fc05bdSLad Prabhakar fmt.format.xfer_func = V4L2_XFER_FUNC_DEFAULT;
30207fc05bdSLad Prabhakar
30307fc05bdSLad Prabhakar return rzg2l_cru_ip_set_format(sd, sd_state, &fmt);
30407fc05bdSLad Prabhakar }
30507fc05bdSLad Prabhakar
30607fc05bdSLad Prabhakar static const struct v4l2_subdev_video_ops rzg2l_cru_ip_video_ops = {
30707fc05bdSLad Prabhakar .s_stream = rzg2l_cru_ip_s_stream,
30807fc05bdSLad Prabhakar };
30907fc05bdSLad Prabhakar
310 static const struct v4l2_subdev_pad_ops rzg2l_cru_ip_pad_ops = {
311 .enum_mbus_code = rzg2l_cru_ip_enum_mbus_code,
312 .enum_frame_size = rzg2l_cru_ip_enum_frame_size,
313 .get_fmt = v4l2_subdev_get_fmt,
314 .set_fmt = rzg2l_cru_ip_set_format,
315 };
316
317 static const struct v4l2_subdev_ops rzg2l_cru_ip_subdev_ops = {
318 .video = &rzg2l_cru_ip_video_ops,
319 .pad = &rzg2l_cru_ip_pad_ops,
320 };
321
322 static const struct v4l2_subdev_internal_ops rzg2l_cru_ip_internal_ops = {
323 .init_state = rzg2l_cru_ip_init_state,
324 };
325
326 static const struct media_entity_operations rzg2l_cru_ip_entity_ops = {
327 .link_validate = v4l2_subdev_link_validate,
328 };
329
rzg2l_cru_ip_subdev_register(struct rzg2l_cru_dev * cru)330 int rzg2l_cru_ip_subdev_register(struct rzg2l_cru_dev *cru)
331 {
332 struct rzg2l_cru_ip *ip = &cru->ip;
333 int ret;
334
335 ip->subdev.dev = cru->dev;
336 v4l2_subdev_init(&ip->subdev, &rzg2l_cru_ip_subdev_ops);
337 ip->subdev.internal_ops = &rzg2l_cru_ip_internal_ops;
338 v4l2_set_subdevdata(&ip->subdev, cru);
339 snprintf(ip->subdev.name, sizeof(ip->subdev.name),
340 "cru-ip-%s", dev_name(cru->dev));
341 ip->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
342
343 ip->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
344 ip->subdev.entity.ops = &rzg2l_cru_ip_entity_ops;
345
346 ip->pads[RZG2L_CRU_IP_SINK].flags = MEDIA_PAD_FL_SINK |
347 MEDIA_PAD_FL_MUST_CONNECT;
348 ip->pads[RZG2L_CRU_IP_SOURCE].flags = MEDIA_PAD_FL_SOURCE |
349 MEDIA_PAD_FL_MUST_CONNECT;
350
351 ret = media_entity_pads_init(&ip->subdev.entity, 2, ip->pads);
352 if (ret)
353 return ret;
354
355 ret = v4l2_subdev_init_finalize(&ip->subdev);
356 if (ret < 0)
357 goto entity_cleanup;
358
359 ret = v4l2_device_register_subdev(&cru->v4l2_dev, &ip->subdev);
360 if (ret < 0)
361 goto error_subdev;
362
363 return 0;
364 error_subdev:
365 v4l2_subdev_cleanup(&ip->subdev);
366 entity_cleanup:
367 media_entity_cleanup(&ip->subdev.entity);
368
369 return ret;
370 }
371
rzg2l_cru_ip_subdev_unregister(struct rzg2l_cru_dev * cru)372 void rzg2l_cru_ip_subdev_unregister(struct rzg2l_cru_dev *cru)
373 {
374 struct rzg2l_cru_ip *ip = &cru->ip;
375
376 media_entity_cleanup(&ip->subdev.entity);
377 v4l2_subdev_cleanup(&ip->subdev);
378 v4l2_device_unregister_subdev(&ip->subdev);
379 }
380