root/drivers/media/i2c/ad5820.c

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

DEFINITIONS

This source file includes following definitions.
  1. ad5820_write
  2. ad5820_update_hw
  3. ad5820_power_off
  4. ad5820_power_on
  5. ad5820_set_ctrl
  6. ad5820_init_controls
  7. ad5820_registered
  8. ad5820_set_power
  9. ad5820_open
  10. ad5820_close
  11. ad5820_suspend
  12. ad5820_resume
  13. ad5820_probe
  14. ad5820_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * drivers/media/i2c/ad5820.c
   4  *
   5  * AD5820 DAC driver for camera voice coil focus.
   6  *
   7  * Copyright (C) 2008 Nokia Corporation
   8  * Copyright (C) 2007 Texas Instruments
   9  * Copyright (C) 2016 Pavel Machek <pavel@ucw.cz>
  10  *
  11  * Contact: Tuukka Toivonen <tuukkat76@gmail.com>
  12  *          Sakari Ailus <sakari.ailus@iki.fi>
  13  *
  14  * Based on af_d88.c by Texas Instruments.
  15  */
  16 
  17 #include <linux/errno.h>
  18 #include <linux/i2c.h>
  19 #include <linux/kernel.h>
  20 #include <linux/module.h>
  21 #include <linux/regulator/consumer.h>
  22 
  23 #include <media/v4l2-ctrls.h>
  24 #include <media/v4l2-device.h>
  25 #include <media/v4l2-subdev.h>
  26 
  27 #define AD5820_NAME             "ad5820"
  28 
  29 /* Register definitions */
  30 #define AD5820_POWER_DOWN               (1 << 15)
  31 #define AD5820_DAC_SHIFT                4
  32 #define AD5820_RAMP_MODE_LINEAR         (0 << 3)
  33 #define AD5820_RAMP_MODE_64_16          (1 << 3)
  34 
  35 #define CODE_TO_RAMP_US(s)      ((s) == 0 ? 0 : (1 << ((s) - 1)) * 50)
  36 #define RAMP_US_TO_CODE(c)      fls(((c) + ((c)>>1)) / 50)
  37 
  38 #define to_ad5820_device(sd)    container_of(sd, struct ad5820_device, subdev)
  39 
  40 struct ad5820_device {
  41         struct v4l2_subdev subdev;
  42         struct ad5820_platform_data *platform_data;
  43         struct regulator *vana;
  44 
  45         struct v4l2_ctrl_handler ctrls;
  46         u32 focus_absolute;
  47         u32 focus_ramp_time;
  48         u32 focus_ramp_mode;
  49 
  50         struct mutex power_lock;
  51         int power_count;
  52 
  53         bool standby;
  54 };
  55 
  56 static int ad5820_write(struct ad5820_device *coil, u16 data)
  57 {
  58         struct i2c_client *client = v4l2_get_subdevdata(&coil->subdev);
  59         struct i2c_msg msg;
  60         __be16 be_data;
  61         int r;
  62 
  63         if (!client->adapter)
  64                 return -ENODEV;
  65 
  66         be_data = cpu_to_be16(data);
  67         msg.addr  = client->addr;
  68         msg.flags = 0;
  69         msg.len   = 2;
  70         msg.buf   = (u8 *)&be_data;
  71 
  72         r = i2c_transfer(client->adapter, &msg, 1);
  73         if (r < 0) {
  74                 dev_err(&client->dev, "write failed, error %d\n", r);
  75                 return r;
  76         }
  77 
  78         return 0;
  79 }
  80 
  81 /*
  82  * Calculate status word and write it to the device based on current
  83  * values of V4L2 controls. It is assumed that the stored V4L2 control
  84  * values are properly limited and rounded.
  85  */
  86 static int ad5820_update_hw(struct ad5820_device *coil)
  87 {
  88         u16 status;
  89 
  90         status = RAMP_US_TO_CODE(coil->focus_ramp_time);
  91         status |= coil->focus_ramp_mode
  92                 ? AD5820_RAMP_MODE_64_16 : AD5820_RAMP_MODE_LINEAR;
  93         status |= coil->focus_absolute << AD5820_DAC_SHIFT;
  94 
  95         if (coil->standby)
  96                 status |= AD5820_POWER_DOWN;
  97 
  98         return ad5820_write(coil, status);
  99 }
 100 
 101 /*
 102  * Power handling
 103  */
 104 static int ad5820_power_off(struct ad5820_device *coil, bool standby)
 105 {
 106         int ret = 0, ret2;
 107 
 108         /*
 109          * Go to standby first as real power off my be denied by the hardware
 110          * (single power line control for both coil and sensor).
 111          */
 112         if (standby) {
 113                 coil->standby = true;
 114                 ret = ad5820_update_hw(coil);
 115         }
 116 
 117         ret2 = regulator_disable(coil->vana);
 118         if (ret)
 119                 return ret;
 120         return ret2;
 121 }
 122 
 123 static int ad5820_power_on(struct ad5820_device *coil, bool restore)
 124 {
 125         int ret;
 126 
 127         ret = regulator_enable(coil->vana);
 128         if (ret < 0)
 129                 return ret;
 130 
 131         if (restore) {
 132                 /* Restore the hardware settings. */
 133                 coil->standby = false;
 134                 ret = ad5820_update_hw(coil);
 135                 if (ret)
 136                         goto fail;
 137         }
 138         return 0;
 139 
 140 fail:
 141         coil->standby = true;
 142         regulator_disable(coil->vana);
 143 
 144         return ret;
 145 }
 146 
 147 /*
 148  * V4L2 controls
 149  */
 150 static int ad5820_set_ctrl(struct v4l2_ctrl *ctrl)
 151 {
 152         struct ad5820_device *coil =
 153                 container_of(ctrl->handler, struct ad5820_device, ctrls);
 154 
 155         switch (ctrl->id) {
 156         case V4L2_CID_FOCUS_ABSOLUTE:
 157                 coil->focus_absolute = ctrl->val;
 158                 return ad5820_update_hw(coil);
 159         }
 160 
 161         return 0;
 162 }
 163 
 164 static const struct v4l2_ctrl_ops ad5820_ctrl_ops = {
 165         .s_ctrl = ad5820_set_ctrl,
 166 };
 167 
 168 
 169 static int ad5820_init_controls(struct ad5820_device *coil)
 170 {
 171         v4l2_ctrl_handler_init(&coil->ctrls, 1);
 172 
 173         /*
 174          * V4L2_CID_FOCUS_ABSOLUTE
 175          *
 176          * Minimum current is 0 mA, maximum is 100 mA. Thus, 1 code is
 177          * equivalent to 100/1023 = 0.0978 mA. Nevertheless, we do not use [mA]
 178          * for focus position, because it is meaningless for user. Meaningful
 179          * would be to use focus distance or even its inverse, but since the
 180          * driver doesn't have sufficiently knowledge to do the conversion, we
 181          * will just use abstract codes here. In any case, smaller value = focus
 182          * position farther from camera. The default zero value means focus at
 183          * infinity, and also least current consumption.
 184          */
 185         v4l2_ctrl_new_std(&coil->ctrls, &ad5820_ctrl_ops,
 186                           V4L2_CID_FOCUS_ABSOLUTE, 0, 1023, 1, 0);
 187 
 188         if (coil->ctrls.error)
 189                 return coil->ctrls.error;
 190 
 191         coil->focus_absolute = 0;
 192         coil->focus_ramp_time = 0;
 193         coil->focus_ramp_mode = 0;
 194 
 195         coil->subdev.ctrl_handler = &coil->ctrls;
 196 
 197         return 0;
 198 }
 199 
 200 /*
 201  * V4L2 subdev operations
 202  */
 203 static int ad5820_registered(struct v4l2_subdev *subdev)
 204 {
 205         struct ad5820_device *coil = to_ad5820_device(subdev);
 206 
 207         return ad5820_init_controls(coil);
 208 }
 209 
 210 static int
 211 ad5820_set_power(struct v4l2_subdev *subdev, int on)
 212 {
 213         struct ad5820_device *coil = to_ad5820_device(subdev);
 214         int ret = 0;
 215 
 216         mutex_lock(&coil->power_lock);
 217 
 218         /*
 219          * If the power count is modified from 0 to != 0 or from != 0 to 0,
 220          * update the power state.
 221          */
 222         if (coil->power_count == !on) {
 223                 ret = on ? ad5820_power_on(coil, true) :
 224                         ad5820_power_off(coil, true);
 225                 if (ret < 0)
 226                         goto done;
 227         }
 228 
 229         /* Update the power count. */
 230         coil->power_count += on ? 1 : -1;
 231         WARN_ON(coil->power_count < 0);
 232 
 233 done:
 234         mutex_unlock(&coil->power_lock);
 235         return ret;
 236 }
 237 
 238 static int ad5820_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 239 {
 240         return ad5820_set_power(sd, 1);
 241 }
 242 
 243 static int ad5820_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 244 {
 245         return ad5820_set_power(sd, 0);
 246 }
 247 
 248 static const struct v4l2_subdev_core_ops ad5820_core_ops = {
 249         .s_power = ad5820_set_power,
 250 };
 251 
 252 static const struct v4l2_subdev_ops ad5820_ops = {
 253         .core = &ad5820_core_ops,
 254 };
 255 
 256 static const struct v4l2_subdev_internal_ops ad5820_internal_ops = {
 257         .registered = ad5820_registered,
 258         .open = ad5820_open,
 259         .close = ad5820_close,
 260 };
 261 
 262 /*
 263  * I2C driver
 264  */
 265 static int __maybe_unused ad5820_suspend(struct device *dev)
 266 {
 267         struct i2c_client *client = container_of(dev, struct i2c_client, dev);
 268         struct v4l2_subdev *subdev = i2c_get_clientdata(client);
 269         struct ad5820_device *coil = to_ad5820_device(subdev);
 270 
 271         if (!coil->power_count)
 272                 return 0;
 273 
 274         return ad5820_power_off(coil, false);
 275 }
 276 
 277 static int __maybe_unused ad5820_resume(struct device *dev)
 278 {
 279         struct i2c_client *client = container_of(dev, struct i2c_client, dev);
 280         struct v4l2_subdev *subdev = i2c_get_clientdata(client);
 281         struct ad5820_device *coil = to_ad5820_device(subdev);
 282 
 283         if (!coil->power_count)
 284                 return 0;
 285 
 286         return ad5820_power_on(coil, true);
 287 }
 288 
 289 static int ad5820_probe(struct i2c_client *client,
 290                         const struct i2c_device_id *devid)
 291 {
 292         struct ad5820_device *coil;
 293         int ret;
 294 
 295         coil = devm_kzalloc(&client->dev, sizeof(*coil), GFP_KERNEL);
 296         if (!coil)
 297                 return -ENOMEM;
 298 
 299         coil->vana = devm_regulator_get(&client->dev, "VANA");
 300         if (IS_ERR(coil->vana)) {
 301                 ret = PTR_ERR(coil->vana);
 302                 if (ret != -EPROBE_DEFER)
 303                         dev_err(&client->dev, "could not get regulator for vana\n");
 304                 return ret;
 305         }
 306 
 307         mutex_init(&coil->power_lock);
 308 
 309         v4l2_i2c_subdev_init(&coil->subdev, client, &ad5820_ops);
 310         coil->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 311         coil->subdev.internal_ops = &ad5820_internal_ops;
 312         coil->subdev.entity.function = MEDIA_ENT_F_LENS;
 313         strscpy(coil->subdev.name, "ad5820 focus", sizeof(coil->subdev.name));
 314 
 315         ret = media_entity_pads_init(&coil->subdev.entity, 0, NULL);
 316         if (ret < 0)
 317                 goto cleanup2;
 318 
 319         ret = v4l2_async_register_subdev(&coil->subdev);
 320         if (ret < 0)
 321                 goto cleanup;
 322 
 323         return ret;
 324 
 325 cleanup2:
 326         mutex_destroy(&coil->power_lock);
 327 cleanup:
 328         media_entity_cleanup(&coil->subdev.entity);
 329         return ret;
 330 }
 331 
 332 static int ad5820_remove(struct i2c_client *client)
 333 {
 334         struct v4l2_subdev *subdev = i2c_get_clientdata(client);
 335         struct ad5820_device *coil = to_ad5820_device(subdev);
 336 
 337         v4l2_async_unregister_subdev(&coil->subdev);
 338         v4l2_ctrl_handler_free(&coil->ctrls);
 339         media_entity_cleanup(&coil->subdev.entity);
 340         mutex_destroy(&coil->power_lock);
 341         return 0;
 342 }
 343 
 344 static const struct i2c_device_id ad5820_id_table[] = {
 345         { AD5820_NAME, 0 },
 346         { }
 347 };
 348 MODULE_DEVICE_TABLE(i2c, ad5820_id_table);
 349 
 350 static SIMPLE_DEV_PM_OPS(ad5820_pm, ad5820_suspend, ad5820_resume);
 351 
 352 static struct i2c_driver ad5820_i2c_driver = {
 353         .driver         = {
 354                 .name   = AD5820_NAME,
 355                 .pm     = &ad5820_pm,
 356         },
 357         .probe          = ad5820_probe,
 358         .remove         = ad5820_remove,
 359         .id_table       = ad5820_id_table,
 360 };
 361 
 362 module_i2c_driver(ad5820_i2c_driver);
 363 
 364 MODULE_AUTHOR("Tuukka Toivonen");
 365 MODULE_DESCRIPTION("AD5820 camera lens driver");
 366 MODULE_LICENSE("GPL");

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