drivers/iio/proximity/srf04.c

Source file repositories/reference/linux-study-clean/drivers/iio/proximity/srf04.c

File Facts

System
Linux kernel
Corpus path
drivers/iio/proximity/srf04.c
Extension
.c
Size
10444 bytes
Lines
402
Domain
Driver Families
Bucket
drivers/iio
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct srf04_cfg {
	unsigned long trigger_pulse_us;
};

struct srf04_data {
	struct device		*dev;
	struct gpio_desc	*gpiod_trig;
	struct gpio_desc	*gpiod_echo;
	struct gpio_desc	*gpiod_power;
	struct mutex		lock;
	int			irqnr;
	ktime_t			ts_rising;
	ktime_t			ts_falling;
	struct completion	rising;
	struct completion	falling;
	const struct srf04_cfg	*cfg;
	int			startup_time_ms;
};

static const struct srf04_cfg srf04_cfg = {
	.trigger_pulse_us = 10,
};

static const struct srf04_cfg mb_lv_cfg = {
	.trigger_pulse_us = 20,
};

static irqreturn_t srf04_handle_irq(int irq, void *dev_id)
{
	struct iio_dev *indio_dev = dev_id;
	struct srf04_data *data = iio_priv(indio_dev);
	ktime_t now = ktime_get();

	if (gpiod_get_value(data->gpiod_echo)) {
		data->ts_rising = now;
		complete(&data->rising);
	} else {
		data->ts_falling = now;
		complete(&data->falling);
	}

	return IRQ_HANDLED;
}

static int srf04_read(struct srf04_data *data)
{
	int ret;
	ktime_t ktime_dt;
	u64 dt_ns;
	u32 time_ns, distance_mm;

	if (data->gpiod_power) {
		ret = pm_runtime_resume_and_get(data->dev);
		if (ret < 0)
			return ret;
	}
	/*
	 * just one read-echo-cycle can take place at a time
	 * ==> lock against concurrent reading calls
	 */
	mutex_lock(&data->lock);

	reinit_completion(&data->rising);
	reinit_completion(&data->falling);

	gpiod_set_value(data->gpiod_trig, 1);
	udelay(data->cfg->trigger_pulse_us);
	gpiod_set_value(data->gpiod_trig, 0);

	if (data->gpiod_power)
		pm_runtime_put_autosuspend(data->dev);

	/* it should not take more than 20 ms until echo is rising */
	ret = wait_for_completion_killable_timeout(&data->rising, HZ/50);
	if (ret < 0) {
		mutex_unlock(&data->lock);
		return ret;
	} else if (ret == 0) {
		mutex_unlock(&data->lock);
		return -ETIMEDOUT;
	}

	/* it cannot take more than 50 ms until echo is falling */
	ret = wait_for_completion_killable_timeout(&data->falling, HZ/20);
	if (ret < 0) {
		mutex_unlock(&data->lock);
		return ret;
	} else if (ret == 0) {
		mutex_unlock(&data->lock);
		return -ETIMEDOUT;

Annotation

Implementation Notes