Merge tag 'for-linus' of git://git.armlinux.org.uk/~rmk/linux-arm
[linux-2.6-microblaze.git] / drivers / iio / proximity / rfd77402.c
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 i2c_client *client, u8 state, u16 check)
94 {
95         int ret;
96
97         ret = i2c_smbus_write_byte_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(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 i2c_client *client)
114 {
115         int ret;
116         int tries = 10;
117
118         ret = rfd77402_set_state(client, RFD77402_CMD_MCPU_ON,
119                                  RFD77402_STATUS_MCPU_ON);
120         if (ret < 0)
121                 return ret;
122
123         ret = i2c_smbus_write_byte_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(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(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(client, 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->client);
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 i2c_client *client)
192 {
193         int ret, i;
194
195         ret = rfd77402_set_state(client, 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(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(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(client, RFD77402_PMU_CFG, 0x0500);
217         if (ret < 0)
218                 return ret;
219
220         ret = rfd77402_set_state(client, 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(client, RFD77402_PMU_CFG, 0x0600);
227         if (ret < 0)
228                 return ret;
229
230         ret = rfd77402_set_state(client, 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(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(client, RFD77402_CMD_STANDBY,
244                                  RFD77402_STATUS_STANDBY);
245
246         return ret;
247 }
248
249 static int rfd77402_powerdown(struct i2c_client *client)
250 {
251         return rfd77402_set_state(client, RFD77402_CMD_STANDBY,
252                                   RFD77402_STATUS_STANDBY);
253 }
254
255 static void rfd77402_disable(void *client)
256 {
257         rfd77402_powerdown(client);
258 }
259
260 static int rfd77402_probe(struct i2c_client *client,
261                           const struct i2c_device_id *id)
262 {
263         struct rfd77402_data *data;
264         struct iio_dev *indio_dev;
265         int ret;
266
267         ret = i2c_smbus_read_word_data(client, RFD77402_MOD_CHIP_ID);
268         if (ret < 0)
269                 return ret;
270         if (ret != 0xad01 && ret != 0xad02) /* known chip ids */
271                 return -ENODEV;
272
273         indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
274         if (!indio_dev)
275                 return -ENOMEM;
276
277         data = iio_priv(indio_dev);
278         data->client = client;
279         mutex_init(&data->lock);
280
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(client);
288         if (ret < 0)
289                 return ret;
290
291         ret = devm_add_action_or_reset(&client->dev, rfd77402_disable, client);
292         if (ret)
293                 return ret;
294
295         return devm_iio_device_register(&client->dev, indio_dev);
296 }
297
298 #ifdef CONFIG_PM_SLEEP
299 static int rfd77402_suspend(struct device *dev)
300 {
301         return rfd77402_powerdown(to_i2c_client(dev));
302 }
303
304 static int rfd77402_resume(struct device *dev)
305 {
306         return rfd77402_init(to_i2c_client(dev));
307 }
308 #endif
309
310 static SIMPLE_DEV_PM_OPS(rfd77402_pm_ops, rfd77402_suspend, rfd77402_resume);
311
312 static const struct i2c_device_id rfd77402_id[] = {
313         { "rfd77402", 0},
314         { }
315 };
316 MODULE_DEVICE_TABLE(i2c, rfd77402_id);
317
318 static struct i2c_driver rfd77402_driver = {
319         .driver = {
320                 .name   = RFD77402_DRV_NAME,
321                 .pm     = &rfd77402_pm_ops,
322         },
323         .probe  = rfd77402_probe,
324         .id_table = rfd77402_id,
325 };
326
327 module_i2c_driver(rfd77402_driver);
328
329 MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>");
330 MODULE_DESCRIPTION("RFD77402 Time-of-Flight sensor driver");
331 MODULE_LICENSE("GPL");