Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a9fd053b authored by Linus Walleij's avatar Linus Walleij Committed by Jonathan Cameron
Browse files

iio: st_sensors: support active-low interrupts



Most ST MEMS Sensors that support interrupts can also handle sending
an active low interrupt, i.e. going from high to low on data ready
(or other interrupt) and thus triggering on a falling edge to the
interrupt controller.

Set up logic to inspect the interrupt line we get for a sensor: if
it is triggering on rising edge, leave everything alone, but if it
triggers on falling edges, set up active low, and if unsupported
configurations appear: warn with errors and reconfigure the interrupt
to a rising edge, which all interrupt generating sensors support.

Create a local header for st_sensors_core.h to share functions
between the sensor core and the trigger setup code.

Cc: Giuseppe Barba <giuseppe.barba@st.com>
Cc: Denis Ciocca <denis.ciocca@st.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Signed-off-by: default avatarJonathan Cameron <jic23@kernel.org>
parent c4f0ebd9
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -67,6 +67,8 @@
#define ST_ACCEL_1_DRDY_IRQ_ADDR		0x22
#define ST_ACCEL_1_DRDY_IRQ_INT1_MASK		0x10
#define ST_ACCEL_1_DRDY_IRQ_INT2_MASK		0x08
#define ST_ACCEL_1_IHL_IRQ_ADDR			0x25
#define ST_ACCEL_1_IHL_IRQ_MASK			0x02
#define ST_ACCEL_1_MULTIREAD_BIT		true

/* CUSTOM VALUES FOR SENSOR 2 */
@@ -92,6 +94,8 @@
#define ST_ACCEL_2_DRDY_IRQ_ADDR		0x22
#define ST_ACCEL_2_DRDY_IRQ_INT1_MASK		0x02
#define ST_ACCEL_2_DRDY_IRQ_INT2_MASK		0x10
#define ST_ACCEL_2_IHL_IRQ_ADDR			0x22
#define ST_ACCEL_2_IHL_IRQ_MASK			0x80
#define ST_ACCEL_2_MULTIREAD_BIT		true

/* CUSTOM VALUES FOR SENSOR 3 */
@@ -125,6 +129,8 @@
#define ST_ACCEL_3_DRDY_IRQ_ADDR		0x23
#define ST_ACCEL_3_DRDY_IRQ_INT1_MASK		0x80
#define ST_ACCEL_3_DRDY_IRQ_INT2_MASK		0x00
#define ST_ACCEL_3_IHL_IRQ_ADDR			0x23
#define ST_ACCEL_3_IHL_IRQ_MASK			0x40
#define ST_ACCEL_3_IG1_EN_ADDR			0x23
#define ST_ACCEL_3_IG1_EN_MASK			0x08
#define ST_ACCEL_3_MULTIREAD_BIT		false
@@ -169,6 +175,8 @@
#define ST_ACCEL_5_DRDY_IRQ_ADDR		0x22
#define ST_ACCEL_5_DRDY_IRQ_INT1_MASK		0x04
#define ST_ACCEL_5_DRDY_IRQ_INT2_MASK		0x20
#define ST_ACCEL_5_IHL_IRQ_ADDR			0x22
#define ST_ACCEL_5_IHL_IRQ_MASK			0x80
#define ST_ACCEL_5_IG1_EN_ADDR			0x21
#define ST_ACCEL_5_IG1_EN_MASK			0x08
#define ST_ACCEL_5_MULTIREAD_BIT		false
@@ -292,6 +300,8 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
			.addr = ST_ACCEL_1_DRDY_IRQ_ADDR,
			.mask_int1 = ST_ACCEL_1_DRDY_IRQ_INT1_MASK,
			.mask_int2 = ST_ACCEL_1_DRDY_IRQ_INT2_MASK,
			.addr_ihl = ST_ACCEL_1_IHL_IRQ_ADDR,
			.mask_ihl = ST_ACCEL_1_IHL_IRQ_MASK,
		},
		.multi_read_bit = ST_ACCEL_1_MULTIREAD_BIT,
		.bootime = 2,
@@ -355,6 +365,8 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
			.addr = ST_ACCEL_2_DRDY_IRQ_ADDR,
			.mask_int1 = ST_ACCEL_2_DRDY_IRQ_INT1_MASK,
			.mask_int2 = ST_ACCEL_2_DRDY_IRQ_INT2_MASK,
			.addr_ihl = ST_ACCEL_2_IHL_IRQ_ADDR,
			.mask_ihl = ST_ACCEL_2_IHL_IRQ_MASK,
		},
		.multi_read_bit = ST_ACCEL_2_MULTIREAD_BIT,
		.bootime = 2,
@@ -430,6 +442,8 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
			.addr = ST_ACCEL_3_DRDY_IRQ_ADDR,
			.mask_int1 = ST_ACCEL_3_DRDY_IRQ_INT1_MASK,
			.mask_int2 = ST_ACCEL_3_DRDY_IRQ_INT2_MASK,
			.addr_ihl = ST_ACCEL_3_IHL_IRQ_ADDR,
			.mask_ihl = ST_ACCEL_3_IHL_IRQ_MASK,
			.ig1 = {
				.en_addr = ST_ACCEL_3_IG1_EN_ADDR,
				.en_mask = ST_ACCEL_3_IG1_EN_MASK,
@@ -537,6 +551,8 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
			.addr = ST_ACCEL_5_DRDY_IRQ_ADDR,
			.mask_int1 = ST_ACCEL_5_DRDY_IRQ_INT1_MASK,
			.mask_int2 = ST_ACCEL_5_DRDY_IRQ_INT2_MASK,
			.addr_ihl = ST_ACCEL_5_IHL_IRQ_ADDR,
			.mask_ihl = ST_ACCEL_5_IHL_IRQ_MASK,
		},
		.multi_read_bit = ST_ACCEL_5_MULTIREAD_BIT,
		.bootime = 2, /* guess */
+4 −2
Original line number Diff line number Diff line
@@ -18,12 +18,14 @@
#include <asm/unaligned.h>
#include <linux/iio/common/st_sensors.h>

#include "st_sensors_core.h"

static inline u32 st_sensors_get_unaligned_le24(const u8 *p)
{
	return (s32)((p[0] | p[1] << 8 | p[2] << 16) << 8) >> 8;
}

static int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
				    u8 reg_addr, u8 mask, u8 data)
{
	int err;
+8 −0
Original line number Diff line number Diff line
/*
 * Local functions in the ST Sensors core
 */
#ifndef __ST_SENSORS_CORE_H
#define __ST_SENSORS_CORE_H
int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
				    u8 reg_addr, u8 mask, u8 data);
#endif
+42 −10
Original line number Diff line number Diff line
@@ -14,32 +14,65 @@
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/interrupt.h>

#include <linux/iio/common/st_sensors.h>

#include "st_sensors_core.h"

int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
				const struct iio_trigger_ops *trigger_ops)
{
	int err;
	int err, irq;
	struct st_sensor_data *sdata = iio_priv(indio_dev);
	unsigned long irq_trig;

	sdata->trig = iio_trigger_alloc("%s-trigger", indio_dev->name);
	if (sdata->trig == NULL) {
		err = -ENOMEM;
		dev_err(&indio_dev->dev, "failed to allocate iio trigger.\n");
		goto iio_trigger_alloc_error;
		return -ENOMEM;
	}

	err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev),
	irq = sdata->get_irq_data_ready(indio_dev);
	irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq));
	/*
	 * If the IRQ is triggered on falling edge, we need to mark the
	 * interrupt as active low, if the hardware supports this.
	 */
	if (irq_trig == IRQF_TRIGGER_FALLING) {
		if (!sdata->sensor_settings->drdy_irq.addr_ihl) {
			dev_err(&indio_dev->dev,
				"falling edge specified for IRQ but hardware "
				"only support rising edge, will request "
				"rising edge\n");
			irq_trig = IRQF_TRIGGER_RISING;
		} else {
			/* Set up INT active low i.e. falling edge */
			err = st_sensors_write_data_with_mask(indio_dev,
				sdata->sensor_settings->drdy_irq.addr_ihl,
				sdata->sensor_settings->drdy_irq.mask_ihl, 1);
			if (err < 0)
				goto iio_trigger_free;
			dev_info(&indio_dev->dev,
				 "interrupts on the falling edge\n");
		}
	} else if (irq_trig == IRQF_TRIGGER_RISING) {
		dev_info(&indio_dev->dev,
			 "interrupts on the rising edge\n");

	} else {
		dev_err(&indio_dev->dev,
		"unsupported IRQ trigger specified (%lx), only "
			"rising and falling edges supported, enforce "
			"rising edge\n", irq_trig);
		irq_trig = IRQF_TRIGGER_RISING;
	}
	err = request_threaded_irq(irq,
			iio_trigger_generic_data_rdy_poll,
			NULL,
			IRQF_TRIGGER_RISING,
			irq_trig,
			sdata->trig->name,
			sdata->trig);
	if (err) {
		dev_err(&indio_dev->dev, "failed to request trigger IRQ.\n");
		goto request_irq_error;
		goto iio_trigger_free;
	}

	iio_trigger_set_drvdata(sdata->trig, indio_dev);
@@ -57,9 +90,8 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,

iio_trigger_register_error:
	free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig);
request_irq_error:
iio_trigger_free:
	iio_trigger_free(sdata->trig);
iio_trigger_alloc_error:
	return err;
}
EXPORT_SYMBOL(st_sensors_allocate_trigger);
+15 −0
Original line number Diff line number Diff line
@@ -185,6 +185,11 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
		.drdy_irq = {
			.addr = ST_GYRO_1_DRDY_IRQ_ADDR,
			.mask_int2 = ST_GYRO_1_DRDY_IRQ_INT2_MASK,
			/*
			 * The sensor has IHL (active low) and open
			 * drain settings, but only for INT1 and not
			 * for the DRDY line on INT2.
			 */
		},
		.multi_read_bit = ST_GYRO_1_MULTIREAD_BIT,
		.bootime = 2,
@@ -248,6 +253,11 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
		.drdy_irq = {
			.addr = ST_GYRO_2_DRDY_IRQ_ADDR,
			.mask_int2 = ST_GYRO_2_DRDY_IRQ_INT2_MASK,
			/*
			 * The sensor has IHL (active low) and open
			 * drain settings, but only for INT1 and not
			 * for the DRDY line on INT2.
			 */
		},
		.multi_read_bit = ST_GYRO_2_MULTIREAD_BIT,
		.bootime = 2,
@@ -307,6 +317,11 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
		.drdy_irq = {
			.addr = ST_GYRO_3_DRDY_IRQ_ADDR,
			.mask_int2 = ST_GYRO_3_DRDY_IRQ_INT2_MASK,
			/*
			 * The sensor has IHL (active low) and open
			 * drain settings, but only for INT1 and not
			 * for the DRDY line on INT2.
			 */
		},
		.multi_read_bit = ST_GYRO_3_MULTIREAD_BIT,
		.bootime = 2,
Loading