From: Russell King <rmk+ker...@armlinux.org.uk>

Add support to CSI for negotiation of frame intervals, and use this
information to configure the frame interval monitor.

Signed-off-by: Russell King <rmk+ker...@armlinux.org.uk>
Signed-off-by: Steve Longerbeam <steve_longerb...@mentor.com>
---
 drivers/staging/media/imx/imx-media-csi.c | 46 +++++++++++++++++++++++++++++--
 drivers/staging/media/imx/imx-media-fim.c | 28 +++++++------------
 drivers/staging/media/imx/imx-media.h     |  2 +-
 3 files changed, 54 insertions(+), 22 deletions(-)

diff --git a/drivers/staging/media/imx/imx-media-csi.c 
b/drivers/staging/media/imx/imx-media-csi.c
index f4c6a33..59d80ba 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -63,6 +63,7 @@ struct csi_priv {
 
        struct v4l2_mbus_framefmt format_mbus[CSI_NUM_PADS];
        const struct imx_media_pixfmt *cc[CSI_NUM_PADS];
+       struct v4l2_fract frame_interval;
        struct v4l2_rect crop;
 
        /* active vb2 buffers to send to video dev sink */
@@ -589,7 +590,8 @@ static int csi_start(struct csi_priv *priv)
 
        /* start the frame interval monitor */
        if (priv->fim) {
-               ret = imx_media_fim_set_stream(priv->fim, priv->sensor, true);
+               ret = imx_media_fim_set_stream(priv->fim,
+                                              &priv->frame_interval, true);
                if (ret)
                        goto idmac_stop;
        }
@@ -604,7 +606,8 @@ static int csi_start(struct csi_priv *priv)
 
 fim_off:
        if (priv->fim)
-               imx_media_fim_set_stream(priv->fim, priv->sensor, false);
+               imx_media_fim_set_stream(priv->fim,
+                                        &priv->frame_interval, false);
 idmac_stop:
        if (priv->dest == IPU_CSI_DEST_IDMAC)
                csi_idmac_stop(priv);
@@ -618,7 +621,8 @@ static void csi_stop(struct csi_priv *priv)
 
        /* stop the frame interval monitor */
        if (priv->fim)
-               imx_media_fim_set_stream(priv->fim, priv->sensor, false);
+               imx_media_fim_set_stream(priv->fim,
+                                        &priv->frame_interval, false);
 
        ipu_csi_disable(priv->csi);
 }
@@ -627,6 +631,36 @@ static void csi_stop(struct csi_priv *priv)
  * V4L2 subdev operations.
  */
 
+static int csi_g_frame_interval(struct v4l2_subdev *sd,
+                               struct v4l2_subdev_frame_interval *fi)
+{
+       struct csi_priv *priv = v4l2_get_subdevdata(sd);
+
+       mutex_lock(&priv->lock);
+       fi->interval = priv->frame_interval;
+       mutex_unlock(&priv->lock);
+
+       return 0;
+}
+
+static int csi_s_frame_interval(struct v4l2_subdev *sd,
+                               struct v4l2_subdev_frame_interval *fi)
+{
+       struct csi_priv *priv = v4l2_get_subdevdata(sd);
+
+       mutex_lock(&priv->lock);
+
+       /* Output pads mirror active input pad, no limits on input pads */
+       if (fi->pad == CSI_SRC_PAD_IDMAC || fi->pad == CSI_SRC_PAD_DIRECT)
+               fi->interval = priv->frame_interval;
+
+       priv->frame_interval = fi->interval;
+
+       mutex_unlock(&priv->lock);
+
+       return 0;
+}
+
 static int csi_s_stream(struct v4l2_subdev *sd, int enable)
 {
        struct csi_priv *priv = v4l2_get_subdevdata(sd);
@@ -1216,6 +1250,10 @@ static int csi_registered(struct v4l2_subdev *sd)
                        goto put_csi;
        }
 
+       /* init default frame interval */
+       priv->frame_interval.numerator = 1;
+       priv->frame_interval.denominator = 30;
+
        priv->fim = imx_media_fim_init(&priv->sd);
        if (IS_ERR(priv->fim)) {
                ret = PTR_ERR(priv->fim);
@@ -1266,6 +1304,8 @@ static struct v4l2_subdev_core_ops csi_core_ops = {
 };
 
 static struct v4l2_subdev_video_ops csi_video_ops = {
+       .g_frame_interval = csi_g_frame_interval,
+       .s_frame_interval = csi_s_frame_interval,
        .s_stream = csi_s_stream,
 };
 
diff --git a/drivers/staging/media/imx/imx-media-fim.c 
b/drivers/staging/media/imx/imx-media-fim.c
index 0623bc5..e9525cd 100644
--- a/drivers/staging/media/imx/imx-media-fim.c
+++ b/drivers/staging/media/imx/imx-media-fim.c
@@ -67,26 +67,18 @@ struct imx_media_fim {
 };
 
 static void update_fim_nominal(struct imx_media_fim *fim,
-                              struct imx_media_subdev *sensor)
+                              const struct v4l2_fract *fi)
 {
-       struct v4l2_streamparm parm;
-       struct v4l2_fract tpf;
-       int ret;
-
-       parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       ret = v4l2_subdev_call(sensor->sd, video, g_parm, &parm);
-       tpf = parm.parm.capture.timeperframe;
-
-       if (ret || tpf.denominator == 0) {
-               dev_dbg(fim->sd->dev, "no tpf from sensor, FIM disabled\n");
+       if (fi->denominator == 0) {
+               dev_dbg(fim->sd->dev, "no frame interval, FIM disabled\n");
                fim->enabled = false;
                return;
        }
 
-       fim->nominal = DIV_ROUND_CLOSEST(1000 * 1000 * tpf.numerator,
-                                        tpf.denominator);
+       fim->nominal = DIV_ROUND_CLOSEST_ULL(1000000ULL * (u64)fi->numerator,
+                                            fi->denominator);
 
-       dev_dbg(fim->sd->dev, "sensor FI=%lu usec\n", fim->nominal);
+       dev_dbg(fim->sd->dev, "FI=%lu usec\n", fim->nominal);
 }
 
 static void reset_fim(struct imx_media_fim *fim, bool curval)
@@ -130,8 +122,8 @@ static void send_fim_event(struct imx_media_fim *fim, 
unsigned long error)
 
 /*
  * Monitor an averaged frame interval. If the average deviates too much
- * from the sensor's nominal frame rate, send the frame interval error
- * event. The frame intervals are averaged in order to quiet noise from
+ * from the nominal frame rate, send the frame interval error event. The
+ * frame intervals are averaged in order to quiet noise from
  * (presumably random) interrupt latency.
  */
 static void frame_interval_monitor(struct imx_media_fim *fim,
@@ -422,12 +414,12 @@ EXPORT_SYMBOL_GPL(imx_media_fim_set_power);
 
 /* Called by the subdev in its s_stream callback */
 int imx_media_fim_set_stream(struct imx_media_fim *fim,
-                            struct imx_media_subdev *sensor,
+                            const struct v4l2_fract *fi,
                             bool on)
 {
        if (on) {
                reset_fim(fim, true);
-               update_fim_nominal(fim, sensor);
+               update_fim_nominal(fim, fi);
 
                if (fim->icap_channel >= 0)
                        fim_acquire_first_ts(fim);
diff --git a/drivers/staging/media/imx/imx-media.h 
b/drivers/staging/media/imx/imx-media.h
index b991081..b6a0e41 100644
--- a/drivers/staging/media/imx/imx-media.h
+++ b/drivers/staging/media/imx/imx-media.h
@@ -256,7 +256,7 @@ struct imx_media_fim;
 void imx_media_fim_eof_monitor(struct imx_media_fim *fim, struct timespec *ts);
 int imx_media_fim_set_power(struct imx_media_fim *fim, bool on);
 int imx_media_fim_set_stream(struct imx_media_fim *fim,
-                            struct imx_media_subdev *sensor,
+                            const struct v4l2_fract *frame_interval,
                             bool on);
 struct imx_media_fim *imx_media_fim_init(struct v4l2_subdev *sd);
 void imx_media_fim_free(struct imx_media_fim *fim);
-- 
2.7.4

Reply via email to