Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * pulsedlight-lidar-lite-v2.c - Support for PulsedLight LIDAR sensor
0004  *
0005  * Copyright (C) 2015, 2017-2018
0006  * Author: Matt Ranostay <matt.ranostay@konsulko.com>
0007  *
0008  * TODO: interrupt mode, and signal strength reporting
0009  */
0010 
0011 #include <linux/err.h>
0012 #include <linux/init.h>
0013 #include <linux/i2c.h>
0014 #include <linux/delay.h>
0015 #include <linux/module.h>
0016 #include <linux/mod_devicetable.h>
0017 #include <linux/pm_runtime.h>
0018 #include <linux/iio/iio.h>
0019 #include <linux/iio/sysfs.h>
0020 #include <linux/iio/buffer.h>
0021 #include <linux/iio/trigger.h>
0022 #include <linux/iio/triggered_buffer.h>
0023 #include <linux/iio/trigger_consumer.h>
0024 
0025 #define LIDAR_REG_CONTROL       0x00
0026 #define LIDAR_REG_CONTROL_ACQUIRE   BIT(2)
0027 
0028 #define LIDAR_REG_STATUS        0x01
0029 #define LIDAR_REG_STATUS_INVALID    BIT(3)
0030 #define LIDAR_REG_STATUS_READY      BIT(0)
0031 
0032 #define LIDAR_REG_DATA_HBYTE        0x0f
0033 #define LIDAR_REG_DATA_LBYTE        0x10
0034 #define LIDAR_REG_DATA_WORD_READ    BIT(7)
0035 
0036 #define LIDAR_REG_PWR_CONTROL   0x65
0037 
0038 #define LIDAR_DRV_NAME "lidar"
0039 
0040 struct lidar_data {
0041     struct iio_dev *indio_dev;
0042     struct i2c_client *client;
0043 
0044     int (*xfer)(struct lidar_data *data, u8 reg, u8 *val, int len);
0045     int i2c_enabled;
0046 
0047     /* Ensure timestamp is naturally aligned */
0048     struct {
0049         u16 chan;
0050         s64 timestamp __aligned(8);
0051     } scan;
0052 };
0053 
0054 static const struct iio_chan_spec lidar_channels[] = {
0055     {
0056         .type = IIO_DISTANCE,
0057         .info_mask_separate =
0058             BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
0059         .scan_index = 0,
0060         .scan_type = {
0061             .sign = 'u',
0062             .realbits = 16,
0063             .storagebits = 16,
0064         },
0065     },
0066     IIO_CHAN_SOFT_TIMESTAMP(1),
0067 };
0068 
0069 static int lidar_i2c_xfer(struct lidar_data *data, u8 reg, u8 *val, int len)
0070 {
0071     struct i2c_client *client = data->client;
0072     struct i2c_msg msg[2];
0073     int ret;
0074 
0075     msg[0].addr = client->addr;
0076     msg[0].flags = client->flags | I2C_M_STOP;
0077     msg[0].len = 1;
0078     msg[0].buf  = (char *) &reg;
0079 
0080     msg[1].addr = client->addr;
0081     msg[1].flags = client->flags | I2C_M_RD;
0082     msg[1].len = len;
0083     msg[1].buf = (char *) val;
0084 
0085     ret = i2c_transfer(client->adapter, msg, 2);
0086 
0087     return (ret == 2) ? 0 : -EIO;
0088 }
0089 
0090 static int lidar_smbus_xfer(struct lidar_data *data, u8 reg, u8 *val, int len)
0091 {
0092     struct i2c_client *client = data->client;
0093     int ret;
0094 
0095     /*
0096      * Device needs a STOP condition between address write, and data read
0097      * so in turn i2c_smbus_read_byte_data cannot be used
0098      */
0099 
0100     while (len--) {
0101         ret = i2c_smbus_write_byte(client, reg++);
0102         if (ret < 0) {
0103             dev_err(&client->dev, "cannot write addr value");
0104             return ret;
0105         }
0106 
0107         ret = i2c_smbus_read_byte(client);
0108         if (ret < 0) {
0109             dev_err(&client->dev, "cannot read data value");
0110             return ret;
0111         }
0112 
0113         *(val++) = ret;
0114     }
0115 
0116     return 0;
0117 }
0118 
0119 static int lidar_read_byte(struct lidar_data *data, u8 reg)
0120 {
0121     int ret;
0122     u8 val;
0123 
0124     ret = data->xfer(data, reg, &val, 1);
0125     if (ret < 0)
0126         return ret;
0127 
0128     return val;
0129 }
0130 
0131 static inline int lidar_write_control(struct lidar_data *data, int val)
0132 {
0133     return i2c_smbus_write_byte_data(data->client, LIDAR_REG_CONTROL, val);
0134 }
0135 
0136 static inline int lidar_write_power(struct lidar_data *data, int val)
0137 {
0138     return i2c_smbus_write_byte_data(data->client,
0139                      LIDAR_REG_PWR_CONTROL, val);
0140 }
0141 
0142 static int lidar_read_measurement(struct lidar_data *data, u16 *reg)
0143 {
0144     __be16 value;
0145     int ret = data->xfer(data, LIDAR_REG_DATA_HBYTE |
0146             (data->i2c_enabled ? LIDAR_REG_DATA_WORD_READ : 0),
0147             (u8 *) &value, 2);
0148 
0149     if (!ret)
0150         *reg = be16_to_cpu(value);
0151 
0152     return ret;
0153 }
0154 
0155 static int lidar_get_measurement(struct lidar_data *data, u16 *reg)
0156 {
0157     struct i2c_client *client = data->client;
0158     int tries = 10;
0159     int ret;
0160 
0161     ret = pm_runtime_resume_and_get(&client->dev);
0162     if (ret < 0)
0163         return ret;
0164 
0165     /* start sample */
0166     ret = lidar_write_control(data, LIDAR_REG_CONTROL_ACQUIRE);
0167     if (ret < 0) {
0168         dev_err(&client->dev, "cannot send start measurement command");
0169         pm_runtime_put_noidle(&client->dev);
0170         return ret;
0171     }
0172 
0173     while (tries--) {
0174         usleep_range(1000, 2000);
0175 
0176         ret = lidar_read_byte(data, LIDAR_REG_STATUS);
0177         if (ret < 0)
0178             break;
0179 
0180         /* return -EINVAL since laser is likely pointed out of range */
0181         if (ret & LIDAR_REG_STATUS_INVALID) {
0182             *reg = 0;
0183             ret = -EINVAL;
0184             break;
0185         }
0186 
0187         /* sample ready to read */
0188         if (!(ret & LIDAR_REG_STATUS_READY)) {
0189             ret = lidar_read_measurement(data, reg);
0190             break;
0191         }
0192         ret = -EIO;
0193     }
0194     pm_runtime_mark_last_busy(&client->dev);
0195     pm_runtime_put_autosuspend(&client->dev);
0196 
0197     return ret;
0198 }
0199 
0200 static int lidar_read_raw(struct iio_dev *indio_dev,
0201               struct iio_chan_spec const *chan,
0202               int *val, int *val2, long mask)
0203 {
0204     struct lidar_data *data = iio_priv(indio_dev);
0205     int ret = -EINVAL;
0206 
0207     switch (mask) {
0208     case IIO_CHAN_INFO_RAW: {
0209         u16 reg;
0210 
0211         if (iio_device_claim_direct_mode(indio_dev))
0212             return -EBUSY;
0213 
0214         ret = lidar_get_measurement(data, &reg);
0215         if (!ret) {
0216             *val = reg;
0217             ret = IIO_VAL_INT;
0218         }
0219         iio_device_release_direct_mode(indio_dev);
0220         break;
0221     }
0222     case IIO_CHAN_INFO_SCALE:
0223         *val = 0;
0224         *val2 = 10000;
0225         ret = IIO_VAL_INT_PLUS_MICRO;
0226         break;
0227     }
0228 
0229     return ret;
0230 }
0231 
0232 static irqreturn_t lidar_trigger_handler(int irq, void *private)
0233 {
0234     struct iio_poll_func *pf = private;
0235     struct iio_dev *indio_dev = pf->indio_dev;
0236     struct lidar_data *data = iio_priv(indio_dev);
0237     int ret;
0238 
0239     ret = lidar_get_measurement(data, &data->scan.chan);
0240     if (!ret) {
0241         iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
0242                            iio_get_time_ns(indio_dev));
0243     } else if (ret != -EINVAL) {
0244         dev_err(&data->client->dev, "cannot read LIDAR measurement");
0245     }
0246 
0247     iio_trigger_notify_done(indio_dev->trig);
0248 
0249     return IRQ_HANDLED;
0250 }
0251 
0252 static const struct iio_info lidar_info = {
0253     .read_raw = lidar_read_raw,
0254 };
0255 
0256 static int lidar_probe(struct i2c_client *client,
0257                const struct i2c_device_id *id)
0258 {
0259     struct lidar_data *data;
0260     struct iio_dev *indio_dev;
0261     int ret;
0262 
0263     indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
0264     if (!indio_dev)
0265         return -ENOMEM;
0266     data = iio_priv(indio_dev);
0267 
0268     if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
0269         data->xfer = lidar_i2c_xfer;
0270         data->i2c_enabled = 1;
0271     } else if (i2c_check_functionality(client->adapter,
0272                 I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE))
0273         data->xfer = lidar_smbus_xfer;
0274     else
0275         return -EOPNOTSUPP;
0276 
0277     indio_dev->info = &lidar_info;
0278     indio_dev->name = LIDAR_DRV_NAME;
0279     indio_dev->channels = lidar_channels;
0280     indio_dev->num_channels = ARRAY_SIZE(lidar_channels);
0281     indio_dev->modes = INDIO_DIRECT_MODE;
0282 
0283     i2c_set_clientdata(client, indio_dev);
0284 
0285     data->client = client;
0286     data->indio_dev = indio_dev;
0287 
0288     ret = iio_triggered_buffer_setup(indio_dev, NULL,
0289                      lidar_trigger_handler, NULL);
0290     if (ret)
0291         return ret;
0292 
0293     ret = iio_device_register(indio_dev);
0294     if (ret)
0295         goto error_unreg_buffer;
0296 
0297     pm_runtime_set_autosuspend_delay(&client->dev, 1000);
0298     pm_runtime_use_autosuspend(&client->dev);
0299 
0300     ret = pm_runtime_set_active(&client->dev);
0301     if (ret)
0302         goto error_unreg_buffer;
0303     pm_runtime_enable(&client->dev);
0304     pm_runtime_idle(&client->dev);
0305 
0306     return 0;
0307 
0308 error_unreg_buffer:
0309     iio_triggered_buffer_cleanup(indio_dev);
0310 
0311     return ret;
0312 }
0313 
0314 static int lidar_remove(struct i2c_client *client)
0315 {
0316     struct iio_dev *indio_dev = i2c_get_clientdata(client);
0317 
0318     iio_device_unregister(indio_dev);
0319     iio_triggered_buffer_cleanup(indio_dev);
0320 
0321     pm_runtime_disable(&client->dev);
0322     pm_runtime_set_suspended(&client->dev);
0323 
0324     return 0;
0325 }
0326 
0327 static const struct i2c_device_id lidar_id[] = {
0328     {"lidar-lite-v2", 0},
0329     {"lidar-lite-v3", 0},
0330     { },
0331 };
0332 MODULE_DEVICE_TABLE(i2c, lidar_id);
0333 
0334 static const struct of_device_id lidar_dt_ids[] = {
0335     { .compatible = "pulsedlight,lidar-lite-v2" },
0336     { .compatible = "grmn,lidar-lite-v3" },
0337     { }
0338 };
0339 MODULE_DEVICE_TABLE(of, lidar_dt_ids);
0340 
0341 static int lidar_pm_runtime_suspend(struct device *dev)
0342 {
0343     struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
0344     struct lidar_data *data = iio_priv(indio_dev);
0345 
0346     return lidar_write_power(data, 0x0f);
0347 }
0348 
0349 static int lidar_pm_runtime_resume(struct device *dev)
0350 {
0351     struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
0352     struct lidar_data *data = iio_priv(indio_dev);
0353     int ret = lidar_write_power(data, 0);
0354 
0355     /* regulator and FPGA needs settling time */
0356     usleep_range(15000, 20000);
0357 
0358     return ret;
0359 }
0360 
0361 static const struct dev_pm_ops lidar_pm_ops = {
0362     RUNTIME_PM_OPS(lidar_pm_runtime_suspend, lidar_pm_runtime_resume, NULL)
0363 };
0364 
0365 static struct i2c_driver lidar_driver = {
0366     .driver = {
0367         .name   = LIDAR_DRV_NAME,
0368         .of_match_table = lidar_dt_ids,
0369         .pm = pm_ptr(&lidar_pm_ops),
0370     },
0371     .probe      = lidar_probe,
0372     .remove     = lidar_remove,
0373     .id_table   = lidar_id,
0374 };
0375 module_i2c_driver(lidar_driver);
0376 
0377 MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
0378 MODULE_DESCRIPTION("PulsedLight LIDAR sensor");
0379 MODULE_LICENSE("GPL");