root/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c

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

DEFINITIONS

This source file includes following definitions.
  1. lidar_i2c_xfer
  2. lidar_smbus_xfer
  3. lidar_read_byte
  4. lidar_write_control
  5. lidar_write_power
  6. lidar_read_measurement
  7. lidar_get_measurement
  8. lidar_read_raw
  9. lidar_trigger_handler
  10. lidar_probe
  11. lidar_remove
  12. lidar_pm_runtime_suspend
  13. lidar_pm_runtime_resume

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * pulsedlight-lidar-lite-v2.c - Support for PulsedLight LIDAR sensor
   4  *
   5  * Copyright (C) 2015, 2017-2018
   6  * Author: Matt Ranostay <matt.ranostay@konsulko.com>
   7  *
   8  * TODO: interrupt mode, and signal strength reporting
   9  */
  10 
  11 #include <linux/err.h>
  12 #include <linux/init.h>
  13 #include <linux/i2c.h>
  14 #include <linux/delay.h>
  15 #include <linux/module.h>
  16 #include <linux/pm_runtime.h>
  17 #include <linux/iio/iio.h>
  18 #include <linux/iio/sysfs.h>
  19 #include <linux/iio/buffer.h>
  20 #include <linux/iio/trigger.h>
  21 #include <linux/iio/triggered_buffer.h>
  22 #include <linux/iio/trigger_consumer.h>
  23 
  24 #define LIDAR_REG_CONTROL               0x00
  25 #define LIDAR_REG_CONTROL_ACQUIRE       BIT(2)
  26 
  27 #define LIDAR_REG_STATUS                0x01
  28 #define LIDAR_REG_STATUS_INVALID        BIT(3)
  29 #define LIDAR_REG_STATUS_READY          BIT(0)
  30 
  31 #define LIDAR_REG_DATA_HBYTE            0x0f
  32 #define LIDAR_REG_DATA_LBYTE            0x10
  33 #define LIDAR_REG_DATA_WORD_READ        BIT(7)
  34 
  35 #define LIDAR_REG_PWR_CONTROL   0x65
  36 
  37 #define LIDAR_DRV_NAME "lidar"
  38 
  39 struct lidar_data {
  40         struct iio_dev *indio_dev;
  41         struct i2c_client *client;
  42 
  43         int (*xfer)(struct lidar_data *data, u8 reg, u8 *val, int len);
  44         int i2c_enabled;
  45 
  46         u16 buffer[8]; /* 2 byte distance + 8 byte timestamp */
  47 };
  48 
  49 static const struct iio_chan_spec lidar_channels[] = {
  50         {
  51                 .type = IIO_DISTANCE,
  52                 .info_mask_separate =
  53                         BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
  54                 .scan_index = 0,
  55                 .scan_type = {
  56                         .sign = 'u',
  57                         .realbits = 16,
  58                         .storagebits = 16,
  59                 },
  60         },
  61         IIO_CHAN_SOFT_TIMESTAMP(1),
  62 };
  63 
  64 static int lidar_i2c_xfer(struct lidar_data *data, u8 reg, u8 *val, int len)
  65 {
  66         struct i2c_client *client = data->client;
  67         struct i2c_msg msg[2];
  68         int ret;
  69 
  70         msg[0].addr = client->addr;
  71         msg[0].flags = client->flags | I2C_M_STOP;
  72         msg[0].len = 1;
  73         msg[0].buf  = (char *) &reg;
  74 
  75         msg[1].addr = client->addr;
  76         msg[1].flags = client->flags | I2C_M_RD;
  77         msg[1].len = len;
  78         msg[1].buf = (char *) val;
  79 
  80         ret = i2c_transfer(client->adapter, msg, 2);
  81 
  82         return (ret == 2) ? 0 : -EIO;
  83 }
  84 
  85 static int lidar_smbus_xfer(struct lidar_data *data, u8 reg, u8 *val, int len)
  86 {
  87         struct i2c_client *client = data->client;
  88         int ret;
  89 
  90         /*
  91          * Device needs a STOP condition between address write, and data read
  92          * so in turn i2c_smbus_read_byte_data cannot be used
  93          */
  94 
  95         while (len--) {
  96                 ret = i2c_smbus_write_byte(client, reg++);
  97                 if (ret < 0) {
  98                         dev_err(&client->dev, "cannot write addr value");
  99                         return ret;
 100                 }
 101 
 102                 ret = i2c_smbus_read_byte(client);
 103                 if (ret < 0) {
 104                         dev_err(&client->dev, "cannot read data value");
 105                         return ret;
 106                 }
 107 
 108                 *(val++) = ret;
 109         }
 110 
 111         return 0;
 112 }
 113 
 114 static int lidar_read_byte(struct lidar_data *data, u8 reg)
 115 {
 116         int ret;
 117         u8 val;
 118 
 119         ret = data->xfer(data, reg, &val, 1);
 120         if (ret < 0)
 121                 return ret;
 122 
 123         return val;
 124 }
 125 
 126 static inline int lidar_write_control(struct lidar_data *data, int val)
 127 {
 128         return i2c_smbus_write_byte_data(data->client, LIDAR_REG_CONTROL, val);
 129 }
 130 
 131 static inline int lidar_write_power(struct lidar_data *data, int val)
 132 {
 133         return i2c_smbus_write_byte_data(data->client,
 134                                          LIDAR_REG_PWR_CONTROL, val);
 135 }
 136 
 137 static int lidar_read_measurement(struct lidar_data *data, u16 *reg)
 138 {
 139         int ret = data->xfer(data, LIDAR_REG_DATA_HBYTE |
 140                         (data->i2c_enabled ? LIDAR_REG_DATA_WORD_READ : 0),
 141                         (u8 *) reg, 2);
 142 
 143         if (!ret)
 144                 *reg = be16_to_cpu(*reg);
 145 
 146         return ret;
 147 }
 148 
 149 static int lidar_get_measurement(struct lidar_data *data, u16 *reg)
 150 {
 151         struct i2c_client *client = data->client;
 152         int tries = 10;
 153         int ret;
 154 
 155         pm_runtime_get_sync(&client->dev);
 156 
 157         /* start sample */
 158         ret = lidar_write_control(data, LIDAR_REG_CONTROL_ACQUIRE);
 159         if (ret < 0) {
 160                 dev_err(&client->dev, "cannot send start measurement command");
 161                 return ret;
 162         }
 163 
 164         while (tries--) {
 165                 usleep_range(1000, 2000);
 166 
 167                 ret = lidar_read_byte(data, LIDAR_REG_STATUS);
 168                 if (ret < 0)
 169                         break;
 170 
 171                 /* return -EINVAL since laser is likely pointed out of range */
 172                 if (ret & LIDAR_REG_STATUS_INVALID) {
 173                         *reg = 0;
 174                         ret = -EINVAL;
 175                         break;
 176                 }
 177 
 178                 /* sample ready to read */
 179                 if (!(ret & LIDAR_REG_STATUS_READY)) {
 180                         ret = lidar_read_measurement(data, reg);
 181                         break;
 182                 }
 183                 ret = -EIO;
 184         }
 185         pm_runtime_mark_last_busy(&client->dev);
 186         pm_runtime_put_autosuspend(&client->dev);
 187 
 188         return ret;
 189 }
 190 
 191 static int lidar_read_raw(struct iio_dev *indio_dev,
 192                           struct iio_chan_spec const *chan,
 193                           int *val, int *val2, long mask)
 194 {
 195         struct lidar_data *data = iio_priv(indio_dev);
 196         int ret = -EINVAL;
 197 
 198         switch (mask) {
 199         case IIO_CHAN_INFO_RAW: {
 200                 u16 reg;
 201 
 202                 if (iio_device_claim_direct_mode(indio_dev))
 203                         return -EBUSY;
 204 
 205                 ret = lidar_get_measurement(data, &reg);
 206                 if (!ret) {
 207                         *val = reg;
 208                         ret = IIO_VAL_INT;
 209                 }
 210                 iio_device_release_direct_mode(indio_dev);
 211                 break;
 212         }
 213         case IIO_CHAN_INFO_SCALE:
 214                 *val = 0;
 215                 *val2 = 10000;
 216                 ret = IIO_VAL_INT_PLUS_MICRO;
 217                 break;
 218         }
 219 
 220         return ret;
 221 }
 222 
 223 static irqreturn_t lidar_trigger_handler(int irq, void *private)
 224 {
 225         struct iio_poll_func *pf = private;
 226         struct iio_dev *indio_dev = pf->indio_dev;
 227         struct lidar_data *data = iio_priv(indio_dev);
 228         int ret;
 229 
 230         ret = lidar_get_measurement(data, data->buffer);
 231         if (!ret) {
 232                 iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
 233                                                    iio_get_time_ns(indio_dev));
 234         } else if (ret != -EINVAL) {
 235                 dev_err(&data->client->dev, "cannot read LIDAR measurement");
 236         }
 237 
 238         iio_trigger_notify_done(indio_dev->trig);
 239 
 240         return IRQ_HANDLED;
 241 }
 242 
 243 static const struct iio_info lidar_info = {
 244         .read_raw = lidar_read_raw,
 245 };
 246 
 247 static int lidar_probe(struct i2c_client *client,
 248                        const struct i2c_device_id *id)
 249 {
 250         struct lidar_data *data;
 251         struct iio_dev *indio_dev;
 252         int ret;
 253 
 254         indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 255         if (!indio_dev)
 256                 return -ENOMEM;
 257         data = iio_priv(indio_dev);
 258 
 259         if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 260                 data->xfer = lidar_i2c_xfer;
 261                 data->i2c_enabled = 1;
 262         } else if (i2c_check_functionality(client->adapter,
 263                                 I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE))
 264                 data->xfer = lidar_smbus_xfer;
 265         else
 266                 return -EOPNOTSUPP;
 267 
 268         indio_dev->info = &lidar_info;
 269         indio_dev->name = LIDAR_DRV_NAME;
 270         indio_dev->channels = lidar_channels;
 271         indio_dev->num_channels = ARRAY_SIZE(lidar_channels);
 272         indio_dev->dev.parent = &client->dev;
 273         indio_dev->modes = INDIO_DIRECT_MODE;
 274 
 275         i2c_set_clientdata(client, indio_dev);
 276 
 277         data->client = client;
 278         data->indio_dev = indio_dev;
 279 
 280         ret = iio_triggered_buffer_setup(indio_dev, NULL,
 281                                          lidar_trigger_handler, NULL);
 282         if (ret)
 283                 return ret;
 284 
 285         ret = iio_device_register(indio_dev);
 286         if (ret)
 287                 goto error_unreg_buffer;
 288 
 289         pm_runtime_set_autosuspend_delay(&client->dev, 1000);
 290         pm_runtime_use_autosuspend(&client->dev);
 291 
 292         ret = pm_runtime_set_active(&client->dev);
 293         if (ret)
 294                 goto error_unreg_buffer;
 295         pm_runtime_enable(&client->dev);
 296         pm_runtime_idle(&client->dev);
 297 
 298         return 0;
 299 
 300 error_unreg_buffer:
 301         iio_triggered_buffer_cleanup(indio_dev);
 302 
 303         return ret;
 304 }
 305 
 306 static int lidar_remove(struct i2c_client *client)
 307 {
 308         struct iio_dev *indio_dev = i2c_get_clientdata(client);
 309 
 310         iio_device_unregister(indio_dev);
 311         iio_triggered_buffer_cleanup(indio_dev);
 312 
 313         pm_runtime_disable(&client->dev);
 314         pm_runtime_set_suspended(&client->dev);
 315 
 316         return 0;
 317 }
 318 
 319 static const struct i2c_device_id lidar_id[] = {
 320         {"lidar-lite-v2", 0},
 321         {"lidar-lite-v3", 0},
 322         { },
 323 };
 324 MODULE_DEVICE_TABLE(i2c, lidar_id);
 325 
 326 static const struct of_device_id lidar_dt_ids[] = {
 327         { .compatible = "pulsedlight,lidar-lite-v2" },
 328         { .compatible = "grmn,lidar-lite-v3" },
 329         { }
 330 };
 331 MODULE_DEVICE_TABLE(of, lidar_dt_ids);
 332 
 333 #ifdef CONFIG_PM
 334 static int lidar_pm_runtime_suspend(struct device *dev)
 335 {
 336         struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
 337         struct lidar_data *data = iio_priv(indio_dev);
 338 
 339         return lidar_write_power(data, 0x0f);
 340 }
 341 
 342 static int lidar_pm_runtime_resume(struct device *dev)
 343 {
 344         struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
 345         struct lidar_data *data = iio_priv(indio_dev);
 346         int ret = lidar_write_power(data, 0);
 347 
 348         /* regulator and FPGA needs settling time */
 349         usleep_range(15000, 20000);
 350 
 351         return ret;
 352 }
 353 #endif
 354 
 355 static const struct dev_pm_ops lidar_pm_ops = {
 356         SET_RUNTIME_PM_OPS(lidar_pm_runtime_suspend,
 357                            lidar_pm_runtime_resume, NULL)
 358 };
 359 
 360 static struct i2c_driver lidar_driver = {
 361         .driver = {
 362                 .name   = LIDAR_DRV_NAME,
 363                 .of_match_table = of_match_ptr(lidar_dt_ids),
 364                 .pm     = &lidar_pm_ops,
 365         },
 366         .probe          = lidar_probe,
 367         .remove         = lidar_remove,
 368         .id_table       = lidar_id,
 369 };
 370 module_i2c_driver(lidar_driver);
 371 
 372 MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
 373 MODULE_DESCRIPTION("PulsedLight LIDAR sensor");
 374 MODULE_LICENSE("GPL");

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