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

From: Jonathan Cameron
Date: Wed Sep 10 2014 - 15:35:55 EST


On 02/09/14 10:30, Laurentiu Palcu wrote:
> 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@xxxxxxxxx>
Looks fine to me, though I'm not really in a fit state to review right now.
Srinivas, do you want to give an Ack?
> ---
>
> 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},
> {}
> };
>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/