]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/iio/proximity/srf04.c
dpaa2-eth: Fix TX FQID values
[linux.git] / drivers / iio / proximity / srf04.c
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 cannot take more than 20 ms */
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         ret = wait_for_completion_killable_timeout(&data->falling, 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         ktime_dt = ktime_sub(data->ts_falling, data->ts_rising);
133
134         mutex_unlock(&data->lock);
135
136         dt_ns = ktime_to_ns(ktime_dt);
137         /*
138          * measuring more than 3 meters is beyond the capabilities of
139          * the sensor
140          * ==> filter out invalid results for not measuring echos of
141          *     another us sensor
142          *
143          * formula:
144          *         distance       3 m
145          * time = ---------- = --------- = 9404389 ns
146          *          speed       319 m/s
147          *
148          * using a minimum speed at -20 °C of 319 m/s
149          */
150         if (dt_ns > 9404389)
151                 return -EIO;
152
153         time_ns = dt_ns;
154
155         /*
156          * the speed as function of the temperature is approximately:
157          *
158          * speed = 331,5 + 0,6 * Temp
159          *   with Temp in °C
160          *   and speed in m/s
161          *
162          * use 343 m/s as ultrasonic speed at 20 °C here in absence of the
163          * temperature
164          *
165          * therefore:
166          *             time     343
167          * distance = ------ * -----
168          *             10^6       2
169          *   with time in ns
170          *   and distance in mm (one way)
171          *
172          * because we limit to 3 meters the multiplication with 343 just
173          * fits into 32 bit
174          */
175         distance_mm = time_ns * 343 / 2000000;
176
177         return distance_mm;
178 }
179
180 static int srf04_read_raw(struct iio_dev *indio_dev,
181                             struct iio_chan_spec const *channel, int *val,
182                             int *val2, long info)
183 {
184         struct srf04_data *data = iio_priv(indio_dev);
185         int ret;
186
187         if (channel->type != IIO_DISTANCE)
188                 return -EINVAL;
189
190         switch (info) {
191         case IIO_CHAN_INFO_RAW:
192                 ret = srf04_read(data);
193                 if (ret < 0)
194                         return ret;
195                 *val = ret;
196                 return IIO_VAL_INT;
197         case IIO_CHAN_INFO_SCALE:
198                 /*
199                  * theoretical maximum resolution is 3 mm
200                  * 1 LSB is 1 mm
201                  */
202                 *val = 0;
203                 *val2 = 1000;
204                 return IIO_VAL_INT_PLUS_MICRO;
205         default:
206                 return -EINVAL;
207         }
208 }
209
210 static const struct iio_info srf04_iio_info = {
211         .read_raw               = srf04_read_raw,
212 };
213
214 static const struct iio_chan_spec srf04_chan_spec[] = {
215         {
216                 .type = IIO_DISTANCE,
217                 .info_mask_separate =
218                                 BIT(IIO_CHAN_INFO_RAW) |
219                                 BIT(IIO_CHAN_INFO_SCALE),
220         },
221 };
222
223 static const struct of_device_id of_srf04_match[] = {
224         { .compatible = "devantech,srf04", .data = &srf04_cfg},
225         { .compatible = "maxbotix,mb1000", .data = &mb_lv_cfg},
226         { .compatible = "maxbotix,mb1010", .data = &mb_lv_cfg},
227         { .compatible = "maxbotix,mb1020", .data = &mb_lv_cfg},
228         { .compatible = "maxbotix,mb1030", .data = &mb_lv_cfg},
229         { .compatible = "maxbotix,mb1040", .data = &mb_lv_cfg},
230         {},
231 };
232
233 MODULE_DEVICE_TABLE(of, of_srf04_match);
234
235 static int srf04_probe(struct platform_device *pdev)
236 {
237         struct device *dev = &pdev->dev;
238         struct srf04_data *data;
239         struct iio_dev *indio_dev;
240         int ret;
241
242         indio_dev = devm_iio_device_alloc(dev, sizeof(struct srf04_data));
243         if (!indio_dev) {
244                 dev_err(dev, "failed to allocate IIO device\n");
245                 return -ENOMEM;
246         }
247
248         data = iio_priv(indio_dev);
249         data->dev = dev;
250         data->cfg = of_match_device(of_srf04_match, dev)->data;
251
252         mutex_init(&data->lock);
253         init_completion(&data->rising);
254         init_completion(&data->falling);
255
256         data->gpiod_trig = devm_gpiod_get(dev, "trig", GPIOD_OUT_LOW);
257         if (IS_ERR(data->gpiod_trig)) {
258                 dev_err(dev, "failed to get trig-gpios: err=%ld\n",
259                                         PTR_ERR(data->gpiod_trig));
260                 return PTR_ERR(data->gpiod_trig);
261         }
262
263         data->gpiod_echo = devm_gpiod_get(dev, "echo", GPIOD_IN);
264         if (IS_ERR(data->gpiod_echo)) {
265                 dev_err(dev, "failed to get echo-gpios: err=%ld\n",
266                                         PTR_ERR(data->gpiod_echo));
267                 return PTR_ERR(data->gpiod_echo);
268         }
269
270         if (gpiod_cansleep(data->gpiod_echo)) {
271                 dev_err(data->dev, "cansleep-GPIOs not supported\n");
272                 return -ENODEV;
273         }
274
275         data->irqnr = gpiod_to_irq(data->gpiod_echo);
276         if (data->irqnr < 0) {
277                 dev_err(data->dev, "gpiod_to_irq: %d\n", data->irqnr);
278                 return data->irqnr;
279         }
280
281         ret = devm_request_irq(dev, data->irqnr, srf04_handle_irq,
282                         IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
283                         pdev->name, indio_dev);
284         if (ret < 0) {
285                 dev_err(data->dev, "request_irq: %d\n", ret);
286                 return ret;
287         }
288
289         platform_set_drvdata(pdev, indio_dev);
290
291         indio_dev->name = "srf04";
292         indio_dev->dev.parent = &pdev->dev;
293         indio_dev->info = &srf04_iio_info;
294         indio_dev->modes = INDIO_DIRECT_MODE;
295         indio_dev->channels = srf04_chan_spec;
296         indio_dev->num_channels = ARRAY_SIZE(srf04_chan_spec);
297
298         return devm_iio_device_register(dev, indio_dev);
299 }
300
301 static struct platform_driver srf04_driver = {
302         .probe          = srf04_probe,
303         .driver         = {
304                 .name           = "srf04-gpio",
305                 .of_match_table = of_srf04_match,
306         },
307 };
308
309 module_platform_driver(srf04_driver);
310
311 MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
312 MODULE_DESCRIPTION("SRF04 ultrasonic sensor for distance measuring using GPIOs");
313 MODULE_LICENSE("GPL");
314 MODULE_ALIAS("platform:srf04");