]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/staging/media/atomisp/i2c/imx/drv201.c
media: staging: atomisp: Convert timers to use timer_setup()
[mirror_ubuntu-bionic-kernel.git] / drivers / staging / media / atomisp / i2c / imx / drv201.c
CommitLineData
a49d2536
AC
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>
a49d2536
AC
19
20#include "drv201.h"
21
22static struct drv201_device drv201_dev;
23
24static int drv201_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 = DRV201_VCM_ADDR;
32 msg[0].flags = 0;
33 msg[0].len = 1;
34 msg[0].buf = &buf[0];
35
36 msg[1].addr = DRV201_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
47static int drv201_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 = DRV201_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
62static int drv201_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 = DRV201_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
78int drv201_vcm_power_up(struct v4l2_subdev *sd)
79{
80 struct i2c_client *client = v4l2_get_subdevdata(sd);
81 int ret;
82 u8 value;
83
84 /* Enable power */
85 ret = drv201_dev.platform_data->power_ctrl(sd, 1);
86 if (ret)
87 return ret;
88 /* Wait for VBAT to stabilize */
89 udelay(1);
90 /*
91 * Jiggle SCL pin to wake up device.
92 * Drv201 expect SCL from low to high to wake device up.
93 * So the 1st access to i2c would fail.
94 * Using following function to wake device up.
95 */
96 drv201_i2c_wr8(client, DRV201_CONTROL, DRV201_RESET);
97
98 /* Need 100us to transit from SHUTDOWN to STANDBY*/
99 usleep_range(WAKEUP_DELAY_US, WAKEUP_DELAY_US * 10);
100
101 /* Reset device */
102 ret = drv201_i2c_wr8(client, DRV201_CONTROL, DRV201_RESET);
103 if (ret < 0)
104 goto fail_powerdown;
105
106 /* Detect device */
107 ret = drv201_i2c_rd8(client, DRV201_CONTROL, &value);
108 if (ret < 0)
109 goto fail_powerdown;
110 if (value != DEFAULT_CONTROL_VAL) {
111 ret = -ENXIO;
112 goto fail_powerdown;
113 }
114
115 drv201_dev.focus = DRV201_MAX_FOCUS_POS;
116 drv201_dev.initialized = true;
117
118 return 0;
119fail_powerdown:
120 drv201_dev.platform_data->power_ctrl(sd, 0);
121 return ret;
122}
123
124int drv201_vcm_power_down(struct v4l2_subdev *sd)
125{
126 return drv201_dev.platform_data->power_ctrl(sd, 0);
127}
128
129
4a3039e2 130static int drv201_t_focus_vcm(struct v4l2_subdev *sd, u16 val)
a49d2536
AC
131{
132 struct i2c_client *client = v4l2_get_subdevdata(sd);
133 u16 data = val & VCM_CODE_MASK;
134
135 if (!drv201_dev.initialized)
136 return -ENODEV;
137 return drv201_i2c_wr16(client, DRV201_VCM_CURRENT, data);
138}
139
140int drv201_t_focus_abs(struct v4l2_subdev *sd, s32 value)
141{
142 int ret;
143
144 value = clamp(value, 0, DRV201_MAX_FOCUS_POS);
145 ret = drv201_t_focus_vcm(sd, value);
146 if (ret == 0) {
147 drv201_dev.number_of_steps = value - drv201_dev.focus;
148 drv201_dev.focus = value;
149 getnstimeofday(&(drv201_dev.timestamp_t_focus_abs));
150 }
151
152 return ret;
153}
154
155int drv201_t_focus_rel(struct v4l2_subdev *sd, s32 value)
156{
157 return drv201_t_focus_abs(sd, drv201_dev.focus + value);
158}
159
160int drv201_q_focus_status(struct v4l2_subdev *sd, s32 *value)
161{
162 u32 status = 0;
163 struct timespec temptime;
164 const struct timespec timedelay = {
165 0,
166 min_t(u32, abs(drv201_dev.number_of_steps)*DELAY_PER_STEP_NS,
167 DELAY_MAX_PER_STEP_NS),
168 };
169
170 ktime_get_ts(&temptime);
171
172 temptime = timespec_sub(temptime, (drv201_dev.timestamp_t_focus_abs));
173
174 if (timespec_compare(&temptime, &timedelay) <= 0) {
175 status |= ATOMISP_FOCUS_STATUS_MOVING;
176 status |= ATOMISP_FOCUS_HP_IN_PROGRESS;
177 } else {
178 status |= ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE;
179 status |= ATOMISP_FOCUS_HP_COMPLETE;
180 }
181 *value = status;
182
183 return 0;
184}
185
186int drv201_q_focus_abs(struct v4l2_subdev *sd, s32 *value)
187{
188 s32 val;
189
190 drv201_q_focus_status(sd, &val);
191
192 if (val & ATOMISP_FOCUS_STATUS_MOVING)
193 *value = drv201_dev.focus - drv201_dev.number_of_steps;
194 else
195 *value = drv201_dev.focus;
196
197 return 0;
198}
199
200int drv201_t_vcm_slew(struct v4l2_subdev *sd, s32 value)
201{
202 return 0;
203}
204
205int drv201_t_vcm_timing(struct v4l2_subdev *sd, s32 value)
206{
207 return 0;
208}