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