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