Lines Matching +full:echo +full:- +full:gpios

1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * PING: ultrasonic sensor for distance measuring by using only one GPIOs
5 * Copyright (c) 2019 Andreas Klinger <ak@it-klinger.de>
8 * http://parallax.com/sites/default/files/downloads/28041-LaserPING-2m-Rangefinder-Guide.pdf
9 * http://parallax.com/sites/default/files/downloads/28015-PING-Documentation-v1.6.pdf
16 * |<->| interrupt interrupt
18 * |<---------------------->|
20 * . --> one round trip of ultra sonic waves
27 * echo: __________________________________/ \_/ \_/ \________________
80 if (gpiod_get_value(data->gpiod_ping)) { in ping_handle_irq()
81 data->ts_rising = now; in ping_handle_irq()
82 complete(&data->rising); in ping_handle_irq()
84 data->ts_falling = now; in ping_handle_irq()
85 complete(&data->falling); in ping_handle_irq()
98 struct platform_device *pdev = to_platform_device(data->dev); in ping_read()
101 * just one read-echo-cycle can take place at a time in ping_read()
104 mutex_lock(&data->lock); in ping_read()
106 reinit_completion(&data->rising); in ping_read()
107 reinit_completion(&data->falling); in ping_read()
109 gpiod_set_value(data->gpiod_ping, 1); in ping_read()
110 udelay(data->cfg->trigger_pulse_us); in ping_read()
111 gpiod_set_value(data->gpiod_ping, 0); in ping_read()
113 ret = gpiod_direction_input(data->gpiod_ping); in ping_read()
115 mutex_unlock(&data->lock); in ping_read()
119 data->irqnr = gpiod_to_irq(data->gpiod_ping); in ping_read()
120 if (data->irqnr < 0) { in ping_read()
121 dev_err(data->dev, "gpiod_to_irq: %d\n", data->irqnr); in ping_read()
122 mutex_unlock(&data->lock); in ping_read()
123 return data->irqnr; in ping_read()
126 ret = request_irq(data->irqnr, ping_handle_irq, in ping_read()
128 pdev->name, indio_dev); in ping_read()
130 dev_err(data->dev, "request_irq: %d\n", ret); in ping_read()
131 mutex_unlock(&data->lock); in ping_read()
135 /* it should not take more than 20 ms until echo is rising */ in ping_read()
136 ret = wait_for_completion_killable_timeout(&data->rising, HZ/50); in ping_read()
140 ret = -ETIMEDOUT; in ping_read()
144 /* it cannot take more than 50 ms until echo is falling */ in ping_read()
145 ret = wait_for_completion_killable_timeout(&data->falling, HZ/20); in ping_read()
149 ret = -ETIMEDOUT; in ping_read()
153 ktime_dt = ktime_sub(data->ts_falling, data->ts_rising); in ping_read()
155 free_irq(data->irqnr, indio_dev); in ping_read()
157 ret = gpiod_direction_output(data->gpiod_ping, GPIOD_OUT_LOW); in ping_read()
159 mutex_unlock(&data->lock); in ping_read()
163 mutex_unlock(&data->lock); in ping_read()
166 if (dt_ns > data->cfg->timeout_ns) { in ping_read()
167 dev_dbg(data->dev, "distance out of range: dt=%lldns\n", in ping_read()
169 return -EIO; in ping_read()
178 if (data->cfg->laserping_error) { in ping_read()
180 dev_dbg(data->dev, "target too close or to far\n"); in ping_read()
181 return -EIO; in ping_read()
184 dev_dbg(data->dev, "internal sensor error\n"); in ping_read()
185 return -EIO; in ping_read()
188 dev_dbg(data->dev, "internal sensor timeout\n"); in ping_read()
189 return -EIO; in ping_read()
205 * distance = ------ * ------- = ------------ in ping_read()
218 free_irq(data->irqnr, indio_dev); in ping_read()
219 mutex_unlock(&data->lock); in ping_read()
221 if (gpiod_direction_output(data->gpiod_ping, GPIOD_OUT_LOW)) in ping_read()
222 dev_dbg(data->dev, "error in gpiod_direction_output\n"); in ping_read()
232 if (channel->type != IIO_DISTANCE) in ping_read_raw()
233 return -EINVAL; in ping_read_raw()
251 return -EINVAL; in ping_read_raw()
278 struct device *dev = &pdev->dev; in ping_probe()
285 return -ENOMEM; in ping_probe()
289 data->dev = dev; in ping_probe()
290 data->cfg = device_get_match_data(dev); in ping_probe()
292 mutex_init(&data->lock); in ping_probe()
293 init_completion(&data->rising); in ping_probe()
294 init_completion(&data->falling); in ping_probe()
296 data->gpiod_ping = devm_gpiod_get(dev, "ping", GPIOD_OUT_LOW); in ping_probe()
297 if (IS_ERR(data->gpiod_ping)) { in ping_probe()
298 dev_err(dev, "failed to get ping-gpios: err=%ld\n", in ping_probe()
299 PTR_ERR(data->gpiod_ping)); in ping_probe()
300 return PTR_ERR(data->gpiod_ping); in ping_probe()
303 if (gpiod_cansleep(data->gpiod_ping)) { in ping_probe()
304 dev_err(data->dev, "cansleep-GPIOs not supported\n"); in ping_probe()
305 return -ENODEV; in ping_probe()
310 indio_dev->name = "ping"; in ping_probe()
311 indio_dev->info = &ping_iio_info; in ping_probe()
312 indio_dev->modes = INDIO_DIRECT_MODE; in ping_probe()
313 indio_dev->channels = ping_chan_spec; in ping_probe()
314 indio_dev->num_channels = ARRAY_SIZE(ping_chan_spec); in ping_probe()
322 .name = "ping-gpio",
329 MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
330 MODULE_DESCRIPTION("PING sensors for distance measuring using one GPIOs");