1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/bitops.h>
3 #include <linux/device.h>
4 #include <linux/delay.h>
5 #include <linux/errno.h>
7 #include <linux/gpio.h>
8 #include <linux/init.h>
11 #include <linux/kernel.h>
13 #include <linux/kmod.h>
14 #include <linux/module.h>
15 #include <linux/moduleparam.h>
16 #include <linux/string.h>
17 #include <linux/slab.h>
18 #include <linux/types.h>
19 #include <media/v4l2-device.h>
23 struct ad5816g_device ad5816g_dev;
25 static int ad5816g_i2c_rd8(struct i2c_client *client, u8 reg, u8 *val)
27 struct i2c_msg msg[2];
32 msg[0].addr = AD5816G_VCM_ADDR;
37 msg[1].addr = AD5816G_VCM_ADDR;
38 msg[1].flags = I2C_M_RD;
42 if (i2c_transfer(client->adapter, msg, 2) != 2)
48 static int ad5816g_i2c_wr8(struct i2c_client *client, u8 reg, u8 val)
54 msg.addr = AD5816G_VCM_ADDR;
58 if (i2c_transfer(client->adapter, &msg, 1) != 1)
63 static int ad5816g_i2c_wr16(struct i2c_client *client, u8 reg, u16 val)
68 buf[1] = (u8)(val >> 8);
69 buf[2] = (u8)(val & 0xff);
70 msg.addr = AD5816G_VCM_ADDR;
74 if (i2c_transfer(client->adapter, &msg, 1) != 1)
79 static int ad5816g_set_arc_mode(struct i2c_client *client)
83 ret = ad5816g_i2c_wr8(client, AD5816G_CONTROL, AD5816G_ARC_EN);
87 ret = ad5816g_i2c_wr8(client, AD5816G_MODE,
88 AD5816G_MODE_2_5M_SWITCH_CLOCK);
92 ret = ad5816g_i2c_wr8(client, AD5816G_VCM_FREQ, AD5816G_DEF_FREQ);
96 int ad5816g_vcm_power_up(struct v4l2_subdev *sd)
98 struct i2c_client *client = v4l2_get_subdevdata(sd);
103 ret = ad5816g_dev.platform_data->power_ctrl(sd, 1);
106 /* waiting time AD5816G(vcm) - t1 + t2
107 * t1(1ms) -Time from VDD high to first i2c cmd
108 * t2(100us) - exit power-down mode time
110 usleep_range(1100, 2200);
112 ret = ad5816g_i2c_rd8(client, AD5816G_IC_INFO, &ad5816g_id);
115 if (ad5816g_id != AD5816G_ID) {
119 ret = ad5816g_set_arc_mode(client);
123 /* set the VCM_THRESHOLD */
124 ret = ad5816g_i2c_wr8(client, AD5816G_VCM_THRESHOLD,
125 AD5816G_DEF_THRESHOLD);
130 ad5816g_dev.platform_data->power_ctrl(sd, 0);
134 int ad5816g_vcm_power_down(struct v4l2_subdev *sd)
136 return ad5816g_dev.platform_data->power_ctrl(sd, 0);
140 static int ad5816g_t_focus_vcm(struct v4l2_subdev *sd, u16 val)
142 struct i2c_client *client = v4l2_get_subdevdata(sd);
143 u16 data = val & VCM_CODE_MASK;
145 return ad5816g_i2c_wr16(client, AD5816G_VCM_CODE_MSB, data);
148 int ad5816g_t_focus_abs(struct v4l2_subdev *sd, s32 value)
152 value = clamp(value, 0, AD5816G_MAX_FOCUS_POS);
153 ret = ad5816g_t_focus_vcm(sd, value);
155 ad5816g_dev.number_of_steps = value - ad5816g_dev.focus;
156 ad5816g_dev.focus = value;
157 getnstimeofday(&(ad5816g_dev.timestamp_t_focus_abs));
163 int ad5816g_t_focus_rel(struct v4l2_subdev *sd, s32 value)
166 return ad5816g_t_focus_abs(sd, ad5816g_dev.focus + value);
169 int ad5816g_q_focus_status(struct v4l2_subdev *sd, s32 *value)
172 struct timespec temptime;
173 const struct timespec timedelay = {
175 min_t(u32, abs(ad5816g_dev.number_of_steps) * DELAY_PER_STEP_NS,
176 DELAY_MAX_PER_STEP_NS),
179 ktime_get_ts(&temptime);
181 temptime = timespec_sub(temptime, (ad5816g_dev.timestamp_t_focus_abs));
183 if (timespec_compare(&temptime, &timedelay) <= 0) {
184 status |= ATOMISP_FOCUS_STATUS_MOVING;
185 status |= ATOMISP_FOCUS_HP_IN_PROGRESS;
187 status |= ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE;
188 status |= ATOMISP_FOCUS_HP_COMPLETE;
195 int ad5816g_q_focus_abs(struct v4l2_subdev *sd, s32 *value)
199 ad5816g_q_focus_status(sd, &val);
201 if (val & ATOMISP_FOCUS_STATUS_MOVING)
202 *value = ad5816g_dev.focus - ad5816g_dev.number_of_steps;
204 *value = ad5816g_dev.focus;
209 int ad5816g_t_vcm_slew(struct v4l2_subdev *sd, s32 value)
214 int ad5816g_t_vcm_timing(struct v4l2_subdev *sd, s32 value)