root/drivers/iio/proximity/srf04.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. srf04_handle_irq
  2. srf04_read
  3. srf04_read_raw
  4. srf04_probe

   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");

/* [<][>][^][v][top][bottom][index][help] */