162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * SRF04: ultrasonic sensor for distance measuring by using GPIOs 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2017 Andreas Klinger <ak@it-klinger.de> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * For details about the device see: 862306a36Sopenharmony_ci * https://www.robot-electronics.co.uk/htm/srf04tech.htm 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * the measurement cycle as timing diagram looks like: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * +---+ 1362306a36Sopenharmony_ci * GPIO | | 1462306a36Sopenharmony_ci * trig: --+ +------------------------------------------------------ 1562306a36Sopenharmony_ci * ^ ^ 1662306a36Sopenharmony_ci * |<->| 1762306a36Sopenharmony_ci * udelay(trigger_pulse_us) 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * ultra +-+ +-+ +-+ 2062306a36Sopenharmony_ci * sonic | | | | | | 2162306a36Sopenharmony_ci * burst: ---------+ +-+ +-+ +----------------------------------------- 2262306a36Sopenharmony_ci * . 2362306a36Sopenharmony_ci * ultra . +-+ +-+ +-+ 2462306a36Sopenharmony_ci * sonic . | | | | | | 2562306a36Sopenharmony_ci * echo: ----------------------------------+ +-+ +-+ +---------------- 2662306a36Sopenharmony_ci * . . 2762306a36Sopenharmony_ci * +------------------------+ 2862306a36Sopenharmony_ci * GPIO | | 2962306a36Sopenharmony_ci * echo: -------------------+ +--------------- 3062306a36Sopenharmony_ci * ^ ^ 3162306a36Sopenharmony_ci * interrupt interrupt 3262306a36Sopenharmony_ci * (ts_rising) (ts_falling) 3362306a36Sopenharmony_ci * |<---------------------->| 3462306a36Sopenharmony_ci * pulse time measured 3562306a36Sopenharmony_ci * --> one round trip of ultra sonic waves 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_ci#include <linux/err.h> 3862306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 3962306a36Sopenharmony_ci#include <linux/kernel.h> 4062306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 4162306a36Sopenharmony_ci#include <linux/module.h> 4262306a36Sopenharmony_ci#include <linux/platform_device.h> 4362306a36Sopenharmony_ci#include <linux/property.h> 4462306a36Sopenharmony_ci#include <linux/sched.h> 4562306a36Sopenharmony_ci#include <linux/interrupt.h> 4662306a36Sopenharmony_ci#include <linux/delay.h> 4762306a36Sopenharmony_ci#include <linux/pm_runtime.h> 4862306a36Sopenharmony_ci#include <linux/iio/iio.h> 4962306a36Sopenharmony_ci#include <linux/iio/sysfs.h> 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistruct srf04_cfg { 5262306a36Sopenharmony_ci unsigned long trigger_pulse_us; 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistruct srf04_data { 5662306a36Sopenharmony_ci struct device *dev; 5762306a36Sopenharmony_ci struct gpio_desc *gpiod_trig; 5862306a36Sopenharmony_ci struct gpio_desc *gpiod_echo; 5962306a36Sopenharmony_ci struct gpio_desc *gpiod_power; 6062306a36Sopenharmony_ci struct mutex lock; 6162306a36Sopenharmony_ci int irqnr; 6262306a36Sopenharmony_ci ktime_t ts_rising; 6362306a36Sopenharmony_ci ktime_t ts_falling; 6462306a36Sopenharmony_ci struct completion rising; 6562306a36Sopenharmony_ci struct completion falling; 6662306a36Sopenharmony_ci const struct srf04_cfg *cfg; 6762306a36Sopenharmony_ci int startup_time_ms; 6862306a36Sopenharmony_ci}; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic const struct srf04_cfg srf04_cfg = { 7162306a36Sopenharmony_ci .trigger_pulse_us = 10, 7262306a36Sopenharmony_ci}; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic const struct srf04_cfg mb_lv_cfg = { 7562306a36Sopenharmony_ci .trigger_pulse_us = 20, 7662306a36Sopenharmony_ci}; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic irqreturn_t srf04_handle_irq(int irq, void *dev_id) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci struct iio_dev *indio_dev = dev_id; 8162306a36Sopenharmony_ci struct srf04_data *data = iio_priv(indio_dev); 8262306a36Sopenharmony_ci ktime_t now = ktime_get(); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci if (gpiod_get_value(data->gpiod_echo)) { 8562306a36Sopenharmony_ci data->ts_rising = now; 8662306a36Sopenharmony_ci complete(&data->rising); 8762306a36Sopenharmony_ci } else { 8862306a36Sopenharmony_ci data->ts_falling = now; 8962306a36Sopenharmony_ci complete(&data->falling); 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return IRQ_HANDLED; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic int srf04_read(struct srf04_data *data) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci int ret; 9862306a36Sopenharmony_ci ktime_t ktime_dt; 9962306a36Sopenharmony_ci u64 dt_ns; 10062306a36Sopenharmony_ci u32 time_ns, distance_mm; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci if (data->gpiod_power) { 10362306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(data->dev); 10462306a36Sopenharmony_ci if (ret < 0) 10562306a36Sopenharmony_ci return ret; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci /* 10862306a36Sopenharmony_ci * just one read-echo-cycle can take place at a time 10962306a36Sopenharmony_ci * ==> lock against concurrent reading calls 11062306a36Sopenharmony_ci */ 11162306a36Sopenharmony_ci mutex_lock(&data->lock); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci reinit_completion(&data->rising); 11462306a36Sopenharmony_ci reinit_completion(&data->falling); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci gpiod_set_value(data->gpiod_trig, 1); 11762306a36Sopenharmony_ci udelay(data->cfg->trigger_pulse_us); 11862306a36Sopenharmony_ci gpiod_set_value(data->gpiod_trig, 0); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (data->gpiod_power) { 12162306a36Sopenharmony_ci pm_runtime_mark_last_busy(data->dev); 12262306a36Sopenharmony_ci pm_runtime_put_autosuspend(data->dev); 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* it should not take more than 20 ms until echo is rising */ 12662306a36Sopenharmony_ci ret = wait_for_completion_killable_timeout(&data->rising, HZ/50); 12762306a36Sopenharmony_ci if (ret < 0) { 12862306a36Sopenharmony_ci mutex_unlock(&data->lock); 12962306a36Sopenharmony_ci return ret; 13062306a36Sopenharmony_ci } else if (ret == 0) { 13162306a36Sopenharmony_ci mutex_unlock(&data->lock); 13262306a36Sopenharmony_ci return -ETIMEDOUT; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci /* it cannot take more than 50 ms until echo is falling */ 13662306a36Sopenharmony_ci ret = wait_for_completion_killable_timeout(&data->falling, HZ/20); 13762306a36Sopenharmony_ci if (ret < 0) { 13862306a36Sopenharmony_ci mutex_unlock(&data->lock); 13962306a36Sopenharmony_ci return ret; 14062306a36Sopenharmony_ci } else if (ret == 0) { 14162306a36Sopenharmony_ci mutex_unlock(&data->lock); 14262306a36Sopenharmony_ci return -ETIMEDOUT; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci ktime_dt = ktime_sub(data->ts_falling, data->ts_rising); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci mutex_unlock(&data->lock); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci dt_ns = ktime_to_ns(ktime_dt); 15062306a36Sopenharmony_ci /* 15162306a36Sopenharmony_ci * measuring more than 6,45 meters is beyond the capabilities of 15262306a36Sopenharmony_ci * the supported sensors 15362306a36Sopenharmony_ci * ==> filter out invalid results for not measuring echos of 15462306a36Sopenharmony_ci * another us sensor 15562306a36Sopenharmony_ci * 15662306a36Sopenharmony_ci * formula: 15762306a36Sopenharmony_ci * distance 6,45 * 2 m 15862306a36Sopenharmony_ci * time = ---------- = ------------ = 40438871 ns 15962306a36Sopenharmony_ci * speed 319 m/s 16062306a36Sopenharmony_ci * 16162306a36Sopenharmony_ci * using a minimum speed at -20 °C of 319 m/s 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_ci if (dt_ns > 40438871) 16462306a36Sopenharmony_ci return -EIO; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci time_ns = dt_ns; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci /* 16962306a36Sopenharmony_ci * the speed as function of the temperature is approximately: 17062306a36Sopenharmony_ci * 17162306a36Sopenharmony_ci * speed = 331,5 + 0,6 * Temp 17262306a36Sopenharmony_ci * with Temp in °C 17362306a36Sopenharmony_ci * and speed in m/s 17462306a36Sopenharmony_ci * 17562306a36Sopenharmony_ci * use 343,5 m/s as ultrasonic speed at 20 °C here in absence of the 17662306a36Sopenharmony_ci * temperature 17762306a36Sopenharmony_ci * 17862306a36Sopenharmony_ci * therefore: 17962306a36Sopenharmony_ci * time 343,5 time * 106 18062306a36Sopenharmony_ci * distance = ------ * ------- = ------------ 18162306a36Sopenharmony_ci * 10^6 2 617176 18262306a36Sopenharmony_ci * with time in ns 18362306a36Sopenharmony_ci * and distance in mm (one way) 18462306a36Sopenharmony_ci * 18562306a36Sopenharmony_ci * because we limit to 6,45 meters the multiplication with 106 just 18662306a36Sopenharmony_ci * fits into 32 bit 18762306a36Sopenharmony_ci */ 18862306a36Sopenharmony_ci distance_mm = time_ns * 106 / 617176; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci return distance_mm; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic int srf04_read_raw(struct iio_dev *indio_dev, 19462306a36Sopenharmony_ci struct iio_chan_spec const *channel, int *val, 19562306a36Sopenharmony_ci int *val2, long info) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci struct srf04_data *data = iio_priv(indio_dev); 19862306a36Sopenharmony_ci int ret; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (channel->type != IIO_DISTANCE) 20162306a36Sopenharmony_ci return -EINVAL; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci switch (info) { 20462306a36Sopenharmony_ci case IIO_CHAN_INFO_RAW: 20562306a36Sopenharmony_ci ret = srf04_read(data); 20662306a36Sopenharmony_ci if (ret < 0) 20762306a36Sopenharmony_ci return ret; 20862306a36Sopenharmony_ci *val = ret; 20962306a36Sopenharmony_ci return IIO_VAL_INT; 21062306a36Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 21162306a36Sopenharmony_ci /* 21262306a36Sopenharmony_ci * theoretical maximum resolution is 3 mm 21362306a36Sopenharmony_ci * 1 LSB is 1 mm 21462306a36Sopenharmony_ci */ 21562306a36Sopenharmony_ci *val = 0; 21662306a36Sopenharmony_ci *val2 = 1000; 21762306a36Sopenharmony_ci return IIO_VAL_INT_PLUS_MICRO; 21862306a36Sopenharmony_ci default: 21962306a36Sopenharmony_ci return -EINVAL; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic const struct iio_info srf04_iio_info = { 22462306a36Sopenharmony_ci .read_raw = srf04_read_raw, 22562306a36Sopenharmony_ci}; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic const struct iio_chan_spec srf04_chan_spec[] = { 22862306a36Sopenharmony_ci { 22962306a36Sopenharmony_ci .type = IIO_DISTANCE, 23062306a36Sopenharmony_ci .info_mask_separate = 23162306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_RAW) | 23262306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE), 23362306a36Sopenharmony_ci }, 23462306a36Sopenharmony_ci}; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic const struct of_device_id of_srf04_match[] = { 23762306a36Sopenharmony_ci { .compatible = "devantech,srf04", .data = &srf04_cfg }, 23862306a36Sopenharmony_ci { .compatible = "maxbotix,mb1000", .data = &mb_lv_cfg }, 23962306a36Sopenharmony_ci { .compatible = "maxbotix,mb1010", .data = &mb_lv_cfg }, 24062306a36Sopenharmony_ci { .compatible = "maxbotix,mb1020", .data = &mb_lv_cfg }, 24162306a36Sopenharmony_ci { .compatible = "maxbotix,mb1030", .data = &mb_lv_cfg }, 24262306a36Sopenharmony_ci { .compatible = "maxbotix,mb1040", .data = &mb_lv_cfg }, 24362306a36Sopenharmony_ci {}, 24462306a36Sopenharmony_ci}; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_srf04_match); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic int srf04_probe(struct platform_device *pdev) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci struct device *dev = &pdev->dev; 25162306a36Sopenharmony_ci struct srf04_data *data; 25262306a36Sopenharmony_ci struct iio_dev *indio_dev; 25362306a36Sopenharmony_ci int ret; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci indio_dev = devm_iio_device_alloc(dev, sizeof(struct srf04_data)); 25662306a36Sopenharmony_ci if (!indio_dev) { 25762306a36Sopenharmony_ci dev_err(dev, "failed to allocate IIO device\n"); 25862306a36Sopenharmony_ci return -ENOMEM; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci data = iio_priv(indio_dev); 26262306a36Sopenharmony_ci data->dev = dev; 26362306a36Sopenharmony_ci data->cfg = device_get_match_data(dev); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci mutex_init(&data->lock); 26662306a36Sopenharmony_ci init_completion(&data->rising); 26762306a36Sopenharmony_ci init_completion(&data->falling); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci data->gpiod_trig = devm_gpiod_get(dev, "trig", GPIOD_OUT_LOW); 27062306a36Sopenharmony_ci if (IS_ERR(data->gpiod_trig)) { 27162306a36Sopenharmony_ci dev_err(dev, "failed to get trig-gpios: err=%ld\n", 27262306a36Sopenharmony_ci PTR_ERR(data->gpiod_trig)); 27362306a36Sopenharmony_ci return PTR_ERR(data->gpiod_trig); 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci data->gpiod_echo = devm_gpiod_get(dev, "echo", GPIOD_IN); 27762306a36Sopenharmony_ci if (IS_ERR(data->gpiod_echo)) { 27862306a36Sopenharmony_ci dev_err(dev, "failed to get echo-gpios: err=%ld\n", 27962306a36Sopenharmony_ci PTR_ERR(data->gpiod_echo)); 28062306a36Sopenharmony_ci return PTR_ERR(data->gpiod_echo); 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci data->gpiod_power = devm_gpiod_get_optional(dev, "power", 28462306a36Sopenharmony_ci GPIOD_OUT_LOW); 28562306a36Sopenharmony_ci if (IS_ERR(data->gpiod_power)) { 28662306a36Sopenharmony_ci dev_err(dev, "failed to get power-gpios: err=%ld\n", 28762306a36Sopenharmony_ci PTR_ERR(data->gpiod_power)); 28862306a36Sopenharmony_ci return PTR_ERR(data->gpiod_power); 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci if (data->gpiod_power) { 29162306a36Sopenharmony_ci data->startup_time_ms = 100; 29262306a36Sopenharmony_ci device_property_read_u32(dev, "startup-time-ms", &data->startup_time_ms); 29362306a36Sopenharmony_ci dev_dbg(dev, "using power gpio: startup-time-ms=%d\n", 29462306a36Sopenharmony_ci data->startup_time_ms); 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (gpiod_cansleep(data->gpiod_echo)) { 29862306a36Sopenharmony_ci dev_err(data->dev, "cansleep-GPIOs not supported\n"); 29962306a36Sopenharmony_ci return -ENODEV; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci data->irqnr = gpiod_to_irq(data->gpiod_echo); 30362306a36Sopenharmony_ci if (data->irqnr < 0) { 30462306a36Sopenharmony_ci dev_err(data->dev, "gpiod_to_irq: %d\n", data->irqnr); 30562306a36Sopenharmony_ci return data->irqnr; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci ret = devm_request_irq(dev, data->irqnr, srf04_handle_irq, 30962306a36Sopenharmony_ci IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 31062306a36Sopenharmony_ci pdev->name, indio_dev); 31162306a36Sopenharmony_ci if (ret < 0) { 31262306a36Sopenharmony_ci dev_err(data->dev, "request_irq: %d\n", ret); 31362306a36Sopenharmony_ci return ret; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci platform_set_drvdata(pdev, indio_dev); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci indio_dev->name = "srf04"; 31962306a36Sopenharmony_ci indio_dev->info = &srf04_iio_info; 32062306a36Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 32162306a36Sopenharmony_ci indio_dev->channels = srf04_chan_spec; 32262306a36Sopenharmony_ci indio_dev->num_channels = ARRAY_SIZE(srf04_chan_spec); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci ret = iio_device_register(indio_dev); 32562306a36Sopenharmony_ci if (ret < 0) { 32662306a36Sopenharmony_ci dev_err(data->dev, "iio_device_register: %d\n", ret); 32762306a36Sopenharmony_ci return ret; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (data->gpiod_power) { 33162306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(data->dev, 1000); 33262306a36Sopenharmony_ci pm_runtime_use_autosuspend(data->dev); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci ret = pm_runtime_set_active(data->dev); 33562306a36Sopenharmony_ci if (ret) { 33662306a36Sopenharmony_ci dev_err(data->dev, "pm_runtime_set_active: %d\n", ret); 33762306a36Sopenharmony_ci iio_device_unregister(indio_dev); 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci pm_runtime_enable(data->dev); 34162306a36Sopenharmony_ci pm_runtime_idle(data->dev); 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return ret; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic int srf04_remove(struct platform_device *pdev) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci struct iio_dev *indio_dev = platform_get_drvdata(pdev); 35062306a36Sopenharmony_ci struct srf04_data *data = iio_priv(indio_dev); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci iio_device_unregister(indio_dev); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (data->gpiod_power) { 35562306a36Sopenharmony_ci pm_runtime_disable(data->dev); 35662306a36Sopenharmony_ci pm_runtime_set_suspended(data->dev); 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci return 0; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic int srf04_pm_runtime_suspend(struct device *dev) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci struct platform_device *pdev = container_of(dev, 36562306a36Sopenharmony_ci struct platform_device, dev); 36662306a36Sopenharmony_ci struct iio_dev *indio_dev = platform_get_drvdata(pdev); 36762306a36Sopenharmony_ci struct srf04_data *data = iio_priv(indio_dev); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci gpiod_set_value(data->gpiod_power, 0); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci return 0; 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic int srf04_pm_runtime_resume(struct device *dev) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci struct platform_device *pdev = container_of(dev, 37762306a36Sopenharmony_ci struct platform_device, dev); 37862306a36Sopenharmony_ci struct iio_dev *indio_dev = platform_get_drvdata(pdev); 37962306a36Sopenharmony_ci struct srf04_data *data = iio_priv(indio_dev); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci gpiod_set_value(data->gpiod_power, 1); 38262306a36Sopenharmony_ci msleep(data->startup_time_ms); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci return 0; 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic const struct dev_pm_ops srf04_pm_ops = { 38862306a36Sopenharmony_ci RUNTIME_PM_OPS(srf04_pm_runtime_suspend, 38962306a36Sopenharmony_ci srf04_pm_runtime_resume, NULL) 39062306a36Sopenharmony_ci}; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic struct platform_driver srf04_driver = { 39362306a36Sopenharmony_ci .probe = srf04_probe, 39462306a36Sopenharmony_ci .remove = srf04_remove, 39562306a36Sopenharmony_ci .driver = { 39662306a36Sopenharmony_ci .name = "srf04-gpio", 39762306a36Sopenharmony_ci .of_match_table = of_srf04_match, 39862306a36Sopenharmony_ci .pm = pm_ptr(&srf04_pm_ops), 39962306a36Sopenharmony_ci }, 40062306a36Sopenharmony_ci}; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cimodule_platform_driver(srf04_driver); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ciMODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>"); 40562306a36Sopenharmony_ciMODULE_DESCRIPTION("SRF04 ultrasonic sensor for distance measuring using GPIOs"); 40662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 40762306a36Sopenharmony_ciMODULE_ALIAS("platform:srf04"); 408