xref: /openbmc/linux/drivers/iio/proximity/ping.c (revision b4b93677)
17bb501f4SAndreas Klinger // SPDX-License-Identifier: GPL-2.0-or-later
27bb501f4SAndreas Klinger /*
37bb501f4SAndreas Klinger  * PING: ultrasonic sensor for distance measuring by using only one GPIOs
47bb501f4SAndreas Klinger  *
57bb501f4SAndreas Klinger  * Copyright (c) 2019 Andreas Klinger <ak@it-klinger.de>
67bb501f4SAndreas Klinger  *
77bb501f4SAndreas Klinger  * For details about the devices see:
87bb501f4SAndreas Klinger  * http://parallax.com/sites/default/files/downloads/28041-LaserPING-2m-Rangefinder-Guide.pdf
97bb501f4SAndreas Klinger  * http://parallax.com/sites/default/files/downloads/28015-PING-Documentation-v1.6.pdf
107bb501f4SAndreas Klinger  *
117bb501f4SAndreas Klinger  * the measurement cycle as timing diagram looks like:
127bb501f4SAndreas Klinger  *
137bb501f4SAndreas Klinger  * GPIO      ___              ________________________
147bb501f4SAndreas Klinger  * ping:  __/   \____________/                        \________________
157bb501f4SAndreas Klinger  *          ^   ^            ^                        ^
167bb501f4SAndreas Klinger  *          |<->|            interrupt                interrupt
177bb501f4SAndreas Klinger  *         udelay(5)         (ts_rising)              (ts_falling)
187bb501f4SAndreas Klinger  *                           |<---------------------->|
197bb501f4SAndreas Klinger  *                           .  pulse time measured   .
207bb501f4SAndreas Klinger  *                           .  --> one round trip of ultra sonic waves
217bb501f4SAndreas Klinger  * ultra                     .                        .
227bb501f4SAndreas Klinger  * sonic            _   _   _.                        .
237bb501f4SAndreas Klinger  * burst: _________/ \_/ \_/ \_________________________________________
247bb501f4SAndreas Klinger  *                                                    .
257bb501f4SAndreas Klinger  * ultra                                              .
267bb501f4SAndreas Klinger  * sonic                                     _   _   _.
277bb501f4SAndreas Klinger  * echo:  __________________________________/ \_/ \_/ \________________
287bb501f4SAndreas Klinger  */
297bb501f4SAndreas Klinger #include <linux/err.h>
307bb501f4SAndreas Klinger #include <linux/gpio/consumer.h>
317bb501f4SAndreas Klinger #include <linux/kernel.h>
3287b7b07bSAndy Shevchenko #include <linux/mod_devicetable.h>
337bb501f4SAndreas Klinger #include <linux/module.h>
347bb501f4SAndreas Klinger #include <linux/platform_device.h>
357bb501f4SAndreas Klinger #include <linux/property.h>
367bb501f4SAndreas Klinger #include <linux/sched.h>
377bb501f4SAndreas Klinger #include <linux/interrupt.h>
387bb501f4SAndreas Klinger #include <linux/delay.h>
397bb501f4SAndreas Klinger #include <linux/iio/iio.h>
407bb501f4SAndreas Klinger #include <linux/iio/sysfs.h>
417bb501f4SAndreas Klinger 
427bb501f4SAndreas Klinger struct ping_cfg {
437bb501f4SAndreas Klinger 	unsigned long	trigger_pulse_us;	/* length of trigger pulse */
447bb501f4SAndreas Klinger 	int		laserping_error;	/* support error code in */
457bb501f4SAndreas Klinger 						/*   pulse width of laser */
467bb501f4SAndreas Klinger 						/*   ping sensors */
477bb501f4SAndreas Klinger 	s64		timeout_ns;		/* timeout in ns */
487bb501f4SAndreas Klinger };
497bb501f4SAndreas Klinger 
507bb501f4SAndreas Klinger struct ping_data {
517bb501f4SAndreas Klinger 	struct device		*dev;
527bb501f4SAndreas Klinger 	struct gpio_desc	*gpiod_ping;
537bb501f4SAndreas Klinger 	struct mutex		lock;
547bb501f4SAndreas Klinger 	int			irqnr;
557bb501f4SAndreas Klinger 	ktime_t			ts_rising;
567bb501f4SAndreas Klinger 	ktime_t			ts_falling;
577bb501f4SAndreas Klinger 	struct completion	rising;
587bb501f4SAndreas Klinger 	struct completion	falling;
597bb501f4SAndreas Klinger 	const struct ping_cfg	*cfg;
607bb501f4SAndreas Klinger };
617bb501f4SAndreas Klinger 
627bb501f4SAndreas Klinger static const struct ping_cfg pa_ping_cfg = {
637bb501f4SAndreas Klinger 	.trigger_pulse_us	= 5,
647bb501f4SAndreas Klinger 	.laserping_error	= 0,
657bb501f4SAndreas Klinger 	.timeout_ns		= 18500000,	/* 3 meters */
667bb501f4SAndreas Klinger };
677bb501f4SAndreas Klinger 
687bb501f4SAndreas Klinger static const struct ping_cfg pa_laser_ping_cfg = {
697bb501f4SAndreas Klinger 	.trigger_pulse_us	= 5,
707bb501f4SAndreas Klinger 	.laserping_error	= 1,
717bb501f4SAndreas Klinger 	.timeout_ns		= 15500000,	/* 2 meters plus error codes */
727bb501f4SAndreas Klinger };
737bb501f4SAndreas Klinger 
ping_handle_irq(int irq,void * dev_id)747bb501f4SAndreas Klinger static irqreturn_t ping_handle_irq(int irq, void *dev_id)
757bb501f4SAndreas Klinger {
767bb501f4SAndreas Klinger 	struct iio_dev *indio_dev = dev_id;
777bb501f4SAndreas Klinger 	struct ping_data *data = iio_priv(indio_dev);
787bb501f4SAndreas Klinger 	ktime_t now = ktime_get();
797bb501f4SAndreas Klinger 
807bb501f4SAndreas Klinger 	if (gpiod_get_value(data->gpiod_ping)) {
817bb501f4SAndreas Klinger 		data->ts_rising = now;
827bb501f4SAndreas Klinger 		complete(&data->rising);
837bb501f4SAndreas Klinger 	} else {
847bb501f4SAndreas Klinger 		data->ts_falling = now;
857bb501f4SAndreas Klinger 		complete(&data->falling);
867bb501f4SAndreas Klinger 	}
877bb501f4SAndreas Klinger 
887bb501f4SAndreas Klinger 	return IRQ_HANDLED;
897bb501f4SAndreas Klinger }
907bb501f4SAndreas Klinger 
ping_read(struct iio_dev * indio_dev)911ecca8a9SAlexandru Ardelean static int ping_read(struct iio_dev *indio_dev)
927bb501f4SAndreas Klinger {
931ecca8a9SAlexandru Ardelean 	struct ping_data *data = iio_priv(indio_dev);
947bb501f4SAndreas Klinger 	int ret;
957bb501f4SAndreas Klinger 	ktime_t ktime_dt;
967bb501f4SAndreas Klinger 	s64 dt_ns;
977bb501f4SAndreas Klinger 	u32 time_ns, distance_mm;
987bb501f4SAndreas Klinger 	struct platform_device *pdev = to_platform_device(data->dev);
997bb501f4SAndreas Klinger 
1007bb501f4SAndreas Klinger 	/*
1017bb501f4SAndreas Klinger 	 * just one read-echo-cycle can take place at a time
1027bb501f4SAndreas Klinger 	 * ==> lock against concurrent reading calls
1037bb501f4SAndreas Klinger 	 */
1047bb501f4SAndreas Klinger 	mutex_lock(&data->lock);
1057bb501f4SAndreas Klinger 
1067bb501f4SAndreas Klinger 	reinit_completion(&data->rising);
1077bb501f4SAndreas Klinger 	reinit_completion(&data->falling);
1087bb501f4SAndreas Klinger 
1097bb501f4SAndreas Klinger 	gpiod_set_value(data->gpiod_ping, 1);
1107bb501f4SAndreas Klinger 	udelay(data->cfg->trigger_pulse_us);
1117bb501f4SAndreas Klinger 	gpiod_set_value(data->gpiod_ping, 0);
1127bb501f4SAndreas Klinger 
1137bb501f4SAndreas Klinger 	ret = gpiod_direction_input(data->gpiod_ping);
1147bb501f4SAndreas Klinger 	if (ret < 0) {
1157bb501f4SAndreas Klinger 		mutex_unlock(&data->lock);
1167bb501f4SAndreas Klinger 		return ret;
1177bb501f4SAndreas Klinger 	}
1187bb501f4SAndreas Klinger 
1197bb501f4SAndreas Klinger 	data->irqnr = gpiod_to_irq(data->gpiod_ping);
1207bb501f4SAndreas Klinger 	if (data->irqnr < 0) {
1217bb501f4SAndreas Klinger 		dev_err(data->dev, "gpiod_to_irq: %d\n", data->irqnr);
1227bb501f4SAndreas Klinger 		mutex_unlock(&data->lock);
1237bb501f4SAndreas Klinger 		return data->irqnr;
1247bb501f4SAndreas Klinger 	}
1257bb501f4SAndreas Klinger 
1267bb501f4SAndreas Klinger 	ret = request_irq(data->irqnr, ping_handle_irq,
1277bb501f4SAndreas Klinger 				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
1287bb501f4SAndreas Klinger 							pdev->name, indio_dev);
1297bb501f4SAndreas Klinger 	if (ret < 0) {
1307bb501f4SAndreas Klinger 		dev_err(data->dev, "request_irq: %d\n", ret);
1317bb501f4SAndreas Klinger 		mutex_unlock(&data->lock);
1327bb501f4SAndreas Klinger 		return ret;
1337bb501f4SAndreas Klinger 	}
1347bb501f4SAndreas Klinger 
1357bb501f4SAndreas Klinger 	/* it should not take more than 20 ms until echo is rising */
1367bb501f4SAndreas Klinger 	ret = wait_for_completion_killable_timeout(&data->rising, HZ/50);
1377bb501f4SAndreas Klinger 	if (ret < 0)
1387bb501f4SAndreas Klinger 		goto err_reset_direction;
1397bb501f4SAndreas Klinger 	else if (ret == 0) {
1407bb501f4SAndreas Klinger 		ret = -ETIMEDOUT;
1417bb501f4SAndreas Klinger 		goto err_reset_direction;
1427bb501f4SAndreas Klinger 	}
1437bb501f4SAndreas Klinger 
1447bb501f4SAndreas Klinger 	/* it cannot take more than 50 ms until echo is falling */
1457bb501f4SAndreas Klinger 	ret = wait_for_completion_killable_timeout(&data->falling, HZ/20);
1467bb501f4SAndreas Klinger 	if (ret < 0)
1477bb501f4SAndreas Klinger 		goto err_reset_direction;
1487bb501f4SAndreas Klinger 	else if (ret == 0) {
1497bb501f4SAndreas Klinger 		ret = -ETIMEDOUT;
1507bb501f4SAndreas Klinger 		goto err_reset_direction;
1517bb501f4SAndreas Klinger 	}
1527bb501f4SAndreas Klinger 
1537bb501f4SAndreas Klinger 	ktime_dt = ktime_sub(data->ts_falling, data->ts_rising);
1547bb501f4SAndreas Klinger 
1557bb501f4SAndreas Klinger 	free_irq(data->irqnr, indio_dev);
1567bb501f4SAndreas Klinger 
1577bb501f4SAndreas Klinger 	ret = gpiod_direction_output(data->gpiod_ping, GPIOD_OUT_LOW);
1587bb501f4SAndreas Klinger 	if (ret < 0) {
1597bb501f4SAndreas Klinger 		mutex_unlock(&data->lock);
1607bb501f4SAndreas Klinger 		return ret;
1617bb501f4SAndreas Klinger 	}
1627bb501f4SAndreas Klinger 
1637bb501f4SAndreas Klinger 	mutex_unlock(&data->lock);
1647bb501f4SAndreas Klinger 
1657bb501f4SAndreas Klinger 	dt_ns = ktime_to_ns(ktime_dt);
1667bb501f4SAndreas Klinger 	if (dt_ns > data->cfg->timeout_ns) {
1677bb501f4SAndreas Klinger 		dev_dbg(data->dev, "distance out of range: dt=%lldns\n",
1687bb501f4SAndreas Klinger 								dt_ns);
1697bb501f4SAndreas Klinger 		return -EIO;
1707bb501f4SAndreas Klinger 	}
1717bb501f4SAndreas Klinger 
1727bb501f4SAndreas Klinger 	time_ns = dt_ns;
1737bb501f4SAndreas Klinger 
1747bb501f4SAndreas Klinger 	/*
1757bb501f4SAndreas Klinger 	 * read error code of laser ping sensor and give users chance to
176*b4b93677SJulia Lawall 	 * figure out error by using dynamic debugging
1777bb501f4SAndreas Klinger 	 */
1787bb501f4SAndreas Klinger 	if (data->cfg->laserping_error) {
1797bb501f4SAndreas Klinger 		if ((time_ns > 12500000) && (time_ns <= 13500000)) {
1807bb501f4SAndreas Klinger 			dev_dbg(data->dev, "target too close or to far\n");
1817bb501f4SAndreas Klinger 			return -EIO;
1827bb501f4SAndreas Klinger 		}
1837bb501f4SAndreas Klinger 		if ((time_ns > 13500000) && (time_ns <= 14500000)) {
1847bb501f4SAndreas Klinger 			dev_dbg(data->dev, "internal sensor error\n");
1857bb501f4SAndreas Klinger 			return -EIO;
1867bb501f4SAndreas Klinger 		}
1877bb501f4SAndreas Klinger 		if ((time_ns > 14500000) && (time_ns <= 15500000)) {
1887bb501f4SAndreas Klinger 			dev_dbg(data->dev, "internal sensor timeout\n");
1897bb501f4SAndreas Klinger 			return -EIO;
1907bb501f4SAndreas Klinger 		}
1917bb501f4SAndreas Klinger 	}
1927bb501f4SAndreas Klinger 
1937bb501f4SAndreas Klinger 	/*
1947bb501f4SAndreas Klinger 	 * the speed as function of the temperature is approximately:
1957bb501f4SAndreas Klinger 	 *
1967bb501f4SAndreas Klinger 	 * speed = 331,5 + 0,6 * Temp
1977bb501f4SAndreas Klinger 	 *   with Temp in °C
1987bb501f4SAndreas Klinger 	 *   and speed in m/s
1997bb501f4SAndreas Klinger 	 *
2007bb501f4SAndreas Klinger 	 * use 343,5 m/s as ultrasonic speed at 20 °C here in absence of the
2017bb501f4SAndreas Klinger 	 * temperature
2027bb501f4SAndreas Klinger 	 *
2037bb501f4SAndreas Klinger 	 * therefore:
2047bb501f4SAndreas Klinger 	 *             time     343,5     time * 232
2057bb501f4SAndreas Klinger 	 * distance = ------ * ------- = ------------
2067bb501f4SAndreas Klinger 	 *             10^6         2        1350800
2077bb501f4SAndreas Klinger 	 *   with time in ns
2087bb501f4SAndreas Klinger 	 *   and distance in mm (one way)
2097bb501f4SAndreas Klinger 	 *
2107bb501f4SAndreas Klinger 	 * because we limit to 3 meters the multiplication with 232 just
2117bb501f4SAndreas Klinger 	 * fits into 32 bit
2127bb501f4SAndreas Klinger 	 */
2137bb501f4SAndreas Klinger 	distance_mm = time_ns * 232 / 1350800;
2147bb501f4SAndreas Klinger 
2157bb501f4SAndreas Klinger 	return distance_mm;
2167bb501f4SAndreas Klinger 
2177bb501f4SAndreas Klinger err_reset_direction:
2187bb501f4SAndreas Klinger 	free_irq(data->irqnr, indio_dev);
2197bb501f4SAndreas Klinger 	mutex_unlock(&data->lock);
2207bb501f4SAndreas Klinger 
2217bb501f4SAndreas Klinger 	if (gpiod_direction_output(data->gpiod_ping, GPIOD_OUT_LOW))
2227bb501f4SAndreas Klinger 		dev_dbg(data->dev, "error in gpiod_direction_output\n");
2237bb501f4SAndreas Klinger 	return ret;
2247bb501f4SAndreas Klinger }
2257bb501f4SAndreas Klinger 
ping_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * channel,int * val,int * val2,long info)2267bb501f4SAndreas Klinger static int ping_read_raw(struct iio_dev *indio_dev,
2277bb501f4SAndreas Klinger 			    struct iio_chan_spec const *channel, int *val,
2287bb501f4SAndreas Klinger 			    int *val2, long info)
2297bb501f4SAndreas Klinger {
2307bb501f4SAndreas Klinger 	int ret;
2317bb501f4SAndreas Klinger 
2327bb501f4SAndreas Klinger 	if (channel->type != IIO_DISTANCE)
2337bb501f4SAndreas Klinger 		return -EINVAL;
2347bb501f4SAndreas Klinger 
2357bb501f4SAndreas Klinger 	switch (info) {
2367bb501f4SAndreas Klinger 	case IIO_CHAN_INFO_RAW:
2371ecca8a9SAlexandru Ardelean 		ret = ping_read(indio_dev);
2387bb501f4SAndreas Klinger 		if (ret < 0)
2397bb501f4SAndreas Klinger 			return ret;
2407bb501f4SAndreas Klinger 		*val = ret;
2417bb501f4SAndreas Klinger 		return IIO_VAL_INT;
2427bb501f4SAndreas Klinger 	case IIO_CHAN_INFO_SCALE:
2437bb501f4SAndreas Klinger 		/*
2447bb501f4SAndreas Klinger 		 * maximum resolution in datasheet is 1 mm
2457bb501f4SAndreas Klinger 		 * 1 LSB is 1 mm
2467bb501f4SAndreas Klinger 		 */
2477bb501f4SAndreas Klinger 		*val = 0;
2487bb501f4SAndreas Klinger 		*val2 = 1000;
2497bb501f4SAndreas Klinger 		return IIO_VAL_INT_PLUS_MICRO;
2507bb501f4SAndreas Klinger 	default:
2517bb501f4SAndreas Klinger 		return -EINVAL;
2527bb501f4SAndreas Klinger 	}
2537bb501f4SAndreas Klinger }
2547bb501f4SAndreas Klinger 
2557bb501f4SAndreas Klinger static const struct iio_info ping_iio_info = {
2567bb501f4SAndreas Klinger 	.read_raw		= ping_read_raw,
2577bb501f4SAndreas Klinger };
2587bb501f4SAndreas Klinger 
2597bb501f4SAndreas Klinger static const struct iio_chan_spec ping_chan_spec[] = {
2607bb501f4SAndreas Klinger 	{
2617bb501f4SAndreas Klinger 		.type = IIO_DISTANCE,
2627bb501f4SAndreas Klinger 		.info_mask_separate =
2637bb501f4SAndreas Klinger 				BIT(IIO_CHAN_INFO_RAW) |
2647bb501f4SAndreas Klinger 				BIT(IIO_CHAN_INFO_SCALE),
2657bb501f4SAndreas Klinger 	},
2667bb501f4SAndreas Klinger };
2677bb501f4SAndreas Klinger 
2687bb501f4SAndreas Klinger static const struct of_device_id of_ping_match[] = {
2697bb501f4SAndreas Klinger 	{ .compatible = "parallax,ping", .data = &pa_ping_cfg },
27010856d88SYueHaibing 	{ .compatible = "parallax,laserping", .data = &pa_laser_ping_cfg },
2717bb501f4SAndreas Klinger 	{},
2727bb501f4SAndreas Klinger };
2737bb501f4SAndreas Klinger 
2747bb501f4SAndreas Klinger MODULE_DEVICE_TABLE(of, of_ping_match);
2757bb501f4SAndreas Klinger 
ping_probe(struct platform_device * pdev)2767bb501f4SAndreas Klinger static int ping_probe(struct platform_device *pdev)
2777bb501f4SAndreas Klinger {
2787bb501f4SAndreas Klinger 	struct device *dev = &pdev->dev;
2797bb501f4SAndreas Klinger 	struct ping_data *data;
2807bb501f4SAndreas Klinger 	struct iio_dev *indio_dev;
2817bb501f4SAndreas Klinger 
2827bb501f4SAndreas Klinger 	indio_dev = devm_iio_device_alloc(dev, sizeof(struct ping_data));
2837bb501f4SAndreas Klinger 	if (!indio_dev) {
2847bb501f4SAndreas Klinger 		dev_err(dev, "failed to allocate IIO device\n");
2857bb501f4SAndreas Klinger 		return -ENOMEM;
2867bb501f4SAndreas Klinger 	}
2877bb501f4SAndreas Klinger 
2887bb501f4SAndreas Klinger 	data = iio_priv(indio_dev);
2897bb501f4SAndreas Klinger 	data->dev = dev;
29087b7b07bSAndy Shevchenko 	data->cfg = device_get_match_data(dev);
2917bb501f4SAndreas Klinger 
2927bb501f4SAndreas Klinger 	mutex_init(&data->lock);
2937bb501f4SAndreas Klinger 	init_completion(&data->rising);
2947bb501f4SAndreas Klinger 	init_completion(&data->falling);
2957bb501f4SAndreas Klinger 
2967bb501f4SAndreas Klinger 	data->gpiod_ping = devm_gpiod_get(dev, "ping", GPIOD_OUT_LOW);
2977bb501f4SAndreas Klinger 	if (IS_ERR(data->gpiod_ping)) {
2987bb501f4SAndreas Klinger 		dev_err(dev, "failed to get ping-gpios: err=%ld\n",
2997bb501f4SAndreas Klinger 						PTR_ERR(data->gpiod_ping));
3007bb501f4SAndreas Klinger 		return PTR_ERR(data->gpiod_ping);
3017bb501f4SAndreas Klinger 	}
3027bb501f4SAndreas Klinger 
3037bb501f4SAndreas Klinger 	if (gpiod_cansleep(data->gpiod_ping)) {
3047bb501f4SAndreas Klinger 		dev_err(data->dev, "cansleep-GPIOs not supported\n");
3057bb501f4SAndreas Klinger 		return -ENODEV;
3067bb501f4SAndreas Klinger 	}
3077bb501f4SAndreas Klinger 
3087bb501f4SAndreas Klinger 	platform_set_drvdata(pdev, indio_dev);
3097bb501f4SAndreas Klinger 
3107bb501f4SAndreas Klinger 	indio_dev->name = "ping";
3117bb501f4SAndreas Klinger 	indio_dev->info = &ping_iio_info;
3127bb501f4SAndreas Klinger 	indio_dev->modes = INDIO_DIRECT_MODE;
3137bb501f4SAndreas Klinger 	indio_dev->channels = ping_chan_spec;
3147bb501f4SAndreas Klinger 	indio_dev->num_channels = ARRAY_SIZE(ping_chan_spec);
3157bb501f4SAndreas Klinger 
3167bb501f4SAndreas Klinger 	return devm_iio_device_register(dev, indio_dev);
3177bb501f4SAndreas Klinger }
3187bb501f4SAndreas Klinger 
3197bb501f4SAndreas Klinger static struct platform_driver ping_driver = {
3207bb501f4SAndreas Klinger 	.probe		= ping_probe,
3217bb501f4SAndreas Klinger 	.driver		= {
3227bb501f4SAndreas Klinger 		.name		= "ping-gpio",
3237bb501f4SAndreas Klinger 		.of_match_table	= of_ping_match,
3247bb501f4SAndreas Klinger 	},
3257bb501f4SAndreas Klinger };
3267bb501f4SAndreas Klinger 
3277bb501f4SAndreas Klinger module_platform_driver(ping_driver);
3287bb501f4SAndreas Klinger 
3297bb501f4SAndreas Klinger MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
3307bb501f4SAndreas Klinger MODULE_DESCRIPTION("PING sensors for distance measuring using one GPIOs");
3317bb501f4SAndreas Klinger MODULE_LICENSE("GPL");
3327bb501f4SAndreas Klinger MODULE_ALIAS("platform:ping");
333