iio: accel: BMC150: add support for other Bosch chips
authorLaurentiu Palcu <laurentiu.palcu@intel.com>
Sun, 9 Feb 2014 10:30:00 +0000 (10:30 +0000)
committerJonathan Cameron <jic23@kernel.org>
Sat, 13 Sep 2014 20:35:46 +0000 (21:35 +0100)
The following chips are either similar or have only the resolution
different. Hence, change this driver to support these chips too:

BMI055  - combo chip (accelerometer part is identical to BMC150's)
BMA255  - identical to BMC150's accelerometer
BMA222E - 8 bit resolution
BMA250E - 10 bit resolution
BMA280  - 14 bit resolution

Additionally:
 * add bmc150_accel_match_acpi_device() function to check that the device
   has been enumerated through ACPI;
 * rename bmc150_accel_acpi_gpio_probe() to bmc150_accel_gpio_probe()
   since the ACPI matching has been moved to the new function.  Also, this
   will allow for the GPIO matching to be done against a device tree too, not only
   ACPI tree;
 * rename bmc150_scale_info struct member 'range' to 'reg_range' to be
   consistent with the naming convention used elsewhere in the driver
   and declare it u8, instead of int;
 * change CONFIG description to list all supported chips;

Signed-off-by: Laurentiu Palcu <laurentiu.palcu@intel.com>
Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
drivers/iio/accel/Kconfig
drivers/iio/accel/bmc150-accel.c

index 01b857e..01a2151 100644 (file)
@@ -23,7 +23,9 @@ config BMC150_ACCEL
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
        help
-         Say yes here to build support for the Bosch BMC150 accelerometer.
+         Say yes here to build support for the following Bosch accelerometers:
+         BMC150, BMI055, BMA250E, BMA222E, BMA255, BMA280.
+
          Currently this only supports the device via an i2c interface.
 
          This is a combo module with both accelerometer and magnetometer.
index 0e6566a..22c096c 100644 (file)
@@ -1,5 +1,12 @@
 /*
- * BMC150 3-axis accelerometer driver
+ * 3-axis accelerometer driver supporting following Bosch-Sensortec chips:
+ *  - BMC150
+ *  - BMI055
+ *  - BMA255
+ *  - BMA250E
+ *  - BMA222E
+ *  - BMA280
+ *
  * Copyright (c) 2014, Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -34,7 +41,6 @@
 #define BMC150_ACCEL_GPIO_NAME                 "bmc150_accel_int"
 
 #define BMC150_ACCEL_REG_CHIP_ID               0x00
-#define BMC150_ACCEL_CHIP_ID_VAL               0xFA
 
 #define BMC150_ACCEL_REG_INT_STATUS_2          0x0B
 #define BMC150_ACCEL_ANY_MOTION_MASK           0x07
@@ -126,6 +132,18 @@ enum bmc150_power_modes {
        BMC150_ACCEL_SLEEP_MODE_SUSPEND = 0x04,
 };
 
+struct bmc150_scale_info {
+       int scale;
+       u8 reg_range;
+};
+
+struct bmc150_accel_chip_info {
+       u8 chip_id;
+       const struct iio_chan_spec *channels;
+       int num_channels;
+       const struct bmc150_scale_info scale_table[4];
+};
+
 struct bmc150_accel_data {
        struct i2c_client *client;
        struct iio_trigger *dready_trig;
@@ -140,6 +158,7 @@ struct bmc150_accel_data {
        bool dready_trigger_on;
        bool motion_trigger_on;
        int64_t timestamp;
+       const struct bmc150_accel_chip_info *chip_info;
 };
 
 static const struct {
@@ -168,16 +187,8 @@ static const struct {
                                     {0x0F, 1} };
 
 static const struct {
-       int scale;
-       int range;
-} bmc150_accel_scale_table[] = { {9610, BMC150_ACCEL_DEF_RANGE_2G},
-                                {19122, BMC150_ACCEL_DEF_RANGE_4G},
-                                {38344, BMC150_ACCEL_DEF_RANGE_8G},
-                                {76590, BMC150_ACCEL_DEF_RANGE_16G} };
-
-static const struct {
        int sleep_dur;
-       int reg_value;
+       u8 reg_value;
 } bmc150_accel_sleep_value_table[] = { {0, 0},
                                       {500, BMC150_ACCEL_SLEEP_500_MICRO},
                                       {1000, BMC150_ACCEL_SLEEP_1_MS},
@@ -267,7 +278,7 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
        }
 
        dev_dbg(&data->client->dev, "Chip Id %x\n", ret);
-       if (ret != BMC150_ACCEL_CHIP_ID_VAL) {
+       if (ret != data->chip_info->chip_id) {
                dev_err(&data->client->dev, "Invalid chip %x\n", ret);
                return -ENODEV;
        }
@@ -541,19 +552,19 @@ static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val)
 {
        int ret, i;
 
-       for (i = 0; i < ARRAY_SIZE(bmc150_accel_scale_table); ++i) {
-               if (bmc150_accel_scale_table[i].scale == val) {
+       for (i = 0; i < ARRAY_SIZE(data->chip_info->scale_table); ++i) {
+               if (data->chip_info->scale_table[i].scale == val) {
                        ret = i2c_smbus_write_byte_data(
-                                       data->client,
-                                       BMC150_ACCEL_REG_PMU_RANGE,
-                                       bmc150_accel_scale_table[i].range);
+                                    data->client,
+                                    BMC150_ACCEL_REG_PMU_RANGE,
+                                    data->chip_info->scale_table[i].reg_range);
                        if (ret < 0) {
                                dev_err(&data->client->dev,
                                        "Error writing pmu_range\n");
                                return ret;
                        }
 
-                       data->range = bmc150_accel_scale_table[i].range;
+                       data->range = data->chip_info->scale_table[i].reg_range;
                        return 0;
                }
        }
@@ -580,10 +591,12 @@ static int bmc150_accel_get_temp(struct bmc150_accel_data *data, int *val)
        return IIO_VAL_INT;
 }
 
-static int bmc150_accel_get_axis(struct bmc150_accel_data *data, int axis,
+static int bmc150_accel_get_axis(struct bmc150_accel_data *data,
+                                struct iio_chan_spec const *chan,
                                 int *val)
 {
        int ret;
+       int axis = chan->scan_index;
 
        mutex_lock(&data->mutex);
        ret = bmc150_accel_set_power_state(data, true);
@@ -600,7 +613,8 @@ static int bmc150_accel_get_axis(struct bmc150_accel_data *data, int axis,
                mutex_unlock(&data->mutex);
                return ret;
        }
-       *val = sign_extend32(ret >> 4, 11);
+       *val = sign_extend32(ret >> chan->scan_type.shift,
+                            chan->scan_type.realbits - 1);
        ret = bmc150_accel_set_power_state(data, false);
        mutex_unlock(&data->mutex);
        if (ret < 0)
@@ -625,9 +639,7 @@ static int bmc150_accel_read_raw(struct iio_dev *indio_dev,
                        if (iio_buffer_enabled(indio_dev))
                                return -EBUSY;
                        else
-                               return bmc150_accel_get_axis(data,
-                                                            chan->scan_index,
-                                                            val);
+                               return bmc150_accel_get_axis(data, chan, val);
                default:
                        return -EINVAL;
                }
@@ -646,13 +658,13 @@ static int bmc150_accel_read_raw(struct iio_dev *indio_dev,
                case IIO_ACCEL:
                {
                        int i;
+                       const struct bmc150_scale_info *si;
+                       int st_size = ARRAY_SIZE(data->chip_info->scale_table);
 
-                       for (i = 0; i < ARRAY_SIZE(bmc150_accel_scale_table);
-                                                                        ++i) {
-                               if (bmc150_accel_scale_table[i].range ==
-                                                               data->range) {
-                                       *val2 =
-                                       bmc150_accel_scale_table[i].scale;
+                       for (i = 0; i < st_size; ++i) {
+                               si = &data->chip_info->scale_table[i];
+                               if (si->reg_range == data->range) {
+                                       *val2 = si->scale;
                                        return IIO_VAL_INT_PLUS_MICRO;
                                }
                        }
@@ -840,7 +852,7 @@ static const struct iio_event_spec bmc150_accel_event = {
                                 BIT(IIO_EV_INFO_PERIOD)
 };
 
-#define BMC150_ACCEL_CHANNEL(_axis) {                                  \
+#define BMC150_ACCEL_CHANNEL(_axis, bits) {                            \
        .type = IIO_ACCEL,                                              \
        .modified = 1,                                                  \
        .channel2 = IIO_MOD_##_axis,                                    \
@@ -850,26 +862,101 @@ static const struct iio_event_spec bmc150_accel_event = {
        .scan_index = AXIS_##_axis,                                     \
        .scan_type = {                                                  \
                .sign = 's',                                            \
-               .realbits = 12,                                 \
+               .realbits = (bits),                                     \
                .storagebits = 16,                                      \
-               .shift = 4,                                             \
+               .shift = 16 - (bits),                                   \
        },                                                              \
        .event_spec = &bmc150_accel_event,                              \
        .num_event_specs = 1                                            \
 }
 
-static const struct iio_chan_spec bmc150_accel_channels[] = {
-       {
-               .type = IIO_TEMP,
-               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
-                                     BIT(IIO_CHAN_INFO_SCALE) |
-                                     BIT(IIO_CHAN_INFO_OFFSET),
-               .scan_index = -1,
+#define BMC150_ACCEL_CHANNELS(bits) {                                  \
+       {                                                               \
+               .type = IIO_TEMP,                                       \
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |          \
+                                     BIT(IIO_CHAN_INFO_SCALE) |        \
+                                     BIT(IIO_CHAN_INFO_OFFSET),        \
+               .scan_index = -1,                                       \
+       },                                                              \
+       BMC150_ACCEL_CHANNEL(X, bits),                                  \
+       BMC150_ACCEL_CHANNEL(Y, bits),                                  \
+       BMC150_ACCEL_CHANNEL(Z, bits),                                  \
+       IIO_CHAN_SOFT_TIMESTAMP(3),                                     \
+}
+
+static const struct iio_chan_spec bma222e_accel_channels[] =
+       BMC150_ACCEL_CHANNELS(8);
+static const struct iio_chan_spec bma250e_accel_channels[] =
+       BMC150_ACCEL_CHANNELS(10);
+static const struct iio_chan_spec bmc150_accel_channels[] =
+       BMC150_ACCEL_CHANNELS(12);
+static const struct iio_chan_spec bma280_accel_channels[] =
+       BMC150_ACCEL_CHANNELS(14);
+
+enum {
+       bmc150,
+       bmi055,
+       bma255,
+       bma250e,
+       bma222e,
+       bma280,
+};
+
+static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
+       [bmc150] = {
+               .chip_id = 0xFA,
+               .channels = bmc150_accel_channels,
+               .num_channels = ARRAY_SIZE(bmc150_accel_channels),
+               .scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G},
+                                {19122, BMC150_ACCEL_DEF_RANGE_4G},
+                                {38344, BMC150_ACCEL_DEF_RANGE_8G},
+                                {76590, BMC150_ACCEL_DEF_RANGE_16G} },
+       },
+       [bmi055] = {
+               .chip_id = 0xFA,
+               .channels = bmc150_accel_channels,
+               .num_channels = ARRAY_SIZE(bmc150_accel_channels),
+               .scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G},
+                                {19122, BMC150_ACCEL_DEF_RANGE_4G},
+                                {38344, BMC150_ACCEL_DEF_RANGE_8G},
+                                {76590, BMC150_ACCEL_DEF_RANGE_16G} },
+       },
+       [bma255] = {
+               .chip_id = 0xFA,
+               .channels = bmc150_accel_channels,
+               .num_channels = ARRAY_SIZE(bmc150_accel_channels),
+               .scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G},
+                                {19122, BMC150_ACCEL_DEF_RANGE_4G},
+                                {38344, BMC150_ACCEL_DEF_RANGE_8G},
+                                {76590, BMC150_ACCEL_DEF_RANGE_16G} },
+       },
+       [bma250e] = {
+               .chip_id = 0xF9,
+               .channels = bma250e_accel_channels,
+               .num_channels = ARRAY_SIZE(bma250e_accel_channels),
+               .scale_table = { {38344, BMC150_ACCEL_DEF_RANGE_2G},
+                                {76590, BMC150_ACCEL_DEF_RANGE_4G},
+                                {153277, BMC150_ACCEL_DEF_RANGE_8G},
+                                {306457, BMC150_ACCEL_DEF_RANGE_16G} },
+       },
+       [bma222e] = {
+               .chip_id = 0xF8,
+               .channels = bma222e_accel_channels,
+               .num_channels = ARRAY_SIZE(bma222e_accel_channels),
+               .scale_table = { {153277, BMC150_ACCEL_DEF_RANGE_2G},
+                                {306457, BMC150_ACCEL_DEF_RANGE_4G},
+                                {612915, BMC150_ACCEL_DEF_RANGE_8G},
+                                {1225831, BMC150_ACCEL_DEF_RANGE_16G} },
+       },
+       [bma280] = {
+               .chip_id = 0xFB,
+               .channels = bma280_accel_channels,
+               .num_channels = ARRAY_SIZE(bma280_accel_channels),
+               .scale_table = { {2392, BMC150_ACCEL_DEF_RANGE_2G},
+                                {4785, BMC150_ACCEL_DEF_RANGE_4G},
+                                {9581, BMC150_ACCEL_DEF_RANGE_8G},
+                                {19152, BMC150_ACCEL_DEF_RANGE_16G} },
        },
-       BMC150_ACCEL_CHANNEL(X),
-       BMC150_ACCEL_CHANNEL(Y),
-       BMC150_ACCEL_CHANNEL(Z),
-       IIO_CHAN_SOFT_TIMESTAMP(3),
 };
 
 static const struct iio_info bmc150_accel_info = {
@@ -1040,10 +1127,23 @@ static irqreturn_t bmc150_accel_data_rdy_trig_poll(int irq, void *private)
                return IRQ_HANDLED;
 }
 
-static int bmc150_accel_acpi_gpio_probe(struct i2c_client *client,
-                                       struct bmc150_accel_data *data)
+static const char *bmc150_accel_match_acpi_device(struct device *dev, int *data)
 {
        const struct acpi_device_id *id;
+
+       id = acpi_match_device(dev->driver->acpi_match_table, dev);
+
+       if (!id)
+               return NULL;
+
+       *data = (int) id->driver_data;
+
+       return dev_name(dev);
+}
+
+static int bmc150_accel_gpio_probe(struct i2c_client *client,
+                                       struct bmc150_accel_data *data)
+{
        struct device *dev;
        struct gpio_desc *gpio;
        int ret;
@@ -1052,17 +1152,11 @@ static int bmc150_accel_acpi_gpio_probe(struct i2c_client *client,
                return -EINVAL;
 
        dev = &client->dev;
-       if (!ACPI_HANDLE(dev))
-               return -ENODEV;
-
-       id = acpi_match_device(dev->driver->acpi_match_table, dev);
-       if (!id)
-               return -ENODEV;
 
        /* data ready gpio interrupt pin */
        gpio = devm_gpiod_get_index(dev, BMC150_ACCEL_GPIO_NAME, 0);
        if (IS_ERR(gpio)) {
-               dev_err(dev, "Failed: acpi gpio get index\n");
+               dev_err(dev, "Failed: gpio get index\n");
                return PTR_ERR(gpio);
        }
 
@@ -1083,6 +1177,8 @@ static int bmc150_accel_probe(struct i2c_client *client,
        struct bmc150_accel_data *data;
        struct iio_dev *indio_dev;
        int ret;
+       const char *name = NULL;
+       int chip_id = 0;
 
        indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
        if (!indio_dev)
@@ -1092,6 +1188,16 @@ static int bmc150_accel_probe(struct i2c_client *client,
        i2c_set_clientdata(client, indio_dev);
        data->client = client;
 
+       if (id) {
+               name = id->name;
+               chip_id = id->driver_data;
+       }
+
+       if (ACPI_HANDLE(&client->dev))
+               name = bmc150_accel_match_acpi_device(&client->dev, &chip_id);
+
+       data->chip_info = &bmc150_accel_chip_info_tbl[chip_id];
+
        ret = bmc150_accel_chip_init(data);
        if (ret < 0)
                return ret;
@@ -1099,14 +1205,14 @@ static int bmc150_accel_probe(struct i2c_client *client,
        mutex_init(&data->mutex);
 
        indio_dev->dev.parent = &client->dev;
-       indio_dev->channels = bmc150_accel_channels;
-       indio_dev->num_channels = ARRAY_SIZE(bmc150_accel_channels);
-       indio_dev->name = BMC150_ACCEL_DRV_NAME;
+       indio_dev->channels = data->chip_info->channels;
+       indio_dev->num_channels = data->chip_info->num_channels;
+       indio_dev->name = name;
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->info = &bmc150_accel_info;
 
        if (client->irq < 0)
-               client->irq = bmc150_accel_acpi_gpio_probe(client, data);
+               client->irq = bmc150_accel_gpio_probe(client, data);
 
        if (client->irq >= 0) {
                ret = devm_request_threaded_irq(
@@ -1284,14 +1390,24 @@ static const struct dev_pm_ops bmc150_accel_pm_ops = {
 };
 
 static const struct acpi_device_id bmc150_accel_acpi_match[] = {
-       {"BSBA0150", 0},
-       {"BMC150A", 0},
+       {"BSBA0150",    bmc150},
+       {"BMC150A",     bmc150},
+       {"BMI055A",     bmi055},
+       {"BMA0255",     bma255},
+       {"BMA250E",     bma250e},
+       {"BMA222E",     bma222e},
+       {"BMA0280",     bma280},
        { },
 };
 MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match);
 
 static const struct i2c_device_id bmc150_accel_id[] = {
-       {"bmc150_accel", 0},
+       {"bmc150_accel",        bmc150},
+       {"bmi055_accel",        bmi055},
+       {"bma255",              bma255},
+       {"bma250e",             bma250e},
+       {"bma222e",             bma222e},
+       {"bma280",              bma280},
        {}
 };