summaryrefslogtreecommitdiff
path: root/drivers/iio/imu
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/imu')
-rw-r--r--drivers/iio/imu/adis16400.c314
-rw-r--r--drivers/iio/imu/bmi160/bmi160.h2
-rw-r--r--drivers/iio/imu/bmi160/bmi160_core.c21
-rw-r--r--drivers/iio/imu/bmi160/bmi160_i2c.c2
-rw-r--r--drivers/iio/imu/bmi160/bmi160_spi.c2
-rw-r--r--drivers/iio/imu/bmi270/bmi270.h2
-rw-r--r--drivers/iio/imu/bmi270/bmi270_core.c327
-rw-r--r--drivers/iio/imu/bmi270/bmi270_i2c.c2
-rw-r--r--drivers/iio/imu/bmi270/bmi270_spi.c2
-rw-r--r--drivers/iio/imu/bno055/bno055.c60
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600.h62
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c360
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c24
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h10
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_core.c107
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c41
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c6
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c4
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c56
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c5
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c6
-rw-r--r--drivers/iio/imu/kmx61.c7
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, &regval);
+ 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, &regval);
+ 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, &regval);
+ 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,