Lines Matching +full:csi +full:- +full:2

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
28 #include <media/v4l2-async.h>
29 #include <media/v4l2-ctrls.h>
30 #include <media/v4l2-fwnode.h>
31 #include <media/v4l2-subdev.h>
34 #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 */
55 CSI_SET_CONF = 2,
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 */
89 u32 rsvd[2];
92 /* CSI command structure */
101 /* CSI notification structure */
136 /* number of data lanes used on the CSI-2 link */
138 /* frequency of the CSI-2 link */
168 return container_of(ctrl->handler, struct mei_csi, ctrl_handler); in ctrl_to_csi()
172 static int mei_csi_send(struct mei_csi *csi, u8 *buf, size_t len) in mei_csi_send() argument
177 reinit_completion(&csi->cmd_completion); in mei_csi_send()
179 ret = mei_cldev_send(csi->cldev, buf, len); in mei_csi_send()
183 ret = wait_for_completion_killable_timeout(&csi->cmd_completion, in mei_csi_send()
188 ret = -ETIMEDOUT; in mei_csi_send()
193 ret = csi->cmd_response.status; in mei_csi_send()
194 if (ret == -1) { in mei_csi_send()
197 v4l2_ctrl_s_ctrl(csi->privacy_ctrl, 1); in mei_csi_send()
199 ret = -EINVAL; in mei_csi_send()
203 if (csi->cmd_response.cmd_id != cmd->cmd_id) in mei_csi_send()
204 ret = -EINVAL; in mei_csi_send()
210 /* set CSI-2 link ownership */
211 static int csi_set_link_owner(struct mei_csi *csi, enum csi_link_owner owner) in csi_set_link_owner() argument
221 mutex_lock(&csi->lock); in csi_set_link_owner()
223 ret = mei_csi_send(csi, (u8 *)&cmd, cmd_size); in csi_set_link_owner()
225 mutex_unlock(&csi->lock); in csi_set_link_owner()
230 /* configure CSI-2 link between host and IVSC */
231 static int csi_set_link_cfg(struct mei_csi *csi) in csi_set_link_cfg() argument
238 cmd.param.conf.nr_of_lanes = csi->nr_of_lanes; in csi_set_link_cfg()
239 cmd.param.conf.link_freq = CSI_LINK_FREQ(csi->link_freq); in csi_set_link_cfg()
242 mutex_lock(&csi->lock); in csi_set_link_cfg()
244 ret = mei_csi_send(csi, (u8 *)&cmd, cmd_size); in csi_set_link_cfg()
253 mutex_unlock(&csi->lock); in csi_set_link_cfg()
261 struct mei_csi *csi = mei_cldev_get_drvdata(cldev); in mei_csi_rx() local
267 dev_err(&cldev->dev, "recv error: %d\n", ret); in mei_csi_rx()
274 csi->status = notif.cont.cont; in mei_csi_rx()
275 v4l2_ctrl_s_ctrl(csi->privacy_ctrl, csi->status); in mei_csi_rx()
280 memcpy(&csi->cmd_response, &notif, ret); in mei_csi_rx()
282 complete(&csi->cmd_completion); in mei_csi_rx()
291 struct mei_csi *csi = sd_to_csi(sd); in mei_csi_set_stream() local
295 if (enable && csi->streaming == 0) { in mei_csi_set_stream()
296 freq = v4l2_get_link_freq(csi->remote->ctrl_handler, 0, 0); in mei_csi_set_stream()
298 dev_err(&csi->cldev->dev, in mei_csi_set_stream()
303 csi->link_freq = freq; in mei_csi_set_stream()
305 /* switch CSI-2 link to host */ in mei_csi_set_stream()
306 ret = csi_set_link_owner(csi, CSI_LINK_HOST); in mei_csi_set_stream()
310 /* configure CSI-2 link */ in mei_csi_set_stream()
311 ret = csi_set_link_cfg(csi); in mei_csi_set_stream()
315 ret = v4l2_subdev_call(csi->remote, video, s_stream, 1); in mei_csi_set_stream()
318 } else if (!enable && csi->streaming == 1) { in mei_csi_set_stream()
319 v4l2_subdev_call(csi->remote, video, s_stream, 0); in mei_csi_set_stream()
321 /* switch CSI-2 link to IVSC */ in mei_csi_set_stream()
322 ret = csi_set_link_owner(csi, CSI_LINK_IVSC); in mei_csi_set_stream()
324 dev_warn(&csi->cldev->dev, in mei_csi_set_stream()
328 csi->streaming = enable; in mei_csi_set_stream()
333 csi_set_link_owner(csi, CSI_LINK_IVSC); in mei_csi_set_stream()
344 struct mei_csi *csi = sd_to_csi(sd); in mei_csi_get_pad_format() local
350 return &csi->format_mbus[pad]; in mei_csi_get_pad_format()
360 struct mei_csi *csi = sd_to_csi(sd); in mei_csi_init_cfg() local
363 mutex_lock(&csi->lock); in mei_csi_init_cfg()
365 for (i = 0; i < sd->entity.num_pads; i++) { in mei_csi_init_cfg()
370 mutex_unlock(&csi->lock); in mei_csi_init_cfg()
380 struct mei_csi *csi = sd_to_csi(sd); in mei_csi_get_fmt() local
382 mutex_lock(&csi->lock); in mei_csi_get_fmt()
384 mbusformat = mei_csi_get_pad_format(sd, sd_state, format->pad, in mei_csi_get_fmt()
385 format->which); in mei_csi_get_fmt()
387 format->format = *mbusformat; in mei_csi_get_fmt()
389 mutex_unlock(&csi->lock); in mei_csi_get_fmt()
400 struct mei_csi *csi = sd_to_csi(sd); in mei_csi_set_fmt() local
403 mbusformat = mei_csi_get_pad_format(sd, sd_state, format->pad, in mei_csi_set_fmt()
404 format->which); in mei_csi_set_fmt()
406 return -EINVAL; in mei_csi_set_fmt()
409 format->which); in mei_csi_set_fmt()
411 return -EINVAL; in mei_csi_set_fmt()
413 v4l_bound_align_image(&format->format.width, 1, 65536, 0, in mei_csi_set_fmt()
414 &format->format.height, 1, 65536, 0, 0); in mei_csi_set_fmt()
416 switch (format->format.code) { in mei_csi_set_fmt()
507 format->format.code = MEDIA_BUS_FMT_Y8_1X8; in mei_csi_set_fmt()
511 if (format->format.field == V4L2_FIELD_ANY) in mei_csi_set_fmt()
512 format->format.field = V4L2_FIELD_NONE; in mei_csi_set_fmt()
514 mutex_lock(&csi->lock); in mei_csi_set_fmt()
516 pad = &csi->pads[format->pad]; in mei_csi_set_fmt()
517 if (pad->flags & MEDIA_PAD_FL_SOURCE) in mei_csi_set_fmt()
518 format->format = csi->format_mbus[CSI_PAD_SINK]; in mei_csi_set_fmt()
520 *mbusformat = format->format; in mei_csi_set_fmt()
522 if (pad->flags & MEDIA_PAD_FL_SINK) in mei_csi_set_fmt()
523 *source_mbusformat = format->format; in mei_csi_set_fmt()
525 mutex_unlock(&csi->lock); in mei_csi_set_fmt()
532 struct mei_csi *csi = ctrl_to_csi(ctrl); in mei_csi_g_volatile_ctrl() local
535 if (ctrl->id == V4L2_CID_LINK_FREQ) { in mei_csi_g_volatile_ctrl()
536 if (!csi->remote) in mei_csi_g_volatile_ctrl()
537 return -EINVAL; in mei_csi_g_volatile_ctrl()
539 freq = v4l2_get_link_freq(csi->remote->ctrl_handler, 0, 0); in mei_csi_g_volatile_ctrl()
541 dev_err(&csi->cldev->dev, in mei_csi_g_volatile_ctrl()
543 return -EINVAL; in mei_csi_g_volatile_ctrl()
547 ctrl->val = 0; in mei_csi_g_volatile_ctrl()
552 return -EINVAL; in mei_csi_g_volatile_ctrl()
582 struct mei_csi *csi = notifier_to_csi(notifier); in mei_csi_notify_bound() local
585 pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode, in mei_csi_notify_bound()
590 csi->remote = subdev; in mei_csi_notify_bound()
591 csi->remote_pad = pad; in mei_csi_notify_bound()
593 return media_create_pad_link(&subdev->entity, pad, in mei_csi_notify_bound()
594 &csi->subdev.entity, CSI_PAD_SINK, in mei_csi_notify_bound()
603 struct mei_csi *csi = notifier_to_csi(notifier); in mei_csi_notify_unbind() local
605 csi->remote = NULL; in mei_csi_notify_unbind()
613 static int mei_csi_init_controls(struct mei_csi *csi) in mei_csi_init_controls() argument
618 mutex_init(&csi->ctrl_lock); in mei_csi_init_controls()
620 ret = v4l2_ctrl_handler_init(&csi->ctrl_handler, 2); in mei_csi_init_controls()
624 csi->ctrl_handler.lock = &csi->ctrl_lock; in mei_csi_init_controls()
626 max = ARRAY_SIZE(link_freq_menu_items) - 1; in mei_csi_init_controls()
627 csi->freq_ctrl = v4l2_ctrl_new_int_menu(&csi->ctrl_handler, in mei_csi_init_controls()
633 if (csi->freq_ctrl) in mei_csi_init_controls()
634 csi->freq_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY | in mei_csi_init_controls()
637 csi->privacy_ctrl = v4l2_ctrl_new_std(&csi->ctrl_handler, NULL, in mei_csi_init_controls()
639 if (csi->privacy_ctrl) in mei_csi_init_controls()
640 csi->privacy_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; in mei_csi_init_controls()
642 if (csi->ctrl_handler.error) in mei_csi_init_controls()
643 return csi->ctrl_handler.error; in mei_csi_init_controls()
645 csi->subdev.ctrl_handler = &csi->ctrl_handler; in mei_csi_init_controls()
650 static int mei_csi_parse_firmware(struct mei_csi *csi) in mei_csi_parse_firmware() argument
655 struct device *dev = &csi->cldev->dev; in mei_csi_parse_firmware()
664 return -EINVAL; in mei_csi_parse_firmware()
671 return -EINVAL; in mei_csi_parse_firmware()
677 v4l2_async_subdev_nf_init(&csi->notifier, &csi->subdev); in mei_csi_parse_firmware()
678 csi->notifier.ops = &mei_csi_notify_ops; in mei_csi_parse_firmware()
680 asd = v4l2_async_nf_add_fwnode(&csi->notifier, fwnode, in mei_csi_parse_firmware()
691 csi->nr_of_lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes; in mei_csi_parse_firmware()
693 ret = v4l2_async_nf_register(&csi->notifier); in mei_csi_parse_firmware()
695 v4l2_async_nf_cleanup(&csi->notifier); in mei_csi_parse_firmware()
705 struct device *dev = &cldev->dev; in mei_csi_probe()
706 struct mei_csi *csi; in mei_csi_probe() local
710 return -EPROBE_DEFER; in mei_csi_probe()
712 csi = devm_kzalloc(dev, sizeof(struct mei_csi), GFP_KERNEL); in mei_csi_probe()
713 if (!csi) in mei_csi_probe()
714 return -ENOMEM; in mei_csi_probe()
716 csi->cldev = cldev; in mei_csi_probe()
717 mutex_init(&csi->lock); in mei_csi_probe()
718 init_completion(&csi->cmd_completion); in mei_csi_probe()
720 mei_cldev_set_drvdata(cldev, csi); in mei_csi_probe()
734 ret = mei_csi_parse_firmware(csi); in mei_csi_probe()
738 csi->subdev.dev = &cldev->dev; in mei_csi_probe()
739 v4l2_subdev_init(&csi->subdev, &mei_csi_subdev_ops); in mei_csi_probe()
740 v4l2_set_subdevdata(&csi->subdev, csi); in mei_csi_probe()
741 csi->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE | in mei_csi_probe()
743 csi->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; in mei_csi_probe()
744 csi->subdev.entity.ops = &mei_csi_entity_ops; in mei_csi_probe()
746 snprintf(csi->subdev.name, sizeof(csi->subdev.name), in mei_csi_probe()
749 ret = mei_csi_init_controls(csi); in mei_csi_probe()
753 csi->format_mbus[CSI_PAD_SOURCE] = mei_csi_format_mbus_default; in mei_csi_probe()
754 csi->format_mbus[CSI_PAD_SINK] = mei_csi_format_mbus_default; in mei_csi_probe()
756 csi->pads[CSI_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; in mei_csi_probe()
757 csi->pads[CSI_PAD_SINK].flags = MEDIA_PAD_FL_SINK; in mei_csi_probe()
758 ret = media_entity_pads_init(&csi->subdev.entity, CSI_NUM_PADS, in mei_csi_probe()
759 csi->pads); in mei_csi_probe()
763 ret = v4l2_subdev_init_finalize(&csi->subdev); in mei_csi_probe()
767 ret = v4l2_async_register_subdev(&csi->subdev); in mei_csi_probe()
771 pm_runtime_enable(&cldev->dev); in mei_csi_probe()
776 v4l2_subdev_cleanup(&csi->subdev); in mei_csi_probe()
779 media_entity_cleanup(&csi->subdev.entity); in mei_csi_probe()
782 v4l2_ctrl_handler_free(&csi->ctrl_handler); in mei_csi_probe()
783 mutex_destroy(&csi->ctrl_lock); in mei_csi_probe()
784 v4l2_async_nf_unregister(&csi->notifier); in mei_csi_probe()
785 v4l2_async_nf_cleanup(&csi->notifier); in mei_csi_probe()
791 mutex_destroy(&csi->lock); in mei_csi_probe()
798 struct mei_csi *csi = mei_cldev_get_drvdata(cldev); in mei_csi_remove() local
800 v4l2_async_nf_unregister(&csi->notifier); in mei_csi_remove()
801 v4l2_async_nf_cleanup(&csi->notifier); in mei_csi_remove()
802 v4l2_ctrl_handler_free(&csi->ctrl_handler); in mei_csi_remove()
803 mutex_destroy(&csi->ctrl_lock); in mei_csi_remove()
804 v4l2_async_unregister_subdev(&csi->subdev); in mei_csi_remove()
805 v4l2_subdev_cleanup(&csi->subdev); in mei_csi_remove()
806 media_entity_cleanup(&csi->subdev.entity); in mei_csi_remove()
808 pm_runtime_disable(&cldev->dev); in mei_csi_remove()
810 mutex_destroy(&csi->lock); in mei_csi_remove()
834 MODULE_DESCRIPTION("Device driver for IVSC CSI");