1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * SRF04: ultrasonic sensor for distance measuring by using GPIOs
5 * Copyright (c) 2017 Andreas Klinger <ak@it-klinger.de>
7 * For details about the device see:
8 * http://www.robot-electronics.co.uk/htm/srf04tech.htm
10 * the measurement cycle as timing diagram looks like:
14 * trig: --+ +------------------------------------------------------
17 * udelay(trigger_pulse_us)
21 * burst: ---------+ +-+ +-+ +-----------------------------------------
25 * echo: ----------------------------------+ +-+ +-+ +----------------
27 * +------------------------+
29 * echo: -------------------+ +---------------
32 * (ts_rising) (ts_falling)
33 * |<---------------------->|
35 * --> one round trip of ultra sonic waves
37 #include <linux/err.h>
38 #include <linux/gpio/consumer.h>
39 #include <linux/kernel.h>
40 #include <linux/module.h>
42 #include <linux/of_device.h>
43 #include <linux/platform_device.h>
44 #include <linux/property.h>
45 #include <linux/sched.h>
46 #include <linux/interrupt.h>
47 #include <linux/delay.h>
48 #include <linux/iio/iio.h>
49 #include <linux/iio/sysfs.h>
52 unsigned long trigger_pulse_us
;
57 struct gpio_desc
*gpiod_trig
;
58 struct gpio_desc
*gpiod_echo
;
63 struct completion rising
;
64 struct completion falling
;
65 const struct srf04_cfg
*cfg
;
68 static const struct srf04_cfg srf04_cfg
= {
69 .trigger_pulse_us
= 10,
72 static const struct srf04_cfg mb_lv_cfg
= {
73 .trigger_pulse_us
= 20,
76 static irqreturn_t
srf04_handle_irq(int irq
, void *dev_id
)
78 struct iio_dev
*indio_dev
= dev_id
;
79 struct srf04_data
*data
= iio_priv(indio_dev
);
80 ktime_t now
= ktime_get();
82 if (gpiod_get_value(data
->gpiod_echo
)) {
83 data
->ts_rising
= now
;
84 complete(&data
->rising
);
86 data
->ts_falling
= now
;
87 complete(&data
->falling
);
93 static int srf04_read(struct srf04_data
*data
)
98 u32 time_ns
, distance_mm
;
101 * just one read-echo-cycle can take place at a time
102 * ==> lock against concurrent reading calls
104 mutex_lock(&data
->lock
);
106 reinit_completion(&data
->rising
);
107 reinit_completion(&data
->falling
);
109 gpiod_set_value(data
->gpiod_trig
, 1);
110 udelay(data
->cfg
->trigger_pulse_us
);
111 gpiod_set_value(data
->gpiod_trig
, 0);
113 /* it cannot take more than 20 ms */
114 ret
= wait_for_completion_killable_timeout(&data
->rising
, HZ
/50);
116 mutex_unlock(&data
->lock
);
118 } else if (ret
== 0) {
119 mutex_unlock(&data
->lock
);
123 ret
= wait_for_completion_killable_timeout(&data
->falling
, HZ
/50);
125 mutex_unlock(&data
->lock
);
127 } else if (ret
== 0) {
128 mutex_unlock(&data
->lock
);
132 ktime_dt
= ktime_sub(data
->ts_falling
, data
->ts_rising
);
134 mutex_unlock(&data
->lock
);
136 dt_ns
= ktime_to_ns(ktime_dt
);
138 * measuring more than 3 meters is beyond the capabilities of
140 * ==> filter out invalid results for not measuring echos of
145 * time = ---------- = --------- = 9404389 ns
148 * using a minimum speed at -20 °C of 319 m/s
156 * the speed as function of the temperature is approximately:
158 * speed = 331,5 + 0,6 * Temp
162 * use 343 m/s as ultrasonic speed at 20 °C here in absence of the
167 * distance = ------ * -----
170 * and distance in mm (one way)
172 * because we limit to 3 meters the multiplication with 343 just
175 distance_mm
= time_ns
* 343 / 2000000;
180 static int srf04_read_raw(struct iio_dev
*indio_dev
,
181 struct iio_chan_spec
const *channel
, int *val
,
182 int *val2
, long info
)
184 struct srf04_data
*data
= iio_priv(indio_dev
);
187 if (channel
->type
!= IIO_DISTANCE
)
191 case IIO_CHAN_INFO_RAW
:
192 ret
= srf04_read(data
);
197 case IIO_CHAN_INFO_SCALE
:
199 * theoretical maximum resolution is 3 mm
204 return IIO_VAL_INT_PLUS_MICRO
;
210 static const struct iio_info srf04_iio_info
= {
211 .read_raw
= srf04_read_raw
,
214 static const struct iio_chan_spec srf04_chan_spec
[] = {
216 .type
= IIO_DISTANCE
,
217 .info_mask_separate
=
218 BIT(IIO_CHAN_INFO_RAW
) |
219 BIT(IIO_CHAN_INFO_SCALE
),
223 static const struct of_device_id of_srf04_match
[] = {
224 { .compatible
= "devantech,srf04", .data
= &srf04_cfg
},
225 { .compatible
= "maxbotix,mb1000", .data
= &mb_lv_cfg
},
226 { .compatible
= "maxbotix,mb1010", .data
= &mb_lv_cfg
},
227 { .compatible
= "maxbotix,mb1020", .data
= &mb_lv_cfg
},
228 { .compatible
= "maxbotix,mb1030", .data
= &mb_lv_cfg
},
229 { .compatible
= "maxbotix,mb1040", .data
= &mb_lv_cfg
},
233 MODULE_DEVICE_TABLE(of
, of_srf04_match
);
235 static int srf04_probe(struct platform_device
*pdev
)
237 struct device
*dev
= &pdev
->dev
;
238 struct srf04_data
*data
;
239 struct iio_dev
*indio_dev
;
242 indio_dev
= devm_iio_device_alloc(dev
, sizeof(struct srf04_data
));
244 dev_err(dev
, "failed to allocate IIO device\n");
248 data
= iio_priv(indio_dev
);
250 data
->cfg
= of_match_device(of_srf04_match
, dev
)->data
;
252 mutex_init(&data
->lock
);
253 init_completion(&data
->rising
);
254 init_completion(&data
->falling
);
256 data
->gpiod_trig
= devm_gpiod_get(dev
, "trig", GPIOD_OUT_LOW
);
257 if (IS_ERR(data
->gpiod_trig
)) {
258 dev_err(dev
, "failed to get trig-gpios: err=%ld\n",
259 PTR_ERR(data
->gpiod_trig
));
260 return PTR_ERR(data
->gpiod_trig
);
263 data
->gpiod_echo
= devm_gpiod_get(dev
, "echo", GPIOD_IN
);
264 if (IS_ERR(data
->gpiod_echo
)) {
265 dev_err(dev
, "failed to get echo-gpios: err=%ld\n",
266 PTR_ERR(data
->gpiod_echo
));
267 return PTR_ERR(data
->gpiod_echo
);
270 if (gpiod_cansleep(data
->gpiod_echo
)) {
271 dev_err(data
->dev
, "cansleep-GPIOs not supported\n");
275 data
->irqnr
= gpiod_to_irq(data
->gpiod_echo
);
276 if (data
->irqnr
< 0) {
277 dev_err(data
->dev
, "gpiod_to_irq: %d\n", data
->irqnr
);
281 ret
= devm_request_irq(dev
, data
->irqnr
, srf04_handle_irq
,
282 IRQF_TRIGGER_RISING
| IRQF_TRIGGER_FALLING
,
283 pdev
->name
, indio_dev
);
285 dev_err(data
->dev
, "request_irq: %d\n", ret
);
289 platform_set_drvdata(pdev
, indio_dev
);
291 indio_dev
->name
= "srf04";
292 indio_dev
->dev
.parent
= &pdev
->dev
;
293 indio_dev
->info
= &srf04_iio_info
;
294 indio_dev
->modes
= INDIO_DIRECT_MODE
;
295 indio_dev
->channels
= srf04_chan_spec
;
296 indio_dev
->num_channels
= ARRAY_SIZE(srf04_chan_spec
);
298 return devm_iio_device_register(dev
, indio_dev
);
301 static struct platform_driver srf04_driver
= {
302 .probe
= srf04_probe
,
304 .name
= "srf04-gpio",
305 .of_match_table
= of_srf04_match
,
309 module_platform_driver(srf04_driver
);
311 MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
312 MODULE_DESCRIPTION("SRF04 ultrasonic sensor for distance measuring using GPIOs");
313 MODULE_LICENSE("GPL");
314 MODULE_ALIAS("platform:srf04");