/* Create links from FIMC-LITE source pads to other entities */
static int __fimc_md_create_flite_source_links(struct fimc_md *fmd)
{
	struct media_entity *source, *sink;
	int i, ret = 0;

	for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
		struct fimc_lite *fimc = fmd->fimc_lite[i];

		if (fimc == NULL)
			continue;

		source = &fimc->subdev.entity;
		sink = &fimc->ve.vdev.entity;
		/* FIMC-LITE's subdev and video node */
		ret = media_entity_create_link(source, FLITE_SD_PAD_SOURCE_DMA,
					       sink, 0, 0);
		if (ret)
			break;
		/* Link from FIMC-LITE to IS-ISP subdev */
		sink = &fmd->fimc_is->isp.subdev.entity;
		ret = media_entity_create_link(source, FLITE_SD_PAD_SOURCE_ISP,
					       sink, 0, 0);
		if (ret)
			break;
	}

	return ret;
}
/* Create FIMC-IS links */
static int __fimc_md_create_fimc_is_links(struct fimc_md *fmd)
{
	struct fimc_isp *isp = &fmd->fimc_is->isp;
	struct media_entity *source, *sink;
	int i, ret;

	source = &isp->subdev.entity;

	for (i = 0; i < FIMC_MAX_DEVS; i++) {
		if (fmd->fimc[i] == NULL)
			continue;

		/* Link from FIMC-IS-ISP subdev to FIMC */
		sink = &fmd->fimc[i]->vid_cap.subdev.entity;
		ret = media_entity_create_link(source, FIMC_ISP_SD_PAD_SRC_FIFO,
					       sink, FIMC_SD_PAD_SINK_FIFO, 0);
		if (ret)
			return ret;
	}

	/* Link from FIMC-IS-ISP subdev to fimc-is-isp.capture video node */
	sink = &isp->video_capture.ve.vdev.entity;

	/* Skip this link if the fimc-is-isp video node driver isn't built-in */
	if (sink->num_pads == 0)
		return 0;

	return media_entity_create_link(source, FIMC_ISP_SD_PAD_SRC_DMA,
					sink, 0, 0);
}
static int atomisp_initialize_modules(struct atomisp_device *isp)
{
	int ret;

	ret = atomisp_mipi_csi2_init(isp);
	if (ret < 0) {
		v4l2_err(&atomisp_dev, "mipi csi2 initialization failed\n");
		goto error_mipi_csi2;
	}

	ret = atomisp_file_input_init(isp);
	if (ret < 0) {
		v4l2_err(&atomisp_dev,
			"file input device initialization failed\n");
		goto error_file_input;
	}

	ret = atomisp_tpg_init(isp);
	if (ret < 0) {
		v4l2_err(&atomisp_dev, "tpg initialization failed\n");
		goto error_tpg;
	}

	ret = atomisp_subdev_init(isp);
	if (ret < 0) {
		v4l2_err(&atomisp_dev, "ISP subdev initialization failed\n");
		goto error_isp_subdev;
	}

	/* connet submoduels */
	ret = media_entity_create_link(
			&isp->csi2_4p.subdev.entity,
			CSI2_PAD_SOURCE,
			&isp->isp_subdev.subdev.entity,
			ATOMISP_SUBDEV_PAD_SINK,
			0);
	if (ret < 0)
		goto error_link;
	ret = media_entity_create_link(
			&isp->csi2_1p.subdev.entity,
			CSI2_PAD_SOURCE,
			&isp->isp_subdev.subdev.entity,
			ATOMISP_SUBDEV_PAD_SINK,
			0);
	if (ret < 0)
		goto error_link;
	return 0;

error_link:
error_isp_subdev:
	atomisp_subdev_cleanup(isp);
error_tpg:
	atomisp_tpg_cleanup(isp);
error_file_input:
	atomisp_file_input_cleanup(isp);
error_mipi_csi2:
	atomisp_mipi_csi2_cleanup(isp);
	return ret;
}
int vpfe_resizer_register_entities(struct vpfe_resizer_device *resizer,
				   struct v4l2_device *vdev)
{
	int ret;
	unsigned int flags = 0;
	struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);

	/* Register the subdev */
	ret = v4l2_device_register_subdev(vdev, &resizer->subdev);
	if (ret < 0) {
		printk(KERN_ERR "failed to register resizer as v4l2-subdev\n");
		return ret;
	}

	ret = vpfe_video_register(&resizer->video_in, vdev);
	if (ret) {
		printk(KERN_ERR "failed to register RSZ video-in device\n");
		goto out_video_in_register;
	}

	resizer->video_in.vpfe_dev = vpfe_dev;

	ret = vpfe_video_register(&resizer->video_out, vdev);
	if (ret) {
		printk(KERN_ERR "failed to register RSZ video-out device\n");
		goto out_video_out_register;
	}

	resizer->video_out.vpfe_dev = vpfe_dev;

	ret = media_entity_create_link(&resizer->video_in.video_dev.entity,
				       0,
				       &resizer->subdev.entity,
				       0, flags);
	if (ret < 0)
		goto out_create_link;

	ret = media_entity_create_link(&resizer->subdev.entity,
				       1,
				       &resizer->video_out.video_dev.entity,
				       0, flags);
	if (ret < 0)
		goto out_create_link;

	return 0;

out_create_link:
	vpfe_video_unregister(&resizer->video_out);
out_video_out_register:
	vpfe_video_unregister(&resizer->video_in);
out_video_in_register:
	media_entity_cleanup(&resizer->subdev.entity);
	v4l2_device_unregister_subdev(&resizer->subdev);
	return ret;
}
int create_link_mipi(struct decon_device *decon)
{
	int i, ret = 0;
	int n_pad = decon->n_sink_pad + decon->n_src_pad;
	int flags = 0;
	char err[80];
	struct exynos_md *md = decon->mdev;

	if (IS_ERR_OR_NULL(md->dsim_sd[decon->id])) {
		decon_err("failed to get subdev of dsim%d\n", decon->id);
		return -EINVAL;
	}

	flags = MEDIA_LNK_FL_ENABLED;
	for (i = decon->n_sink_pad; i < n_pad ; i++) {
		ret = media_entity_create_link(&decon->sd.entity, i,
				&md->dsim_sd[decon->id]->entity, 0, flags);
		if (ret) {
			snprintf(err, sizeof(err), "%s --> %s",
					decon->sd.entity.name,
					decon->output_sd->entity.name);
			return ret;
		}

		decon_info("%s[%d] --> [0]%s link is created successfully\n",
				decon->sd.entity.name, i,
				decon->output_sd->entity.name);
	}

	return ret;
}
int create_link_hdmi(struct decon_device *decon)
{
	int i, ret = 0;
	int n_pad = decon->n_sink_pad + decon->n_src_pad;
	int flags = 0;
	char err[80];

	if (!strcmp(decon->output_sd->name, "s5p-hdmi-sd"))
		flags = MEDIA_LNK_FL_ENABLED;
	for (i = decon->n_sink_pad; i < n_pad ; i++) {
		ret = media_entity_create_link(&decon->sd.entity, i,
				&decon->output_sd->entity, 0, flags);
		if (ret) {
			snprintf(err, sizeof(err), "%s --> %s",
					decon->sd.entity.name,
					decon->output_sd->entity.name);
			return ret;
		}
		decon_info("%s[%d] --> [0]%s link is created successfully\n",
				decon->sd.entity.name, i,
				decon->output_sd->entity.name);
	}

	return ret;
}
Example #7
0
static int gsc_capture_create_link(struct gsc_dev *gsc)
{
	struct media_entity *source, *sink;
	struct exynos_platform_gscaler *pdata = gsc->pdata;
	struct exynos_isp_info *isp_info;
	u32 num_clients = pdata->num_clients;
	int ret, i;
	enum cam_port id;

	/* GSC-SUBDEV ------> GSC-VIDEO (Always link enable) */
	source = &gsc->cap.sd_cap->entity;
	sink = &gsc->cap.vfd->entity;
	if (source && sink) {
		ret = media_entity_create_link(source, GSC_PAD_SOURCE, sink,
				0, MEDIA_LNK_FL_IMMUTABLE |
				MEDIA_LNK_FL_ENABLED);
		if (ret) {
			gsc_err("failed link flite to gsc\n");
			return ret;
		}
	}
	for (i = 0; i < num_clients; i++) {
		isp_info = pdata->isp_info[i];
		id = isp_info->cam_port;
		/* FIMC-LITE ------> GSC-SUBDEV (ITU & MIPI common) */
		source = &gsc->cap.sd_flite[id]->entity;
		sink = &gsc->cap.sd_cap->entity;
		if (source && sink) {
			if (pdata->cam_preview)
				ret = media_entity_create_link(source,
						FLITE_PAD_SOURCE_PREV,
						sink, GSC_PAD_SINK, 0);
			if (!ret && pdata->cam_camcording)
				ret = media_entity_create_link(source,
						FLITE_PAD_SOURCE_CAMCORD,
						sink, GSC_PAD_SINK, 0);
			if (ret) {
				gsc_err("failed link flite to gsc\n");
				return ret;
			}
		}
	}

	return 0;
}
Example #8
0
static int atomisp_initialize_modules(struct atomisp_device *isp)
{
	int ret;
	unsigned int i, j;

	ret = atomisp_mipi_csi2_init(isp);
	if (ret < 0) {
		v4l2_err(&atomisp_dev, "mipi csi2 initialization failed\n");
		goto error_mipi_csi2;
	}

	ret = atomisp_file_input_init(isp);
	if (ret < 0) {
		v4l2_err(&atomisp_dev,
			"file input device initialization failed\n");
		goto error_file_input;
	}

	ret = atomisp_tpg_init(isp);
	if (ret < 0) {
		v4l2_err(&atomisp_dev, "tpg initialization failed\n");
		goto error_tpg;
	}

	ret = atomisp_subdev_init(isp);
	if (ret < 0) {
		v4l2_err(&atomisp_dev, "ISP subdev initialization failed\n");
		goto error_isp_subdev;
	}

	/* connet submoduels */
	for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) {
		for (j = 0; j < isp->num_of_streams; j++) {
			ret = media_entity_create_link(
				&isp->csi2_port[i].subdev.entity,
				CSI2_PAD_SOURCE,
				&isp->isp_subdev[j].subdev.entity,
				ATOMISP_SUBDEV_PAD_SINK,
				0);
			if (ret < 0)
				goto error_link;
		}
	}
	return 0;

error_link:
error_isp_subdev:
	atomisp_subdev_cleanup(isp);
error_tpg:
	atomisp_tpg_cleanup(isp);
error_file_input:
	atomisp_file_input_cleanup(isp);
error_mipi_csi2:
	atomisp_mipi_csi2_cleanup(isp);
	return ret;
}
Example #9
0
/*
 * csi2_init_entities - Initialize subdev and media entity.
 * @csi2: Pointer to csi2 structure.
 * return -ENOMEM or zero on success
 */
static int csi2_init_entities(struct iss_csi2_device *csi2, const char *subname)
{
	struct v4l2_subdev *sd = &csi2->subdev;
	struct media_pad *pads = csi2->pads;
	struct media_entity *me = &sd->entity;
	int ret;
	char name[V4L2_SUBDEV_NAME_SIZE];

	v4l2_subdev_init(sd, &csi2_ops);
	sd->internal_ops = &csi2_internal_ops;
	sprintf(name, "CSI2%s", subname);
	snprintf(sd->name, sizeof(sd->name), "OMAP4 ISS %s", name);

	sd->grp_id = 1 << 16;	/* group ID for iss subdevs */
	v4l2_set_subdevdata(sd, csi2);
	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;

	pads[CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
	pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;

	me->ops = &csi2_media_ops;
	ret = media_entity_init(me, CSI2_PADS_NUM, pads, 0);
	if (ret < 0)
		return ret;

	csi2_init_formats(sd, NULL);

	/* Video device node */
	csi2->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	csi2->video_out.ops = &csi2_issvideo_ops;
	csi2->video_out.bpl_alignment = 32;
	csi2->video_out.bpl_zero_padding = 1;
	csi2->video_out.bpl_max = 0x1ffe0;
	csi2->video_out.iss = csi2->iss;
	csi2->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3;

	ret = omap4iss_video_init(&csi2->video_out, name);
	if (ret < 0)
		goto error_video;

	/* Connect the CSI2 subdev to the video node. */
	ret = media_entity_create_link(&csi2->subdev.entity, CSI2_PAD_SOURCE,
				       &csi2->video_out.video.entity, 0, 0);
	if (ret < 0)
		goto error_link;

	return 0;

error_link:
	omap4iss_video_cleanup(&csi2->video_out);
error_video:
	media_entity_cleanup(&csi2->subdev.entity);
	return ret;
}
Example #10
0
static int camif_create_media_links(struct camif_dev *camif)
{
	int i, ret;

	ret = media_entity_create_link(&camif->sensor.sd->entity, 0,
				&camif->subdev.entity, CAMIF_SD_PAD_SINK,
				MEDIA_LNK_FL_IMMUTABLE |
				MEDIA_LNK_FL_ENABLED);
	if (ret)
		return ret;

	for (i = 1; i < CAMIF_SD_PADS_NUM && !ret; i++) {
		ret = media_entity_create_link(&camif->subdev.entity, i,
				&camif->vp[i - 1].vdev.entity, 0,
				MEDIA_LNK_FL_IMMUTABLE |
				MEDIA_LNK_FL_ENABLED);
	}

	return ret;
}
/**
 * __fimc_md_create_fimc_links - create links to all FIMC entities
 * @fmd: fimc media device
 * @source: the source entity to create links to all fimc entities from
 * @sensor: sensor subdev linked to FIMC[fimc_id] entity, may be null
 * @pad: the source entity pad index
 * @fimc_id: index of the fimc device for which link should be enabled
 */
static int __fimc_md_create_fimc_links(struct fimc_md *fmd,
				       struct media_entity *source,
				       struct v4l2_subdev *sensor,
				       int pad, int fimc_id)
{
	struct fimc_sensor_info *s_info;
	struct media_entity *sink;
	unsigned int flags;
	int ret, i;

	for (i = 0; i < FIMC_MAX_DEVS; i++) {
		if (!fmd->fimc[i])
			break;
		/*
		 * Some FIMC variants are not fitted with camera capture
		 * interface. Skip creating a link from sensor for those.
		 */
		if (sensor->grp_id == SENSOR_GROUP_ID &&
		    !fmd->fimc[i]->variant->has_cam_if)
			continue;

		flags = (i == fimc_id) ? MEDIA_LNK_FL_ENABLED : 0;
		sink = &fmd->fimc[i]->vid_cap.subdev->entity;
		ret = media_entity_create_link(source, pad, sink,
					      FIMC_SD_PAD_SINK, flags);
		if (ret)
			return ret;

		/* Notify FIMC capture subdev entity */
		ret = media_entity_call(sink, link_setup, &sink->pads[0],
					&source->pads[pad], flags);
		if (ret)
			break;

		v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]",
			  source->name, flags ? '=' : '-', sink->name);

		if (flags == 0)
			continue;
		s_info = v4l2_get_subdev_hostdata(sensor);
		if (!WARN_ON(s_info == NULL)) {
			unsigned long irq_flags;
			spin_lock_irqsave(&fmd->slock, irq_flags);
			s_info->host = fmd->fimc[i];
			spin_unlock_irqrestore(&fmd->slock, irq_flags);
		}
	}
	return 0;
}
Example #12
0
/*
 * ipipeif_init_entities - Initialize V4L2 subdev and media entity
 * @ipipeif: ISS ISP IPIPEIF module
 *
 * Return 0 on success and a negative error code on failure.
 */
static int ipipeif_init_entities(struct iss_ipipeif_device *ipipeif)
{
	struct v4l2_subdev *sd = &ipipeif->subdev;
	struct media_pad *pads = ipipeif->pads;
	struct media_entity *me = &sd->entity;
	int ret;

	ipipeif->input = IPIPEIF_INPUT_NONE;

	v4l2_subdev_init(sd, &ipipeif_v4l2_ops);
	sd->internal_ops = &ipipeif_v4l2_internal_ops;
	strlcpy(sd->name, "OMAP4 ISS ISP IPIPEIF", sizeof(sd->name));
	sd->grp_id = 1 << 16;	/* group ID for iss subdevs */
	v4l2_set_subdevdata(sd, ipipeif);
	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;

	pads[IPIPEIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
	pads[IPIPEIF_PAD_SOURCE_ISIF_SF].flags = MEDIA_PAD_FL_SOURCE;
	pads[IPIPEIF_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE;

	me->ops = &ipipeif_media_ops;
	ret = media_entity_init(me, IPIPEIF_PADS_NUM, pads, 0);
	if (ret < 0)
		return ret;

	ipipeif_init_formats(sd, NULL);

	ipipeif->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	ipipeif->video_out.ops = &ipipeif_video_ops;
	ipipeif->video_out.iss = to_iss_device(ipipeif);
	ipipeif->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3;
	ipipeif->video_out.bpl_alignment = 32;
	ipipeif->video_out.bpl_zero_padding = 1;
	ipipeif->video_out.bpl_max = 0x1ffe0;

	ret = omap4iss_video_init(&ipipeif->video_out, "ISP IPIPEIF");
	if (ret < 0)
		return ret;

	/* Connect the IPIPEIF subdev to the video node. */
	ret = media_entity_create_link(&ipipeif->subdev.entity,
				       IPIPEIF_PAD_SOURCE_ISIF_SF,
				       &ipipeif->video_out.video.entity, 0, 0);
	if (ret < 0)
		return ret;

	return 0;
}
Example #13
0
/*
 * ispcsi2_init_entities - Initialize subdev and media entity.
 * @csi2: Pointer to ispcsi2 structure.
 * return -ENOMEM or zero on success
 */
static int isp_csi2_init_entities(struct isp_csi2_device *csi2)
{
	struct v4l2_subdev *sd = &csi2->subdev;
	struct media_pad *pads = csi2->pads;
	struct media_entity *me = &sd->entity;
	int ret;

	v4l2_subdev_init(sd, &csi2_ops);
	strlcpy(sd->name, "OMAP3 ISP CSI2a", sizeof(sd->name));

	sd->grp_id = 1 << 16;	/* group ID for isp subdevs */
	v4l2_set_subdevdata(sd, csi2);
	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;

	v4l2_ctrl_handler_init(&csi2->ctrls, 1);
	sd->ctrl_handler = &csi2->ctrls;

	pads[CSI2_PAD_SOURCE].flags = MEDIA_PAD_FLAG_OUTPUT;
	pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FLAG_INPUT;

	me->ops = &csi2_media_ops;
	ret = media_entity_init(me, CSI2_PADS_NUM, pads, 0);
	if (ret < 0)
		return ret;

	csi2_init_formats(sd, NULL);

	/* Video device node */
	csi2->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	csi2->video_out.ops = &csi2_ispvideo_ops;
	csi2->video_out.bpl_alignment = 32;
	csi2->video_out.bpl_zero_padding = 1;
	csi2->video_out.bpl_max = 0x1ffe0;
	csi2->video_out.isp = csi2->isp;
	csi2->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3;

	ret = isp_video_init(&csi2->video_out, "CSI2a");
	if (ret < 0)
		return ret;

	/* Connect the CSI2 subdev to the video node. */
	ret = media_entity_create_link(&csi2->subdev.entity, CSI2_PAD_SOURCE,
				       &csi2->video_out.video.entity, 0, 0);
	if (ret < 0)
		return ret;

	return 0;
}
Example #14
0
static int gsc_capture_create_link(struct gsc_dev *gsc)
{
	struct media_entity *source, *sink;
	int ret;

	/* GSC-SUBDEV ------> GSC-VIDEO (Always link enable) */
	source = &gsc->cap.sd_cap->entity;
	sink = &gsc->cap.vfd->entity;
	if (source && sink) {
		ret = media_entity_create_link(source, GSC_PAD_SOURCE, sink, 0, 0);
		if (ret) {
			gsc_err("failed link flite to gsc\n");
			return ret;
		}
	}

	return 0;
}
static int gsc_capture_create_link(struct gsc_dev *gsc)
{
	struct media_entity *source, *sink;
	int ret;

	/* GSC-SUBDEV ------> GSC-VIDEO (Always link enable) */
	source = &gsc->cap.sd->entity;
	sink = &gsc->cap.vfd->entity;
	if (source && sink) {
		ret = media_entity_create_link(source,
				GSC_PAD_SOURCE, sink, 0,
				MEDIA_LNK_FL_ENABLED |
				MEDIA_LNK_FL_IMMUTABLE);
		if (ret) {
			gsc_err("failed link sd-gsc to vd-gsc\n");
			return ret;
		}
	}

	return 0;
}
Example #16
0
/* Create links from FIMC-LITE source pads to other entities */
static int __fimc_md_create_flite_source_links(struct fimc_md *fmd)
{
	struct media_entity *source, *sink;
	unsigned int flags = MEDIA_LNK_FL_ENABLED;
	int i, ret;

	for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
		struct fimc_lite *fimc = fmd->fimc_lite[i];
		if (fimc == NULL)
			continue;
		source = &fimc->subdev.entity;
		sink = &fimc->vfd.entity;
		/* FIMC-LITE's subdev and video node */
		ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE,
					       sink, 0, flags);
		if (ret)
			break;
		/* TODO: create links to other entities */
	}

	return ret;
}
Example #17
0
/**
 * fimc_md_create_links - create default links between registered entities
 *
 * Parallel interface sensor entities are connected directly to FIMC capture
 * entities. The sensors using MIPI CSIS bus are connected through immutable
 * link with CSI receiver entity specified by mux_id. Any registered CSIS
 * entity has a link to each registered FIMC capture entity. Enabled links
 * are created by default between each subsequent registered sensor and
 * subsequent FIMC capture entity. The number of default active links is
 * determined by the number of available sensors or FIMC entities,
 * whichever is less.
 */
static int fimc_md_create_links(struct fimc_md *fmd)
{
	struct v4l2_subdev *sensor, *csis;
	struct fimc_sensor_info *s_info;
	struct s5p_fimc_isp_info *pdata;
	struct media_entity *source, *sink;
	int i, j, ret = 0;
	u32 flags = 0;

	for (j = 0; j < fmd->num_sensors; j++) {
		if (fmd->sensor[j].subdev == NULL) {
			v4l2_warn(&fmd->v4l2_dev,
				"fmd->sensor[%d].subdev = NULL!!\n", j);
			continue;
		}

		sensor = fmd->sensor[j].subdev;
		s_info = v4l2_get_subdev_hostdata(sensor);
		if (!s_info) {
			v4l2_warn(&fmd->v4l2_dev,
				"(%d) fimc_sensor_info = NULL!!\n", j);
			continue;
		}
		pdata = &s_info->pdata;
		switch (pdata->bus_type) {
		case FIMC_ITU_601...FIMC_ITU_656:
			/* TODO : add ITU configuration */
			break;
		case FIMC_MIPI_CSI2:
			/* 1. create link beween sensor and mipi-csi */
			if (WARN(pdata->mux_id >= CSIS_MAX_ENTITIES,
				"Wrong CSI channel id: %d\n", pdata->mux_id))
				return -EINVAL;
			csis = fmd->csis[pdata->mux_id].sd;
			if (WARN(csis == NULL,
				 "MIPI-CSI interface specified "
				 "but s5p-csis module is not loaded!\n"))
				return -EINVAL;

			ret = media_entity_create_link(&sensor->entity, 0,
					      &csis->entity, CSIS_PAD_SINK,
					      flags);
			if (ret)
				return ret;

			v4l2_info(&fmd->v4l2_dev, "created link [%s] -> [%s]",
				  sensor->entity.name, csis->entity.name);

			/* 2. create link beween mipi-csi and fimc */
			source = &csis->entity;
			for (i = 0; i < FIMC_MAX_DEVS; i++) {
				if (!fmd->fimc[i])
					continue;
				/*
				 * Some FIMC variants are not fitted with camera capture
				 * interface. Skip creating a link from sensor for those.
				 */
				if (!fmd->fimc[i]->variant->has_cam_if)
					continue;
				sink = &fmd->fimc[i]->vid_cap.subdev.entity;

				ret = media_entity_create_link(source,
					CSIS_PAD_SOURCE,
					sink,
					FIMC_SD_PAD_SINK, flags);
				if (ret)
					return ret;

				/* Notify FIMC capture subdev entity */
				ret = media_entity_call(sink, link_setup,
					&sink->pads[FIMC_SD_PAD_SINK],
					&source->pads[CSIS_PAD_SOURCE], flags);

				if (ret)
					break;
				v4l2_info(&fmd->v4l2_dev,
					"created link [%s] %c> [%s]",
					source->name, flags ? '=' : '-',
					sink->name);
			}
			break;
		case FIMC_IS_WB:
			/* 1. create link beween sensor and mipi-csi */
			if (WARN(pdata->mux_id >= CSIS_MAX_ENTITIES,
				"Wrong CSI channel id: %d\n", pdata->mux_id))
				return -EINVAL;
			csis = fmd->csis[pdata->mux_id].sd;
			if (WARN(csis == NULL,
				 "MIPI-CSI interface specified "
				 "but s5p-csis module is not loaded!\n"))
				return -EINVAL;

			ret = media_entity_create_link(&sensor->entity, 0,
					      &csis->entity, CSIS_PAD_SINK,
					      flags);
			if (ret)
				return ret;

			v4l2_info(&fmd->v4l2_dev, "created link [%s] -> [%s]",
				  sensor->entity.name, csis->entity.name);
			/* 2. create link beween mipi-csi and fimc-lite */
			source = &csis->entity;
			sink = &fmd->fimc_lite[pdata->mux_id]->subdev.entity;
			ret = media_entity_create_link(source, CSIS_PAD_SOURCE,
					sink, FLITE_SD_PAD_SINK,
					flags);
			if (ret)
				return ret;
			/* Notify FIMC-LITE subdev entity */
			ret = media_entity_call(sink, link_setup,
					&source->pads[CSIS_PAD_SOURCE],
					&sink->pads[FLITE_SD_PAD_SINK],
					flags);
			if (ret)
				break;

			v4l2_info(&fmd->v4l2_dev, "created link [%s] -> [%s]",
				source->name, sink->name);
			/* 3. create link beween fimc-lite and fimc-is */
			source = &fmd->fimc_lite[pdata->mux_id]->subdev.entity;
			sink = &fmd->fimc_is->isp.subdev.entity;
			ret = media_entity_create_link(source,
					FLITE_SD_PAD_SOURCE,
					sink, FIMC_IS_SD_PAD_SINK,
					flags);
			if (ret)
				return ret;

			/* Notify FIMC-IS subdev entity */
			ret = media_entity_call(sink, link_setup,
					&source->pads[FLITE_SD_PAD_SOURCE],
					&sink->pads[FIMC_IS_SD_PAD_SINK],
					flags);

			v4l2_info(&fmd->v4l2_dev, "created link [%s] -> [%s]",
				source->name, sink->name);

			/* 4. create link beween fimc-is and fimc */
			source = &fmd->fimc_is->isp.subdev.entity;
			for (i = 0; i < (FIMC_MAX_DEVS - 1); i++) {
				if (!fmd->fimc[i])
					continue;
				/*
				 * Some FIMC variants are not fitted with camera capture
				 * interface. Skip creating a link from sensor for those.
				 */
				if (!fmd->fimc[i]->variant->has_cam_if)
					continue;
				sink = &fmd->fimc[i]->vid_cap.subdev.entity;

				ret = media_entity_create_link(source,
					CSIS_PAD_SOURCE,
					sink,
					FIMC_SD_PAD_SINK, flags);
				if (ret)
					return ret;

				/* Notify FIMC capture subdev entity */
				ret = media_entity_call(sink, link_setup,
					&source->pads[CSIS_PAD_SOURCE],
					&sink->pads[FIMC_SD_PAD_SINK],
					flags);

				if (ret)
					break;
				v4l2_info(&fmd->v4l2_dev,
					"created link [%s] %c> [%s]",
					source->name, flags ? '=' : '-',
					sink->name);
			}
			break;
		default:
			v4l2_err(&fmd->v4l2_dev, "Wrong bus_type: %x\n",
				 pdata->bus_type);
			return -EINVAL;
		}
	}

	/* Create immutable link between each FIMC's subdev and video node */
	flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED;
	for (i = 0; i < FIMC_MAX_DEVS; i++) {
		if (!fmd->fimc[i])
			continue;
		source = &fmd->fimc[i]->vid_cap.subdev.entity;
		sink = &fmd->fimc[i]->vid_cap.vfd.entity;
		ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE,
					      sink, 0, flags);
		if (ret)
			break;
		v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]",
				source->name, flags ? '=' : '-', sink->name);
	}
	return ret;
}
Example #18
0
static int atomisp_register_entities(struct atomisp_device *isp)
{
	int ret = 0;
	unsigned int i;

	isp->media_dev.dev = isp->dev;

	strlcpy(isp->media_dev.model, "Intel Atom ISP",
		sizeof(isp->media_dev.model));

	ret = media_device_register(&isp->media_dev);
	if (ret < 0) {
		v4l2_err(&atomisp_dev, "%s: Media device registration "
			 "failed (%d)\n", __func__, ret);
		return ret;
	}

	isp->v4l2_dev.mdev = &isp->media_dev;
	ret = v4l2_device_register(isp->dev, &isp->v4l2_dev);
	if (ret < 0) {
		v4l2_err(&atomisp_dev,
			"%s: V4L2 device registration failed (%d)\n",
			__func__, ret);
		goto v4l2_device_failed;
	}

	ret = atomisp_subdev_probe(isp);
	if (ret < 0)
		goto csi_and_subdev_probe_failed;

	/* Register internal entities */
	for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) {
		ret = atomisp_mipi_csi2_register_entities(&isp->csi2_port[i],
								&isp->v4l2_dev);
		if (ret == 0)
			continue;

		/* error case */
		v4l2_err(&atomisp_dev,
			"failed to register the CSI port: %d\n", i);
		/* deregister all registered CSI ports */
		while (i--)
			atomisp_mipi_csi2_unregister_entities(
							&isp->csi2_port[i]);

		goto csi_and_subdev_probe_failed;
	}

	ret =
	atomisp_file_input_register_entities(&isp->file_dev, &isp->v4l2_dev);
	if (ret < 0) {
		v4l2_err(&atomisp_dev,
			"atomisp_file_input_register_entities\n");
		goto file_input_register_failed;
	}

	ret = atomisp_tpg_register_entities(&isp->tpg, &isp->v4l2_dev);
	if (ret < 0) {
		v4l2_err(&atomisp_dev, "atomisp_tpg_register_entities\n");
		goto tpg_register_failed;
	}

	for (i = 0; i < isp->num_of_streams; i++) {
		ret =
		atomisp_subdev_register_entities(&isp->isp_subdev[i],
						 &isp->v4l2_dev);
		if (ret < 0) {
			v4l2_err(&atomisp_dev,
				"atomisp_subdev_register_entities fail\n");
			goto subdev_register_failed;
		}
	}

	for (i = 0; i < isp->input_cnt; i++) {
		if (isp->inputs[i].port >= ATOMISP_CAMERA_NR_PORTS) {
			v4l2_err(&atomisp_dev,
					"isp->inputs port %d not supported\n",
					isp->inputs[i].port);
			ret = -EINVAL;
			goto link_failed;
		}

		ret = media_entity_create_link(
			&isp->inputs[i].camera->entity, 0,
			&isp->csi2_port[isp->inputs[i].port].subdev.entity,
			CSI2_PAD_SINK,
			MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
		if (ret < 0) {
			dev_err(isp->dev,
				"link create from sensor to csi-2 receiver failed\n");
			goto link_failed;
		}
	}

	v4l2_dbg(1, dbg_level, &atomisp_dev,
		"FILE_INPUT enable, camera_cnt: %d\n", isp->input_cnt);
	isp->inputs[isp->input_cnt].type = FILE_INPUT;
	isp->inputs[isp->input_cnt].port = -1;
	isp->inputs[isp->input_cnt].shading_table = NULL;
	isp->inputs[isp->input_cnt].morph_table = NULL;
	isp->inputs[isp->input_cnt++].camera = &isp->file_dev.sd;

	if (isp->input_cnt < ATOM_ISP_MAX_INPUTS) {
		v4l2_dbg(1, dbg_level, &atomisp_dev,
			"TPG detected, camera_cnt: %d\n", isp->input_cnt);
		isp->inputs[isp->input_cnt].type = TEST_PATTERN;
		isp->inputs[isp->input_cnt].port = -1;
		isp->inputs[isp->input_cnt].shading_table = NULL;
		isp->inputs[isp->input_cnt].morph_table = NULL;
		isp->inputs[isp->input_cnt++].camera = &isp->tpg.sd;
	} else {
		v4l2_warn(&atomisp_dev,
			"too many atomisp inputs, TPG ignored.\n");
	}

	ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev);
	if (ret < 0)
		goto link_failed;

	return ret;

link_failed:
	for (i = 0; i < isp->num_of_streams; i++)
		atomisp_subdev_unregister_entities(&isp->isp_subdev[i]);
subdev_register_failed:
	while (i--)
		atomisp_subdev_unregister_entities(&isp->isp_subdev[i]);
	atomisp_tpg_unregister_entities(&isp->tpg);
tpg_register_failed:
	atomisp_file_input_unregister_entities(&isp->file_dev);
file_input_register_failed:
	for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++)
		atomisp_mipi_csi2_unregister_entities(&isp->csi2_port[i]);
csi_and_subdev_probe_failed:
	v4l2_device_unregister(&isp->v4l2_dev);
v4l2_device_failed:
	media_device_unregister(&isp->media_dev);
	return ret;
}
/*
 * isp_subdev_init_entities - Initialize V4L2 subdev and media entity
 * @asd: ISP CCDC module
 *
 * Return 0 on success and a negative error code on failure.
 */
static int isp_subdev_init_entities(struct atomisp_sub_device *asd)
{
	struct v4l2_subdev *sd = &asd->subdev;
	struct media_pad *pads = asd->pads;
	struct media_entity *me = &sd->entity;
	int ret;

	asd->input = ATOMISP_SUBDEV_INPUT_NONE;

	v4l2_subdev_init(sd, &isp_subdev_v4l2_ops);
	strlcpy(sd->name, "ATOM ISP SUBDEV", sizeof(sd->name));
	v4l2_set_subdevdata(sd, asd);
	sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;

	pads[ATOMISP_SUBDEV_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
	pads[ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW].flags = MEDIA_PAD_FL_SOURCE;
	pads[ATOMISP_SUBDEV_PAD_SOURCE_VF].flags = MEDIA_PAD_FL_SOURCE;
	pads[ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE].flags = MEDIA_PAD_FL_SOURCE;

	asd->fmt[ATOMISP_SUBDEV_PAD_SINK].fmt.code =
		V4L2_MBUS_FMT_SBGGR10_1X10;
	asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW].fmt.code =
		V4L2_MBUS_FMT_SBGGR10_1X10;
	asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_VF].fmt.code =
		V4L2_MBUS_FMT_SBGGR10_1X10;
	asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE].fmt.code =
		V4L2_MBUS_FMT_SBGGR10_1X10;

	me->ops = &isp_subdev_media_ops;
	me->type = MEDIA_ENT_T_V4L2_SUBDEV;
	ret = media_entity_init(me, ATOMISP_SUBDEV_PADS_NUM, pads, 0);
	if (ret < 0)
		return ret;

	atomisp_init_subdev_pipe(asd, &asd->video_in,
			V4L2_BUF_TYPE_VIDEO_OUTPUT);

	atomisp_init_subdev_pipe(asd, &asd->video_out_preview,
			V4L2_BUF_TYPE_VIDEO_CAPTURE);

	atomisp_init_subdev_pipe(asd, &asd->video_out_vf,
			V4L2_BUF_TYPE_VIDEO_CAPTURE);

	atomisp_init_subdev_pipe(asd, &asd->video_out_capture,
			V4L2_BUF_TYPE_VIDEO_CAPTURE);

	ret = atomisp_video_init(&asd->video_in, "MEMORY");
	if (ret < 0)
		return ret;

	ret = atomisp_video_init(&asd->video_out_capture, "CAPTURE");
	if (ret < 0)
		return ret;

	ret = atomisp_video_init(&asd->video_out_vf, "VIEWFINDER");
	if (ret < 0)
		return ret;

	ret = atomisp_video_init(&asd->video_out_preview, "PREVIEW");
	if (ret < 0)
		return ret;

	/* Connect the isp subdev to the video node. */
	ret = media_entity_create_link(&asd->video_in.vdev.entity,
		0, &asd->subdev.entity, ATOMISP_SUBDEV_PAD_SINK, 0);
	if (ret < 0)
		return ret;

	ret = media_entity_create_link(&asd->subdev.entity,
		ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW,
		&asd->video_out_preview.vdev.entity, 0, 0);
	if (ret < 0)
		return ret;

	ret = media_entity_create_link(&asd->subdev.entity,
		ATOMISP_SUBDEV_PAD_SOURCE_VF,
		&asd->video_out_vf.vdev.entity, 0, 0);
	if (ret < 0)
		return ret;

	ret = media_entity_create_link(&asd->subdev.entity,
		ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE,
		&asd->video_out_capture.vdev.entity, 0, 0);
	if (ret < 0)
		return ret;

	ret = v4l2_ctrl_handler_init(&asd->ctrl_handler, 1);
	if (ret)
		return ret;

	asd->fmt_auto = v4l2_ctrl_new_custom(&asd->ctrl_handler,
						    &ctrl_fmt_auto, NULL);
	asd->run_mode = v4l2_ctrl_new_custom(&asd->ctrl_handler,
						    &ctrl_run_mode, NULL);
	asd->vfpp = v4l2_ctrl_new_custom(&asd->ctrl_handler,
						&ctrl_vfpp, NULL);
	asd->continuous_mode = v4l2_ctrl_new_custom(&asd->ctrl_handler,
					     &ctrl_continuous_mode, NULL);
	asd->continuous_viewfinder = v4l2_ctrl_new_custom(&asd->ctrl_handler,
					     &ctrl_continuous_viewfinder,
					     NULL);
	asd->continuous_raw_buffer_size =
			v4l2_ctrl_new_custom(&asd->ctrl_handler,
					     &ctrl_continuous_raw_buffer_size,
					     NULL);

	/* Make controls visible on subdev as well. */
	asd->subdev.ctrl_handler = &asd->ctrl_handler;

	return asd->ctrl_handler.error;
}
/**
 * __fimc_md_create_fimc_links - create links to all FIMC entities
 * @fmd: fimc media device
 * @source: the source entity to create links to all fimc entities from
 * @sensor: sensor subdev linked to FIMC[fimc_id] entity, may be null
 * @pad: the source entity pad index
 * @link_mask: bitmask of the fimc devices for which link should be enabled
 */
static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
					    struct media_entity *source,
					    struct v4l2_subdev *sensor,
					    int pad, int link_mask)
{
	struct fimc_source_info *si = NULL;
	struct media_entity *sink;
	unsigned int flags = 0;
	int i, ret = 0;

	if (sensor) {
		si = v4l2_get_subdev_hostdata(sensor);
		/* Skip direct FIMC links in the logical FIMC-IS sensor path */
		if (si && si->fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK)
			ret = 1;
	}

	for (i = 0; !ret && i < FIMC_MAX_DEVS; i++) {
		if (!fmd->fimc[i])
			continue;
		/*
		 * Some FIMC variants are not fitted with camera capture
		 * interface. Skip creating a link from sensor for those.
		 */
		if (!fmd->fimc[i]->variant->has_cam_if)
			continue;

		flags = ((1 << i) & link_mask) ? MEDIA_LNK_FL_ENABLED : 0;

		sink = &fmd->fimc[i]->vid_cap.subdev.entity;
		ret = media_entity_create_link(source, pad, sink,
					      FIMC_SD_PAD_SINK_CAM, flags);
		if (ret)
			return ret;

		/* Notify FIMC capture subdev entity */
		ret = media_entity_call(sink, link_setup, &sink->pads[0],
					&source->pads[pad], flags);
		if (ret)
			break;

		v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]\n",
			  source->name, flags ? '=' : '-', sink->name);
	}

	for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
		if (!fmd->fimc_lite[i])
			continue;

		sink = &fmd->fimc_lite[i]->subdev.entity;
		ret = media_entity_create_link(source, pad, sink,
					       FLITE_SD_PAD_SINK, 0);
		if (ret)
			return ret;

		/* Notify FIMC-LITE subdev entity */
		ret = media_entity_call(sink, link_setup, &sink->pads[0],
					&source->pads[pad], 0);
		if (ret)
			break;

		v4l2_info(&fmd->v4l2_dev, "created link [%s] -> [%s]\n",
			  source->name, sink->name);
	}
	return 0;
}
static int atomisp_register_entities(struct atomisp_device *isp)
{
	int ret = 0;
	int i = 0;
	struct v4l2_subdev *subdev = NULL;
	struct media_entity *input = NULL;
	unsigned int flags;
	unsigned int pad;

	isp->media_dev.dev = isp->dev;

	strlcpy(isp->media_dev.model, "Intel Atom ISP",
		sizeof(isp->media_dev.model));

	ret = media_device_register(&isp->media_dev);
	if (ret < 0) {
		v4l2_err(&atomisp_dev, "%s: Media device registration "
			 "failed (%d)\n", __func__, ret);
		return ret;
	}

	isp->v4l2_dev.mdev = &isp->media_dev;
	ret = v4l2_device_register(isp->dev, &isp->v4l2_dev);
	if (ret < 0) {
		v4l2_err(&atomisp_dev,
			"%s: V4L2 device registration failed (%d)\n",
			__func__, ret);
		goto v4l2_device_failed;
	}

	/*
	 * fixing me!
	 * not sub device exists on
	 * mrfld vp
	 */
	if (!IS_MRFLD) {
		ret = atomisp_subdev_probe(isp);
		if (ret < 0)
			goto lane4_and_subdev_probe_failed;
	}

	/* Register internal entities */
	ret =
	atomisp_mipi_csi2_register_entities(&isp->csi2_4p, &isp->v4l2_dev);
	if (ret < 0) {
		v4l2_err(&atomisp_dev,
			"atomisp_mipi_csi2_register_entities 4p\n");
		goto lane4_and_subdev_probe_failed;
	}

	ret =
	atomisp_mipi_csi2_register_entities(&isp->csi2_1p, &isp->v4l2_dev);
	if (ret < 0) {
		v4l2_err(&atomisp_dev,
			"atomisp_mipi_csi2_register_entities 1p\n");
		goto lane1_failed;
	}

	ret =
	atomisp_file_input_register_entities(&isp->file_dev, &isp->v4l2_dev);
	if (ret < 0) {
		v4l2_err(&atomisp_dev,
			"atomisp_file_input_register_entities\n");
		goto file_input_register_failed;
	}

	ret = atomisp_tpg_register_entities(&isp->tpg, &isp->v4l2_dev);
	if (ret < 0) {
		v4l2_err(&atomisp_dev, "atomisp_tpg_register_entities\n");
		goto tpg_register_failed;
	}

	ret =
	atomisp_subdev_register_entities(&isp->isp_subdev, &isp->v4l2_dev);
	if (ret < 0) {
		v4l2_err(&atomisp_dev,
			"atomisp_subdev_register_entities fail\n");
		goto subdev_register_failed;
	}

	for (i = 0; i < isp->input_cnt; i++) {
		subdev = isp->inputs[i].camera;
		switch (isp->inputs[i].port) {
		case ATOMISP_CAMERA_PORT_PRIMARY:
			input = &isp->csi2_4p.subdev.entity;
			pad = CSI2_PAD_SINK;
			flags = 0;
			break;
		case ATOMISP_CAMERA_PORT_SECONDARY:
			input = &isp->csi2_1p.subdev.entity;
			pad = CSI2_PAD_SINK;
			flags = 0;
			break;
		default:
			v4l2_dbg(1, dbg_level, &atomisp_dev,
				  "isp->inputs type not supported\n");
			break;
		}
		ret = media_entity_create_link(&subdev->entity, 0,
			input, pad, flags);
		if (ret < 0) {
			v4l2_err(&atomisp_dev,
				"snr to mipi csi link failed\n");
			goto link_failed;
		}
	}

	v4l2_dbg(1, dbg_level, &atomisp_dev,
		"FILE_INPUT enable, camera_cnt: %d\n", isp->input_cnt);
	isp->inputs[isp->input_cnt].type = FILE_INPUT;
	isp->inputs[isp->input_cnt].port = -1;
	isp->inputs[isp->input_cnt].shading_table = NULL;
	isp->inputs[isp->input_cnt].morph_table = NULL;
	isp->inputs[isp->input_cnt++].camera = &isp->file_dev.sd;

	if (isp->input_cnt < ATOM_ISP_MAX_INPUTS) {
		v4l2_dbg(1, dbg_level, &atomisp_dev,
			"TPG detected, camera_cnt: %d\n", isp->input_cnt);
		isp->inputs[isp->input_cnt].type = TEST_PATTERN;
		isp->inputs[isp->input_cnt].port = -1;
		isp->inputs[isp->input_cnt].shading_table = NULL;
		isp->inputs[isp->input_cnt].morph_table = NULL;
		isp->inputs[isp->input_cnt++].camera = &isp->tpg.sd;
	} else {
		v4l2_warn(&atomisp_dev,
			"too many atomisp inputs, TPG ignored.\n");
	}

	ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev);
	if (ret < 0)
		goto link_failed;

	return ret;

link_failed:
	atomisp_subdev_unregister_entities(&isp->isp_subdev);
subdev_register_failed:
	atomisp_tpg_unregister_entities(&isp->tpg);
tpg_register_failed:
	atomisp_file_input_unregister_entities(&isp->file_dev);
file_input_register_failed:
	atomisp_mipi_csi2_unregister_entities(&isp->csi2_1p);
lane1_failed:
	atomisp_mipi_csi2_unregister_entities(&isp->csi2_4p);
lane4_and_subdev_probe_failed:
	v4l2_device_unregister(&isp->v4l2_dev);
v4l2_device_failed:
	media_device_unregister(&isp->media_dev);
	return ret;
}
/**
 * fimc_md_create_links - create default links between registered entities
 *
 * Parallel interface sensor entities are connected directly to FIMC capture
 * entities. The sensors using MIPI CSIS bus are connected through immutable
 * link with CSI receiver entity specified by mux_id. Any registered CSIS
 * entity has a link to each registered FIMC capture entity. Enabled links
 * are created by default between each subsequent registered sensor and
 * subsequent FIMC capture entity. The number of default active links is
 * determined by the number of available sensors or FIMC entities,
 * whichever is less.
 */
static int fimc_md_create_links(struct fimc_md *fmd)
{
	struct v4l2_subdev *sensor, *csis;
	struct s5p_fimc_isp_info *pdata;
	struct fimc_sensor_info *s_info;
	struct media_entity *source, *sink;
	int i, pad, fimc_id = 0;
	int ret = 0;
	u32 flags;

	for (i = 0; i < fmd->num_sensors; i++) {
		if (fmd->sensor[i].subdev == NULL)
			continue;

		sensor = fmd->sensor[i].subdev;
		s_info = v4l2_get_subdev_hostdata(sensor);
		if (!s_info || !s_info->pdata)
			continue;

		source = NULL;
		pdata = s_info->pdata;

		switch (pdata->bus_type) {
		case FIMC_MIPI_CSI2:
			if (WARN(pdata->mux_id >= CSIS_MAX_ENTITIES,
				"Wrong CSI channel id: %d\n", pdata->mux_id))
				return -EINVAL;

			csis = fmd->csis[pdata->mux_id].sd;
			if (WARN(csis == NULL,
				 "MIPI-CSI interface specified "
				 "but s5p-csis module is not loaded!\n"))
				return -EINVAL;

			ret = media_entity_create_link(&sensor->entity, 0,
					      &csis->entity, CSIS_PAD_SINK,
					      MEDIA_LNK_FL_IMMUTABLE |
					      MEDIA_LNK_FL_ENABLED);
			if (ret)
				return ret;

			v4l2_info(&fmd->v4l2_dev, "created link [%s] => [%s]",
				  sensor->entity.name, csis->entity.name);

			source = &csis->entity;
			pad = CSIS_PAD_SOURCE;
			break;

		case FIMC_ITU_601...FIMC_ITU_656:
			source = &sensor->entity;
			pad = 0;
			break;

		default:
			v4l2_err(&fmd->v4l2_dev, "Wrong bus_type: %x\n",
				 pdata->bus_type);
			return -EINVAL;
		}
		if (source == NULL)
			continue;

		ret = __fimc_md_create_fimc_links(fmd, source, sensor, pad,
						  fimc_id++);
	}
	/* Create immutable links between each FIMC's subdev and video node */
	flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED;
	for (i = 0; i < FIMC_MAX_DEVS; i++) {
		if (!fmd->fimc[i])
			continue;
		source = &fmd->fimc[i]->vid_cap.subdev->entity;
		sink = &fmd->fimc[i]->vid_cap.vfd->entity;
		ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE,
					      sink, 0, flags);
		if (ret)
			break;
	}

	return ret;
}
Example #23
0
struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
{
	struct v4l2_subdev *subdev;
	struct vsp1_video *video;
	struct vsp1_rwpf *wpf;
	unsigned int flags;
	int ret;

	wpf = devm_kzalloc(vsp1->dev, sizeof(*wpf), GFP_KERNEL);
	if (wpf == NULL)
		return ERR_PTR(-ENOMEM);

	wpf->max_width = WPF_MAX_WIDTH;
	wpf->max_height = WPF_MAX_HEIGHT;

	wpf->entity.type = VSP1_ENTITY_WPF;
	wpf->entity.index = index;
	wpf->entity.id = VI6_DPR_NODE_WPF(index);

	ret = vsp1_entity_init(vsp1, &wpf->entity, 2);
	if (ret < 0)
		return ERR_PTR(ret);

	/* Initialize the V4L2 subdev. */
	subdev = &wpf->entity.subdev;
	v4l2_subdev_init(subdev, &wpf_ops);

	subdev->entity.ops = &vsp1_media_ops;
	subdev->internal_ops = &vsp1_subdev_internal_ops;
	snprintf(subdev->name, sizeof(subdev->name), "%s wpf.%u",
		 dev_name(vsp1->dev), index);
	v4l2_set_subdevdata(subdev, wpf);
	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;

	vsp1_entity_init_formats(subdev, NULL);

	/* Initialize the video device. */
	video = &wpf->video;

	video->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
	video->vsp1 = vsp1;
	video->ops = &wpf_vdev_ops;

	ret = vsp1_video_init(video, &wpf->entity);
	if (ret < 0)
		goto error_video;

	/* Connect the video device to the WPF. All connections are immutable
	 * except for the WPF0 source link if a LIF is present.
	 */
	flags = MEDIA_LNK_FL_ENABLED;
	if (!(vsp1->pdata->features & VSP1_HAS_LIF) || index != 0)
		flags |= MEDIA_LNK_FL_IMMUTABLE;

	ret = media_entity_create_link(&wpf->entity.subdev.entity,
				       RWPF_PAD_SOURCE,
				       &wpf->video.video.entity, 0, flags);
	if (ret < 0)
		goto error_link;

	wpf->entity.sink = &wpf->video.video.entity;

	return wpf;

error_link:
	vsp1_video_cleanup(video);
error_video:
	media_entity_cleanup(&wpf->entity.subdev.entity);
	return ERR_PTR(ret);
}
Example #24
0
struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
{
	struct v4l2_subdev *subdev;
	struct vsp1_video *video;
	struct vsp1_rwpf *rpf;
	int ret;

	rpf = devm_kzalloc(vsp1->dev, sizeof(*rpf), GFP_KERNEL);
	if (rpf == NULL)
		return ERR_PTR(-ENOMEM);

	rpf->max_width = RPF_MAX_WIDTH;
	rpf->max_height = RPF_MAX_HEIGHT;

	rpf->entity.type = VSP1_ENTITY_RPF;
	rpf->entity.index = index;

	ret = vsp1_entity_init(vsp1, &rpf->entity, 2);
	if (ret < 0)
		return ERR_PTR(ret);

	/* Initialize the V4L2 subdev. */
	subdev = &rpf->entity.subdev;
	v4l2_subdev_init(subdev, &rpf_ops);

	subdev->entity.ops = &vsp1_media_ops;
	subdev->internal_ops = &vsp1_subdev_internal_ops;
	snprintf(subdev->name, sizeof(subdev->name), "%s rpf.%u",
		 dev_name(vsp1->dev), index);
	v4l2_set_subdevdata(subdev, rpf);
	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;

	vsp1_entity_init_formats(subdev, NULL);

	/* Initialize the video device. */
	video = &rpf->video;

	video->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
	video->vsp1 = vsp1;
	video->ops = &rpf_vdev_ops;

	ret = vsp1_video_init(video, &rpf->entity);
	if (ret < 0)
		goto error_video;

	/* Connect the video device to the RPF. */
	ret = media_entity_create_link(&rpf->video.video.entity, 0,
				       &rpf->entity.subdev.entity,
				       RWPF_PAD_SINK,
				       MEDIA_LNK_FL_ENABLED |
				       MEDIA_LNK_FL_IMMUTABLE);
	if (ret < 0)
		goto error_link;

	return rpf;

error_link:
	vsp1_video_cleanup(video);
error_video:
	media_entity_cleanup(&rpf->entity.subdev.entity);
	return ERR_PTR(ret);
}
Example #25
0
static int unicam_register_entities(struct unicam_device *unicam)
{
	struct unicam_platform_data *pdata = unicam->pdata;
	struct unicam_v4l2_subdevs_groups *subdevs;
	int ret, i;

	/* media device registration */
	unicam->media_dev.dev = unicam->dev;
	strlcpy(unicam->media_dev.model, "Broadcom Kona Unicam",
			sizeof(unicam->media_dev.model));
	unicam->media_dev.hw_revision = unicam->revision;
	unicam->media_dev.link_notify = unicam_pipeline_link_notify;
	ret = media_device_register(&unicam->media_dev);
	if (ret < 0) {
		dev_err(unicam->dev, "media device registration failed (%d)\n",
				ret);
		return ret;

	}

	/* v4l2 device registration */
	unicam->v4l2_dev.mdev = &unicam->media_dev;
	ret = v4l2_device_register(unicam->dev, &unicam->v4l2_dev);
	if (ret < 0) {
		dev_err(unicam->dev, "V4L2 device registration failed (%d)\n",
				ret);
		goto done;
	}

	/* now register all enitites */
	ret = kona_unicam_csi2_register_entities(&unicam->csi2a,
			&unicam->v4l2_dev);
	if (ret < 0) {
		dev_err(unicam->dev, "failed to register csi2a entities (%d)\n",
				ret);
		goto done;
	}

	/* now register external entities */
	for (i = 0; i < pdata->num_subdevs; i++) {
		struct v4l2_subdev *sensor;
		struct media_entity *input;
		unsigned int pad;

		subdevs = &pdata->subdevs[i];

		sensor = unicam_register_subdev_group(unicam,
				subdevs->i2c_info);
		if (sensor == NULL)
			continue;

		sensor->host_priv = subdevs;

		/*
		 * connect the sensor to the correct interface module.
		 * we only have one receiver here
		 */
		switch (subdevs->interface) {
		case UNICAM_INTERFACE_CSI2_PHY1:
			input = &unicam->csi2a.subdev.entity;
			pad = CSI2_PAD_SINK;
			break;

		default:
			dev_err(unicam->dev, "invalid interface type %u\n",
					subdevs->interface);
			goto done;
		}

		ret = media_entity_create_link(&sensor->entity, 0, input, pad,
				0);

		if (ret < 0)
			goto done;
	};

	ret = v4l2_device_register_subdev_nodes(&unicam->v4l2_dev);

done:
	if (ret < 0)
		unicam_unregister_entities(unicam);

	return ret;
}
static int vpfe_register_entities(struct vpfe_device *vpfe_dev)
{
	int ret, i;
	unsigned int flags = 0;

	/* register i2c devices first */
	ret = register_i2c_devices(vpfe_dev);
	if (ret)
		return ret;

	/* register rest of the sub-devs */
	ret = vpfe_ccdc_register_entities(&vpfe_dev->vpfe_ccdc,
					  &vpfe_dev->v4l2_dev);
	if (ret)
		return ret;

	ret = vpfe_previewer_register_entities(&vpfe_dev->vpfe_previewer,
					       &vpfe_dev->v4l2_dev);
	if (ret)
		goto out_ccdc_register;

	ret = vpfe_resizer_register_entities(&vpfe_dev->vpfe_resizer,
					     &vpfe_dev->v4l2_dev);
	if (ret)
		goto out_previewer_register;

	ret = vpfe_aew_register_entities(&vpfe_dev->vpfe_aew,
					 &vpfe_dev->v4l2_dev);
	if (ret)
		goto out_resizer_register;

	ret = vpfe_af_register_entities(&vpfe_dev->vpfe_af,
					&vpfe_dev->v4l2_dev);
	if (ret)
		goto out_aew_register;

	/* create links now, starting with external(i2c) entities */
	for (i = 0; i < vpfe_dev->num_subdevs; i++) {
		/* if entity has no pads (ex: amplifier),
		   cant establish link */
		if (vpfe_dev->sd[i]->entity.num_pads) {
			ret = media_entity_create_link(&vpfe_dev->sd[i]->entity,
				0, &vpfe_dev->vpfe_ccdc.subdev.entity,
				0, flags);
			if (ret < 0)
				goto out_resizer_register;
		}
	}

	ret = media_entity_create_link(&vpfe_dev->vpfe_ccdc.subdev.entity,
					1, &vpfe_dev->vpfe_aew.subdev.entity,
					0, flags);
	if (ret < 0)
		goto out_resizer_register;

	ret = media_entity_create_link(&vpfe_dev->vpfe_ccdc.subdev.entity,
					1, &vpfe_dev->vpfe_af.subdev.entity,
					0, flags);
	if (ret < 0)
		goto out_resizer_register;

	ret = media_entity_create_link(&vpfe_dev->vpfe_ccdc.subdev.entity,
				       1,
				       &vpfe_dev->vpfe_previewer.subdev.entity,
				       0, flags);
	if (ret < 0)
		goto out_resizer_register;

	ret = media_entity_create_link(&vpfe_dev->vpfe_previewer.subdev.entity,
				       1, &vpfe_dev->vpfe_resizer.subdev.entity,
				       0, flags);
	if (ret < 0)
		goto out_resizer_register;

	return 0;

out_aew_register:
	vpfe_aew_unregister_entities(&vpfe_dev->vpfe_aew);
out_resizer_register:
	vpfe_resizer_unregister_entities(&vpfe_dev->vpfe_resizer);
out_previewer_register:
	vpfe_previewer_unregister_entities(&vpfe_dev->vpfe_previewer);
out_ccdc_register:
	vpfe_ccdc_unregister_entities(&vpfe_dev->vpfe_ccdc);
	return ret;
}
struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
{
	struct v4l2_subdev *subdev;
	struct vsp1_video *video;
	struct vsp1_rwpf *wpf;
	unsigned int flags;
	int ret;

	wpf = devm_kzalloc(vsp1->dev, sizeof(*wpf), GFP_KERNEL);
	if (wpf == NULL)
		return ERR_PTR(-ENOMEM);

	wpf->max_width = WPF_MAX_WIDTH;
	wpf->max_height = WPF_MAX_HEIGHT;

	wpf->entity.type = VSP1_ENTITY_WPF;
	wpf->entity.index = index;

	ret = vsp1_entity_init(vsp1, &wpf->entity, 2);
	if (ret < 0)
		return ERR_PTR(ret);

	/* Initialize the V4L2 subdev. */
	subdev = &wpf->entity.subdev;
	v4l2_subdev_init(subdev, &wpf_ops);

	subdev->entity.ops = &vsp1_media_ops;
	subdev->internal_ops = &vsp1_subdev_internal_ops;
	snprintf(subdev->name, sizeof(subdev->name), "%s wpf.%u",
		 dev_name(vsp1->dev), index);
	v4l2_set_subdevdata(subdev, wpf);
	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;

	vsp1_entity_init_formats(subdev, NULL);

	/* Initialize the control handler. */
	v4l2_ctrl_handler_init(&wpf->ctrls, 1);
	v4l2_ctrl_new_std(&wpf->ctrls, &wpf_ctrl_ops, V4L2_CID_ALPHA_COMPONENT,
			  0, 255, 1, 255);

	wpf->entity.subdev.ctrl_handler = &wpf->ctrls;

	if (wpf->ctrls.error) {
		dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n",
			index);
		ret = wpf->ctrls.error;
		goto error;
	}

	/* Initialize the video device. */
	video = &wpf->video;

	video->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
	video->vsp1 = vsp1;
	video->ops = &wpf_vdev_ops;

	ret = vsp1_video_init(video, &wpf->entity);
	if (ret < 0)
		goto error;

	wpf->entity.video = video;

	/* Connect the video device to the WPF. All connections are immutable
	 * except for the WPF0 source link if a LIF is present.
	 */
	flags = MEDIA_LNK_FL_ENABLED;
	if (!(vsp1->pdata.features & VSP1_HAS_LIF) || index != 0)
		flags |= MEDIA_LNK_FL_IMMUTABLE;

	ret = media_entity_create_link(&wpf->entity.subdev.entity,
				       RWPF_PAD_SOURCE,
				       &wpf->video.video.entity, 0, flags);
	if (ret < 0)
		goto error;

	wpf->entity.sink = &wpf->video.video.entity;

	return wpf;

error:
	vsp1_entity_destroy(&wpf->entity);
	return ERR_PTR(ret);
}
Example #28
0
int register_nxp_out(struct nxp_out *me)
{
    int ret;

    pr_debug("%s\n", __func__);

    ret = register_nxp_mlc(me->mlcs[0]);
    if (ret < 0) {
        pr_err("%s: failed to register_nxp_mlc(0)\n", __func__);
        goto error_out;
    }

    ret = register_nxp_mlc(me->mlcs[1]);
    if (ret < 0) {
        pr_err("%s: failed to register_nxp_mlc(1)\n", __func__);
        goto error_out;
    }

#if defined(CONFIG_NXP_OUT_RESOLUTION_CONVERTER)
    ret = register_nxp_resc(me->resc);
    if (ret < 0) {
        pr_err("%s: failed to register_nxp_resc()\n", __func__);
        goto error_out;
    }

    /* create link */
    /* link mlc0 pad source to hdmi pad sink */
    ret = media_entity_create_link(
            &me->mlcs[0]->subdev.entity, NXP_MLC_PAD_SOURCE,
            &me->resc->subdev.entity, 0,
            0);
    if (ret < 0) {
        pr_err("%s: failed to link mlc0 to resc\n", __func__);
        goto error_out;
    }
    /* link mlc1 pad source to resc pad sink */
    ret = media_entity_create_link(
            &me->mlcs[1]->subdev.entity, NXP_MLC_PAD_SOURCE,
            &me->resc->subdev.entity, 0,
            0);
    if (ret < 0) {
        pr_err("%s: failed to link mlc1 to resc\n", __func__);
        goto error_out;
    }
#endif

#if defined(CONFIG_NXP_OUT_HDMI)
    ret = register_nxp_hdmi(me->hdmi);
    if (ret < 0) {
        pr_err("%s: failed to register_nxp_hdmi()\n", __func__);
        goto error_out;
    }

    /* create link */
    /* link mlc0 pad source to hdmi pad sink */
    ret = media_entity_create_link(
            &me->mlcs[0]->subdev.entity, NXP_MLC_PAD_SOURCE,
            &me->hdmi->sd.entity, 0,
            0);
    if (ret < 0) {
        pr_err("%s: failed to link mlc0 to hdmi\n", __func__);
        goto error_out;
    }
    /* link mlc1 pad source to hdmi pad sink */
    ret = media_entity_create_link(
            &me->mlcs[1]->subdev.entity, NXP_MLC_PAD_SOURCE,
            &me->hdmi->sd.entity, 0,
            0);
    if (ret < 0) {
        pr_err("%s: failed to link mlc1 to hdmi\n", __func__);
        goto error_out;
    }

#if defined(CONFIG_NXP_OUT_RESOLUTION_CONVERTER)
    /* link resc pad source to hdmi pad sink */
    ret = media_entity_create_link(
            &me->resc->subdev.entity, NXP_RESC_PAD_SOURCE,
            &me->hdmi->sd.entity, 0,
            0);
    if (ret < 0) {
        pr_err("%s: failed to link resc to hdmi\n", __func__);
        goto error_out;
    }
#endif

#endif

    return 0;

error_out:
#if defined(CONFIG_NXP_OUT_RESOLUTION_CONVERTER)
    unregister_nxp_resc(me->resc);
#endif
#if defined(CONFIG_NXP_OUT_HDMI)
    unregister_nxp_hdmi(me->hdmi);
#endif
    unregister_nxp_mlc(me->mlcs[1]);
    unregister_nxp_mlc(me->mlcs[0]);
    return ret;
}
Example #29
0
/**
 * __fimc_md_create_fimc_links - create links to all FIMC entities
 * @fmd: fimc media device
 * @source: the source entity to create links to all fimc entities from
 * @sensor: sensor subdev linked to FIMC[fimc_id] entity, may be null
 * @pad: the source entity pad index
 * @link_mask: bitmask of the fimc devices for which link should be enabled
 */
static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
					    struct media_entity *source,
					    struct v4l2_subdev *sensor,
					    int pad, int link_mask)
{
	struct fimc_sensor_info *s_info;
	struct media_entity *sink;
	unsigned int flags = 0;
	int ret, i;

	for (i = 0; i < FIMC_MAX_DEVS; i++) {
		if (!fmd->fimc[i])
			continue;
		/*
		 * Some FIMC variants are not fitted with camera capture
		 * interface. Skip creating a link from sensor for those.
		 */
		if (!fmd->fimc[i]->variant->has_cam_if)
			continue;

		flags = ((1 << i) & link_mask) ? MEDIA_LNK_FL_ENABLED : 0;

		sink = &fmd->fimc[i]->vid_cap.subdev.entity;
		ret = media_entity_create_link(source, pad, sink,
					      FIMC_SD_PAD_SINK, flags);
		if (ret)
			return ret;

		/* Notify FIMC capture subdev entity */
		ret = media_entity_call(sink, link_setup, &sink->pads[0],
					&source->pads[pad], flags);
		if (ret)
			break;

		v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]",
			  source->name, flags ? '=' : '-', sink->name);

		if (flags == 0 || sensor == NULL)
			continue;
		s_info = v4l2_get_subdev_hostdata(sensor);
		if (!(s_info == NULL)&&!i) {
			unsigned long irq_flags;
			spin_lock_irqsave(&fmd->slock, irq_flags);
			s_info->host = fmd->fimc[i];
			spin_unlock_irqrestore(&fmd->slock, irq_flags);
		}
	}

	for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
		if (!fmd->fimc_lite[i])
			continue;

		if (link_mask & (1 << (i + FIMC_MAX_DEVS)))
			flags = MEDIA_LNK_FL_ENABLED;
		else
			flags = 0;

		sink = &fmd->fimc_lite[i]->subdev.entity;
		ret = media_entity_create_link(source, pad, sink,
					       FLITE_SD_PAD_SINK, flags);
		if (ret)
			return ret;

		/* Notify FIMC-LITE subdev entity */
		ret = media_entity_call(sink, link_setup, &sink->pads[0],
					&source->pads[pad], flags);
		if (ret)
			break;

		v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]",
			  source->name, flags ? '=' : '-', sink->name);
	}
	return 0;
}
Example #30
0
/*
 * isp_subdev_init_entities - Initialize V4L2 subdev and media entity
 * @isp_subdev: ISP CCDC module
 *
 * Return 0 on success and a negative error code on failure.
 */
static int isp_subdev_init_entities(struct atomisp_sub_device *isp_subdev)
{
    struct v4l2_subdev *sd = &isp_subdev->subdev;
    struct media_pad *pads = isp_subdev->pads;
    struct media_entity *me = &sd->entity;
    int ret;

    isp_subdev->input = ATOMISP_SUBDEV_INPUT_NONE;

    v4l2_subdev_init(sd, &isp_subdev_v4l2_ops);
    strlcpy(sd->name, "ATOM ISP SUBDEV", sizeof(sd->name));
    v4l2_set_subdevdata(sd, isp_subdev);
    sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
    sd->nevents = 16; /* TBD */

    pads[ATOMISP_SUBDEV_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
    pads[ATOMISP_SUBDEV_PAD_SOURCE_VF].flags = MEDIA_PAD_FL_SOURCE;
    pads[ATOMISP_SUBDEV_PAD_SOURCE_MO].flags = MEDIA_PAD_FL_SOURCE;

    isp_subdev->formats[ATOMISP_SUBDEV_PAD_SINK].code =
        V4L2_MBUS_FMT_SBGGR10_1X10;
    isp_subdev->formats[ATOMISP_SUBDEV_PAD_SOURCE_VF].code =
        V4L2_MBUS_FMT_SBGGR10_1X10;
    isp_subdev->formats[ATOMISP_SUBDEV_PAD_SOURCE_MO].code =
        V4L2_MBUS_FMT_SBGGR10_1X10;

    me->ops = &isp_subdev_media_ops;
    me->type = MEDIA_ENT_T_V4L2_SUBDEV;
    ret = media_entity_init(me, ATOMISP_SUBDEV_PADS_NUM, pads, 0);
    if (ret < 0)
        return ret;

    isp_subdev->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
    isp_subdev->video_in.isp = isp_subdev->isp;
    spin_lock_init(&isp_subdev->video_in.irq_lock);

    isp_subdev->video_out_vf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    isp_subdev->video_out_vf.isp = isp_subdev->isp;
    isp_subdev->video_out_vf.is_main = false;
    spin_lock_init(&isp_subdev->video_out_vf.irq_lock);

    isp_subdev->video_out_mo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    isp_subdev->video_out_mo.isp = isp_subdev->isp;
    isp_subdev->video_out_mo.is_main = true;
    spin_lock_init(&isp_subdev->video_out_mo.irq_lock);

    ret = atomisp_video_init(&isp_subdev->video_in, "MEMORY");
    if (ret < 0)
        return ret;

    ret = atomisp_video_init(&isp_subdev->video_out_mo, "MAINOUTPUT");
    if (ret < 0)
        return ret;

    ret = atomisp_video_init(&isp_subdev->video_out_vf, "VIEWFINDER");
    if (ret < 0)
        return ret;

    /* Connect the isp subdev to the video node. */
    ret = media_entity_create_link(&isp_subdev->video_in.vdev.entity,
                                   0, &isp_subdev->subdev.entity, ATOMISP_SUBDEV_PAD_SINK, 0);
    if (ret < 0)
        return ret;
    ret = media_entity_create_link(&isp_subdev->subdev.entity,
                                   ATOMISP_SUBDEV_PAD_SOURCE_VF,
                                   &isp_subdev->video_out_vf.vdev.entity, 0, 0);
    if (ret < 0)
        return ret;

    ret = media_entity_create_link(&isp_subdev->subdev.entity,
                                   ATOMISP_SUBDEV_PAD_SOURCE_MO,
                                   &isp_subdev->video_out_mo.vdev.entity, 0, 0);
    if (ret < 0)
        return ret;

    return 0;
}