[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1409650219-11225-1-git-send-email-laurentiu.palcu@intel.com>
Date: Tue, 2 Sep 2014 12:30:19 +0300
From: Laurentiu Palcu <laurentiu.palcu@...el.com>
To: Jonathan Cameron <jic23@...nel.org>
Cc: Hartmut Knaack <knaack.h@....de>,
Lars-Peter Clausen <lars@...afoo.de>,
Peter Meerwald <pmeerw@...erw.net>,
Laurentiu Palcu <laurentiu.palcu@...el.com>,
Srinivas Pandruvada <srinivas.pandruvada@...ux.intel.com>,
linux-iio@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: [PATCH v5 3/3] iio: accel: BMC150: add support for other Bosch chips
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@...el.com>
---
Changes in v5:
* addressed Joe's suggestion to rewrite a small portion of the code to make it
more readable;
* changed the CONFIG description according to Srinivas's advise;
Changes in v4:
* address Peter's comments: see 3rd bullet in the commit's message. As a result, do
some re-indentation to make lines fit 80 chars;
Changes in v3:
* remove the chip id macros since they were not used anywhere else and put the id
values directly in the chip info table;
* fix the unnecessary casting from const char * to char * and back;
laurentiu
drivers/iio/accel/Kconfig | 4 +-
drivers/iio/accel/bmc150-accel.c | 234 +++++++++++++++++++++++++++++----------
2 files changed, 178 insertions(+), 60 deletions(-)
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 01b857e..01a2151 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -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.
diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
index 0e6566a..22c096c 100644
--- a/drivers/iio/accel/bmc150-accel.c
+++ b/drivers/iio/accel/bmc150-accel.c
@@ -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},
{}
};
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists