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