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