1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * srf08.c - Support for Devantech SRFxx ultrasonic ranger |
4 | * with i2c interface |
5 | * actually supported are srf02, srf08, srf10 |
6 | * |
7 | * Copyright (c) 2016, 2017 Andreas Klinger <ak@it-klinger.de> |
8 | * |
9 | * For details about the device see: |
10 | * https://www.robot-electronics.co.uk/htm/srf08tech.html |
11 | * https://www.robot-electronics.co.uk/htm/srf10tech.htm |
12 | * https://www.robot-electronics.co.uk/htm/srf02tech.htm |
13 | */ |
14 | |
15 | #include <linux/err.h> |
16 | #include <linux/i2c.h> |
17 | #include <linux/delay.h> |
18 | #include <linux/module.h> |
19 | #include <linux/bitops.h> |
20 | #include <linux/iio/iio.h> |
21 | #include <linux/iio/sysfs.h> |
22 | #include <linux/iio/buffer.h> |
23 | #include <linux/iio/trigger_consumer.h> |
24 | #include <linux/iio/triggered_buffer.h> |
25 | |
26 | /* registers of SRF08 device */ |
27 | #define SRF08_WRITE_COMMAND 0x00 /* Command Register */ |
28 | #define SRF08_WRITE_MAX_GAIN 0x01 /* Max Gain Register: 0 .. 31 */ |
29 | #define SRF08_WRITE_RANGE 0x02 /* Range Register: 0 .. 255 */ |
30 | #define SRF08_READ_SW_REVISION 0x00 /* Software Revision */ |
31 | #define SRF08_READ_LIGHT 0x01 /* Light Sensor during last echo */ |
32 | #define SRF08_READ_ECHO_1_HIGH 0x02 /* Range of first echo received */ |
33 | #define SRF08_READ_ECHO_1_LOW 0x03 /* Range of first echo received */ |
34 | |
35 | #define SRF08_CMD_RANGING_CM 0x51 /* Ranging Mode - Result in cm */ |
36 | |
37 | enum srf08_sensor_type { |
38 | SRF02, |
39 | SRF08, |
40 | SRF10, |
41 | SRF_MAX_TYPE |
42 | }; |
43 | |
44 | struct srf08_chip_info { |
45 | const int *sensitivity_avail; |
46 | int num_sensitivity_avail; |
47 | int sensitivity_default; |
48 | |
49 | /* default value of Range in mm */ |
50 | int range_default; |
51 | }; |
52 | |
53 | struct srf08_data { |
54 | struct i2c_client *client; |
55 | |
56 | /* |
57 | * Gain in the datasheet is called sensitivity here to distinct it |
58 | * from the gain used with amplifiers of adc's |
59 | */ |
60 | int sensitivity; |
61 | |
62 | /* max. Range in mm */ |
63 | int range_mm; |
64 | struct mutex lock; |
65 | |
66 | /* Ensure timestamp is naturally aligned */ |
67 | struct { |
68 | s16 chan; |
69 | s64 timestamp __aligned(8); |
70 | } scan; |
71 | |
72 | /* Sensor-Type */ |
73 | enum srf08_sensor_type sensor_type; |
74 | |
75 | /* Chip-specific information */ |
76 | const struct srf08_chip_info *chip_info; |
77 | }; |
78 | |
79 | /* |
80 | * in the documentation one can read about the "Gain" of the device |
81 | * which is used here for amplifying the signal and filtering out unwanted |
82 | * ones. |
83 | * But with ADC's this term is already used differently and that's why it |
84 | * is called "Sensitivity" here. |
85 | */ |
86 | static const struct srf08_chip_info srf02_chip_info = { |
87 | .sensitivity_avail = NULL, |
88 | .num_sensitivity_avail = 0, |
89 | .sensitivity_default = 0, |
90 | |
91 | .range_default = 0, |
92 | }; |
93 | |
94 | static const int srf08_sensitivity_avail[] = { |
95 | 94, 97, 100, 103, 107, 110, 114, 118, |
96 | 123, 128, 133, 139, 145, 152, 159, 168, |
97 | 177, 187, 199, 212, 227, 245, 265, 288, |
98 | 317, 352, 395, 450, 524, 626, 777, 1025 |
99 | }; |
100 | |
101 | static const struct srf08_chip_info srf08_chip_info = { |
102 | .sensitivity_avail = srf08_sensitivity_avail, |
103 | .num_sensitivity_avail = ARRAY_SIZE(srf08_sensitivity_avail), |
104 | .sensitivity_default = 1025, |
105 | |
106 | .range_default = 6020, |
107 | }; |
108 | |
109 | static const int srf10_sensitivity_avail[] = { |
110 | 40, 40, 50, 60, 70, 80, 100, 120, |
111 | 140, 200, 250, 300, 350, 400, 500, 600, |
112 | 700, |
113 | }; |
114 | |
115 | static const struct srf08_chip_info srf10_chip_info = { |
116 | .sensitivity_avail = srf10_sensitivity_avail, |
117 | .num_sensitivity_avail = ARRAY_SIZE(srf10_sensitivity_avail), |
118 | .sensitivity_default = 700, |
119 | |
120 | .range_default = 6020, |
121 | }; |
122 | |
123 | static int srf08_read_ranging(struct srf08_data *data) |
124 | { |
125 | struct i2c_client *client = data->client; |
126 | int ret, i; |
127 | int waittime; |
128 | |
129 | mutex_lock(&data->lock); |
130 | |
131 | ret = i2c_smbus_write_byte_data(client: data->client, |
132 | SRF08_WRITE_COMMAND, SRF08_CMD_RANGING_CM); |
133 | if (ret < 0) { |
134 | dev_err(&client->dev, "write command - err: %d\n" , ret); |
135 | mutex_unlock(lock: &data->lock); |
136 | return ret; |
137 | } |
138 | |
139 | /* |
140 | * we read here until a correct version number shows up as |
141 | * suggested by the documentation |
142 | * |
143 | * with an ultrasonic speed of 343 m/s and a roundtrip of it |
144 | * sleep the expected duration and try to read from the device |
145 | * if nothing useful is read try it in a shorter grid |
146 | * |
147 | * polling for not more than 20 ms should be enough |
148 | */ |
149 | waittime = 1 + data->range_mm / 172; |
150 | msleep(msecs: waittime); |
151 | for (i = 0; i < 4; i++) { |
152 | ret = i2c_smbus_read_byte_data(client: data->client, |
153 | SRF08_READ_SW_REVISION); |
154 | |
155 | /* check if a valid version number is read */ |
156 | if (ret < 255 && ret > 0) |
157 | break; |
158 | msleep(msecs: 5); |
159 | } |
160 | |
161 | if (ret >= 255 || ret <= 0) { |
162 | dev_err(&client->dev, "device not ready\n" ); |
163 | mutex_unlock(lock: &data->lock); |
164 | return -EIO; |
165 | } |
166 | |
167 | ret = i2c_smbus_read_word_swapped(client: data->client, |
168 | SRF08_READ_ECHO_1_HIGH); |
169 | if (ret < 0) { |
170 | dev_err(&client->dev, "cannot read distance: ret=%d\n" , ret); |
171 | mutex_unlock(lock: &data->lock); |
172 | return ret; |
173 | } |
174 | |
175 | mutex_unlock(lock: &data->lock); |
176 | |
177 | return ret; |
178 | } |
179 | |
180 | static irqreturn_t srf08_trigger_handler(int irq, void *p) |
181 | { |
182 | struct iio_poll_func *pf = p; |
183 | struct iio_dev *indio_dev = pf->indio_dev; |
184 | struct srf08_data *data = iio_priv(indio_dev); |
185 | s16 sensor_data; |
186 | |
187 | sensor_data = srf08_read_ranging(data); |
188 | if (sensor_data < 0) |
189 | goto err; |
190 | |
191 | mutex_lock(&data->lock); |
192 | |
193 | data->scan.chan = sensor_data; |
194 | iio_push_to_buffers_with_timestamp(indio_dev, |
195 | data: &data->scan, timestamp: pf->timestamp); |
196 | |
197 | mutex_unlock(lock: &data->lock); |
198 | err: |
199 | iio_trigger_notify_done(trig: indio_dev->trig); |
200 | return IRQ_HANDLED; |
201 | } |
202 | |
203 | static int srf08_read_raw(struct iio_dev *indio_dev, |
204 | struct iio_chan_spec const *channel, int *val, |
205 | int *val2, long mask) |
206 | { |
207 | struct srf08_data *data = iio_priv(indio_dev); |
208 | int ret; |
209 | |
210 | if (channel->type != IIO_DISTANCE) |
211 | return -EINVAL; |
212 | |
213 | switch (mask) { |
214 | case IIO_CHAN_INFO_RAW: |
215 | ret = srf08_read_ranging(data); |
216 | if (ret < 0) |
217 | return ret; |
218 | *val = ret; |
219 | return IIO_VAL_INT; |
220 | case IIO_CHAN_INFO_SCALE: |
221 | /* 1 LSB is 1 cm */ |
222 | *val = 0; |
223 | *val2 = 10000; |
224 | return IIO_VAL_INT_PLUS_MICRO; |
225 | default: |
226 | return -EINVAL; |
227 | } |
228 | } |
229 | |
230 | static ssize_t srf08_show_range_mm_available(struct device *dev, |
231 | struct device_attribute *attr, char *buf) |
232 | { |
233 | return sprintf(buf, fmt: "[0.043 0.043 11.008]\n" ); |
234 | } |
235 | |
236 | static IIO_DEVICE_ATTR(sensor_max_range_available, S_IRUGO, |
237 | srf08_show_range_mm_available, NULL, 0); |
238 | |
239 | static ssize_t srf08_show_range_mm(struct device *dev, |
240 | struct device_attribute *attr, char *buf) |
241 | { |
242 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
243 | struct srf08_data *data = iio_priv(indio_dev); |
244 | |
245 | return sprintf(buf, fmt: "%d.%03d\n" , data->range_mm / 1000, |
246 | data->range_mm % 1000); |
247 | } |
248 | |
249 | /* |
250 | * set the range of the sensor to an even multiple of 43 mm |
251 | * which corresponds to 1 LSB in the register |
252 | * |
253 | * register value corresponding range |
254 | * 0x00 43 mm |
255 | * 0x01 86 mm |
256 | * 0x02 129 mm |
257 | * ... |
258 | * 0xFF 11008 mm |
259 | */ |
260 | static ssize_t srf08_write_range_mm(struct srf08_data *data, unsigned int val) |
261 | { |
262 | int ret; |
263 | struct i2c_client *client = data->client; |
264 | unsigned int mod; |
265 | u8 regval; |
266 | |
267 | ret = val / 43 - 1; |
268 | mod = val % 43; |
269 | |
270 | if (mod || (ret < 0) || (ret > 255)) |
271 | return -EINVAL; |
272 | |
273 | regval = ret; |
274 | |
275 | mutex_lock(&data->lock); |
276 | |
277 | ret = i2c_smbus_write_byte_data(client, SRF08_WRITE_RANGE, value: regval); |
278 | if (ret < 0) { |
279 | dev_err(&client->dev, "write_range - err: %d\n" , ret); |
280 | mutex_unlock(lock: &data->lock); |
281 | return ret; |
282 | } |
283 | |
284 | data->range_mm = val; |
285 | |
286 | mutex_unlock(lock: &data->lock); |
287 | |
288 | return 0; |
289 | } |
290 | |
291 | static ssize_t srf08_store_range_mm(struct device *dev, |
292 | struct device_attribute *attr, |
293 | const char *buf, size_t len) |
294 | { |
295 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
296 | struct srf08_data *data = iio_priv(indio_dev); |
297 | int ret; |
298 | int integer, fract; |
299 | |
300 | ret = iio_str_to_fixpoint(str: buf, fract_mult: 100, integer: &integer, fract: &fract); |
301 | if (ret) |
302 | return ret; |
303 | |
304 | ret = srf08_write_range_mm(data, val: integer * 1000 + fract); |
305 | if (ret < 0) |
306 | return ret; |
307 | |
308 | return len; |
309 | } |
310 | |
311 | static IIO_DEVICE_ATTR(sensor_max_range, S_IRUGO | S_IWUSR, |
312 | srf08_show_range_mm, srf08_store_range_mm, 0); |
313 | |
314 | static ssize_t srf08_show_sensitivity_available(struct device *dev, |
315 | struct device_attribute *attr, char *buf) |
316 | { |
317 | int i, len = 0; |
318 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
319 | struct srf08_data *data = iio_priv(indio_dev); |
320 | |
321 | for (i = 0; i < data->chip_info->num_sensitivity_avail; i++) |
322 | if (data->chip_info->sensitivity_avail[i]) |
323 | len += sprintf(buf: buf + len, fmt: "%d " , |
324 | data->chip_info->sensitivity_avail[i]); |
325 | |
326 | len += sprintf(buf: buf + len, fmt: "\n" ); |
327 | |
328 | return len; |
329 | } |
330 | |
331 | static IIO_DEVICE_ATTR(sensor_sensitivity_available, S_IRUGO, |
332 | srf08_show_sensitivity_available, NULL, 0); |
333 | |
334 | static ssize_t srf08_show_sensitivity(struct device *dev, |
335 | struct device_attribute *attr, char *buf) |
336 | { |
337 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
338 | struct srf08_data *data = iio_priv(indio_dev); |
339 | int len; |
340 | |
341 | len = sprintf(buf, fmt: "%d\n" , data->sensitivity); |
342 | |
343 | return len; |
344 | } |
345 | |
346 | static ssize_t srf08_write_sensitivity(struct srf08_data *data, |
347 | unsigned int val) |
348 | { |
349 | struct i2c_client *client = data->client; |
350 | int ret, i; |
351 | u8 regval; |
352 | |
353 | if (!val) |
354 | return -EINVAL; |
355 | |
356 | for (i = 0; i < data->chip_info->num_sensitivity_avail; i++) |
357 | if (val == data->chip_info->sensitivity_avail[i]) { |
358 | regval = i; |
359 | break; |
360 | } |
361 | |
362 | if (i >= data->chip_info->num_sensitivity_avail) |
363 | return -EINVAL; |
364 | |
365 | mutex_lock(&data->lock); |
366 | |
367 | ret = i2c_smbus_write_byte_data(client, SRF08_WRITE_MAX_GAIN, value: regval); |
368 | if (ret < 0) { |
369 | dev_err(&client->dev, "write_sensitivity - err: %d\n" , ret); |
370 | mutex_unlock(lock: &data->lock); |
371 | return ret; |
372 | } |
373 | |
374 | data->sensitivity = val; |
375 | |
376 | mutex_unlock(lock: &data->lock); |
377 | |
378 | return 0; |
379 | } |
380 | |
381 | static ssize_t srf08_store_sensitivity(struct device *dev, |
382 | struct device_attribute *attr, |
383 | const char *buf, size_t len) |
384 | { |
385 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
386 | struct srf08_data *data = iio_priv(indio_dev); |
387 | int ret; |
388 | unsigned int val; |
389 | |
390 | ret = kstrtouint(s: buf, base: 10, res: &val); |
391 | if (ret) |
392 | return ret; |
393 | |
394 | ret = srf08_write_sensitivity(data, val); |
395 | if (ret < 0) |
396 | return ret; |
397 | |
398 | return len; |
399 | } |
400 | |
401 | static IIO_DEVICE_ATTR(sensor_sensitivity, S_IRUGO | S_IWUSR, |
402 | srf08_show_sensitivity, srf08_store_sensitivity, 0); |
403 | |
404 | static struct attribute *srf08_attributes[] = { |
405 | &iio_dev_attr_sensor_max_range.dev_attr.attr, |
406 | &iio_dev_attr_sensor_max_range_available.dev_attr.attr, |
407 | &iio_dev_attr_sensor_sensitivity.dev_attr.attr, |
408 | &iio_dev_attr_sensor_sensitivity_available.dev_attr.attr, |
409 | NULL, |
410 | }; |
411 | |
412 | static const struct attribute_group srf08_attribute_group = { |
413 | .attrs = srf08_attributes, |
414 | }; |
415 | |
416 | static const struct iio_chan_spec srf08_channels[] = { |
417 | { |
418 | .type = IIO_DISTANCE, |
419 | .info_mask_separate = |
420 | BIT(IIO_CHAN_INFO_RAW) | |
421 | BIT(IIO_CHAN_INFO_SCALE), |
422 | .scan_index = 0, |
423 | .scan_type = { |
424 | .sign = 's', |
425 | .realbits = 16, |
426 | .storagebits = 16, |
427 | .endianness = IIO_CPU, |
428 | }, |
429 | }, |
430 | IIO_CHAN_SOFT_TIMESTAMP(1), |
431 | }; |
432 | |
433 | static const struct iio_info srf08_info = { |
434 | .read_raw = srf08_read_raw, |
435 | .attrs = &srf08_attribute_group, |
436 | }; |
437 | |
438 | /* |
439 | * srf02 don't have an adjustable range or sensitivity, |
440 | * so we don't need attributes at all |
441 | */ |
442 | static const struct iio_info srf02_info = { |
443 | .read_raw = srf08_read_raw, |
444 | }; |
445 | |
446 | static int srf08_probe(struct i2c_client *client) |
447 | { |
448 | const struct i2c_device_id *id = i2c_client_get_device_id(client); |
449 | struct iio_dev *indio_dev; |
450 | struct srf08_data *data; |
451 | int ret; |
452 | |
453 | if (!i2c_check_functionality(adap: client->adapter, |
454 | I2C_FUNC_SMBUS_READ_BYTE_DATA | |
455 | I2C_FUNC_SMBUS_WRITE_BYTE_DATA | |
456 | I2C_FUNC_SMBUS_READ_WORD_DATA)) |
457 | return -ENODEV; |
458 | |
459 | indio_dev = devm_iio_device_alloc(parent: &client->dev, sizeof_priv: sizeof(*data)); |
460 | if (!indio_dev) |
461 | return -ENOMEM; |
462 | |
463 | data = iio_priv(indio_dev); |
464 | i2c_set_clientdata(client, data: indio_dev); |
465 | data->client = client; |
466 | data->sensor_type = (enum srf08_sensor_type)id->driver_data; |
467 | |
468 | switch (data->sensor_type) { |
469 | case SRF02: |
470 | data->chip_info = &srf02_chip_info; |
471 | indio_dev->info = &srf02_info; |
472 | break; |
473 | case SRF08: |
474 | data->chip_info = &srf08_chip_info; |
475 | indio_dev->info = &srf08_info; |
476 | break; |
477 | case SRF10: |
478 | data->chip_info = &srf10_chip_info; |
479 | indio_dev->info = &srf08_info; |
480 | break; |
481 | default: |
482 | return -EINVAL; |
483 | } |
484 | |
485 | indio_dev->name = id->name; |
486 | indio_dev->modes = INDIO_DIRECT_MODE; |
487 | indio_dev->channels = srf08_channels; |
488 | indio_dev->num_channels = ARRAY_SIZE(srf08_channels); |
489 | |
490 | mutex_init(&data->lock); |
491 | |
492 | ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, |
493 | iio_pollfunc_store_time, srf08_trigger_handler, NULL); |
494 | if (ret < 0) { |
495 | dev_err(&client->dev, "setup of iio triggered buffer failed\n" ); |
496 | return ret; |
497 | } |
498 | |
499 | if (data->chip_info->range_default) { |
500 | /* |
501 | * set default range of device in mm here |
502 | * these register values cannot be read from the hardware |
503 | * therefore set driver specific default values |
504 | * |
505 | * srf02 don't have a default value so it'll be omitted |
506 | */ |
507 | ret = srf08_write_range_mm(data, |
508 | val: data->chip_info->range_default); |
509 | if (ret < 0) |
510 | return ret; |
511 | } |
512 | |
513 | if (data->chip_info->sensitivity_default) { |
514 | /* |
515 | * set default sensitivity of device here |
516 | * these register values cannot be read from the hardware |
517 | * therefore set driver specific default values |
518 | * |
519 | * srf02 don't have a default value so it'll be omitted |
520 | */ |
521 | ret = srf08_write_sensitivity(data, |
522 | val: data->chip_info->sensitivity_default); |
523 | if (ret < 0) |
524 | return ret; |
525 | } |
526 | |
527 | return devm_iio_device_register(&client->dev, indio_dev); |
528 | } |
529 | |
530 | static const struct of_device_id of_srf08_match[] = { |
531 | { .compatible = "devantech,srf02" , (void *)SRF02 }, |
532 | { .compatible = "devantech,srf08" , (void *)SRF08 }, |
533 | { .compatible = "devantech,srf10" , (void *)SRF10 }, |
534 | {}, |
535 | }; |
536 | |
537 | MODULE_DEVICE_TABLE(of, of_srf08_match); |
538 | |
539 | static const struct i2c_device_id srf08_id[] = { |
540 | { "srf02" , SRF02 }, |
541 | { "srf08" , SRF08 }, |
542 | { "srf10" , SRF10 }, |
543 | { } |
544 | }; |
545 | MODULE_DEVICE_TABLE(i2c, srf08_id); |
546 | |
547 | static struct i2c_driver srf08_driver = { |
548 | .driver = { |
549 | .name = "srf08" , |
550 | .of_match_table = of_srf08_match, |
551 | }, |
552 | .probe = srf08_probe, |
553 | .id_table = srf08_id, |
554 | }; |
555 | module_i2c_driver(srf08_driver); |
556 | |
557 | MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>" ); |
558 | MODULE_DESCRIPTION("Devantech SRF02/SRF08/SRF10 i2c ultrasonic ranger driver" ); |
559 | MODULE_LICENSE("GPL" ); |
560 | |