iio: mpl3115: add support for DRDY interrupt

MPL3115 sensor features a "data ready" interrupt which indicates the
presence of new measurements.

Signed-off-by: Antoni Pokusinski <apokusinski01@gmail.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
This commit is contained in:
Antoni Pokusinski
2025-10-02 22:02:05 +02:00
committed by Jonathan Cameron
parent b4105b2031
commit 8464f61099

View File

@@ -7,40 +7,66 @@
* (7-bit I2C slave address 0x60)
*
* TODO: FIFO buffer, altimeter mode, oversampling, continuous mode,
* interrupts, user offset correction, raw mode
* user offset correction, raw mode
*/
#include <linux/module.h>
#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/buffer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/delay.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/trigger.h>
#define MPL3115_STATUS 0x00
#define MPL3115_OUT_PRESS 0x01 /* MSB first, 20 bit */
#define MPL3115_OUT_TEMP 0x04 /* MSB first, 12 bit */
#define MPL3115_WHO_AM_I 0x0c
#define MPL3115_INT_SOURCE 0x12
#define MPL3115_PT_DATA_CFG 0x13
#define MPL3115_CTRL_REG1 0x26
#define MPL3115_CTRL_REG3 0x28
#define MPL3115_CTRL_REG4 0x29
#define MPL3115_CTRL_REG5 0x2a
#define MPL3115_DEVICE_ID 0xc4
#define MPL3115_STATUS_PRESS_RDY BIT(2)
#define MPL3115_STATUS_TEMP_RDY BIT(1)
#define MPL3115_INT_SRC_DRDY BIT(7)
#define MPL3115_PT_DATA_EVENT_ALL GENMASK(2, 0)
#define MPL3115_CTRL1_RESET BIT(2) /* software reset */
#define MPL3115_CTRL1_OST BIT(1) /* initiate measurement */
#define MPL3115_CTRL1_ACTIVE BIT(0) /* continuous measurement */
#define MPL3115_CTRL1_OS_258MS GENMASK(5, 4) /* 64x oversampling */
#define MPL3115_CTRL3_IPOL1 BIT(5)
#define MPL3115_CTRL3_IPOL2 BIT(1)
#define MPL3115_CTRL4_INT_EN_DRDY BIT(7)
#define MPL3115_CTRL5_INT_CFG_DRDY BIT(7)
struct mpl3115_data {
struct i2c_client *client;
struct iio_trigger *drdy_trig;
struct mutex lock;
u8 ctrl_reg1;
};
enum mpl3115_irq_pin {
MPL3115_IRQ_INT1,
MPL3115_IRQ_INT2,
};
static int mpl3115_request(struct mpl3115_data *data)
{
int ret, tries = 15;
@@ -153,9 +179,11 @@ static int mpl3115_fill_trig_buffer(struct iio_dev *indio_dev, u8 *buffer)
struct mpl3115_data *data = iio_priv(indio_dev);
int ret, pos = 0;
ret = mpl3115_request(data);
if (ret < 0)
return ret;
if (!(data->ctrl_reg1 & MPL3115_CTRL1_ACTIVE)) {
ret = mpl3115_request(data);
if (ret < 0)
return ret;
}
if (test_bit(0, indio_dev->active_scan_mask)) {
ret = i2c_smbus_read_i2c_block_data(data->client,
@@ -234,10 +262,145 @@ static const struct iio_chan_spec mpl3115_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(2),
};
static irqreturn_t mpl3115_interrupt_handler(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct mpl3115_data *data = iio_priv(indio_dev);
int ret;
ret = i2c_smbus_read_byte_data(data->client, MPL3115_INT_SOURCE);
if (ret < 0)
return IRQ_HANDLED;
if (!(ret & MPL3115_INT_SRC_DRDY))
return IRQ_NONE;
iio_trigger_poll_nested(data->drdy_trig);
return IRQ_HANDLED;
}
static int mpl3115_config_interrupt(struct mpl3115_data *data,
u8 ctrl_reg1, u8 ctrl_reg4)
{
int ret;
ret = i2c_smbus_write_byte_data(data->client, MPL3115_CTRL_REG1,
ctrl_reg1);
if (ret < 0)
return ret;
ret = i2c_smbus_write_byte_data(data->client, MPL3115_CTRL_REG4,
ctrl_reg4);
if (ret < 0)
goto reg1_cleanup;
data->ctrl_reg1 = ctrl_reg1;
return 0;
reg1_cleanup:
i2c_smbus_write_byte_data(data->client, MPL3115_CTRL_REG1,
data->ctrl_reg1);
return ret;
}
static int mpl3115_set_trigger_state(struct iio_trigger *trig, bool state)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct mpl3115_data *data = iio_priv(indio_dev);
u8 ctrl_reg1 = data->ctrl_reg1;
u8 ctrl_reg4 = state ? MPL3115_CTRL4_INT_EN_DRDY : 0;
if (state)
ctrl_reg1 |= MPL3115_CTRL1_ACTIVE;
else
ctrl_reg1 &= ~MPL3115_CTRL1_ACTIVE;
guard(mutex)(&data->lock);
return mpl3115_config_interrupt(data, ctrl_reg1, ctrl_reg4);
}
static const struct iio_trigger_ops mpl3115_trigger_ops = {
.set_trigger_state = mpl3115_set_trigger_state,
};
static const struct iio_info mpl3115_info = {
.read_raw = &mpl3115_read_raw,
};
static int mpl3115_trigger_probe(struct mpl3115_data *data,
struct iio_dev *indio_dev)
{
struct fwnode_handle *fwnode = dev_fwnode(&data->client->dev);
int ret, irq, irq_type, irq_pin = MPL3115_IRQ_INT1;
irq = fwnode_irq_get_byname(fwnode, "INT1");
if (irq < 0) {
irq = fwnode_irq_get_byname(fwnode, "INT2");
if (irq < 0)
return 0;
irq_pin = MPL3115_IRQ_INT2;
}
irq_type = irq_get_trigger_type(irq);
if (irq_type != IRQF_TRIGGER_RISING && irq_type != IRQF_TRIGGER_FALLING)
return -EINVAL;
ret = i2c_smbus_write_byte_data(data->client, MPL3115_PT_DATA_CFG,
MPL3115_PT_DATA_EVENT_ALL);
if (ret < 0)
return ret;
if (irq_pin == MPL3115_IRQ_INT1) {
ret = i2c_smbus_write_byte_data(data->client,
MPL3115_CTRL_REG5,
MPL3115_CTRL5_INT_CFG_DRDY);
if (ret)
return ret;
if (irq_type == IRQF_TRIGGER_RISING) {
ret = i2c_smbus_write_byte_data(data->client,
MPL3115_CTRL_REG3,
MPL3115_CTRL3_IPOL1);
if (ret)
return ret;
}
} else if (irq_type == IRQF_TRIGGER_RISING) {
ret = i2c_smbus_write_byte_data(data->client, MPL3115_CTRL_REG3,
MPL3115_CTRL3_IPOL2);
if (ret)
return ret;
}
data->drdy_trig = devm_iio_trigger_alloc(&data->client->dev,
"%s-dev%d",
indio_dev->name,
iio_device_id(indio_dev));
if (!data->drdy_trig)
return -ENOMEM;
data->drdy_trig->ops = &mpl3115_trigger_ops;
iio_trigger_set_drvdata(data->drdy_trig, indio_dev);
ret = devm_request_threaded_irq(&data->client->dev, irq, NULL,
mpl3115_interrupt_handler,
IRQF_ONESHOT,
"mpl3115_irq", indio_dev);
if (ret)
return ret;
ret = devm_iio_trigger_register(&data->client->dev, data->drdy_trig);
if (ret)
return ret;
indio_dev->trig = iio_trigger_get(data->drdy_trig);
return 0;
}
static int mpl3115_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
@@ -277,6 +440,10 @@ static int mpl3115_probe(struct i2c_client *client)
if (ret < 0)
return ret;
ret = mpl3115_trigger_probe(data, indio_dev);
if (ret)
return ret;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
mpl3115_trigger_handler, NULL);
if (ret < 0)