]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/staging/media/atomisp/i2c/imx/ad5816g.c
media: staging: atomisp: Convert timers to use timer_setup()
[mirror_ubuntu-bionic-kernel.git] / drivers / staging / media / atomisp / i2c / imx / ad5816g.c
1 #include <linux/bitops.h>
2 #include <linux/device.h>
3 #include <linux/delay.h>
4 #include <linux/errno.h>
5 #include <linux/fs.h>
6 #include <linux/gpio.h>
7 #include <linux/init.h>
8 #include <linux/i2c.h>
9 #include <linux/io.h>
10 #include <linux/kernel.h>
11 #include <linux/mm.h>
12 #include <linux/kmod.h>
13 #include <linux/module.h>
14 #include <linux/moduleparam.h>
15 #include <linux/string.h>
16 #include <linux/slab.h>
17 #include <linux/types.h>
18 #include <media/v4l2-device.h>
19
20 #include "ad5816g.h"
21
22 struct ad5816g_device ad5816g_dev;
23
24 static int ad5816g_i2c_rd8(struct i2c_client *client, u8 reg, u8 *val)
25 {
26 struct i2c_msg msg[2];
27 u8 buf[2];
28 buf[0] = reg;
29 buf[1] = 0;
30
31 msg[0].addr = AD5816G_VCM_ADDR;
32 msg[0].flags = 0;
33 msg[0].len = 1;
34 msg[0].buf = &buf[0];
35
36 msg[1].addr = AD5816G_VCM_ADDR;
37 msg[1].flags = I2C_M_RD;
38 msg[1].len = 1;
39 msg[1].buf = &buf[1];
40 *val = 0;
41 if (i2c_transfer(client->adapter, msg, 2) != 2)
42 return -EIO;
43 *val = buf[1];
44 return 0;
45 }
46
47 static int ad5816g_i2c_wr8(struct i2c_client *client, u8 reg, u8 val)
48 {
49 struct i2c_msg msg;
50 u8 buf[2];
51 buf[0] = reg;
52 buf[1] = val;
53 msg.addr = AD5816G_VCM_ADDR;
54 msg.flags = 0;
55 msg.len = 2;
56 msg.buf = &buf[0];
57 if (i2c_transfer(client->adapter, &msg, 1) != 1)
58 return -EIO;
59 return 0;
60 }
61
62 static int ad5816g_i2c_wr16(struct i2c_client *client, u8 reg, u16 val)
63 {
64 struct i2c_msg msg;
65 u8 buf[3];
66 buf[0] = reg;
67 buf[1] = (u8)(val >> 8);
68 buf[2] = (u8)(val & 0xff);
69 msg.addr = AD5816G_VCM_ADDR;
70 msg.flags = 0;
71 msg.len = 3;
72 msg.buf = &buf[0];
73 if (i2c_transfer(client->adapter, &msg, 1) != 1)
74 return -EIO;
75 return 0;
76 }
77
78 static int ad5816g_set_arc_mode(struct i2c_client *client)
79 {
80 int ret;
81
82 ret = ad5816g_i2c_wr8(client, AD5816G_CONTROL, AD5816G_ARC_EN);
83 if (ret)
84 return ret;
85
86 ret = ad5816g_i2c_wr8(client, AD5816G_MODE,
87 AD5816G_MODE_2_5M_SWITCH_CLOCK);
88 if (ret)
89 return ret;
90
91 ret = ad5816g_i2c_wr8(client, AD5816G_VCM_FREQ, AD5816G_DEF_FREQ);
92 return ret;
93 }
94
95 int ad5816g_vcm_power_up(struct v4l2_subdev *sd)
96 {
97 struct i2c_client *client = v4l2_get_subdevdata(sd);
98 int ret;
99 u8 ad5816g_id;
100
101 /* Enable power */
102 ret = ad5816g_dev.platform_data->power_ctrl(sd, 1);
103 if (ret)
104 return ret;
105 /* waiting time AD5816G(vcm) - t1 + t2
106 * t1(1ms) -Time from VDD high to first i2c cmd
107 * t2(100us) - exit power-down mode time
108 */
109 usleep_range(1100, 2200);
110 /* Detect device */
111 ret = ad5816g_i2c_rd8(client, AD5816G_IC_INFO, &ad5816g_id);
112 if (ret < 0)
113 goto fail_powerdown;
114 if (ad5816g_id != AD5816G_ID) {
115 ret = -ENXIO;
116 goto fail_powerdown;
117 }
118 ret = ad5816g_set_arc_mode(client);
119 if (ret)
120 return ret;
121
122 /* set the VCM_THRESHOLD */
123 ret = ad5816g_i2c_wr8(client, AD5816G_VCM_THRESHOLD,
124 AD5816G_DEF_THRESHOLD);
125
126 return ret;
127
128 fail_powerdown:
129 ad5816g_dev.platform_data->power_ctrl(sd, 0);
130 return ret;
131 }
132
133 int ad5816g_vcm_power_down(struct v4l2_subdev *sd)
134 {
135 return ad5816g_dev.platform_data->power_ctrl(sd, 0);
136 }
137
138
139 static int ad5816g_t_focus_vcm(struct v4l2_subdev *sd, u16 val)
140 {
141 struct i2c_client *client = v4l2_get_subdevdata(sd);
142 u16 data = val & VCM_CODE_MASK;
143
144 return ad5816g_i2c_wr16(client, AD5816G_VCM_CODE_MSB, data);
145 }
146
147 int ad5816g_t_focus_abs(struct v4l2_subdev *sd, s32 value)
148 {
149 int ret;
150
151 value = clamp(value, 0, AD5816G_MAX_FOCUS_POS);
152 ret = ad5816g_t_focus_vcm(sd, value);
153 if (ret == 0) {
154 ad5816g_dev.number_of_steps = value - ad5816g_dev.focus;
155 ad5816g_dev.focus = value;
156 getnstimeofday(&(ad5816g_dev.timestamp_t_focus_abs));
157 }
158
159 return ret;
160 }
161
162 int ad5816g_t_focus_rel(struct v4l2_subdev *sd, s32 value)
163 {
164
165 return ad5816g_t_focus_abs(sd, ad5816g_dev.focus + value);
166 }
167
168 int ad5816g_q_focus_status(struct v4l2_subdev *sd, s32 *value)
169 {
170 u32 status = 0;
171 struct timespec temptime;
172 const struct timespec timedelay = {
173 0,
174 min_t(u32, abs(ad5816g_dev.number_of_steps) * DELAY_PER_STEP_NS,
175 DELAY_MAX_PER_STEP_NS),
176 };
177
178 ktime_get_ts(&temptime);
179
180 temptime = timespec_sub(temptime, (ad5816g_dev.timestamp_t_focus_abs));
181
182 if (timespec_compare(&temptime, &timedelay) <= 0) {
183 status |= ATOMISP_FOCUS_STATUS_MOVING;
184 status |= ATOMISP_FOCUS_HP_IN_PROGRESS;
185 } else {
186 status |= ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE;
187 status |= ATOMISP_FOCUS_HP_COMPLETE;
188 }
189 *value = status;
190
191 return 0;
192 }
193
194 int ad5816g_q_focus_abs(struct v4l2_subdev *sd, s32 *value)
195 {
196 s32 val;
197
198 ad5816g_q_focus_status(sd, &val);
199
200 if (val & ATOMISP_FOCUS_STATUS_MOVING)
201 *value = ad5816g_dev.focus - ad5816g_dev.number_of_steps;
202 else
203 *value = ad5816g_dev.focus;
204
205 return 0;
206 }
207
208 int ad5816g_t_vcm_slew(struct v4l2_subdev *sd, s32 value)
209 {
210 return 0;
211 }
212
213 int ad5816g_t_vcm_timing(struct v4l2_subdev *sd, s32 value)
214 {
215 return 0;
216 }