xref: /OK3568_Linux_fs/kernel/drivers/media/i2c/dw9807-vcm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun // Copyright (C) 2018 Intel Corporation
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun #include <linux/acpi.h>
5*4882a593Smuzhiyun #include <linux/delay.h>
6*4882a593Smuzhiyun #include <linux/i2c.h>
7*4882a593Smuzhiyun #include <linux/iopoll.h>
8*4882a593Smuzhiyun #include <linux/module.h>
9*4882a593Smuzhiyun #include <linux/pm_runtime.h>
10*4882a593Smuzhiyun #include <media/v4l2-ctrls.h>
11*4882a593Smuzhiyun #include <media/v4l2-device.h>
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #define DW9807_MAX_FOCUS_POS	1023
14*4882a593Smuzhiyun /*
15*4882a593Smuzhiyun  * This sets the minimum granularity for the focus positions.
16*4882a593Smuzhiyun  * A value of 1 gives maximum accuracy for a desired focus position.
17*4882a593Smuzhiyun  */
18*4882a593Smuzhiyun #define DW9807_FOCUS_STEPS	1
19*4882a593Smuzhiyun /*
20*4882a593Smuzhiyun  * This acts as the minimum granularity of lens movement.
21*4882a593Smuzhiyun  * Keep this value power of 2, so the control steps can be
22*4882a593Smuzhiyun  * uniformly adjusted for gradual lens movement, with desired
23*4882a593Smuzhiyun  * number of control steps.
24*4882a593Smuzhiyun  */
25*4882a593Smuzhiyun #define DW9807_CTRL_STEPS	16
26*4882a593Smuzhiyun #define DW9807_CTRL_DELAY_US	1000
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #define DW9807_CTL_ADDR		0x02
29*4882a593Smuzhiyun /*
30*4882a593Smuzhiyun  * DW9807 separates two registers to control the VCM position.
31*4882a593Smuzhiyun  * One for MSB value, another is LSB value.
32*4882a593Smuzhiyun  */
33*4882a593Smuzhiyun #define DW9807_MSB_ADDR		0x03
34*4882a593Smuzhiyun #define DW9807_LSB_ADDR		0x04
35*4882a593Smuzhiyun #define DW9807_STATUS_ADDR	0x05
36*4882a593Smuzhiyun #define DW9807_MODE_ADDR	0x06
37*4882a593Smuzhiyun #define DW9807_RESONANCE_ADDR	0x07
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #define MAX_RETRY		10
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun struct dw9807_device {
42*4882a593Smuzhiyun 	struct v4l2_ctrl_handler ctrls_vcm;
43*4882a593Smuzhiyun 	struct v4l2_subdev sd;
44*4882a593Smuzhiyun 	u16 current_val;
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun 
sd_to_dw9807_vcm(struct v4l2_subdev * subdev)47*4882a593Smuzhiyun static inline struct dw9807_device *sd_to_dw9807_vcm(
48*4882a593Smuzhiyun 					struct v4l2_subdev *subdev)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun 	return container_of(subdev, struct dw9807_device, sd);
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun 
dw9807_i2c_check(struct i2c_client * client)53*4882a593Smuzhiyun static int dw9807_i2c_check(struct i2c_client *client)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun 	const char status_addr = DW9807_STATUS_ADDR;
56*4882a593Smuzhiyun 	char status_result;
57*4882a593Smuzhiyun 	int ret;
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	ret = i2c_master_send(client, &status_addr, sizeof(status_addr));
60*4882a593Smuzhiyun 	if (ret < 0) {
61*4882a593Smuzhiyun 		dev_err(&client->dev, "I2C write STATUS address fail ret = %d\n",
62*4882a593Smuzhiyun 			ret);
63*4882a593Smuzhiyun 		return ret;
64*4882a593Smuzhiyun 	}
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	ret = i2c_master_recv(client, &status_result, sizeof(status_result));
67*4882a593Smuzhiyun 	if (ret < 0) {
68*4882a593Smuzhiyun 		dev_err(&client->dev, "I2C read STATUS value fail ret = %d\n",
69*4882a593Smuzhiyun 			ret);
70*4882a593Smuzhiyun 		return ret;
71*4882a593Smuzhiyun 	}
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	return status_result;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun 
dw9807_set_dac(struct i2c_client * client,u16 data)76*4882a593Smuzhiyun static int dw9807_set_dac(struct i2c_client *client, u16 data)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun 	const char tx_data[3] = {
79*4882a593Smuzhiyun 		DW9807_MSB_ADDR, ((data >> 8) & 0x03), (data & 0xff)
80*4882a593Smuzhiyun 	};
81*4882a593Smuzhiyun 	int val, ret;
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	/*
84*4882a593Smuzhiyun 	 * According to the datasheet, need to check the bus status before we
85*4882a593Smuzhiyun 	 * write VCM position. This ensure that we really write the value
86*4882a593Smuzhiyun 	 * into the register
87*4882a593Smuzhiyun 	 */
88*4882a593Smuzhiyun 	ret = readx_poll_timeout(dw9807_i2c_check, client, val, val <= 0,
89*4882a593Smuzhiyun 			DW9807_CTRL_DELAY_US, MAX_RETRY * DW9807_CTRL_DELAY_US);
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	if (ret || val < 0) {
92*4882a593Smuzhiyun 		if (ret) {
93*4882a593Smuzhiyun 			dev_warn(&client->dev,
94*4882a593Smuzhiyun 				"Cannot do the write operation because VCM is busy\n");
95*4882a593Smuzhiyun 		}
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 		return ret ? -EBUSY : val;
98*4882a593Smuzhiyun 	}
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	/* Write VCM position to registers */
101*4882a593Smuzhiyun 	ret = i2c_master_send(client, tx_data, sizeof(tx_data));
102*4882a593Smuzhiyun 	if (ret < 0) {
103*4882a593Smuzhiyun 		dev_err(&client->dev,
104*4882a593Smuzhiyun 			"I2C write MSB fail ret=%d\n", ret);
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 		return ret;
107*4882a593Smuzhiyun 	}
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	return 0;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun 
dw9807_set_ctrl(struct v4l2_ctrl * ctrl)112*4882a593Smuzhiyun static int dw9807_set_ctrl(struct v4l2_ctrl *ctrl)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun 	struct dw9807_device *dev_vcm = container_of(ctrl->handler,
115*4882a593Smuzhiyun 		struct dw9807_device, ctrls_vcm);
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) {
118*4882a593Smuzhiyun 		struct i2c_client *client = v4l2_get_subdevdata(&dev_vcm->sd);
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 		dev_vcm->current_val = ctrl->val;
121*4882a593Smuzhiyun 		return dw9807_set_dac(client, ctrl->val);
122*4882a593Smuzhiyun 	}
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	return -EINVAL;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun static const struct v4l2_ctrl_ops dw9807_vcm_ctrl_ops = {
128*4882a593Smuzhiyun 	.s_ctrl = dw9807_set_ctrl,
129*4882a593Smuzhiyun };
130*4882a593Smuzhiyun 
dw9807_open(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh)131*4882a593Smuzhiyun static int dw9807_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	int rval;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	rval = pm_runtime_get_sync(sd->dev);
136*4882a593Smuzhiyun 	if (rval < 0) {
137*4882a593Smuzhiyun 		pm_runtime_put_noidle(sd->dev);
138*4882a593Smuzhiyun 		return rval;
139*4882a593Smuzhiyun 	}
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	return 0;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
dw9807_close(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh)144*4882a593Smuzhiyun static int dw9807_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	pm_runtime_put(sd->dev);
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	return 0;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun static const struct v4l2_subdev_internal_ops dw9807_int_ops = {
152*4882a593Smuzhiyun 	.open = dw9807_open,
153*4882a593Smuzhiyun 	.close = dw9807_close,
154*4882a593Smuzhiyun };
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun static const struct v4l2_subdev_ops dw9807_ops = { };
157*4882a593Smuzhiyun 
dw9807_subdev_cleanup(struct dw9807_device * dw9807_dev)158*4882a593Smuzhiyun static void dw9807_subdev_cleanup(struct dw9807_device *dw9807_dev)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun 	v4l2_async_unregister_subdev(&dw9807_dev->sd);
161*4882a593Smuzhiyun 	v4l2_ctrl_handler_free(&dw9807_dev->ctrls_vcm);
162*4882a593Smuzhiyun 	media_entity_cleanup(&dw9807_dev->sd.entity);
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun 
dw9807_init_controls(struct dw9807_device * dev_vcm)165*4882a593Smuzhiyun static int dw9807_init_controls(struct dw9807_device *dev_vcm)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun 	struct v4l2_ctrl_handler *hdl = &dev_vcm->ctrls_vcm;
168*4882a593Smuzhiyun 	const struct v4l2_ctrl_ops *ops = &dw9807_vcm_ctrl_ops;
169*4882a593Smuzhiyun 	struct i2c_client *client = v4l2_get_subdevdata(&dev_vcm->sd);
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	v4l2_ctrl_handler_init(hdl, 1);
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FOCUS_ABSOLUTE,
174*4882a593Smuzhiyun 			  0, DW9807_MAX_FOCUS_POS, DW9807_FOCUS_STEPS, 0);
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	dev_vcm->sd.ctrl_handler = hdl;
177*4882a593Smuzhiyun 	if (hdl->error) {
178*4882a593Smuzhiyun 		dev_err(&client->dev, "%s fail error: 0x%x\n",
179*4882a593Smuzhiyun 			__func__, hdl->error);
180*4882a593Smuzhiyun 		return hdl->error;
181*4882a593Smuzhiyun 	}
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	return 0;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun 
dw9807_probe(struct i2c_client * client)186*4882a593Smuzhiyun static int dw9807_probe(struct i2c_client *client)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun 	struct dw9807_device *dw9807_dev;
189*4882a593Smuzhiyun 	int rval;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	dw9807_dev = devm_kzalloc(&client->dev, sizeof(*dw9807_dev),
192*4882a593Smuzhiyun 				  GFP_KERNEL);
193*4882a593Smuzhiyun 	if (dw9807_dev == NULL)
194*4882a593Smuzhiyun 		return -ENOMEM;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	v4l2_i2c_subdev_init(&dw9807_dev->sd, client, &dw9807_ops);
197*4882a593Smuzhiyun 	dw9807_dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
198*4882a593Smuzhiyun 	dw9807_dev->sd.internal_ops = &dw9807_int_ops;
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	rval = dw9807_init_controls(dw9807_dev);
201*4882a593Smuzhiyun 	if (rval)
202*4882a593Smuzhiyun 		goto err_cleanup;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	rval = media_entity_pads_init(&dw9807_dev->sd.entity, 0, NULL);
205*4882a593Smuzhiyun 	if (rval < 0)
206*4882a593Smuzhiyun 		goto err_cleanup;
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	dw9807_dev->sd.entity.function = MEDIA_ENT_F_LENS;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	rval = v4l2_async_register_subdev(&dw9807_dev->sd);
211*4882a593Smuzhiyun 	if (rval < 0)
212*4882a593Smuzhiyun 		goto err_cleanup;
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	pm_runtime_set_active(&client->dev);
215*4882a593Smuzhiyun 	pm_runtime_enable(&client->dev);
216*4882a593Smuzhiyun 	pm_runtime_idle(&client->dev);
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	return 0;
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun err_cleanup:
221*4882a593Smuzhiyun 	v4l2_ctrl_handler_free(&dw9807_dev->ctrls_vcm);
222*4882a593Smuzhiyun 	media_entity_cleanup(&dw9807_dev->sd.entity);
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	return rval;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun 
dw9807_remove(struct i2c_client * client)227*4882a593Smuzhiyun static int dw9807_remove(struct i2c_client *client)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
230*4882a593Smuzhiyun 	struct dw9807_device *dw9807_dev = sd_to_dw9807_vcm(sd);
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	pm_runtime_disable(&client->dev);
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	dw9807_subdev_cleanup(dw9807_dev);
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	return 0;
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun /*
240*4882a593Smuzhiyun  * This function sets the vcm position, so it consumes least current
241*4882a593Smuzhiyun  * The lens position is gradually moved in units of DW9807_CTRL_STEPS,
242*4882a593Smuzhiyun  * to make the movements smoothly.
243*4882a593Smuzhiyun  */
dw9807_vcm_suspend(struct device * dev)244*4882a593Smuzhiyun static int __maybe_unused dw9807_vcm_suspend(struct device *dev)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun 	struct i2c_client *client = to_i2c_client(dev);
247*4882a593Smuzhiyun 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
248*4882a593Smuzhiyun 	struct dw9807_device *dw9807_dev = sd_to_dw9807_vcm(sd);
249*4882a593Smuzhiyun 	const char tx_data[2] = { DW9807_CTL_ADDR, 0x01 };
250*4882a593Smuzhiyun 	int ret, val;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	for (val = dw9807_dev->current_val & ~(DW9807_CTRL_STEPS - 1);
253*4882a593Smuzhiyun 	     val >= 0; val -= DW9807_CTRL_STEPS) {
254*4882a593Smuzhiyun 		ret = dw9807_set_dac(client, val);
255*4882a593Smuzhiyun 		if (ret)
256*4882a593Smuzhiyun 			dev_err_once(dev, "%s I2C failure: %d", __func__, ret);
257*4882a593Smuzhiyun 		usleep_range(DW9807_CTRL_DELAY_US, DW9807_CTRL_DELAY_US + 10);
258*4882a593Smuzhiyun 	}
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	/* Power down */
261*4882a593Smuzhiyun 	ret = i2c_master_send(client, tx_data, sizeof(tx_data));
262*4882a593Smuzhiyun 	if (ret < 0) {
263*4882a593Smuzhiyun 		dev_err(&client->dev, "I2C write CTL fail ret = %d\n", ret);
264*4882a593Smuzhiyun 		return ret;
265*4882a593Smuzhiyun 	}
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	return 0;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun /*
271*4882a593Smuzhiyun  * This function sets the vcm position to the value set by the user
272*4882a593Smuzhiyun  * through v4l2_ctrl_ops s_ctrl handler
273*4882a593Smuzhiyun  * The lens position is gradually moved in units of DW9807_CTRL_STEPS,
274*4882a593Smuzhiyun  * to make the movements smoothly.
275*4882a593Smuzhiyun  */
dw9807_vcm_resume(struct device * dev)276*4882a593Smuzhiyun static int  __maybe_unused dw9807_vcm_resume(struct device *dev)
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun 	struct i2c_client *client = to_i2c_client(dev);
279*4882a593Smuzhiyun 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
280*4882a593Smuzhiyun 	struct dw9807_device *dw9807_dev = sd_to_dw9807_vcm(sd);
281*4882a593Smuzhiyun 	const char tx_data[2] = { DW9807_CTL_ADDR, 0x00 };
282*4882a593Smuzhiyun 	int ret, val;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	/* Power on */
285*4882a593Smuzhiyun 	ret = i2c_master_send(client, tx_data, sizeof(tx_data));
286*4882a593Smuzhiyun 	if (ret < 0) {
287*4882a593Smuzhiyun 		dev_err(&client->dev, "I2C write CTL fail ret = %d\n", ret);
288*4882a593Smuzhiyun 		return ret;
289*4882a593Smuzhiyun 	}
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	for (val = dw9807_dev->current_val % DW9807_CTRL_STEPS;
292*4882a593Smuzhiyun 	     val < dw9807_dev->current_val + DW9807_CTRL_STEPS - 1;
293*4882a593Smuzhiyun 	     val += DW9807_CTRL_STEPS) {
294*4882a593Smuzhiyun 		ret = dw9807_set_dac(client, val);
295*4882a593Smuzhiyun 		if (ret)
296*4882a593Smuzhiyun 			dev_err_ratelimited(dev, "%s I2C failure: %d",
297*4882a593Smuzhiyun 						__func__, ret);
298*4882a593Smuzhiyun 		usleep_range(DW9807_CTRL_DELAY_US, DW9807_CTRL_DELAY_US + 10);
299*4882a593Smuzhiyun 	}
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	return 0;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun static const struct of_device_id dw9807_of_table[] = {
305*4882a593Smuzhiyun 	{ .compatible = "dongwoon,dw9807-vcm" },
306*4882a593Smuzhiyun 	{ /* sentinel */ }
307*4882a593Smuzhiyun };
308*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, dw9807_of_table);
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun static const struct dev_pm_ops dw9807_pm_ops = {
311*4882a593Smuzhiyun 	SET_SYSTEM_SLEEP_PM_OPS(dw9807_vcm_suspend, dw9807_vcm_resume)
312*4882a593Smuzhiyun 	SET_RUNTIME_PM_OPS(dw9807_vcm_suspend, dw9807_vcm_resume, NULL)
313*4882a593Smuzhiyun };
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun static struct i2c_driver dw9807_i2c_driver = {
316*4882a593Smuzhiyun 	.driver = {
317*4882a593Smuzhiyun 		.name = "dw9807",
318*4882a593Smuzhiyun 		.pm = &dw9807_pm_ops,
319*4882a593Smuzhiyun 		.of_match_table = dw9807_of_table,
320*4882a593Smuzhiyun 	},
321*4882a593Smuzhiyun 	.probe_new = dw9807_probe,
322*4882a593Smuzhiyun 	.remove = dw9807_remove,
323*4882a593Smuzhiyun };
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun module_i2c_driver(dw9807_i2c_driver);
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun MODULE_AUTHOR("Chiang, Alan");
328*4882a593Smuzhiyun MODULE_DESCRIPTION("DW9807 VCM driver");
329*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
330