[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250518111321.75226-8-l.rubusch@gmail.com>
Date: Sun, 18 May 2025 11:13:16 +0000
From: Lothar Rubusch <l.rubusch@...il.com>
To: jic23@...nel.org,
dlechner@...libre.com,
nuno.sa@...log.com,
andy@...nel.org,
corbet@....net,
lucas.p.stankus@...il.com,
lars@...afoo.de,
Michael.Hennerich@...log.com
Cc: linux-iio@...r.kernel.org,
linux-doc@...r.kernel.org,
linux-kernel@...r.kernel.org,
Lothar Rubusch <l.rubusch@...il.com>
Subject: [PATCH v1 07/12] iio: accel: adxl313: add basic interrupt handling
Prepare the interrupt handler. Add register entries to evaluate the
incoming interrupt. Add functions to clear status registers and reset the
FIFO.
Signed-off-by: Lothar Rubusch <l.rubusch@...il.com>
---
drivers/iio/accel/adxl313.h | 16 ++++
drivers/iio/accel/adxl313_core.c | 133 +++++++++++++++++++++++++++++++
2 files changed, 149 insertions(+)
diff --git a/drivers/iio/accel/adxl313.h b/drivers/iio/accel/adxl313.h
index c5673f1934fb..4cb1fe1f2616 100644
--- a/drivers/iio/accel/adxl313.h
+++ b/drivers/iio/accel/adxl313.h
@@ -49,11 +49,25 @@
#define ADXL313_SPI_3WIRE BIT(6)
#define ADXL313_I2C_DISABLE BIT(6)
+#define ADXL313_INT_OVERRUN BIT(0)
+#define ADXL313_INT_WATERMARK BIT(1)
+#define ADXL313_INT_INACTIVITY BIT(3)
+#define ADXL313_INT_ACTIVITY BIT(4)
+#define ADXL313_INT_DREADY BIT(7)
+
+/* FIFO entries: how many values are stored in the FIFO */
+#define ADXL313_REG_FIFO_STATUS_ENTRIES_MSK GENMASK(5, 0)
+/* FIFO samples: number of samples needed for watermark (FIFO mode) */
+#define ADXL313_REG_FIFO_CTL_SAMPLES_MSK GENMASK(4, 0)
#define ADXL313_REG_FIFO_CTL_MODE_MSK GENMASK(7, 6)
#define ADXL313_FIFO_BYPASS 0
#define ADXL313_FIFO_STREAM 2
+#define ADXL313_FIFO_SIZE 32
+
+#define ADXL313_NUM_AXIS 3
+
extern const struct regmap_access_table adxl312_readable_regs_table;
extern const struct regmap_access_table adxl313_readable_regs_table;
extern const struct regmap_access_table adxl314_readable_regs_table;
@@ -75,7 +89,9 @@ struct adxl313_data {
const struct adxl313_chip_info *chip_info;
struct mutex lock; /* lock to protect transf_buf */
int irq;
+ u8 fifo_mode;
__le16 transf_buf __aligned(IIO_DMA_MINALIGN);
+ __le16 fifo_buf[ADXL313_NUM_AXIS * ADXL313_FIFO_SIZE + 1];
};
struct adxl313_chip_info {
diff --git a/drivers/iio/accel/adxl313_core.c b/drivers/iio/accel/adxl313_core.c
index 05e99708c2c1..574962a8f35d 100644
--- a/drivers/iio/accel/adxl313_core.c
+++ b/drivers/iio/accel/adxl313_core.c
@@ -13,12 +13,20 @@
#include <linux/property.h>
#include <linux/regmap.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/sysfs.h>
+
#include "adxl313.h"
#define ADXL313_INT_NONE 0
#define ADXL313_INT1 1
#define ADXL313_INT2 2
+#define ADXL313_REG_XYZ_BASE ADXL313_REG_DATA_AXIS(0)
+
static const struct regmap_range adxl312_readable_reg_range[] = {
regmap_reg_range(ADXL313_REG_DEVID0, ADXL313_REG_DEVID0),
regmap_reg_range(ADXL313_REG_OFS_AXIS(0), ADXL313_REG_OFS_AXIS(2)),
@@ -62,6 +70,7 @@ bool adxl313_is_volatile_reg(struct device *dev, unsigned int reg)
case ADXL313_REG_DATA_AXIS(4):
case ADXL313_REG_DATA_AXIS(5):
case ADXL313_REG_FIFO_STATUS:
+ case ADXL313_REG_INT_SOURCE:
return true;
default:
return false;
@@ -365,6 +374,118 @@ static int adxl313_write_raw(struct iio_dev *indio_dev,
}
}
+static int adxl313_get_samples(struct adxl313_data *data)
+{
+ unsigned int regval = 0;
+ int ret;
+
+ ret = regmap_read(data->regmap, ADXL313_REG_FIFO_STATUS, ®val);
+ if (ret)
+ return ret;
+
+ return FIELD_GET(ADXL313_REG_FIFO_STATUS_ENTRIES_MSK, regval);
+}
+
+static int adxl313_set_fifo(struct adxl313_data *data)
+{
+ unsigned int int_line;
+ int ret;
+
+ ret = adxl313_set_measure_en(data, false);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(data->regmap, ADXL313_REG_INT_MAP, &int_line);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(data->regmap, ADXL313_REG_FIFO_CTL,
+ FIELD_PREP(ADXL313_REG_FIFO_CTL_MODE_MSK,
+ data->fifo_mode));
+
+ return adxl313_set_measure_en(data, true);
+}
+
+static int adxl313_fifo_transfer(struct adxl313_data *data, int samples)
+{
+ size_t count;
+ int i;
+ int ret;
+
+ ret = 0;
+ count = sizeof(data->fifo_buf[0]) * ADXL313_NUM_AXIS;
+ for (i = 0; i < samples; i++) {
+ ret = regmap_bulk_read(data->regmap, ADXL313_REG_XYZ_BASE,
+ data->fifo_buf + (i * count / 2), count);
+ if (ret)
+ return ret;
+ }
+ return ret;
+}
+
+static void adxl313_fifo_reset(struct adxl313_data *data)
+{
+ int regval;
+ int samples;
+
+ adxl313_set_measure_en(data, false);
+
+ /* clear samples */
+ samples = adxl313_get_samples(data);
+ if (samples)
+ adxl313_fifo_transfer(data, samples);
+
+ /* clear interrupt register */
+ regmap_read(data->regmap, ADXL313_REG_INT_SOURCE, ®val);
+
+ adxl313_set_measure_en(data, true);
+}
+
+static int adxl313_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct adxl313_data *data = iio_priv(indio_dev);
+
+ data->fifo_mode = ADXL313_FIFO_STREAM;
+ return adxl313_set_fifo(data);
+}
+
+static int adxl313_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct adxl313_data *data = iio_priv(indio_dev);
+ int ret;
+
+ data->fifo_mode = ADXL313_FIFO_BYPASS;
+ ret = adxl313_set_fifo(data);
+ if (ret)
+ return ret;
+
+ return regmap_write(data->regmap, ADXL313_REG_INT_ENABLE, 0);
+}
+
+static const struct iio_buffer_setup_ops adxl313_buffer_ops = {
+ .postenable = adxl313_buffer_postenable,
+ .predisable = adxl313_buffer_predisable,
+};
+
+static irqreturn_t adxl313_irq_handler(int irq, void *p)
+{
+ struct iio_dev *indio_dev = p;
+ struct adxl313_data *data = iio_priv(indio_dev);
+ int int_stat;
+
+ if (regmap_read(data->regmap, ADXL313_REG_INT_SOURCE, &int_stat))
+ return IRQ_NONE;
+
+ if (FIELD_GET(ADXL313_INT_OVERRUN, int_stat))
+ goto err;
+
+ return IRQ_HANDLED;
+err:
+ adxl313_fifo_reset(data);
+
+ return IRQ_HANDLED;
+}
+
static int adxl313_reg_access(struct iio_dev *indio_dev, unsigned int reg,
unsigned int writeval, unsigned int *readval)
{
@@ -486,6 +607,18 @@ int adxl313_core_probe(struct device *dev,
ret = regmap_write(data->regmap, ADXL313_REG_INT_MAP, regval);
if (ret)
return ret;
+
+ ret = devm_iio_kfifo_buffer_setup(dev, indio_dev,
+ &adxl313_buffer_ops);
+ if (ret)
+ return ret;
+
+ ret = devm_request_threaded_irq(dev, data->irq, NULL,
+ &adxl313_irq_handler,
+ IRQF_SHARED | IRQF_ONESHOT,
+ indio_dev->name, indio_dev);
+ if (ret)
+ return ret;
} else {
/* FIFO_BYPASSED mode */
ret = regmap_write(data->regmap, ADXL313_REG_FIFO_CTL,
--
2.39.5
Powered by blists - more mailing lists