#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef CONFIG_GMIN_INTEL_MID /* FIXME! for non-gmin*/ #include #endif #include #include "ad5816g.h" struct ad5816g_device ad5816g_dev; static int ad5816g_i2c_rd8(struct i2c_client *client, u8 reg, u8 *val) { struct i2c_msg msg[2]; u8 buf[2]; buf[0] = reg; buf[1] = 0; msg[0].addr = AD5816G_VCM_ADDR; msg[0].flags = 0; msg[0].len = 1; msg[0].buf = &buf[0]; msg[1].addr = AD5816G_VCM_ADDR; msg[1].flags = I2C_M_RD; msg[1].len = 1; msg[1].buf = &buf[1]; *val = 0; if (i2c_transfer(client->adapter, msg, 2) != 2) return -EIO; *val = buf[1]; return 0; } static int ad5816g_i2c_wr8(struct i2c_client *client, u8 reg, u8 val) { struct i2c_msg msg; u8 buf[2]; buf[0] = reg; buf[1] = val; msg.addr = AD5816G_VCM_ADDR; msg.flags = 0; msg.len = 2; msg.buf = &buf[0]; if (i2c_transfer(client->adapter, &msg, 1) != 1) return -EIO; return 0; } static int ad5816g_i2c_wr16(struct i2c_client *client, u8 reg, u16 val) { struct i2c_msg msg; u8 buf[3]; buf[0] = reg; buf[1] = (u8)(val >> 8); buf[2] = (u8)(val & 0xff); msg.addr = AD5816G_VCM_ADDR; msg.flags = 0; msg.len = 3; msg.buf = &buf[0]; if (i2c_transfer(client->adapter, &msg, 1) != 1) return -EIO; return 0; } static int ad5816g_set_arc_mode(struct i2c_client *client) { int ret; ret = ad5816g_i2c_wr8(client, AD5816G_CONTROL, AD5816G_ARC_EN); if (ret) return ret; ret = ad5816g_i2c_wr8(client, AD5816G_MODE, AD5816G_MODE_2_5M_SWITCH_CLOCK); if (ret) return ret; ret = ad5816g_i2c_wr8(client, AD5816G_VCM_FREQ, AD5816G_DEF_FREQ); return ret; } int ad5816g_vcm_power_up(struct v4l2_subdev *sd) { struct i2c_client *client = v4l2_get_subdevdata(sd); int ret; u8 ad5816g_id; /* Enable power */ ret = ad5816g_dev.platform_data->power_ctrl(sd, 1); if (ret) return ret; /* waiting time AD5816G(vcm) - t1 + t2 * t1(1ms) -Time from VDD high to first i2c cmd * t2(100us) - exit power-down mode time */ usleep_range(1100, 1100); /* Detect device */ ret = ad5816g_i2c_rd8(client, AD5816G_IC_INFO, &ad5816g_id); if (ret < 0) goto fail_powerdown; if (ad5816g_id != AD5816G_ID) { ret = -ENXIO; goto fail_powerdown; } ret = ad5816g_set_arc_mode(client); if (ret) return ret; /* set the VCM_THRESHOLD */ ret = ad5816g_i2c_wr8(client, AD5816G_VCM_THRESHOLD, AD5816G_DEF_THRESHOLD); return ret; fail_powerdown: ad5816g_dev.platform_data->power_ctrl(sd, 0); return ret; } int ad5816g_vcm_power_down(struct v4l2_subdev *sd) { return ad5816g_dev.platform_data->power_ctrl(sd, 0); } int ad5816g_t_focus_vcm(struct v4l2_subdev *sd, u16 val) { struct i2c_client *client = v4l2_get_subdevdata(sd); u16 data = val & VCM_CODE_MASK; return ad5816g_i2c_wr16(client, AD5816G_VCM_CODE_MSB, data); } int ad5816g_t_focus_abs(struct v4l2_subdev *sd, s32 value) { int ret; value = clamp(value, 0, AD5816G_MAX_FOCUS_POS); ret = ad5816g_t_focus_vcm(sd, value); if (ret == 0) { ad5816g_dev.number_of_steps = value - ad5816g_dev.focus; ad5816g_dev.focus = value; getnstimeofday(&(ad5816g_dev.timestamp_t_focus_abs)); } return ret; } int ad5816g_t_focus_rel(struct v4l2_subdev *sd, s32 value) { return ad5816g_t_focus_abs(sd, ad5816g_dev.focus + value); } int ad5816g_q_focus_status(struct v4l2_subdev *sd, s32 *value) { u32 status = 0; struct timespec temptime; const struct timespec timedelay = { 0, min_t(u32, abs(ad5816g_dev.number_of_steps) * DELAY_PER_STEP_NS, DELAY_MAX_PER_STEP_NS), }; ktime_get_ts(&temptime); temptime = timespec_sub(temptime, (ad5816g_dev.timestamp_t_focus_abs)); if (timespec_compare(&temptime, &timedelay) <= 0) { status |= ATOMISP_FOCUS_STATUS_MOVING; status |= ATOMISP_FOCUS_HP_IN_PROGRESS; } else { status |= ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE; status |= ATOMISP_FOCUS_HP_COMPLETE; } *value = status; return 0; } int ad5816g_q_focus_abs(struct v4l2_subdev *sd, s32 *value) { s32 val; ad5816g_q_focus_status(sd, &val); if (val & ATOMISP_FOCUS_STATUS_MOVING) *value = ad5816g_dev.focus - ad5816g_dev.number_of_steps; else *value = ad5816g_dev.focus ; return 0; } int ad5816g_t_vcm_slew(struct v4l2_subdev *sd, s32 value) { return 0; } int ad5816g_t_vcm_timing(struct v4l2_subdev *sd, s32 value) { return 0; } int ad5816g_vcm_init(struct v4l2_subdev *sd) { ad5816g_dev.platform_data = camera_get_af_platform_data(); return (NULL == ad5816g_dev.platform_data) ? -ENODEV : 0; }