GNU Linux-libre 4.14.290-gnu1
[releases.git] / drivers / staging / media / atomisp / i2c / imx / drv201.c
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>
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
132 static int drv201_t_focus_vcm(struct v4l2_subdev *sd, u16 val)
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 }