From b95ed406278f7588a5504ef94cb526bb8d7f70ff Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Maneyrol Date: Fri, 15 Nov 2019 15:06:21 +0100 Subject: iio: imu: inv_mpu6050: delete not existing MPU9150 spi support MPU9150 is i2c only. Update Kconfig to delete in description chips that are i2c or spi only. Signed-off-by: Jean-Baptiste Maneyrol Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_mpu6050/Kconfig | 6 +++--- drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/iio/imu') diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig index e4c4c12236a7..963a0cafe0cb 100644 --- a/drivers/iio/imu/inv_mpu6050/Kconfig +++ b/drivers/iio/imu/inv_mpu6050/Kconfig @@ -14,7 +14,7 @@ config INV_MPU6050_I2C select INV_MPU6050_IIO select REGMAP_I2C help - This driver supports the Invensense MPU6000/6050/6500/6515, + This driver supports the Invensense MPU6050/6500/6515, MPU9150/9250/9255 and ICM20608/20602 motion tracking devices over I2C. This driver can be built as a module. The module will be called @@ -26,8 +26,8 @@ config INV_MPU6050_SPI select INV_MPU6050_IIO select REGMAP_SPI help - This driver supports the Invensense MPU6000/6050/6500/6515, - MPU9150/9250/9255 and ICM20608/20602 motion tracking devices + This driver supports the Invensense MPU6000/6500/6515, + MPU9250/9255 and ICM20608/20602 motion tracking devices over SPI. This driver can be built as a module. The module will be called inv-mpu6050-spi. diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c index 142692fc0758..ec102d5a5c77 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c @@ -74,7 +74,6 @@ static int inv_mpu_probe(struct spi_device *spi) static const struct spi_device_id inv_mpu_id[] = { {"mpu6000", INV_MPU6000}, {"mpu6500", INV_MPU6500}, - {"mpu9150", INV_MPU9150}, {"mpu9250", INV_MPU9250}, {"mpu9255", INV_MPU9255}, {"icm20608", INV_ICM20608}, -- cgit v1.2.3 From a2587eb032f1679dd695b9e5113bcb6b52e46e0a Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Maneyrol Date: Fri, 15 Nov 2019 15:06:22 +0100 Subject: iio: imu: inv_mpu6050: add support of MPU9150 magnetometer Add support for driving MPU9150 magnetometer (AK8975) from mpu. Signed-off-by: Jean-Baptiste Maneyrol Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 57 ++++++++++++++----- drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c | 2 + drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c | 80 +++++++++++++++++++-------- drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c | 1 + 4 files changed, 104 insertions(+), 36 deletions(-) (limited to 'drivers/iio/imu') diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 45e77b308238..23c0557891a0 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -914,6 +914,33 @@ static const unsigned long inv_mpu_scan_masks[] = { .ext_info = inv_ext_info, \ } +static const struct iio_chan_spec inv_mpu9150_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(INV_MPU9X50_SCAN_TIMESTAMP), + /* + * Note that temperature should only be via polled reading only, + * not the final scan elements output. + */ + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) + | BIT(IIO_CHAN_INFO_OFFSET) + | BIT(IIO_CHAN_INFO_SCALE), + .scan_index = -1, + }, + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X), + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU6050_SCAN_GYRO_Y), + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU6050_SCAN_GYRO_Z), + + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_X, INV_MPU6050_SCAN_ACCL_X), + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_MPU6050_SCAN_ACCL_Y), + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z), + + /* Magnetometer resolution is 13 bits */ + INV_MPU9X50_MAGN_CHAN(IIO_MOD_X, 13, INV_MPU9X50_SCAN_MAGN_X), + INV_MPU9X50_MAGN_CHAN(IIO_MOD_Y, 13, INV_MPU9X50_SCAN_MAGN_Y), + INV_MPU9X50_MAGN_CHAN(IIO_MOD_Z, 13, INV_MPU9X50_SCAN_MAGN_Z), +}; + static const struct iio_chan_spec inv_mpu9250_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(INV_MPU9X50_SCAN_TIMESTAMP), /* @@ -1323,21 +1350,16 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, inv_mpu_bus_setup(indio_dev); switch (chip_type) { + case INV_MPU9150: + indio_dev->channels = inv_mpu9150_channels; + indio_dev->num_channels = ARRAY_SIZE(inv_mpu9150_channels); + indio_dev->available_scan_masks = inv_mpu9x50_scan_masks; + break; case INV_MPU9250: case INV_MPU9255: - /* - * Use magnetometer inside the chip only if there is no i2c - * auxiliary device in use. - */ - if (!st->magn_disabled) { - indio_dev->channels = inv_mpu9250_channels; - indio_dev->num_channels = ARRAY_SIZE(inv_mpu9250_channels); - indio_dev->available_scan_masks = inv_mpu9x50_scan_masks; - } else { - indio_dev->channels = inv_mpu_channels; - indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels); - indio_dev->available_scan_masks = inv_mpu_scan_masks; - } + indio_dev->channels = inv_mpu9250_channels; + indio_dev->num_channels = ARRAY_SIZE(inv_mpu9250_channels); + indio_dev->available_scan_masks = inv_mpu9x50_scan_masks; break; case INV_ICM20602: indio_dev->channels = inv_icm20602_channels; @@ -1350,6 +1372,15 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, indio_dev->available_scan_masks = inv_mpu_scan_masks; break; } + /* + * Use magnetometer inside the chip only if there is no i2c + * auxiliary device in use. Otherwise Going back to 6-axis only. + */ + if (st->magn_disabled) { + indio_dev->channels = inv_mpu_channels; + indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels); + indio_dev->available_scan_masks = inv_mpu_scan_masks; + } indio_dev->info = &mpu_info; indio_dev->modes = INDIO_BUFFER_TRIGGERED; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c index 389cc8505e0e..f47a28b4be23 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c @@ -77,6 +77,7 @@ static bool inv_mpu_i2c_aux_bus(struct device *dev) case INV_ICM20602: /* no i2c auxiliary bus on the chip */ return false; + case INV_MPU9150: case INV_MPU9250: case INV_MPU9255: if (st->magn_disabled) @@ -102,6 +103,7 @@ static int inv_mpu_magn_disable(struct iio_dev *indio_dev) struct device_node *mux_node; switch (st->chip_type) { + case INV_MPU9150: case INV_MPU9250: case INV_MPU9255: mux_node = of_get_child_by_name(dev->of_node, "i2c-gate"); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c index 02735af152c8..4f192352521e 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c @@ -12,7 +12,9 @@ #include "inv_mpu_magn.h" /* - * MPU9250 magnetometer is an AKM AK8963 chip on I2C aux bus + * MPU9xxx magnetometer are AKM chips on I2C aux bus + * MPU9150 is AK8975 + * MPU9250 is AK8963 */ #define INV_MPU_MAGN_I2C_ADDR 0x0C @@ -33,10 +35,10 @@ #define INV_MPU_MAGN_BITS_MODE_PWDN 0x00 #define INV_MPU_MAGN_BITS_MODE_SINGLE 0x01 #define INV_MPU_MAGN_BITS_MODE_FUSE 0x0F -#define INV_MPU_MAGN_BIT_OUTPUT_BIT 0x10 +#define INV_MPU9250_MAGN_BIT_OUTPUT_BIT 0x10 -#define INV_MPU_MAGN_REG_CNTL2 0x0B -#define INV_MPU_MAGN_BIT_SRST 0x01 +#define INV_MPU9250_MAGN_REG_CNTL2 0x0B +#define INV_MPU9250_MAGN_BIT_SRST 0x01 #define INV_MPU_MAGN_REG_ASAX 0x10 #define INV_MPU_MAGN_REG_ASAY 0x11 @@ -48,6 +50,7 @@ static bool inv_magn_supported(const struct inv_mpu6050_state *st) { switch (st->chip_type) { + case INV_MPU9150: case INV_MPU9250: case INV_MPU9255: return true; @@ -61,6 +64,7 @@ static int inv_magn_init(struct inv_mpu6050_state *st) { uint8_t val; uint8_t asa[3]; + int32_t sensitivity; int ret; /* check whoami */ @@ -71,12 +75,19 @@ static int inv_magn_init(struct inv_mpu6050_state *st) if (val != INV_MPU_MAGN_BITS_WIA) return -ENODEV; - /* reset chip */ - ret = inv_mpu_aux_write(st, INV_MPU_MAGN_I2C_ADDR, - INV_MPU_MAGN_REG_CNTL2, - INV_MPU_MAGN_BIT_SRST); - if (ret) - return ret; + /* software reset for MPU925x only */ + switch (st->chip_type) { + case INV_MPU9250: + case INV_MPU9255: + ret = inv_mpu_aux_write(st, INV_MPU_MAGN_I2C_ADDR, + INV_MPU9250_MAGN_REG_CNTL2, + INV_MPU9250_MAGN_BIT_SRST); + if (ret) + return ret; + break; + default: + break; + } /* read fuse ROM data */ ret = inv_mpu_aux_write(st, INV_MPU_MAGN_I2C_ADDR, @@ -97,6 +108,25 @@ static int inv_magn_init(struct inv_mpu6050_state *st) if (ret) return ret; + /* + * Sensor sentivity + * 1 uT = 0.01 G and value is in micron (1e6) + * sensitvity = x uT * 0.01 * 1e6 + */ + switch (st->chip_type) { + case INV_MPU9150: + /* sensor sensitivity is 0.3 uT */ + sensitivity = 3000; + break; + case INV_MPU9250: + case INV_MPU9255: + /* sensor sensitivity in 16 bits mode: 0.15 uT */ + sensitivity = 1500; + break; + default: + return -EINVAL; + } + /* * Sensitivity adjustement and scale to Gauss * @@ -104,16 +134,11 @@ static int inv_magn_init(struct inv_mpu6050_state *st) * Factor simplification: * Hadj = H * ((ASA + 128) / 256) * - * Sensor sentivity - * 0.15 uT in 16 bits mode - * 1 uT = 0.01 G and value is in micron (1e6) - * sensitvity = 0.15 uT * 0.01 * 1e6 - * - * raw_to_gauss = Hadj * 1500 + * raw_to_gauss = Hadj * sensitivity */ - st->magn_raw_to_gauss[0] = (((int32_t)asa[0] + 128) * 1500) / 256; - st->magn_raw_to_gauss[1] = (((int32_t)asa[1] + 128) * 1500) / 256; - st->magn_raw_to_gauss[2] = (((int32_t)asa[2] + 128) * 1500) / 256; + st->magn_raw_to_gauss[0] = (((int32_t)asa[0] + 128) * sensitivity) / 256; + st->magn_raw_to_gauss[1] = (((int32_t)asa[1] + 128) * sensitivity) / 256; + st->magn_raw_to_gauss[2] = (((int32_t)asa[2] + 128) * sensitivity) / 256; return 0; } @@ -129,6 +154,7 @@ static int inv_magn_init(struct inv_mpu6050_state *st) */ int inv_mpu_magn_probe(struct inv_mpu6050_state *st) { + uint8_t val; int ret; /* quit if chip is not supported */ @@ -179,10 +205,17 @@ int inv_mpu_magn_probe(struct inv_mpu6050_state *st) if (ret) return ret; - /* add 16 bits mode */ - ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_DO(1), - INV_MPU_MAGN_BITS_MODE_SINGLE | - INV_MPU_MAGN_BIT_OUTPUT_BIT); + /* add 16 bits mode for MPU925x */ + val = INV_MPU_MAGN_BITS_MODE_SINGLE; + switch (st->chip_type) { + case INV_MPU9250: + case INV_MPU9255: + val |= INV_MPU9250_MAGN_BIT_OUTPUT_BIT; + break; + default: + break; + } + ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_DO(1), val); if (ret) return ret; @@ -237,6 +270,7 @@ int inv_mpu_magn_set_orient(struct inv_mpu6050_state *st) /* fill magnetometer orientation */ switch (st->chip_type) { + case INV_MPU9150: case INV_MPU9250: case INV_MPU9255: /* x <- y */ diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c index d7d951927a44..a9c75bc62f18 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c @@ -50,6 +50,7 @@ static void inv_scan_query(struct iio_dev *indio_dev) struct inv_mpu6050_state *st = iio_priv(indio_dev); switch (st->chip_type) { + case INV_MPU9150: case INV_MPU9250: case INV_MPU9255: return inv_scan_query_mpu9x50(indio_dev); -- cgit v1.2.3 From 6a9afcb198b4de323485c0ee94ff09f653012d4b Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 22 Nov 2019 15:24:11 +0200 Subject: iio: imu: adis: rename txrx_lock -> state_lock The lock can be extended a bit to protect other elements that are not particular to just TX/RX. Another idea would have been to just add a new `state_lock`, but that would mean 2 locks which would be redundant, and probably cause more potential for dead-locks. What will be done in the next patches, will be to add some unlocked versions for read/write_reg functions. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis.c | 10 +++++----- drivers/iio/imu/adis_buffer.c | 4 ++-- include/linux/iio/imu/adis.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/iio/imu') diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c index 85de565a4e80..db562fec79b2 100644 --- a/drivers/iio/imu/adis.c +++ b/drivers/iio/imu/adis.c @@ -70,7 +70,7 @@ int adis_write_reg(struct adis *adis, unsigned int reg, }, }; - mutex_lock(&adis->txrx_lock); + mutex_lock(&adis->state_lock); spi_message_init(&msg); @@ -114,7 +114,7 @@ int adis_write_reg(struct adis *adis, unsigned int reg, } out_unlock: - mutex_unlock(&adis->txrx_lock); + mutex_unlock(&adis->state_lock); return ret; } @@ -166,7 +166,7 @@ int adis_read_reg(struct adis *adis, unsigned int reg, }, }; - mutex_lock(&adis->txrx_lock); + mutex_lock(&adis->state_lock); spi_message_init(&msg); if (adis->current_page != page) { @@ -211,7 +211,7 @@ int adis_read_reg(struct adis *adis, unsigned int reg, } out_unlock: - mutex_unlock(&adis->txrx_lock); + mutex_unlock(&adis->state_lock); return ret; } @@ -438,7 +438,7 @@ EXPORT_SYMBOL_GPL(adis_single_conversion); int adis_init(struct adis *adis, struct iio_dev *indio_dev, struct spi_device *spi, const struct adis_data *data) { - mutex_init(&adis->txrx_lock); + mutex_init(&adis->state_lock); adis->spi = spi; adis->data = data; iio_device_set_drvdata(indio_dev, adis); diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index 4998a89d083d..3f4dd5c00b03 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -129,7 +129,7 @@ static irqreturn_t adis_trigger_handler(int irq, void *p) return -ENOMEM; if (adis->data->has_paging) { - mutex_lock(&adis->txrx_lock); + mutex_lock(&adis->state_lock); if (adis->current_page != 0) { adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID); adis->tx[1] = 0; @@ -144,7 +144,7 @@ static irqreturn_t adis_trigger_handler(int irq, void *p) if (adis->data->has_paging) { adis->current_page = 0; - mutex_unlock(&adis->txrx_lock); + mutex_unlock(&adis->state_lock); } iio_push_to_buffers_with_timestamp(indio_dev, adis->buffer, diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h index 92aae14593bf..100b5d1cebf1 100644 --- a/include/linux/iio/imu/adis.h +++ b/include/linux/iio/imu/adis.h @@ -61,7 +61,7 @@ struct adis { const struct adis_data *data; struct adis_burst *burst; - struct mutex txrx_lock; + struct mutex state_lock; struct spi_message msg; struct spi_transfer *xfer; unsigned int current_page; -- cgit v1.2.3 From 770d465619423a946248018ea39ed9a74c8f2ff4 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 22 Nov 2019 15:24:12 +0200 Subject: iio: imu: adis: add unlocked read/write function versions This will allow more flexible control to group reads & writes into a single lock (particularly the state_lock). The end-goal is to remove the indio_dev->mlock usage, and the simplest fix would have been to just add another lock, which would not be a good idea on the long-run. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis.c | 35 ++++++------- include/linux/iio/imu/adis.h | 116 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 130 insertions(+), 21 deletions(-) (limited to 'drivers/iio/imu') diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c index db562fec79b2..2f518e6c727d 100644 --- a/drivers/iio/imu/adis.c +++ b/drivers/iio/imu/adis.c @@ -26,7 +26,14 @@ #define ADIS_MSC_CTRL_DATA_RDY_DIO2 BIT(0) #define ADIS_GLOB_CMD_SW_RESET BIT(7) -int adis_write_reg(struct adis *adis, unsigned int reg, +/** + * __adis_write_reg() - write N bytes to register (unlocked version) + * @adis: The adis device + * @reg: The address of the lower of the two registers + * @value: The value to write to device (up to 4 bytes) + * @size: The size of the @value (in bytes) + */ +int __adis_write_reg(struct adis *adis, unsigned int reg, unsigned int value, unsigned int size) { unsigned int page = reg / ADIS_PAGE_SIZE; @@ -70,8 +77,6 @@ int adis_write_reg(struct adis *adis, unsigned int reg, }, }; - mutex_lock(&adis->state_lock); - spi_message_init(&msg); if (adis->current_page != page) { @@ -96,8 +101,7 @@ int adis_write_reg(struct adis *adis, unsigned int reg, adis->tx[3] = value & 0xff; break; default: - ret = -EINVAL; - goto out_unlock; + return -EINVAL; } xfers[size].cs_change = 0; @@ -113,20 +117,18 @@ int adis_write_reg(struct adis *adis, unsigned int reg, adis->current_page = page; } -out_unlock: - mutex_unlock(&adis->state_lock); - return ret; } -EXPORT_SYMBOL_GPL(adis_write_reg); +EXPORT_SYMBOL_GPL(__adis_write_reg); /** - * adis_read_reg() - read 2 bytes from a 16-bit register + * __adis_read_reg() - read N bytes from register (unlocked version) * @adis: The adis device * @reg: The address of the lower of the two registers * @val: The value read back from the device + * @size: The size of the @val buffer */ -int adis_read_reg(struct adis *adis, unsigned int reg, +int __adis_read_reg(struct adis *adis, unsigned int reg, unsigned int *val, unsigned int size) { unsigned int page = reg / ADIS_PAGE_SIZE; @@ -166,7 +168,6 @@ int adis_read_reg(struct adis *adis, unsigned int reg, }, }; - mutex_lock(&adis->state_lock); spi_message_init(&msg); if (adis->current_page != page) { @@ -188,15 +189,14 @@ int adis_read_reg(struct adis *adis, unsigned int reg, spi_message_add_tail(&xfers[3], &msg); break; default: - ret = -EINVAL; - goto out_unlock; + return -EINVAL; } ret = spi_sync(adis->spi, &msg); if (ret) { dev_err(&adis->spi->dev, "Failed to read register 0x%02X: %d\n", reg, ret); - goto out_unlock; + return ret; } else { adis->current_page = page; } @@ -210,12 +210,9 @@ int adis_read_reg(struct adis *adis, unsigned int reg, break; } -out_unlock: - mutex_unlock(&adis->state_lock); - return ret; } -EXPORT_SYMBOL_GPL(adis_read_reg); +EXPORT_SYMBOL_GPL(__adis_read_reg); #ifdef CONFIG_DEBUG_FS diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h index 100b5d1cebf1..38ebe41092e1 100644 --- a/include/linux/iio/imu/adis.h +++ b/include/linux/iio/imu/adis.h @@ -75,11 +75,123 @@ int adis_init(struct adis *adis, struct iio_dev *indio_dev, struct spi_device *spi, const struct adis_data *data); int adis_reset(struct adis *adis); -int adis_write_reg(struct adis *adis, unsigned int reg, +int __adis_write_reg(struct adis *adis, unsigned int reg, unsigned int val, unsigned int size); -int adis_read_reg(struct adis *adis, unsigned int reg, +int __adis_read_reg(struct adis *adis, unsigned int reg, unsigned int *val, unsigned int size); +/** + * __adis_write_reg_8() - Write single byte to a register (unlocked) + * @adis: The adis device + * @reg: The address of the register to be written + * @value: The value to write + */ +static inline int __adis_write_reg_8(struct adis *adis, unsigned int reg, + uint8_t val) +{ + return __adis_write_reg(adis, reg, val, 1); +} + +/** + * __adis_write_reg_16() - Write 2 bytes to a pair of registers (unlocked) + * @adis: The adis device + * @reg: The address of the lower of the two registers + * @value: Value to be written + */ +static inline int __adis_write_reg_16(struct adis *adis, unsigned int reg, + uint16_t val) +{ + return __adis_write_reg(adis, reg, val, 2); +} + +/** + * __adis_write_reg_32() - write 4 bytes to four registers (unlocked) + * @adis: The adis device + * @reg: The address of the lower of the four register + * @value: Value to be written + */ +static inline int __adis_write_reg_32(struct adis *adis, unsigned int reg, + uint32_t val) +{ + return __adis_write_reg(adis, reg, val, 4); +} + +/** + * __adis_read_reg_16() - read 2 bytes from a 16-bit register (unlocked) + * @adis: The adis device + * @reg: The address of the lower of the two registers + * @val: The value read back from the device + */ +static inline int __adis_read_reg_16(struct adis *adis, unsigned int reg, + uint16_t *val) +{ + unsigned int tmp; + int ret; + + ret = __adis_read_reg(adis, reg, &tmp, 2); + if (ret == 0) + *val = tmp; + + return ret; +} + +/** + * __adis_read_reg_32() - read 4 bytes from a 32-bit register (unlocked) + * @adis: The adis device + * @reg: The address of the lower of the two registers + * @val: The value read back from the device + */ +static inline int __adis_read_reg_32(struct adis *adis, unsigned int reg, + uint32_t *val) +{ + unsigned int tmp; + int ret; + + ret = __adis_read_reg(adis, reg, &tmp, 4); + if (ret == 0) + *val = tmp; + + return ret; +} + +/** + * adis_write_reg() - write N bytes to register + * @adis: The adis device + * @reg: The address of the lower of the two registers + * @value: The value to write to device (up to 4 bytes) + * @size: The size of the @value (in bytes) + */ +static inline int adis_write_reg(struct adis *adis, unsigned int reg, + unsigned int val, unsigned int size) +{ + int ret; + + mutex_lock(&adis->state_lock); + ret = __adis_write_reg(adis, reg, val, size); + mutex_unlock(&adis->state_lock); + + return ret; +} + +/** + * adis_read_reg() - read N bytes from register + * @adis: The adis device + * @reg: The address of the lower of the two registers + * @val: The value read back from the device + * @size: The size of the @val buffer + */ +static int adis_read_reg(struct adis *adis, unsigned int reg, + unsigned int *val, unsigned int size) +{ + int ret; + + mutex_lock(&adis->state_lock); + ret = __adis_read_reg(adis, reg, val, size); + mutex_unlock(&adis->state_lock); + + return ret; +} + /** * adis_write_reg_8() - Write single byte to a register * @adis: The adis device -- cgit v1.2.3 From 100bfa38c8cb81ccbbd17ee4f0c1164f455f6039 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 22 Nov 2019 15:24:13 +0200 Subject: iio: imu: adis[16480]: group RW into a single lock in adis_enable_irq() The adis_enable_irq() does a read & a write. This change keeps a lock for the duration of both operations vs for each op. The change is also needed in adis16480, since that has it's own implementation for adis_enable_irq(). Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis.c | 17 +++++++++++------ drivers/iio/imu/adis16480.c | 4 ++-- 2 files changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers/iio/imu') diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c index 2f518e6c727d..5cf7a15be6ee 100644 --- a/drivers/iio/imu/adis.c +++ b/drivers/iio/imu/adis.c @@ -250,12 +250,16 @@ int adis_enable_irq(struct adis *adis, bool enable) int ret = 0; uint16_t msc; - if (adis->data->enable_irq) - return adis->data->enable_irq(adis, enable); + mutex_lock(&adis->state_lock); - ret = adis_read_reg_16(adis, adis->data->msc_ctrl_reg, &msc); + if (adis->data->enable_irq) { + ret = adis->data->enable_irq(adis, enable); + goto out_unlock; + } + + ret = __adis_read_reg_16(adis, adis->data->msc_ctrl_reg, &msc); if (ret) - goto error_ret; + goto out_unlock; msc |= ADIS_MSC_CTRL_DATA_RDY_POL_HIGH; msc &= ~ADIS_MSC_CTRL_DATA_RDY_DIO2; @@ -264,9 +268,10 @@ int adis_enable_irq(struct adis *adis, bool enable) else msc &= ~ADIS_MSC_CTRL_DATA_RDY_EN; - ret = adis_write_reg_16(adis, adis->data->msc_ctrl_reg, msc); + ret = __adis_write_reg_16(adis, adis->data->msc_ctrl_reg, msc); -error_ret: +out_unlock: + mutex_unlock(&adis->state_lock); return ret; } EXPORT_SYMBOL(adis_enable_irq); diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index 748f8bbf184d..e943039c3f98 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -947,14 +947,14 @@ static int adis16480_enable_irq(struct adis *adis, bool enable) uint16_t val; int ret; - ret = adis_read_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, &val); + ret = __adis_read_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, &val); if (ret) return ret; val &= ~ADIS16480_DRDY_EN_MSK; val |= ADIS16480_DRDY_EN(enable); - return adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, val); + return __adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, val); } static int adis16480_initial_setup(struct iio_dev *indio_dev) -- cgit v1.2.3 From 6a4d6a7d6588d8c15501542da786ebff6602475c Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 22 Nov 2019 15:24:14 +0200 Subject: iio: imu: adis: create an unlocked version of adis_check_status() This one also gets re-used in certain operations, so it makes sense to have an unlocked version of this to group it with other reads/writes/operations to have a single lock for the whole state change. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis.c | 8 ++++---- include/linux/iio/imu/adis.h | 13 ++++++++++++- 2 files changed, 16 insertions(+), 5 deletions(-) (limited to 'drivers/iio/imu') diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c index 5cf7a15be6ee..b63d6e6f5415 100644 --- a/drivers/iio/imu/adis.c +++ b/drivers/iio/imu/adis.c @@ -277,18 +277,18 @@ out_unlock: EXPORT_SYMBOL(adis_enable_irq); /** - * adis_check_status() - Check the device for error conditions + * __adis_check_status() - Check the device for error conditions (unlocked) * @adis: The adis device * * Returns 0 on success, a negative error code otherwise */ -int adis_check_status(struct adis *adis) +int __adis_check_status(struct adis *adis) { uint16_t status; int ret; int i; - ret = adis_read_reg_16(adis, adis->data->diag_stat_reg, &status); + ret = __adis_read_reg_16(adis, adis->data->diag_stat_reg, &status); if (ret) return ret; @@ -306,7 +306,7 @@ int adis_check_status(struct adis *adis) return -EIO; } -EXPORT_SYMBOL_GPL(adis_check_status); +EXPORT_SYMBOL_GPL(__adis_check_status); /** * adis_reset() - Reset the device diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h index 38ebe41092e1..db759957e1c1 100644 --- a/include/linux/iio/imu/adis.h +++ b/include/linux/iio/imu/adis.h @@ -267,7 +267,18 @@ static inline int adis_read_reg_32(struct adis *adis, unsigned int reg, } int adis_enable_irq(struct adis *adis, bool enable); -int adis_check_status(struct adis *adis); +int __adis_check_status(struct adis *adis); + +static inline int adis_check_status(struct adis *adis) +{ + int ret; + + mutex_lock(&adis->state_lock); + ret = __adis_check_status(adis); + mutex_unlock(&adis->state_lock); + + return ret; +} int adis_initial_startup(struct adis *adis); -- cgit v1.2.3 From 762ab093cbe26451175a5a63ea06c971bf973525 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 22 Nov 2019 15:24:15 +0200 Subject: iio: imu: adis: create an unlocked version of adis_reset() The reset routine may also be important to be protected by the state-lock and grouped with other operations, so create an unlocked version, so that this can be done. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis.c | 8 ++++---- include/linux/iio/imu/adis.h | 19 ++++++++++++++++++- 2 files changed, 22 insertions(+), 5 deletions(-) (limited to 'drivers/iio/imu') diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c index b63d6e6f5415..615f174f0e6e 100644 --- a/drivers/iio/imu/adis.c +++ b/drivers/iio/imu/adis.c @@ -309,23 +309,23 @@ int __adis_check_status(struct adis *adis) EXPORT_SYMBOL_GPL(__adis_check_status); /** - * adis_reset() - Reset the device + * __adis_reset() - Reset the device (unlocked version) * @adis: The adis device * * Returns 0 on success, a negative error code otherwise */ -int adis_reset(struct adis *adis) +int __adis_reset(struct adis *adis) { int ret; - ret = adis_write_reg_8(adis, adis->data->glob_cmd_reg, + ret = __adis_write_reg_8(adis, adis->data->glob_cmd_reg, ADIS_GLOB_CMD_SW_RESET); if (ret) dev_err(&adis->spi->dev, "Failed to reset device: %d\n", ret); return ret; } -EXPORT_SYMBOL_GPL(adis_reset); +EXPORT_SYMBOL_GPL(__adis_reset); static int adis_self_test(struct adis *adis) { diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h index db759957e1c1..4b5bc0e06e69 100644 --- a/include/linux/iio/imu/adis.h +++ b/include/linux/iio/imu/adis.h @@ -73,7 +73,24 @@ struct adis { int adis_init(struct adis *adis, struct iio_dev *indio_dev, struct spi_device *spi, const struct adis_data *data); -int adis_reset(struct adis *adis); +int __adis_reset(struct adis *adis); + +/** + * adis_reset() - Reset the device + * @adis: The adis device + * + * Returns 0 on success, a negative error code otherwise + */ +static inline int adis_reset(struct adis *adis) +{ + int ret; + + mutex_lock(&adis->state_lock); + ret = __adis_reset(adis); + mutex_unlock(&adis->state_lock); + + return ret; +} int __adis_write_reg(struct adis *adis, unsigned int reg, unsigned int val, unsigned int size); -- cgit v1.2.3 From cb5a07f1f15cc3fd7e12bfdd48ba0e9fb585ea5e Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 22 Nov 2019 15:24:16 +0200 Subject: iio: imu: adis: protect initial startup routine with state lock The initial startup routine is called by some ADIS drivers during probe, and before registering with IIO. Normally, userspace should not be able to do any access to the device (as there shouldn't be any available). This change extends the state lock to the entire initial-startup routine. Behaviourally nothing should change, but this should make the library function a bit more robust. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/iio/imu') diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c index 615f174f0e6e..10b8922fd51b 100644 --- a/drivers/iio/imu/adis.c +++ b/drivers/iio/imu/adis.c @@ -331,7 +331,7 @@ static int adis_self_test(struct adis *adis) { int ret; - ret = adis_write_reg_16(adis, adis->data->msc_ctrl_reg, + ret = __adis_write_reg_16(adis, adis->data->msc_ctrl_reg, adis->data->self_test_mask); if (ret) { dev_err(&adis->spi->dev, "Failed to initiate self test: %d\n", @@ -341,10 +341,10 @@ static int adis_self_test(struct adis *adis) msleep(adis->data->startup_delay); - ret = adis_check_status(adis); + ret = __adis_check_status(adis); if (adis->data->self_test_no_autoclear) - adis_write_reg_16(adis, adis->data->msc_ctrl_reg, 0x00); + __adis_write_reg_16(adis, adis->data->msc_ctrl_reg, 0x00); return ret; } @@ -362,19 +362,23 @@ int adis_initial_startup(struct adis *adis) { int ret; + mutex_lock(&adis->state_lock); + ret = adis_self_test(adis); if (ret) { dev_err(&adis->spi->dev, "Self-test failed, trying reset.\n"); - adis_reset(adis); + __adis_reset(adis); msleep(adis->data->startup_delay); ret = adis_self_test(adis); if (ret) { dev_err(&adis->spi->dev, "Second self-test failed, giving up.\n"); - return ret; + goto out_unlock; } } - return 0; +out_unlock: + mutex_unlock(&adis->state_lock); + return ret; } EXPORT_SYMBOL_GPL(adis_initial_startup); -- cgit v1.2.3 From c5485a5d6a5f7d00ca4aba6698526c5ae3f2a1a2 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 22 Nov 2019 15:24:17 +0200 Subject: iio: imu: adis: group single conversion under a single state lock The single conversion function does a series of reads + writes. This change extends the use of the state_lock for the entire set of operations. Previously, indio_dev's mlock was used. This change also removes the use of this lock. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/iio/imu') diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c index 10b8922fd51b..c53f3ed3cb97 100644 --- a/drivers/iio/imu/adis.c +++ b/drivers/iio/imu/adis.c @@ -404,15 +404,15 @@ int adis_single_conversion(struct iio_dev *indio_dev, unsigned int uval; int ret; - mutex_lock(&indio_dev->mlock); + mutex_lock(&adis->state_lock); - ret = adis_read_reg(adis, chan->address, &uval, + ret = __adis_read_reg(adis, chan->address, &uval, chan->scan_type.storagebits / 8); if (ret) goto err_unlock; if (uval & error_mask) { - ret = adis_check_status(adis); + ret = __adis_check_status(adis); if (ret) goto err_unlock; } @@ -424,7 +424,7 @@ int adis_single_conversion(struct iio_dev *indio_dev, ret = IIO_VAL_INT; err_unlock: - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&adis->state_lock); return ret; } EXPORT_SYMBOL_GPL(adis_single_conversion); -- cgit v1.2.3 From ce476cd18aaea91ee31b991774553ba5239c9ee2 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 22 Nov 2019 15:24:18 +0200 Subject: iio: imu: adis16400: rework locks using ADIS library's state lock This change removes the use of indio_dev's mlock in favor using the state lock from the ADIS library. The set_freq() & get_freq() hooks are unlocked, so they require specific locking. That is because in some cases the get_freq() hook is used in combination with adis16400_set_filter(). In cases where only one read/write is done, the functions that hold the state lock are used. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16400.c | 51 ++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 26 deletions(-) (limited to 'drivers/iio/imu') diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c index 44e46dc96e00..662cb5367c11 100644 --- a/drivers/iio/imu/adis16400.c +++ b/drivers/iio/imu/adis16400.c @@ -162,6 +162,7 @@ struct adis16400_chip_info { unsigned int accel_scale_micro; int temp_scale_nano; int temp_offset; + /* set_freq() & get_freq() need to avoid using ADIS lib's state lock */ int (*set_freq)(struct adis16400_state *st, unsigned int freq); int (*get_freq)(struct adis16400_state *st); }; @@ -326,7 +327,7 @@ static int adis16334_get_freq(struct adis16400_state *st) int ret; uint16_t t; - ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t); + ret = __adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t); if (ret) return ret; @@ -350,7 +351,7 @@ static int adis16334_set_freq(struct adis16400_state *st, unsigned int freq) t <<= ADIS16334_RATE_DIV_SHIFT; t |= ADIS16334_RATE_INT_CLK; - return adis_write_reg_16(&st->adis, ADIS16400_SMPL_PRD, t); + return __adis_write_reg_16(&st->adis, ADIS16400_SMPL_PRD, t); } static int adis16400_get_freq(struct adis16400_state *st) @@ -358,7 +359,7 @@ static int adis16400_get_freq(struct adis16400_state *st) int sps, ret; uint16_t t; - ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t); + ret = __adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t); if (ret) return ret; @@ -390,7 +391,7 @@ static int adis16400_set_freq(struct adis16400_state *st, unsigned int freq) else st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; - return adis_write_reg_8(&st->adis, ADIS16400_SMPL_PRD, val); + return __adis_write_reg_8(&st->adis, ADIS16400_SMPL_PRD, val); } static const unsigned int adis16400_3db_divisors[] = { @@ -404,7 +405,7 @@ static const unsigned int adis16400_3db_divisors[] = { [7] = 200, /* Not a valid setting */ }; -static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val) +static int __adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val) { struct adis16400_state *st = iio_priv(indio_dev); uint16_t val16; @@ -415,11 +416,11 @@ static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val) break; } - ret = adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16); + ret = __adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16); if (ret) return ret; - ret = adis_write_reg_16(&st->adis, ADIS16400_SENS_AVG, + ret = __adis_write_reg_16(&st->adis, ADIS16400_SENS_AVG, (val16 & ~0x07) | i); return ret; } @@ -507,32 +508,31 @@ static int adis16400_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long info) { struct adis16400_state *st = iio_priv(indio_dev); + struct mutex *slock = &st->adis.state_lock; int ret, sps; switch (info) { case IIO_CHAN_INFO_CALIBBIAS: - mutex_lock(&indio_dev->mlock); ret = adis_write_reg_16(&st->adis, adis16400_addresses[chan->scan_index], val); - mutex_unlock(&indio_dev->mlock); return ret; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: /* * Need to cache values so we can update if the frequency * changes. */ - mutex_lock(&indio_dev->mlock); + mutex_lock(slock); st->filt_int = val; /* Work out update to current value */ sps = st->variant->get_freq(st); if (sps < 0) { - mutex_unlock(&indio_dev->mlock); + mutex_unlock(slock); return sps; } - ret = adis16400_set_filter(indio_dev, sps, + ret = __adis16400_set_filter(indio_dev, sps, val * 1000 + val2 / 1000); - mutex_unlock(&indio_dev->mlock); + mutex_unlock(slock); return ret; case IIO_CHAN_INFO_SAMP_FREQ: sps = val * 1000 + val2 / 1000; @@ -540,9 +540,9 @@ static int adis16400_write_raw(struct iio_dev *indio_dev, if (sps <= 0) return -EINVAL; - mutex_lock(&indio_dev->mlock); + mutex_lock(slock); ret = st->variant->set_freq(st, sps); - mutex_unlock(&indio_dev->mlock); + mutex_unlock(slock); return ret; default: return -EINVAL; @@ -553,6 +553,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long info) { struct adis16400_state *st = iio_priv(indio_dev); + struct mutex *slock = &st->adis.state_lock; int16_t val16; int ret; @@ -596,10 +597,8 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, return -EINVAL; } case IIO_CHAN_INFO_CALIBBIAS: - mutex_lock(&indio_dev->mlock); ret = adis_read_reg_16(&st->adis, adis16400_addresses[chan->scan_index], &val16); - mutex_unlock(&indio_dev->mlock); if (ret) return ret; val16 = sign_extend32(val16, 11); @@ -610,27 +609,27 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, *val = st->variant->temp_offset; return IIO_VAL_INT; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: - mutex_lock(&indio_dev->mlock); + mutex_lock(slock); /* Need both the number of taps and the sampling frequency */ - ret = adis_read_reg_16(&st->adis, + ret = __adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16); if (ret) { - mutex_unlock(&indio_dev->mlock); + mutex_unlock(slock); return ret; } ret = st->variant->get_freq(st); - if (ret >= 0) { - ret /= adis16400_3db_divisors[val16 & 0x07]; - *val = ret / 1000; - *val2 = (ret % 1000) * 1000; - } - mutex_unlock(&indio_dev->mlock); + mutex_unlock(slock); if (ret) return ret; + ret /= adis16400_3db_divisors[val16 & 0x07]; + *val = ret / 1000; + *val2 = (ret % 1000) * 1000; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(slock); ret = st->variant->get_freq(st); + mutex_unlock(slock); if (ret) return ret; *val = ret / 1000; -- cgit v1.2.3 From d693845da31c4d1093a8165d1ac4a73eac0f9373 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 22 Nov 2019 15:24:20 +0200 Subject: iio: imu: adis16480: use state lock for filter freq set It's the only operation that does 2 operations (a read & a write), so the unlocked functions can be used under a single state lock. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16480.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers/iio/imu') diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index e943039c3f98..f73094e8d35d 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -555,6 +555,7 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, unsigned int freq) { struct adis16480 *st = iio_priv(indio_dev); + struct mutex *slock = &st->adis.state_lock; unsigned int enable_mask, offset, reg; unsigned int diff, best_diff; unsigned int i, best_freq; @@ -565,9 +566,11 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev, offset = ad16480_filter_data[chan->scan_index][1]; enable_mask = BIT(offset + 2); - ret = adis_read_reg_16(&st->adis, reg, &val); + mutex_lock(slock); + + ret = __adis_read_reg_16(&st->adis, reg, &val); if (ret) - return ret; + goto out_unlock; if (freq == 0) { val &= ~enable_mask; @@ -589,7 +592,11 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev, val |= enable_mask; } - return adis_write_reg_16(&st->adis, reg, val); + ret = __adis_write_reg_16(&st->adis, reg, val); +out_unlock: + mutex_unlock(slock); + + return ret; } static int adis16480_read_raw(struct iio_dev *indio_dev, -- cgit v1.2.3 From 52241a082d6c08f4993180752ed5a12b39712f03 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 27 Nov 2019 21:17:38 +0100 Subject: iio: imu: inv_mpu6050: Select I2C_MUX again commit f7072198f217 ("iio: imu: Fix inv_mpu6050 dependencies") undid the explicit selection of I2C_MUX previously done by the driver, because I2C_MUX implicitly depended on HAS_IOMEM. However commit 93d710a65ef0 ("i2c: mux: fix up dependencies") cleared up the situation properly and drivers that need to select I2C_MUX can now do so again. It makes a lot of sense for a driver to select the driver infrastructure it needs so restore the natural order of things. Cc: Richard Weinberger Cc: Stephan Gerhold Signed-off-by: Linus Walleij Acked-by: Jean-Baptiste Maneyrol Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_mpu6050/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/iio/imu') diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig index 963a0cafe0cb..017bc0fcc365 100644 --- a/drivers/iio/imu/inv_mpu6050/Kconfig +++ b/drivers/iio/imu/inv_mpu6050/Kconfig @@ -10,7 +10,8 @@ config INV_MPU6050_IIO config INV_MPU6050_I2C tristate "Invensense MPU6050 devices (I2C)" - depends on I2C_MUX + depends on I2C + select I2C_MUX select INV_MPU6050_IIO select REGMAP_I2C help -- cgit v1.2.3 From 757b4bcaa0d8fa74500b14b1655f6638ceafd056 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 1 Dec 2019 23:38:18 +0200 Subject: iio: imu: st_lsm6dsx: fix checkpatch warning Fix following checkpatch warning: CHECK: Alignment should match open parenthesis +static int st_lsm6dsx_read_event(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/iio/imu') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 11b2c7bc8041..a4ed72aef93e 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -1587,11 +1587,11 @@ static int st_lsm6dsx_event_setup(struct st_lsm6dsx_hw *hw, int state) } static int st_lsm6dsx_read_event(struct iio_dev *iio_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) + 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 st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); struct st_lsm6dsx_hw *hw = sensor->hw; -- cgit v1.2.3 From 07bf07e2cc7d8658de138b8a217cb0a936d26e7e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 16 Dec 2019 20:19:23 +0200 Subject: iio: st_lsm6dsx: Mark predefined constants with __maybe_unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we put static variable to a header file it's copied to each module that includes the header. But not all of them are actually used it. Mark predefined constants with __maybe_unused to calm a compiler down: In file included from drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c:17: .../st_lsm6dsx/st_lsm6dsx.h:399:28: warning: ‘st_lsm6dsx_available_scan_masks’ defined but not used [-Wunused-const-variable=] 399 | static const unsigned long st_lsm6dsx_available_scan_masks[] = {0x7, 0x0}; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .../st_lsm6dsx/st_lsm6dsx.h:392:36: warning: ‘st_lsm6dsx_event’ defined but not used [-Wunused-const-variable=] 392 | static const struct iio_event_spec st_lsm6dsx_event = { | ^~~~~~~~~~~~~~~~ ... Signed-off-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/iio/imu') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index c605b153be41..f1189eef6e37 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -391,14 +391,17 @@ struct st_lsm6dsx_hw { const struct st_lsm6dsx_settings *settings; }; -static const struct iio_event_spec st_lsm6dsx_event = { +static __maybe_unused const struct iio_event_spec st_lsm6dsx_event = { .type = IIO_EV_TYPE_THRESH, .dir = IIO_EV_DIR_EITHER, .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE) }; -static const unsigned long st_lsm6dsx_available_scan_masks[] = {0x7, 0x0}; +static __maybe_unused const unsigned long st_lsm6dsx_available_scan_masks[] = { + 0x7, 0x0, +}; + extern const struct dev_pm_ops st_lsm6dsx_pm_ops; int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, -- cgit v1.2.3 From e3da43077046d3b44da0f66b2f202e25ba9ca694 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 16 Dec 2019 20:19:24 +0200 Subject: iio: st_lsm6dsx: Drop unneeded OF code There is no need to have OF guard against ID table. Drop it for good. Signed-off-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c | 3 +-- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/iio/imu') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c index cd47ec1fedcb..0fb32131afce 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include "st_lsm6dsx.h" @@ -122,7 +121,7 @@ static struct i2c_driver st_lsm6dsx_driver = { .driver = { .name = "st_lsm6dsx_i2c", .pm = &st_lsm6dsx_pm_ops, - .of_match_table = of_match_ptr(st_lsm6dsx_i2c_of_match), + .of_match_table = st_lsm6dsx_i2c_of_match, }, .probe = st_lsm6dsx_i2c_probe, .id_table = st_lsm6dsx_i2c_id_table, diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c index 67ff36eac247..eb1086e4a951 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include "st_lsm6dsx.h" @@ -122,7 +121,7 @@ static struct spi_driver st_lsm6dsx_driver = { .driver = { .name = "st_lsm6dsx_spi", .pm = &st_lsm6dsx_pm_ops, - .of_match_table = of_match_ptr(st_lsm6dsx_spi_of_match), + .of_match_table = st_lsm6dsx_spi_of_match, }, .probe = st_lsm6dsx_spi_probe, .id_table = st_lsm6dsx_spi_id_table, -- cgit v1.2.3 From 03d4c566c51def8151dee1e87dae6479722890d2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 16 Dec 2019 20:19:25 +0200 Subject: iio: st_lsm6dsx: Make use of device properties Device property API allows to gather device resources from different sources, such as ACPI. Convert the drivers to unleash the power of device property API. Signed-off-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/iio/imu') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index a4ed72aef93e..95d7eb1d9cdb 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -1804,14 +1805,14 @@ static const struct iio_info st_lsm6dsx_gyro_info = { .hwfifo_set_watermark = st_lsm6dsx_set_watermark, }; -static int st_lsm6dsx_of_get_drdy_pin(struct st_lsm6dsx_hw *hw, int *drdy_pin) +static int st_lsm6dsx_get_drdy_pin(struct st_lsm6dsx_hw *hw, int *drdy_pin) { - struct device_node *np = hw->dev->of_node; + struct device *dev = hw->dev; - if (!np) + if (!dev_fwnode(dev)) return -EINVAL; - return of_property_read_u32(np, "st,drdy-int-pin", drdy_pin); + return device_property_read_u32(dev, "st,drdy-int-pin", drdy_pin); } static int @@ -1820,7 +1821,7 @@ st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, { int err = 0, drdy_pin; - if (st_lsm6dsx_of_get_drdy_pin(hw, &drdy_pin) < 0) { + if (st_lsm6dsx_get_drdy_pin(hw, &drdy_pin) < 0) { struct st_sensors_platform_data *pdata; struct device *dev = hw->dev; @@ -1849,15 +1850,15 @@ st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, static int st_lsm6dsx_init_shub(struct st_lsm6dsx_hw *hw) { const struct st_lsm6dsx_shub_settings *hub_settings; - struct device_node *np = hw->dev->of_node; struct st_sensors_platform_data *pdata; + struct device *dev = hw->dev; unsigned int data; int err = 0; hub_settings = &hw->settings->shub_settings; - pdata = (struct st_sensors_platform_data *)hw->dev->platform_data; - if ((np && of_property_read_bool(np, "st,pullups")) || + pdata = (struct st_sensors_platform_data *)dev->platform_data; + if ((dev_fwnode(dev) && device_property_read_bool(dev, "st,pullups")) || (pdata && pdata->pullups)) { err = st_lsm6dsx_set_page(hw, true); if (err < 0) @@ -2135,9 +2136,9 @@ static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private) static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw) { - struct device_node *np = hw->dev->of_node; struct st_sensors_platform_data *pdata; const struct st_lsm6dsx_reg *reg; + struct device *dev = hw->dev; unsigned long irq_type; bool irq_active_low; int err; @@ -2165,8 +2166,8 @@ static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw) if (err < 0) return err; - pdata = (struct st_sensors_platform_data *)hw->dev->platform_data; - if ((np && of_property_read_bool(np, "drive-open-drain")) || + pdata = (struct st_sensors_platform_data *)dev->platform_data; + if ((dev_fwnode(dev) && device_property_read_bool(dev, "drive-open-drain")) || (pdata && pdata->open_drain)) { reg = &hw->settings->irq_config.od; err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, @@ -2196,7 +2197,6 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, { struct st_sensors_platform_data *pdata = dev->platform_data; const struct st_lsm6dsx_shub_settings *hub_settings; - struct device_node *np = dev->of_node; struct st_lsm6dsx_hw *hw; const char *name = NULL; int i, err; @@ -2259,7 +2259,7 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, return err; } - if ((np && of_property_read_bool(np, "wakeup-source")) || + if ((dev_fwnode(dev) && device_property_read_bool(dev, "wakeup-source")) || (pdata && pdata->wakeup_source)) device_init_wakeup(dev, true); -- cgit v1.2.3 From ee978bb86d055131364baa617fbdb0a9bb52612a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 14 Dec 2019 17:52:54 +0100 Subject: iio: imu: st_lsm6dsx: export max num of slave devices in st_lsm6dsx_shub_settings Export max number of slave devices supported by the i2c master controller in st_lsm6dsx_shub_settings data structure. This is a preliminary patch to support i2c master controller on lsm6dsm sensors Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 2 ++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 2 ++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c | 3 +-- 3 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/iio/imu') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index f1189eef6e37..140e4c6971f3 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -176,6 +176,7 @@ struct st_lsm6dsx_hw_ts_settings { * @pullup_en: i2c controller pull-up register info (addr + mask). * @aux_sens: aux sensor register info (addr + mask). * @wr_once: write_once register info (addr + mask). + * @num_ext_dev: max number of slave devices. * @shub_out: sensor hub first output register info. * @slv0_addr: slave0 address in secondary page. * @dw_slv0_addr: slave0 write register address in secondary page. @@ -187,6 +188,7 @@ struct st_lsm6dsx_shub_settings { struct st_lsm6dsx_reg pullup_en; struct st_lsm6dsx_reg aux_sens; struct st_lsm6dsx_reg wr_once; + u8 num_ext_dev; u8 shub_out; u8 slv0_addr; u8 dw_slv0_addr; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 95d7eb1d9cdb..91dc9796add7 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -883,6 +883,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x14, .mask = BIT(6), }, + .num_ext_dev = 3, .shub_out = 0x02, .slv0_addr = 0x15, .dw_slv0_addr = 0x21, @@ -1257,6 +1258,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x14, .mask = BIT(6), }, + .num_ext_dev = 3, .shub_out = 0x02, .slv0_addr = 0x15, .dw_slv0_addr = 0x21, diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c index fa5d1001a46c..5684e663d0aa 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c @@ -30,7 +30,6 @@ #include "st_lsm6dsx.h" -#define ST_LSM6DSX_MAX_SLV_NUM 3 #define ST_LSM6DSX_SLV_ADDR(n, base) ((base) + (n) * 3) #define ST_LSM6DSX_SLV_SUB_ADDR(n, base) ((base) + 1 + (n) * 3) #define ST_LSM6DSX_SLV_CONFIG(n, base) ((base) + 2 + (n) * 3) @@ -770,7 +769,7 @@ int st_lsm6dsx_shub_probe(struct st_lsm6dsx_hw *hw, const char *name) if (err < 0) return err; - if (++num_ext_dev >= ST_LSM6DSX_MAX_SLV_NUM) + if (++num_ext_dev >= hw->settings->shub_settings.num_ext_dev) break; id++; } -- cgit v1.2.3 From 007f2ebbac2ac7f0f6d80ca5afd3f51c5a083838 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 14 Dec 2019 17:52:55 +0100 Subject: iio: imu: st_lsm6dsx: check if master_enable is located in primary page Check if the master enable register is located in the primary or in the secondary memory page. This is a preliminary patch to support i2c master controller on lsm6dsm devices Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 6 +++++- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 2 ++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c | 11 +++++++---- 3 files changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers/iio/imu') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 140e4c6971f3..bd1c77d16147 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -184,7 +184,11 @@ struct st_lsm6dsx_hw_ts_settings { */ struct st_lsm6dsx_shub_settings { struct st_lsm6dsx_reg page_mux; - struct st_lsm6dsx_reg master_en; + struct { + bool sec_page; + u8 addr; + u8 mask; + } master_en; struct st_lsm6dsx_reg pullup_en; struct st_lsm6dsx_reg aux_sens; struct st_lsm6dsx_reg wr_once; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 91dc9796add7..b8cfea977968 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -868,6 +868,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = BIT(6), }, .master_en = { + .sec_page = true, .addr = 0x14, .mask = BIT(2), }, @@ -1243,6 +1244,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = BIT(6), }, .master_en = { + .sec_page = true, .addr = 0x14, .mask = BIT(2), }, diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c index 5684e663d0aa..767482e61a1e 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c @@ -185,15 +185,18 @@ static int st_lsm6dsx_shub_master_enable(struct st_lsm6dsx_sensor *sensor, mutex_lock(&hw->page_lock); hub_settings = &hw->settings->shub_settings; - err = st_lsm6dsx_set_page(hw, true); - if (err < 0) - goto out; + if (hub_settings->master_en.sec_page) { + err = st_lsm6dsx_set_page(hw, true); + if (err < 0) + goto out; + } data = ST_LSM6DSX_SHIFT_VAL(enable, hub_settings->master_en.mask); err = regmap_update_bits(hw->regmap, hub_settings->master_en.addr, hub_settings->master_en.mask, data); - st_lsm6dsx_set_page(hw, false); + if (hub_settings->master_en.sec_page) + st_lsm6dsx_set_page(hw, false); out: mutex_unlock(&hw->page_lock); -- cgit v1.2.3 From 3a4319574584ef5a71e11780cc83337282818882 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 14 Dec 2019 17:52:56 +0100 Subject: iio: imu: st_lsm6dsx: check if pull_up is located in primary page Check if the pull up register is located in the primary or in the secondary memory page. This is a preliminary patch to support i2c master controller on lsm6dsm devices Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 6 +++++- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 13 +++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers/iio/imu') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index bd1c77d16147..4974f6fafd53 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -189,7 +189,11 @@ struct st_lsm6dsx_shub_settings { u8 addr; u8 mask; } master_en; - struct st_lsm6dsx_reg pullup_en; + struct { + bool sec_page; + u8 addr; + u8 mask; + } pullup_en; struct st_lsm6dsx_reg aux_sens; struct st_lsm6dsx_reg wr_once; u8 num_ext_dev; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index b8cfea977968..b5e9f71be085 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -873,6 +873,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = BIT(2), }, .pullup_en = { + .sec_page = true, .addr = 0x14, .mask = BIT(3), }, @@ -1249,6 +1250,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = BIT(2), }, .pullup_en = { + .sec_page = true, .addr = 0x14, .mask = BIT(3), }, @@ -1864,16 +1866,19 @@ static int st_lsm6dsx_init_shub(struct st_lsm6dsx_hw *hw) pdata = (struct st_sensors_platform_data *)dev->platform_data; if ((dev_fwnode(dev) && device_property_read_bool(dev, "st,pullups")) || (pdata && pdata->pullups)) { - err = st_lsm6dsx_set_page(hw, true); - if (err < 0) - return err; + if (hub_settings->pullup_en.sec_page) { + err = st_lsm6dsx_set_page(hw, true); + if (err < 0) + return err; + } data = ST_LSM6DSX_SHIFT_VAL(1, hub_settings->pullup_en.mask); err = regmap_update_bits(hw->regmap, hub_settings->pullup_en.addr, hub_settings->pullup_en.mask, data); - st_lsm6dsx_set_page(hw, false); + if (hub_settings->pullup_en.sec_page) + st_lsm6dsx_set_page(hw, false); if (err < 0) return err; -- cgit v1.2.3 From 5b8343e067f8c0ce6e480659956d011e876d3635 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 14 Dec 2019 17:52:57 +0100 Subject: iio: imu: st_lsm6dsx: check if shub_output reg is located in primary page Check if the sensor hub output register is located in the primary or in the secondary memory page. This is a preliminary patch to support i2c master controller on lsm6dsm devices Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 5 ++++- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 10 ++++++++-- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c | 28 ++++++++++++++++------------ 3 files changed, 28 insertions(+), 15 deletions(-) (limited to 'drivers/iio/imu') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 4974f6fafd53..001179e19ba7 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -197,7 +197,10 @@ struct st_lsm6dsx_shub_settings { struct st_lsm6dsx_reg aux_sens; struct st_lsm6dsx_reg wr_once; u8 num_ext_dev; - u8 shub_out; + struct { + bool sec_page; + u8 addr; + } shub_out; u8 slv0_addr; u8 dw_slv0_addr; u8 batch_en; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index b5e9f71be085..49ad70c589bd 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -886,7 +886,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = BIT(6), }, .num_ext_dev = 3, - .shub_out = 0x02, + .shub_out = { + .sec_page = true, + .addr = 0x02, + }, .slv0_addr = 0x15, .dw_slv0_addr = 0x21, .batch_en = BIT(3), @@ -1263,7 +1266,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = BIT(6), }, .num_ext_dev = 3, - .shub_out = 0x02, + .shub_out = { + .sec_page = true, + .addr = 0x02, + }, .slv0_addr = 0x15, .dw_slv0_addr = 0x21, .batch_en = BIT(3), diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c index 767482e61a1e..ccc59682cb66 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c @@ -105,20 +105,27 @@ static void st_lsm6dsx_shub_wait_complete(struct st_lsm6dsx_hw *hw) * * Read st_lsm6dsx i2c controller register */ -static int st_lsm6dsx_shub_read_reg(struct st_lsm6dsx_hw *hw, u8 addr, - u8 *data, int len) +static int +st_lsm6dsx_shub_read_reg(struct st_lsm6dsx_hw *hw, u8 *data, + int len) { + const struct st_lsm6dsx_shub_settings *hub_settings; int err; mutex_lock(&hw->page_lock); - err = st_lsm6dsx_set_page(hw, true); - if (err < 0) - goto out; + hub_settings = &hw->settings->shub_settings; + if (hub_settings->shub_out.sec_page) { + err = st_lsm6dsx_set_page(hw, true); + if (err < 0) + goto out; + } - err = regmap_bulk_read(hw->regmap, addr, data, len); + err = regmap_bulk_read(hw->regmap, hub_settings->shub_out.addr, + data, len); - st_lsm6dsx_set_page(hw, false); + if (hub_settings->shub_out.sec_page) + st_lsm6dsx_set_page(hw, false); out: mutex_unlock(&hw->page_lock); @@ -236,8 +243,7 @@ st_lsm6dsx_shub_read(struct st_lsm6dsx_sensor *sensor, u8 addr, st_lsm6dsx_shub_wait_complete(hw); - err = st_lsm6dsx_shub_read_reg(hw, hub_settings->shub_out, data, - len & ST_LS6DSX_READ_OP_MASK); + err = st_lsm6dsx_shub_read_reg(hw, data, len & ST_LS6DSX_READ_OP_MASK); st_lsm6dsx_shub_master_enable(sensor, false); @@ -719,9 +725,7 @@ st_lsm6dsx_shub_check_wai(struct st_lsm6dsx_hw *hw, u8 *i2c_addr, st_lsm6dsx_shub_wait_complete(hw); - err = st_lsm6dsx_shub_read_reg(hw, - hub_settings->shub_out, - &data, sizeof(data)); + err = st_lsm6dsx_shub_read_reg(hw, &data, sizeof(data)); st_lsm6dsx_shub_master_enable(sensor, false); -- cgit v1.2.3 From 111b0875774b9622161e2ed6dd176e21c8665da0 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 14 Dec 2019 17:52:58 +0100 Subject: iio: imu: st_lsm6dsx: rename st_lsm6dsx_shub_read_reg in st_lsm6dsx_shub_read_output Rename st_lsm6dsx_shub_read_reg routine in st_lsm6dsx_shub_read_output since it is used to read from sensorhub channel0 output register Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/iio/imu') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c index ccc59682cb66..dc739dfb36f2 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c @@ -101,13 +101,13 @@ static void st_lsm6dsx_shub_wait_complete(struct st_lsm6dsx_hw *hw) } /** - * st_lsm6dsx_shub_read_reg - read i2c controller register + * st_lsm6dsx_shub_read_output - read i2c controller register * * Read st_lsm6dsx i2c controller register */ static int -st_lsm6dsx_shub_read_reg(struct st_lsm6dsx_hw *hw, u8 *data, - int len) +st_lsm6dsx_shub_read_output(struct st_lsm6dsx_hw *hw, u8 *data, + int len) { const struct st_lsm6dsx_shub_settings *hub_settings; int err; @@ -243,7 +243,8 @@ st_lsm6dsx_shub_read(struct st_lsm6dsx_sensor *sensor, u8 addr, st_lsm6dsx_shub_wait_complete(hw); - err = st_lsm6dsx_shub_read_reg(hw, data, len & ST_LS6DSX_READ_OP_MASK); + err = st_lsm6dsx_shub_read_output(hw, data, + len & ST_LS6DSX_READ_OP_MASK); st_lsm6dsx_shub_master_enable(sensor, false); @@ -725,7 +726,7 @@ st_lsm6dsx_shub_check_wai(struct st_lsm6dsx_hw *hw, u8 *i2c_addr, st_lsm6dsx_shub_wait_complete(hw); - err = st_lsm6dsx_shub_read_reg(hw, &data, sizeof(data)); + err = st_lsm6dsx_shub_read_output(hw, &data, sizeof(data)); st_lsm6dsx_shub_master_enable(sensor, false); -- cgit v1.2.3 From e485e2a2cfd6404d21066be6378ed42f8ce81060 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 14 Dec 2019 17:52:59 +0100 Subject: iio: imu: st_lsm6dsx: enable sensor-hub support for lsm6dsm Enabled i2c master controller support for LSM6DSM sensor. Enable ext_sensor0 for lsm6dsm. This series has been tested using LIS2MDL as slave device connected to the i2c controller of the LSM6DSM Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 4 +++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c | 27 +++++++++++---- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 47 ++++++++++++++++++++++++++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c | 31 ++++++++++++----- 4 files changed, 94 insertions(+), 15 deletions(-) (limited to 'drivers/iio/imu') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 001179e19ba7..a763ff46f596 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -176,11 +176,13 @@ struct st_lsm6dsx_hw_ts_settings { * @pullup_en: i2c controller pull-up register info (addr + mask). * @aux_sens: aux sensor register info (addr + mask). * @wr_once: write_once register info (addr + mask). + * @emb_func: embedded function register info (addr + mask). * @num_ext_dev: max number of slave devices. * @shub_out: sensor hub first output register info. * @slv0_addr: slave0 address in secondary page. * @dw_slv0_addr: slave0 write register address in secondary page. * @batch_en: Enable/disable FIFO batching. + * @pause: controller pause value. */ struct st_lsm6dsx_shub_settings { struct st_lsm6dsx_reg page_mux; @@ -196,6 +198,7 @@ struct st_lsm6dsx_shub_settings { } pullup_en; struct st_lsm6dsx_reg aux_sens; struct st_lsm6dsx_reg wr_once; + struct st_lsm6dsx_reg emb_func; u8 num_ext_dev; struct { bool sec_page; @@ -204,6 +207,7 @@ struct st_lsm6dsx_shub_settings { u8 slv0_addr; u8 dw_slv0_addr; u8 batch_en; + u8 pause; }; struct st_lsm6dsx_event_settings { diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index d416990ae309..cc2b19b60d61 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -332,12 +332,13 @@ static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 addr, */ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) { + struct st_lsm6dsx_sensor *acc_sensor, *gyro_sensor, *ext_sensor = NULL; + int err, acc_sip, gyro_sip, ts_sip, ext_sip, read_len, offset; u16 fifo_len, pattern_len = hw->sip * ST_LSM6DSX_SAMPLE_SIZE; u16 fifo_diff_mask = hw->settings->fifo_ops.fifo_diff.mask; - int err, acc_sip, gyro_sip, ts_sip, read_len, offset; - struct st_lsm6dsx_sensor *acc_sensor, *gyro_sensor; u8 gyro_buff[ST_LSM6DSX_IIO_BUFF_SIZE]; u8 acc_buff[ST_LSM6DSX_IIO_BUFF_SIZE]; + u8 ext_buff[ST_LSM6DSX_IIO_BUFF_SIZE]; bool reset_ts = false; __le16 fifo_status; s64 ts = 0; @@ -360,6 +361,8 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) acc_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]); gyro_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_GYRO]); + if (hw->iio_devs[ST_LSM6DSX_ID_EXT0]) + ext_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_EXT0]); for (read_len = 0; read_len < fifo_len; read_len += pattern_len) { err = st_lsm6dsx_read_block(hw, ST_LSM6DSX_REG_FIFO_OUTL_ADDR, @@ -387,12 +390,13 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) * following pattern is repeated every 9 samples: * - Gx, Gy, Gz, Ax, Ay, Az, Ts, Gx, Gy, Gz, Ts, Gx, .. */ + ext_sip = ext_sensor ? ext_sensor->sip : 0; gyro_sip = gyro_sensor->sip; acc_sip = acc_sensor->sip; ts_sip = hw->ts_sip; offset = 0; - while (acc_sip > 0 || gyro_sip > 0) { + while (acc_sip > 0 || gyro_sip > 0 || ext_sip > 0) { if (gyro_sip > 0) { memcpy(gyro_buff, &hw->buff[offset], ST_LSM6DSX_SAMPLE_SIZE); @@ -403,6 +407,11 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) ST_LSM6DSX_SAMPLE_SIZE); offset += ST_LSM6DSX_SAMPLE_SIZE; } + if (ext_sip > 0) { + memcpy(ext_buff, &hw->buff[offset], + ST_LSM6DSX_SAMPLE_SIZE); + offset += ST_LSM6DSX_SAMPLE_SIZE; + } if (ts_sip-- > 0) { u8 data[ST_LSM6DSX_SAMPLE_SIZE]; @@ -436,6 +445,10 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) iio_push_to_buffers_with_timestamp( hw->iio_devs[ST_LSM6DSX_ID_ACC], acc_buff, acc_sensor->ts_ref + ts); + if (ext_sip-- > 0) + iio_push_to_buffers_with_timestamp( + hw->iio_devs[ST_LSM6DSX_ID_EXT0], + ext_buff, ext_sensor->ts_ref + ts); } } @@ -628,12 +641,12 @@ int st_lsm6dsx_update_fifo(struct st_lsm6dsx_sensor *sensor, bool enable) err = st_lsm6dsx_sensor_set_enable(sensor, enable); if (err < 0) goto out; - - err = st_lsm6dsx_set_fifo_odr(sensor, enable); - if (err < 0) - goto out; } + err = st_lsm6dsx_set_fifo_odr(sensor, enable); + if (err < 0) + goto out; + err = st_lsm6dsx_update_decimators(hw); if (err < 0) goto out; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 49ad70c589bd..0c64e35c7599 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -656,6 +656,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x08, .mask = GENMASK(5, 3), }, + [ST_LSM6DSX_ID_EXT0] = { + .addr = 0x09, + .mask = GENMASK(2, 0), + }, }, .fifo_ops = { .update_fifo = st_lsm6dsx_update_fifo, @@ -688,6 +692,39 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = GENMASK(5, 3), }, }, + .shub_settings = { + .page_mux = { + .addr = 0x01, + .mask = BIT(7), + }, + .master_en = { + .addr = 0x1a, + .mask = BIT(0), + }, + .pullup_en = { + .addr = 0x1a, + .mask = BIT(3), + }, + .aux_sens = { + .addr = 0x04, + .mask = GENMASK(5, 4), + }, + .wr_once = { + .addr = 0x07, + .mask = BIT(5), + }, + .emb_func = { + .addr = 0x19, + .mask = BIT(2), + }, + .num_ext_dev = 1, + .shub_out = { + .addr = 0x2e, + }, + .slv0_addr = 0x02, + .dw_slv0_addr = 0x0e, + .pause = 0x7, + }, .event_settings = { .enable_reg = { .addr = 0x58, @@ -1902,6 +1939,16 @@ static int st_lsm6dsx_init_shub(struct st_lsm6dsx_hw *hw) hub_settings->aux_sens.mask, data); st_lsm6dsx_set_page(hw, false); + + if (err < 0) + return err; + } + + if (hub_settings->emb_func.addr) { + data = ST_LSM6DSX_SHIFT_VAL(1, hub_settings->emb_func.mask); + err = regmap_update_bits(hw->regmap, + hub_settings->emb_func.addr, + hub_settings->emb_func.mask, data); } return err; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c index dc739dfb36f2..eea555617d4a 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c @@ -221,16 +221,21 @@ st_lsm6dsx_shub_read(struct st_lsm6dsx_sensor *sensor, u8 addr, u8 *data, int len) { const struct st_lsm6dsx_shub_settings *hub_settings; + u8 config[3], slv_addr, slv_config = 0; struct st_lsm6dsx_hw *hw = sensor->hw; - u8 config[3], slv_addr; + const struct st_lsm6dsx_reg *aux_sens; int err; hub_settings = &hw->settings->shub_settings; slv_addr = ST_LSM6DSX_SLV_ADDR(0, hub_settings->slv0_addr); + aux_sens = &hw->settings->shub_settings.aux_sens; + /* do not overwrite aux_sens */ + if (slv_addr + 2 == aux_sens->addr) + slv_config = ST_LSM6DSX_SHIFT_VAL(3, aux_sens->mask); config[0] = (sensor->ext_info.addr << 1) | 1; config[1] = addr; - config[2] = len & ST_LS6DSX_READ_OP_MASK; + config[2] = (len & ST_LS6DSX_READ_OP_MASK) | slv_config; err = st_lsm6dsx_shub_write_reg(hw, slv_addr, config, sizeof(config)); @@ -248,7 +253,9 @@ st_lsm6dsx_shub_read(struct st_lsm6dsx_sensor *sensor, u8 addr, st_lsm6dsx_shub_master_enable(sensor, false); - memset(config, 0, sizeof(config)); + config[0] = hub_settings->pause; + config[1] = 0; + config[2] = slv_config; return st_lsm6dsx_shub_write_reg(hw, slv_addr, config, sizeof(config)); } @@ -305,7 +312,8 @@ st_lsm6dsx_shub_write(struct st_lsm6dsx_sensor *sensor, u8 addr, st_lsm6dsx_shub_master_enable(sensor, false); } - memset(config, 0, sizeof(config)); + config[0] = hub_settings->pause; + config[1] = 0; return st_lsm6dsx_shub_write_reg(hw, slv_addr, config, sizeof(config)); } @@ -697,14 +705,19 @@ st_lsm6dsx_shub_check_wai(struct st_lsm6dsx_hw *hw, u8 *i2c_addr, const struct st_lsm6dsx_ext_dev_settings *settings) { const struct st_lsm6dsx_shub_settings *hub_settings; + u8 config[3], data, slv_addr, slv_config = 0; + const struct st_lsm6dsx_reg *aux_sens; struct st_lsm6dsx_sensor *sensor; - u8 config[3], data, slv_addr; bool found = false; int i, err; + sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]); hub_settings = &hw->settings->shub_settings; + aux_sens = &hw->settings->shub_settings.aux_sens; slv_addr = ST_LSM6DSX_SLV_ADDR(0, hub_settings->slv0_addr); - sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]); + /* do not overwrite aux_sens */ + if (slv_addr + 2 == aux_sens->addr) + slv_config = ST_LSM6DSX_SHIFT_VAL(3, aux_sens->mask); for (i = 0; i < ARRAY_SIZE(settings->i2c_addr); i++) { if (!settings->i2c_addr[i]) @@ -713,7 +726,7 @@ st_lsm6dsx_shub_check_wai(struct st_lsm6dsx_hw *hw, u8 *i2c_addr, /* read wai slave register */ config[0] = (settings->i2c_addr[i] << 1) | 0x1; config[1] = settings->wai.addr; - config[2] = 0x1; + config[2] = 0x1 | slv_config; err = st_lsm6dsx_shub_write_reg(hw, slv_addr, config, sizeof(config)); @@ -742,7 +755,9 @@ st_lsm6dsx_shub_check_wai(struct st_lsm6dsx_hw *hw, u8 *i2c_addr, } /* reset SLV0 channel */ - memset(config, 0, sizeof(config)); + config[0] = hub_settings->pause; + config[1] = 0; + config[2] = slv_config; err = st_lsm6dsx_shub_write_reg(hw, slv_addr, config, sizeof(config)); if (err < 0) -- cgit v1.2.3