|
@@ -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;
|