1 #include <linux/bitops.h>
2 #include <linux/device.h>
3 #include <linux/delay.h>
4 #include <linux/errno.h>
6 #include <linux/gpio.h>
7 #include <linux/init.h>
10 #include <linux/kernel.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>
22 static struct dw9714_device dw9714_dev
;
23 static int dw9714_i2c_write(struct i2c_client
*client
, u16 data
)
26 const int num_msg
= 1;
30 val
= cpu_to_be16(data
);
31 msg
.addr
= DW9714_VCM_ADDR
;
33 msg
.len
= DW9714_16BIT
;
36 ret
= i2c_transfer(client
->adapter
, &msg
, 1);
38 return ret
== num_msg
? 0 : -EIO
;
41 int dw9714_vcm_power_up(struct v4l2_subdev
*sd
)
46 ret
= dw9714_dev
.platform_data
->power_ctrl(sd
, 1);
47 /* waiting time requested by DW9714A(vcm) */
48 usleep_range(12000, 12500);
52 int dw9714_vcm_power_down(struct v4l2_subdev
*sd
)
54 return dw9714_dev
.platform_data
->power_ctrl(sd
, 0);
58 static int dw9714_t_focus_vcm(struct v4l2_subdev
*sd
, u16 val
)
60 struct i2c_client
*client
= v4l2_get_subdevdata(sd
);
62 u8 mclk
= vcm_step_mclk(dw9714_dev
.vcm_settings
.step_setting
);
63 u8 s
= vcm_step_s(dw9714_dev
.vcm_settings
.step_setting
);
66 * For different mode, VCM_PROTECTION_OFF/ON required by the
67 * control procedure. For DW9714_DIRECT/DLC mode, slew value is
70 switch (dw9714_dev
.vcm_mode
) {
72 if (dw9714_dev
.vcm_settings
.update
) {
73 ret
= dw9714_i2c_write(client
, VCM_PROTECTION_OFF
);
76 ret
= dw9714_i2c_write(client
, DIRECT_VCM
);
79 ret
= dw9714_i2c_write(client
, VCM_PROTECTION_ON
);
82 dw9714_dev
.vcm_settings
.update
= false;
84 ret
= dw9714_i2c_write(client
,
85 vcm_val(val
, VCM_DEFAULT_S
));
88 if (dw9714_dev
.vcm_settings
.update
) {
89 ret
= dw9714_i2c_write(client
, VCM_PROTECTION_OFF
);
92 ret
= dw9714_i2c_write(client
,
93 vcm_dlc_mclk(DLC_DISABLE
, mclk
));
96 ret
= dw9714_i2c_write(client
,
97 vcm_tsrc(dw9714_dev
.vcm_settings
.t_src
));
100 ret
= dw9714_i2c_write(client
, VCM_PROTECTION_ON
);
103 dw9714_dev
.vcm_settings
.update
= false;
105 ret
= dw9714_i2c_write(client
, vcm_val(val
, s
));
108 if (dw9714_dev
.vcm_settings
.update
) {
109 ret
= dw9714_i2c_write(client
, VCM_PROTECTION_OFF
);
112 ret
= dw9714_i2c_write(client
,
113 vcm_dlc_mclk(DLC_ENABLE
, mclk
));
116 ret
= dw9714_i2c_write(client
,
117 vcm_tsrc(dw9714_dev
.vcm_settings
.t_src
));
120 ret
= dw9714_i2c_write(client
, VCM_PROTECTION_ON
);
123 dw9714_dev
.vcm_settings
.update
= false;
125 ret
= dw9714_i2c_write(client
,
126 vcm_val(val
, VCM_DEFAULT_S
));
132 int dw9714_t_focus_abs(struct v4l2_subdev
*sd
, s32 value
)
136 value
= clamp(value
, 0, DW9714_MAX_FOCUS_POS
);
137 ret
= dw9714_t_focus_vcm(sd
, value
);
139 dw9714_dev
.number_of_steps
= value
- dw9714_dev
.focus
;
140 dw9714_dev
.focus
= value
;
141 getnstimeofday(&(dw9714_dev
.timestamp_t_focus_abs
));
147 int dw9714_t_focus_abs_init(struct v4l2_subdev
*sd
)
151 ret
= dw9714_t_focus_vcm(sd
, DW9714_DEFAULT_FOCUS_POS
);
153 dw9714_dev
.number_of_steps
=
154 DW9714_DEFAULT_FOCUS_POS
- dw9714_dev
.focus
;
155 dw9714_dev
.focus
= DW9714_DEFAULT_FOCUS_POS
;
156 getnstimeofday(&(dw9714_dev
.timestamp_t_focus_abs
));
162 int dw9714_t_focus_rel(struct v4l2_subdev
*sd
, s32 value
)
165 return dw9714_t_focus_abs(sd
, dw9714_dev
.focus
+ value
);
168 int dw9714_q_focus_status(struct v4l2_subdev
*sd
, s32
*value
)
171 struct timespec temptime
;
172 const struct timespec timedelay
= {
174 min_t(u32
, abs(dw9714_dev
.number_of_steps
)*DELAY_PER_STEP_NS
,
175 DELAY_MAX_PER_STEP_NS
),
178 ktime_get_ts(&temptime
);
180 temptime
= timespec_sub(temptime
, (dw9714_dev
.timestamp_t_focus_abs
));
182 if (timespec_compare(&temptime
, &timedelay
) <= 0) {
183 status
|= ATOMISP_FOCUS_STATUS_MOVING
;
184 status
|= ATOMISP_FOCUS_HP_IN_PROGRESS
;
186 status
|= ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE
;
187 status
|= ATOMISP_FOCUS_HP_COMPLETE
;
194 int dw9714_q_focus_abs(struct v4l2_subdev
*sd
, s32
*value
)
198 dw9714_q_focus_status(sd
, &val
);
200 if (val
& ATOMISP_FOCUS_STATUS_MOVING
)
201 *value
= dw9714_dev
.focus
- dw9714_dev
.number_of_steps
;
203 *value
= dw9714_dev
.focus
;
208 int dw9714_t_vcm_slew(struct v4l2_subdev
*sd
, s32 value
)
210 dw9714_dev
.vcm_settings
.step_setting
= value
;
211 dw9714_dev
.vcm_settings
.update
= true;
216 int dw9714_t_vcm_timing(struct v4l2_subdev
*sd
, s32 value
)
218 dw9714_dev
.vcm_settings
.t_src
= value
;
219 dw9714_dev
.vcm_settings
.update
= true;