]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/staging/media/atomisp/i2c/imx/dw9714.c
media: staging: atomisp: Remove unneeded intel-mid.h inclusion
[mirror_ubuntu-bionic-kernel.git] / drivers / staging / media / atomisp / i2c / imx / dw9714.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 "dw9714.h"
21
22 static struct dw9714_device dw9714_dev;
23 static int dw9714_i2c_write(struct i2c_client *client, u16 data)
24 {
25 struct i2c_msg msg;
26 const int num_msg = 1;
27 int ret;
28 u16 val;
29
30 val = cpu_to_be16(data);
31 msg.addr = DW9714_VCM_ADDR;
32 msg.flags = 0;
33 msg.len = DW9714_16BIT;
34 msg.buf = (u8 *)&val;
35
36 ret = i2c_transfer(client->adapter, &msg, 1);
37
38 return ret == num_msg ? 0 : -EIO;
39 }
40
41 int dw9714_vcm_power_up(struct v4l2_subdev *sd)
42 {
43 int ret;
44
45 /* Enable power */
46 ret = dw9714_dev.platform_data->power_ctrl(sd, 1);
47 /* waiting time requested by DW9714A(vcm) */
48 usleep_range(12000, 12500);
49 return ret;
50 }
51
52 int dw9714_vcm_power_down(struct v4l2_subdev *sd)
53 {
54 return dw9714_dev.platform_data->power_ctrl(sd, 0);
55 }
56
57
58 static int dw9714_t_focus_vcm(struct v4l2_subdev *sd, u16 val)
59 {
60 struct i2c_client *client = v4l2_get_subdevdata(sd);
61 int ret = -EINVAL;
62 u8 mclk = vcm_step_mclk(dw9714_dev.vcm_settings.step_setting);
63 u8 s = vcm_step_s(dw9714_dev.vcm_settings.step_setting);
64
65 /*
66 * For different mode, VCM_PROTECTION_OFF/ON required by the
67 * control procedure. For DW9714_DIRECT/DLC mode, slew value is
68 * VCM_DEFAULT_S(0).
69 */
70 switch (dw9714_dev.vcm_mode) {
71 case DW9714_DIRECT:
72 if (dw9714_dev.vcm_settings.update) {
73 ret = dw9714_i2c_write(client, VCM_PROTECTION_OFF);
74 if (ret)
75 return ret;
76 ret = dw9714_i2c_write(client, DIRECT_VCM);
77 if (ret)
78 return ret;
79 ret = dw9714_i2c_write(client, VCM_PROTECTION_ON);
80 if (ret)
81 return ret;
82 dw9714_dev.vcm_settings.update = false;
83 }
84 ret = dw9714_i2c_write(client,
85 vcm_val(val, VCM_DEFAULT_S));
86 break;
87 case DW9714_LSC:
88 if (dw9714_dev.vcm_settings.update) {
89 ret = dw9714_i2c_write(client, VCM_PROTECTION_OFF);
90 if (ret)
91 return ret;
92 ret = dw9714_i2c_write(client,
93 vcm_dlc_mclk(DLC_DISABLE, mclk));
94 if (ret)
95 return ret;
96 ret = dw9714_i2c_write(client,
97 vcm_tsrc(dw9714_dev.vcm_settings.t_src));
98 if (ret)
99 return ret;
100 ret = dw9714_i2c_write(client, VCM_PROTECTION_ON);
101 if (ret)
102 return ret;
103 dw9714_dev.vcm_settings.update = false;
104 }
105 ret = dw9714_i2c_write(client, vcm_val(val, s));
106 break;
107 case DW9714_DLC:
108 if (dw9714_dev.vcm_settings.update) {
109 ret = dw9714_i2c_write(client, VCM_PROTECTION_OFF);
110 if (ret)
111 return ret;
112 ret = dw9714_i2c_write(client,
113 vcm_dlc_mclk(DLC_ENABLE, mclk));
114 if (ret)
115 return ret;
116 ret = dw9714_i2c_write(client,
117 vcm_tsrc(dw9714_dev.vcm_settings.t_src));
118 if (ret)
119 return ret;
120 ret = dw9714_i2c_write(client, VCM_PROTECTION_ON);
121 if (ret)
122 return ret;
123 dw9714_dev.vcm_settings.update = false;
124 }
125 ret = dw9714_i2c_write(client,
126 vcm_val(val, VCM_DEFAULT_S));
127 break;
128 }
129 return ret;
130 }
131
132 int dw9714_t_focus_abs(struct v4l2_subdev *sd, s32 value)
133 {
134 int ret;
135
136 value = clamp(value, 0, DW9714_MAX_FOCUS_POS);
137 ret = dw9714_t_focus_vcm(sd, value);
138 if (ret == 0) {
139 dw9714_dev.number_of_steps = value - dw9714_dev.focus;
140 dw9714_dev.focus = value;
141 getnstimeofday(&(dw9714_dev.timestamp_t_focus_abs));
142 }
143
144 return ret;
145 }
146
147 int dw9714_t_focus_abs_init(struct v4l2_subdev *sd)
148 {
149 int ret;
150
151 ret = dw9714_t_focus_vcm(sd, DW9714_DEFAULT_FOCUS_POS);
152 if (ret == 0) {
153 dw9714_dev.number_of_steps =
154 DW9714_DEFAULT_FOCUS_POS - dw9714_dev.focus;
155 dw9714_dev.focus = DW9714_DEFAULT_FOCUS_POS;
156 getnstimeofday(&(dw9714_dev.timestamp_t_focus_abs));
157 }
158
159 return ret;
160 }
161
162 int dw9714_t_focus_rel(struct v4l2_subdev *sd, s32 value)
163 {
164
165 return dw9714_t_focus_abs(sd, dw9714_dev.focus + value);
166 }
167
168 int dw9714_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(dw9714_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, (dw9714_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 dw9714_q_focus_abs(struct v4l2_subdev *sd, s32 *value)
195 {
196 s32 val;
197
198 dw9714_q_focus_status(sd, &val);
199
200 if (val & ATOMISP_FOCUS_STATUS_MOVING)
201 *value = dw9714_dev.focus - dw9714_dev.number_of_steps;
202 else
203 *value = dw9714_dev.focus;
204
205 return 0;
206 }
207
208 int dw9714_t_vcm_slew(struct v4l2_subdev *sd, s32 value)
209 {
210 dw9714_dev.vcm_settings.step_setting = value;
211 dw9714_dev.vcm_settings.update = true;
212
213 return 0;
214 }
215
216 int dw9714_t_vcm_timing(struct v4l2_subdev *sd, s32 value)
217 {
218 dw9714_dev.vcm_settings.t_src = value;
219 dw9714_dev.vcm_settings.update = true;
220
221 return 0;
222 }