2 * Support for dw9719 vcm driver.
4 * Copyright (c) 2012 Intel Corporation. All Rights Reserved.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 #include <linux/delay.h>
25 static struct dw9719_device dw9719_dev;
27 static int dw9719_i2c_rd8(struct i2c_client *client, u8 reg, u8 *val)
29 struct i2c_msg msg[2];
32 msg[0].addr = DW9719_VCM_ADDR;
37 msg[1].addr = DW9719_VCM_ADDR;
38 msg[1].flags = I2C_M_RD;
43 if (i2c_transfer(client->adapter, msg, 2) != 2)
50 static int dw9719_i2c_wr8(struct i2c_client *client, u8 reg, u8 val)
53 u8 buf[2] = { reg, val };
55 msg.addr = DW9719_VCM_ADDR;
57 msg.len = sizeof(buf);
60 if (i2c_transfer(client->adapter, &msg, 1) != 1)
66 static int dw9719_i2c_wr16(struct i2c_client *client, u8 reg, u16 val)
69 u8 buf[3] = { reg, (u8)(val >> 8), (u8)(val & 0xff)};
71 msg.addr = DW9719_VCM_ADDR;
73 msg.len = sizeof(buf);
76 if (i2c_transfer(client->adapter, &msg, 1) != 1)
82 int dw9719_vcm_power_up(struct v4l2_subdev *sd)
84 struct i2c_client *client = v4l2_get_subdevdata(sd);
89 ret = dw9719_dev.platform_data->power_ctrl(sd, 1);
90 /* waiting time requested by DW9714A(vcm) */
93 /* Wait for VBAT to stabilize */
97 * Jiggle SCL pin to wake up device.
99 ret = dw9719_i2c_wr8(client, DW9719_CONTROL, 1);
100 /* Need 100us to transit from SHUTDOWN to STANDBY*/
101 usleep_range(100, 1000);
103 /* Enable the ringing compensation */
104 ret = dw9719_i2c_wr8(client, DW9719_CONTROL, DW9719_ENABLE_RINGING);
109 ret = dw9719_i2c_wr8(client, DW9719_MODE, DW9719_MODE_SAC3);
113 /* Set the resonance frequency */
114 ret = dw9719_i2c_wr8(client, DW9719_VCM_FREQ, DW9719_DEFAULT_VCM_FREQ);
119 ret = dw9719_i2c_rd8(client, DW9719_INFO, &value);
122 if (value != DW9719_ID) {
126 dw9719_dev.focus = 0;
127 dw9719_dev.initialized = true;
132 dw9719_dev.platform_data->power_ctrl(sd, 0);
136 int dw9719_vcm_power_down(struct v4l2_subdev *sd)
138 return dw9719_dev.platform_data->power_ctrl(sd, 0);
141 int dw9719_q_focus_status(struct v4l2_subdev *sd, s32 *value)
143 static const struct timespec move_time = {
148 struct timespec current_time, finish_time, delta_time;
150 getnstimeofday(¤t_time);
151 finish_time = timespec_add(dw9719_dev.focus_time, move_time);
152 delta_time = timespec_sub(current_time, finish_time);
153 if (delta_time.tv_sec >= 0 && delta_time.tv_nsec >= 0) {
154 *value = ATOMISP_FOCUS_HP_COMPLETE |
155 ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE;
157 *value = ATOMISP_FOCUS_STATUS_MOVING |
158 ATOMISP_FOCUS_HP_IN_PROGRESS;
164 int dw9719_t_focus_abs(struct v4l2_subdev *sd, s32 value)
166 struct i2c_client *client = v4l2_get_subdevdata(sd);
169 value = clamp(value, 0, DW9719_MAX_FOCUS_POS);
170 ret = dw9719_i2c_wr16(client, DW9719_VCM_CURRENT, value);
174 getnstimeofday(&dw9719_dev.focus_time);
175 dw9719_dev.focus = value;
180 int dw9719_t_focus_rel(struct v4l2_subdev *sd, s32 value)
182 return dw9719_t_focus_abs(sd, dw9719_dev.focus + value);
185 int dw9719_q_focus_abs(struct v4l2_subdev *sd, s32 *value)
187 *value = dw9719_dev.focus;
190 int dw9719_t_vcm_slew(struct v4l2_subdev *sd, s32 value)
195 int dw9719_t_vcm_timing(struct v4l2_subdev *sd, s32 value)