[media] m5mols: Extend the busy wait helper
authorHeungJun Kim <riverful.kim@samsung.com>
Mon, 12 Dec 2011 11:04:03 +0000 (08:04 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Fri, 30 Dec 2011 16:33:09 +0000 (14:33 -0200)
Make m5mols_busy_wait function jiffies based rather than relying
on some fixed number of I2C read iterations while busy waiting
for the device to execute a request. With fixed number of iterations
we may be getting different wait times, depending on the I2C speed.

In some conditions we have to wait even if the I2C communications
fails, in those cases M5MOLS_I2C_RDY_WAIT_MASK should be passed
as the mask argument to m5mols_busy_wait().

Signed-off-by: HeungJun Kim <riverful.kim@samsung.com>
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/m5mols/m5mols.h
drivers/media/video/m5mols/m5mols_core.c

index 42c494c1e583e4ee1c55376daf4fd7fa7c1c2d2e..f33171672c31a6a959cb2449c0a2de8fb633629f 100644 (file)
@@ -257,7 +257,15 @@ int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg_comb, u8 *val);
 int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg_comb, u16 *val);
 int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg_comb, u32 *val);
 int m5mols_write(struct v4l2_subdev *sd, u32 reg_comb, u32 val);
-int m5mols_busy(struct v4l2_subdev *sd, u32 reg, u8 value);
+
+int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask,
+                    int timeout);
+
+/* Mask value for busy waiting until M-5MOLS I2C interface is initialized */
+#define M5MOLS_I2C_RDY_WAIT_FL         (1 << 16)
+/* ISP state transition timeout, in ms */
+#define M5MOLS_MODE_CHANGE_TIMEOUT     200
+#define M5MOLS_BUSY_WAIT_DEF_TIMEOUT   250
 
 /*
  * Mode operation of the M-5MOLS
index 10170b89ab59b457cfab9126e8a0d345efdcbb6b..5005127bb11c3e78645a942b056937d82df8c9f1 100644 (file)
@@ -272,19 +272,35 @@ int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val)
        return 0;
 }
 
-int m5mols_busy(struct v4l2_subdev *sd, u32 reg, u8 mask)
+/**
+ * m5mols_busy_wait - Busy waiting with I2C register polling
+ * @reg: the I2C_REG() address of an 8-bit status register to check
+ * @value: expected status register value
+ * @mask: bit mask for the read status register value
+ * @timeout: timeout in miliseconds, or -1 for default timeout
+ *
+ * The @reg register value is ORed with @mask before comparing with @value.
+ *
+ * Return: 0 if the requested condition became true within less than
+ *         @timeout ms, or else negative errno.
+ */
+int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask,
+                    int timeout)
 {
-       u8 busy;
-       int i;
-       int ret;
+       int ms = timeout < 0 ? M5MOLS_BUSY_WAIT_DEF_TIMEOUT : timeout;
+       unsigned long end = jiffies + msecs_to_jiffies(ms);
+       u8 status;
 
-       for (i = 0; i < M5MOLS_I2C_CHECK_RETRY; i++) {
-               ret = m5mols_read_u8(sd, reg, &busy);
-               if (ret < 0)
+       do {
+               int ret = m5mols_read_u8(sd, reg, &status);
+
+               if (ret < 0 && !(mask & M5MOLS_I2C_RDY_WAIT_FL))
                        return ret;
-               if ((busy & mask) == mask)
+               if (!ret && (status & mask & 0xff) == (value & 0xff))
                        return 0;
-       }
+               usleep_range(100, 250);
+       } while (ms > 0 && time_is_after_jiffies(end));
+
        return -EBUSY;
 }
 
@@ -316,8 +332,10 @@ int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg)
 static int m5mols_reg_mode(struct v4l2_subdev *sd, u8 mode)
 {
        int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode);
-
-       return ret ? ret : m5mols_busy(sd, mode, SYSTEM_SYSMODE);
+       if (ret < 0)
+               return ret;
+       return m5mols_busy_wait(sd, SYSTEM_SYSMODE, mode, 0xff,
+                               M5MOLS_MODE_CHANGE_TIMEOUT);
 }
 
 /**
@@ -829,9 +847,10 @@ static int m5mols_s_power(struct v4l2_subdev *sd, int on)
                if (!ret)
                        ret = m5mols_write(sd, AF_MODE, REG_AF_POWEROFF);
                if (!ret)
-                       ret = m5mols_busy(sd, SYSTEM_STATUS, REG_AF_IDLE);
-               if (!ret)
-                       v4l2_info(sd, "Success soft-landing lens\n");
+                       ret = m5mols_busy_wait(sd, SYSTEM_STATUS, REG_AF_IDLE,
+                                              0xff, -1);
+               if (ret < 0)
+                       v4l2_warn(sd, "Soft landing lens failed\n");
        }
 
        ret = m5mols_sensor_power(info, false);