diff options
Diffstat (limited to 'drivers/media/video/s5p-fimc/fimc-mdevice.c')
-rw-r--r-- | drivers/media/video/s5p-fimc/fimc-mdevice.c | 164 |
1 files changed, 101 insertions, 63 deletions
diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c index c319842c762d..212474130dfb 100644 --- a/drivers/media/video/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/video/s5p-fimc/fimc-mdevice.c @@ -25,6 +25,7 @@ #include <media/media-device.h> #include "fimc-core.h" +#include "fimc-lite.h" #include "fimc-mdevice.h" #include "mipi-csis.h" @@ -37,22 +38,43 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd, * * Caller holds the graph mutex. */ -void fimc_pipeline_prepare(struct fimc_dev *fimc, struct media_entity *me) +void fimc_pipeline_prepare(struct fimc_pipeline *p, struct media_entity *me) { - struct media_entity_graph graph; + struct media_pad *pad = &me->pads[0]; struct v4l2_subdev *sd; + int i; - media_entity_graph_walk_start(&graph, me); + for (i = 0; i < IDX_MAX; i++) + p->subdevs[i] = NULL; - while ((me = media_entity_graph_walk_next(&graph))) { - if (media_entity_type(me) != MEDIA_ENT_T_V4L2_SUBDEV) - continue; - sd = media_entity_to_v4l2_subdev(me); + while (1) { + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + + /* source pad */ + pad = media_entity_remote_source(pad); + if (pad == NULL || + media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + break; - if (sd->grp_id == SENSOR_GROUP_ID) - fimc->pipeline.sensor = sd; - else if (sd->grp_id == CSIS_GROUP_ID) - fimc->pipeline.csis = sd; + sd = media_entity_to_v4l2_subdev(pad->entity); + + switch (sd->grp_id) { + case SENSOR_GROUP_ID: + p->subdevs[IDX_SENSOR] = sd; + break; + case CSIS_GROUP_ID: + p->subdevs[IDX_CSIS] = sd; + break; + case FIMC_GROUP_ID: + /* No need to control FIMC subdev through subdev ops */ + break; + default: + pr_warn("%s: Unknown subdev grp_id: %#x\n", + __func__, sd->grp_id); + } + /* sink pad */ + pad = &sd->entity.pads[0]; } } @@ -85,30 +107,27 @@ static int __subdev_set_power(struct v4l2_subdev *sd, int on) /** * fimc_pipeline_s_power - change power state of all pipeline subdevs * @fimc: fimc device terminating the pipeline - * @state: 1 to enable power or 0 for power down + * @state: true to power on, false to power off * - * Need to be called with the graph mutex held. + * Needs to be called with the graph mutex held. */ -int fimc_pipeline_s_power(struct fimc_dev *fimc, int state) +int fimc_pipeline_s_power(struct fimc_pipeline *p, bool state) { - int ret = 0; + unsigned int i; + int ret; - if (fimc->pipeline.sensor == NULL) + if (p->subdevs[IDX_SENSOR] == NULL) return -ENXIO; - if (state) { - ret = __subdev_set_power(fimc->pipeline.csis, 1); - if (ret && ret != -ENXIO) + for (i = 0; i < IDX_MAX; i++) { + unsigned int idx = state ? (IDX_MAX - 1) - i : i; + + ret = __subdev_set_power(p->subdevs[idx], state); + if (ret < 0 && ret != -ENXIO) return ret; - return __subdev_set_power(fimc->pipeline.sensor, 1); } - ret = __subdev_set_power(fimc->pipeline.sensor, 0); - if (ret) - return ret; - ret = __subdev_set_power(fimc->pipeline.csis, 0); - - return ret == -ENXIO ? 0 : ret; + return 0; } /** @@ -119,32 +138,36 @@ int fimc_pipeline_s_power(struct fimc_dev *fimc, int state) * * This function must be called with the graph mutex held. */ -static int __fimc_pipeline_initialize(struct fimc_dev *fimc, +static int __fimc_pipeline_initialize(struct fimc_pipeline *p, struct media_entity *me, bool prep) { int ret; if (prep) - fimc_pipeline_prepare(fimc, me); - if (fimc->pipeline.sensor == NULL) + fimc_pipeline_prepare(p, me); + + if (p->subdevs[IDX_SENSOR] == NULL) return -EINVAL; - ret = fimc_md_set_camclk(fimc->pipeline.sensor, true); + + ret = fimc_md_set_camclk(p->subdevs[IDX_SENSOR], true); if (ret) return ret; - return fimc_pipeline_s_power(fimc, 1); + + return fimc_pipeline_s_power(p, 1); } -int fimc_pipeline_initialize(struct fimc_dev *fimc, struct media_entity *me, +int fimc_pipeline_initialize(struct fimc_pipeline *p, struct media_entity *me, bool prep) { int ret; mutex_lock(&me->parent->graph_mutex); - ret = __fimc_pipeline_initialize(fimc, me, prep); + ret = __fimc_pipeline_initialize(p, me, prep); mutex_unlock(&me->parent->graph_mutex); return ret; } +EXPORT_SYMBOL_GPL(fimc_pipeline_initialize); /** * __fimc_pipeline_shutdown - disable the sensor clock and pipeline power @@ -154,52 +177,55 @@ int fimc_pipeline_initialize(struct fimc_dev *fimc, struct media_entity *me, * sensor clock. * Called with the graph mutex held. */ -int __fimc_pipeline_shutdown(struct fimc_dev *fimc) +int __fimc_pipeline_shutdown(struct fimc_pipeline *p) { int ret = 0; - if (fimc->pipeline.sensor) { - ret = fimc_pipeline_s_power(fimc, 0); - fimc_md_set_camclk(fimc->pipeline.sensor, false); + 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; } -int fimc_pipeline_shutdown(struct fimc_dev *fimc) +int fimc_pipeline_shutdown(struct fimc_pipeline *p) { - struct media_entity *me = &fimc->vid_cap.vfd->entity; + struct media_entity *me = &p->subdevs[IDX_SENSOR]->entity; int ret; mutex_lock(&me->parent->graph_mutex); - ret = __fimc_pipeline_shutdown(fimc); + ret = __fimc_pipeline_shutdown(p); mutex_unlock(&me->parent->graph_mutex); return ret; } +EXPORT_SYMBOL_GPL(fimc_pipeline_shutdown); /** * fimc_pipeline_s_stream - invoke s_stream on pipeline subdevs - * @fimc: fimc device terminating the pipeline + * @pipeline: video pipeline structure * @on: passed as the s_stream call argument */ -int fimc_pipeline_s_stream(struct fimc_dev *fimc, int on) +int fimc_pipeline_s_stream(struct fimc_pipeline *p, bool on) { - struct fimc_pipeline *p = &fimc->pipeline; - int ret = 0; + int i, ret; - if (p->sensor == NULL) + if (p->subdevs[IDX_SENSOR] == NULL) return -ENODEV; - if ((on && p->csis) || !on) - ret = v4l2_subdev_call(on ? p->csis : p->sensor, - video, s_stream, on); - if (ret < 0 && ret != -ENOIOCTLCMD) - return ret; - if ((!on && p->csis) || on) - ret = v4l2_subdev_call(on ? p->sensor : p->csis, - video, s_stream, on); - return ret == -ENOIOCTLCMD ? 0 : ret; + for (i = 0; i < IDX_MAX; i++) { + unsigned int idx = on ? (IDX_MAX - 1) - i : i; + + ret = v4l2_subdev_call(p->subdevs[idx], video, s_stream, on); + + if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) + return ret; + } + + return 0; + } +EXPORT_SYMBOL_GPL(fimc_pipeline_s_stream); /* * Sensor subdevice helper functions @@ -677,6 +703,7 @@ int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on) static int fimc_md_link_notify(struct media_pad *source, struct media_pad *sink, u32 flags) { + struct fimc_pipeline *pipeline; struct v4l2_subdev *sd; struct fimc_dev *fimc; int ret = 0; @@ -685,16 +712,26 @@ static int fimc_md_link_notify(struct media_pad *source, return 0; sd = media_entity_to_v4l2_subdev(sink->entity); - fimc = v4l2_get_subdevdata(sd); - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - ret = __fimc_pipeline_shutdown(fimc); - fimc->pipeline.sensor = NULL; - fimc->pipeline.csis = NULL; + switch (sd->grp_id) { + case FIMC_GROUP_ID: + fimc = v4l2_get_subdevdata(sd); + pipeline = &fimc->pipeline; + break; + default: + return 0; + } - mutex_lock(&fimc->lock); - fimc_ctrls_delete(fimc->vid_cap.ctx); - mutex_unlock(&fimc->lock); + if (!(flags & MEDIA_LNK_FL_ENABLED)) { + ret = __fimc_pipeline_shutdown(pipeline); + pipeline->subdevs[IDX_SENSOR] = NULL; + pipeline->subdevs[IDX_CSIS] = NULL; + + if (fimc) { + mutex_lock(&fimc->lock); + fimc_ctrls_delete(fimc->vid_cap.ctx); + mutex_unlock(&fimc->lock); + } return ret; } /* @@ -704,7 +741,8 @@ static int fimc_md_link_notify(struct media_pad *source, */ mutex_lock(&fimc->lock); if (fimc->vid_cap.refcnt > 0) { - ret = __fimc_pipeline_initialize(fimc, source->entity, true); + ret = __fimc_pipeline_initialize(pipeline, + source->entity, true); if (!ret) ret = fimc_capture_ctrls_create(fimc); } |