drivers/iio/proximity/ping.c

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

File Facts

System
Linux kernel
Corpus path
drivers/iio/proximity/ping.c
Extension
.c
Size
8709 bytes
Lines
331
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 ping_cfg {
	unsigned long	trigger_pulse_us;	/* length of trigger pulse */
	int		laserping_error;	/* support error code in */
						/*   pulse width of laser */
						/*   ping sensors */
	s64		timeout_ns;		/* timeout in ns */
};

struct ping_data {
	struct device		*dev;
	struct gpio_desc	*gpiod_ping;
	struct mutex		lock;
	int			irqnr;
	ktime_t			ts_rising;
	ktime_t			ts_falling;
	struct completion	rising;
	struct completion	falling;
	const struct ping_cfg	*cfg;
};

static const struct ping_cfg pa_ping_cfg = {
	.trigger_pulse_us	= 5,
	.laserping_error	= 0,
	.timeout_ns		= 18500000,	/* 3 meters */
};

static const struct ping_cfg pa_laser_ping_cfg = {
	.trigger_pulse_us	= 5,
	.laserping_error	= 1,
	.timeout_ns		= 15500000,	/* 2 meters plus error codes */
};

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

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

	return IRQ_HANDLED;
}

static int ping_read(struct iio_dev *indio_dev)
{
	struct ping_data *data = iio_priv(indio_dev);
	int ret;
	ktime_t ktime_dt;
	s64 dt_ns;
	u32 time_ns, distance_mm;
	struct platform_device *pdev = to_platform_device(data->dev);

	/*
	 * 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_ping, 1);
	udelay(data->cfg->trigger_pulse_us);
	gpiod_set_value(data->gpiod_ping, 0);

	ret = gpiod_direction_input(data->gpiod_ping);
	if (ret < 0) {
		mutex_unlock(&data->lock);
		return ret;
	}

	data->irqnr = gpiod_to_irq(data->gpiod_ping);
	if (data->irqnr < 0) {
		dev_err(data->dev, "gpiod_to_irq: %d\n", data->irqnr);
		mutex_unlock(&data->lock);
		return data->irqnr;
	}

	ret = request_irq(data->irqnr, ping_handle_irq,
				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
							pdev->name, indio_dev);
	if (ret < 0) {
		dev_err(data->dev, "request_irq: %d\n", ret);
		mutex_unlock(&data->lock);

Annotation

Implementation Notes