#include <linux/spinlock.h>
#include <linux/iio/iio.h>
#include <linux/acpi.h>
+#include <linux/platform_device.h>
#include "inv_mpu_iio.h"
/*
.raw_accl = INV_MPU6050_REG_RAW_ACCEL,
.temperature = INV_MPU6050_REG_TEMPERATURE,
.int_enable = INV_MPU6050_REG_INT_ENABLE,
+ .int_status = INV_MPU6050_REG_INT_STATUS,
.pwr_mgmt_1 = INV_MPU6050_REG_PWR_MGMT_1,
.pwr_mgmt_2 = INV_MPU6050_REG_PWR_MGMT_2,
.int_pin_cfg = INV_MPU6050_REG_INT_PIN_CFG,
if (result)
return result;
+ result = regmap_write(st->map, st->reg->int_pin_cfg, st->irq_mask);
+ if (result)
+ return result;
+
memcpy(&st->chip_config, hw_info[st->chip_type].config,
sizeof(struct inv_mpu6050_chip_config));
result = inv_mpu6050_set_power_itg(st, false);
struct inv_mpu6050_platform_data *pdata;
struct device *dev = regmap_get_device(regmap);
int result;
+ struct irq_data *desc;
+ int irq_type;
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
st->plat_data = *pdata;
}
+ desc = irq_get_irq_data(irq);
+ if (!desc) {
+ dev_err(dev, "Could not find IRQ %d\n", irq);
+ return -EINVAL;
+ }
+
+ irq_type = irqd_get_trigger_type(desc);
+ if (irq_type == IRQF_TRIGGER_RISING)
+ st->irq_mask = INV_MPU6050_ACTIVE_HIGH;
+ else if (irq_type == IRQF_TRIGGER_FALLING)
+ st->irq_mask = INV_MPU6050_ACTIVE_LOW;
+ else if (irq_type == IRQF_TRIGGER_HIGH)
+ st->irq_mask = INV_MPU6050_ACTIVE_HIGH |
+ INV_MPU6050_LATCH_INT_EN;
+ else if (irq_type == IRQF_TRIGGER_LOW)
+ st->irq_mask = INV_MPU6050_ACTIVE_LOW |
+ INV_MPU6050_LATCH_INT_EN;
+ else {
+ dev_err(dev, "Invalid interrupt type 0x%x specified\n",
+ irq_type);
+ return -EINVAL;
+ }
+
/* power is turned on inside check chip type*/
result = inv_check_and_setup_chip(st);
if (result)
dev_err(dev, "configure buffer fail %d\n", result);
return result;
}
- result = inv_mpu6050_probe_trigger(indio_dev);
+ result = inv_mpu6050_probe_trigger(indio_dev, irq_type);
if (result) {
dev_err(dev, "trigger probe fail %d\n", result);
goto out_unreg_ring;
goto error_unlock;
ret = regmap_write(st->map, st->reg->int_pin_cfg,
- INV_MPU6050_INT_PIN_CFG |
- INV_MPU6050_BIT_BYPASS_EN);
+ st->irq_mask | INV_MPU6050_BIT_BYPASS_EN);
error_unlock:
mutex_unlock(&st->lock);
mutex_lock(&st->lock);
/* It doesn't really mattter, if any of the calls fails */
- regmap_write(st->map, st->reg->int_pin_cfg, INV_MPU6050_INT_PIN_CFG);
+ regmap_write(st->map, st->reg->int_pin_cfg, st->irq_mask);
inv_mpu6050_set_power_itg(st, false);
mutex_unlock(&st->lock);
* @raw_accl: Address of first accel register.
* @temperature: temperature register
* @int_enable: Interrupt enable register.
+ * @int_status: Interrupt status register.
* @pwr_mgmt_1: Controls chip's power state and clock source.
* @pwr_mgmt_2: Controls power state of individual sensors.
* @int_pin_cfg; Controls interrupt pin configuration.
u8 raw_accl;
u8 temperature;
u8 int_enable;
+ u8 int_status;
u8 pwr_mgmt_1;
u8 pwr_mgmt_2;
u8 int_pin_cfg;
* @timestamps: kfifo queue to store time stamp.
* @map regmap pointer.
* @irq interrupt number.
+ * @irq_mask the int_pin_cfg mask to configure interrupt type.
*/
struct inv_mpu6050_state {
#define TIMESTAMP_FIFO_SIZE 16
DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE);
struct regmap *map;
int irq;
+ u8 irq_mask;
};
/*register and associated bit definition*/
#define INV_MPU6050_REG_TEMPERATURE 0x41
#define INV_MPU6050_REG_RAW_GYRO 0x43
+#define INV_MPU6050_REG_INT_STATUS 0x3A
+#define INV_MPU6050_BIT_RAW_DATA_RDY_INT 0x01
+
#define INV_MPU6050_REG_USER_CTRL 0x6A
#define INV_MPU6050_BIT_FIFO_RST 0x04
#define INV_MPU6050_BIT_DMP_RST 0x08
#define INV_MPU6050_OUTPUT_DATA_SIZE 24
#define INV_MPU6050_REG_INT_PIN_CFG 0x37
+#define INV_MPU6050_ACTIVE_HIGH 0x00
+#define INV_MPU6050_ACTIVE_LOW 0x80
+/* enable level triggering */
+#define INV_MPU6050_LATCH_INT_EN 0x20
#define INV_MPU6050_BIT_BYPASS_EN 0x2
-#define INV_MPU6050_INT_PIN_CFG 0
+
/* init parameters */
#define INV_MPU6050_INIT_FIFO_RATE 50
irqreturn_t inv_mpu6050_irq_handler(int irq, void *p);
irqreturn_t inv_mpu6050_read_fifo(int irq, void *p);
-int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev);
+int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev, int irq_type);
void inv_mpu6050_remove_trigger(struct inv_mpu6050_state *st);
int inv_reset_fifo(struct iio_dev *indio_dev);
int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask);
u8 data[INV_MPU6050_OUTPUT_DATA_SIZE];
u16 fifo_count;
s64 timestamp;
+ int int_status;
mutex_lock(&st->lock);
+
+ /* ack interrupt and check status */
+ result = regmap_read(st->map, st->reg->int_status, &int_status);
+ if (result) {
+ dev_err(regmap_get_device(st->map),
+ "failed to ack interrupt\n");
+ goto flush_fifo;
+ }
+ if (!(int_status & INV_MPU6050_BIT_RAW_DATA_RDY_INT)) {
+ dev_warn(regmap_get_device(st->map),
+ "spurious interrupt with status 0x%x\n", int_status);
+ goto end_session;
+ }
+
if (!(st->chip_config.accl_fifo_enable |
st->chip_config.gyro_fifo_enable))
goto end_session;
.set_trigger_state = &inv_mpu_data_rdy_trigger_set_state,
};
-int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev)
+int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev, int irq_type)
{
int ret;
struct inv_mpu6050_state *st = iio_priv(indio_dev);
ret = devm_request_irq(&indio_dev->dev, st->irq,
&iio_trigger_generic_data_rdy_poll,
- IRQF_TRIGGER_RISING,
+ irq_type,
"inv_mpu",
st->trig);
if (ret)