ALSA: usb-audio: mixer: volume quirk for ESS Technology Asus USB DAC
[linux/fpc-iii.git] / drivers / iio / proximity / rfd77402.c
blobfe29fb1a19a6453aa497376c8db15a874b9a14b3
1 /*
2 * rfd77402.c - Support for RF Digital RFD77402 Time-of-Flight (distance) sensor
4 * Copyright 2017 Peter Meerwald-Stadler <pmeerw@pmeerw.net>
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.
10 * 7-bit I2C slave address 0x4c
12 * TODO: interrupt
13 * https://media.digikey.com/pdf/Data%20Sheets/RF%20Digital%20PDFs/RFD77402.pdf
16 #include <linux/module.h>
17 #include <linux/i2c.h>
18 #include <linux/delay.h>
20 #include <linux/iio/iio.h>
22 #define RFD77402_DRV_NAME "rfd77402"
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)
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)
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
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)
51 #define RFD77402_PMU_CFG 0x14
52 #define RFD77402_PMU_MCPU_INIT BIT(9)
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)
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
67 #define RFD77402_MOD_CHIP_ID 0x28
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},
82 struct rfd77402_data {
83 struct i2c_client *client;
84 /* Serialize reads from the sensor */
85 struct mutex lock;
88 static const struct iio_chan_spec rfd77402_channels[] = {
90 .type = IIO_DISTANCE,
91 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
92 BIT(IIO_CHAN_INFO_SCALE),
96 static int rfd77402_set_state(struct rfd77402_data *data, u8 state, u16 check)
98 int ret;
100 ret = i2c_smbus_write_byte_data(data->client, RFD77402_CMD_R,
101 state | RFD77402_CMD_VALID);
102 if (ret < 0)
103 return ret;
105 usleep_range(10000, 20000);
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;
113 return 0;
116 static int rfd77402_measure(struct rfd77402_data *data)
118 int ret;
119 int tries = 10;
121 ret = rfd77402_set_state(data, RFD77402_CMD_MCPU_ON,
122 RFD77402_STATUS_MCPU_ON);
123 if (ret < 0)
124 return ret;
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;
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);
141 if (tries < 0) {
142 ret = -ETIMEDOUT;
143 goto err;
146 ret = i2c_smbus_read_word_data(data->client, RFD77402_RESULT_R);
147 if (ret < 0)
148 goto err;
150 if ((ret & RFD77402_RESULT_ERR_MASK) ||
151 !(ret & RFD77402_RESULT_VALID)) {
152 ret = -EIO;
153 goto err;
156 return (ret & RFD77402_RESULT_DIST_MASK) >> 2;
158 err:
159 rfd77402_set_state(data, RFD77402_CMD_MCPU_OFF,
160 RFD77402_STATUS_MCPU_OFF);
161 return ret;
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)
168 struct rfd77402_data *data = iio_priv(indio_dev);
169 int ret;
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;
190 static const struct iio_info rfd77402_info = {
191 .read_raw = rfd77402_read_raw,
194 static int rfd77402_init(struct rfd77402_data *data)
196 int ret, i;
198 ret = rfd77402_set_state(data, RFD77402_CMD_STANDBY,
199 RFD77402_STATUS_STANDBY);
200 if (ret < 0)
201 return ret;
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;
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;
218 /* set initialization */
219 ret = i2c_smbus_write_word_data(data->client, RFD77402_PMU_CFG, 0x0500);
220 if (ret < 0)
221 return ret;
223 ret = rfd77402_set_state(data, RFD77402_CMD_MCPU_OFF,
224 RFD77402_STATUS_MCPU_OFF);
225 if (ret < 0)
226 return ret;
228 /* set initialization */
229 ret = i2c_smbus_write_word_data(data->client, RFD77402_PMU_CFG, 0x0600);
230 if (ret < 0)
231 return ret;
233 ret = rfd77402_set_state(data, RFD77402_CMD_MCPU_ON,
234 RFD77402_STATUS_MCPU_ON);
235 if (ret < 0)
236 return ret;
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;
246 ret = rfd77402_set_state(data, RFD77402_CMD_STANDBY,
247 RFD77402_STATUS_STANDBY);
249 return ret;
252 static int rfd77402_powerdown(struct rfd77402_data *data)
254 return rfd77402_set_state(data, RFD77402_CMD_STANDBY,
255 RFD77402_STATUS_STANDBY);
258 static int rfd77402_probe(struct i2c_client *client,
259 const struct i2c_device_id *id)
261 struct rfd77402_data *data;
262 struct iio_dev *indio_dev;
263 int ret;
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;
271 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
272 if (!indio_dev)
273 return -ENOMEM;
275 data = iio_priv(indio_dev);
276 i2c_set_clientdata(client, indio_dev);
277 data->client = client;
278 mutex_init(&data->lock);
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;
287 ret = rfd77402_init(data);
288 if (ret < 0)
289 return ret;
291 ret = iio_device_register(indio_dev);
292 if (ret)
293 goto err_powerdown;
295 return 0;
297 err_powerdown:
298 rfd77402_powerdown(data);
299 return ret;
302 static int rfd77402_remove(struct i2c_client *client)
304 struct iio_dev *indio_dev = i2c_get_clientdata(client);
306 iio_device_unregister(indio_dev);
307 rfd77402_powerdown(iio_priv(indio_dev));
309 return 0;
312 #ifdef CONFIG_PM_SLEEP
313 static int rfd77402_suspend(struct device *dev)
315 struct rfd77402_data *data = iio_priv(i2c_get_clientdata(
316 to_i2c_client(dev)));
318 return rfd77402_powerdown(data);
321 static int rfd77402_resume(struct device *dev)
323 struct rfd77402_data *data = iio_priv(i2c_get_clientdata(
324 to_i2c_client(dev)));
326 return rfd77402_init(data);
328 #endif
330 static SIMPLE_DEV_PM_OPS(rfd77402_pm_ops, rfd77402_suspend, rfd77402_resume);
332 static const struct i2c_device_id rfd77402_id[] = {
333 { "rfd77402", 0},
336 MODULE_DEVICE_TABLE(i2c, rfd77402_id);
338 static struct i2c_driver rfd77402_driver = {
339 .driver = {
340 .name = RFD77402_DRV_NAME,
341 .pm = &rfd77402_pm_ops,
343 .probe = rfd77402_probe,
344 .remove = rfd77402_remove,
345 .id_table = rfd77402_id,
348 module_i2c_driver(rfd77402_driver);
350 MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>");
351 MODULE_DESCRIPTION("RFD77402 Time-of-Flight sensor driver");
352 MODULE_LICENSE("GPL");