diff options
Diffstat (limited to 'drivers/iio/imu/st_lsm9ds0')
-rw-r--r-- | drivers/iio/imu/st_lsm9ds0/Kconfig | 28 | ||||
-rw-r--r-- | drivers/iio/imu/st_lsm9ds0/Makefile | 5 | ||||
-rw-r--r-- | drivers/iio/imu/st_lsm9ds0/st_lsm9ds0.h | 23 | ||||
-rw-r--r-- | drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c | 163 | ||||
-rw-r--r-- | drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c | 84 | ||||
-rw-r--r-- | drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c | 83 |
6 files changed, 386 insertions, 0 deletions
diff --git a/drivers/iio/imu/st_lsm9ds0/Kconfig b/drivers/iio/imu/st_lsm9ds0/Kconfig new file mode 100644 index 000000000000..53b7017014f8 --- /dev/null +++ b/drivers/iio/imu/st_lsm9ds0/Kconfig @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config IIO_ST_LSM9DS0 + tristate "STMicroelectronics LSM9DS0 IMU driver" + depends on (I2C || SPI_MASTER) && SYSFS + depends on !SENSORS_LIS3_I2C + depends on !SENSORS_LIS3_SPI + select IIO_ST_LSM9DS0_I2C if I2C + select IIO_ST_LSM9DS0_SPI if SPI_MASTER + select IIO_ST_ACCEL_3AXIS + select IIO_ST_MAGN_3AXIS + + help + Say yes here to build support for STMicroelectronics LSM9DS0 IMU + sensor. Supported devices: accelerometer/magnetometer of lsm9ds0. + + To compile this driver as a module, choose M here: the module + will be called st_lsm9ds0. + +config IIO_ST_LSM9DS0_I2C + tristate + depends on IIO_ST_LSM9DS0 + select REGMAP_I2C + +config IIO_ST_LSM9DS0_SPI + tristate + depends on IIO_ST_LSM9DS0 + select REGMAP_SPI diff --git a/drivers/iio/imu/st_lsm9ds0/Makefile b/drivers/iio/imu/st_lsm9ds0/Makefile new file mode 100644 index 000000000000..488af523f648 --- /dev/null +++ b/drivers/iio/imu/st_lsm9ds0/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_IIO_ST_LSM9DS0) += st_lsm9ds0.o +st_lsm9ds0-y := st_lsm9ds0_core.o +obj-$(CONFIG_IIO_ST_LSM9DS0_I2C) += st_lsm9ds0_i2c.o +obj-$(CONFIG_IIO_ST_LSM9DS0_SPI) += st_lsm9ds0_spi.o diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0.h b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0.h new file mode 100644 index 000000000000..146393afd9a7 --- /dev/null +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +// STMicroelectronics LSM9DS0 IMU driver + +#ifndef ST_LSM9DS0_H +#define ST_LSM9DS0_H + +struct iio_dev; +struct regulator; + +struct st_lsm9ds0 { + struct device *dev; + const char *name; + int irq; + struct iio_dev *accel; + struct iio_dev *magn; + struct regulator *vdd; + struct regulator *vdd_io; +}; + +int st_lsm9ds0_probe(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap); +int st_lsm9ds0_remove(struct st_lsm9ds0 *lsm9ds0); + +#endif /* ST_LSM9DS0_H */ diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c new file mode 100644 index 000000000000..8204f7303fd7 --- /dev/null +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * STMicroelectronics LSM9DS0 IMU driver + * + * Copyright (C) 2021, Intel Corporation + * + * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/regulator/consumer.h> + +#include <linux/iio/common/st_sensors.h> +#include <linux/iio/iio.h> + +#include "st_lsm9ds0.h" + +static int st_lsm9ds0_power_enable(struct device *dev, struct st_lsm9ds0 *lsm9ds0) +{ + int ret; + + /* Regulators not mandatory, but if requested we should enable them. */ + lsm9ds0->vdd = devm_regulator_get(dev, "vdd"); + if (IS_ERR(lsm9ds0->vdd)) { + dev_err(dev, "unable to get Vdd supply\n"); + return PTR_ERR(lsm9ds0->vdd); + } + ret = regulator_enable(lsm9ds0->vdd); + if (ret) { + dev_warn(dev, "Failed to enable specified Vdd supply\n"); + return ret; + } + + lsm9ds0->vdd_io = devm_regulator_get(dev, "vddio"); + if (IS_ERR(lsm9ds0->vdd_io)) { + dev_err(dev, "unable to get Vdd_IO supply\n"); + regulator_disable(lsm9ds0->vdd); + return PTR_ERR(lsm9ds0->vdd_io); + } + ret = regulator_enable(lsm9ds0->vdd_io); + if (ret) { + dev_warn(dev, "Failed to enable specified Vdd_IO supply\n"); + regulator_disable(lsm9ds0->vdd); + return ret; + } + + return 0; +} + +static void st_lsm9ds0_power_disable(void *data) +{ + struct st_lsm9ds0 *lsm9ds0 = data; + + regulator_disable(lsm9ds0->vdd_io); + regulator_disable(lsm9ds0->vdd); +} + +static int devm_st_lsm9ds0_power_enable(struct st_lsm9ds0 *lsm9ds0) +{ + struct device *dev = lsm9ds0->dev; + int ret; + + ret = st_lsm9ds0_power_enable(dev, lsm9ds0); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, st_lsm9ds0_power_disable, lsm9ds0); +} + +static int st_lsm9ds0_probe_accel(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap) +{ + const struct st_sensor_settings *settings; + struct device *dev = lsm9ds0->dev; + struct st_sensor_data *data; + + settings = st_accel_get_settings(lsm9ds0->name); + if (!settings) { + dev_err(dev, "device name %s not recognized.\n", lsm9ds0->name); + return -ENODEV; + } + + lsm9ds0->accel = devm_iio_device_alloc(dev, sizeof(*data)); + if (!lsm9ds0->accel) + return -ENOMEM; + + lsm9ds0->accel->name = lsm9ds0->name; + + data = iio_priv(lsm9ds0->accel); + data->sensor_settings = (struct st_sensor_settings *)settings; + data->dev = dev; + data->irq = lsm9ds0->irq; + data->regmap = regmap; + data->vdd = lsm9ds0->vdd; + data->vdd_io = lsm9ds0->vdd_io; + + return st_accel_common_probe(lsm9ds0->accel); +} + +static int st_lsm9ds0_probe_magn(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap) +{ + const struct st_sensor_settings *settings; + struct device *dev = lsm9ds0->dev; + struct st_sensor_data *data; + + settings = st_magn_get_settings(lsm9ds0->name); + if (!settings) { + dev_err(dev, "device name %s not recognized.\n", lsm9ds0->name); + return -ENODEV; + } + + lsm9ds0->magn = devm_iio_device_alloc(dev, sizeof(*data)); + if (!lsm9ds0->magn) + return -ENOMEM; + + lsm9ds0->magn->name = lsm9ds0->name; + + data = iio_priv(lsm9ds0->magn); + data->sensor_settings = (struct st_sensor_settings *)settings; + data->dev = dev; + data->irq = lsm9ds0->irq; + data->regmap = regmap; + data->vdd = lsm9ds0->vdd; + data->vdd_io = lsm9ds0->vdd_io; + + return st_magn_common_probe(lsm9ds0->magn); +} + +int st_lsm9ds0_probe(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap) +{ + int ret; + + ret = devm_st_lsm9ds0_power_enable(lsm9ds0); + if (ret) + return ret; + + /* Setup accelerometer device */ + ret = st_lsm9ds0_probe_accel(lsm9ds0, regmap); + if (ret) + return ret; + + /* Setup magnetometer device */ + ret = st_lsm9ds0_probe_magn(lsm9ds0, regmap); + if (ret) + st_accel_common_remove(lsm9ds0->accel); + + return ret; +} +EXPORT_SYMBOL_GPL(st_lsm9ds0_probe); + +int st_lsm9ds0_remove(struct st_lsm9ds0 *lsm9ds0) +{ + st_magn_common_remove(lsm9ds0->magn); + st_accel_common_remove(lsm9ds0->accel); + + return 0; +} +EXPORT_SYMBOL_GPL(st_lsm9ds0_remove); + +MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>"); +MODULE_DESCRIPTION("STMicroelectronics LSM9DS0 IMU core driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c new file mode 100644 index 000000000000..50a36ab53bc3 --- /dev/null +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * STMicroelectronics LSM9DS0 IMU driver + * + * Copyright (C) 2021, Intel Corporation + * + * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> + */ + +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> + +#include <linux/iio/common/st_sensors_i2c.h> + +#include "st_lsm9ds0.h" + +static const struct of_device_id st_lsm9ds0_of_match[] = { + { + .compatible = "st,lsm9ds0-imu", + .data = LSM9DS0_IMU_DEV_NAME, + }, + {} +}; +MODULE_DEVICE_TABLE(of, st_lsm9ds0_of_match); + +static const struct i2c_device_id st_lsm9ds0_id_table[] = { + { LSM9DS0_IMU_DEV_NAME }, + {} +}; +MODULE_DEVICE_TABLE(i2c, st_lsm9ds0_id_table); + +static const struct regmap_config st_lsm9ds0_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .read_flag_mask = 0x80, +}; + +static int st_lsm9ds0_i2c_probe(struct i2c_client *client) +{ + const struct regmap_config *config = &st_lsm9ds0_regmap_config; + struct device *dev = &client->dev; + struct st_lsm9ds0 *lsm9ds0; + struct regmap *regmap; + + st_sensors_dev_name_probe(dev, client->name, sizeof(client->name)); + + lsm9ds0 = devm_kzalloc(dev, sizeof(*lsm9ds0), GFP_KERNEL); + if (!lsm9ds0) + return -ENOMEM; + + lsm9ds0->dev = dev; + lsm9ds0->name = client->name; + lsm9ds0->irq = client->irq; + + regmap = devm_regmap_init_i2c(client, config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + i2c_set_clientdata(client, lsm9ds0); + + return st_lsm9ds0_probe(lsm9ds0, regmap); +} + +static int st_lsm9ds0_i2c_remove(struct i2c_client *client) +{ + return st_lsm9ds0_remove(i2c_get_clientdata(client)); +} + +static struct i2c_driver st_lsm9ds0_driver = { + .driver = { + .name = "st-lsm9ds0-i2c", + .of_match_table = st_lsm9ds0_of_match, + }, + .probe_new = st_lsm9ds0_i2c_probe, + .remove = st_lsm9ds0_i2c_remove, + .id_table = st_lsm9ds0_id_table, +}; +module_i2c_driver(st_lsm9ds0_driver); + +MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>"); +MODULE_DESCRIPTION("STMicroelectronics LSM9DS0 IMU I2C driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c new file mode 100644 index 000000000000..272c88990dd0 --- /dev/null +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * STMicroelectronics LSM9DS0 IMU driver + * + * Copyright (C) 2021, Intel Corporation + * + * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> + +#include <linux/iio/common/st_sensors_spi.h> + +#include "st_lsm9ds0.h" + +static const struct of_device_id st_lsm9ds0_of_match[] = { + { + .compatible = "st,lsm9ds0-imu", + .data = LSM9DS0_IMU_DEV_NAME, + }, + {} +}; +MODULE_DEVICE_TABLE(of, st_lsm9ds0_of_match); + +static const struct spi_device_id st_lsm9ds0_id_table[] = { + { LSM9DS0_IMU_DEV_NAME }, + {} +}; +MODULE_DEVICE_TABLE(spi, st_lsm9ds0_id_table); + +static const struct regmap_config st_lsm9ds0_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .read_flag_mask = 0xc0, +}; + +static int st_lsm9ds0_spi_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct st_lsm9ds0 *lsm9ds0; + struct regmap *regmap; + + st_sensors_dev_name_probe(dev, spi->modalias, sizeof(spi->modalias)); + + lsm9ds0 = devm_kzalloc(dev, sizeof(*lsm9ds0), GFP_KERNEL); + if (!lsm9ds0) + return -ENOMEM; + + lsm9ds0->dev = dev; + lsm9ds0->name = spi->modalias; + lsm9ds0->irq = spi->irq; + + regmap = devm_regmap_init_spi(spi, &st_lsm9ds0_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + spi_set_drvdata(spi, lsm9ds0); + + return st_lsm9ds0_probe(lsm9ds0, regmap); +} + +static int st_lsm9ds0_spi_remove(struct spi_device *spi) +{ + return st_lsm9ds0_remove(spi_get_drvdata(spi)); +} + +static struct spi_driver st_lsm9ds0_driver = { + .driver = { + .name = "st-lsm9ds0-spi", + .of_match_table = st_lsm9ds0_of_match, + }, + .probe = st_lsm9ds0_spi_probe, + .remove = st_lsm9ds0_spi_remove, + .id_table = st_lsm9ds0_id_table, +}; +module_spi_driver(st_lsm9ds0_driver); + +MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>"); +MODULE_DESCRIPTION("STMicroelectronics LSM9DS0 IMU SPI driver"); +MODULE_LICENSE("GPL v2"); |