linux/drivers/iio/proximity/srf04.c
<<
>>
Prefs
   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 * https://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/pm_runtime.h>
  49#include <linux/iio/iio.h>
  50#include <linux/iio/sysfs.h>
  51
  52struct srf04_cfg {
  53        unsigned long trigger_pulse_us;
  54};
  55
  56struct srf04_data {
  57        struct device           *dev;
  58        struct gpio_desc        *gpiod_trig;
  59        struct gpio_desc        *gpiod_echo;
  60        struct gpio_desc        *gpiod_power;
  61        struct mutex            lock;
  62        int                     irqnr;
  63        ktime_t                 ts_rising;
  64        ktime_t                 ts_falling;
  65        struct completion       rising;
  66        struct completion       falling;
  67        const struct srf04_cfg  *cfg;
  68        int                     startup_time_ms;
  69};
  70
  71static const struct srf04_cfg srf04_cfg = {
  72        .trigger_pulse_us = 10,
  73};
  74
  75static const struct srf04_cfg mb_lv_cfg = {
  76        .trigger_pulse_us = 20,
  77};
  78
  79static irqreturn_t srf04_handle_irq(int irq, void *dev_id)
  80{
  81        struct iio_dev *indio_dev = dev_id;
  82        struct srf04_data *data = iio_priv(indio_dev);
  83        ktime_t now = ktime_get();
  84
  85        if (gpiod_get_value(data->gpiod_echo)) {
  86                data->ts_rising = now;
  87                complete(&data->rising);
  88        } else {
  89                data->ts_falling = now;
  90                complete(&data->falling);
  91        }
  92
  93        return IRQ_HANDLED;
  94}
  95
  96static int srf04_read(struct srf04_data *data)
  97{
  98        int ret;
  99        ktime_t ktime_dt;
 100        u64 dt_ns;
 101        u32 time_ns, distance_mm;
 102
 103        if (data->gpiod_power) {
 104                ret = pm_runtime_resume_and_get(data->dev);
 105                if (ret < 0)
 106                        return ret;
 107        }
 108        /*
 109         * just one read-echo-cycle can take place at a time
 110         * ==> lock against concurrent reading calls
 111         */
 112        mutex_lock(&data->lock);
 113
 114        reinit_completion(&data->rising);
 115        reinit_completion(&data->falling);
 116
 117        gpiod_set_value(data->gpiod_trig, 1);
 118        udelay(data->cfg->trigger_pulse_us);
 119        gpiod_set_value(data->gpiod_trig, 0);
 120
 121        if (data->gpiod_power) {
 122                pm_runtime_mark_last_busy(data->dev);
 123                pm_runtime_put_autosuspend(data->dev);
 124        }
 125
 126        /* it should not take more than 20 ms until echo is rising */
 127        ret = wait_for_completion_killable_timeout(&data->rising, HZ/50);
 128        if (ret < 0) {
 129                mutex_unlock(&data->lock);
 130                return ret;
 131        } else if (ret == 0) {
 132                mutex_unlock(&data->lock);
 133                return -ETIMEDOUT;
 134        }
 135
 136        /* it cannot take more than 50 ms until echo is falling */
 137        ret = wait_for_completion_killable_timeout(&data->falling, HZ/20);
 138        if (ret < 0) {
 139                mutex_unlock(&data->lock);
 140                return ret;
 141        } else if (ret == 0) {
 142                mutex_unlock(&data->lock);
 143                return -ETIMEDOUT;
 144        }
 145
 146        ktime_dt = ktime_sub(data->ts_falling, data->ts_rising);
 147
 148        mutex_unlock(&data->lock);
 149
 150        dt_ns = ktime_to_ns(ktime_dt);
 151        /*
 152         * measuring more than 6,45 meters is beyond the capabilities of
 153         * the supported sensors
 154         * ==> filter out invalid results for not measuring echos of
 155         *     another us sensor
 156         *
 157         * formula:
 158         *         distance     6,45 * 2 m
 159         * time = ---------- = ------------ = 40438871 ns
 160         *          speed         319 m/s
 161         *
 162         * using a minimum speed at -20 °C of 319 m/s
 163         */
 164        if (dt_ns > 40438871)
 165                return -EIO;
 166
 167        time_ns = dt_ns;
 168
 169        /*
 170         * the speed as function of the temperature is approximately:
 171         *
 172         * speed = 331,5 + 0,6 * Temp
 173         *   with Temp in °C
 174         *   and speed in m/s
 175         *
 176         * use 343,5 m/s as ultrasonic speed at 20 °C here in absence of the
 177         * temperature
 178         *
 179         * therefore:
 180         *             time     343,5     time * 106
 181         * distance = ------ * ------- = ------------
 182         *             10^6         2         617176
 183         *   with time in ns
 184         *   and distance in mm (one way)
 185         *
 186         * because we limit to 6,45 meters the multiplication with 106 just
 187         * fits into 32 bit
 188         */
 189        distance_mm = time_ns * 106 / 617176;
 190
 191        return distance_mm;
 192}
 193
 194static int srf04_read_raw(struct iio_dev *indio_dev,
 195                            struct iio_chan_spec const *channel, int *val,
 196                            int *val2, long info)
 197{
 198        struct srf04_data *data = iio_priv(indio_dev);
 199        int ret;
 200
 201        if (channel->type != IIO_DISTANCE)
 202                return -EINVAL;
 203
 204        switch (info) {
 205        case IIO_CHAN_INFO_RAW:
 206                ret = srf04_read(data);
 207                if (ret < 0)
 208                        return ret;
 209                *val = ret;
 210                return IIO_VAL_INT;
 211        case IIO_CHAN_INFO_SCALE:
 212                /*
 213                 * theoretical maximum resolution is 3 mm
 214                 * 1 LSB is 1 mm
 215                 */
 216                *val = 0;
 217                *val2 = 1000;
 218                return IIO_VAL_INT_PLUS_MICRO;
 219        default:
 220                return -EINVAL;
 221        }
 222}
 223
 224static const struct iio_info srf04_iio_info = {
 225        .read_raw               = srf04_read_raw,
 226};
 227
 228static const struct iio_chan_spec srf04_chan_spec[] = {
 229        {
 230                .type = IIO_DISTANCE,
 231                .info_mask_separate =
 232                                BIT(IIO_CHAN_INFO_RAW) |
 233                                BIT(IIO_CHAN_INFO_SCALE),
 234        },
 235};
 236
 237static const struct of_device_id of_srf04_match[] = {
 238        { .compatible = "devantech,srf04", .data = &srf04_cfg},
 239        { .compatible = "maxbotix,mb1000", .data = &mb_lv_cfg},
 240        { .compatible = "maxbotix,mb1010", .data = &mb_lv_cfg},
 241        { .compatible = "maxbotix,mb1020", .data = &mb_lv_cfg},
 242        { .compatible = "maxbotix,mb1030", .data = &mb_lv_cfg},
 243        { .compatible = "maxbotix,mb1040", .data = &mb_lv_cfg},
 244        {},
 245};
 246
 247MODULE_DEVICE_TABLE(of, of_srf04_match);
 248
 249static int srf04_probe(struct platform_device *pdev)
 250{
 251        struct device *dev = &pdev->dev;
 252        struct srf04_data *data;
 253        struct iio_dev *indio_dev;
 254        int ret;
 255
 256        indio_dev = devm_iio_device_alloc(dev, sizeof(struct srf04_data));
 257        if (!indio_dev) {
 258                dev_err(dev, "failed to allocate IIO device\n");
 259                return -ENOMEM;
 260        }
 261
 262        data = iio_priv(indio_dev);
 263        data->dev = dev;
 264        data->cfg = of_match_device(of_srf04_match, dev)->data;
 265
 266        mutex_init(&data->lock);
 267        init_completion(&data->rising);
 268        init_completion(&data->falling);
 269
 270        data->gpiod_trig = devm_gpiod_get(dev, "trig", GPIOD_OUT_LOW);
 271        if (IS_ERR(data->gpiod_trig)) {
 272                dev_err(dev, "failed to get trig-gpios: err=%ld\n",
 273                                        PTR_ERR(data->gpiod_trig));
 274                return PTR_ERR(data->gpiod_trig);
 275        }
 276
 277        data->gpiod_echo = devm_gpiod_get(dev, "echo", GPIOD_IN);
 278        if (IS_ERR(data->gpiod_echo)) {
 279                dev_err(dev, "failed to get echo-gpios: err=%ld\n",
 280                                        PTR_ERR(data->gpiod_echo));
 281                return PTR_ERR(data->gpiod_echo);
 282        }
 283
 284        data->gpiod_power = devm_gpiod_get_optional(dev, "power",
 285                                                                GPIOD_OUT_LOW);
 286        if (IS_ERR(data->gpiod_power)) {
 287                dev_err(dev, "failed to get power-gpios: err=%ld\n",
 288                                                PTR_ERR(data->gpiod_power));
 289                return PTR_ERR(data->gpiod_power);
 290        }
 291        if (data->gpiod_power) {
 292
 293                if (of_property_read_u32(dev->of_node, "startup-time-ms",
 294                                                &data->startup_time_ms))
 295                        data->startup_time_ms = 100;
 296                dev_dbg(dev, "using power gpio: startup-time-ms=%d\n",
 297                                                        data->startup_time_ms);
 298        }
 299
 300        if (gpiod_cansleep(data->gpiod_echo)) {
 301                dev_err(data->dev, "cansleep-GPIOs not supported\n");
 302                return -ENODEV;
 303        }
 304
 305        data->irqnr = gpiod_to_irq(data->gpiod_echo);
 306        if (data->irqnr < 0) {
 307                dev_err(data->dev, "gpiod_to_irq: %d\n", data->irqnr);
 308                return data->irqnr;
 309        }
 310
 311        ret = devm_request_irq(dev, data->irqnr, srf04_handle_irq,
 312                        IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
 313                        pdev->name, indio_dev);
 314        if (ret < 0) {
 315                dev_err(data->dev, "request_irq: %d\n", ret);
 316                return ret;
 317        }
 318
 319        platform_set_drvdata(pdev, indio_dev);
 320
 321        indio_dev->name = "srf04";
 322        indio_dev->info = &srf04_iio_info;
 323        indio_dev->modes = INDIO_DIRECT_MODE;
 324        indio_dev->channels = srf04_chan_spec;
 325        indio_dev->num_channels = ARRAY_SIZE(srf04_chan_spec);
 326
 327        ret = iio_device_register(indio_dev);
 328        if (ret < 0) {
 329                dev_err(data->dev, "iio_device_register: %d\n", ret);
 330                return ret;
 331        }
 332
 333        if (data->gpiod_power) {
 334                pm_runtime_set_autosuspend_delay(data->dev, 1000);
 335                pm_runtime_use_autosuspend(data->dev);
 336
 337                ret = pm_runtime_set_active(data->dev);
 338                if (ret) {
 339                        dev_err(data->dev, "pm_runtime_set_active: %d\n", ret);
 340                        iio_device_unregister(indio_dev);
 341                }
 342
 343                pm_runtime_enable(data->dev);
 344                pm_runtime_idle(data->dev);
 345        }
 346
 347        return ret;
 348}
 349
 350static int srf04_remove(struct platform_device *pdev)
 351{
 352        struct iio_dev *indio_dev = platform_get_drvdata(pdev);
 353        struct srf04_data *data = iio_priv(indio_dev);
 354
 355        iio_device_unregister(indio_dev);
 356
 357        if (data->gpiod_power) {
 358                pm_runtime_disable(data->dev);
 359                pm_runtime_set_suspended(data->dev);
 360        }
 361
 362        return 0;
 363}
 364
 365static int __maybe_unused srf04_pm_runtime_suspend(struct device *dev)
 366{
 367        struct platform_device *pdev = container_of(dev,
 368                                                struct platform_device, dev);
 369        struct iio_dev *indio_dev = platform_get_drvdata(pdev);
 370        struct srf04_data *data = iio_priv(indio_dev);
 371
 372        gpiod_set_value(data->gpiod_power, 0);
 373
 374        return 0;
 375}
 376
 377static int __maybe_unused srf04_pm_runtime_resume(struct device *dev)
 378{
 379        struct platform_device *pdev = container_of(dev,
 380                                                struct platform_device, dev);
 381        struct iio_dev *indio_dev = platform_get_drvdata(pdev);
 382        struct srf04_data *data = iio_priv(indio_dev);
 383
 384        gpiod_set_value(data->gpiod_power, 1);
 385        msleep(data->startup_time_ms);
 386
 387        return 0;
 388}
 389
 390static const struct dev_pm_ops srf04_pm_ops = {
 391        SET_RUNTIME_PM_OPS(srf04_pm_runtime_suspend,
 392                                srf04_pm_runtime_resume, NULL)
 393};
 394
 395static struct platform_driver srf04_driver = {
 396        .probe          = srf04_probe,
 397        .remove         = srf04_remove,
 398        .driver         = {
 399                .name           = "srf04-gpio",
 400                .of_match_table = of_srf04_match,
 401                .pm             = &srf04_pm_ops,
 402        },
 403};
 404
 405module_platform_driver(srf04_driver);
 406
 407MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
 408MODULE_DESCRIPTION("SRF04 ultrasonic sensor for distance measuring using GPIOs");
 409MODULE_LICENSE("GPL");
 410MODULE_ALIAS("platform:srf04");
 411