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