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
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;
}
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);
}
/**
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);