[media] m5mols: Add support for the system initialization interrupt
authorHeungJun Kim <riverful.kim@samsung.com>
Sat, 3 Dec 2011 14:47:40 +0000 (11:47 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Fri, 30 Dec 2011 16:35:25 +0000 (14:35 -0200)
The M-5MOLS internal controller's initialization time depends on the
hardware and firmware revision. Currently the driver just waits for
worst case time period, after applying the voltage supplies, for
the device to be ready. The M-5MOLS supports "System initialization"
interrupt which is triggered after the controller finished booting.
So use this interrupt to optimize the initialization sequence.

After the voltage supplies are applied the I2C communication will
fail, until the internal controller initializes to Flash Writer
state. For the period when the I2C is not accessible use the
isp_ready flag to suppress the error logs.

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
drivers/media/video/m5mols/m5mols_reg.h

index 5a8a858fdb2da30f9c7d5958d55b52cf0166f19a..0265ea602280a91e3215d8e4e7abea4f9e41918d 100644 (file)
@@ -174,8 +174,8 @@ struct m5mols_version {
  * @ver: information of the version
  * @cap: the capture mode attributes
  * @power: current sensor's power status
- * @ctrl_sync: true means all controls of the sensor are initialized
- * @int_capture: true means the capture interrupt is issued once
+ * @isp_ready: 1 when the ISP controller has completed booting
+ * @ctrl_sync: 1 when the control handler state is restored in H/W
  * @lock_ae: true means the Auto Exposure is locked
  * @lock_awb: true means the Aut WhiteBalance is locked
  * @resolution:        register value for current resolution
@@ -204,8 +204,11 @@ struct m5mols_info {
 
        struct m5mols_version ver;
        struct m5mols_capture cap;
-       bool power;
-       bool ctrl_sync;
+
+       unsigned int isp_ready:1;
+       unsigned int power:1;
+       unsigned int ctrl_sync:1;
+
        bool lock_ae;
        bool lock_awb;
        u8 resolution;
@@ -213,7 +216,6 @@ struct m5mols_info {
        int (*set_power)(struct device *dev, int on);
 };
 
-#define is_powered(__info) (__info->power)
 #define is_ctrl_synced(__info) (__info->ctrl_sync)
 #define is_available_af(__info)        (__info->ver.af)
 #define is_code(__code, __type) (__code == m5mols_default_ffmt[__type].code)
index 070f04c399148b1497cfa863105eee6f921ae842..3c7556f4022131c12963b97195d2a5b96e5cd680 100644 (file)
@@ -135,10 +135,13 @@ static u32 m5mols_swap_byte(u8 *data, u8 length)
  * @reg: combination of size, category and command for the I2C packet
  * @size: desired size of I2C packet
  * @val: read value
+ *
+ * Returns 0 on success, or else negative errno.
  */
 static int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct m5mols_info *info = to_m5mols(sd);
        u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1];
        u8 category = I2C_CATEGORY(reg);
        u8 cmd = I2C_COMMAND(reg);
@@ -168,15 +171,17 @@ static int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val)
        usleep_range(200, 200);
 
        ret = i2c_transfer(client->adapter, msg, 2);
-       if (ret < 0) {
-               v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n",
-                        size, category, cmd, ret);
-               return ret;
+
+       if (ret == 2) {
+               *val = m5mols_swap_byte(&rbuf[1], size);
+               return 0;
        }
 
-       *val = m5mols_swap_byte(&rbuf[1], size);
+       if (info->isp_ready)
+               v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n",
+                        size, category, cmd, ret);
 
-       return 0;
+       return ret < 0 ? ret : -EIO;
 }
 
 int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg, u8 *val)
@@ -229,10 +234,13 @@ int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg, u32 *val)
  * m5mols_write - I2C command write function
  * @reg: combination of size, category and command for the I2C packet
  * @val: value to write
+ *
+ * Returns 0 on success, or else negative errno.
  */
 int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct m5mols_info *info = to_m5mols(sd);
        u8 wbuf[M5MOLS_I2C_MAX_SIZE + 4];
        u8 category = I2C_CATEGORY(reg);
        u8 cmd = I2C_COMMAND(reg);
@@ -263,13 +271,14 @@ int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val)
        usleep_range(200, 200);
 
        ret = i2c_transfer(client->adapter, msg, 1);
-       if (ret < 0) {
-               v4l2_err(sd, "write failed: size:%d cat:%02x cmd:%02x. %d\n",
-                       size, category, cmd, ret);
-               return ret;
-       }
+       if (ret == 1)
+               return 0;
 
-       return 0;
+       if (info->isp_ready)
+               v4l2_err(sd, "write failed: cat:%02x cmd:%02x ret:%d\n",
+                        category, cmd, ret);
+
+       return ret < 0 ? ret : -EIO;
 }
 
 /**
@@ -620,7 +629,7 @@ int m5mols_sync_controls(struct m5mols_info *info)
                        return ret;
 
                v4l2_ctrl_handler_setup(&info->handle);
-               info->ctrl_sync = true;
+               info->ctrl_sync = 1;
        }
 
        return ret;
@@ -700,10 +709,10 @@ static int m5mols_sensor_power(struct m5mols_info *info, bool enable)
        const struct m5mols_platform_data *pdata = info->pdata;
        int ret;
 
-       if (enable) {
-               if (is_powered(info))
-                       return 0;
+       if (info->power == enable)
+               return 0;
 
+       if (enable) {
                if (info->set_power) {
                        ret = info->set_power(&client->dev, 1);
                        if (ret)
@@ -717,15 +726,11 @@ static int m5mols_sensor_power(struct m5mols_info *info, bool enable)
                }
 
                gpio_set_value(pdata->gpio_reset, !pdata->reset_polarity);
-               usleep_range(1000, 1000);
-               info->power = true;
+               info->power = 1;
 
                return ret;
        }
 
-       if (!is_powered(info))
-               return 0;
-
        ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
        if (ret)
                return ret;
@@ -734,8 +739,9 @@ static int m5mols_sensor_power(struct m5mols_info *info, bool enable)
                info->set_power(&client->dev, 0);
 
        gpio_set_value(pdata->gpio_reset, pdata->reset_polarity);
-       usleep_range(1000, 1000);
-       info->power = false;
+
+       info->isp_ready = 0;
+       info->power = 0;
 
        return ret;
 }
@@ -748,21 +754,29 @@ int __attribute__ ((weak)) m5mols_update_fw(struct v4l2_subdev *sd,
 }
 
 /**
- * m5mols_sensor_armboot - Booting M-5MOLS internal ARM core.
+ * m5mols_fw_start - M-5MOLS internal ARM controller initialization
  *
- * Booting internal ARM core makes the M-5MOLS is ready for getting commands
- * with I2C. It's the first thing to be done after it powered up. It must wait
- * at least 520ms recommended by M-5MOLS datasheet, after executing arm booting.
+ * Execute the M-5MOLS internal ARM controller initialization sequence.
+ * This function should be called after the supply voltage has been
+ * applied and before any requests to the device are made.
  */
-static int m5mols_sensor_armboot(struct v4l2_subdev *sd)
+static int m5mols_fw_start(struct v4l2_subdev *sd)
 {
+       struct m5mols_info *info = to_m5mols(sd);
        int ret;
 
-       ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT);
+       atomic_set(&info->irq_done, 0);
+       /* Wait until I2C slave is initialized in Flash Writer mode */
+       ret = m5mols_busy_wait(sd, FLASH_CAM_START, REG_IN_FLASH_MODE,
+                              M5MOLS_I2C_RDY_WAIT_FL | 0xff, -1);
+       if (!ret)
+               ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT);
+       if (!ret)
+               ret = m5mols_wait_interrupt(sd, REG_INT_MODE, 2000);
        if (ret < 0)
                return ret;
 
-       msleep(520);
+       info->isp_ready = 1;
 
        ret = m5mols_get_version(sd);
        if (!ret)
@@ -840,7 +854,7 @@ static int m5mols_s_power(struct v4l2_subdev *sd, int on)
        if (on) {
                ret = m5mols_sensor_power(info, true);
                if (!ret)
-                       ret = m5mols_sensor_armboot(sd);
+                       ret = m5mols_fw_start(sd);
                if (!ret)
                        ret = m5mols_init_controls(info);
                if (ret)
@@ -869,7 +883,7 @@ static int m5mols_s_power(struct v4l2_subdev *sd, int on)
        ret = m5mols_sensor_power(info, false);
        if (!ret) {
                v4l2_ctrl_handler_free(&info->handle);
-               info->ctrl_sync = false;
+               info->ctrl_sync = 0;
        }
 
        return ret;
index d488add006de2b54ee67f827ae1911da78bd4e04..ae4aced0f9b23b0789c69647f2810c9cf98426a7 100644 (file)
 
 /* Starts internal ARM core booting after power-up */
 #define FLASH_CAM_START                I2C_REG(CAT_FLASH, 0x12, 1)
-#define REG_START_ARM_BOOT     0x01
+#define REG_START_ARM_BOOT     0x01    /* write value */
+#define REG_IN_FLASH_MODE      0x00    /* read value */
 
 #endif /* M5MOLS_REG_H */