[PATCH 3/3] iio: accel: BMC150: add support for other Bosch chips

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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
BMA222 - 8 bit resolution
BMA250 - 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;

Signed-off-by: Laurentiu Palcu <laurentiu.palcu@xxxxxxxxx>
---
 drivers/iio/accel/bmc150-accel.c | 231 ++++++++++++++++++++++++++++++---------
 1 file changed, 177 insertions(+), 54 deletions(-)

diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
index 0e6566a..07e10fc 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
+ *  - BMA250
+ *  - BMA222
+ *  - BMA280
+ *
  * Copyright (c) 2014, Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -35,6 +42,11 @@
 
 #define BMC150_ACCEL_REG_CHIP_ID		0x00
 #define BMC150_ACCEL_CHIP_ID_VAL		0xFA
+#define BMA255_ACCEL_CHIP_ID_VAL		0xFA
+#define BMI055_ACCEL_CHIP_ID_VAL		0xFA
+#define BMA222_ACCEL_CHIP_ID_VAL		0xF8
+#define BMA250_ACCEL_CHIP_ID_VAL		0xF9
+#define BMA280_ACCEL_CHIP_ID_VAL		0xFB
 
 #define BMC150_ACCEL_REG_INT_STATUS_2		0x0B
 #define BMC150_ACCEL_ANY_MOTION_MASK		0x07
@@ -126,6 +138,18 @@ enum bmc150_power_modes {
 	BMC150_ACCEL_SLEEP_MODE_SUSPEND = 0x04,
 };
 
+struct bmc150_scale_info {
+	int scale;
+	int 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 +164,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,14 +193,6 @@ 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;
 } bmc150_accel_sleep_value_table[] = { {0, 0},
@@ -267,7 +284,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 +558,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->chip_info->scale_table[i].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].range;
 			return 0;
 		}
 	}
@@ -580,10 +597,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 +619,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 +645,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;
 		}
@@ -647,12 +665,13 @@ static int bmc150_accel_read_raw(struct iio_dev *indio_dev,
 		{
 			int i;
 
-			for (i = 0; i < ARRAY_SIZE(bmc150_accel_scale_table);
-									 ++i) {
-				if (bmc150_accel_scale_table[i].range ==
+			for (i = 0;
+			     i < ARRAY_SIZE(data->chip_info->scale_table);
+			     ++i) {
+				if (data->chip_info->scale_table[i].range ==
 								data->range) {
 					*val2 =
-					bmc150_accel_scale_table[i].scale;
+					data->chip_info->scale_table[i].scale;
 					return IIO_VAL_INT_PLUS_MICRO;
 				}
 			}
@@ -840,7 +859,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,28 +869,103 @@ 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,
-	},
-	BMC150_ACCEL_CHANNEL(X),
-	BMC150_ACCEL_CHANNEL(Y),
-	BMC150_ACCEL_CHANNEL(Z),
-	IIO_CHAN_SOFT_TIMESTAMP(3),
+#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 bma222_accel_channels[] =
+	BMC150_ACCEL_CHANNELS(8);
+static const struct iio_chan_spec bma250_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,
+	bma250,
+	bma222,
+	bma280,
 };
 
+static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
+	[bmc150] = {
+		.chip_id = BMC150_ACCEL_CHIP_ID_VAL,
+		.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},
+				 {75590, BMC150_ACCEL_DEF_RANGE_16G} },
+	},
+	[bmi055] = {
+		.chip_id = BMI055_ACCEL_CHIP_ID_VAL,
+		.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},
+				 {75590, BMC150_ACCEL_DEF_RANGE_16G} },
+	},
+	[bma255] = {
+		.chip_id = BMA255_ACCEL_CHIP_ID_VAL,
+		.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},
+				 {75590, BMC150_ACCEL_DEF_RANGE_16G} },
+	},
+	[bma250] = {
+		.chip_id = BMA250_ACCEL_CHIP_ID_VAL,
+		.channels = bma250_accel_channels,
+		.num_channels = ARRAY_SIZE(bma250_accel_channels),
+		.scale_table = { {38344, BMC150_ACCEL_DEF_RANGE_2G},
+				 {75590, BMC150_ACCEL_DEF_RANGE_4G},
+				 {153277, BMC150_ACCEL_DEF_RANGE_8G},
+				 {306457, BMC150_ACCEL_DEF_RANGE_16G} },
+	},
+	[bma222] = {
+		.chip_id = BMA222_ACCEL_CHIP_ID_VAL,
+		.channels = bma222_accel_channels,
+		.num_channels = ARRAY_SIZE(bma222_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 = BMA280_ACCEL_CHIP_ID_VAL,
+		.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} },
+	},
+};
+
 static const struct iio_info bmc150_accel_info = {
 	.attrs			= &bmc150_accel_attrs_group,
 	.read_raw		= bmc150_accel_read_raw,
@@ -1040,10 +1134,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 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 (char *) 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 +1159,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 +1184,8 @@ static int bmc150_accel_probe(struct i2c_client *client,
 	struct bmc150_accel_data *data;
 	struct iio_dev *indio_dev;
 	int ret;
+	char *name = NULL;
+	int chip_id = 0;
 
 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 	if (!indio_dev)
@@ -1092,6 +1195,16 @@ static int bmc150_accel_probe(struct i2c_client *client,
 	i2c_set_clientdata(client, indio_dev);
 	data->client = client;
 
+	if (id) {
+		name = (char *) 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 +1212,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 +1397,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},
+	{"BMA0250",	bma250},
+	{"BMA0222",	bma222},
+	{"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},
+	{"bma250",		bma250},
+	{"bma222",		bma222},
+	{"bma280",		bma280},
 	{}
 };
 
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux