mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-06-08 06:20:14 -04:00
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:
committed by
Jonathan Cameron
parent
b4105b2031
commit
8464f61099
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user