Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * SRF04: ultrasonic sensor for distance measuring by using GPIOs
0004  *
0005  * Copyright (c) 2017 Andreas Klinger <ak@it-klinger.de>
0006  *
0007  * For details about the device see:
0008  * https://www.robot-electronics.co.uk/htm/srf04tech.htm
0009  *
0010  * the measurement cycle as timing diagram looks like:
0011  *
0012  *          +---+
0013  * GPIO     |   |
0014  * trig:  --+   +------------------------------------------------------
0015  *          ^   ^
0016  *          |<->|
0017  *         udelay(trigger_pulse_us)
0018  *
0019  * ultra           +-+ +-+ +-+
0020  * sonic           | | | | | |
0021  * burst: ---------+ +-+ +-+ +-----------------------------------------
0022  *                           .
0023  * ultra                     .              +-+ +-+ +-+
0024  * sonic                     .              | | | | | |
0025  * echo:  ----------------------------------+ +-+ +-+ +----------------
0026  *                           .                        .
0027  *                           +------------------------+
0028  * GPIO                      |                        |
0029  * echo:  -------------------+                        +---------------
0030  *                           ^                        ^
0031  *                           interrupt                interrupt
0032  *                           (ts_rising)              (ts_falling)
0033  *                           |<---------------------->|
0034  *                              pulse time measured
0035  *                              --> one round trip of ultra sonic waves
0036  */
0037 #include <linux/err.h>
0038 #include <linux/gpio/consumer.h>
0039 #include <linux/kernel.h>
0040 #include <linux/mod_devicetable.h>
0041 #include <linux/module.h>
0042 #include <linux/platform_device.h>
0043 #include <linux/property.h>
0044 #include <linux/sched.h>
0045 #include <linux/interrupt.h>
0046 #include <linux/delay.h>
0047 #include <linux/pm_runtime.h>
0048 #include <linux/iio/iio.h>
0049 #include <linux/iio/sysfs.h>
0050 
0051 struct srf04_cfg {
0052     unsigned long trigger_pulse_us;
0053 };
0054 
0055 struct srf04_data {
0056     struct device       *dev;
0057     struct gpio_desc    *gpiod_trig;
0058     struct gpio_desc    *gpiod_echo;
0059     struct gpio_desc    *gpiod_power;
0060     struct mutex        lock;
0061     int         irqnr;
0062     ktime_t         ts_rising;
0063     ktime_t         ts_falling;
0064     struct completion   rising;
0065     struct completion   falling;
0066     const struct srf04_cfg  *cfg;
0067     int         startup_time_ms;
0068 };
0069 
0070 static const struct srf04_cfg srf04_cfg = {
0071     .trigger_pulse_us = 10,
0072 };
0073 
0074 static const struct srf04_cfg mb_lv_cfg = {
0075     .trigger_pulse_us = 20,
0076 };
0077 
0078 static irqreturn_t srf04_handle_irq(int irq, void *dev_id)
0079 {
0080     struct iio_dev *indio_dev = dev_id;
0081     struct srf04_data *data = iio_priv(indio_dev);
0082     ktime_t now = ktime_get();
0083 
0084     if (gpiod_get_value(data->gpiod_echo)) {
0085         data->ts_rising = now;
0086         complete(&data->rising);
0087     } else {
0088         data->ts_falling = now;
0089         complete(&data->falling);
0090     }
0091 
0092     return IRQ_HANDLED;
0093 }
0094 
0095 static int srf04_read(struct srf04_data *data)
0096 {
0097     int ret;
0098     ktime_t ktime_dt;
0099     u64 dt_ns;
0100     u32 time_ns, distance_mm;
0101 
0102     if (data->gpiod_power) {
0103         ret = pm_runtime_resume_and_get(data->dev);
0104         if (ret < 0)
0105             return ret;
0106     }
0107     /*
0108      * just one read-echo-cycle can take place at a time
0109      * ==> lock against concurrent reading calls
0110      */
0111     mutex_lock(&data->lock);
0112 
0113     reinit_completion(&data->rising);
0114     reinit_completion(&data->falling);
0115 
0116     gpiod_set_value(data->gpiod_trig, 1);
0117     udelay(data->cfg->trigger_pulse_us);
0118     gpiod_set_value(data->gpiod_trig, 0);
0119 
0120     if (data->gpiod_power) {
0121         pm_runtime_mark_last_busy(data->dev);
0122         pm_runtime_put_autosuspend(data->dev);
0123     }
0124 
0125     /* it should not take more than 20 ms until echo is rising */
0126     ret = wait_for_completion_killable_timeout(&data->rising, HZ/50);
0127     if (ret < 0) {
0128         mutex_unlock(&data->lock);
0129         return ret;
0130     } else if (ret == 0) {
0131         mutex_unlock(&data->lock);
0132         return -ETIMEDOUT;
0133     }
0134 
0135     /* it cannot take more than 50 ms until echo is falling */
0136     ret = wait_for_completion_killable_timeout(&data->falling, HZ/20);
0137     if (ret < 0) {
0138         mutex_unlock(&data->lock);
0139         return ret;
0140     } else if (ret == 0) {
0141         mutex_unlock(&data->lock);
0142         return -ETIMEDOUT;
0143     }
0144 
0145     ktime_dt = ktime_sub(data->ts_falling, data->ts_rising);
0146 
0147     mutex_unlock(&data->lock);
0148 
0149     dt_ns = ktime_to_ns(ktime_dt);
0150     /*
0151      * measuring more than 6,45 meters is beyond the capabilities of
0152      * the supported sensors
0153      * ==> filter out invalid results for not measuring echos of
0154      *     another us sensor
0155      *
0156      * formula:
0157      *         distance     6,45 * 2 m
0158      * time = ---------- = ------------ = 40438871 ns
0159      *          speed         319 m/s
0160      *
0161      * using a minimum speed at -20 °C of 319 m/s
0162      */
0163     if (dt_ns > 40438871)
0164         return -EIO;
0165 
0166     time_ns = dt_ns;
0167 
0168     /*
0169      * the speed as function of the temperature is approximately:
0170      *
0171      * speed = 331,5 + 0,6 * Temp
0172      *   with Temp in °C
0173      *   and speed in m/s
0174      *
0175      * use 343,5 m/s as ultrasonic speed at 20 °C here in absence of the
0176      * temperature
0177      *
0178      * therefore:
0179      *             time     343,5     time * 106
0180      * distance = ------ * ------- = ------------
0181      *             10^6         2         617176
0182      *   with time in ns
0183      *   and distance in mm (one way)
0184      *
0185      * because we limit to 6,45 meters the multiplication with 106 just
0186      * fits into 32 bit
0187      */
0188     distance_mm = time_ns * 106 / 617176;
0189 
0190     return distance_mm;
0191 }
0192 
0193 static int srf04_read_raw(struct iio_dev *indio_dev,
0194                 struct iio_chan_spec const *channel, int *val,
0195                 int *val2, long info)
0196 {
0197     struct srf04_data *data = iio_priv(indio_dev);
0198     int ret;
0199 
0200     if (channel->type != IIO_DISTANCE)
0201         return -EINVAL;
0202 
0203     switch (info) {
0204     case IIO_CHAN_INFO_RAW:
0205         ret = srf04_read(data);
0206         if (ret < 0)
0207             return ret;
0208         *val = ret;
0209         return IIO_VAL_INT;
0210     case IIO_CHAN_INFO_SCALE:
0211         /*
0212          * theoretical maximum resolution is 3 mm
0213          * 1 LSB is 1 mm
0214          */
0215         *val = 0;
0216         *val2 = 1000;
0217         return IIO_VAL_INT_PLUS_MICRO;
0218     default:
0219         return -EINVAL;
0220     }
0221 }
0222 
0223 static const struct iio_info srf04_iio_info = {
0224     .read_raw       = srf04_read_raw,
0225 };
0226 
0227 static const struct iio_chan_spec srf04_chan_spec[] = {
0228     {
0229         .type = IIO_DISTANCE,
0230         .info_mask_separate =
0231                 BIT(IIO_CHAN_INFO_RAW) |
0232                 BIT(IIO_CHAN_INFO_SCALE),
0233     },
0234 };
0235 
0236 static const struct of_device_id of_srf04_match[] = {
0237     { .compatible = "devantech,srf04", .data = &srf04_cfg },
0238     { .compatible = "maxbotix,mb1000", .data = &mb_lv_cfg },
0239     { .compatible = "maxbotix,mb1010", .data = &mb_lv_cfg },
0240     { .compatible = "maxbotix,mb1020", .data = &mb_lv_cfg },
0241     { .compatible = "maxbotix,mb1030", .data = &mb_lv_cfg },
0242     { .compatible = "maxbotix,mb1040", .data = &mb_lv_cfg },
0243     {},
0244 };
0245 
0246 MODULE_DEVICE_TABLE(of, of_srf04_match);
0247 
0248 static int srf04_probe(struct platform_device *pdev)
0249 {
0250     struct device *dev = &pdev->dev;
0251     struct srf04_data *data;
0252     struct iio_dev *indio_dev;
0253     int ret;
0254 
0255     indio_dev = devm_iio_device_alloc(dev, sizeof(struct srf04_data));
0256     if (!indio_dev) {
0257         dev_err(dev, "failed to allocate IIO device\n");
0258         return -ENOMEM;
0259     }
0260 
0261     data = iio_priv(indio_dev);
0262     data->dev = dev;
0263     data->cfg = device_get_match_data(dev);
0264 
0265     mutex_init(&data->lock);
0266     init_completion(&data->rising);
0267     init_completion(&data->falling);
0268 
0269     data->gpiod_trig = devm_gpiod_get(dev, "trig", GPIOD_OUT_LOW);
0270     if (IS_ERR(data->gpiod_trig)) {
0271         dev_err(dev, "failed to get trig-gpios: err=%ld\n",
0272                     PTR_ERR(data->gpiod_trig));
0273         return PTR_ERR(data->gpiod_trig);
0274     }
0275 
0276     data->gpiod_echo = devm_gpiod_get(dev, "echo", GPIOD_IN);
0277     if (IS_ERR(data->gpiod_echo)) {
0278         dev_err(dev, "failed to get echo-gpios: err=%ld\n",
0279                     PTR_ERR(data->gpiod_echo));
0280         return PTR_ERR(data->gpiod_echo);
0281     }
0282 
0283     data->gpiod_power = devm_gpiod_get_optional(dev, "power",
0284                                 GPIOD_OUT_LOW);
0285     if (IS_ERR(data->gpiod_power)) {
0286         dev_err(dev, "failed to get power-gpios: err=%ld\n",
0287                         PTR_ERR(data->gpiod_power));
0288         return PTR_ERR(data->gpiod_power);
0289     }
0290     if (data->gpiod_power) {
0291         data->startup_time_ms = 100;
0292         device_property_read_u32(dev, "startup-time-ms", &data->startup_time_ms);
0293         dev_dbg(dev, "using power gpio: startup-time-ms=%d\n",
0294                             data->startup_time_ms);
0295     }
0296 
0297     if (gpiod_cansleep(data->gpiod_echo)) {
0298         dev_err(data->dev, "cansleep-GPIOs not supported\n");
0299         return -ENODEV;
0300     }
0301 
0302     data->irqnr = gpiod_to_irq(data->gpiod_echo);
0303     if (data->irqnr < 0) {
0304         dev_err(data->dev, "gpiod_to_irq: %d\n", data->irqnr);
0305         return data->irqnr;
0306     }
0307 
0308     ret = devm_request_irq(dev, data->irqnr, srf04_handle_irq,
0309             IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
0310             pdev->name, indio_dev);
0311     if (ret < 0) {
0312         dev_err(data->dev, "request_irq: %d\n", ret);
0313         return ret;
0314     }
0315 
0316     platform_set_drvdata(pdev, indio_dev);
0317 
0318     indio_dev->name = "srf04";
0319     indio_dev->info = &srf04_iio_info;
0320     indio_dev->modes = INDIO_DIRECT_MODE;
0321     indio_dev->channels = srf04_chan_spec;
0322     indio_dev->num_channels = ARRAY_SIZE(srf04_chan_spec);
0323 
0324     ret = iio_device_register(indio_dev);
0325     if (ret < 0) {
0326         dev_err(data->dev, "iio_device_register: %d\n", ret);
0327         return ret;
0328     }
0329 
0330     if (data->gpiod_power) {
0331         pm_runtime_set_autosuspend_delay(data->dev, 1000);
0332         pm_runtime_use_autosuspend(data->dev);
0333 
0334         ret = pm_runtime_set_active(data->dev);
0335         if (ret) {
0336             dev_err(data->dev, "pm_runtime_set_active: %d\n", ret);
0337             iio_device_unregister(indio_dev);
0338         }
0339 
0340         pm_runtime_enable(data->dev);
0341         pm_runtime_idle(data->dev);
0342     }
0343 
0344     return ret;
0345 }
0346 
0347 static int srf04_remove(struct platform_device *pdev)
0348 {
0349     struct iio_dev *indio_dev = platform_get_drvdata(pdev);
0350     struct srf04_data *data = iio_priv(indio_dev);
0351 
0352     iio_device_unregister(indio_dev);
0353 
0354     if (data->gpiod_power) {
0355         pm_runtime_disable(data->dev);
0356         pm_runtime_set_suspended(data->dev);
0357     }
0358 
0359     return 0;
0360 }
0361 
0362 static int __maybe_unused srf04_pm_runtime_suspend(struct device *dev)
0363 {
0364     struct platform_device *pdev = container_of(dev,
0365                         struct platform_device, dev);
0366     struct iio_dev *indio_dev = platform_get_drvdata(pdev);
0367     struct srf04_data *data = iio_priv(indio_dev);
0368 
0369     gpiod_set_value(data->gpiod_power, 0);
0370 
0371     return 0;
0372 }
0373 
0374 static int __maybe_unused srf04_pm_runtime_resume(struct device *dev)
0375 {
0376     struct platform_device *pdev = container_of(dev,
0377                         struct platform_device, dev);
0378     struct iio_dev *indio_dev = platform_get_drvdata(pdev);
0379     struct srf04_data *data = iio_priv(indio_dev);
0380 
0381     gpiod_set_value(data->gpiod_power, 1);
0382     msleep(data->startup_time_ms);
0383 
0384     return 0;
0385 }
0386 
0387 static const struct dev_pm_ops srf04_pm_ops = {
0388     SET_RUNTIME_PM_OPS(srf04_pm_runtime_suspend,
0389                 srf04_pm_runtime_resume, NULL)
0390 };
0391 
0392 static struct platform_driver srf04_driver = {
0393     .probe      = srf04_probe,
0394     .remove     = srf04_remove,
0395     .driver     = {
0396         .name       = "srf04-gpio",
0397         .of_match_table = of_srf04_match,
0398         .pm     = &srf04_pm_ops,
0399     },
0400 };
0401 
0402 module_platform_driver(srf04_driver);
0403 
0404 MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
0405 MODULE_DESCRIPTION("SRF04 ultrasonic sensor for distance measuring using GPIOs");
0406 MODULE_LICENSE("GPL");
0407 MODULE_ALIAS("platform:srf04");