]> git.ipfire.org Git - people/arne_f/kernel.git/blame - drivers/staging/media/atomisp/i2c/imx/drv201.c
License cleanup: add SPDX GPL-2.0 license identifier to files with no license
[people/arne_f/kernel.git] / drivers / staging / media / atomisp / i2c / imx / drv201.c
CommitLineData
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
24static struct drv201_device drv201_dev;
25
26static 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
49static 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
64static 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
80int 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;
121fail_powerdown:
122 drv201_dev.platform_data->power_ctrl(sd, 0);
123 return ret;
124}
125
126int drv201_vcm_power_down(struct v4l2_subdev *sd)
127{
128 return drv201_dev.platform_data->power_ctrl(sd, 0);
129}
130
131
4a3039e2 132static 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
142int 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
157int drv201_t_focus_rel(struct v4l2_subdev *sd, s32 value)
158{
159 return drv201_t_focus_abs(sd, drv201_dev.focus + value);
160}
161
162int 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
188int 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
202int drv201_t_vcm_slew(struct v4l2_subdev *sd, s32 value)
203{
204 return 0;
205}
206
207int drv201_t_vcm_timing(struct v4l2_subdev *sd, s32 value)
208{
209 return 0;
210}