Lines Matching +full:csi +full:- +full:bridge
1 // SPDX-License-Identifier: GPL-2.0-only
4 * Intel Visual Sensing Controller CSI Linux driver
8 * To set ownership of CSI-2 link and to configure CSI-2 link, there
29 #include <media/ipu-bridge.h>
30 #include <media/ipu6-pci-table.h>
31 #include <media/v4l2-async.h>
32 #include <media/v4l2-ctrls.h>
33 #include <media/v4l2-fwnode.h>
34 #include <media/v4l2-subdev.h>
36 #define MEI_CSI_ENTITY_NAME "Intel IVSC CSI"
40 /* to setup CSI-2 link an extra delay needed and determined experimentally */
51 /* used to set csi ownership */
54 /* used to configure CSI-2 link */
61 /* CSI-2 link ownership definition */
80 /* configuration of the CSI-2 link between host and IVSC */
82 /* number of data lanes used on the CSI-2 link */
85 /* frequency of the CSI-2 link */
92 /* CSI command structure */
101 /* CSI notification structure */
134 /* number of data lanes used on the CSI-2 link */
136 /* frequency of the CSI-2 link */
158 static int mei_csi_send(struct mei_csi *csi, u8 *buf, size_t len)
163 reinit_completion(&csi->cmd_completion);
165 ret = mei_cldev_send(csi->cldev, buf, len);
169 ret = wait_for_completion_killable_timeout(&csi->cmd_completion,
174 ret = -ETIMEDOUT;
179 ret = csi->cmd_response.status;
180 if (ret == -1) {
183 v4l2_ctrl_s_ctrl(csi->privacy_ctrl, 1);
185 ret = -EINVAL;
189 if (csi->cmd_response.cmd_id != cmd->cmd_id)
190 ret = -EINVAL;
196 /* set CSI-2 link ownership */
197 static int csi_set_link_owner(struct mei_csi *csi, enum csi_link_owner owner)
207 mutex_lock(&csi->lock);
209 ret = mei_csi_send(csi, (u8 *)&cmd, cmd_size);
211 mutex_unlock(&csi->lock);
216 /* configure CSI-2 link between host and IVSC */
217 static int csi_set_link_cfg(struct mei_csi *csi)
224 cmd.param.conf.nr_of_lanes = csi->nr_of_lanes;
225 cmd.param.conf.link_freq = CSI_LINK_FREQ(csi->link_freq);
228 mutex_lock(&csi->lock);
230 ret = mei_csi_send(csi, (u8 *)&cmd, cmd_size);
239 mutex_unlock(&csi->lock);
247 struct mei_csi *csi = mei_cldev_get_drvdata(cldev);
253 dev_err(&cldev->dev, "recv error: %d\n", ret);
260 v4l2_ctrl_s_ctrl(csi->privacy_ctrl,
265 memcpy(&csi->cmd_response, ¬if, ret);
267 complete(&csi->cmd_completion);
276 struct mei_csi *csi = sd_to_csi(sd);
278 media_entity_to_v4l2_subdev(csi->remote->entity);
282 if (enable && csi->streaming == 0) {
283 freq = v4l2_get_link_freq(csi->remote, 0, 0);
285 dev_err(&csi->cldev->dev,
290 csi->link_freq = freq;
292 /* switch CSI-2 link to host */
293 ret = csi_set_link_owner(csi, CSI_LINK_HOST);
297 /* configure CSI-2 link */
298 ret = csi_set_link_cfg(csi);
305 } else if (!enable && csi->streaming == 1) {
308 /* switch CSI-2 link to IVSC */
309 ret = csi_set_link_owner(csi, CSI_LINK_IVSC);
311 dev_warn(&csi->cldev->dev,
315 csi->streaming = enable;
320 csi_set_link_owner(csi, CSI_LINK_IVSC);
332 for (i = 0; i < sd->entity.num_pads; i++) {
350 if (format->pad) {
356 v4l_bound_align_image(&format->format.width, 1, 65536, 0,
357 &format->format.height, 1, 65536, 0, 0);
359 switch (format->format.code) {
450 format->format.code = MEDIA_BUS_FMT_Y8_1X8;
454 if (format->format.field == V4L2_FIELD_ANY)
455 format->format.field = V4L2_FIELD_NONE;
457 *sink_fmt = format->format;
466 struct mei_csi *csi = sd_to_csi(sd);
470 mbus_config->type = V4L2_MBUS_CSI2_DPHY;
472 mbus_config->bus.mipi_csi2.data_lanes[i] = i + 1;
473 mbus_config->bus.mipi_csi2.num_data_lanes = csi->nr_of_lanes;
475 freq = v4l2_get_link_freq(csi->remote, 0, 0);
477 dev_err(&csi->cldev->dev,
479 return -EINVAL;
482 csi->link_freq = freq;
483 mbus_config->link_freq = freq;
515 struct mei_csi *csi = notifier_to_csi(notifier);
518 pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode,
523 csi->remote = &subdev->entity.pads[pad];
525 return media_create_pad_link(&subdev->entity, pad,
526 &csi->subdev.entity, CSI_PAD_SINK,
535 struct mei_csi *csi = notifier_to_csi(notifier);
537 csi->remote = NULL;
545 static int mei_csi_init_controls(struct mei_csi *csi)
549 mutex_init(&csi->ctrl_lock);
551 ret = v4l2_ctrl_handler_init(&csi->ctrl_handler, 1);
555 csi->ctrl_handler.lock = &csi->ctrl_lock;
557 csi->privacy_ctrl = v4l2_ctrl_new_std(&csi->ctrl_handler, NULL,
559 if (csi->privacy_ctrl)
560 csi->privacy_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
562 if (csi->ctrl_handler.error)
563 return csi->ctrl_handler.error;
565 csi->subdev.ctrl_handler = &csi->ctrl_handler;
570 static int mei_csi_parse_firmware(struct mei_csi *csi)
575 struct device *dev = &csi->cldev->dev;
583 return -EINVAL;
586 v4l2_async_subdev_nf_init(&csi->notifier, &csi->subdev);
587 csi->notifier.ops = &mei_csi_notify_ops;
595 csi->nr_of_lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes;
599 ret = -ENOTCONN;
611 if (csi->nr_of_lanes != v4l2_ep.bus.mipi_csi2.num_data_lanes) {
612 ret = -EINVAL;
615 csi->nr_of_lanes, v4l2_ep.bus.mipi_csi2.num_data_lanes);
619 asd = v4l2_async_nf_add_fwnode_remote(&csi->notifier, sink_ep,
626 ret = v4l2_async_nf_register(&csi->notifier);
635 v4l2_async_nf_cleanup(&csi->notifier);
644 struct device *dev = &cldev->dev;
646 struct mei_csi *csi;
655 return -ENODEV;
657 ret = ipu_bridge_init(&ipu->dev, ipu_bridge_parse_ssdb);
658 put_device(&ipu->dev);
662 dev_err(dev, "mei-csi probed without device fwnode!\n");
663 return -ENXIO;
666 csi = devm_kzalloc(dev, sizeof(struct mei_csi), GFP_KERNEL);
667 if (!csi)
668 return -ENOMEM;
670 csi->cldev = cldev;
671 mutex_init(&csi->lock);
672 init_completion(&csi->cmd_completion);
674 mei_cldev_set_drvdata(cldev, csi);
688 ret = mei_csi_parse_firmware(csi);
692 csi->subdev.dev = &cldev->dev;
693 csi->subdev.state_lock = &csi->lock;
694 v4l2_subdev_init(&csi->subdev, &mei_csi_subdev_ops);
695 csi->subdev.internal_ops = &mei_csi_internal_ops;
696 v4l2_set_subdevdata(&csi->subdev, csi);
697 csi->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE |
699 csi->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
700 csi->subdev.entity.ops = &mei_csi_entity_ops;
702 snprintf(csi->subdev.name, sizeof(csi->subdev.name),
705 ret = mei_csi_init_controls(csi);
709 csi->pads[CSI_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
710 csi->pads[CSI_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
711 ret = media_entity_pads_init(&csi->subdev.entity, CSI_NUM_PADS,
712 csi->pads);
716 ret = v4l2_subdev_init_finalize(&csi->subdev);
720 ret = v4l2_async_register_subdev(&csi->subdev);
724 pm_runtime_enable(&cldev->dev);
729 v4l2_subdev_cleanup(&csi->subdev);
732 media_entity_cleanup(&csi->subdev.entity);
735 v4l2_ctrl_handler_free(&csi->ctrl_handler);
736 mutex_destroy(&csi->ctrl_lock);
737 v4l2_async_nf_unregister(&csi->notifier);
738 v4l2_async_nf_cleanup(&csi->notifier);
744 mutex_destroy(&csi->lock);
751 struct mei_csi *csi = mei_cldev_get_drvdata(cldev);
753 v4l2_async_nf_unregister(&csi->notifier);
754 v4l2_async_nf_cleanup(&csi->notifier);
755 v4l2_ctrl_handler_free(&csi->ctrl_handler);
756 mutex_destroy(&csi->ctrl_lock);
757 v4l2_async_unregister_subdev(&csi->subdev);
758 v4l2_subdev_cleanup(&csi->subdev);
759 media_entity_cleanup(&csi->subdev.entity);
761 pm_runtime_disable(&cldev->dev);
763 mutex_destroy(&csi->lock);
788 MODULE_DESCRIPTION("Device driver for IVSC CSI");