1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * SRF04: ultrasonic sensor for distance measuring by using GPIOs 4 * 5 * Copyright (c) 2017 Andreas Klinger <ak@it-klinger.de> 6 * 7 * For details about the device see: 8 * http://www.robot-electronics.co.uk/htm/srf04tech.htm 9 * 10 * the measurement cycle as timing diagram looks like: 11 * 12 * +---+ 13 * GPIO | | 14 * trig: --+ +------------------------------------------------------ 15 * ^ ^ 16 * |<->| 17 * udelay(trigger_pulse_us) 18 * 19 * ultra +-+ +-+ +-+ 20 * sonic | | | | | | 21 * burst: ---------+ +-+ +-+ +----------------------------------------- 22 * . 23 * ultra . +-+ +-+ +-+ 24 * sonic . | | | | | | 25 * echo: ----------------------------------+ +-+ +-+ +---------------- 26 * . . 27 * +------------------------+ 28 * GPIO | | 29 * echo: -------------------+ +--------------- 30 * ^ ^ 31 * interrupt interrupt 32 * (ts_rising) (ts_falling) 33 * |<---------------------->| 34 * pulse time measured 35 * --> one round trip of ultra sonic waves 36 */ 37 #include <linux/err.h> 38 #include <linux/gpio/consumer.h> 39 #include <linux/kernel.h> 40 #include <linux/module.h> 41 #include <linux/of.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> 50 51 struct srf04_cfg { 52 unsigned long trigger_pulse_us; 53 }; 54 55 struct srf04_data { 56 struct device *dev; 57 struct gpio_desc *gpiod_trig; 58 struct gpio_desc *gpiod_echo; 59 struct mutex lock; 60 int irqnr; 61 ktime_t ts_rising; 62 ktime_t ts_falling; 63 struct completion rising; 64 struct completion falling; 65 const struct srf04_cfg *cfg; 66 }; 67 68 static const struct srf04_cfg srf04_cfg = { 69 .trigger_pulse_us = 10, 70 }; 71 72 static const struct srf04_cfg mb_lv_cfg = { 73 .trigger_pulse_us = 20, 74 }; 75 76 static irqreturn_t srf04_handle_irq(int irq, void *dev_id) 77 { 78 struct iio_dev *indio_dev = dev_id; 79 struct srf04_data *data = iio_priv(indio_dev); 80 ktime_t now = ktime_get(); 81 82 if (gpiod_get_value(data->gpiod_echo)) { 83 data->ts_rising = now; 84 complete(&data->rising); 85 } else { 86 data->ts_falling = now; 87 complete(&data->falling); 88 } 89 90 return IRQ_HANDLED; 91 } 92 93 static int srf04_read(struct srf04_data *data) 94 { 95 int ret; 96 ktime_t ktime_dt; 97 u64 dt_ns; 98 u32 time_ns, distance_mm; 99 100 /* 101 * just one read-echo-cycle can take place at a time 102 * ==> lock against concurrent reading calls 103 */ 104 mutex_lock(&data->lock); 105 106 reinit_completion(&data->rising); 107 reinit_completion(&data->falling); 108 109 gpiod_set_value(data->gpiod_trig, 1); 110 udelay(data->cfg->trigger_pulse_us); 111 gpiod_set_value(data->gpiod_trig, 0); 112 113 /* it should not take more than 20 ms until echo is rising */ 114 ret = wait_for_completion_killable_timeout(&data->rising, HZ/50); 115 if (ret < 0) { 116 mutex_unlock(&data->lock); 117 return ret; 118 } else if (ret == 0) { 119 mutex_unlock(&data->lock); 120 return -ETIMEDOUT; 121 } 122 123 /* it cannot take more than 50 ms until echo is falling */ 124 ret = wait_for_completion_killable_timeout(&data->falling, HZ/20); 125 if (ret < 0) { 126 mutex_unlock(&data->lock); 127 return ret; 128 } else if (ret == 0) { 129 mutex_unlock(&data->lock); 130 return -ETIMEDOUT; 131 } 132 133 ktime_dt = ktime_sub(data->ts_falling, data->ts_rising); 134 135 mutex_unlock(&data->lock); 136 137 dt_ns = ktime_to_ns(ktime_dt); 138 /* 139 * measuring more than 6,45 meters is beyond the capabilities of 140 * the supported sensors 141 * ==> filter out invalid results for not measuring echos of 142 * another us sensor 143 * 144 * formula: 145 * distance 6,45 * 2 m 146 * time = ---------- = ------------ = 40438871 ns 147 * speed 319 m/s 148 * 149 * using a minimum speed at -20 °C of 319 m/s 150 */ 151 if (dt_ns > 40438871) 152 return -EIO; 153 154 time_ns = dt_ns; 155 156 /* 157 * the speed as function of the temperature is approximately: 158 * 159 * speed = 331,5 + 0,6 * Temp 160 * with Temp in °C 161 * and speed in m/s 162 * 163 * use 343,5 m/s as ultrasonic speed at 20 °C here in absence of the 164 * temperature 165 * 166 * therefore: 167 * time 343,5 time * 106 168 * distance = ------ * ------- = ------------ 169 * 10^6 2 617176 170 * with time in ns 171 * and distance in mm (one way) 172 * 173 * because we limit to 6,45 meters the multiplication with 106 just 174 * fits into 32 bit 175 */ 176 distance_mm = time_ns * 106 / 617176; 177 178 return distance_mm; 179 } 180 181 static int srf04_read_raw(struct iio_dev *indio_dev, 182 struct iio_chan_spec const *channel, int *val, 183 int *val2, long info) 184 { 185 struct srf04_data *data = iio_priv(indio_dev); 186 int ret; 187 188 if (channel->type != IIO_DISTANCE) 189 return -EINVAL; 190 191 switch (info) { 192 case IIO_CHAN_INFO_RAW: 193 ret = srf04_read(data); 194 if (ret < 0) 195 return ret; 196 *val = ret; 197 return IIO_VAL_INT; 198 case IIO_CHAN_INFO_SCALE: 199 /* 200 * theoretical maximum resolution is 3 mm 201 * 1 LSB is 1 mm 202 */ 203 *val = 0; 204 *val2 = 1000; 205 return IIO_VAL_INT_PLUS_MICRO; 206 default: 207 return -EINVAL; 208 } 209 } 210 211 static const struct iio_info srf04_iio_info = { 212 .read_raw = srf04_read_raw, 213 }; 214 215 static const struct iio_chan_spec srf04_chan_spec[] = { 216 { 217 .type = IIO_DISTANCE, 218 .info_mask_separate = 219 BIT(IIO_CHAN_INFO_RAW) | 220 BIT(IIO_CHAN_INFO_SCALE), 221 }, 222 }; 223 224 static const struct of_device_id of_srf04_match[] = { 225 { .compatible = "devantech,srf04", .data = &srf04_cfg}, 226 { .compatible = "maxbotix,mb1000", .data = &mb_lv_cfg}, 227 { .compatible = "maxbotix,mb1010", .data = &mb_lv_cfg}, 228 { .compatible = "maxbotix,mb1020", .data = &mb_lv_cfg}, 229 { .compatible = "maxbotix,mb1030", .data = &mb_lv_cfg}, 230 { .compatible = "maxbotix,mb1040", .data = &mb_lv_cfg}, 231 {}, 232 }; 233 234 MODULE_DEVICE_TABLE(of, of_srf04_match); 235 236 static int srf04_probe(struct platform_device *pdev) 237 { 238 struct device *dev = &pdev->dev; 239 struct srf04_data *data; 240 struct iio_dev *indio_dev; 241 int ret; 242 243 indio_dev = devm_iio_device_alloc(dev, sizeof(struct srf04_data)); 244 if (!indio_dev) { 245 dev_err(dev, "failed to allocate IIO device\n"); 246 return -ENOMEM; 247 } 248 249 data = iio_priv(indio_dev); 250 data->dev = dev; 251 data->cfg = of_match_device(of_srf04_match, dev)->data; 252 253 mutex_init(&data->lock); 254 init_completion(&data->rising); 255 init_completion(&data->falling); 256 257 data->gpiod_trig = devm_gpiod_get(dev, "trig", GPIOD_OUT_LOW); 258 if (IS_ERR(data->gpiod_trig)) { 259 dev_err(dev, "failed to get trig-gpios: err=%ld\n", 260 PTR_ERR(data->gpiod_trig)); 261 return PTR_ERR(data->gpiod_trig); 262 } 263 264 data->gpiod_echo = devm_gpiod_get(dev, "echo", GPIOD_IN); 265 if (IS_ERR(data->gpiod_echo)) { 266 dev_err(dev, "failed to get echo-gpios: err=%ld\n", 267 PTR_ERR(data->gpiod_echo)); 268 return PTR_ERR(data->gpiod_echo); 269 } 270 271 if (gpiod_cansleep(data->gpiod_echo)) { 272 dev_err(data->dev, "cansleep-GPIOs not supported\n"); 273 return -ENODEV; 274 } 275 276 data->irqnr = gpiod_to_irq(data->gpiod_echo); 277 if (data->irqnr < 0) { 278 dev_err(data->dev, "gpiod_to_irq: %d\n", data->irqnr); 279 return data->irqnr; 280 } 281 282 ret = devm_request_irq(dev, data->irqnr, srf04_handle_irq, 283 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 284 pdev->name, indio_dev); 285 if (ret < 0) { 286 dev_err(data->dev, "request_irq: %d\n", ret); 287 return ret; 288 } 289 290 platform_set_drvdata(pdev, indio_dev); 291 292 indio_dev->name = "srf04"; 293 indio_dev->dev.parent = &pdev->dev; 294 indio_dev->info = &srf04_iio_info; 295 indio_dev->modes = INDIO_DIRECT_MODE; 296 indio_dev->channels = srf04_chan_spec; 297 indio_dev->num_channels = ARRAY_SIZE(srf04_chan_spec); 298 299 return devm_iio_device_register(dev, indio_dev); 300 } 301 302 static struct platform_driver srf04_driver = { 303 .probe = srf04_probe, 304 .driver = { 305 .name = "srf04-gpio", 306 .of_match_table = of_srf04_match, 307 }, 308 }; 309 310 module_platform_driver(srf04_driver); 311 312 MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>"); 313 MODULE_DESCRIPTION("SRF04 ultrasonic sensor for distance measuring using GPIOs"); 314 MODULE_LICENSE("GPL"); 315 MODULE_ALIAS("platform:srf04"); 316