Lines Matching +full:fimc +full:- +full:is

1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd.
11 #include <linux/clk-provider.h>
26 #include <media/v4l2-async.h>
27 #include <media/v4l2-ctrls.h>
28 #include <media/v4l2-fwnode.h>
29 #include <media/media-device.h>
30 #include <media/drv-intf/exynos-fimc.h>
32 #include "media-dev.h"
33 #include "fimc-core.h"
34 #include "fimc-is.h"
35 #include "fimc-lite.h"
36 #include "mipi-csis.h"
38 /* Set up image sensor subdev -> FIMC capture node notifications. */
52 spin_lock_irqsave(&fmd->slock, flags); in __setup_sensor_notification()
53 md_si->host = v4l2_get_subdevdata(fimc_sd); in __setup_sensor_notification()
54 spin_unlock_irqrestore(&fmd->slock, flags); in __setup_sensor_notification()
58 * fimc_pipeline_prepare - update pipeline information with subdevice pointers
59 * @p: fimc pipeline
73 p->subdevs[i] = NULL; in fimc_pipeline_prepare()
79 for (i = 0; i < me->num_pads; i++) { in fimc_pipeline_prepare()
80 struct media_pad *spad = &me->pads[i]; in fimc_pipeline_prepare()
81 if (!(spad->flags & MEDIA_PAD_FL_SINK)) in fimc_pipeline_prepare()
88 if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) in fimc_pipeline_prepare()
90 sd = media_entity_to_v4l2_subdev(pad->entity); in fimc_pipeline_prepare()
92 switch (sd->grp_id) { in fimc_pipeline_prepare()
97 p->subdevs[IDX_SENSOR] = sd; in fimc_pipeline_prepare()
100 p->subdevs[IDX_CSIS] = sd; in fimc_pipeline_prepare()
103 p->subdevs[IDX_FLITE] = sd; in fimc_pipeline_prepare()
106 p->subdevs[IDX_FIMC] = sd; in fimc_pipeline_prepare()
109 p->subdevs[IDX_IS_ISP] = sd; in fimc_pipeline_prepare()
114 me = &sd->entity; in fimc_pipeline_prepare()
115 if (me->num_pads == 1) in fimc_pipeline_prepare()
119 if (sensor && p->subdevs[IDX_FIMC]) in fimc_pipeline_prepare()
120 __setup_sensor_notification(fmd, sensor, p->subdevs[IDX_FIMC]); in fimc_pipeline_prepare()
124 * __subdev_set_power - change power state of a single subdev
128 * Return result of s_power subdev operation or -ENXIO if sd argument
129 * is NULL. Return 0 if the subdevice does not implement s_power.
137 return -ENXIO; in __subdev_set_power()
139 use_count = &sd->entity.use_count; in __subdev_set_power()
142 else if (!on && (*use_count == 0 || --(*use_count) > 0)) in __subdev_set_power()
146 return ret != -ENOIOCTLCMD ? ret : 0; in __subdev_set_power()
150 * fimc_pipeline_s_power - change power state of all pipeline subdevs
151 * @p: fimc device terminating the pipeline
158 static const u8 seq[2][IDX_MAX - 1] = { in fimc_pipeline_s_power()
164 if (p->subdevs[IDX_SENSOR] == NULL) in fimc_pipeline_s_power()
165 return -ENXIO; in fimc_pipeline_s_power()
167 for (i = 0; i < IDX_MAX - 1; i++) { in fimc_pipeline_s_power()
170 ret = __subdev_set_power(p->subdevs[idx], on); in fimc_pipeline_s_power()
173 if (ret < 0 && ret != -ENXIO) in fimc_pipeline_s_power()
178 for (; i >= 0; i--) { in fimc_pipeline_s_power()
180 __subdev_set_power(p->subdevs[idx], !on); in fimc_pipeline_s_power()
186 * __fimc_pipeline_enable - enable power of all pipeline subdevs
189 * @fmd: fimc media device
199 /* Enable PXLASYNC clock if this pipeline includes FIMC-IS */ in __fimc_pipeline_enable()
200 if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) { in __fimc_pipeline_enable()
201 ret = clk_prepare_enable(fmd->wbclk[CLK_IDX_WB_B]); in __fimc_pipeline_enable()
210 if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) in __fimc_pipeline_enable()
211 clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]); in __fimc_pipeline_enable()
217 * __fimc_pipeline_open - update the pipeline information, enable power
219 * @ep: fimc device terminating the pipeline
233 return -EINVAL; in __fimc_pipeline_open()
238 sd = p->subdevs[IDX_SENSOR]; in __fimc_pipeline_open()
252 * __fimc_pipeline_close - disable the sensor clock and pipeline power
253 * @ep: fimc device terminating the pipeline
260 struct v4l2_subdev *sd = p ? p->subdevs[IDX_SENSOR] : NULL; in __fimc_pipeline_close()
271 fmd = entity_to_fimc_mdev(&sd->entity); in __fimc_pipeline_close()
273 /* Disable PXLASYNC clock if this pipeline includes FIMC-IS */ in __fimc_pipeline_close()
274 if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) in __fimc_pipeline_close()
275 clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]); in __fimc_pipeline_close()
277 return ret == -ENXIO ? 0 : ret; in __fimc_pipeline_close()
281 * __fimc_pipeline_s_stream - call s_stream() on pipeline subdevs
295 if (p->subdevs[IDX_SENSOR] == NULL) { in __fimc_pipeline_s_stream()
297 struct v4l2_subdev *sd = p->subdevs[IDX_CSIS]; in __fimc_pipeline_s_stream()
300 sd = p->subdevs[IDX_FIMC]; in __fimc_pipeline_s_stream()
304 * If neither CSIS nor FIMC was set up, in __fimc_pipeline_s_stream()
307 return -ENODEV; in __fimc_pipeline_s_stream()
310 fmd = entity_to_fimc_mdev(&sd->entity); in __fimc_pipeline_s_stream()
312 if (!fmd->user_subdev_api) { in __fimc_pipeline_s_stream()
317 return -ENODEV; in __fimc_pipeline_s_stream()
321 if (p->subdevs[IDX_FIMC]) in __fimc_pipeline_s_stream()
323 else if (p->subdevs[IDX_IS_ISP]) in __fimc_pipeline_s_stream()
325 else if (p->subdevs[IDX_FLITE]) in __fimc_pipeline_s_stream()
328 return -ENODEV; in __fimc_pipeline_s_stream()
331 * Sensor could have been linked between open and STREAMON - in __fimc_pipeline_s_stream()
332 * check if this is the case. in __fimc_pipeline_s_stream()
334 fimc_pipeline_prepare(p, &p->subdevs[sd_id]->entity); in __fimc_pipeline_s_stream()
336 if (p->subdevs[IDX_SENSOR] == NULL) in __fimc_pipeline_s_stream()
337 return -ENODEV; in __fimc_pipeline_s_stream()
348 ret = v4l2_subdev_call(p->subdevs[idx], video, s_stream, on); in __fimc_pipeline_s_stream()
350 if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) in __fimc_pipeline_s_stream()
357 for (; i >= 0; i--) { in __fimc_pipeline_s_stream()
359 v4l2_subdev_call(p->subdevs[idx], video, s_stream, !on); in __fimc_pipeline_s_stream()
364 /* Media pipeline operations for the FIMC/FIMC-LITE video device driver */
380 list_add_tail(&p->list, &fmd->pipelines); in fimc_md_pipeline_create()
382 p->ep.ops = &fimc_pipeline_ops; in fimc_md_pipeline_create()
383 return &p->ep; in fimc_md_pipeline_create()
388 while (!list_empty(&fmd->pipelines)) { in fimc_md_pipelines_free()
391 p = list_entry(fmd->pipelines.next, typeof(*p), list); in fimc_md_pipelines_free()
392 list_del(&p->list); in fimc_md_pipelines_free()
400 int index = fmd->num_sensors; in fimc_md_parse_one_endpoint()
401 struct fimc_source_info *pd = &fmd->sensor[index].pdata; in fimc_md_parse_one_endpoint()
415 return -EINVAL; in fimc_md_parse_one_endpoint()
418 pd->mux_id = (endpoint.base.port - 1) & 0x1; in fimc_md_parse_one_endpoint()
422 v4l2_info(&fmd->v4l2_dev, "Remote device at %pOF not found\n", in fimc_md_parse_one_endpoint()
430 pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_601; in fimc_md_parse_one_endpoint()
432 pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_656; in fimc_md_parse_one_endpoint()
433 pd->flags = endpoint.bus.parallel.flags; in fimc_md_parse_one_endpoint()
436 * MIPI CSI-2: only input mux selection and in fimc_md_parse_one_endpoint()
437 * the sensor's clock frequency is needed. in fimc_md_parse_one_endpoint()
439 pd->sensor_bus_type = FIMC_BUS_TYPE_MIPI_CSI2; in fimc_md_parse_one_endpoint()
441 v4l2_err(&fmd->v4l2_dev, "Wrong port id (%u) at node %pOF\n", in fimc_md_parse_one_endpoint()
445 * For FIMC-IS handled sensors, that are placed under i2c-isp device in fimc_md_parse_one_endpoint()
446 * node, FIMC is connected to the FIMC-IS through its ISP Writeback in fimc_md_parse_one_endpoint()
447 * input. Sensors are attached to the FIMC-LITE hostdata interface in fimc_md_parse_one_endpoint()
448 * directly or through MIPI-CSIS, depending on the external media bus in fimc_md_parse_one_endpoint()
455 if (of_node_name_eq(np, "i2c-isp")) in fimc_md_parse_one_endpoint()
456 pd->fimc_bus_type = FIMC_BUS_TYPE_ISP_WRITEBACK; in fimc_md_parse_one_endpoint()
458 pd->fimc_bus_type = pd->sensor_bus_type; in fimc_md_parse_one_endpoint()
461 if (WARN_ON(index >= ARRAY_SIZE(fmd->sensor))) { in fimc_md_parse_one_endpoint()
463 return -EINVAL; in fimc_md_parse_one_endpoint()
466 asd = v4l2_async_nf_add_fwnode_remote(&fmd->subdev_notifier, in fimc_md_parse_one_endpoint()
475 fmd->sensor[index].asd = asd; in fimc_md_parse_one_endpoint()
476 fmd->num_sensors++; in fimc_md_parse_one_endpoint()
481 /* Parse port node and register as a sub-device any sensor specified there. */
499 /* Register all SoC external sub-devices */
502 struct device_node *parent = fmd->pdev->dev.of_node; in fimc_md_register_sensor_entities()
508 * Runtime resume one of the FIMC entities to make sure in fimc_md_register_sensor_entities()
511 if (!fmd->pmf) in fimc_md_register_sensor_entities()
512 return -ENXIO; in fimc_md_register_sensor_entities()
514 ret = pm_runtime_resume_and_get(fmd->pmf); in fimc_md_register_sensor_entities()
518 fmd->num_sensors = 0; in fimc_md_register_sensor_entities()
520 /* Attach sensors linked to MIPI CSI-2 receivers */ in fimc_md_register_sensor_entities()
539 /* Attach sensors listed in the parallel-ports node */ in fimc_md_register_sensor_entities()
540 ports = of_get_child_by_name(parent, "parallel-ports"); in fimc_md_register_sensor_entities()
554 pm_runtime_put(fmd->pmf); in fimc_md_register_sensor_entities()
559 v4l2_async_nf_cleanup(&fmd->subdev_notifier); in fimc_md_register_sensor_entities()
560 pm_runtime_put(fmd->pmf); in fimc_md_register_sensor_entities()
570 return -EINVAL; in __of_get_csis_id()
573 return reg - FIMC_INPUT_MIPI_CSI2_0; in __of_get_csis_id()
577 * MIPI-CSIS, FIMC and FIMC-LITE platform devices registration.
586 if (WARN_ON(fimc_lite->index >= FIMC_LITE_MAX_DEVS || in register_fimc_lite_entity()
587 fmd->fimc_lite[fimc_lite->index])) in register_fimc_lite_entity()
588 return -EBUSY; in register_fimc_lite_entity()
590 sd = &fimc_lite->subdev; in register_fimc_lite_entity()
591 sd->grp_id = GRP_ID_FLITE; in register_fimc_lite_entity()
595 return -ENOMEM; in register_fimc_lite_entity()
599 ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); in register_fimc_lite_entity()
601 fmd->fimc_lite[fimc_lite->index] = fimc_lite; in register_fimc_lite_entity()
603 v4l2_err(&fmd->v4l2_dev, "Failed to register FIMC.LITE%d\n", in register_fimc_lite_entity()
604 fimc_lite->index); in register_fimc_lite_entity()
608 static int register_fimc_entity(struct fimc_md *fmd, struct fimc_dev *fimc) in register_fimc_entity() argument
614 if (WARN_ON(fimc->id >= FIMC_MAX_DEVS || fmd->fimc[fimc->id])) in register_fimc_entity()
615 return -EBUSY; in register_fimc_entity()
617 sd = &fimc->vid_cap.subdev; in register_fimc_entity()
618 sd->grp_id = GRP_ID_FIMC; in register_fimc_entity()
622 return -ENOMEM; in register_fimc_entity()
626 ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); in register_fimc_entity()
628 if (!fmd->pmf && fimc->pdev) in register_fimc_entity()
629 fmd->pmf = &fimc->pdev->dev; in register_fimc_entity()
630 fmd->fimc[fimc->id] = fimc; in register_fimc_entity()
631 fimc->vid_cap.user_subdev_api = fmd->user_subdev_api; in register_fimc_entity()
633 v4l2_err(&fmd->v4l2_dev, "Failed to register FIMC.%d (%d)\n", in register_fimc_entity()
634 fimc->id, ret); in register_fimc_entity()
643 struct device_node *node = pdev->dev.of_node; in register_csis_entity()
646 id = node ? __of_get_csis_id(node) : max(0, pdev->id); in register_csis_entity()
649 return -ENOENT; in register_csis_entity()
651 if (WARN_ON(fmd->csis[id].sd)) in register_csis_entity()
652 return -EBUSY; in register_csis_entity()
654 sd->grp_id = GRP_ID_CSIS; in register_csis_entity()
655 ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); in register_csis_entity()
657 fmd->csis[id].sd = sd; in register_csis_entity()
659 v4l2_err(&fmd->v4l2_dev, in register_csis_entity()
660 "Failed to register MIPI-CSIS.%d (%d)\n", id, ret); in register_csis_entity()
664 static int register_fimc_is_entity(struct fimc_md *fmd, struct fimc_is *is) in register_fimc_is_entity() argument
666 struct v4l2_subdev *sd = &is->isp.subdev; in register_fimc_is_entity()
673 return -ENOMEM; in register_fimc_is_entity()
677 ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); in register_fimc_is_entity()
679 v4l2_err(&fmd->v4l2_dev, in register_fimc_is_entity()
680 "Failed to register FIMC-ISP (%d)\n", ret); in register_fimc_is_entity()
684 fmd->fimc_is = is; in register_fimc_is_entity()
692 struct device *dev = &pdev->dev; in fimc_md_register_platform_entity()
693 int ret = -EPROBE_DEFER; in fimc_md_register_platform_entity()
696 /* Lock to ensure dev->driver won't change. */ in fimc_md_register_platform_entity()
699 if (!dev->driver || !try_module_get(dev->driver->owner)) in fimc_md_register_platform_entity()
703 /* Some subdev didn't probe successfully id drvdata is NULL */ in fimc_md_register_platform_entity()
719 ret = -ENODEV; in fimc_md_register_platform_entity()
723 module_put(dev->driver->owner); in fimc_md_register_platform_entity()
726 if (ret == -EPROBE_DEFER) in fimc_md_register_platform_entity()
727 dev_info(&fmd->pdev->dev, "deferring %s device registration\n", in fimc_md_register_platform_entity()
730 dev_err(&fmd->pdev->dev, "%s device registration failed (%d)\n", in fimc_md_register_platform_entity()
735 /* Register FIMC, FIMC-LITE and CSIS media entities */
744 int plat_entity = -1; in fimc_md_register_platform_entities()
758 !of_property_read_bool(node, "samsung,lcd-wb")) in fimc_md_register_platform_entities()
764 put_device(&pdev->dev); in fimc_md_register_platform_entities()
779 struct fimc_dev *dev = fmd->fimc[i]; in fimc_md_unregister_entities()
782 v4l2_device_unregister_subdev(&dev->vid_cap.subdev); in fimc_md_unregister_entities()
783 dev->vid_cap.ve.pipe = NULL; in fimc_md_unregister_entities()
784 fmd->fimc[i] = NULL; in fimc_md_unregister_entities()
787 struct fimc_lite *dev = fmd->fimc_lite[i]; in fimc_md_unregister_entities()
790 v4l2_device_unregister_subdev(&dev->subdev); in fimc_md_unregister_entities()
791 dev->ve.pipe = NULL; in fimc_md_unregister_entities()
792 fmd->fimc_lite[i] = NULL; in fimc_md_unregister_entities()
795 if (fmd->csis[i].sd == NULL) in fimc_md_unregister_entities()
797 v4l2_device_unregister_subdev(fmd->csis[i].sd); in fimc_md_unregister_entities()
798 fmd->csis[i].sd = NULL; in fimc_md_unregister_entities()
801 if (fmd->fimc_is) in fimc_md_unregister_entities()
802 v4l2_device_unregister_subdev(&fmd->fimc_is->isp.subdev); in fimc_md_unregister_entities()
804 v4l2_info(&fmd->v4l2_dev, "Unregistered all entities\n"); in fimc_md_unregister_entities()
808 * __fimc_md_create_fimc_sink_links - create links to all FIMC entities
809 * @fmd: fimc media device
810 * @source: the source entity to create links to all fimc entities from
811 * @sensor: sensor subdev linked to FIMC[fimc_id] entity, may be null
813 * @link_mask: bitmask of the fimc devices for which link should be enabled
827 /* Skip direct FIMC links in the logical FIMC-IS sensor path */ in __fimc_md_create_fimc_sink_links()
828 if (si && si->fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK) in __fimc_md_create_fimc_sink_links()
833 if (!fmd->fimc[i]) in __fimc_md_create_fimc_sink_links()
836 * Some FIMC variants are not fitted with camera capture in __fimc_md_create_fimc_sink_links()
839 if (!fmd->fimc[i]->variant->has_cam_if) in __fimc_md_create_fimc_sink_links()
844 sink = &fmd->fimc[i]->vid_cap.subdev.entity; in __fimc_md_create_fimc_sink_links()
850 /* Notify FIMC capture subdev entity */ in __fimc_md_create_fimc_sink_links()
851 ret = media_entity_call(sink, link_setup, &sink->pads[0], in __fimc_md_create_fimc_sink_links()
852 &source->pads[pad], flags); in __fimc_md_create_fimc_sink_links()
856 v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]\n", in __fimc_md_create_fimc_sink_links()
857 source->name, flags ? '=' : '-', sink->name); in __fimc_md_create_fimc_sink_links()
861 if (!fmd->fimc_lite[i]) in __fimc_md_create_fimc_sink_links()
864 sink = &fmd->fimc_lite[i]->subdev.entity; in __fimc_md_create_fimc_sink_links()
870 /* Notify FIMC-LITE subdev entity */ in __fimc_md_create_fimc_sink_links()
871 ret = media_entity_call(sink, link_setup, &sink->pads[0], in __fimc_md_create_fimc_sink_links()
872 &source->pads[pad], 0); in __fimc_md_create_fimc_sink_links()
876 v4l2_info(&fmd->v4l2_dev, "created link [%s] -> [%s]\n", in __fimc_md_create_fimc_sink_links()
877 source->name, sink->name); in __fimc_md_create_fimc_sink_links()
882 /* Create links from FIMC-LITE source pads to other entities */
889 struct fimc_lite *fimc = fmd->fimc_lite[i]; in __fimc_md_create_flite_source_links() local
891 if (fimc == NULL) in __fimc_md_create_flite_source_links()
894 source = &fimc->subdev.entity; in __fimc_md_create_flite_source_links()
895 sink = &fimc->ve.vdev.entity; in __fimc_md_create_flite_source_links()
896 /* FIMC-LITE's subdev and video node */ in __fimc_md_create_flite_source_links()
901 /* Link from FIMC-LITE to IS-ISP subdev */ in __fimc_md_create_flite_source_links()
902 sink = &fmd->fimc_is->isp.subdev.entity; in __fimc_md_create_flite_source_links()
912 /* Create FIMC-IS links */
915 struct fimc_isp *isp = &fmd->fimc_is->isp; in __fimc_md_create_fimc_is_links()
919 source = &isp->subdev.entity; in __fimc_md_create_fimc_is_links()
922 if (fmd->fimc[i] == NULL) in __fimc_md_create_fimc_is_links()
925 /* Link from FIMC-IS-ISP subdev to FIMC */ in __fimc_md_create_fimc_is_links()
926 sink = &fmd->fimc[i]->vid_cap.subdev.entity; in __fimc_md_create_fimc_is_links()
933 /* Link from FIMC-IS-ISP subdev to fimc-is-isp.capture video node */ in __fimc_md_create_fimc_is_links()
934 sink = &isp->video_capture.ve.vdev.entity; in __fimc_md_create_fimc_is_links()
936 /* Skip this link if the fimc-is-isp video node driver isn't built-in */ in __fimc_md_create_fimc_is_links()
937 if (sink->num_pads == 0) in __fimc_md_create_fimc_is_links()
945 * fimc_md_create_links - create default links between registered entities
946 * @fmd: fimc media device
948 * Parallel interface sensor entities are connected directly to FIMC capture
951 * entity has a link to each registered FIMC capture entity. Enabled links
953 * subsequent FIMC capture entity. The number of default active links is
954 * determined by the number of available sensors or FIMC entities,
955 * whichever is less.
966 for (i = 0; i < fmd->num_sensors; i++) { in fimc_md_create_links()
967 if (fmd->sensor[i].subdev == NULL) in fimc_md_create_links()
970 sensor = fmd->sensor[i].subdev; in fimc_md_create_links()
977 switch (pdata->sensor_bus_type) { in fimc_md_create_links()
979 if (WARN(pdata->mux_id >= CSIS_MAX_ENTITIES, in fimc_md_create_links()
980 "Wrong CSI channel id: %d\n", pdata->mux_id)) in fimc_md_create_links()
981 return -EINVAL; in fimc_md_create_links()
983 csis = fmd->csis[pdata->mux_id].sd; in fimc_md_create_links()
985 "MIPI-CSI interface specified but s5p-csis module is not loaded!\n")) in fimc_md_create_links()
986 return -EINVAL; in fimc_md_create_links()
988 pad = sensor->entity.num_pads - 1; in fimc_md_create_links()
989 ret = media_create_pad_link(&sensor->entity, pad, in fimc_md_create_links()
990 &csis->entity, CSIS_PAD_SINK, in fimc_md_create_links()
996 v4l2_info(&fmd->v4l2_dev, "created link [%s] => [%s]\n", in fimc_md_create_links()
997 sensor->entity.name, csis->entity.name); in fimc_md_create_links()
1000 csi_sensors[pdata->mux_id] = sensor; in fimc_md_create_links()
1004 source = &sensor->entity; in fimc_md_create_links()
1009 v4l2_err(&fmd->v4l2_dev, "Wrong bus_type: %x\n", in fimc_md_create_links()
1010 pdata->sensor_bus_type); in fimc_md_create_links()
1011 return -EINVAL; in fimc_md_create_links()
1022 if (fmd->csis[i].sd == NULL) in fimc_md_create_links()
1025 source = &fmd->csis[i].sd->entity; in fimc_md_create_links()
1034 /* Create immutable links between each FIMC's subdev and video node */ in fimc_md_create_links()
1037 if (!fmd->fimc[i]) in fimc_md_create_links()
1040 source = &fmd->fimc[i]->vid_cap.subdev.entity; in fimc_md_create_links()
1041 sink = &fmd->fimc[i]->vid_cap.ve.vdev.entity; in fimc_md_create_links()
1053 if (fmd->use_isp) in fimc_md_create_links()
1066 while (--i >= 0) { in fimc_md_put_clocks()
1067 if (IS_ERR(fmd->camclk[i].clock)) in fimc_md_put_clocks()
1069 clk_put(fmd->camclk[i].clock); in fimc_md_put_clocks()
1070 fmd->camclk[i].clock = ERR_PTR(-EINVAL); in fimc_md_put_clocks()
1075 if (IS_ERR(fmd->wbclk[i])) in fimc_md_put_clocks()
1077 clk_put(fmd->wbclk[i]); in fimc_md_put_clocks()
1078 fmd->wbclk[i] = ERR_PTR(-EINVAL); in fimc_md_put_clocks()
1084 struct device *dev = &fmd->pdev->dev; in fimc_md_get_clocks()
1090 fmd->camclk[i].clock = ERR_PTR(-EINVAL); in fimc_md_get_clocks()
1101 fmd->camclk[i].clock = clock; in fimc_md_get_clocks()
1106 if (!fmd->use_isp) in fimc_md_get_clocks()
1112 fmd->wbclk[CLK_IDX_WB_A] = ERR_PTR(-EINVAL); in fimc_md_get_clocks()
1118 v4l2_err(&fmd->v4l2_dev, "Failed to get clock: %s\n", in fimc_md_get_clocks()
1123 fmd->wbclk[i] = clock; in fimc_md_get_clocks()
1139 if (vdev->entity.use_count == 0) in __fimc_md_modify_pipeline()
1143 p = to_fimc_pipeline(ve->pipe); in __fimc_md_modify_pipeline()
1146 * has been disconnected and p->subdevs array is cleared now. in __fimc_md_modify_pipeline()
1148 if (!enable && p->subdevs[IDX_SENSOR] == NULL) in __fimc_md_modify_pipeline()
1152 ret = __fimc_pipeline_open(ve->pipe, entity, true); in __fimc_md_modify_pipeline()
1154 ret = __fimc_pipeline_close(ve->pipe); in __fimc_md_modify_pipeline()
1157 memset(p->subdevs, 0, sizeof(p->subdevs)); in __fimc_md_modify_pipeline()
1162 /* Locking: called with entity->graph_obj.mdev->graph_mutex mutex held. */
1172 * through active links. This is needed as we cannot power on/off the in __fimc_md_modify_pipelines()
1209 &container_of(link->graph_obj.mdev, struct fimc_md, in fimc_md_link_notify()
1210 media_dev)->link_setup_graph; in fimc_md_link_notify()
1211 struct media_entity *sink = link->sink->entity; in fimc_md_link_notify()
1217 link->graph_obj.mdev); in fimc_md_link_notify()
1228 if (link->flags & MEDIA_LNK_FL_ENABLED) in fimc_md_link_notify()
1233 return ret ? -EPIPE : 0; in fimc_md_link_notify()
1245 if (fmd->user_subdev_api) in subdev_conf_mode_show()
1246 return strscpy(buf, "Sub-device API (sub-dev)\n", PAGE_SIZE); in subdev_conf_mode_show()
1248 return strscpy(buf, "V4L2 video node only API (vid-dev)\n", PAGE_SIZE); in subdev_conf_mode_show()
1259 if (!strcmp(buf, "vid-dev\n")) in subdev_conf_mode_store()
1261 else if (!strcmp(buf, "sub-dev\n")) in subdev_conf_mode_store()
1266 fmd->user_subdev_api = subdev_api; in subdev_conf_mode_store()
1268 if (fmd->fimc[i]) in subdev_conf_mode_store()
1269 fmd->fimc[i]->vid_cap.user_subdev_api = subdev_api; in subdev_conf_mode_store()
1273 * This device attribute is to select video pipeline configuration method.
1275 * vid-dev - for V4L2 video node API only, subdevice will be configured
1277 * sub-dev - for media controller API, subdevs must be configured in user
1286 if (camclk->fmd->pmf == NULL) in cam_clk_prepare()
1287 return -ENODEV; in cam_clk_prepare()
1289 return pm_runtime_resume_and_get(camclk->fmd->pmf); in cam_clk_prepare()
1296 if (camclk->fmd->pmf == NULL) in cam_clk_unprepare()
1299 pm_runtime_put_sync(camclk->fmd->pmf); in cam_clk_unprepare()
1309 struct cam_clk_provider *cp = &fmd->clk_provider; in fimc_md_unregister_clk_provider()
1312 if (cp->of_node) in fimc_md_unregister_clk_provider()
1313 of_clk_del_provider(cp->of_node); in fimc_md_unregister_clk_provider()
1315 for (i = 0; i < cp->num_clocks; i++) in fimc_md_unregister_clk_provider()
1316 clk_unregister(cp->clks[i]); in fimc_md_unregister_clk_provider()
1321 struct cam_clk_provider *cp = &fmd->clk_provider; in fimc_md_register_clk_provider()
1322 struct device *dev = &fmd->pdev->dev; in fimc_md_register_clk_provider()
1326 struct cam_clk *camclk = &cp->camclk[i]; in fimc_md_register_clk_provider()
1330 ret = of_property_read_string_index(dev->of_node, in fimc_md_register_clk_provider()
1331 "clock-output-names", i, &init.name); in fimc_md_register_clk_provider()
1335 p_name = __clk_get_name(fmd->camclk[i].clock); in fimc_md_register_clk_provider()
1342 camclk->hw.init = &init; in fimc_md_register_clk_provider()
1343 camclk->fmd = fmd; in fimc_md_register_clk_provider()
1345 cp->clks[i] = clk_register(NULL, &camclk->hw); in fimc_md_register_clk_provider()
1346 if (IS_ERR(cp->clks[i])) { in fimc_md_register_clk_provider()
1348 init.name, PTR_ERR(cp->clks[i])); in fimc_md_register_clk_provider()
1349 ret = PTR_ERR(cp->clks[i]); in fimc_md_register_clk_provider()
1352 cp->num_clocks++; in fimc_md_register_clk_provider()
1355 if (cp->num_clocks == 0) { in fimc_md_register_clk_provider()
1360 cp->clk_data.clks = cp->clks; in fimc_md_register_clk_provider()
1361 cp->clk_data.clk_num = cp->num_clocks; in fimc_md_register_clk_provider()
1362 cp->of_node = dev->of_node; in fimc_md_register_clk_provider()
1363 ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, in fimc_md_register_clk_provider()
1364 &cp->clk_data); in fimc_md_register_clk_provider()
1381 for (i = 0; i < ARRAY_SIZE(fmd->sensor); i++) in subdev_notifier_bound()
1382 if (fmd->sensor[i].asd == asd) in subdev_notifier_bound()
1383 si = &fmd->sensor[i]; in subdev_notifier_bound()
1386 return -EINVAL; in subdev_notifier_bound()
1388 v4l2_set_subdev_hostdata(subdev, &si->pdata); in subdev_notifier_bound()
1390 if (si->pdata.fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK) in subdev_notifier_bound()
1391 subdev->grp_id = GRP_ID_FIMC_IS_SENSOR; in subdev_notifier_bound()
1393 subdev->grp_id = GRP_ID_SENSOR; in subdev_notifier_bound()
1395 si->subdev = subdev; in subdev_notifier_bound()
1397 v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice: %s (%d)\n", in subdev_notifier_bound()
1398 subdev->name, fmd->num_sensors); in subdev_notifier_bound()
1400 fmd->num_sensors++; in subdev_notifier_bound()
1410 mutex_lock(&fmd->media_dev.graph_mutex); in subdev_notifier_complete()
1416 ret = v4l2_device_register_subdev_nodes(&fmd->v4l2_dev); in subdev_notifier_complete()
1418 mutex_unlock(&fmd->media_dev.graph_mutex); in subdev_notifier_complete()
1422 return media_device_register(&fmd->media_dev); in subdev_notifier_complete()
1432 struct device *dev = &pdev->dev; in fimc_md_probe()
1440 return -ENOMEM; in fimc_md_probe()
1442 ret = of_platform_populate(dev->of_node, NULL, NULL, dev); in fimc_md_probe()
1444 return -ENOMEM; in fimc_md_probe()
1446 spin_lock_init(&fmd->slock); in fimc_md_probe()
1447 INIT_LIST_HEAD(&fmd->pipelines); in fimc_md_probe()
1448 fmd->pdev = pdev; in fimc_md_probe()
1450 strscpy(fmd->media_dev.model, "Samsung S5P FIMC", in fimc_md_probe()
1451 sizeof(fmd->media_dev.model)); in fimc_md_probe()
1452 fmd->media_dev.ops = &fimc_md_ops; in fimc_md_probe()
1453 fmd->media_dev.dev = dev; in fimc_md_probe()
1455 v4l2_dev = &fmd->v4l2_dev; in fimc_md_probe()
1456 v4l2_dev->mdev = &fmd->media_dev; in fimc_md_probe()
1457 v4l2_dev->notify = fimc_sensor_notify; in fimc_md_probe()
1458 strscpy(v4l2_dev->name, "s5p-fimc-md", sizeof(v4l2_dev->name)); in fimc_md_probe()
1460 fmd->use_isp = fimc_md_is_isp_available(dev->of_node); in fimc_md_probe()
1461 fmd->user_subdev_api = true; in fimc_md_probe()
1463 media_device_init(&fmd->media_dev); in fimc_md_probe()
1465 ret = v4l2_device_register(dev, &fmd->v4l2_dev); in fimc_md_probe()
1481 v4l2_async_nf_init(&fmd->subdev_notifier, &fmd->v4l2_dev); in fimc_md_probe()
1483 ret = fimc_md_register_platform_entities(fmd, dev->of_node); in fimc_md_probe()
1491 ret = device_create_file(&pdev->dev, &dev_attr_subdev_conf_mode); in fimc_md_probe()
1495 * FIMC platform devices need to be registered before the sclk_cam in fimc_md_probe()
1505 if (fmd->num_sensors > 0) { in fimc_md_probe()
1506 fmd->subdev_notifier.ops = &subdev_notifier_ops; in fimc_md_probe()
1507 fmd->num_sensors = 0; in fimc_md_probe()
1509 ret = v4l2_async_nf_register(&fmd->subdev_notifier); in fimc_md_probe()
1519 device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode); in fimc_md_probe()
1521 v4l2_async_nf_cleanup(&fmd->subdev_notifier); in fimc_md_probe()
1527 v4l2_device_unregister(&fmd->v4l2_dev); in fimc_md_probe()
1529 media_device_cleanup(&fmd->media_dev); in fimc_md_probe()
1541 v4l2_async_nf_unregister(&fmd->subdev_notifier); in fimc_md_remove()
1542 v4l2_async_nf_cleanup(&fmd->subdev_notifier); in fimc_md_remove()
1544 v4l2_device_unregister(&fmd->v4l2_dev); in fimc_md_remove()
1545 device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode); in fimc_md_remove()
1548 media_device_unregister(&fmd->media_dev); in fimc_md_remove()
1549 media_device_cleanup(&fmd->media_dev); in fimc_md_remove()
1554 { .name = "s5p-fimc-md" },
1560 { .compatible = "samsung,fimc" },
1570 .name = "s5p-fimc-md",
1578 request_module("s5p-csis"); in fimc_md_init()
1600 MODULE_DESCRIPTION("S5P FIMC camera host interface/video postprocessor driver");