On 10/11/19 8:54 PM, Dan Robertson wrote:
> Add a IIO driver for the Bosch BMA400 3-axes ultra-low power accelerometer.
> The driver supports reading from the acceleration and temperature
> registers. The driver also supports reading and configuring the output data
> rate, oversampling ratio, and scale.
> 
> Signed-off-by: Dan Robertson <[email protected]>
> ---
>  drivers/iio/accel/Kconfig       |  19 +
>  drivers/iio/accel/Makefile      |   2 +
>  drivers/iio/accel/bma400.h      |  86 ++++
>  drivers/iio/accel/bma400_core.c | 839 ++++++++++++++++++++++++++++++++
>  drivers/iio/accel/bma400_i2c.c  |  58 +++
>  5 files changed, 1004 insertions(+)
>  create mode 100644 drivers/iio/accel/bma400.h
>  create mode 100644 drivers/iio/accel/bma400_core.c
>  create mode 100644 drivers/iio/accel/bma400_i2c.c
> 
> diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
> index 9b9656ce37e6..cca6727e037e 100644
> --- a/drivers/iio/accel/Kconfig
> +++ b/drivers/iio/accel/Kconfig
> @@ -112,6 +112,25 @@ config BMA220
>         To compile this driver as a module, choose M here: the
>         module will be called bma220_spi.
>  
> +config BMA400
> +     tristate "Bosch BMA400 3-Axis Accelerometer Driver"
> +     depends on I2C
> +     select REGMAP
> +     select BMA400_I2C if (I2C)

Since this already has "depends on I2C", the "if (I2C)" above is not needed.
Or maybe BMA400 alone does not depend on I2C?

> +     help
> +       Say Y here if you want to build a driver for the Bosch BMA400
> +       triaxial acceleration sensor.
> +
> +       To compile this driver as a module, choose M here: the
> +       module will be called bma400_core and you will also get
> +       bma400_i2c for I2C

        Add ending '.'.

> +
> +config BMA400_I2C
> +     tristate
> +     depends on BMA400
> +     depends on I2C
> +     select REGMAP_I2C
> +

The bma400_i2c driver seems to use some OF interfaces.
Should it also depend on OF?

>  config BMC150_ACCEL
>       tristate "Bosch BMC150 Accelerometer Driver"
>       select IIO_BUFFER
> diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
> index 56bd0215e0d4..3a051cf37f40 100644
> --- a/drivers/iio/accel/Makefile
> +++ b/drivers/iio/accel/Makefile
> @@ -14,6 +14,8 @@ obj-$(CONFIG_ADXL372_I2C) += adxl372_i2c.o
>  obj-$(CONFIG_ADXL372_SPI) += adxl372_spi.o
>  obj-$(CONFIG_BMA180) += bma180.o
>  obj-$(CONFIG_BMA220) += bma220_spi.o
> +obj-$(CONFIG_BMA400) += bma400_core.o
> +obj-$(CONFIG_BMA400_I2C) += bma400_i2c.o
>  obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o
>  obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o
>  obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o


> diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c
> new file mode 100644
> index 000000000000..5b3cb8919c47
> --- /dev/null
> +++ b/drivers/iio/accel/bma400_core.c
> @@ -0,0 +1,839 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * bma400_core.c - Core IIO driver for Bosch BMA400 triaxial acceleration
> + *                 sensor. Used by bma400-i2c.
> + *
> + * Copyright 2019 Dan Robertson <[email protected]>
> + *
> + * TODO:
> + *  - Support for power management
> + *  - Support events and interrupts
> + *  - Create channel the step count
> + *  - Create channel for sensor time
> + */
> +
> +#include <linux/device.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +#include <linux/bitops.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +
> +#include "bma400.h"
> +

[snip]

> +
> +struct bma400_data {
> +     struct device *dev;
> +     struct mutex mutex; /* data register lock */

#include <linux/mutex.h>

> +     struct iio_mount_matrix orientation;
> +     struct regmap *regmap;
> +     enum bma400_power_mode power_mode;
> +     const int *sample_freq;
> +     int oversampling_ratio;
> +     int scale;
> +};

[snip]

> +
> +static int bma400_get_accel_oversampling_ratio(struct bma400_data *data)
> +{
> +     unsigned int val;
> +     unsigned int osr;
> +     int ret;
> +
> +     /*
> +      * The oversampling ratio is stored in a different register
> +      * based on the power-mode. In normal mode the OSR is stored
> +      * in ACC_CONFIG1. In low-power mode it is stored in
> +      * ACC_CONFIG0.
> +      */
> +     switch (data->power_mode) {
> +     case POWER_MODE_LOW:
> +             ret = regmap_read(data->regmap, BMA400_ACC_CONFIG0_REG, &val);
> +             if (ret < 0) {
> +                     data->oversampling_ratio = -1;
> +                     return ret;
> +             }
> +
> +             osr = (val & BMA400_LP_OSR_MASK) >> BMA400_LP_OSR_SHIFT;
> +
> +             data->oversampling_ratio = osr;
> +             return 0;
> +     case POWER_MODE_NORMAL:
> +             ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &val);
> +             if (ret < 0) {
> +                     data->oversampling_ratio = -1;
> +                     return ret;
> +             }
> +
> +             osr = (val & BMA400_NP_OSR_MASK) >> BMA400_NP_OSR_SHIFT;
> +
> +             data->oversampling_ratio = osr;
> +             return 0;
> +     default:
> +             data->oversampling_ratio = -1;
> +             return 0;
> +     }
> +}
> +
> +static int bma400_set_accel_oversampling_ratio(struct bma400_data *data,
> +                                            int val)
> +{
> +     int ret;
> +     unsigned int acc_config;
> +
> +     if (val & ~BMA400_TWO_BITS_MASK)
> +             return -EINVAL;
> +
> +     /*
> +      * The oversampling ratio is stored in a different register
> +      * based on the power-mode.
> +      */
> +     switch (data->power_mode) {
> +     case POWER_MODE_LOW:
> +             ret = regmap_read(data->regmap, BMA400_ACC_CONFIG0_REG,
> +                               &acc_config);
> +             if (acc_config < 0)
> +                     return acc_config;
> +
> +             ret = regmap_write(data->regmap, BMA400_ACC_CONFIG0_REG,
> +                                (acc_config & ~BMA400_LP_OSR_MASK) |
> +                                (val << BMA400_LP_OSR_SHIFT));
> +             if (ret < 0) {
> +                     dev_err(data->dev, "Failed to write out OSR");
> +                     return ret;
> +             }
> +
> +             data->oversampling_ratio = val;
> +             return 0;
> +     case POWER_MODE_NORMAL:
> +             ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG,
> +                               &acc_config);
> +             if (ret < 0)
> +                     return ret;
> +
> +             ret = regmap_write(data->regmap, BMA400_ACC_CONFIG1_REG,
> +                                (acc_config & ~BMA400_NP_OSR_MASK) |
> +                                (val << BMA400_NP_OSR_SHIFT));
> +             if (ret < 0) {
> +                     dev_err(data->dev, "Failed to write out OSR");
> +                     return ret;
> +             }
> +
> +             data->oversampling_ratio = val;
> +             return 0;
> +     default:
> +             return -EINVAL;
> +     }
> +     return ret;
> +}
> +
> +static int bma400_get_accel_scale(struct bma400_data *data)
> +{
> +     int idx;
> +     int ret;
> +     unsigned int val;
> +
> +     ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &val);
> +     if (ret < 0)
> +             return ret;
> +
> +     idx = (((val & BMA400_ACC_SCALE_MASK) >> BMA400_SCALE_SHIFT) * 2) + 1;
> +     if (idx >= ARRAY_SIZE(bma400_scale_table))
> +             return -EINVAL;
> +
> +     data->scale = bma400_scale_table[idx];
> +
> +     return 0;
> +}
> +
> +static int bma400_get_accel_scale_idx(struct bma400_data *data, int val)
> +{
> +     int i;
> +
> +     for (i = 1; i < ARRAY_SIZE(bma400_scale_table); i += 2) {

#include <linux/kernel.h>

> +             if (bma400_scale_table[i] == val)
> +                     return i - 1;
> +     }
> +     return -EINVAL;
> +}


[snip]


-- 
~Randy

Reply via email to