diff options
Diffstat (limited to 'drivers/iio/imu')
22 files changed, 1102 insertions, 320 deletions
diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c index 90ed3f9bb39c..36323ad149e0 100644 --- a/drivers/iio/imu/adis16400.c +++ b/drivers/iio/imu/adis16400.c @@ -170,7 +170,7 @@ struct adis16400_chip_info { * that must be enabled together **/ struct adis16400_state { - struct adis16400_chip_info *variant; + const struct adis16400_chip_info *variant; int filt_int; struct adis adis; @@ -289,19 +289,6 @@ static void adis16400_debugfs_init(struct iio_dev *indio_dev) d, st, &adis16400_flash_count_fops); } -enum adis16400_chip_variant { - ADIS16300, - ADIS16334, - ADIS16350, - ADIS16360, - ADIS16362, - ADIS16364, - ADIS16367, - ADIS16400, - ADIS16445, - ADIS16448, -}; - static int adis16334_get_freq(struct adis16400_state *st) { int ret; @@ -984,137 +971,142 @@ static const struct adis_timeout adis16448_timeouts = { .self_test_ms = 45, }; -static struct adis16400_chip_info adis16400_chips[] = { - [ADIS16300] = { - .channels = adis16300_channels, - .num_channels = ARRAY_SIZE(adis16300_channels), - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | - ADIS16400_HAS_SERIAL_NUMBER, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ - .accel_scale_micro = 5884, - .temp_scale_nano = 140000000, /* 0.14 C */ - .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */ - .set_freq = adis16400_set_freq, - .get_freq = adis16400_get_freq, - .adis_data = ADIS16400_DATA(&adis16300_timeouts, 18), - }, - [ADIS16334] = { - .channels = adis16334_channels, - .num_channels = ARRAY_SIZE(adis16334_channels), - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_NO_BURST | - ADIS16400_HAS_SERIAL_NUMBER, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ - .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */ - .temp_scale_nano = 67850000, /* 0.06785 C */ - .temp_offset = 25000000 / 67850, /* 25 C = 0x00 */ - .set_freq = adis16334_set_freq, - .get_freq = adis16334_get_freq, - .adis_data = ADIS16400_DATA(&adis16334_timeouts, 0), - }, - [ADIS16350] = { - .channels = adis16350_channels, - .num_channels = ARRAY_SIZE(adis16350_channels), - .gyro_scale_micro = IIO_DEGREE_TO_RAD(73260), /* 0.07326 deg/s */ - .accel_scale_micro = IIO_G_TO_M_S_2(2522), /* 0.002522 g */ - .temp_scale_nano = 145300000, /* 0.1453 C */ - .temp_offset = 25000000 / 145300, /* 25 C = 0x00 */ - .flags = ADIS16400_NO_BURST | ADIS16400_HAS_SLOW_MODE, - .set_freq = adis16400_set_freq, - .get_freq = adis16400_get_freq, - .adis_data = ADIS16400_DATA(&adis16300_timeouts, 0), - }, - [ADIS16360] = { - .channels = adis16350_channels, - .num_channels = ARRAY_SIZE(adis16350_channels), - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | - ADIS16400_HAS_SERIAL_NUMBER, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ - .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ - .temp_scale_nano = 136000000, /* 0.136 C */ - .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ - .set_freq = adis16400_set_freq, - .get_freq = adis16400_get_freq, - .adis_data = ADIS16400_DATA(&adis16300_timeouts, 28), - }, - [ADIS16362] = { - .channels = adis16350_channels, - .num_channels = ARRAY_SIZE(adis16350_channels), - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | - ADIS16400_HAS_SERIAL_NUMBER, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ - .accel_scale_micro = IIO_G_TO_M_S_2(333), /* 0.333 mg */ - .temp_scale_nano = 136000000, /* 0.136 C */ - .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ - .set_freq = adis16400_set_freq, - .get_freq = adis16400_get_freq, - .adis_data = ADIS16400_DATA(&adis16362_timeouts, 28), - }, - [ADIS16364] = { - .channels = adis16350_channels, - .num_channels = ARRAY_SIZE(adis16350_channels), - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | - ADIS16400_HAS_SERIAL_NUMBER, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ - .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */ - .temp_scale_nano = 136000000, /* 0.136 C */ - .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ - .set_freq = adis16400_set_freq, - .get_freq = adis16400_get_freq, - .adis_data = ADIS16400_DATA(&adis16362_timeouts, 28), - }, - [ADIS16367] = { - .channels = adis16350_channels, - .num_channels = ARRAY_SIZE(adis16350_channels), - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | - ADIS16400_HAS_SERIAL_NUMBER, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(2000), /* 0.2 deg/s */ - .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ - .temp_scale_nano = 136000000, /* 0.136 C */ - .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ - .set_freq = adis16400_set_freq, - .get_freq = adis16400_get_freq, - .adis_data = ADIS16400_DATA(&adis16300_timeouts, 28), - }, - [ADIS16400] = { - .channels = adis16400_channels, - .num_channels = ARRAY_SIZE(adis16400_channels), - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ - .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ - .temp_scale_nano = 140000000, /* 0.14 C */ - .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */ - .set_freq = adis16400_set_freq, - .get_freq = adis16400_get_freq, - .adis_data = ADIS16400_DATA(&adis16400_timeouts, 24), - }, - [ADIS16445] = { - .channels = adis16445_channels, - .num_channels = ARRAY_SIZE(adis16445_channels), - .flags = ADIS16400_HAS_PROD_ID | - ADIS16400_HAS_SERIAL_NUMBER | - ADIS16400_BURST_DIAG_STAT, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(10000), /* 0.01 deg/s */ - .accel_scale_micro = IIO_G_TO_M_S_2(250), /* 1/4000 g */ - .temp_scale_nano = 73860000, /* 0.07386 C */ - .temp_offset = 31000000 / 73860, /* 31 C = 0x00 */ - .set_freq = adis16334_set_freq, - .get_freq = adis16334_get_freq, - .adis_data = ADIS16400_DATA(&adis16445_timeouts, 16), - }, - [ADIS16448] = { - .channels = adis16448_channels, - .num_channels = ARRAY_SIZE(adis16448_channels), - .flags = ADIS16400_HAS_PROD_ID | - ADIS16400_HAS_SERIAL_NUMBER | - ADIS16400_BURST_DIAG_STAT, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(40000), /* 0.04 deg/s */ - .accel_scale_micro = IIO_G_TO_M_S_2(833), /* 1/1200 g */ - .temp_scale_nano = 73860000, /* 0.07386 C */ - .temp_offset = 31000000 / 73860, /* 31 C = 0x00 */ - .set_freq = adis16334_set_freq, - .get_freq = adis16334_get_freq, - .adis_data = ADIS16400_DATA(&adis16448_timeouts, 24), - } +static const struct adis16400_chip_info adis16300_chip_info = { + .channels = adis16300_channels, + .num_channels = ARRAY_SIZE(adis16300_channels), + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | + ADIS16400_HAS_SERIAL_NUMBER, + .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ + .accel_scale_micro = 5884, + .temp_scale_nano = 140000000, /* 0.14 C */ + .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */ + .set_freq = adis16400_set_freq, + .get_freq = adis16400_get_freq, + .adis_data = ADIS16400_DATA(&adis16300_timeouts, 18), +}; + +static const struct adis16400_chip_info adis16334_chip_info = { + .channels = adis16334_channels, + .num_channels = ARRAY_SIZE(adis16334_channels), + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_NO_BURST | + ADIS16400_HAS_SERIAL_NUMBER, + .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ + .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */ + .temp_scale_nano = 67850000, /* 0.06785 C */ + .temp_offset = 25000000 / 67850, /* 25 C = 0x00 */ + .set_freq = adis16334_set_freq, + .get_freq = adis16334_get_freq, + .adis_data = ADIS16400_DATA(&adis16334_timeouts, 0), +}; + +static const struct adis16400_chip_info adis16350_chip_info = { + .channels = adis16350_channels, + .num_channels = ARRAY_SIZE(adis16350_channels), + .gyro_scale_micro = IIO_DEGREE_TO_RAD(73260), /* 0.07326 deg/s */ + .accel_scale_micro = IIO_G_TO_M_S_2(2522), /* 0.002522 g */ + .temp_scale_nano = 145300000, /* 0.1453 C */ + .temp_offset = 25000000 / 145300, /* 25 C = 0x00 */ + .flags = ADIS16400_NO_BURST | ADIS16400_HAS_SLOW_MODE, + .set_freq = adis16400_set_freq, + .get_freq = adis16400_get_freq, + .adis_data = ADIS16400_DATA(&adis16300_timeouts, 0), +}; + +static const struct adis16400_chip_info adis16360_chip_info = { + .channels = adis16350_channels, + .num_channels = ARRAY_SIZE(adis16350_channels), + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | + ADIS16400_HAS_SERIAL_NUMBER, + .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ + .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ + .temp_scale_nano = 136000000, /* 0.136 C */ + .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ + .set_freq = adis16400_set_freq, + .get_freq = adis16400_get_freq, + .adis_data = ADIS16400_DATA(&adis16300_timeouts, 28), +}; + +static const struct adis16400_chip_info adis16362_chip_info = { + .channels = adis16350_channels, + .num_channels = ARRAY_SIZE(adis16350_channels), + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | + ADIS16400_HAS_SERIAL_NUMBER, + .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ + .accel_scale_micro = IIO_G_TO_M_S_2(333), /* 0.333 mg */ + .temp_scale_nano = 136000000, /* 0.136 C */ + .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ + .set_freq = adis16400_set_freq, + .get_freq = adis16400_get_freq, + .adis_data = ADIS16400_DATA(&adis16362_timeouts, 28), +}; + +static const struct adis16400_chip_info adis16364_chip_info = { + .channels = adis16350_channels, + .num_channels = ARRAY_SIZE(adis16350_channels), + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | + ADIS16400_HAS_SERIAL_NUMBER, + .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ + .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */ + .temp_scale_nano = 136000000, /* 0.136 C */ + .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ + .set_freq = adis16400_set_freq, + .get_freq = adis16400_get_freq, + .adis_data = ADIS16400_DATA(&adis16362_timeouts, 28), +}; + +static const struct adis16400_chip_info adis16367_chip_info = { + .channels = adis16350_channels, + .num_channels = ARRAY_SIZE(adis16350_channels), + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | + ADIS16400_HAS_SERIAL_NUMBER, + .gyro_scale_micro = IIO_DEGREE_TO_RAD(2000), /* 0.2 deg/s */ + .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ + .temp_scale_nano = 136000000, /* 0.136 C */ + .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ + .set_freq = adis16400_set_freq, + .get_freq = adis16400_get_freq, + .adis_data = ADIS16400_DATA(&adis16300_timeouts, 28), +}; + +static const struct adis16400_chip_info adis16400_chip_info = { + .channels = adis16400_channels, + .num_channels = ARRAY_SIZE(adis16400_channels), + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, + .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ + .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ + .temp_scale_nano = 140000000, /* 0.14 C */ + .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */ + .set_freq = adis16400_set_freq, + .get_freq = adis16400_get_freq, + .adis_data = ADIS16400_DATA(&adis16400_timeouts, 24), +}; + +static const struct adis16400_chip_info adis16445_chip_info = { + .channels = adis16445_channels, + .num_channels = ARRAY_SIZE(adis16445_channels), + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SERIAL_NUMBER | + ADIS16400_BURST_DIAG_STAT, + .gyro_scale_micro = IIO_DEGREE_TO_RAD(10000), /* 0.01 deg/s */ + .accel_scale_micro = IIO_G_TO_M_S_2(250), /* 1/4000 g */ + .temp_scale_nano = 73860000, /* 0.07386 C */ + .temp_offset = 31000000 / 73860, /* 31 C = 0x00 */ + .set_freq = adis16334_set_freq, + .get_freq = adis16334_get_freq, + .adis_data = ADIS16400_DATA(&adis16445_timeouts, 16), +}; + +static const struct adis16400_chip_info adis16448_chip_info = { + .channels = adis16448_channels, + .num_channels = ARRAY_SIZE(adis16448_channels), + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SERIAL_NUMBER | + ADIS16400_BURST_DIAG_STAT, + .gyro_scale_micro = IIO_DEGREE_TO_RAD(40000), /* 0.04 deg/s */ + .accel_scale_micro = IIO_G_TO_M_S_2(833), /* 1/1200 g */ + .temp_scale_nano = 73860000, /* 0.07386 C */ + .temp_offset = 31000000 / 73860, /* 31 C = 0x00 */ + .set_freq = adis16334_set_freq, + .get_freq = adis16334_get_freq, + .adis_data = ADIS16400_DATA(&adis16448_timeouts, 24), }; static const struct iio_info adis16400_info = { @@ -1157,7 +1149,7 @@ static int adis16400_probe(struct spi_device *spi) st = iio_priv(indio_dev); /* setup the industrialio driver allocated elements */ - st->variant = &adis16400_chips[spi_get_device_id(spi)->driver_data]; + st->variant = spi_get_device_match_data(spi); indio_dev->name = spi_get_device_id(spi)->name; indio_dev->channels = st->variant->channels; indio_dev->num_channels = st->variant->num_channels; @@ -1197,21 +1189,21 @@ static int adis16400_probe(struct spi_device *spi) } static const struct spi_device_id adis16400_id[] = { - {"adis16300", ADIS16300}, - {"adis16305", ADIS16300}, - {"adis16334", ADIS16334}, - {"adis16350", ADIS16350}, - {"adis16354", ADIS16350}, - {"adis16355", ADIS16350}, - {"adis16360", ADIS16360}, - {"adis16362", ADIS16362}, - {"adis16364", ADIS16364}, - {"adis16365", ADIS16360}, - {"adis16367", ADIS16367}, - {"adis16400", ADIS16400}, - {"adis16405", ADIS16400}, - {"adis16445", ADIS16445}, - {"adis16448", ADIS16448}, + { "adis16300", (kernel_ulong_t)&adis16300_chip_info }, + { "adis16305", (kernel_ulong_t)&adis16300_chip_info }, + { "adis16334", (kernel_ulong_t)&adis16334_chip_info }, + { "adis16350", (kernel_ulong_t)&adis16350_chip_info }, + { "adis16354", (kernel_ulong_t)&adis16350_chip_info }, + { "adis16355", (kernel_ulong_t)&adis16350_chip_info }, + { "adis16360", (kernel_ulong_t)&adis16360_chip_info }, + { "adis16362", (kernel_ulong_t)&adis16362_chip_info }, + { "adis16364", (kernel_ulong_t)&adis16364_chip_info }, + { "adis16365", (kernel_ulong_t)&adis16360_chip_info }, + { "adis16367", (kernel_ulong_t)&adis16367_chip_info }, + { "adis16400", (kernel_ulong_t)&adis16400_chip_info }, + { "adis16405", (kernel_ulong_t)&adis16400_chip_info }, + { "adis16445", (kernel_ulong_t)&adis16445_chip_info }, + { "adis16448", (kernel_ulong_t)&adis16448_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, adis16400_id); diff --git a/drivers/iio/imu/bmi160/bmi160.h b/drivers/iio/imu/bmi160/bmi160.h index 32c2ea2d7112..ffbe8205e703 100644 --- a/drivers/iio/imu/bmi160/bmi160.h +++ b/drivers/iio/imu/bmi160/bmi160.h @@ -28,4 +28,6 @@ int bmi160_enable_irq(struct regmap *regmap, bool enable); int bmi160_probe_trigger(struct iio_dev *indio_dev, int irq, u32 irq_type); +extern const struct dev_pm_ops bmi160_core_pm_ops; + #endif /* BMI160_H_ */ diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c index 0423ef6f9571..5f47708b4c5d 100644 --- a/drivers/iio/imu/bmi160/bmi160_core.c +++ b/drivers/iio/imu/bmi160/bmi160_core.c @@ -161,7 +161,7 @@ struct bmi160_regs { u8 pmu_cmd_suspend; }; -static struct bmi160_regs bmi160_regs[] = { +static const struct bmi160_regs bmi160_regs[] = { [BMI160_ACCEL] = { .data = BMI160_REG_DATA_ACCEL_XOUT_L, .config = BMI160_REG_ACCEL_CONFIG, @@ -890,6 +890,25 @@ int bmi160_core_probe(struct device *dev, struct regmap *regmap, } EXPORT_SYMBOL_NS_GPL(bmi160_core_probe, "IIO_BMI160"); +static int bmi160_core_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + + return iio_device_suspend_triggering(indio_dev); +} + +static int bmi160_core_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + + return iio_device_resume_triggering(indio_dev); +} + +const struct dev_pm_ops bmi160_core_pm_ops = { + RUNTIME_PM_OPS(bmi160_core_runtime_suspend, bmi160_core_runtime_resume, NULL) +}; +EXPORT_SYMBOL_NS_GPL(bmi160_core_pm_ops, "IIO_BMI160"); + MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>"); MODULE_DESCRIPTION("Bosch BMI160 driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c index 9fa3a19a8977..3e2758f4e0d3 100644 --- a/drivers/iio/imu/bmi160/bmi160_i2c.c +++ b/drivers/iio/imu/bmi160/bmi160_i2c.c @@ -11,6 +11,7 @@ #include <linux/i2c.h> #include <linux/mod_devicetable.h> #include <linux/module.h> +#include <linux/pm.h> #include <linux/regmap.h> #include "bmi160.h" @@ -69,6 +70,7 @@ MODULE_DEVICE_TABLE(of, bmi160_of_match); static struct i2c_driver bmi160_i2c_driver = { .driver = { .name = "bmi160_i2c", + .pm = pm_ptr(&bmi160_core_pm_ops), .acpi_match_table = bmi160_acpi_match, .of_match_table = bmi160_of_match, }, diff --git a/drivers/iio/imu/bmi160/bmi160_spi.c b/drivers/iio/imu/bmi160/bmi160_spi.c index ebb586904215..3581bd788483 100644 --- a/drivers/iio/imu/bmi160/bmi160_spi.c +++ b/drivers/iio/imu/bmi160/bmi160_spi.c @@ -7,6 +7,7 @@ */ #include <linux/mod_devicetable.h> #include <linux/module.h> +#include <linux/pm.h> #include <linux/regmap.h> #include <linux/spi/spi.h> @@ -61,6 +62,7 @@ static struct spi_driver bmi160_spi_driver = { .acpi_match_table = bmi160_acpi_match, .of_match_table = bmi160_of_match, .name = "bmi160_spi", + .pm = pm_ptr(&bmi160_core_pm_ops), }, }; module_spi_driver(bmi160_spi_driver); diff --git a/drivers/iio/imu/bmi270/bmi270.h b/drivers/iio/imu/bmi270/bmi270.h index d94525f6aee8..a6c4204032fc 100644 --- a/drivers/iio/imu/bmi270/bmi270.h +++ b/drivers/iio/imu/bmi270/bmi270.h @@ -20,4 +20,6 @@ struct device; int bmi270_core_probe(struct device *dev, struct regmap *regmap, const struct bmi270_chip_info *chip_info); +extern const struct dev_pm_ops bmi270_core_pm_ops; + #endif /* BMI270_H_ */ diff --git a/drivers/iio/imu/bmi270/bmi270_core.c b/drivers/iio/imu/bmi270/bmi270_core.c index 2e4469f30d53..519f1c9d466d 100644 --- a/drivers/iio/imu/bmi270/bmi270_core.c +++ b/drivers/iio/imu/bmi270/bmi270_core.c @@ -8,6 +8,7 @@ #include <linux/regmap.h> #include <linux/units.h> +#include <linux/iio/events.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/iio/trigger.h> @@ -28,9 +29,14 @@ #define BMI270_ACCEL_X_REG 0x0c #define BMI270_ANG_VEL_X_REG 0x12 +#define BMI270_INT_STATUS_0_REG 0x1c +#define BMI270_INT_STATUS_0_STEP_CNT_MSK BIT(1) + #define BMI270_INT_STATUS_1_REG 0x1d #define BMI270_INT_STATUS_1_ACC_GYR_DRDY_MSK GENMASK(7, 6) +#define BMI270_SC_OUT_0_REG 0x1e + #define BMI270_INTERNAL_STATUS_REG 0x21 #define BMI270_INTERNAL_STATUS_MSG_MSK GENMASK(3, 0) #define BMI270_INTERNAL_STATUS_MSG_INIT_OK 0x01 @@ -39,6 +45,8 @@ #define BMI270_TEMPERATURE_0_REG 0x22 +#define BMI270_FEAT_PAGE_REG 0x2f + #define BMI270_ACC_CONF_REG 0x40 #define BMI270_ACC_CONF_ODR_MSK GENMASK(3, 0) #define BMI270_ACC_CONF_ODR_100HZ 0x08 @@ -70,6 +78,10 @@ #define BMI270_INT_LATCH_REG 0x55 #define BMI270_INT_LATCH_REG_MSK BIT(0) +#define BMI270_INT1_MAP_FEAT_REG 0x56 +#define BMI270_INT2_MAP_FEAT_REG 0x57 +#define BMI270_INT_MAP_FEAT_STEP_CNT_WTRMRK_MSK BIT(1) + #define BMI270_INT_MAP_DATA_REG 0x58 #define BMI270_INT_MAP_DATA_DRDY_INT1_MSK BIT(2) #define BMI270_INT_MAP_DATA_DRDY_INT2_MSK BIT(6) @@ -90,10 +102,18 @@ #define BMI270_PWR_CTRL_ACCEL_EN_MSK BIT(2) #define BMI270_PWR_CTRL_TEMP_EN_MSK BIT(3) +#define BMI270_STEP_SC26_WTRMRK_MSK GENMASK(9, 0) +#define BMI270_STEP_SC26_RST_CNT_MSK BIT(10) +#define BMI270_STEP_SC26_EN_CNT_MSK BIT(12) + /* See datasheet section 4.6.14, Temperature Sensor */ #define BMI270_TEMP_OFFSET 11776 #define BMI270_TEMP_SCALE 1953125 +/* See page 90 of datasheet. The step counter "holds implicitly a 20x factor" */ +#define BMI270_STEP_COUNTER_FACTOR 20 +#define BMI270_STEP_COUNTER_MAX 20460 + #define BMI260_INIT_DATA_FILE "bmi260-init-data.fw" #define BMI270_INIT_DATA_FILE "bmi270-init-data.fw" @@ -111,6 +131,7 @@ struct bmi270_data { struct iio_trigger *trig; /* Protect device's private data from concurrent access */ struct mutex mutex; + bool steps_enabled; /* * Where IIO_DMA_MINALIGN may be larger than 8 bytes, align to @@ -120,6 +141,11 @@ struct bmi270_data { __le16 channels[6]; aligned_s64 timestamp; } buffer __aligned(IIO_DMA_MINALIGN); + /* + * Variable to access feature registers. It can be accessed concurrently + * with the 'buffer' variable + */ + __le16 regval __aligned(IIO_DMA_MINALIGN); }; enum bmi270_scan { @@ -282,6 +308,137 @@ static const struct bmi270_odr_item bmi270_odr_table[] = { }, }; +enum bmi270_feature_reg_id { + BMI270_SC_26_REG, +}; + +struct bmi270_feature_reg { + u8 page; + u8 addr; +}; + +static const struct bmi270_feature_reg bmi270_feature_regs[] = { + [BMI270_SC_26_REG] = { + .page = 6, + .addr = 0x32, + }, +}; + +static int bmi270_write_feature_reg(struct bmi270_data *data, + enum bmi270_feature_reg_id id, + u16 val) +{ + const struct bmi270_feature_reg *reg = &bmi270_feature_regs[id]; + int ret; + + ret = regmap_write(data->regmap, BMI270_FEAT_PAGE_REG, reg->page); + if (ret) + return ret; + + data->regval = cpu_to_le16(val); + return regmap_bulk_write(data->regmap, reg->addr, &data->regval, + sizeof(data->regval)); +} + +static int bmi270_read_feature_reg(struct bmi270_data *data, + enum bmi270_feature_reg_id id, + u16 *val) +{ + const struct bmi270_feature_reg *reg = &bmi270_feature_regs[id]; + int ret; + + ret = regmap_write(data->regmap, BMI270_FEAT_PAGE_REG, reg->page); + if (ret) + return ret; + + ret = regmap_bulk_read(data->regmap, reg->addr, &data->regval, + sizeof(data->regval)); + if (ret) + return ret; + + *val = le16_to_cpu(data->regval); + return 0; +} + +static int bmi270_update_feature_reg(struct bmi270_data *data, + enum bmi270_feature_reg_id id, + u16 mask, u16 val) +{ + u16 regval; + int ret; + + ret = bmi270_read_feature_reg(data, id, ®val); + if (ret) + return ret; + + regval = (regval & ~mask) | (val & mask); + + return bmi270_write_feature_reg(data, id, regval); +} + +static int bmi270_enable_steps(struct bmi270_data *data, int val) +{ + int ret; + + guard(mutex)(&data->mutex); + if (data->steps_enabled) + return 0; + + ret = bmi270_update_feature_reg(data, BMI270_SC_26_REG, + BMI270_STEP_SC26_EN_CNT_MSK, + FIELD_PREP(BMI270_STEP_SC26_EN_CNT_MSK, + val ? 1 : 0)); + if (ret) + return ret; + + data->steps_enabled = true; + return 0; +} + +static int bmi270_read_steps(struct bmi270_data *data, int *val) +{ + __le16 steps_count; + int ret; + + ret = regmap_bulk_read(data->regmap, BMI270_SC_OUT_0_REG, &steps_count, + sizeof(steps_count)); + if (ret) + return ret; + + *val = sign_extend32(le16_to_cpu(steps_count), 15); + return IIO_VAL_INT; +} + +static int bmi270_int_map_reg(enum bmi270_irq_pin pin) +{ + switch (pin) { + case BMI270_IRQ_INT1: + return BMI270_INT1_MAP_FEAT_REG; + case BMI270_IRQ_INT2: + return BMI270_INT2_MAP_FEAT_REG; + default: + return -EINVAL; + } +} + +static int bmi270_step_wtrmrk_en(struct bmi270_data *data, bool state) +{ + int reg; + + guard(mutex)(&data->mutex); + if (!data->steps_enabled) + return -EINVAL; + + reg = bmi270_int_map_reg(data->irq_pin); + if (reg < 0) + return reg; + + return regmap_update_bits(data->regmap, reg, + BMI270_INT_MAP_FEAT_STEP_CNT_WTRMRK_MSK, + FIELD_PREP(BMI270_INT_MAP_FEAT_STEP_CNT_WTRMRK_MSK, + state)); +} + static int bmi270_set_scale(struct bmi270_data *data, int chan_type, int uscale) { int i; @@ -438,19 +595,31 @@ static irqreturn_t bmi270_irq_thread_handler(int irq, void *private) { struct iio_dev *indio_dev = private; struct bmi270_data *data = iio_priv(indio_dev); - unsigned int status; + unsigned int status0, status1; + s64 timestamp = iio_get_time_ns(indio_dev); int ret; scoped_guard(mutex, &data->mutex) { + ret = regmap_read(data->regmap, BMI270_INT_STATUS_0_REG, + &status0); + if (ret) + return IRQ_NONE; + ret = regmap_read(data->regmap, BMI270_INT_STATUS_1_REG, - &status); + &status1); if (ret) return IRQ_NONE; } - if (FIELD_GET(BMI270_INT_STATUS_1_ACC_GYR_DRDY_MSK, status)) + if (FIELD_GET(BMI270_INT_STATUS_1_ACC_GYR_DRDY_MSK, status1)) iio_trigger_poll_nested(data->trig); + if (FIELD_GET(BMI270_INT_STATUS_0_STEP_CNT_MSK, status0)) + iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_STEPS, 0, + IIO_EV_TYPE_CHANGE, + IIO_EV_DIR_NONE), + timestamp); + return IRQ_HANDLED; } @@ -551,6 +720,8 @@ static int bmi270_read_raw(struct iio_dev *indio_dev, struct bmi270_data *data = iio_priv(indio_dev); switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + return bmi270_read_steps(data, val); case IIO_CHAN_INFO_RAW: if (!iio_device_claim_direct(indio_dev)) return -EBUSY; @@ -571,6 +742,9 @@ static int bmi270_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SAMP_FREQ: ret = bmi270_get_odr(data, chan->type, val, val2); return ret ? ret : IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_ENABLE: + *val = data->steps_enabled ? 1 : 0; + return IIO_VAL_INT; default: return -EINVAL; } @@ -596,6 +770,19 @@ static int bmi270_write_raw(struct iio_dev *indio_dev, ret = bmi270_set_odr(data, chan->type, val, val2); iio_device_release_direct(indio_dev); return ret; + case IIO_CHAN_INFO_ENABLE: + return bmi270_enable_steps(data, val); + case IIO_CHAN_INFO_PROCESSED: { + if (val || !data->steps_enabled) + return -EINVAL; + + guard(mutex)(&data->mutex); + /* Clear step counter value */ + return bmi270_update_feature_reg(data, BMI270_SC_26_REG, + BMI270_STEP_SC26_RST_CNT_MSK, + FIELD_PREP(BMI270_STEP_SC26_RST_CNT_MSK, + 1)); + } default: return -EINVAL; } @@ -640,10 +827,116 @@ static int bmi270_read_avail(struct iio_dev *indio_dev, } } +static int bmi270_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, bool state) +{ + struct bmi270_data *data = iio_priv(indio_dev); + + switch (type) { + case IIO_EV_TYPE_CHANGE: + return bmi270_step_wtrmrk_en(data, state); + default: + return -EINVAL; + } +} + +static int bmi270_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct bmi270_data *data = iio_priv(indio_dev); + int ret, reg, regval; + + guard(mutex)(&data->mutex); + + switch (chan->type) { + case IIO_STEPS: + reg = bmi270_int_map_reg(data->irq_pin); + if (reg) + return reg; + + ret = regmap_read(data->regmap, reg, ®val); + if (ret) + return ret; + return FIELD_GET(BMI270_INT_MAP_FEAT_STEP_CNT_WTRMRK_MSK, + regval) ? 1 : 0; + default: + return -EINVAL; + } +} + +static int bmi270_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct bmi270_data *data = iio_priv(indio_dev); + unsigned int raw; + + guard(mutex)(&data->mutex); + + switch (type) { + case IIO_EV_TYPE_CHANGE: + if (!in_range(val, 0, BMI270_STEP_COUNTER_MAX + 1)) + return -EINVAL; + + raw = val / BMI270_STEP_COUNTER_FACTOR; + return bmi270_update_feature_reg(data, BMI270_SC_26_REG, + BMI270_STEP_SC26_WTRMRK_MSK, + FIELD_PREP(BMI270_STEP_SC26_WTRMRK_MSK, + raw)); + default: + return -EINVAL; + } +} + +static int bmi270_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct bmi270_data *data = iio_priv(indio_dev); + unsigned int raw; + u16 regval; + int ret; + + guard(mutex)(&data->mutex); + + switch (type) { + case IIO_EV_TYPE_CHANGE: + ret = bmi270_read_feature_reg(data, BMI270_SC_26_REG, ®val); + if (ret) + return ret; + + raw = FIELD_GET(BMI270_STEP_SC26_WTRMRK_MSK, regval); + *val = raw * BMI270_STEP_COUNTER_FACTOR; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static const struct iio_event_spec bmi270_step_wtrmrk_event = { + .type = IIO_EV_TYPE_CHANGE, + .dir = IIO_EV_DIR_NONE, + .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) | BIT(IIO_EV_INFO_VALUE), +}; + static const struct iio_info bmi270_info = { .read_raw = bmi270_read_raw, .write_raw = bmi270_write_raw, .read_avail = bmi270_read_avail, + .write_event_config = bmi270_write_event_config, + .read_event_config = bmi270_read_event_config, + .write_event_value = bmi270_write_event_value, + .read_event_value = bmi270_read_event_value, }; #define BMI270_ACCEL_CHANNEL(_axis) { \ @@ -698,6 +991,14 @@ static const struct iio_chan_spec bmi270_channels[] = { BIT(IIO_CHAN_INFO_OFFSET), .scan_index = -1, /* No buffer support */ }, + { + .type = IIO_STEPS, + .info_mask_separate = BIT(IIO_CHAN_INFO_ENABLE) | + BIT(IIO_CHAN_INFO_PROCESSED), + .scan_index = -1, /* No buffer support */ + .event_spec = &bmi270_step_wtrmrk_event, + .num_event_specs = 1, + }, IIO_CHAN_SOFT_TIMESTAMP(BMI270_SCAN_TIMESTAMP), }; @@ -982,6 +1283,7 @@ int bmi270_core_probe(struct device *dev, struct regmap *regmap, indio_dev->available_scan_masks = bmi270_avail_scan_masks; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &bmi270_info; + dev_set_drvdata(data->dev, indio_dev); ret = bmi270_trigger_probe(data, indio_dev); if (ret) @@ -997,6 +1299,25 @@ int bmi270_core_probe(struct device *dev, struct regmap *regmap, } EXPORT_SYMBOL_NS_GPL(bmi270_core_probe, "IIO_BMI270"); +static int bmi270_core_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + + return iio_device_suspend_triggering(indio_dev); +} + +static int bmi270_core_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + + return iio_device_resume_triggering(indio_dev); +} + +const struct dev_pm_ops bmi270_core_pm_ops = { + RUNTIME_PM_OPS(bmi270_core_runtime_suspend, bmi270_core_runtime_resume, NULL) +}; +EXPORT_SYMBOL_NS_GPL(bmi270_core_pm_ops, "IIO_BMI270"); + MODULE_AUTHOR("Alex Lanzano"); MODULE_DESCRIPTION("BMI270 driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/bmi270/bmi270_i2c.c b/drivers/iio/imu/bmi270/bmi270_i2c.c index 44699ab58909..c77839b03a96 100644 --- a/drivers/iio/imu/bmi270/bmi270_i2c.c +++ b/drivers/iio/imu/bmi270/bmi270_i2c.c @@ -4,6 +4,7 @@ #include <linux/iio/iio.h> #include <linux/module.h> #include <linux/mod_devicetable.h> +#include <linux/pm.h> #include <linux/regmap.h> #include "bmi270.h" @@ -52,6 +53,7 @@ static const struct of_device_id bmi270_of_match[] = { static struct i2c_driver bmi270_i2c_driver = { .driver = { .name = "bmi270_i2c", + .pm = pm_ptr(&bmi270_core_pm_ops), .acpi_match_table = bmi270_acpi_match, .of_match_table = bmi270_of_match, }, diff --git a/drivers/iio/imu/bmi270/bmi270_spi.c b/drivers/iio/imu/bmi270/bmi270_spi.c index 88a77aba5e4f..19dd7734f9d0 100644 --- a/drivers/iio/imu/bmi270/bmi270_spi.c +++ b/drivers/iio/imu/bmi270/bmi270_spi.c @@ -3,6 +3,7 @@ #include <linux/iio/iio.h> #include <linux/mod_devicetable.h> #include <linux/module.h> +#include <linux/pm.h> #include <linux/regmap.h> #include <linux/spi/spi.h> @@ -79,6 +80,7 @@ static const struct of_device_id bmi270_of_match[] = { static struct spi_driver bmi270_spi_driver = { .driver = { .name = "bmi270", + .pm = pm_ptr(&bmi270_core_pm_ops), .of_match_table = bmi270_of_match, }, .probe = bmi270_spi_probe, diff --git a/drivers/iio/imu/bno055/bno055.c b/drivers/iio/imu/bno055/bno055.c index 597c402b98de..303bc308f80a 100644 --- a/drivers/iio/imu/bno055/bno055.c +++ b/drivers/iio/imu/bno055/bno055.c @@ -114,34 +114,35 @@ #define BNO055_UID_LEN 16 struct bno055_sysfs_attr { - int *vals; + const int *vals; int len; - int *fusion_vals; - int *hw_xlate; + const int *fusion_vals; + const int *hw_xlate; + int hw_xlate_len; int type; }; -static int bno055_acc_lpf_vals[] = { +static const int bno055_acc_lpf_vals[] = { 7, 810000, 15, 630000, 31, 250000, 62, 500000, 125, 0, 250, 0, 500, 0, 1000, 0, }; -static struct bno055_sysfs_attr bno055_acc_lpf = { +static const struct bno055_sysfs_attr bno055_acc_lpf = { .vals = bno055_acc_lpf_vals, .len = ARRAY_SIZE(bno055_acc_lpf_vals), - .fusion_vals = (int[]){62, 500000}, + .fusion_vals = (const int[]){62, 500000}, .type = IIO_VAL_INT_PLUS_MICRO, }; -static int bno055_acc_range_vals[] = { +static const int bno055_acc_range_vals[] = { /* G: 2, 4, 8, 16 */ 1962, 3924, 7848, 15696 }; -static struct bno055_sysfs_attr bno055_acc_range = { +static const struct bno055_sysfs_attr bno055_acc_range = { .vals = bno055_acc_range_vals, .len = ARRAY_SIZE(bno055_acc_range_vals), - .fusion_vals = (int[]){3924}, /* 4G */ + .fusion_vals = (const int[]){3924}, /* 4G */ .type = IIO_VAL_INT, }; @@ -165,33 +166,37 @@ static struct bno055_sysfs_attr bno055_acc_range = { * = hwval * (dps_range/(2^15 * k)) * where k is rad-to-deg factor */ -static int bno055_gyr_scale_vals[] = { +static const int bno055_gyr_scale_vals[] = { 125, 1877467, 250, 1877467, 500, 1877467, 1000, 1877467, 2000, 1877467, }; -static struct bno055_sysfs_attr bno055_gyr_scale = { +static const int bno055_gyr_scale_hw_xlate[] = {0, 1, 2, 3, 4}; +static const struct bno055_sysfs_attr bno055_gyr_scale = { .vals = bno055_gyr_scale_vals, .len = ARRAY_SIZE(bno055_gyr_scale_vals), - .fusion_vals = (int[]){1, 900}, - .hw_xlate = (int[]){4, 3, 2, 1, 0}, + .fusion_vals = (const int[]){1, 900}, + .hw_xlate = bno055_gyr_scale_hw_xlate, + .hw_xlate_len = ARRAY_SIZE(bno055_gyr_scale_hw_xlate), .type = IIO_VAL_FRACTIONAL, }; -static int bno055_gyr_lpf_vals[] = {12, 23, 32, 47, 64, 116, 230, 523}; -static struct bno055_sysfs_attr bno055_gyr_lpf = { +static const int bno055_gyr_lpf_vals[] = {12, 23, 32, 47, 64, 116, 230, 523}; +static const int bno055_gyr_lpf_hw_xlate[] = {5, 4, 7, 3, 6, 2, 1, 0}; +static const struct bno055_sysfs_attr bno055_gyr_lpf = { .vals = bno055_gyr_lpf_vals, .len = ARRAY_SIZE(bno055_gyr_lpf_vals), - .fusion_vals = (int[]){32}, - .hw_xlate = (int[]){5, 4, 7, 3, 6, 2, 1, 0}, + .fusion_vals = (const int[]){32}, + .hw_xlate = bno055_gyr_lpf_hw_xlate, + .hw_xlate_len = ARRAY_SIZE(bno055_gyr_lpf_hw_xlate), .type = IIO_VAL_INT, }; -static int bno055_mag_odr_vals[] = {2, 6, 8, 10, 15, 20, 25, 30}; -static struct bno055_sysfs_attr bno055_mag_odr = { +static const int bno055_mag_odr_vals[] = {2, 6, 8, 10, 15, 20, 25, 30}; +static const struct bno055_sysfs_attr bno055_mag_odr = { .vals = bno055_mag_odr_vals, .len = ARRAY_SIZE(bno055_mag_odr_vals), - .fusion_vals = (int[]){20}, + .fusion_vals = (const int[]){20}, .type = IIO_VAL_INT, }; @@ -290,7 +295,7 @@ const struct regmap_config bno055_regmap_config = { .max_register = 0x80 * 2, .writeable_reg = bno055_regmap_writeable, .readable_reg = bno055_regmap_readable, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_NS_GPL(bno055_regmap_config, "IIO_BNO055"); @@ -548,7 +553,8 @@ static const struct iio_chan_spec bno055_channels[] = { }; static int bno055_get_regmask(struct bno055_priv *priv, int *val, int *val2, - int reg, int mask, struct bno055_sysfs_attr *attr) + int reg, int mask, + const struct bno055_sysfs_attr *attr) { const int shift = __ffs(mask); int hwval, idx; @@ -561,7 +567,7 @@ static int bno055_get_regmask(struct bno055_priv *priv, int *val, int *val2, idx = (hwval & mask) >> shift; if (attr->hw_xlate) - for (i = 0; i < attr->len; i++) + for (i = 0; i < attr->hw_xlate_len; i++) if (attr->hw_xlate[i] == idx) { idx = i; break; @@ -577,7 +583,8 @@ static int bno055_get_regmask(struct bno055_priv *priv, int *val, int *val2, } static int bno055_set_regmask(struct bno055_priv *priv, int val, int val2, - int reg, int mask, struct bno055_sysfs_attr *attr) + int reg, int mask, + const struct bno055_sysfs_attr *attr) { const int shift = __ffs(mask); int best_delta; @@ -758,7 +765,8 @@ static int bno055_read_simple_chan(struct iio_dev *indio_dev, } } -static int bno055_sysfs_attr_avail(struct bno055_priv *priv, struct bno055_sysfs_attr *attr, +static int bno055_sysfs_attr_avail(struct bno055_priv *priv, + const struct bno055_sysfs_attr *attr, const int **vals, int *length) { if (priv->operation_mode != BNO055_OPR_MODE_AMG) { @@ -1357,7 +1365,7 @@ static const struct bin_attribute *const bno055_bin_attrs[] = { static const struct attribute_group bno055_attrs_group = { .attrs = bno055_attrs, - .bin_attrs_new = bno055_bin_attrs, + .bin_attrs = bno055_bin_attrs, }; static const struct iio_info bno055_info = { diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index f893dbe69965..1430ab4f1dea 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -135,6 +135,14 @@ struct inv_icm42600_suspended { bool temp; }; +struct inv_icm42600_apex { + unsigned int on; + struct { + u64 value; + bool enable; + } wom; +}; + /** * struct inv_icm42600_state - driver state variables * @lock: lock for serializing multiple registers access. @@ -143,14 +151,16 @@ struct inv_icm42600_suspended { * @map: regmap pointer. * @vdd_supply: VDD voltage regulator for the chip. * @vddio_supply: I/O voltage regulator for the chip. + * @irq: chip irq, required to enable/disable and set wakeup * @orientation: sensor chip orientation relative to main hardware. * @conf: chip sensors configurations. * @suspended: suspended sensors configuration. * @indio_gyro: gyroscope IIO device. * @indio_accel: accelerometer IIO device. - * @buffer: data transfer buffer aligned for DMA. - * @fifo: FIFO management structure. * @timestamp: interrupt timestamps. + * @apex: APEX (Advanced Pedometer and Event detection) management + * @fifo: FIFO management structure. + * @buffer: data transfer buffer aligned for DMA. */ struct inv_icm42600_state { struct mutex lock; @@ -159,17 +169,19 @@ struct inv_icm42600_state { struct regmap *map; struct regulator *vdd_supply; struct regulator *vddio_supply; + int irq; struct iio_mount_matrix orientation; struct inv_icm42600_conf conf; struct inv_icm42600_suspended suspended; struct iio_dev *indio_gyro; struct iio_dev *indio_accel; - uint8_t buffer[2] __aligned(IIO_DMA_MINALIGN); - struct inv_icm42600_fifo fifo; struct { - int64_t gyro; - int64_t accel; + s64 gyro; + s64 accel; } timestamp; + struct inv_icm42600_apex apex; + struct inv_icm42600_fifo fifo; + u8 buffer[3] __aligned(IIO_DMA_MINALIGN); }; @@ -253,6 +265,18 @@ struct inv_icm42600_sensor_state { #define INV_ICM42600_REG_FIFO_COUNT 0x002E #define INV_ICM42600_REG_FIFO_DATA 0x0030 +#define INV_ICM42600_REG_INT_STATUS2 0x0037 +#define INV_ICM42600_INT_STATUS2_SMD_INT BIT(3) +#define INV_ICM42600_INT_STATUS2_WOM_INT GENMASK(2, 0) + +#define INV_ICM42600_REG_INT_STATUS3 0x0038 +#define INV_ICM42600_INT_STATUS3_STEP_DET_INT BIT(5) +#define INV_ICM42600_INT_STATUS3_STEP_CNT_OVF_INT BIT(4) +#define INV_ICM42600_INT_STATUS3_TILT_DET_INT BIT(3) +#define INV_ICM42600_INT_STATUS3_WAKE_INT BIT(2) +#define INV_ICM42600_INT_STATUS3_SLEEP_INT BIT(1) +#define INV_ICM42600_INT_STATUS3_TAP_DET_INT BIT(0) + #define INV_ICM42600_REG_SIGNAL_PATH_RESET 0x004B #define INV_ICM42600_SIGNAL_PATH_RESET_DMP_INIT_EN BIT(6) #define INV_ICM42600_SIGNAL_PATH_RESET_DMP_MEM_RESET BIT(5) @@ -309,6 +333,14 @@ struct inv_icm42600_sensor_state { #define INV_ICM42600_TMST_CONFIG_TMST_FSYNC_EN BIT(1) #define INV_ICM42600_TMST_CONFIG_TMST_EN BIT(0) +#define INV_ICM42600_REG_SMD_CONFIG 0x0057 +#define INV_ICM42600_SMD_CONFIG_WOM_INT_MODE BIT(3) +#define INV_ICM42600_SMD_CONFIG_WOM_MODE BIT(2) +#define INV_ICM42600_SMD_CONFIG_SMD_MODE_OFF 0x00 +#define INV_ICM42600_SMD_CONFIG_SMD_MODE_WOM 0x01 +#define INV_ICM42600_SMD_CONFIG_SMD_MODE_SHORT 0x02 +#define INV_ICM42600_SMD_CONFIG_SMD_MODE_LONG 0x03 + #define INV_ICM42600_REG_FIFO_CONFIG1 0x005F #define INV_ICM42600_FIFO_CONFIG1_RESUME_PARTIAL_RD BIT(6) #define INV_ICM42600_FIFO_CONFIG1_WM_GT_TH BIT(5) @@ -338,6 +370,11 @@ struct inv_icm42600_sensor_state { #define INV_ICM42600_INT_SOURCE0_FIFO_FULL_INT1_EN BIT(1) #define INV_ICM42600_INT_SOURCE0_UI_AGC_RDY_INT1_EN BIT(0) +#define INV_ICM42600_REG_INT_SOURCE1 0x0066 +#define INV_ICM42600_INT_SOURCE1_I3C_ERROR_INT1_EN BIT(6) +#define INV_ICM42600_INT_SOURCE1_SMD_INT1_EN BIT(3) +#define INV_ICM42600_INT_SOURCE1_WOM_INT1_EN GENMASK(2, 0) + #define INV_ICM42600_REG_WHOAMI 0x0075 #define INV_ICM42600_WHOAMI_ICM42600 0x40 #define INV_ICM42600_WHOAMI_ICM42602 0x41 @@ -373,6 +410,10 @@ struct inv_icm42600_sensor_state { #define INV_ICM42600_INTF_CONFIG6_I3C_SDR_EN BIT(0) /* User bank 4 (MSB 0x40) */ +#define INV_ICM42600_REG_ACCEL_WOM_X_THR 0x404A +#define INV_ICM42600_REG_ACCEL_WOM_Y_THR 0x404B +#define INV_ICM42600_REG_ACCEL_WOM_Z_THR 0x404C + #define INV_ICM42600_REG_INT_SOURCE8 0x404F #define INV_ICM42600_INT_SOURCE8_FSYNC_IBI_EN BIT(5) #define INV_ICM42600_INT_SOURCE8_PLL_RDY_IBI_EN BIT(4) @@ -410,7 +451,7 @@ const struct iio_mount_matrix * inv_icm42600_get_mount_matrix(const struct iio_dev *indio_dev, const struct iio_chan_spec *chan); -uint32_t inv_icm42600_odr_to_period(enum inv_icm42600_odr odr); +u32 inv_icm42600_odr_to_period(enum inv_icm42600_odr odr); int inv_icm42600_set_accel_conf(struct inv_icm42600_state *st, struct inv_icm42600_sensor_conf *conf, @@ -423,6 +464,9 @@ int inv_icm42600_set_gyro_conf(struct inv_icm42600_state *st, int inv_icm42600_set_temp_conf(struct inv_icm42600_state *st, bool enable, unsigned int *sleep_ms); +int inv_icm42600_enable_wom(struct inv_icm42600_state *st); +int inv_icm42600_disable_wom(struct inv_icm42600_state *st); + int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg, unsigned int writeval, unsigned int *readval); @@ -437,4 +481,8 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st); int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev); +void inv_icm42600_accel_handle_events(struct iio_dev *indio_dev, + unsigned int status2, unsigned int status3, + s64 timestamp); + #endif diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index e6cd9dcb0687..7a28051330b7 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -10,9 +10,12 @@ #include <linux/regmap.h> #include <linux/delay.h> #include <linux/math64.h> +#include <linux/minmax.h> +#include <linux/units.h> #include <linux/iio/buffer.h> #include <linux/iio/common/inv_sensors_timestamp.h> +#include <linux/iio/events.h> #include <linux/iio/iio.h> #include <linux/iio/kfifo_buf.h> @@ -47,6 +50,16 @@ .ext_info = _ext_info, \ } +#define INV_ICM42600_ACCEL_EVENT_CHAN(_modifier, _events, _events_nb) \ + { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = _modifier, \ + .event_spec = _events, \ + .num_event_specs = _events_nb, \ + .scan_index = -1, \ + } + enum inv_icm42600_accel_scan { INV_ICM42600_ACCEL_SCAN_X, INV_ICM42600_ACCEL_SCAN_Y, @@ -82,14 +95,15 @@ static int inv_icm42600_accel_power_mode_set(struct iio_dev *indio_dev, if (idx >= ARRAY_SIZE(inv_icm42600_accel_power_mode_values)) return -EINVAL; - if (iio_buffer_enabled(indio_dev)) - return -EBUSY; - power_mode = inv_icm42600_accel_power_mode_values[idx]; filter = inv_icm42600_accel_filter_values[idx]; guard(mutex)(&st->lock); + /* cannot change if accel sensor is on */ + if (st->conf.accel.mode != INV_ICM42600_SENSOR_MODE_OFF) + return -EBUSY; + /* prevent change if power mode is not supported by the ODR */ switch (power_mode) { case INV_ICM42600_SENSOR_MODE_LOW_NOISE: @@ -160,6 +174,16 @@ static const struct iio_chan_spec_ext_info inv_icm42600_accel_ext_infos[] = { { } }; +/* WoM event: rising ROC */ +static const struct iio_event_spec inv_icm42600_wom_events[] = { + { + .type = IIO_EV_TYPE_ROC, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_VALUE), + }, +}; + static const struct iio_chan_spec inv_icm42600_accel_channels[] = { INV_ICM42600_ACCEL_CHAN(IIO_MOD_X, INV_ICM42600_ACCEL_SCAN_X, inv_icm42600_accel_ext_infos), @@ -169,6 +193,8 @@ static const struct iio_chan_spec inv_icm42600_accel_channels[] = { inv_icm42600_accel_ext_infos), INV_ICM42600_TEMP_CHAN(INV_ICM42600_ACCEL_SCAN_TEMP), IIO_CHAN_SOFT_TIMESTAMP(INV_ICM42600_ACCEL_SCAN_TIMESTAMP), + INV_ICM42600_ACCEL_EVENT_CHAN(IIO_MOD_X_OR_Y_OR_Z, inv_icm42600_wom_events, + ARRAY_SIZE(inv_icm42600_wom_events)), }; /* @@ -177,7 +203,7 @@ static const struct iio_chan_spec inv_icm42600_accel_channels[] = { */ struct inv_icm42600_accel_buffer { struct inv_icm42600_fifo_sensor_data accel; - int16_t temp; + s16 temp; aligned_s64 timestamp; }; @@ -241,7 +267,7 @@ out_unlock: static int inv_icm42600_accel_read_sensor(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, - int16_t *val) + s16 *val) { struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); @@ -284,7 +310,7 @@ static int inv_icm42600_accel_read_sensor(struct iio_dev *indio_dev, if (ret) goto exit; - *val = (int16_t)be16_to_cpup(data); + *val = (s16)be16_to_cpup(data); if (*val == INV_ICM42600_DATA_INVALID) ret = -EINVAL; exit: @@ -294,6 +320,180 @@ exit: return ret; } +static unsigned int inv_icm42600_accel_convert_roc_to_wom(u64 roc, + int accel_hz, int accel_uhz) +{ + /* 1000/256mg per LSB converted in µm/s² */ + const unsigned int convert = (9807U * (MICRO / MILLI)) / 256U; + u64 value; + u64 freq_uhz; + + /* return 0 only if roc is 0 */ + if (roc == 0) + return 0; + + freq_uhz = (u64)accel_hz * MICRO + (u64)accel_uhz; + value = div64_u64(roc * MICRO, freq_uhz * (u64)convert); + + /* limit value to 8 bits and prevent 0 */ + return clamp(value, 1, 255); +} + +static u64 inv_icm42600_accel_convert_wom_to_roc(unsigned int threshold, + int accel_hz, int accel_uhz) +{ + /* 1000/256mg per LSB converted in µm/s² */ + const unsigned int convert = (9807U * (MICRO / MILLI)) / 256U; + u64 value; + u64 freq_uhz; + + value = threshold * convert; + freq_uhz = (u64)accel_hz * MICRO + (u64)accel_uhz; + + /* compute the differential by multiplying by the frequency */ + return div_u64(value * freq_uhz, MICRO); +} + +static int inv_icm42600_accel_set_wom_threshold(struct inv_icm42600_state *st, + u64 value, + int accel_hz, int accel_uhz) +{ + unsigned int threshold; + int ret; + + /* convert roc to wom threshold and convert back to handle clipping */ + threshold = inv_icm42600_accel_convert_roc_to_wom(value, accel_hz, accel_uhz); + value = inv_icm42600_accel_convert_wom_to_roc(threshold, accel_hz, accel_uhz); + + dev_dbg(regmap_get_device(st->map), "wom_threshold: 0x%x\n", threshold); + + /* set accel WoM threshold for the 3 axes */ + st->buffer[0] = threshold; + st->buffer[1] = threshold; + st->buffer[2] = threshold; + ret = regmap_bulk_write(st->map, INV_ICM42600_REG_ACCEL_WOM_X_THR, st->buffer, 3); + if (ret) + return ret; + + st->apex.wom.value = value; + + return 0; +} + +static int _inv_icm42600_accel_enable_wom(struct iio_dev *indio_dev) +{ + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); + struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); + struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT; + unsigned int sleep_ms = 0; + int ret; + + scoped_guard(mutex, &st->lock) { + /* turn on accel sensor */ + conf.mode = accel_st->power_mode; + conf.filter = accel_st->filter; + ret = inv_icm42600_set_accel_conf(st, &conf, &sleep_ms); + if (ret) + return ret; + } + + if (sleep_ms) + msleep(sleep_ms); + + scoped_guard(mutex, &st->lock) { + ret = inv_icm42600_enable_wom(st); + if (ret) + return ret; + st->apex.on++; + st->apex.wom.enable = true; + } + + return 0; +} + +static int inv_icm42600_accel_enable_wom(struct iio_dev *indio_dev) +{ + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); + struct device *pdev = regmap_get_device(st->map); + int ret; + + ret = pm_runtime_resume_and_get(pdev); + if (ret) + return ret; + + ret = _inv_icm42600_accel_enable_wom(indio_dev); + if (ret) { + pm_runtime_mark_last_busy(pdev); + pm_runtime_put_autosuspend(pdev); + return ret; + } + + return 0; +} + +static int _inv_icm42600_accel_disable_wom(struct iio_dev *indio_dev) +{ + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); + struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT; + unsigned int sleep_ms = 0; + int ret; + + scoped_guard(mutex, &st->lock) { + /* + * Consider that turning off WoM is always working to avoid + * blocking the chip in on mode and prevent going back to sleep. + * If there is an error, the chip will anyway go back to sleep + * and the feature will not work anymore. + */ + st->apex.wom.enable = false; + st->apex.on--; + ret = inv_icm42600_disable_wom(st); + if (ret) + return ret; + /* turn off accel sensor if not used */ + if (!st->apex.on && !iio_buffer_enabled(indio_dev)) { + conf.mode = INV_ICM42600_SENSOR_MODE_OFF; + ret = inv_icm42600_set_accel_conf(st, &conf, &sleep_ms); + if (ret) + return ret; + } + } + + if (sleep_ms) + msleep(sleep_ms); + + return 0; +} + +static int inv_icm42600_accel_disable_wom(struct iio_dev *indio_dev) +{ + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); + struct device *pdev = regmap_get_device(st->map); + int ret; + + ret = _inv_icm42600_accel_disable_wom(indio_dev); + + pm_runtime_mark_last_busy(pdev); + pm_runtime_put_autosuspend(pdev); + + return ret; +} + +void inv_icm42600_accel_handle_events(struct iio_dev *indio_dev, + unsigned int status2, unsigned int status3, + s64 timestamp) +{ + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); + u64 ev_code; + + /* handle WoM event */ + if (st->apex.wom.enable && (status2 & INV_ICM42600_INT_STATUS2_WOM_INT)) { + ev_code = IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z, + IIO_EV_TYPE_ROC, IIO_EV_DIR_RISING); + iio_push_event(indio_dev, ev_code, timestamp); + } +} + /* IIO format int + nano */ static const int inv_icm42600_accel_scale[] = { /* +/- 16G => 0.004788403 m/s-2 */ @@ -466,6 +666,10 @@ static int inv_icm42600_accel_write_odr(struct iio_dev *indio_dev, ret = inv_icm42600_set_accel_conf(st, &conf, NULL); if (ret) goto out_unlock; + /* update wom threshold since roc is dependent on sampling frequency */ + ret = inv_icm42600_accel_set_wom_threshold(st, st->apex.wom.value, val, val2); + if (ret) + goto out_unlock; inv_icm42600_buffer_update_fifo_period(st); inv_icm42600_buffer_update_watermark(st); @@ -492,11 +696,11 @@ static int inv_icm42600_accel_read_offset(struct inv_icm42600_state *st, int *val, int *val2) { struct device *dev = regmap_get_device(st->map); - int64_t val64; - int32_t bias; + s64 val64; + s32 bias; unsigned int reg; - int16_t offset; - uint8_t data[2]; + s16 offset; + u8 data[2]; int ret; if (chan->type != IIO_ACCEL) @@ -550,7 +754,7 @@ static int inv_icm42600_accel_read_offset(struct inv_icm42600_state *st, * result in micro (1000000) * (offset * 5 * 9.806650 * 1000000) / 10000 */ - val64 = (int64_t)offset * 5LL * 9806650LL; + val64 = (s64)offset * 5LL * 9806650LL; /* for rounding, add + or - divisor (10000) divided by 2 */ if (val64 >= 0) val64 += 10000LL / 2LL; @@ -568,10 +772,10 @@ static int inv_icm42600_accel_write_offset(struct inv_icm42600_state *st, int val, int val2) { struct device *dev = regmap_get_device(st->map); - int64_t val64; - int32_t min, max; + s64 val64; + s32 min, max; unsigned int reg, regval; - int16_t offset; + s16 offset; int ret; if (chan->type != IIO_ACCEL) @@ -596,7 +800,7 @@ static int inv_icm42600_accel_write_offset(struct inv_icm42600_state *st, inv_icm42600_accel_calibbias[1]; max = inv_icm42600_accel_calibbias[4] * 1000000L + inv_icm42600_accel_calibbias[5]; - val64 = (int64_t)val * 1000000LL + (int64_t)val2; + val64 = (s64)val * 1000000LL + (s64)val2; if (val64 < min || val64 > max) return -EINVAL; @@ -671,7 +875,7 @@ static int inv_icm42600_accel_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); - int16_t data; + s16 data; int ret; switch (chan->type) { @@ -819,6 +1023,116 @@ static int inv_icm42600_accel_hwfifo_flush(struct iio_dev *indio_dev, return ret; } +static int inv_icm42600_accel_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); + + /* handle only WoM (roc rising) event */ + if (type != IIO_EV_TYPE_ROC || dir != IIO_EV_DIR_RISING) + return -EINVAL; + + guard(mutex)(&st->lock); + + return st->apex.wom.enable ? 1 : 0; +} + +static int inv_icm42600_accel_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + bool state) +{ + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); + + /* handle only WoM (roc rising) event */ + if (type != IIO_EV_TYPE_ROC || dir != IIO_EV_DIR_RISING) + return -EINVAL; + + scoped_guard(mutex, &st->lock) { + if (st->apex.wom.enable == state) + return 0; + } + + if (state) + return inv_icm42600_accel_enable_wom(indio_dev); + + return inv_icm42600_accel_disable_wom(indio_dev); +} + +static int inv_icm42600_accel_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); + u32 rem; + + /* handle only WoM (roc rising) event value */ + if (type != IIO_EV_TYPE_ROC || dir != IIO_EV_DIR_RISING) + return -EINVAL; + + guard(mutex)(&st->lock); + + /* return value in micro */ + *val = div_u64_rem(st->apex.wom.value, MICRO, &rem); + *val2 = rem; + return IIO_VAL_INT_PLUS_MICRO; +} + +static int _inv_icm42600_accel_wom_value(struct inv_icm42600_state *st, + int val, int val2) +{ + u64 value; + unsigned int accel_hz, accel_uhz; + int ret; + + guard(mutex)(&st->lock); + + ret = inv_icm42600_accel_read_odr(st, &accel_hz, &accel_uhz); + if (ret < 0) + return ret; + + value = (u64)val * MICRO + (u64)val2; + + return inv_icm42600_accel_set_wom_threshold(st, value, + accel_hz, accel_uhz); +} + +static int inv_icm42600_accel_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); + struct device *dev = regmap_get_device(st->map); + int ret; + + /* handle only WoM (roc rising) event value */ + if (type != IIO_EV_TYPE_ROC || dir != IIO_EV_DIR_RISING) + return -EINVAL; + + if (val < 0 || val2 < 0) + return -EINVAL; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + + ret = _inv_icm42600_accel_wom_value(st, val, val2); + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + return ret; +} + static const struct iio_info inv_icm42600_accel_info = { .read_raw = inv_icm42600_accel_read_raw, .read_avail = inv_icm42600_accel_read_avail, @@ -828,6 +1142,10 @@ static const struct iio_info inv_icm42600_accel_info = { .update_scan_mode = inv_icm42600_accel_update_scan_mode, .hwfifo_set_watermark = inv_icm42600_accel_hwfifo_set_watermark, .hwfifo_flush_to_buffer = inv_icm42600_accel_hwfifo_flush, + .read_event_config = inv_icm42600_accel_read_event_config, + .write_event_config = inv_icm42600_accel_write_event_config, + .read_event_value = inv_icm42600_accel_read_event_value, + .write_event_value = inv_icm42600_accel_write_event_value, }; struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st) @@ -888,6 +1206,11 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st) if (ret) return ERR_PTR(ret); + /* accel events are wakeup capable */ + ret = devm_device_init_wakeup(&indio_dev->dev); + if (ret) + return ERR_PTR(ret); + return indio_dev; } @@ -902,7 +1225,8 @@ int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev) const int8_t *temp; unsigned int odr; int64_t ts_val; - struct inv_icm42600_accel_buffer buffer; + /* buffer is copied to userspace, zeroing it to avoid any data leak */ + struct inv_icm42600_accel_buffer buffer = { }; /* parse all fifo packets */ for (i = 0, no = 0; i < st->fifo.count; i += size, ++no) { @@ -921,8 +1245,6 @@ int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev) inv_sensors_timestamp_apply_odr(ts, st->fifo.period, st->fifo.nb.total, no); - /* buffer is copied to userspace, zeroing it to avoid any data leak */ - memset(&buffer, 0, sizeof(buffer)); memcpy(&buffer.accel, accel, sizeof(buffer.accel)); /* convert 8 bits FIFO temperature in high resolution format */ buffer.temp = temp ? (*temp * 64) : 0; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c index aae7c56481a3..7c4ed981db04 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c @@ -26,28 +26,28 @@ #define INV_ICM42600_FIFO_HEADER_ODR_GYRO BIT(0) struct inv_icm42600_fifo_1sensor_packet { - uint8_t header; + u8 header; struct inv_icm42600_fifo_sensor_data data; - int8_t temp; + s8 temp; } __packed; #define INV_ICM42600_FIFO_1SENSOR_PACKET_SIZE 8 struct inv_icm42600_fifo_2sensors_packet { - uint8_t header; + u8 header; struct inv_icm42600_fifo_sensor_data accel; struct inv_icm42600_fifo_sensor_data gyro; - int8_t temp; + s8 temp; __be16 timestamp; } __packed; #define INV_ICM42600_FIFO_2SENSORS_PACKET_SIZE 16 ssize_t inv_icm42600_fifo_decode_packet(const void *packet, const void **accel, - const void **gyro, const int8_t **temp, + const void **gyro, const s8 **temp, const void **timestamp, unsigned int *odr) { const struct inv_icm42600_fifo_1sensor_packet *pack1 = packet; const struct inv_icm42600_fifo_2sensors_packet *pack2 = packet; - uint8_t header = *((const uint8_t *)packet); + u8 header = *((const u8 *)packet); /* FIFO empty */ if (header & INV_ICM42600_FIFO_HEADER_MSG) { @@ -100,7 +100,7 @@ ssize_t inv_icm42600_fifo_decode_packet(const void *packet, const void **accel, void inv_icm42600_buffer_update_fifo_period(struct inv_icm42600_state *st) { - uint32_t period_gyro, period_accel, period; + u32 period_gyro, period_accel, period; if (st->fifo.en & INV_ICM42600_SENSOR_GYRO) period_gyro = inv_icm42600_odr_to_period(st->conf.gyro.odr); @@ -204,8 +204,8 @@ int inv_icm42600_buffer_update_watermark(struct inv_icm42600_state *st) { size_t packet_size, wm_size; unsigned int wm_gyro, wm_accel, watermark; - uint32_t period_gyro, period_accel, period; - uint32_t latency_gyro, latency_accel, latency; + u32 period_gyro, period_accel, period; + u32 latency_gyro, latency_accel, latency; bool restore; __le16 raw_wm; int ret; @@ -422,7 +422,7 @@ static int inv_icm42600_buffer_postdisable(struct iio_dev *indio_dev) conf.mode = INV_ICM42600_SENSOR_MODE_OFF; if (sensor == INV_ICM42600_SENSOR_GYRO) ret = inv_icm42600_set_gyro_conf(st, &conf, &sleep_sensor); - else + else if (!st->apex.on) ret = inv_icm42600_set_accel_conf(st, &conf, &sleep_sensor); if (ret) goto out_unlock; @@ -459,7 +459,7 @@ int inv_icm42600_buffer_fifo_read(struct inv_icm42600_state *st, __be16 *raw_fifo_count; ssize_t i, size; const void *accel, *gyro, *timestamp; - const int8_t *temp; + const s8 *temp; unsigned int odr; int ret; @@ -550,7 +550,7 @@ int inv_icm42600_buffer_hwfifo_flush(struct inv_icm42600_state *st, struct inv_icm42600_sensor_state *gyro_st = iio_priv(st->indio_gyro); struct inv_icm42600_sensor_state *accel_st = iio_priv(st->indio_accel); struct inv_sensors_timestamp *ts; - int64_t gyro_ts, accel_ts; + s64 gyro_ts, accel_ts; int ret; gyro_ts = iio_get_time_ns(st->indio_gyro); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h index f6c85daf42b0..ffca4da1e249 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h @@ -28,7 +28,7 @@ struct inv_icm42600_state; struct inv_icm42600_fifo { unsigned int on; unsigned int en; - uint32_t period; + u32 period; struct { unsigned int gyro; unsigned int accel; @@ -41,7 +41,7 @@ struct inv_icm42600_fifo { size_t accel; size_t total; } nb; - uint8_t data[2080] __aligned(IIO_DMA_MINALIGN); + u8 data[2080] __aligned(IIO_DMA_MINALIGN); }; /* FIFO data packet */ @@ -52,7 +52,7 @@ struct inv_icm42600_fifo_sensor_data { } __packed; #define INV_ICM42600_FIFO_DATA_INVALID -32768 -static inline int16_t inv_icm42600_fifo_get_sensor_data(__be16 d) +static inline s16 inv_icm42600_fifo_get_sensor_data(__be16 d) { return be16_to_cpu(d); } @@ -60,7 +60,7 @@ static inline int16_t inv_icm42600_fifo_get_sensor_data(__be16 d) static inline bool inv_icm42600_fifo_is_data_valid(const struct inv_icm42600_fifo_sensor_data *s) { - int16_t x, y, z; + s16 x, y, z; x = inv_icm42600_fifo_get_sensor_data(s->x); y = inv_icm42600_fifo_get_sensor_data(s->y); @@ -75,7 +75,7 @@ inv_icm42600_fifo_is_data_valid(const struct inv_icm42600_fifo_sensor_data *s) } ssize_t inv_icm42600_fifo_decode_packet(const void *packet, const void **accel, - const void **gyro, const int8_t **temp, + const void **gyro, const s8 **temp, const void **timestamp, unsigned int *odr); extern const struct iio_buffer_setup_ops inv_icm42600_buffer_ops; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c index 63d46619ebfa..a4d42e7e2180 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c @@ -83,7 +83,7 @@ const struct regmap_config inv_icm42600_regmap_config = { .num_ranges = ARRAY_SIZE(inv_icm42600_regmap_ranges), .volatile_table = inv_icm42600_regmap_volatile_accesses, .rd_noinc_table = inv_icm42600_regmap_rd_noinc_accesses, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; EXPORT_SYMBOL_NS_GPL(inv_icm42600_regmap_config, "IIO_ICM42600"); @@ -97,13 +97,13 @@ const struct regmap_config inv_icm42600_spi_regmap_config = { .num_ranges = ARRAY_SIZE(inv_icm42600_regmap_ranges), .volatile_table = inv_icm42600_regmap_volatile_accesses, .rd_noinc_table = inv_icm42600_regmap_rd_noinc_accesses, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .use_single_write = true, }; EXPORT_SYMBOL_NS_GPL(inv_icm42600_spi_regmap_config, "IIO_ICM42600"); struct inv_icm42600_hw { - uint8_t whoami; + u8 whoami; const char *name; const struct inv_icm42600_conf *conf; }; @@ -188,9 +188,9 @@ inv_icm42600_get_mount_matrix(const struct iio_dev *indio_dev, return &st->orientation; } -uint32_t inv_icm42600_odr_to_period(enum inv_icm42600_odr odr) +u32 inv_icm42600_odr_to_period(enum inv_icm42600_odr odr) { - static uint32_t odr_periods[INV_ICM42600_ODR_NB] = { + static u32 odr_periods[INV_ICM42600_ODR_NB] = { /* reserved values */ 0, 0, 0, /* 8kHz */ @@ -404,6 +404,37 @@ int inv_icm42600_set_temp_conf(struct inv_icm42600_state *st, bool enable, sleep_ms); } +int inv_icm42600_enable_wom(struct inv_icm42600_state *st) +{ + int ret; + + /* enable WoM hardware */ + ret = regmap_write(st->map, INV_ICM42600_REG_SMD_CONFIG, + INV_ICM42600_SMD_CONFIG_SMD_MODE_WOM | + INV_ICM42600_SMD_CONFIG_WOM_MODE); + if (ret) + return ret; + + /* enable WoM interrupt */ + return regmap_set_bits(st->map, INV_ICM42600_REG_INT_SOURCE1, + INV_ICM42600_INT_SOURCE1_WOM_INT1_EN); +} + +int inv_icm42600_disable_wom(struct inv_icm42600_state *st) +{ + int ret; + + /* disable WoM interrupt */ + ret = regmap_clear_bits(st->map, INV_ICM42600_REG_INT_SOURCE1, + INV_ICM42600_INT_SOURCE1_WOM_INT1_EN); + if (ret) + return ret; + + /* disable WoM hardware */ + return regmap_write(st->map, INV_ICM42600_REG_SMD_CONFIG, + INV_ICM42600_SMD_CONFIG_SMD_MODE_OFF); +} + int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg, unsigned int writeval, unsigned int *readval) { @@ -548,6 +579,19 @@ static irqreturn_t inv_icm42600_irq_handler(int irq, void *_data) mutex_lock(&st->lock); + if (st->apex.on) { + unsigned int status2, status3; + + /* read INT_STATUS2 and INT_STATUS3 in 1 operation */ + ret = regmap_bulk_read(st->map, INV_ICM42600_REG_INT_STATUS2, st->buffer, 2); + if (ret) + goto out_unlock; + status2 = st->buffer[0]; + status3 = st->buffer[1]; + inv_icm42600_accel_handle_events(st->indio_accel, status2, status3, + st->timestamp.accel); + } + ret = regmap_read(st->map, INV_ICM42600_REG_INT_STATUS, &status); if (ret) goto out_unlock; @@ -721,6 +765,7 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, mutex_init(&st->lock); st->chip = chip; st->map = regmap; + st->irq = irq; ret = iio_read_mount_matrix(dev, &st->orientation); if (ret) { @@ -799,6 +844,9 @@ EXPORT_SYMBOL_NS_GPL(inv_icm42600_core_probe, "IIO_ICM42600"); static int inv_icm42600_suspend(struct device *dev) { struct inv_icm42600_state *st = dev_get_drvdata(dev); + struct device *accel_dev; + bool wakeup; + int accel_conf; int ret; mutex_lock(&st->lock); @@ -819,13 +867,32 @@ static int inv_icm42600_suspend(struct device *dev) goto out_unlock; } + /* keep chip on and wake-up capable if APEX and wakeup on */ + accel_dev = &st->indio_accel->dev; + wakeup = st->apex.on && device_may_wakeup(accel_dev); + if (wakeup) { + /* keep accel on and setup irq for wakeup */ + accel_conf = st->conf.accel.mode; + enable_irq_wake(st->irq); + disable_irq(st->irq); + } else { + /* disable APEX features and accel if wakeup disabled */ + if (st->apex.wom.enable) { + ret = inv_icm42600_disable_wom(st); + if (ret) + goto out_unlock; + } + accel_conf = INV_ICM42600_SENSOR_MODE_OFF; + } + ret = inv_icm42600_set_pwr_mgmt0(st, INV_ICM42600_SENSOR_MODE_OFF, - INV_ICM42600_SENSOR_MODE_OFF, false, - NULL); + accel_conf, false, NULL); if (ret) goto out_unlock; - regulator_disable(st->vddio_supply); + /* disable vddio regulator if chip is sleeping */ + if (!wakeup) + regulator_disable(st->vddio_supply); out_unlock: mutex_unlock(&st->lock); @@ -841,13 +908,24 @@ static int inv_icm42600_resume(struct device *dev) struct inv_icm42600_state *st = dev_get_drvdata(dev); struct inv_icm42600_sensor_state *gyro_st = iio_priv(st->indio_gyro); struct inv_icm42600_sensor_state *accel_st = iio_priv(st->indio_accel); + struct device *accel_dev; + bool wakeup; int ret; mutex_lock(&st->lock); - ret = inv_icm42600_enable_regulator_vddio(st); - if (ret) - goto out_unlock; + /* check wakeup capability */ + accel_dev = &st->indio_accel->dev; + wakeup = st->apex.on && device_may_wakeup(accel_dev); + /* restore irq state or vddio if cut off */ + if (wakeup) { + enable_irq(st->irq); + disable_irq_wake(st->irq); + } else { + ret = inv_icm42600_enable_regulator_vddio(st); + if (ret) + goto out_unlock; + } pm_runtime_disable(dev); pm_runtime_set_active(dev); @@ -860,6 +938,13 @@ static int inv_icm42600_resume(struct device *dev) if (ret) goto out_unlock; + /* restore APEX features if disabled */ + if (!wakeup && st->apex.wom.enable) { + ret = inv_icm42600_enable_wom(st); + if (ret) + goto out_unlock; + } + /* restore FIFO data streaming */ if (st->fifo.on) { inv_sensors_timestamp_reset(&gyro_st->ts); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c index b4d7ce1432a4..9ba6f13628e6 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c @@ -77,7 +77,7 @@ static const struct iio_chan_spec inv_icm42600_gyro_channels[] = { */ struct inv_icm42600_gyro_buffer { struct inv_icm42600_fifo_sensor_data gyro; - int16_t temp; + s16 temp; aligned_s64 timestamp; }; @@ -139,7 +139,7 @@ out_unlock: static int inv_icm42600_gyro_read_sensor(struct inv_icm42600_state *st, struct iio_chan_spec const *chan, - int16_t *val) + s16 *val) { struct device *dev = regmap_get_device(st->map); struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT; @@ -179,7 +179,7 @@ static int inv_icm42600_gyro_read_sensor(struct inv_icm42600_state *st, if (ret) goto exit; - *val = (int16_t)be16_to_cpup(data); + *val = (s16)be16_to_cpup(data); if (*val == INV_ICM42600_DATA_INVALID) ret = -EINVAL; exit: @@ -399,11 +399,11 @@ static int inv_icm42600_gyro_read_offset(struct inv_icm42600_state *st, int *val, int *val2) { struct device *dev = regmap_get_device(st->map); - int64_t val64; - int32_t bias; + s64 val64; + s32 bias; unsigned int reg; - int16_t offset; - uint8_t data[2]; + s16 offset; + u8 data[2]; int ret; if (chan->type != IIO_ANGL_VEL) @@ -457,7 +457,7 @@ static int inv_icm42600_gyro_read_offset(struct inv_icm42600_state *st, * result in nano (1000000000) * (offset * 64 * Pi * 1000000000) / (2048 * 180) */ - val64 = (int64_t)offset * 64LL * 3141592653LL; + val64 = (s64)offset * 64LL * 3141592653LL; /* for rounding, add + or - divisor (2048 * 180) divided by 2 */ if (val64 >= 0) val64 += 2048 * 180 / 2; @@ -475,9 +475,9 @@ static int inv_icm42600_gyro_write_offset(struct inv_icm42600_state *st, int val, int val2) { struct device *dev = regmap_get_device(st->map); - int64_t val64, min, max; + s64 val64, min, max; unsigned int reg, regval; - int16_t offset; + s16 offset; int ret; if (chan->type != IIO_ANGL_VEL) @@ -498,11 +498,11 @@ static int inv_icm42600_gyro_write_offset(struct inv_icm42600_state *st, } /* inv_icm42600_gyro_calibbias: min - step - max in nano */ - min = (int64_t)inv_icm42600_gyro_calibbias[0] * 1000000000LL + - (int64_t)inv_icm42600_gyro_calibbias[1]; - max = (int64_t)inv_icm42600_gyro_calibbias[4] * 1000000000LL + - (int64_t)inv_icm42600_gyro_calibbias[5]; - val64 = (int64_t)val * 1000000000LL + (int64_t)val2; + min = (s64)inv_icm42600_gyro_calibbias[0] * 1000000000LL + + (s64)inv_icm42600_gyro_calibbias[1]; + max = (s64)inv_icm42600_gyro_calibbias[4] * 1000000000LL + + (s64)inv_icm42600_gyro_calibbias[5]; + val64 = (s64)val * 1000000000LL + (s64)val2; if (val64 < min || val64 > max) return -EINVAL; @@ -577,7 +577,7 @@ static int inv_icm42600_gyro_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); - int16_t data; + s16 data; int ret; switch (chan->type) { @@ -803,10 +803,11 @@ int inv_icm42600_gyro_parse_fifo(struct iio_dev *indio_dev) ssize_t i, size; unsigned int no; const void *accel, *gyro, *timestamp; - const int8_t *temp; + const s8 *temp; unsigned int odr; - int64_t ts_val; - struct inv_icm42600_gyro_buffer buffer; + s64 ts_val; + /* buffer is copied to userspace, zeroing it to avoid any data leak */ + struct inv_icm42600_gyro_buffer buffer = { }; /* parse all fifo packets */ for (i = 0, no = 0; i < st->fifo.count; i += size, ++no) { @@ -825,8 +826,6 @@ int inv_icm42600_gyro_parse_fifo(struct iio_dev *indio_dev) inv_sensors_timestamp_apply_odr(ts, st->fifo.period, st->fifo.nb.total, no); - /* buffer is copied to userspace, zeroing it to avoid any data leak */ - memset(&buffer, 0, sizeof(buffer)); memcpy(&buffer.gyro, gyro, sizeof(buffer.gyro)); /* convert 8 bits FIFO temperature in high resolution format */ buffer.temp = temp ? (*temp * 64) : 0; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c index 988f227f6563..8b15afca498c 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c @@ -13,7 +13,7 @@ #include "inv_icm42600.h" #include "inv_icm42600_temp.h" -static int inv_icm42600_temp_read(struct inv_icm42600_state *st, int16_t *temp) +static int inv_icm42600_temp_read(struct inv_icm42600_state *st, s16 *temp) { struct device *dev = regmap_get_device(st->map); __be16 *raw; @@ -31,7 +31,7 @@ static int inv_icm42600_temp_read(struct inv_icm42600_state *st, int16_t *temp) if (ret) goto exit; - *temp = (int16_t)be16_to_cpup(raw); + *temp = (s16)be16_to_cpup(raw); if (*temp == INV_ICM42600_DATA_INVALID) ret = -EINVAL; @@ -48,7 +48,7 @@ int inv_icm42600_temp_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); - int16_t temp; + s16 temp; int ret; if (chan->type != IIO_TEMP) diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c index a9bcf02e5b43..460792ed27e0 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c @@ -130,12 +130,10 @@ int inv_mpu_acpi_create_mux_client(struct i2c_client *client) st->mux_client = NULL; if (adev) { - struct i2c_board_info info; + struct i2c_board_info info = { }; struct i2c_client *mux_client; int ret = -1; - memset(&info, 0, sizeof(info)); - dmi_check_system(inv_mpu_dev_list); switch (matched_product_name) { case INV_MPU_ASUS_T100TA: diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c index 8a7f2911905a..970cf5c47f68 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c @@ -14,6 +14,8 @@ /* * i2c master auxiliary bus transfer function. * Requires the i2c operations to be correctly setup before. + * Disables SLV0 and checks for NACK status internally. + * Assumes that only SLV0 is used for transfers. */ static int inv_mpu_i2c_master_xfer(const struct inv_mpu6050_state *st) { @@ -23,6 +25,7 @@ static int inv_mpu_i2c_master_xfer(const struct inv_mpu6050_state *st) uint8_t d; unsigned int user_ctrl; int ret; + unsigned int status; /* set sample rate */ d = INV_MPU6050_FIFO_RATE_TO_DIVIDER(freq); @@ -51,12 +54,27 @@ static int inv_mpu_i2c_master_xfer(const struct inv_mpu6050_state *st) if (ret) goto error_restore_rate; + /* disable i2c slave */ + ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0); + if (ret) + goto error_disable_i2c; + + /* check i2c status */ + ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status); + if (ret) + return ret; + + if (status & INV_MPU6050_BIT_I2C_SLV0_NACK) + return -EIO; + return 0; error_stop_i2c: regmap_write(st->map, st->reg->user_ctrl, st->chip_config.user_ctrl); error_restore_rate: regmap_write(st->map, st->reg->sample_rate_div, st->chip_config.divider); +error_disable_i2c: + regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0); return ret; } @@ -117,7 +135,6 @@ int inv_mpu_aux_init(const struct inv_mpu6050_state *st) int inv_mpu_aux_read(const struct inv_mpu6050_state *st, uint8_t addr, uint8_t reg, uint8_t *val, size_t size) { - unsigned int status; int ret; if (size > 0x0F) @@ -136,30 +153,14 @@ int inv_mpu_aux_read(const struct inv_mpu6050_state *st, uint8_t addr, if (ret) return ret; - /* do i2c xfer */ + /* do i2c xfer, disable i2c slave and check status*/ ret = inv_mpu_i2c_master_xfer(st); if (ret) - goto error_disable_i2c; - - /* disable i2c slave */ - ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0); - if (ret) - goto error_disable_i2c; - - /* check i2c status */ - ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status); - if (ret) return ret; - if (status & INV_MPU6050_BIT_I2C_SLV0_NACK) - return -EIO; /* read data in registers */ return regmap_bulk_read(st->map, INV_MPU6050_REG_EXT_SENS_DATA, val, size); - -error_disable_i2c: - regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0); - return ret; } /** @@ -174,7 +175,6 @@ error_disable_i2c: int inv_mpu_aux_write(const struct inv_mpu6050_state *st, uint8_t addr, uint8_t reg, uint8_t val) { - unsigned int status; int ret; /* setup i2c SLV0 control: i2c addr, register, value, enable + size */ @@ -192,26 +192,10 @@ int inv_mpu_aux_write(const struct inv_mpu6050_state *st, uint8_t addr, if (ret) return ret; - /* do i2c xfer */ + /* do i2c xfer, disable i2c slave and check status*/ ret = inv_mpu_i2c_master_xfer(st); if (ret) - goto error_disable_i2c; - - /* disable i2c slave */ - ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0); - if (ret) - goto error_disable_i2c; - - /* check i2c status */ - ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status); - if (ret) return ret; - if (status & INV_MPU6050_BIT_I2C_SLV0_NACK) - return -EIO; return 0; - -error_disable_i2c: - regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0); - return ret; } diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index b8656c02354a..39eb516acc73 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -1382,7 +1382,7 @@ inv_fifo_rate_show(struct device *dev, struct device_attribute *attr, fifo_rate = INV_MPU6050_DIVIDER_TO_FIFO_RATE(st->chip_config.divider); mutex_unlock(&st->lock); - return scnprintf(buf, PAGE_SIZE, "%u\n", fifo_rate); + return sysfs_emit(buf, "%u\n", fifo_rate); } /* @@ -1409,8 +1409,7 @@ static ssize_t inv_attr_show(struct device *dev, struct device_attribute *attr, case ATTR_ACCL_MATRIX: m = st->plat_data.orientation; - return scnprintf(buf, PAGE_SIZE, - "%d, %d, %d; %d, %d, %d; %d, %d, %d\n", + return sysfs_emit(buf, "%d, %d, %d; %d, %d, %d; %d, %d, %d\n", m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]); default: return -EINVAL; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c index 273196e647a2..c4c11124f92f 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c @@ -50,7 +50,8 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) u16 fifo_count; u32 fifo_period; s64 timestamp; - u8 data[INV_MPU6050_OUTPUT_DATA_SIZE] __aligned(8); + /* clear internal data buffer for avoiding kernel data leak */ + u8 data[INV_MPU6050_OUTPUT_DATA_SIZE] __aligned(8) = { }; size_t i, nb; mutex_lock(&st->lock); @@ -103,9 +104,6 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) inv_sensors_timestamp_interrupt(&st->timestamp, 1, pf->timestamp); inv_sensors_timestamp_apply_odr(&st->timestamp, fifo_period, 1, 0); - /* clear internal data buffer for avoiding kernel data leak */ - memset(data, 0, sizeof(data)); - /* read all data once and process every samples */ result = regmap_noinc_read(st->map, st->reg->fifo_r_w, st->data, fifo_count); if (result) diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index 2bdfb2619137..55c82891e08c 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -22,9 +22,6 @@ #include <linux/iio/triggered_buffer.h> #include <linux/iio/trigger_consumer.h> -#define KMX61_DRV_NAME "kmx61" -#define KMX61_IRQ_NAME "kmx61_event" - #define KMX61_REG_WHO_AM_I 0x00 #define KMX61_REG_INS1 0x01 #define KMX61_REG_INS2 0x02 @@ -1312,7 +1309,7 @@ static int kmx61_probe(struct i2c_client *client) kmx61_data_rdy_trig_poll, kmx61_event_handler, IRQF_TRIGGER_RISING, - KMX61_IRQ_NAME, + "kmx61_event", data); if (ret) goto err_chip_uninit; @@ -1494,7 +1491,7 @@ MODULE_DEVICE_TABLE(i2c, kmx61_id); static struct i2c_driver kmx61_driver = { .driver = { - .name = KMX61_DRV_NAME, + .name = "kmx61", .pm = pm_ptr(&kmx61_pm_ops), }, .probe = kmx61_probe, |