/** * m5mols_fw_start - M-5MOLS internal ARM controller initialization * * 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_fw_start(struct v4l2_subdev *sd) { struct m5mols_info *info = to_m5mols(sd); int ret; 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; info->isp_ready = 1; ret = m5mols_get_version(sd); if (!ret) ret = m5mols_update_fw(sd, m5mols_sensor_power); if (ret) return ret; v4l2_dbg(1, m5mols_debug, sd, "Success ARM Booting\n"); ret = m5mols_write(sd, PARM_INTERFACE, REG_INTERFACE_MIPI); if (!ret) ret = m5mols_enable_interrupt(sd, REG_INT_AF | REG_INT_CAPTURE); return ret; }
/** * m5mols_s_power - Main sensor power control function * * To prevent breaking the lens when the sensor is powered off the Soft-Landing * algorithm is called where available. The Soft-Landing algorithm availability * dependends on the firmware provider. */ static int m5mols_s_power(struct v4l2_subdev *sd, int on) { struct m5mols_info *info = to_m5mols(sd); int ret; if (on) { ret = m5mols_sensor_power(info, true); if (!ret) ret = m5mols_fw_start(sd); return ret; } if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) { ret = m5mols_set_mode(info, REG_MONITOR); if (!ret) ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP); if (!ret) ret = m5mols_write(sd, AF_MODE, REG_AF_POWEROFF); if (!ret) 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); info->ctrl_sync = 0; return ret; }
/** * m5mols_reg_mode - Write the mode and check busy status * * It always accompanies a little delay changing the M-5MOLS mode, so it is * needed checking current busy status to guarantee right mode. */ static int m5mols_reg_mode(struct v4l2_subdev *sd, u8 mode) { int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode); if (ret < 0) return ret; return m5mols_busy_wait(sd, SYSTEM_SYSMODE, mode, 0xff, M5MOLS_MODE_CHANGE_TIMEOUT); }
/* Execute the lens soft-landing algorithm */ static int m5mols_auto_focus_stop(struct m5mols_info *info) { int ret; ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP); if (!ret) ret = m5mols_write(&info->sd, AF_MODE, REG_AF_POWEROFF); if (!ret) ret = m5mols_busy_wait(&info->sd, SYSTEM_STATUS, REG_AF_IDLE, 0xff, -1); return ret; }
int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 irq_mask, u32 timeout) { struct m5mols_info *info = to_m5mols(sd); int ret = wait_event_interruptible_timeout(info->irq_waitq, atomic_add_unless(&info->irq_done, -1, 0), msecs_to_jiffies(timeout)); if (ret <= 0) return ret ? ret : -ETIMEDOUT; return m5mols_busy_wait(sd, SYSTEM_INT_FACTOR, irq_mask, M5MOLS_I2C_RDY_WAIT_FL | irq_mask, -1); }