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