static int fimc_init_capture(struct fimc_dev *fimc)
 {
        struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+       struct fimc_pipeline *p = &fimc->pipeline;
        struct fimc_sensor_info *sensor;
        unsigned long flags;
        int ret = 0;
 
-       if (fimc->pipeline.sensor == NULL || ctx == NULL)
+       if (p->subdevs[IDX_SENSOR] == NULL || ctx == NULL)
                return -ENXIO;
        if (ctx->s_frame.fmt == NULL)
                return -EINVAL;
 
-       sensor = v4l2_get_subdev_hostdata(fimc->pipeline.sensor);
+       sensor = v4l2_get_subdev_hostdata(p->subdevs[IDX_SENSOR]);
 
        spin_lock_irqsave(&fimc->slock, flags);
        fimc_prepare_dma_offset(ctx, &ctx->d_frame);
        spin_unlock_irqrestore(&fimc->slock, flags);
 
        if (streaming)
-               return fimc_pipeline_s_stream(fimc, 0);
+               return fimc_pipeline_s_stream(&fimc->pipeline, 0);
        else
                return 0;
 }
                fimc_activate_capture(ctx);
 
                if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state))
-                       fimc_pipeline_s_stream(fimc, 1);
+                       fimc_pipeline_s_stream(&fimc->pipeline, 1);
        }
 
        return 0;
        int ret = fimc_stop_capture(fimc, suspend);
        if (ret)
                return ret;
-       return fimc_pipeline_shutdown(fimc);
+       return fimc_pipeline_shutdown(&fimc->pipeline);
 }
 
 static void buffer_queue(struct vb2_buffer *vb);
 
        INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q);
        vid_cap->buf_index = 0;
-       fimc_pipeline_initialize(fimc, &fimc->vid_cap.vfd->entity,
+       fimc_pipeline_initialize(&fimc->pipeline, &vid_cap->vfd->entity,
                                 false);
        fimc_init_capture(fimc);
 
                spin_unlock_irqrestore(&fimc->slock, flags);
 
                if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state))
-                       fimc_pipeline_s_stream(fimc, 1);
+                       fimc_pipeline_s_stream(&fimc->pipeline, 1);
                return;
        }
        spin_unlock_irqrestore(&fimc->slock, flags);
                return ret;
 
        return v4l2_ctrl_add_handler(&vid_cap->ctx->ctrl_handler,
-                                   fimc->pipeline.sensor->ctrl_handler);
+                   fimc->pipeline.subdevs[IDX_SENSOR]->ctrl_handler);
 }
 
 static int fimc_capture_set_default_format(struct fimc_dev *fimc);
        pm_runtime_get_sync(&fimc->pdev->dev);
 
        if (++fimc->vid_cap.refcnt == 1) {
-               ret = fimc_pipeline_initialize(fimc,
+               ret = fimc_pipeline_initialize(&fimc->pipeline,
                               &fimc->vid_cap.vfd->entity, true);
                if (ret < 0) {
                        dev_err(&fimc->pdev->dev,
        if (--fimc->vid_cap.refcnt == 0) {
                clear_bit(ST_CAPT_BUSY, &fimc->state);
                fimc_stop_capture(fimc, false);
-               fimc_pipeline_shutdown(fimc);
+               fimc_pipeline_shutdown(&fimc->pipeline);
                clear_bit(ST_CAPT_SUSPENDED, &fimc->state);
        }
 
                                    bool set)
 {
        struct fimc_dev *fimc = ctx->fimc_dev;
-       struct v4l2_subdev *sd = fimc->pipeline.sensor;
-       struct v4l2_subdev *csis = fimc->pipeline.csis;
+       struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
+       struct v4l2_subdev *csis = fimc->pipeline.subdevs[IDX_CSIS];
        struct v4l2_subdev_format sfmt;
        struct v4l2_mbus_framefmt *mf = &sfmt.format;
        struct fimc_fmt *ffmt = NULL;
                               struct v4l2_input *i)
 {
        struct fimc_dev *fimc = video_drvdata(file);
-       struct v4l2_subdev *sd = fimc->pipeline.sensor;
+       struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
 
        if (i->index != 0)
                return -EINVAL;
        if (fimc_capture_active(fimc))
                return -EBUSY;
 
-       media_entity_pipeline_start(&p->sensor->entity, p->pipe);
+       media_entity_pipeline_start(&p->subdevs[IDX_SENSOR]->entity,
+                                   p->m_pipeline);
 
        if (fimc->vid_cap.user_subdev_api) {
                ret = fimc_pipeline_validate(fimc);
                            enum v4l2_buf_type type)
 {
        struct fimc_dev *fimc = video_drvdata(file);
-       struct v4l2_subdev *sd = fimc->pipeline.sensor;
+       struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
        int ret;
 
        ret = vb2_streamoff(&fimc->vid_cap.vbq, type);
 
 #include <media/media-device.h>
 
 #include "fimc-core.h"
+#include "fimc-lite.h"
 #include "fimc-mdevice.h"
 #include "mipi-csis.h"
 
  *
  * 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];
        }
 }
 
 /**
  * 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;
 }
 
 /**
  *
  * 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
  * 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
 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;
                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;
        }
        /*
         */
        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);
        }