]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
a49d2536 AC |
2 | #include <linux/bitops.h> |
3 | #include <linux/device.h> | |
4 | #include <linux/delay.h> | |
5 | #include <linux/errno.h> | |
6 | #include <linux/fs.h> | |
7 | #include <linux/gpio.h> | |
8 | #include <linux/init.h> | |
9 | #include <linux/i2c.h> | |
10 | #include <linux/io.h> | |
11 | #include <linux/kernel.h> | |
12 | #include <linux/mm.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> | |
20 | #include <asm/intel-mid.h> | |
21 | ||
22 | #include "drv201.h" | |
23 | ||
24 | static struct drv201_device drv201_dev; | |
25 | ||
26 | static int drv201_i2c_rd8(struct i2c_client *client, u8 reg, u8 *val) | |
27 | { | |
28 | struct i2c_msg msg[2]; | |
29 | u8 buf[2]; | |
30 | buf[0] = reg; | |
31 | buf[1] = 0; | |
32 | ||
33 | msg[0].addr = DRV201_VCM_ADDR; | |
34 | msg[0].flags = 0; | |
35 | msg[0].len = 1; | |
36 | msg[0].buf = &buf[0]; | |
37 | ||
38 | msg[1].addr = DRV201_VCM_ADDR; | |
39 | msg[1].flags = I2C_M_RD; | |
40 | msg[1].len = 1; | |
41 | msg[1].buf = &buf[1]; | |
42 | *val = 0; | |
43 | if (i2c_transfer(client->adapter, msg, 2) != 2) | |
44 | return -EIO; | |
45 | *val = buf[1]; | |
46 | return 0; | |
47 | } | |
48 | ||
49 | static int drv201_i2c_wr8(struct i2c_client *client, u8 reg, u8 val) | |
50 | { | |
51 | struct i2c_msg msg; | |
52 | u8 buf[2]; | |
53 | buf[0] = reg; | |
54 | buf[1] = val; | |
55 | msg.addr = DRV201_VCM_ADDR; | |
56 | msg.flags = 0; | |
57 | msg.len = 2; | |
58 | msg.buf = &buf[0]; | |
59 | if (i2c_transfer(client->adapter, &msg, 1) != 1) | |
60 | return -EIO; | |
61 | return 0; | |
62 | } | |
63 | ||
64 | static int drv201_i2c_wr16(struct i2c_client *client, u8 reg, u16 val) | |
65 | { | |
66 | struct i2c_msg msg; | |
67 | u8 buf[3]; | |
68 | buf[0] = reg; | |
69 | buf[1] = (u8)(val >> 8); | |
70 | buf[2] = (u8)(val & 0xff); | |
71 | msg.addr = DRV201_VCM_ADDR; | |
72 | msg.flags = 0; | |
73 | msg.len = 3; | |
74 | msg.buf = &buf[0]; | |
75 | if (i2c_transfer(client->adapter, &msg, 1) != 1) | |
76 | return -EIO; | |
77 | return 0; | |
78 | } | |
79 | ||
80 | int drv201_vcm_power_up(struct v4l2_subdev *sd) | |
81 | { | |
82 | struct i2c_client *client = v4l2_get_subdevdata(sd); | |
83 | int ret; | |
84 | u8 value; | |
85 | ||
86 | /* Enable power */ | |
87 | ret = drv201_dev.platform_data->power_ctrl(sd, 1); | |
88 | if (ret) | |
89 | return ret; | |
90 | /* Wait for VBAT to stabilize */ | |
91 | udelay(1); | |
92 | /* | |
93 | * Jiggle SCL pin to wake up device. | |
94 | * Drv201 expect SCL from low to high to wake device up. | |
95 | * So the 1st access to i2c would fail. | |
96 | * Using following function to wake device up. | |
97 | */ | |
98 | drv201_i2c_wr8(client, DRV201_CONTROL, DRV201_RESET); | |
99 | ||
100 | /* Need 100us to transit from SHUTDOWN to STANDBY*/ | |
101 | usleep_range(WAKEUP_DELAY_US, WAKEUP_DELAY_US * 10); | |
102 | ||
103 | /* Reset device */ | |
104 | ret = drv201_i2c_wr8(client, DRV201_CONTROL, DRV201_RESET); | |
105 | if (ret < 0) | |
106 | goto fail_powerdown; | |
107 | ||
108 | /* Detect device */ | |
109 | ret = drv201_i2c_rd8(client, DRV201_CONTROL, &value); | |
110 | if (ret < 0) | |
111 | goto fail_powerdown; | |
112 | if (value != DEFAULT_CONTROL_VAL) { | |
113 | ret = -ENXIO; | |
114 | goto fail_powerdown; | |
115 | } | |
116 | ||
117 | drv201_dev.focus = DRV201_MAX_FOCUS_POS; | |
118 | drv201_dev.initialized = true; | |
119 | ||
120 | return 0; | |
121 | fail_powerdown: | |
122 | drv201_dev.platform_data->power_ctrl(sd, 0); | |
123 | return ret; | |
124 | } | |
125 | ||
126 | int drv201_vcm_power_down(struct v4l2_subdev *sd) | |
127 | { | |
128 | return drv201_dev.platform_data->power_ctrl(sd, 0); | |
129 | } | |
130 | ||
131 | ||
4a3039e2 | 132 | static int drv201_t_focus_vcm(struct v4l2_subdev *sd, u16 val) |
a49d2536 AC |
133 | { |
134 | struct i2c_client *client = v4l2_get_subdevdata(sd); | |
135 | u16 data = val & VCM_CODE_MASK; | |
136 | ||
137 | if (!drv201_dev.initialized) | |
138 | return -ENODEV; | |
139 | return drv201_i2c_wr16(client, DRV201_VCM_CURRENT, data); | |
140 | } | |
141 | ||
142 | int drv201_t_focus_abs(struct v4l2_subdev *sd, s32 value) | |
143 | { | |
144 | int ret; | |
145 | ||
146 | value = clamp(value, 0, DRV201_MAX_FOCUS_POS); | |
147 | ret = drv201_t_focus_vcm(sd, value); | |
148 | if (ret == 0) { | |
149 | drv201_dev.number_of_steps = value - drv201_dev.focus; | |
150 | drv201_dev.focus = value; | |
151 | getnstimeofday(&(drv201_dev.timestamp_t_focus_abs)); | |
152 | } | |
153 | ||
154 | return ret; | |
155 | } | |
156 | ||
157 | int drv201_t_focus_rel(struct v4l2_subdev *sd, s32 value) | |
158 | { | |
159 | return drv201_t_focus_abs(sd, drv201_dev.focus + value); | |
160 | } | |
161 | ||
162 | int drv201_q_focus_status(struct v4l2_subdev *sd, s32 *value) | |
163 | { | |
164 | u32 status = 0; | |
165 | struct timespec temptime; | |
166 | const struct timespec timedelay = { | |
167 | 0, | |
168 | min_t(u32, abs(drv201_dev.number_of_steps)*DELAY_PER_STEP_NS, | |
169 | DELAY_MAX_PER_STEP_NS), | |
170 | }; | |
171 | ||
172 | ktime_get_ts(&temptime); | |
173 | ||
174 | temptime = timespec_sub(temptime, (drv201_dev.timestamp_t_focus_abs)); | |
175 | ||
176 | if (timespec_compare(&temptime, &timedelay) <= 0) { | |
177 | status |= ATOMISP_FOCUS_STATUS_MOVING; | |
178 | status |= ATOMISP_FOCUS_HP_IN_PROGRESS; | |
179 | } else { | |
180 | status |= ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE; | |
181 | status |= ATOMISP_FOCUS_HP_COMPLETE; | |
182 | } | |
183 | *value = status; | |
184 | ||
185 | return 0; | |
186 | } | |
187 | ||
188 | int drv201_q_focus_abs(struct v4l2_subdev *sd, s32 *value) | |
189 | { | |
190 | s32 val; | |
191 | ||
192 | drv201_q_focus_status(sd, &val); | |
193 | ||
194 | if (val & ATOMISP_FOCUS_STATUS_MOVING) | |
195 | *value = drv201_dev.focus - drv201_dev.number_of_steps; | |
196 | else | |
197 | *value = drv201_dev.focus; | |
198 | ||
199 | return 0; | |
200 | } | |
201 | ||
202 | int drv201_t_vcm_slew(struct v4l2_subdev *sd, s32 value) | |
203 | { | |
204 | return 0; | |
205 | } | |
206 | ||
207 | int drv201_t_vcm_timing(struct v4l2_subdev *sd, s32 value) | |
208 | { | |
209 | return 0; | |
210 | } |