root/drivers/iio/proximity/rfd77402.c

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

DEFINITIONS

This source file includes following definitions.
  1. rfd77402_set_state
  2. rfd77402_measure
  3. rfd77402_read_raw
  4. rfd77402_init
  5. rfd77402_powerdown
  6. rfd77402_probe
  7. rfd77402_remove
  8. rfd77402_suspend
  9. rfd77402_resume

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * rfd77402.c - Support for RF Digital RFD77402 Time-of-Flight (distance) sensor
   4  *
   5  * Copyright 2017 Peter Meerwald-Stadler <pmeerw@pmeerw.net>
   6  *
   7  * 7-bit I2C slave address 0x4c
   8  *
   9  * TODO: interrupt
  10  * https://media.digikey.com/pdf/Data%20Sheets/RF%20Digital%20PDFs/RFD77402.pdf
  11  */
  12 
  13 #include <linux/module.h>
  14 #include <linux/i2c.h>
  15 #include <linux/delay.h>
  16 
  17 #include <linux/iio/iio.h>
  18 
  19 #define RFD77402_DRV_NAME "rfd77402"
  20 
  21 #define RFD77402_ICSR           0x00 /* Interrupt Control Status Register */
  22 #define RFD77402_ICSR_INT_MODE  BIT(2)
  23 #define RFD77402_ICSR_INT_POL   BIT(3)
  24 #define RFD77402_ICSR_RESULT    BIT(4)
  25 #define RFD77402_ICSR_M2H_MSG   BIT(5)
  26 #define RFD77402_ICSR_H2M_MSG   BIT(6)
  27 #define RFD77402_ICSR_RESET     BIT(7)
  28 
  29 #define RFD77402_CMD_R          0x04
  30 #define RFD77402_CMD_SINGLE     0x01
  31 #define RFD77402_CMD_STANDBY    0x10
  32 #define RFD77402_CMD_MCPU_OFF   0x11
  33 #define RFD77402_CMD_MCPU_ON    0x12
  34 #define RFD77402_CMD_RESET      BIT(6)
  35 #define RFD77402_CMD_VALID      BIT(7)
  36 
  37 #define RFD77402_STATUS_R       0x06
  38 #define RFD77402_STATUS_PM_MASK GENMASK(4, 0)
  39 #define RFD77402_STATUS_STANDBY 0x00
  40 #define RFD77402_STATUS_MCPU_OFF        0x10
  41 #define RFD77402_STATUS_MCPU_ON 0x18
  42 
  43 #define RFD77402_RESULT_R       0x08
  44 #define RFD77402_RESULT_DIST_MASK       GENMASK(12, 2)
  45 #define RFD77402_RESULT_ERR_MASK        GENMASK(14, 13)
  46 #define RFD77402_RESULT_VALID   BIT(15)
  47 
  48 #define RFD77402_PMU_CFG        0x14
  49 #define RFD77402_PMU_MCPU_INIT  BIT(9)
  50 
  51 #define RFD77402_I2C_INIT_CFG   0x1c
  52 #define RFD77402_I2C_ADDR_INCR  BIT(0)
  53 #define RFD77402_I2C_DATA_INCR  BIT(2)
  54 #define RFD77402_I2C_HOST_DEBUG BIT(5)
  55 #define RFD77402_I2C_MCPU_DEBUG BIT(6)
  56 
  57 #define RFD77402_CMD_CFGR_A     0x0c
  58 #define RFD77402_CMD_CFGR_B     0x0e
  59 #define RFD77402_HFCFG_0        0x20
  60 #define RFD77402_HFCFG_1        0x22
  61 #define RFD77402_HFCFG_2        0x24
  62 #define RFD77402_HFCFG_3        0x26
  63 
  64 #define RFD77402_MOD_CHIP_ID    0x28
  65 
  66 /* magic configuration values from datasheet */
  67 static const struct {
  68         u8 reg;
  69         u16 val;
  70 } rf77402_tof_config[] = {
  71         {RFD77402_CMD_CFGR_A,   0xe100},
  72         {RFD77402_CMD_CFGR_B,   0x10ff},
  73         {RFD77402_HFCFG_0,      0x07d0},
  74         {RFD77402_HFCFG_1,      0x5008},
  75         {RFD77402_HFCFG_2,      0xa041},
  76         {RFD77402_HFCFG_3,      0x45d4},
  77 };
  78 
  79 struct rfd77402_data {
  80         struct i2c_client *client;
  81         /* Serialize reads from the sensor */
  82         struct mutex lock;
  83 };
  84 
  85 static const struct iio_chan_spec rfd77402_channels[] = {
  86         {
  87                 .type = IIO_DISTANCE,
  88                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
  89                                       BIT(IIO_CHAN_INFO_SCALE),
  90         },
  91 };
  92 
  93 static int rfd77402_set_state(struct rfd77402_data *data, u8 state, u16 check)
  94 {
  95         int ret;
  96 
  97         ret = i2c_smbus_write_byte_data(data->client, RFD77402_CMD_R,
  98                                         state | RFD77402_CMD_VALID);
  99         if (ret < 0)
 100                 return ret;
 101 
 102         usleep_range(10000, 20000);
 103 
 104         ret = i2c_smbus_read_word_data(data->client, RFD77402_STATUS_R);
 105         if (ret < 0)
 106                 return ret;
 107         if ((ret & RFD77402_STATUS_PM_MASK) != check)
 108                 return -ENODEV;
 109 
 110         return 0;
 111 }
 112 
 113 static int rfd77402_measure(struct rfd77402_data *data)
 114 {
 115         int ret;
 116         int tries = 10;
 117 
 118         ret = rfd77402_set_state(data, RFD77402_CMD_MCPU_ON,
 119                                  RFD77402_STATUS_MCPU_ON);
 120         if (ret < 0)
 121                 return ret;
 122 
 123         ret = i2c_smbus_write_byte_data(data->client, RFD77402_CMD_R,
 124                                         RFD77402_CMD_SINGLE |
 125                                         RFD77402_CMD_VALID);
 126         if (ret < 0)
 127                 goto err;
 128 
 129         while (tries-- > 0) {
 130                 ret = i2c_smbus_read_byte_data(data->client, RFD77402_ICSR);
 131                 if (ret < 0)
 132                         goto err;
 133                 if (ret & RFD77402_ICSR_RESULT)
 134                         break;
 135                 msleep(20);
 136         }
 137 
 138         if (tries < 0) {
 139                 ret = -ETIMEDOUT;
 140                 goto err;
 141         }
 142 
 143         ret = i2c_smbus_read_word_data(data->client, RFD77402_RESULT_R);
 144         if (ret < 0)
 145                 goto err;
 146 
 147         if ((ret & RFD77402_RESULT_ERR_MASK) ||
 148             !(ret & RFD77402_RESULT_VALID)) {
 149                 ret = -EIO;
 150                 goto err;
 151         }
 152 
 153         return (ret & RFD77402_RESULT_DIST_MASK) >> 2;
 154 
 155 err:
 156         rfd77402_set_state(data, RFD77402_CMD_MCPU_OFF,
 157                            RFD77402_STATUS_MCPU_OFF);
 158         return ret;
 159 }
 160 
 161 static int rfd77402_read_raw(struct iio_dev *indio_dev,
 162                              struct iio_chan_spec const *chan,
 163                              int *val, int *val2, long mask)
 164 {
 165         struct rfd77402_data *data = iio_priv(indio_dev);
 166         int ret;
 167 
 168         switch (mask) {
 169         case IIO_CHAN_INFO_RAW:
 170                 mutex_lock(&data->lock);
 171                 ret = rfd77402_measure(data);
 172                 mutex_unlock(&data->lock);
 173                 if (ret < 0)
 174                         return ret;
 175                 *val = ret;
 176                 return IIO_VAL_INT;
 177         case IIO_CHAN_INFO_SCALE:
 178                 /* 1 LSB is 1 mm */
 179                 *val = 0;
 180                 *val2 = 1000;
 181                 return IIO_VAL_INT_PLUS_MICRO;
 182         default:
 183                 return -EINVAL;
 184         }
 185 }
 186 
 187 static const struct iio_info rfd77402_info = {
 188         .read_raw = rfd77402_read_raw,
 189 };
 190 
 191 static int rfd77402_init(struct rfd77402_data *data)
 192 {
 193         int ret, i;
 194 
 195         ret = rfd77402_set_state(data, RFD77402_CMD_STANDBY,
 196                                  RFD77402_STATUS_STANDBY);
 197         if (ret < 0)
 198                 return ret;
 199 
 200         /* configure INT pad as push-pull, active low */
 201         ret = i2c_smbus_write_byte_data(data->client, RFD77402_ICSR,
 202                                         RFD77402_ICSR_INT_MODE);
 203         if (ret < 0)
 204                 return ret;
 205 
 206         /* I2C configuration */
 207         ret = i2c_smbus_write_word_data(data->client, RFD77402_I2C_INIT_CFG,
 208                                         RFD77402_I2C_ADDR_INCR |
 209                                         RFD77402_I2C_DATA_INCR |
 210                                         RFD77402_I2C_HOST_DEBUG |
 211                                         RFD77402_I2C_MCPU_DEBUG);
 212         if (ret < 0)
 213                 return ret;
 214 
 215         /* set initialization */
 216         ret = i2c_smbus_write_word_data(data->client, RFD77402_PMU_CFG, 0x0500);
 217         if (ret < 0)
 218                 return ret;
 219 
 220         ret = rfd77402_set_state(data, RFD77402_CMD_MCPU_OFF,
 221                                  RFD77402_STATUS_MCPU_OFF);
 222         if (ret < 0)
 223                 return ret;
 224 
 225         /* set initialization */
 226         ret = i2c_smbus_write_word_data(data->client, RFD77402_PMU_CFG, 0x0600);
 227         if (ret < 0)
 228                 return ret;
 229 
 230         ret = rfd77402_set_state(data, RFD77402_CMD_MCPU_ON,
 231                                  RFD77402_STATUS_MCPU_ON);
 232         if (ret < 0)
 233                 return ret;
 234 
 235         for (i = 0; i < ARRAY_SIZE(rf77402_tof_config); i++) {
 236                 ret = i2c_smbus_write_word_data(data->client,
 237                                                 rf77402_tof_config[i].reg,
 238                                                 rf77402_tof_config[i].val);
 239                 if (ret < 0)
 240                         return ret;
 241         }
 242 
 243         ret = rfd77402_set_state(data, RFD77402_CMD_STANDBY,
 244                                  RFD77402_STATUS_STANDBY);
 245 
 246         return ret;
 247 }
 248 
 249 static int rfd77402_powerdown(struct rfd77402_data *data)
 250 {
 251         return rfd77402_set_state(data, RFD77402_CMD_STANDBY,
 252                                   RFD77402_STATUS_STANDBY);
 253 }
 254 
 255 static int rfd77402_probe(struct i2c_client *client,
 256                           const struct i2c_device_id *id)
 257 {
 258         struct rfd77402_data *data;
 259         struct iio_dev *indio_dev;
 260         int ret;
 261 
 262         ret = i2c_smbus_read_word_data(client, RFD77402_MOD_CHIP_ID);
 263         if (ret < 0)
 264                 return ret;
 265         if (ret != 0xad01 && ret != 0xad02) /* known chip ids */
 266                 return -ENODEV;
 267 
 268         indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 269         if (!indio_dev)
 270                 return -ENOMEM;
 271 
 272         data = iio_priv(indio_dev);
 273         i2c_set_clientdata(client, indio_dev);
 274         data->client = client;
 275         mutex_init(&data->lock);
 276 
 277         indio_dev->dev.parent = &client->dev;
 278         indio_dev->info = &rfd77402_info;
 279         indio_dev->channels = rfd77402_channels;
 280         indio_dev->num_channels = ARRAY_SIZE(rfd77402_channels);
 281         indio_dev->name = RFD77402_DRV_NAME;
 282         indio_dev->modes = INDIO_DIRECT_MODE;
 283 
 284         ret = rfd77402_init(data);
 285         if (ret < 0)
 286                 return ret;
 287 
 288         ret = iio_device_register(indio_dev);
 289         if (ret)
 290                 goto err_powerdown;
 291 
 292         return 0;
 293 
 294 err_powerdown:
 295         rfd77402_powerdown(data);
 296         return ret;
 297 }
 298 
 299 static int rfd77402_remove(struct i2c_client *client)
 300 {
 301         struct iio_dev *indio_dev = i2c_get_clientdata(client);
 302 
 303         iio_device_unregister(indio_dev);
 304         rfd77402_powerdown(iio_priv(indio_dev));
 305 
 306         return 0;
 307 }
 308 
 309 #ifdef CONFIG_PM_SLEEP
 310 static int rfd77402_suspend(struct device *dev)
 311 {
 312         struct rfd77402_data *data = iio_priv(i2c_get_clientdata(
 313                                      to_i2c_client(dev)));
 314 
 315         return rfd77402_powerdown(data);
 316 }
 317 
 318 static int rfd77402_resume(struct device *dev)
 319 {
 320         struct rfd77402_data *data = iio_priv(i2c_get_clientdata(
 321                                      to_i2c_client(dev)));
 322 
 323         return rfd77402_init(data);
 324 }
 325 #endif
 326 
 327 static SIMPLE_DEV_PM_OPS(rfd77402_pm_ops, rfd77402_suspend, rfd77402_resume);
 328 
 329 static const struct i2c_device_id rfd77402_id[] = {
 330         { "rfd77402", 0},
 331         { }
 332 };
 333 MODULE_DEVICE_TABLE(i2c, rfd77402_id);
 334 
 335 static struct i2c_driver rfd77402_driver = {
 336         .driver = {
 337                 .name   = RFD77402_DRV_NAME,
 338                 .pm     = &rfd77402_pm_ops,
 339         },
 340         .probe  = rfd77402_probe,
 341         .remove = rfd77402_remove,
 342         .id_table = rfd77402_id,
 343 };
 344 
 345 module_i2c_driver(rfd77402_driver);
 346 
 347 MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>");
 348 MODULE_DESCRIPTION("RFD77402 Time-of-Flight sensor driver");
 349 MODULE_LICENSE("GPL");

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