summaryrefslogtreecommitdiff
path: root/drivers/iio/accel/bmc150-accel-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/accel/bmc150-accel-core.c')
-rw-r--r--drivers/iio/accel/bmc150-accel-core.c78
1 files changed, 64 insertions, 14 deletions
diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c
index 5ce384ebe6c7..e8693a42ad46 100644
--- a/drivers/iio/accel/bmc150-accel-core.c
+++ b/drivers/iio/accel/bmc150-accel-core.c
@@ -10,6 +10,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/acpi.h>
+#include <linux/of_irq.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/iio/iio.h>
@@ -57,12 +58,18 @@
#define BMC150_ACCEL_RESET_VAL 0xB6
#define BMC150_ACCEL_REG_INT_MAP_0 0x19
-#define BMC150_ACCEL_INT_MAP_0_BIT_SLOPE BIT(2)
+#define BMC150_ACCEL_INT_MAP_0_BIT_INT1_SLOPE BIT(2)
#define BMC150_ACCEL_REG_INT_MAP_1 0x1A
-#define BMC150_ACCEL_INT_MAP_1_BIT_DATA BIT(0)
-#define BMC150_ACCEL_INT_MAP_1_BIT_FWM BIT(1)
-#define BMC150_ACCEL_INT_MAP_1_BIT_FFULL BIT(2)
+#define BMC150_ACCEL_INT_MAP_1_BIT_INT1_DATA BIT(0)
+#define BMC150_ACCEL_INT_MAP_1_BIT_INT1_FWM BIT(1)
+#define BMC150_ACCEL_INT_MAP_1_BIT_INT1_FFULL BIT(2)
+#define BMC150_ACCEL_INT_MAP_1_BIT_INT2_FFULL BIT(5)
+#define BMC150_ACCEL_INT_MAP_1_BIT_INT2_FWM BIT(6)
+#define BMC150_ACCEL_INT_MAP_1_BIT_INT2_DATA BIT(7)
+
+#define BMC150_ACCEL_REG_INT_MAP_2 0x1B
+#define BMC150_ACCEL_INT_MAP_2_BIT_INT2_SLOPE BIT(2)
#define BMC150_ACCEL_REG_INT_RST_LATCH 0x21
#define BMC150_ACCEL_INT_MODE_LATCH_RESET 0x80
@@ -81,6 +88,7 @@
#define BMC150_ACCEL_REG_INT_OUT_CTRL 0x20
#define BMC150_ACCEL_INT_OUT_CTRL_INT1_LVL BIT(0)
+#define BMC150_ACCEL_INT_OUT_CTRL_INT2_LVL BIT(2)
#define BMC150_ACCEL_REG_INT_5 0x27
#define BMC150_ACCEL_SLOPE_DUR_MASK 0x03
@@ -476,21 +484,24 @@ static bool bmc150_apply_acpi_orientation(struct device *dev,
}
#endif
-static const struct bmc150_accel_interrupt_info {
+struct bmc150_accel_interrupt_info {
u8 map_reg;
u8 map_bitmask;
u8 en_reg;
u8 en_bitmask;
-} bmc150_accel_interrupts[BMC150_ACCEL_INTERRUPTS] = {
+};
+
+static const struct bmc150_accel_interrupt_info
+bmc150_accel_interrupts_int1[BMC150_ACCEL_INTERRUPTS] = {
{ /* data ready interrupt */
.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
- .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_DATA,
+ .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_INT1_DATA,
.en_reg = BMC150_ACCEL_REG_INT_EN_1,
.en_bitmask = BMC150_ACCEL_INT_EN_BIT_DATA_EN,
},
{ /* motion interrupt */
.map_reg = BMC150_ACCEL_REG_INT_MAP_0,
- .map_bitmask = BMC150_ACCEL_INT_MAP_0_BIT_SLOPE,
+ .map_bitmask = BMC150_ACCEL_INT_MAP_0_BIT_INT1_SLOPE,
.en_reg = BMC150_ACCEL_REG_INT_EN_0,
.en_bitmask = BMC150_ACCEL_INT_EN_BIT_SLP_X |
BMC150_ACCEL_INT_EN_BIT_SLP_Y |
@@ -498,19 +509,56 @@ static const struct bmc150_accel_interrupt_info {
},
{ /* fifo watermark interrupt */
.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
- .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_FWM,
+ .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_INT1_FWM,
+ .en_reg = BMC150_ACCEL_REG_INT_EN_1,
+ .en_bitmask = BMC150_ACCEL_INT_EN_BIT_FWM_EN,
+ },
+};
+
+static const struct bmc150_accel_interrupt_info
+bmc150_accel_interrupts_int2[BMC150_ACCEL_INTERRUPTS] = {
+ { /* data ready interrupt */
+ .map_reg = BMC150_ACCEL_REG_INT_MAP_1,
+ .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_INT2_DATA,
+ .en_reg = BMC150_ACCEL_REG_INT_EN_1,
+ .en_bitmask = BMC150_ACCEL_INT_EN_BIT_DATA_EN,
+ },
+ { /* motion interrupt */
+ .map_reg = BMC150_ACCEL_REG_INT_MAP_2,
+ .map_bitmask = BMC150_ACCEL_INT_MAP_2_BIT_INT2_SLOPE,
+ .en_reg = BMC150_ACCEL_REG_INT_EN_0,
+ .en_bitmask = BMC150_ACCEL_INT_EN_BIT_SLP_X |
+ BMC150_ACCEL_INT_EN_BIT_SLP_Y |
+ BMC150_ACCEL_INT_EN_BIT_SLP_Z
+ },
+ { /* fifo watermark interrupt */
+ .map_reg = BMC150_ACCEL_REG_INT_MAP_1,
+ .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_INT2_FWM,
.en_reg = BMC150_ACCEL_REG_INT_EN_1,
.en_bitmask = BMC150_ACCEL_INT_EN_BIT_FWM_EN,
},
};
static void bmc150_accel_interrupts_setup(struct iio_dev *indio_dev,
- struct bmc150_accel_data *data)
+ struct bmc150_accel_data *data, int irq)
{
+ const struct bmc150_accel_interrupt_info *irq_info = NULL;
+ struct device *dev = regmap_get_device(data->regmap);
int i;
+ /*
+ * For now we map all interrupts to the same output pin.
+ * However, some boards may have just INT2 (and not INT1) connected,
+ * so we try to detect which IRQ it is based on the interrupt-names.
+ * Without interrupt-names, we assume the irq belongs to INT1.
+ */
+ irq_info = bmc150_accel_interrupts_int1;
+ if (data->type == BOSCH_BMC156 ||
+ irq == of_irq_get_byname(dev->of_node, "INT2"))
+ irq_info = bmc150_accel_interrupts_int2;
+
for (i = 0; i < BMC150_ACCEL_INTERRUPTS; i++)
- data->interrupts[i].info = &bmc150_accel_interrupts[i];
+ data->interrupts[i].info = &irq_info[i];
}
static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i,
@@ -1127,7 +1175,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
{306458, BMC150_ACCEL_DEF_RANGE_16G} },
},
{
- .name = "BMA253/BMA254/BMA255/BMC150/BMI055",
+ .name = "BMA253/BMA254/BMA255/BMC150/BMC156/BMI055",
.chip_id = 0xFA,
.channels = bmc150_accel_channels,
.num_channels = ARRAY_SIZE(bmc150_accel_channels),
@@ -1614,7 +1662,8 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
}
int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
- const char *name, bool block_supported)
+ enum bmc150_type type, const char *name,
+ bool block_supported)
{
const struct attribute **fifo_attrs;
struct bmc150_accel_data *data;
@@ -1629,6 +1678,7 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
dev_set_drvdata(dev, indio_dev);
data->regmap = regmap;
+ data->type = type;
if (!bmc150_apply_acpi_orientation(dev, &data->orientation)) {
ret = iio_read_mount_matrix(dev, &data->orientation);
@@ -1714,7 +1764,7 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
goto err_buffer_cleanup;
}
- bmc150_accel_interrupts_setup(indio_dev, data);
+ bmc150_accel_interrupts_setup(indio_dev, data, irq);
ret = bmc150_accel_triggers_setup(indio_dev, data);
if (ret)