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->info = &rfd77402_info; 278 indio_dev->channels = rfd77402_channels; 279 indio_dev->num_channels = ARRAY_SIZE(rfd77402_channels); 280 indio_dev->name = RFD77402_DRV_NAME; 281 indio_dev->modes = INDIO_DIRECT_MODE; 282 283 ret = rfd77402_init(data); 284 if (ret < 0) 285 return ret; 286 287 ret = iio_device_register(indio_dev); 288 if (ret) 289 goto err_powerdown; 290 291 return 0; 292 293 err_powerdown: 294 rfd77402_powerdown(data); 295 return ret; 296 } 297 298 static int rfd77402_remove(struct i2c_client *client) 299 { 300 struct iio_dev *indio_dev = i2c_get_clientdata(client); 301 302 iio_device_unregister(indio_dev); 303 rfd77402_powerdown(iio_priv(indio_dev)); 304 305 return 0; 306 } 307 308 #ifdef CONFIG_PM_SLEEP 309 static int rfd77402_suspend(struct device *dev) 310 { 311 struct rfd77402_data *data = iio_priv(i2c_get_clientdata( 312 to_i2c_client(dev))); 313 314 return rfd77402_powerdown(data); 315 } 316 317 static int rfd77402_resume(struct device *dev) 318 { 319 struct rfd77402_data *data = iio_priv(i2c_get_clientdata( 320 to_i2c_client(dev))); 321 322 return rfd77402_init(data); 323 } 324 #endif 325 326 static SIMPLE_DEV_PM_OPS(rfd77402_pm_ops, rfd77402_suspend, rfd77402_resume); 327 328 static const struct i2c_device_id rfd77402_id[] = { 329 { "rfd77402", 0}, 330 { } 331 }; 332 MODULE_DEVICE_TABLE(i2c, rfd77402_id); 333 334 static struct i2c_driver rfd77402_driver = { 335 .driver = { 336 .name = RFD77402_DRV_NAME, 337 .pm = &rfd77402_pm_ops, 338 }, 339 .probe = rfd77402_probe, 340 .remove = rfd77402_remove, 341 .id_table = rfd77402_id, 342 }; 343 344 module_i2c_driver(rfd77402_driver); 345 346 MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>"); 347 MODULE_DESCRIPTION("RFD77402 Time-of-Flight sensor driver"); 348 MODULE_LICENSE("GPL"); 349