/** * __fimc_pipeline_open - update the pipeline information, enable power * of all pipeline subdevs and the sensor clock * @me: media entity to start graph walk with * @prepare: true to walk the current pipeline and acquire all subdevs * * Called with the graph mutex held. */ static int __fimc_pipeline_open(struct exynos_media_pipeline *ep, struct media_entity *me, bool prepare) { struct fimc_md *fmd = entity_to_fimc_mdev(me); struct fimc_pipeline *p = to_fimc_pipeline(ep); struct v4l2_subdev *sd; int ret; if (WARN_ON(p == NULL || me == NULL)) return -EINVAL; if (prepare) fimc_pipeline_prepare(p, me); sd = p->subdevs[IDX_SENSOR]; if (sd == NULL) return -EINVAL; /* Disable PXLASYNC clock if this pipeline includes FIMC-IS */ if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) { ret = clk_prepare_enable(fmd->wbclk[CLK_IDX_WB_B]); if (ret < 0) return ret; } ret = fimc_pipeline_s_power(p, 1); if (!ret) return 0; if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]); return ret; }
/** * __fimc_pipeline_shutdown - disable the sensor clock and pipeline power * @fimc: fimc device terminating the pipeline * * Disable power of all subdevs in the pipeline and turn off the external * sensor clock. * Called with the graph mutex held. */ int __fimc_pipeline_shutdown(struct fimc_dev *fimc) { int ret = 0; if (fimc->pipeline.sensor) { ret = fimc_pipeline_s_power(fimc, 0); fimc_md_set_camclk(fimc->pipeline.sensor, false); } return ret == -ENXIO ? 0 : ret; }
/** * __fimc_pipeline_close - disable the sensor clock and pipeline power * @fimc: fimc device terminating the pipeline * * Disable power of all subdevs in the pipeline and turn off the external * sensor clock. * Called with the graph mutex held. */ static int __fimc_pipeline_close(struct fimc_pipeline *p) { int ret = 0; if (p->subdevs[IDX_SENSOR]) { ret = fimc_pipeline_s_power(p, 0); fimc_md_set_camclk(p->subdevs[IDX_SENSOR], false); } return ret == -ENXIO ? 0 : ret; }
/** * __fimc_pipeline_initialize - update the pipeline information, enable power * of all pipeline subdevs and the sensor clock * @me: media entity to start graph walk with * @prep: true to acquire sensor (and csis) subdevs * * This function must be called with the graph mutex held. */ static int __fimc_pipeline_initialize(struct fimc_dev *fimc, struct media_entity *me, bool prep) { int ret; if (prep) fimc_pipeline_prepare(fimc, me); if (fimc->pipeline.sensor == NULL) return -EINVAL; ret = fimc_md_set_camclk(fimc->pipeline.sensor, true); if (ret) return ret; return fimc_pipeline_s_power(fimc, 1); }
/** * __fimc_pipeline_open - update the pipeline information, enable power * of all pipeline subdevs and the sensor clock * @me: media entity to start graph walk with * @prep: true to acquire sensor (and csis) subdevs * * This function must be called with the graph mutex held. */ static int __fimc_pipeline_open(struct fimc_pipeline *p, struct media_entity *me, bool prep) { int ret; if (prep) fimc_pipeline_prepare(p, me); if (p->subdevs[IDX_SENSOR] == NULL) return -EINVAL; ret = fimc_md_set_camclk(p->subdevs[IDX_SENSOR], true); if (ret) return ret; return fimc_pipeline_s_power(p, 1); }
/** * __fimc_pipeline_close - disable the sensor clock and pipeline power * @fimc: fimc device terminating the pipeline * * Disable power of all subdevs and turn the external sensor clock off. */ static int __fimc_pipeline_close(struct exynos_media_pipeline *ep) { struct fimc_pipeline *p = to_fimc_pipeline(ep); struct v4l2_subdev *sd = p ? p->subdevs[IDX_SENSOR] : NULL; struct fimc_md *fmd; int ret; if (sd == NULL) { pr_warn("%s(): No sensor subdev\n", __func__); return 0; } ret = fimc_pipeline_s_power(p, 0); fmd = entity_to_fimc_mdev(&sd->entity); /* Disable PXLASYNC clock if this pipeline includes FIMC-IS */ if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]); return ret == -ENXIO ? 0 : ret; }
/** * __fimc_pipeline_enable - enable power of all pipeline subdevs * and the sensor clock * @ep: video pipeline structure * @fmd: fimc media device * * Called with the graph mutex held. */ static int __fimc_pipeline_enable(struct exynos_media_pipeline *ep, struct fimc_md *fmd) { struct fimc_pipeline *p = to_fimc_pipeline(ep); int ret; /* Enable PXLASYNC clock if this pipeline includes FIMC-IS */ if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) { ret = clk_prepare_enable(fmd->wbclk[CLK_IDX_WB_B]); if (ret < 0) return ret; } ret = fimc_pipeline_s_power(p, 1); if (!ret) return 0; if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]); return ret; }
/** * __fimc_pipeline_close - disable the sensor clock and pipeline power * @fimc: fimc device terminating the pipeline * * Disable power of all subdevs and turn the external sensor clock off. */ static int __fimc_pipeline_close(struct fimc_pipeline *p) { struct v4l2_subdev *sd = p ? p->subdevs[IDX_SENSOR] : NULL; struct fimc_md *fmd; int ret = 0; if (WARN_ON(sd == NULL)) return -EINVAL; if (p->subdevs[IDX_SENSOR]) { ret = fimc_pipeline_s_power(p, 0); fimc_md_set_camclk(sd, false); } fmd = entity_to_fimc_mdev(&sd->entity); /* Disable PXLASYNC clock if this pipeline includes FIMC-IS */ if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]); return ret == -ENXIO ? 0 : ret; }
/** * __fimc_pipeline_s_stream - call s_stream() on pipeline subdevs * @pipeline: video pipeline structure * @on: passed as the s_stream() callback argument */ static int __fimc_pipeline_s_stream(struct exynos_media_pipeline *ep, bool on) { static const u8 seq[2][IDX_MAX] = { { IDX_FIMC, IDX_SENSOR, IDX_IS_ISP, IDX_CSIS, IDX_FLITE }, { IDX_CSIS, IDX_FLITE, IDX_FIMC, IDX_SENSOR, IDX_IS_ISP }, }; struct fimc_pipeline *p = to_fimc_pipeline(ep); struct fimc_md *fmd = entity_to_fimc_mdev(&p->subdevs[IDX_CSIS]->entity); enum fimc_subdev_index sd_id; int i, ret = 0; if (p->subdevs[IDX_SENSOR] == NULL) { if (!fmd->user_subdev_api) { /* * Sensor must be already discovered if we * aren't in the user_subdev_api mode */ return -ENODEV; } /* Get pipeline sink entity */ if (p->subdevs[IDX_FIMC]) sd_id = IDX_FIMC; else if (p->subdevs[IDX_IS_ISP]) sd_id = IDX_IS_ISP; else if (p->subdevs[IDX_FLITE]) sd_id = IDX_FLITE; else return -ENODEV; /* * Sensor could have been linked between open and STREAMON - * check if this is the case. */ fimc_pipeline_prepare(p, &p->subdevs[sd_id]->entity); if (p->subdevs[IDX_SENSOR] == NULL) return -ENODEV; ret = __fimc_pipeline_enable(ep, fmd); if (ret < 0) return ret; } for (i = 0; i < IDX_MAX; i++) { unsigned int idx = seq[on][i]; ret = v4l2_subdev_call(p->subdevs[idx], video, s_stream, on); if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) goto error; } return 0; error: fimc_pipeline_s_power(p, !on); for (; i >= 0; i--) { unsigned int idx = seq[on][i]; v4l2_subdev_call(p->subdevs[idx], video, s_stream, !on); } return ret; }