root/drivers/media/i2c/dw9807-vcm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sd_to_dw9807_vcm
  2. dw9807_i2c_check
  3. dw9807_set_dac
  4. dw9807_set_ctrl
  5. dw9807_open
  6. dw9807_close
  7. dw9807_subdev_cleanup
  8. dw9807_init_controls
  9. dw9807_probe
  10. dw9807_remove
  11. dw9807_vcm_suspend
  12. dw9807_vcm_resume

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

/* [<][>][^][v][top][bottom][index][help] */