• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */
3 
4 #include <linux/compat.h>
5 #include <linux/delay.h>
6 #include <linux/interrupt.h>
7 #include <linux/iommu.h>
8 #include <linux/pm_runtime.h>
9 #include <linux/videodev2.h>
10 #include <media/media-entity.h>
11 #include <media/videobuf2-dma-contig.h>
12 #include <media/v4l2-event.h>
13 
14 #include "dev.h"
15 #include "regs.h"
16 
cal_fec_mesh(u32 width,u32 height,u32 mode)17 u32 cal_fec_mesh(u32 width, u32 height, u32 mode)
18 {
19 	u32 mesh_size, mesh_left_height;
20 	u32 w = ALIGN(width, 32);
21 	u32 h = ALIGN(height, 32);
22 	u32 spb_num = (h + 127) >> 7;
23 	u32 left_height = h & 127;
24 	u32 mesh_width = mode ? (w / 32 + 1) : (w / 16 + 1);
25 	u32 mesh_height = mode ? 9 : 17;
26 
27 	if (!left_height)
28 		left_height = 128;
29 	mesh_left_height = mode ? (left_height / 16 + 1) :
30 				(left_height / 8 + 1);
31 	mesh_size = (spb_num - 1) * mesh_width * mesh_height +
32 		mesh_width * mesh_left_height;
33 
34 	return mesh_size;
35 }
36 
37 static const struct isppsd_fmt rkispp_formats[] = {
38 	{
39 		.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
40 		.fourcc = V4L2_PIX_FMT_NV16,
41 		.wr_fmt = FMT_YUV422,
42 	},
43 };
44 
find_fmt(u32 mbus_code)45 static const struct isppsd_fmt *find_fmt(u32 mbus_code)
46 {
47 	const struct isppsd_fmt *fmt;
48 	int i, array_size = ARRAY_SIZE(rkispp_formats);
49 
50 	for (i = 0; i < array_size; i++) {
51 		fmt = &rkispp_formats[i];
52 		if (fmt->mbus_code == mbus_code)
53 			return fmt;
54 	}
55 
56 	return NULL;
57 }
58 
rkispp_subdev_link_setup(struct media_entity * entity,const struct media_pad * local,const struct media_pad * remote,u32 flags)59 static int rkispp_subdev_link_setup(struct media_entity *entity,
60 				    const struct media_pad *local,
61 				    const struct media_pad *remote,
62 				    u32 flags)
63 {
64 	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
65 	struct rkispp_subdev *ispp_sdev;
66 	struct rkispp_device *dev;
67 	struct rkispp_stream_vdev *vdev;
68 	struct rkispp_stream *stream = NULL;
69 
70 	if (local->index != RKISPP_PAD_SINK &&
71 	    local->index != RKISPP_PAD_SOURCE)
72 		return 0;
73 
74 	if (!sd)
75 		return -ENODEV;
76 	ispp_sdev = v4l2_get_subdevdata(sd);
77 	dev = ispp_sdev->dev;
78 	vdev = &dev->stream_vdev;
79 
80 	if (!strcmp(remote->entity->name, II_VDEV_NAME)) {
81 		stream = &vdev->stream[STREAM_II];
82 		if (ispp_sdev->state & ISPP_START)
83 			return -EBUSY;
84 		if (flags & MEDIA_LNK_FL_ENABLED)
85 			dev->inp = INP_DDR;
86 		else if (ispp_sdev->remote_sd)
87 			dev->inp = INP_ISP;
88 		else
89 			dev->inp = INP_INVAL;
90 		stream->linked = flags & MEDIA_LNK_FL_ENABLED;
91 		v4l2_dbg(1, rkispp_debug, &dev->v4l2_dev,
92 			 "input:%d\n", dev->inp);
93 	} else if (!strcmp(remote->entity->name, MB_VDEV_NAME)) {
94 		stream = &vdev->stream[STREAM_MB];
95 	} else if (!strcmp(remote->entity->name, S0_VDEV_NAME)) {
96 		stream = &vdev->stream[STREAM_S0];
97 	} else if (!strcmp(remote->entity->name, S1_VDEV_NAME)) {
98 		stream = &vdev->stream[STREAM_S1];
99 	} else if (!strcmp(remote->entity->name, S2_VDEV_NAME)) {
100 		stream = &vdev->stream[STREAM_S2];
101 	}
102 	if (stream && dev->stream_sync) {
103 		stream->linked = flags & MEDIA_LNK_FL_ENABLED;
104 		v4l2_dbg(1, rkispp_debug, &dev->v4l2_dev,
105 			 "stream:%d linked:%d\n",
106 			 stream->id, stream->linked);
107 	}
108 	return 0;
109 }
110 
rkispp_sd_get_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * fmt)111 static int rkispp_sd_get_fmt(struct v4l2_subdev *sd,
112 			     struct v4l2_subdev_pad_config *cfg,
113 			     struct v4l2_subdev_format *fmt)
114 {
115 	struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
116 	struct v4l2_mbus_framefmt *mf;
117 	const struct isppsd_fmt *ispp_fmt;
118 	int ret = 0;
119 
120 	if (!fmt)
121 		goto err;
122 
123 	if (fmt->pad != RKISPP_PAD_SINK &&
124 	    fmt->pad != RKISPP_PAD_SOURCE)
125 		goto err;
126 
127 	mf = &fmt->format;
128 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
129 		if (!cfg)
130 			goto err;
131 		mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
132 	}
133 
134 	*mf = ispp_sdev->in_fmt;
135 	if (fmt->pad == RKISPP_PAD_SINK && ispp_sdev->dev->inp == INP_ISP) {
136 		ret = v4l2_subdev_call(ispp_sdev->remote_sd,
137 				       pad, get_fmt, cfg, fmt);
138 		if (!ret) {
139 			ispp_fmt = find_fmt(fmt->format.code);
140 			if (!ispp_fmt)
141 				goto err;
142 			ispp_sdev->in_fmt = *mf;
143 			ispp_sdev->out_fmt = *ispp_fmt;
144 		}
145 	} else if (fmt->pad == RKISPP_PAD_SOURCE) {
146 		*mf = ispp_sdev->in_fmt;
147 		mf->width = ispp_sdev->out_fmt.width;
148 		mf->height = ispp_sdev->out_fmt.height;
149 	}
150 	return ret;
151 err:
152 	return -EINVAL;
153 }
154 
rkispp_sd_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * fmt)155 static int rkispp_sd_set_fmt(struct v4l2_subdev *sd,
156 			     struct v4l2_subdev_pad_config *cfg,
157 			     struct v4l2_subdev_format *fmt)
158 {
159 	struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
160 	struct v4l2_mbus_framefmt *mf;
161 
162 	if (!fmt)
163 		return -EINVAL;
164 
165 	/* format from isp output */
166 	if (fmt->pad == RKISPP_PAD_SINK && ispp_sdev->dev->inp == INP_ISP)
167 		return 0;
168 
169 	mf = &fmt->format;
170 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
171 		if (!cfg)
172 			return -EINVAL;
173 		mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
174 	}
175 
176 	if (fmt->pad == RKISPP_PAD_SINK) {
177 		ispp_sdev->in_fmt = *mf;
178 	} else {
179 		ispp_sdev->out_fmt.width = mf->width;
180 		ispp_sdev->out_fmt.height = mf->height;
181 	}
182 
183 	return 0;
184 }
185 
rkispp_sd_get_selection(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_selection * sel)186 static int rkispp_sd_get_selection(struct v4l2_subdev *sd,
187 				   struct v4l2_subdev_pad_config *cfg,
188 				   struct v4l2_subdev_selection *sel)
189 {
190 	struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
191 	struct v4l2_rect *crop;
192 	int ret = 0;
193 
194 	if (!sel)
195 		goto err;
196 	if (sel->pad != RKISPP_PAD_SINK)
197 		goto err;
198 
199 	crop = &sel->r;
200 	if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
201 		if (!cfg)
202 			goto err;
203 		crop = v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
204 	}
205 
206 	if (ispp_sdev->dev->inp != INP_ISP) {
207 		crop->left = 0;
208 		crop->top = 0;
209 		crop->width = ispp_sdev->in_fmt.width;
210 		crop->height = ispp_sdev->in_fmt.height;
211 		return 0;
212 	}
213 
214 	ret = v4l2_subdev_call(ispp_sdev->remote_sd,
215 			pad, get_selection, cfg, sel);
216 	if (!ret && sel->target == V4L2_SEL_TGT_CROP) {
217 		ispp_sdev->out_fmt.width = crop->width;
218 		ispp_sdev->out_fmt.height = crop->height;
219 	}
220 
221 	return ret;
222 err:
223 	return -EINVAL;
224 }
225 
rkispp_sd_set_selection(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_selection * sel)226 static int rkispp_sd_set_selection(struct v4l2_subdev *sd,
227 				   struct v4l2_subdev_pad_config *cfg,
228 				   struct v4l2_subdev_selection *sel)
229 {
230 	struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
231 	struct v4l2_rect *crop;
232 	int ret = 0;
233 
234 	if (!sel)
235 		goto err;
236 	if (sel->pad != RKISPP_PAD_SINK ||
237 	    sel->target != V4L2_SEL_TGT_CROP)
238 		goto err;
239 
240 	crop = &sel->r;
241 	if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
242 		if (!cfg)
243 			goto err;
244 		crop = v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
245 	}
246 
247 	if (ispp_sdev->dev->inp != INP_ISP) {
248 		crop->left = 0;
249 		crop->top = 0;
250 		crop->width = ispp_sdev->in_fmt.width;
251 		crop->height = ispp_sdev->in_fmt.height;
252 		return 0;
253 	}
254 
255 	ret = v4l2_subdev_call(ispp_sdev->remote_sd,
256 			pad, set_selection, cfg, sel);
257 	if (!ret) {
258 		ispp_sdev->out_fmt.width = crop->width;
259 		ispp_sdev->out_fmt.height = crop->height;
260 	}
261 
262 	return ret;
263 err:
264 	return -EINVAL;
265 }
266 
rkispp_sd_s_stream(struct v4l2_subdev * sd,int on)267 static int rkispp_sd_s_stream(struct v4l2_subdev *sd, int on)
268 {
269 	struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
270 	struct rkispp_device *dev = ispp_sdev->dev;
271 	int ret = 0;
272 
273 	v4l2_dbg(1, rkispp_debug, &ispp_sdev->dev->v4l2_dev,
274 		 "s_stream on:%d\n", on);
275 
276 	if (on) {
277 		ispp_sdev->state = ISPP_START;
278 		ispp_sdev->frm_sync_seq = -1;
279 		ispp_sdev->frame_timestamp = 0;
280 		rkispp_event_handle(dev, CMD_STREAM, &ispp_sdev->state);
281 	}
282 
283 	if (dev->inp == INP_ISP)
284 		ret = v4l2_subdev_call(ispp_sdev->remote_sd, video, s_stream, on);
285 
286 	if ((on && ret) || (!on && !ret)) {
287 		ispp_sdev->state = ISPP_STOP;
288 		if (dev->stream_vdev.monitor.is_en) {
289 			dev->stream_vdev.monitor.is_en = false;
290 			if (!completion_done(&dev->stream_vdev.monitor.cmpl))
291 				complete(&dev->stream_vdev.monitor.cmpl);
292 			if (!completion_done(&dev->stream_vdev.monitor.tnr.cmpl))
293 				complete(&dev->stream_vdev.monitor.tnr.cmpl);
294 			if (!completion_done(&dev->stream_vdev.monitor.nr.cmpl))
295 				complete(&dev->stream_vdev.monitor.nr.cmpl);
296 			if (!completion_done(&dev->stream_vdev.monitor.fec.cmpl))
297 				complete(&dev->stream_vdev.monitor.fec.cmpl);
298 		}
299 		rkispp_event_handle(dev, CMD_STREAM, &ispp_sdev->state);
300 	}
301 	return ret;
302 }
303 
rkispp_sd_s_rx_buffer(struct v4l2_subdev * sd,void * buf,unsigned int * size)304 static int rkispp_sd_s_rx_buffer(struct v4l2_subdev *sd,
305 				 void *buf, unsigned int *size)
306 {
307 	struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
308 	struct rkispp_device *dev = ispp_sdev->dev;
309 	u32 cmd = CMD_INIT_POOL;
310 
311 	/* size isn't using now */
312 	if (!buf)
313 		return -EINVAL;
314 
315 	if (ispp_sdev->state == ISPP_START) {
316 		struct rkisp_ispp_buf *dbufs = buf;
317 		struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
318 		u64 ns = ktime_get_ns();
319 
320 		vdev->dbg.interval = ns - vdev->dbg.timestamp;
321 		vdev->dbg.timestamp = ns;
322 		vdev->dbg.delay = ns - dbufs->frame_timestamp;
323 		vdev->dbg.id = dbufs->frame_id;
324 		cmd = CMD_QUEUE_DMABUF;
325 	}
326 
327 	return rkispp_event_handle(dev, cmd, buf);
328 }
329 
rkispp_sd_s_power(struct v4l2_subdev * sd,int on)330 static int rkispp_sd_s_power(struct v4l2_subdev *sd, int on)
331 {
332 	struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
333 	struct rkispp_device *ispp_dev = ispp_sdev->dev;
334 	int ret;
335 
336 	v4l2_dbg(1, rkispp_debug, &ispp_dev->v4l2_dev,
337 		 "s_power on:%d\n", on);
338 	if (on) {
339 		if (ispp_dev->inp == INP_ISP) {
340 			struct v4l2_subdev_format fmt;
341 			struct v4l2_subdev_selection sel;
342 
343 			/* update format, if ispp input change */
344 			fmt.pad = RKISPP_PAD_SINK;
345 			fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
346 			ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt);
347 			if (ret) {
348 				v4l2_err(&ispp_dev->v4l2_dev,
349 					 "%s get format fail:%d\n",
350 					 __func__, ret);
351 				return ret;
352 			}
353 			sel.pad = RKISPP_PAD_SINK;
354 			sel.target = V4L2_SEL_TGT_CROP;
355 			sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
356 			ret = v4l2_subdev_call(sd, pad,
357 				get_selection, NULL, &sel);
358 			if (ret) {
359 				v4l2_err(&ispp_dev->v4l2_dev,
360 					 "%s get crop fail:%d\n",
361 					 __func__, ret);
362 				return ret;
363 			}
364 
365 			ret = v4l2_subdev_call(ispp_sdev->remote_sd,
366 					       core, s_power, 1);
367 			if (ret < 0) {
368 				v4l2_err(&ispp_dev->v4l2_dev,
369 					 "%s set isp power on fail:%d\n",
370 					 __func__, ret);
371 				return ret;
372 			}
373 		}
374 		ret = pm_runtime_get_sync(ispp_dev->dev);
375 		if (ret < 0) {
376 			v4l2_err(&ispp_dev->v4l2_dev,
377 				 "%s runtime get failed:%d\n",
378 				 __func__, ret);
379 			if (ispp_dev->inp == INP_ISP)
380 				v4l2_subdev_call(ispp_sdev->remote_sd,
381 						 core, s_power, 0);
382 			return ret;
383 		}
384 	} else {
385 		if (ispp_dev->inp == INP_ISP)
386 			v4l2_subdev_call(ispp_sdev->remote_sd, core, s_power, 0);
387 		ret = pm_runtime_put_sync(ispp_dev->dev);
388 		if (ret < 0)
389 			v4l2_err(&ispp_dev->v4l2_dev,
390 				 "%s runtime put failed:%d\n",
391 				 __func__, ret);
392 	}
393 
394 	return ret;
395 }
396 
rkispp_ioctl(struct v4l2_subdev * sd,unsigned int cmd,void * arg)397 static long rkispp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
398 {
399 	struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
400 	struct rkispp_device *ispp_dev = ispp_sdev->dev;
401 	struct rkispp_fecbuf_info *fecbuf;
402 	struct rkispp_fecbuf_size *fecsize;
403 	struct rkisp_ispp_reg **reg_buf;
404 	bool *rkispp_reg_withstream;
405 	long ret = 0;
406 
407 	if (!arg)
408 		return -EINVAL;
409 
410 	switch (cmd) {
411 	case RKISPP_CMD_GET_FECBUF_INFO:
412 		fecbuf = (struct rkispp_fecbuf_info *)arg;
413 		rkispp_params_get_fecbuf_inf(&ispp_dev->params_vdev, fecbuf);
414 		break;
415 	case RKISPP_CMD_SET_FECBUF_SIZE:
416 		fecsize = (struct rkispp_fecbuf_size *)arg;
417 		rkispp_params_set_fecbuf_size(&ispp_dev->params_vdev, fecsize);
418 		break;
419 	case RKISP_ISPP_CMD_REQUEST_REGBUF:
420 		reg_buf = (struct rkisp_ispp_reg **)arg;
421 		rkispp_request_regbuf(ispp_dev, reg_buf);
422 		break;
423 	case RKISP_ISPP_CMD_GET_REG_WITHSTREAM:
424 		rkispp_reg_withstream = arg;
425 		*rkispp_reg_withstream = rkispp_is_reg_withstream_global();
426 		break;
427 	#if IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_ISPP_VERSION_V10)
428 	case RKISPP_CMD_TRIGGER_YNRRUN:
429 		rkispp_sendbuf_to_nr(ispp_dev, (struct rkispp_tnr_inf *)arg);
430 		break;
431 	case RKISPP_CMD_GET_TNRBUF_FD:
432 		ret = rkispp_get_tnrbuf_fd(ispp_dev, (struct rkispp_buf_idxfd *)arg);
433 		break;
434 	case RKISPP_CMD_TRIGGER_MODE:
435 		rkispp_set_trigger_mode(ispp_dev, (struct rkispp_trigger_mode *)arg);
436 		break;
437 	#endif
438 	default:
439 		ret = -ENOIOCTLCMD;
440 	}
441 
442 	return ret;
443 }
444 
445 #ifdef CONFIG_COMPAT
rkispp_compat_ioctl32(struct v4l2_subdev * sd,unsigned int cmd,unsigned long arg)446 static long rkispp_compat_ioctl32(struct v4l2_subdev *sd,
447 				  unsigned int cmd, unsigned long arg)
448 {
449 	void __user *up = compat_ptr(arg);
450 	struct rkispp_fecbuf_info fecbuf;
451 	struct rkispp_fecbuf_size fecsize;
452 	struct rkispp_tnr_inf tnr_inf;
453 	struct rkispp_buf_idxfd idxfd;
454 	struct rkispp_trigger_mode t_mode;
455 	long ret = 0;
456 
457 	if (!up)
458 		return -EINVAL;
459 
460 	switch (cmd) {
461 	case RKISPP_CMD_GET_FECBUF_INFO:
462 		ret = rkispp_ioctl(sd, cmd, &fecbuf);
463 		if (!ret && copy_to_user(up, &fecbuf, sizeof(fecbuf)))
464 			ret = -EFAULT;
465 		break;
466 	case RKISPP_CMD_SET_FECBUF_SIZE:
467 		if (copy_from_user(&fecsize, up, sizeof(fecsize)))
468 			return -EFAULT;
469 		ret = rkispp_ioctl(sd, cmd, &fecsize);
470 		break;
471 	case RKISPP_CMD_TRIGGER_YNRRUN:
472 		if (copy_from_user(&tnr_inf, up, sizeof(tnr_inf)))
473 			return -EFAULT;
474 		ret = rkispp_ioctl(sd, cmd, &tnr_inf);
475 		break;
476 	case RKISPP_CMD_GET_TNRBUF_FD:
477 		ret = rkispp_ioctl(sd, cmd, &idxfd);
478 		if (!ret && copy_to_user(up, &idxfd, sizeof(idxfd)))
479 			ret = -EFAULT;
480 		break;
481 	case RKISPP_CMD_TRIGGER_MODE:
482 		if (copy_from_user(&t_mode, up, sizeof(t_mode)))
483 			return -EFAULT;
484 		ret = rkispp_ioctl(sd, cmd, &t_mode);
485 		break;
486 	default:
487 		ret = -ENOIOCTLCMD;
488 	}
489 
490 	return ret;
491 }
492 #endif
493 
rkispp_subscribe_event(struct v4l2_subdev * sd,struct v4l2_fh * fh,struct v4l2_event_subscription * sub)494 static int rkispp_subscribe_event(struct v4l2_subdev *sd,
495 				  struct v4l2_fh *fh,
496 				  struct v4l2_event_subscription *sub)
497 {
498 	switch (sub->type) {
499 	case RKISPP_V4L2_EVENT_TNR_COMPLETE:
500 		return v4l2_event_subscribe(fh, sub, RKISPP_BUF_MAX, NULL);
501 	default:
502 		return -EINVAL;
503 	}
504 }
505 
506 static const struct media_entity_operations rkispp_sd_media_ops = {
507 	.link_setup = rkispp_subdev_link_setup,
508 	.link_validate = v4l2_subdev_link_validate,
509 };
510 
511 static const struct v4l2_subdev_pad_ops rkispp_sd_pad_ops = {
512 	.get_fmt = rkispp_sd_get_fmt,
513 	.set_fmt = rkispp_sd_set_fmt,
514 	.get_selection = rkispp_sd_get_selection,
515 	.set_selection = rkispp_sd_set_selection,
516 };
517 
518 static const struct v4l2_subdev_video_ops rkispp_sd_video_ops = {
519 	.s_stream = rkispp_sd_s_stream,
520 	.s_rx_buffer = rkispp_sd_s_rx_buffer,
521 };
522 
523 static const struct v4l2_subdev_core_ops rkispp_sd_core_ops = {
524 	.s_power = rkispp_sd_s_power,
525 	.ioctl = rkispp_ioctl,
526 #ifdef CONFIG_COMPAT
527 	.compat_ioctl32 = rkispp_compat_ioctl32,
528 #endif
529 	.subscribe_event = rkispp_subscribe_event,
530 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
531 };
532 
533 static struct v4l2_subdev_ops rkispp_sd_ops = {
534 	.core = &rkispp_sd_core_ops,
535 	.video = &rkispp_sd_video_ops,
536 	.pad = &rkispp_sd_pad_ops,
537 };
538 
rkispp_register_subdev(struct rkispp_device * dev,struct v4l2_device * v4l2_dev)539 int rkispp_register_subdev(struct rkispp_device *dev,
540 			   struct v4l2_device *v4l2_dev)
541 {
542 	struct rkispp_subdev *ispp_sdev = &dev->ispp_sdev;
543 	struct v4l2_subdev *sd;
544 	int ret;
545 
546 	memset(ispp_sdev, 0, sizeof(*ispp_sdev));
547 	ispp_sdev->dev = dev;
548 	sd = &ispp_sdev->sd;
549 	ispp_sdev->state = ISPP_STOP;
550 	v4l2_subdev_init(sd, &rkispp_sd_ops);
551 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
552 	sd->entity.ops = &rkispp_sd_media_ops;
553 	snprintf(sd->name, sizeof(sd->name), "rkispp-subdev");
554 	sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_COMPOSER;
555 	ispp_sdev->pads[RKISPP_PAD_SINK].flags =
556 		MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
557 	ispp_sdev->pads[RKISPP_PAD_SINK_PARAMS].flags = MEDIA_PAD_FL_SINK;
558 	ispp_sdev->pads[RKISPP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
559 	ispp_sdev->pads[RKISPP_PAD_SOURCE_STATS].flags = MEDIA_PAD_FL_SOURCE;
560 
561 	ret = media_entity_pads_init(&sd->entity, RKISPP_PAD_MAX,
562 				     ispp_sdev->pads);
563 	if (ret < 0)
564 		return ret;
565 	sd->owner = THIS_MODULE;
566 	v4l2_set_subdevdata(sd, ispp_sdev);
567 	sd->grp_id = GRP_ID_ISPP;
568 	ret = v4l2_device_register_subdev(v4l2_dev, sd);
569 	if (ret < 0)
570 		goto free_media;
571 
572 	ret = v4l2_device_register_subdev_nodes(v4l2_dev);
573 	if (ret < 0)
574 		goto free_subdev;
575 	return ret;
576 free_subdev:
577 	v4l2_device_unregister_subdev(sd);
578 free_media:
579 	media_entity_cleanup(&sd->entity);
580 	v4l2_err(sd, "Failed to register subdev, ret:%d\n", ret);
581 	return ret;
582 }
583 
rkispp_unregister_subdev(struct rkispp_device * dev)584 void rkispp_unregister_subdev(struct rkispp_device *dev)
585 {
586 	struct v4l2_subdev *sd = &dev->ispp_sdev.sd;
587 
588 	v4l2_device_unregister_subdev(sd);
589 	media_entity_cleanup(&sd->entity);
590 }
591