From 3cdea6e9a838dd04afad146cf9e558fa4ef9f9cb Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 10 Apr 2021 18:47:28 +0200 Subject: iio: adc: exynos: drop unneeded variable assignment The initialization of 'ret' variable in probe function is shortly after overwritten. This initialization is simply not used. Addresses-Coverity: Unused value Signed-off-by: Krzysztof Kozlowski Reviewed-by: Alim Akhtar Link: https://lore.kernel.org/r/20210410164728.8096-1-krzysztof.kozlowski@canonical.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/exynos_adc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index 8c98d8c9ab1f..3b3868aa2533 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -794,7 +794,7 @@ static int exynos_adc_probe(struct platform_device *pdev) struct s3c2410_ts_mach_info *pdata = dev_get_platdata(&pdev->dev); struct iio_dev *indio_dev = NULL; bool has_ts = false; - int ret = -ENODEV; + int ret; int irq; indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct exynos_adc)); -- cgit v1.2.3 From df041e737a38a316976273281f66fbce2ec4b397 Mon Sep 17 00:00:00 2001 From: Puranjay Mohan Date: Wed, 7 Apr 2021 23:51:47 +0530 Subject: iio: temperature: add driver support for ti tmp117 TMP117 is a Digital temperature sensor with integrated Non-Volatile memory. Add support for tmp117 driver in iio subsystem. Datasheet: https://www.ti.com/lit/gpn/tmp117 Signed-off-by: Puranjay Mohan Reviewed-by: Andy Shevchenko Reviewed-by: Lars-Peter Clausen Link: https://lore.kernel.org/r/20210407182147.77221-3-puranjay12@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/Kconfig | 10 +++ drivers/iio/temperature/Makefile | 1 + drivers/iio/temperature/tmp117.c | 185 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+) create mode 100644 drivers/iio/temperature/tmp117.c (limited to 'drivers/iio') diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig index 4df60082c1fa..f20ae3c963cb 100644 --- a/drivers/iio/temperature/Kconfig +++ b/drivers/iio/temperature/Kconfig @@ -96,6 +96,16 @@ config TMP007 This driver can also be built as a module. If so, the module will be called tmp007. +config TMP117 + tristate "TMP117 Digital temperature sensor with integrated NV memory" + depends on I2C + help + If you say yes here you get support for the Texas Instruments + TMP117 Digital temperature sensor with integrated NV memory. + + This driver can also be built as a module. If so, the module will + be called tmp117. + config TSYS01 tristate "Measurement Specialties TSYS01 temperature sensor using I2C bus connection" depends on I2C diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile index 90c113115422..e3392c4b29b4 100644 --- a/drivers/iio/temperature/Makefile +++ b/drivers/iio/temperature/Makefile @@ -12,5 +12,6 @@ obj-$(CONFIG_MLX90614) += mlx90614.o obj-$(CONFIG_MLX90632) += mlx90632.o obj-$(CONFIG_TMP006) += tmp006.o obj-$(CONFIG_TMP007) += tmp007.o +obj-$(CONFIG_TMP117) += tmp117.o obj-$(CONFIG_TSYS01) += tsys01.o obj-$(CONFIG_TSYS02D) += tsys02d.o diff --git a/drivers/iio/temperature/tmp117.c b/drivers/iio/temperature/tmp117.c new file mode 100644 index 000000000000..f9b8f2b570f6 --- /dev/null +++ b/drivers/iio/temperature/tmp117.c @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital temperature sensor with integrated Non-volatile memory + * Copyright (c) 2021 Puranjay Mohan + * + * Driver for the Texas Instruments TMP117 Temperature Sensor + * (7-bit I2C slave address (0x48 - 0x4B), changeable via ADD pins) + * + * Note: This driver assumes that the sensor has been calibrated beforehand. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define TMP117_REG_TEMP 0x0 +#define TMP117_REG_CFGR 0x1 +#define TMP117_REG_HIGH_LIM 0x2 +#define TMP117_REG_LOW_LIM 0x3 +#define TMP117_REG_EEPROM_UL 0x4 +#define TMP117_REG_EEPROM1 0x5 +#define TMP117_REG_EEPROM2 0x6 +#define TMP117_REG_TEMP_OFFSET 0x7 +#define TMP117_REG_EEPROM3 0x8 +#define TMP117_REG_DEVICE_ID 0xF + +#define TMP117_RESOLUTION_10UC 78125 +#define TMP117_DEVICE_ID 0x0117 +#define MICRODEGREE_PER_10MILLIDEGREE 10000 + +struct tmp117_data { + struct i2c_client *client; + s16 calibbias; +}; + +static int tmp117_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, int *val, + int *val2, long mask) +{ + struct tmp117_data *data = iio_priv(indio_dev); + s32 ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = i2c_smbus_read_word_swapped(data->client, + TMP117_REG_TEMP); + if (ret < 0) + return ret; + *val = sign_extend32(ret, 15); + return IIO_VAL_INT; + + case IIO_CHAN_INFO_CALIBBIAS: + ret = i2c_smbus_read_word_swapped(data->client, + TMP117_REG_TEMP_OFFSET); + if (ret < 0) + return ret; + *val = sign_extend32(ret, 15); + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + /* + * Conversion from 10s of uC to mC + * as IIO reports temperature in mC + */ + *val = TMP117_RESOLUTION_10UC / MICRODEGREE_PER_10MILLIDEGREE; + *val2 = (TMP117_RESOLUTION_10UC % + MICRODEGREE_PER_10MILLIDEGREE) * 100; + + return IIO_VAL_INT_PLUS_MICRO; + + default: + return -EINVAL; + } +} + +static int tmp117_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, int val, + int val2, long mask) +{ + struct tmp117_data *data = iio_priv(indio_dev); + s16 off; + + switch (mask) { + case IIO_CHAN_INFO_CALIBBIAS: + off = clamp_t(int, val, S16_MIN, S16_MAX); + if (off == data->calibbias) + return 0; + data->calibbias = off; + return i2c_smbus_write_word_swapped(data->client, + TMP117_REG_TEMP_OFFSET, off); + + default: + return -EINVAL; + } +} + +static const struct iio_chan_spec tmp117_channels[] = { + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_SCALE), + }, +}; + +static const struct iio_info tmp117_info = { + .read_raw = tmp117_read_raw, + .write_raw = tmp117_write_raw, +}; + +static int tmp117_identify(struct i2c_client *client) +{ + int dev_id; + + dev_id = i2c_smbus_read_word_swapped(client, TMP117_REG_DEVICE_ID); + if (dev_id < 0) + return dev_id; + if (dev_id != TMP117_DEVICE_ID) { + dev_err(&client->dev, "TMP117 not found\n"); + return -ENODEV; + } + return 0; +} + +static int tmp117_probe(struct i2c_client *client) +{ + struct tmp117_data *data; + struct iio_dev *indio_dev; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) + return -EOPNOTSUPP; + + ret = tmp117_identify(client); + if (ret < 0) + return ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->client = client; + data->calibbias = 0; + + indio_dev->name = "tmp117"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &tmp117_info; + + indio_dev->channels = tmp117_channels; + indio_dev->num_channels = ARRAY_SIZE(tmp117_channels); + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static const struct of_device_id tmp117_of_match[] = { + { .compatible = "ti,tmp117", }, + { } +}; +MODULE_DEVICE_TABLE(of, tmp117_of_match); + +static const struct i2c_device_id tmp117_id[] = { + { "tmp117", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tmp117_id); + +static struct i2c_driver tmp117_driver = { + .driver = { + .name = "tmp117", + .of_match_table = tmp117_of_match, + }, + .probe_new = tmp117_probe, + .id_table = tmp117_id, +}; +module_i2c_driver(tmp117_driver); + +MODULE_AUTHOR("Puranjay Mohan "); +MODULE_DESCRIPTION("TI TMP117 Temperature sensor driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 643adb9af72e2af62a532590fad0c767045c1e76 Mon Sep 17 00:00:00 2001 From: Tian Tao Date: Mon, 12 Apr 2021 16:39:09 +0800 Subject: iio:chemical:sps30: Convert sysfs sprintf/snprintf family to sysfs_emit Fix the following coccicheck warning: ./drivers/iio/chemical/sps30.c:414:8-16: WARNING: use scnprintf or sprintf Signed-off-by: Tian Tao Link: https://lore.kernel.org/r/1618216751-1678-2-git-send-email-tiantao6@hisilicon.com Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/sps30.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/chemical/sps30.c b/drivers/iio/chemical/sps30.c index 2ea9a5c4d846..7486591588c3 100644 --- a/drivers/iio/chemical/sps30.c +++ b/drivers/iio/chemical/sps30.c @@ -411,9 +411,9 @@ static ssize_t cleaning_period_available_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "[%d %d %d]\n", - SPS30_AUTO_CLEANING_PERIOD_MIN, 1, - SPS30_AUTO_CLEANING_PERIOD_MAX); + return sysfs_emit(buf, "[%d %d %d]\n", + SPS30_AUTO_CLEANING_PERIOD_MIN, 1, + SPS30_AUTO_CLEANING_PERIOD_MAX); } static IIO_DEVICE_ATTR_WO(start_cleaning, 0); -- cgit v1.2.3 From c79859bd77debda56fcce011d161c563c4a06451 Mon Sep 17 00:00:00 2001 From: Tian Tao Date: Mon, 12 Apr 2021 16:39:10 +0800 Subject: iio: light: Convert sysfs sprintf/snprintf family to sysfs_emit Fix the following coccicheck warning: drivers/iio/light/veml6030.c:131:8-16: WARNING: use scnprintf or sprintf Signed-off-by: Tian Tao Link: https://lore.kernel.org/r/1618216751-1678-3-git-send-email-tiantao6@hisilicon.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/veml6030.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/light/veml6030.c b/drivers/iio/light/veml6030.c index de85c9b30be1..3c937c55a10d 100644 --- a/drivers/iio/light/veml6030.c +++ b/drivers/iio/light/veml6030.c @@ -128,7 +128,7 @@ static ssize_t in_illuminance_period_available_show(struct device *dev, return -EINVAL; } - return snprintf(buf, PAGE_SIZE, "%s\n", period_values[x]); + return sysfs_emit(buf, "%s\n", period_values[x]); } static IIO_DEVICE_ATTR_RO(in_illuminance_period_available, 0); -- cgit v1.2.3 From 8bad6050654b46ac7ea40c5c5f9ec79396b175a3 Mon Sep 17 00:00:00 2001 From: Tian Tao Date: Mon, 12 Apr 2021 16:39:11 +0800 Subject: iio: trigger: stm32-timer: Convert sysfs sprintf/snprintf family to sysfs_emit Fix the following coccicheck warning: drivers/iio/trigger/stm32-timer-trigger.c:299:8-16: WARNING: use scnprintf or sprintf Signed-off-by: Tian Tao Link: https://lore.kernel.org/r/1618216751-1678-4-git-send-email-tiantao6@hisilicon.com Signed-off-by: Jonathan Cameron --- drivers/iio/trigger/stm32-timer-trigger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c index 3aa9e8bba005..33083877cd19 100644 --- a/drivers/iio/trigger/stm32-timer-trigger.c +++ b/drivers/iio/trigger/stm32-timer-trigger.c @@ -296,7 +296,7 @@ static ssize_t stm32_tt_show_master_mode(struct device *dev, else cr2 = (cr2 & TIM_CR2_MMS) >> TIM_CR2_MMS_SHIFT; - return snprintf(buf, PAGE_SIZE, "%s\n", master_mode_table[cr2]); + return sysfs_emit(buf, "%s\n", master_mode_table[cr2]); } static ssize_t stm32_tt_store_master_mode(struct device *dev, -- cgit v1.2.3 From 494186662ecf1c6e0c1d68b06b45434f298688d9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 12 Apr 2021 16:18:35 +0300 Subject: iio: adc: ad7298: Enable on Intel Galileo Gen 1 Enable ADC on Intel Galileo Gen 1 board. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210412131835.70212-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7298.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c index d2163cb62f4f..3f4e73f7d35a 100644 --- a/drivers/iio/adc/ad7298.c +++ b/drivers/iio/adc/ad7298.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -346,6 +347,12 @@ static int ad7298_probe(struct spi_device *spi) return devm_iio_device_register(&spi->dev, indio_dev); } +static const struct acpi_device_id ad7298_acpi_ids[] = { + { "INT3494", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, ad7298_acpi_ids); + static const struct spi_device_id ad7298_id[] = { {"ad7298", 0}, {} @@ -355,6 +362,7 @@ MODULE_DEVICE_TABLE(spi, ad7298_id); static struct spi_driver ad7298_driver = { .driver = { .name = "ad7298", + .acpi_match_table = ad7298_acpi_ids, }, .probe = ad7298_probe, .id_table = ad7298_id, -- cgit v1.2.3 From d877539ad8e8fdde9af69887055fec6402be1a13 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Thu, 22 Apr 2021 12:19:03 +0200 Subject: iio: adis_buffer: do not return ints in irq handlers On an IRQ handler we should not return normal error codes as 'irqreturn_t' is expected. Not necessarily stable material as the old check cannot fail, so it's a bug we can not hit. Fixes: ccd2b52f4ac69 ("staging:iio: Add common ADIS library") Reviewed-by: Alexandru Ardelean Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20210422101911.135630-2-nuno.sa@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis_buffer.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index ac354321f63a..175af154e443 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -129,9 +129,6 @@ static irqreturn_t adis_trigger_handler(int irq, void *p) struct adis *adis = iio_device_get_drvdata(indio_dev); int ret; - if (!adis->buffer) - return -ENOMEM; - if (adis->data->has_paging) { mutex_lock(&adis->state_lock); if (adis->current_page != 0) { -- cgit v1.2.3 From ab3df79782e7d8a27a58576c9b4e8c6c4879ad79 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Thu, 22 Apr 2021 12:19:04 +0200 Subject: iio: adis16400: do not return ints in irq handlers On an IRQ handler we should not return normal error codes as 'irqreturn_t' is expected. Not necessary to apply to stable as the original check cannot fail and as such the bug cannot actually occur. Fixes: 5eda3550a3cc1 ("staging:iio:adis16400: Preallocate transfer message") Reviewed-by: Alexandru Ardelean Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20210422101911.135630-3-nuno.sa@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16400.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c index 768aa493a1a6..b2f92b55b910 100644 --- a/drivers/iio/imu/adis16400.c +++ b/drivers/iio/imu/adis16400.c @@ -645,9 +645,6 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p) void *buffer; int ret; - if (!adis->buffer) - return -ENOMEM; - if (!(st->variant->flags & ADIS16400_NO_BURST) && st->adis.spi->max_speed_hz > ADIS16400_SPI_BURST) { st->adis.spi->max_speed_hz = ADIS16400_SPI_BURST; -- cgit v1.2.3 From 00f6742b5ff43b0cbf094e8e7481699f3ae9bcf7 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Thu, 22 Apr 2021 12:19:06 +0200 Subject: iio: adis_buffer: check return value on page change On the trigger handler, we might need to change the device page. Hence, we should check the return value from 'spi_write()' and act accordingly. Signed-off-by: Nuno Sa Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210422101911.135630-5-nuno.sa@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis_buffer.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index 175af154e443..0ae551a748eb 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -134,7 +134,12 @@ static irqreturn_t adis_trigger_handler(int irq, void *p) if (adis->current_page != 0) { adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID); adis->tx[1] = 0; - spi_write(adis->spi, adis->tx, 2); + ret = spi_write(adis->spi, adis->tx, 2); + if (ret) { + dev_err(&adis->spi->dev, "Failed to change device page: %d\n", ret); + mutex_unlock(&adis->state_lock); + goto irq_done; + } } } @@ -151,6 +156,7 @@ static irqreturn_t adis_trigger_handler(int irq, void *p) iio_push_to_buffers_with_timestamp(indio_dev, adis->buffer, pf->timestamp); +irq_done: iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; -- cgit v1.2.3 From 2335f0d7c790157bebf76fae963ba41bcba45fdb Mon Sep 17 00:00:00 2001 From: Joe Sandom Date: Wed, 21 Apr 2021 23:13:29 +0100 Subject: iio: light: Added AMS tsl2591 driver implementation Driver implementation for AMS/TAOS tsl2591 ambient light sensor. This driver supports configuration via device tree and sysfs. Supported channels for raw infrared light intensity, raw combined light intensity and illuminance in lux. The driver additionally supports iio events on lower and upper thresholds. This is a very-high sensitivity light-to-digital converter that transforms light intensity into a digital signal. Datasheet: https://ams.com/tsl25911#tab/documents Signed-off-by: Joe Sandom Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210421221330.17007-1-joe.g.sandom@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/Kconfig | 11 + drivers/iio/light/Makefile | 1 + drivers/iio/light/tsl2591.c | 1225 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1237 insertions(+) create mode 100644 drivers/iio/light/tsl2591.c (limited to 'drivers/iio') diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 917f9becf9c7..a62c7b4b8678 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -499,6 +499,17 @@ config TSL2583 Provides support for the TAOS tsl2580, tsl2581 and tsl2583 devices. Access ALS data via iio, sysfs. +config TSL2591 + tristate "TAOS TSL2591 ambient light sensor" + depends on I2C + help + Select Y here for support of the AMS/TAOS TSL2591 ambient light sensor, + featuring channels for combined visible + IR intensity and lux illuminance. + Access data via iio and sysfs. Supports iio_events. + + To compile this driver as a module, select M: the + module will be called tsl2591. + config TSL2772 tristate "TAOS TSL/TMD2x71 and TSL/TMD2x72 Family of light and proximity sensors" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index ea376deaca54..d10912faf964 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_ST_UVIS25_SPI) += st_uvis25_spi.o obj-$(CONFIG_TCS3414) += tcs3414.o obj-$(CONFIG_TCS3472) += tcs3472.o obj-$(CONFIG_TSL2583) += tsl2583.o +obj-$(CONFIG_TSL2591) += tsl2591.o obj-$(CONFIG_TSL2772) += tsl2772.o obj-$(CONFIG_TSL4531) += tsl4531.o obj-$(CONFIG_US5182D) += us5182d.o diff --git a/drivers/iio/light/tsl2591.c b/drivers/iio/light/tsl2591.c new file mode 100644 index 000000000000..2bdae388ff01 --- /dev/null +++ b/drivers/iio/light/tsl2591.c @@ -0,0 +1,1225 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 Joe Sandom + * + * Datasheet: https://ams.com/tsl25911#tab/documents + * + * Device driver for the TAOS TSL2591. This is a very-high sensitivity + * light-to-digital converter that transforms light intensity into a digital + * signal. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +/* ADC integration time, field value to time in ms */ +#define TSL2591_FVAL_TO_MSEC(x) (((x) + 1) * 100) +/* ADC integration time, field value to time in seconds */ +#define TSL2591_FVAL_TO_SEC(x) ((x) + 1) +/* ADC integration time, time in seconds to field value */ +#define TSL2591_SEC_TO_FVAL(x) ((x) - 1) + +/* TSL2591 register set */ +#define TSL2591_ENABLE 0x00 +#define TSL2591_CONTROL 0x01 +#define TSL2591_AILTL 0x04 +#define TSL2591_AILTH 0x05 +#define TSL2591_AIHTL 0x06 +#define TSL2591_AIHTH 0x07 +#define TSL2591_NP_AILTL 0x08 +#define TSL2591_NP_AILTH 0x09 +#define TSL2591_NP_AIHTL 0x0A +#define TSL2591_NP_AIHTH 0x0B +#define TSL2591_PERSIST 0x0C +#define TSL2591_PACKAGE_ID 0x11 +#define TSL2591_DEVICE_ID 0x12 +#define TSL2591_STATUS 0x13 +#define TSL2591_C0_DATAL 0x14 +#define TSL2591_C0_DATAH 0x15 +#define TSL2591_C1_DATAL 0x16 +#define TSL2591_C1_DATAH 0x17 + +/* TSL2591 command register definitions */ +#define TSL2591_CMD_NOP 0xA0 +#define TSL2591_CMD_SF_INTSET 0xE4 +#define TSL2591_CMD_SF_CALS_I 0xE5 +#define TSL2591_CMD_SF_CALS_NPI 0xE7 +#define TSL2591_CMD_SF_CNP_ALSI 0xEA + +/* TSL2591 enable register definitions */ +#define TSL2591_PWR_ON 0x01 +#define TSL2591_PWR_OFF 0x00 +#define TSL2591_ENABLE_ALS 0x02 +#define TSL2591_ENABLE_ALS_INT 0x10 +#define TSL2591_ENABLE_SLEEP_INT 0x40 +#define TSL2591_ENABLE_NP_INT 0x80 + +/* TSL2591 control register definitions */ +#define TSL2591_CTRL_ALS_INTEGRATION_100MS 0x00 +#define TSL2591_CTRL_ALS_INTEGRATION_200MS 0x01 +#define TSL2591_CTRL_ALS_INTEGRATION_300MS 0x02 +#define TSL2591_CTRL_ALS_INTEGRATION_400MS 0x03 +#define TSL2591_CTRL_ALS_INTEGRATION_500MS 0x04 +#define TSL2591_CTRL_ALS_INTEGRATION_600MS 0x05 +#define TSL2591_CTRL_ALS_LOW_GAIN 0x00 +#define TSL2591_CTRL_ALS_MED_GAIN 0x10 +#define TSL2591_CTRL_ALS_HIGH_GAIN 0x20 +#define TSL2591_CTRL_ALS_MAX_GAIN 0x30 +#define TSL2591_CTRL_SYS_RESET 0x80 + +/* TSL2591 persist register definitions */ +#define TSL2591_PRST_ALS_INT_CYCLE_0 0x00 +#define TSL2591_PRST_ALS_INT_CYCLE_ANY 0x01 +#define TSL2591_PRST_ALS_INT_CYCLE_2 0x02 +#define TSL2591_PRST_ALS_INT_CYCLE_3 0x03 +#define TSL2591_PRST_ALS_INT_CYCLE_5 0x04 +#define TSL2591_PRST_ALS_INT_CYCLE_10 0x05 +#define TSL2591_PRST_ALS_INT_CYCLE_15 0x06 +#define TSL2591_PRST_ALS_INT_CYCLE_20 0x07 +#define TSL2591_PRST_ALS_INT_CYCLE_25 0x08 +#define TSL2591_PRST_ALS_INT_CYCLE_30 0x09 +#define TSL2591_PRST_ALS_INT_CYCLE_35 0x0A +#define TSL2591_PRST_ALS_INT_CYCLE_40 0x0B +#define TSL2591_PRST_ALS_INT_CYCLE_45 0x0C +#define TSL2591_PRST_ALS_INT_CYCLE_50 0x0D +#define TSL2591_PRST_ALS_INT_CYCLE_55 0x0E +#define TSL2591_PRST_ALS_INT_CYCLE_60 0x0F +#define TSL2591_PRST_ALS_INT_CYCLE_MAX (BIT(4) - 1) + +/* TSL2591 PID register mask */ +#define TSL2591_PACKAGE_ID_MASK GENMASK(5, 4) + +/* TSL2591 ID register mask */ +#define TSL2591_DEVICE_ID_MASK GENMASK(7, 0) + +/* TSL2591 status register masks */ +#define TSL2591_STS_ALS_VALID_MASK BIT(0) +#define TSL2591_STS_ALS_INT_MASK BIT(4) +#define TSL2591_STS_NPERS_INT_MASK BIT(5) +#define TSL2591_STS_VAL_HIGH_MASK BIT(0) + +/* TSL2591 constant values */ +#define TSL2591_PACKAGE_ID_VAL 0x00 +#define TSL2591_DEVICE_ID_VAL 0x50 + +/* Power off suspend delay time MS */ +#define TSL2591_POWER_OFF_DELAY_MS 2000 + +/* TSL2591 default values */ +#define TSL2591_DEFAULT_ALS_INT_TIME TSL2591_CTRL_ALS_INTEGRATION_300MS +#define TSL2591_DEFAULT_ALS_GAIN TSL2591_CTRL_ALS_MED_GAIN +#define TSL2591_DEFAULT_ALS_PERSIST TSL2591_PRST_ALS_INT_CYCLE_ANY +#define TSL2591_DEFAULT_ALS_LOWER_THRESH 100 +#define TSL2591_DEFAULT_ALS_UPPER_THRESH 1500 + +/* TSL2591 number of data registers */ +#define TSL2591_NUM_DATA_REGISTERS 4 + +/* TSL2591 number of valid status reads on ADC complete */ +#define TSL2591_ALS_STS_VALID_COUNT 10 + +/* TSL2591 delay period between polls when checking for ALS valid flag */ +#define TSL2591_DELAY_PERIOD_US 10000 + +/* TSL2591 maximum values */ +#define TSL2591_MAX_ALS_INT_TIME_MS 600 +#define TSL2591_ALS_MAX_VALUE (BIT(16) - 1) + +/* + * LUX calculations; + * AGAIN values from Adafruit's TSL2591 Arduino library + * https://github.com/adafruit/Adafruit_TSL2591_Library + */ +#define TSL2591_CTRL_ALS_LOW_GAIN_MULTIPLIER 1 +#define TSL2591_CTRL_ALS_MED_GAIN_MULTIPLIER 25 +#define TSL2591_CTRL_ALS_HIGH_GAIN_MULTIPLIER 428 +#define TSL2591_CTRL_ALS_MAX_GAIN_MULTIPLIER 9876 +#define TSL2591_LUX_COEFFICIENT 408 + +struct tsl2591_als_settings { + u16 als_lower_thresh; + u16 als_upper_thresh; + u8 als_int_time; + u8 als_persist; + u8 als_gain; +}; + +struct tsl2591_chip { + struct tsl2591_als_settings als_settings; + struct i2c_client *client; + /* + * Keep als_settings in sync with hardware state + * and ensure multiple readers are serialized. + */ + struct mutex als_mutex; + bool events_enabled; +}; + +/* + * Period table is ALS persist cycle x integration time setting + * Integration times: 100ms, 200ms, 300ms, 400ms, 500ms, 600ms + * ALS cycles: 1, 2, 3, 5, 10, 20, 25, 30, 35, 40, 45, 50, 55, 60 + */ +static const char * const tsl2591_als_period_list[] = { + "0.1 0.2 0.3 0.5 1.0 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0", + "0.2 0.4 0.6 1.0 2.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0", + "0.3 0.6 0.9 1.5 3.0 6.0 7.5 9.0 10.5 12.0 13.5 15.0 16.5 18.0", + "0.4 0.8 1.2 2.0 4.0 8.0 10.0 12.0 14.0 16.0 18.0 20.0 22.0 24.0", + "0.5 1.0 1.5 2.5 5.0 10.0 12.5 15.0 17.5 20.0 22.5 25.0 27.5 30.0", + "0.6 1.2 1.8 3.0 6.0 12.0 15.0 18.0 21.0 24.0 27.0 30.0 33.0 36.0", +}; + +static const int tsl2591_int_time_available[] = { + 1, 2, 3, 4, 5, 6, +}; + +static const int tsl2591_calibscale_available[] = { + 1, 25, 428, 9876, +}; + +static int tsl2591_set_als_lower_threshold(struct tsl2591_chip *chip, + u16 als_lower_threshold); +static int tsl2591_set_als_upper_threshold(struct tsl2591_chip *chip, + u16 als_upper_threshold); + +static int tsl2591_gain_to_multiplier(const u8 als_gain) +{ + switch (als_gain) { + case TSL2591_CTRL_ALS_LOW_GAIN: + return TSL2591_CTRL_ALS_LOW_GAIN_MULTIPLIER; + case TSL2591_CTRL_ALS_MED_GAIN: + return TSL2591_CTRL_ALS_MED_GAIN_MULTIPLIER; + case TSL2591_CTRL_ALS_HIGH_GAIN: + return TSL2591_CTRL_ALS_HIGH_GAIN_MULTIPLIER; + case TSL2591_CTRL_ALS_MAX_GAIN: + return TSL2591_CTRL_ALS_MAX_GAIN_MULTIPLIER; + default: + return -EINVAL; + } +} + +static u8 tsl2591_multiplier_to_gain(const u32 multiplier) +{ + switch (multiplier) { + case TSL2591_CTRL_ALS_LOW_GAIN_MULTIPLIER: + return TSL2591_CTRL_ALS_LOW_GAIN; + case TSL2591_CTRL_ALS_MED_GAIN_MULTIPLIER: + return TSL2591_CTRL_ALS_MED_GAIN; + case TSL2591_CTRL_ALS_HIGH_GAIN_MULTIPLIER: + return TSL2591_CTRL_ALS_HIGH_GAIN; + case TSL2591_CTRL_ALS_MAX_GAIN_MULTIPLIER: + return TSL2591_CTRL_ALS_MAX_GAIN; + default: + return -EINVAL; + } +} + +static int tsl2591_persist_cycle_to_lit(const u8 als_persist) +{ + switch (als_persist) { + case TSL2591_PRST_ALS_INT_CYCLE_ANY: + return 1; + case TSL2591_PRST_ALS_INT_CYCLE_2: + return 2; + case TSL2591_PRST_ALS_INT_CYCLE_3: + return 3; + case TSL2591_PRST_ALS_INT_CYCLE_5: + return 5; + case TSL2591_PRST_ALS_INT_CYCLE_10: + return 10; + case TSL2591_PRST_ALS_INT_CYCLE_15: + return 15; + case TSL2591_PRST_ALS_INT_CYCLE_20: + return 20; + case TSL2591_PRST_ALS_INT_CYCLE_25: + return 25; + case TSL2591_PRST_ALS_INT_CYCLE_30: + return 30; + case TSL2591_PRST_ALS_INT_CYCLE_35: + return 35; + case TSL2591_PRST_ALS_INT_CYCLE_40: + return 40; + case TSL2591_PRST_ALS_INT_CYCLE_45: + return 45; + case TSL2591_PRST_ALS_INT_CYCLE_50: + return 50; + case TSL2591_PRST_ALS_INT_CYCLE_55: + return 55; + case TSL2591_PRST_ALS_INT_CYCLE_60: + return 60; + default: + return -EINVAL; + } +} + +static int tsl2591_persist_lit_to_cycle(const u8 als_persist) +{ + switch (als_persist) { + case 1: + return TSL2591_PRST_ALS_INT_CYCLE_ANY; + case 2: + return TSL2591_PRST_ALS_INT_CYCLE_2; + case 3: + return TSL2591_PRST_ALS_INT_CYCLE_3; + case 5: + return TSL2591_PRST_ALS_INT_CYCLE_5; + case 10: + return TSL2591_PRST_ALS_INT_CYCLE_10; + case 15: + return TSL2591_PRST_ALS_INT_CYCLE_15; + case 20: + return TSL2591_PRST_ALS_INT_CYCLE_20; + case 25: + return TSL2591_PRST_ALS_INT_CYCLE_25; + case 30: + return TSL2591_PRST_ALS_INT_CYCLE_30; + case 35: + return TSL2591_PRST_ALS_INT_CYCLE_35; + case 40: + return TSL2591_PRST_ALS_INT_CYCLE_40; + case 45: + return TSL2591_PRST_ALS_INT_CYCLE_45; + case 50: + return TSL2591_PRST_ALS_INT_CYCLE_50; + case 55: + return TSL2591_PRST_ALS_INT_CYCLE_55; + case 60: + return TSL2591_PRST_ALS_INT_CYCLE_60; + default: + return -EINVAL; + } +} + +static int tsl2591_compatible_int_time(struct tsl2591_chip *chip, + const u32 als_integration_time) +{ + switch (als_integration_time) { + case TSL2591_CTRL_ALS_INTEGRATION_100MS: + case TSL2591_CTRL_ALS_INTEGRATION_200MS: + case TSL2591_CTRL_ALS_INTEGRATION_300MS: + case TSL2591_CTRL_ALS_INTEGRATION_400MS: + case TSL2591_CTRL_ALS_INTEGRATION_500MS: + case TSL2591_CTRL_ALS_INTEGRATION_600MS: + return 0; + default: + return -EINVAL; + } +} + +static int tsl2591_als_time_to_fval(const u32 als_integration_time) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(tsl2591_int_time_available); i++) { + if (als_integration_time == tsl2591_int_time_available[i]) + return TSL2591_SEC_TO_FVAL(als_integration_time); + } + + return -EINVAL; +} + +static int tsl2591_compatible_gain(struct tsl2591_chip *chip, const u8 als_gain) +{ + switch (als_gain) { + case TSL2591_CTRL_ALS_LOW_GAIN: + case TSL2591_CTRL_ALS_MED_GAIN: + case TSL2591_CTRL_ALS_HIGH_GAIN: + case TSL2591_CTRL_ALS_MAX_GAIN: + return 0; + default: + return -EINVAL; + } +} + +static int tsl2591_compatible_als_persist_cycle(struct tsl2591_chip *chip, + const u32 als_persist) +{ + switch (als_persist) { + case TSL2591_PRST_ALS_INT_CYCLE_ANY: + case TSL2591_PRST_ALS_INT_CYCLE_2: + case TSL2591_PRST_ALS_INT_CYCLE_3: + case TSL2591_PRST_ALS_INT_CYCLE_5: + case TSL2591_PRST_ALS_INT_CYCLE_10: + case TSL2591_PRST_ALS_INT_CYCLE_15: + case TSL2591_PRST_ALS_INT_CYCLE_20: + case TSL2591_PRST_ALS_INT_CYCLE_25: + case TSL2591_PRST_ALS_INT_CYCLE_30: + case TSL2591_PRST_ALS_INT_CYCLE_35: + case TSL2591_PRST_ALS_INT_CYCLE_40: + case TSL2591_PRST_ALS_INT_CYCLE_45: + case TSL2591_PRST_ALS_INT_CYCLE_50: + case TSL2591_PRST_ALS_INT_CYCLE_55: + case TSL2591_PRST_ALS_INT_CYCLE_60: + return 0; + default: + return -EINVAL; + } +} + +static int tsl2591_check_als_valid(struct i2c_client *client) +{ + int ret; + + ret = i2c_smbus_read_byte_data(client, TSL2591_CMD_NOP | TSL2591_STATUS); + if (ret < 0) { + dev_err(&client->dev, "Failed to read register\n"); + return -EINVAL; + } + + return FIELD_GET(TSL2591_STS_ALS_VALID_MASK, ret); +} + +static int tsl2591_wait_adc_complete(struct tsl2591_chip *chip) +{ + struct tsl2591_als_settings settings = chip->als_settings; + struct i2c_client *client = chip->client; + int delay; + int val; + int ret; + + delay = TSL2591_FVAL_TO_MSEC(settings.als_int_time); + if (!delay) + return -EINVAL; + + /* + * Sleep for ALS integration time to allow enough time or an ADC read + * cycle to complete. Check status after delay for ALS valid. + */ + msleep(delay); + + /* Check for status ALS valid flag for up to 100ms */ + ret = readx_poll_timeout(tsl2591_check_als_valid, client, + val, val == TSL2591_STS_VAL_HIGH_MASK, + TSL2591_DELAY_PERIOD_US, + TSL2591_DELAY_PERIOD_US * TSL2591_ALS_STS_VALID_COUNT); + if (ret) + dev_err(&client->dev, "Timed out waiting for valid ALS data\n"); + + return ret; +} + +/* + * tsl2591_read_channel_data - Reads raw channel data and calculates lux + * + * Formula for lux calculation; + * Derived from Adafruit's TSL2591 library + * Link: https://github.com/adafruit/Adafruit_TSL2591_Library + * Counts Per Lux (CPL) = (ATIME_ms * AGAIN) / LUX DF + * lux = ((C0DATA - C1DATA) * (1 - (C1DATA / C0DATA))) / CPL + * + * Scale values to get more representative value of lux i.e. + * lux = ((C0DATA - C1DATA) * (1000 - ((C1DATA * 1000) / C0DATA))) / CPL + * + * Channel 0 = IR + Visible + * Channel 1 = IR only + */ +static int tsl2591_read_channel_data(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2) +{ + struct tsl2591_chip *chip = iio_priv(indio_dev); + struct tsl2591_als_settings *settings = &chip->als_settings; + struct i2c_client *client = chip->client; + u8 als_data[TSL2591_NUM_DATA_REGISTERS]; + int counts_per_lux, int_time_fval, gain_multi, lux; + u16 als_ch0, als_ch1; + int ret; + + ret = tsl2591_wait_adc_complete(chip); + if (ret < 0) { + dev_err(&client->dev, "No data available. Err: %d\n", ret); + return ret; + } + + ret = i2c_smbus_read_i2c_block_data(client, + TSL2591_CMD_NOP | TSL2591_C0_DATAL, + sizeof(als_data), als_data); + if (ret < 0) { + dev_err(&client->dev, "Failed to read data bytes"); + return ret; + } + + als_ch0 = get_unaligned_le16(&als_data[0]); + als_ch1 = get_unaligned_le16(&als_data[2]); + + switch (chan->type) { + case IIO_INTENSITY: + if (chan->channel2 == IIO_MOD_LIGHT_BOTH) + *val = als_ch0; + else if (chan->channel2 == IIO_MOD_LIGHT_IR) + *val = als_ch1; + else + return -EINVAL; + break; + case IIO_LIGHT: + gain_multi = tsl2591_gain_to_multiplier(settings->als_gain); + if (gain_multi < 0) { + dev_err(&client->dev, "Invalid multiplier"); + return gain_multi; + } + + int_time_fval = TSL2591_FVAL_TO_MSEC(settings->als_int_time); + /* Calculate counts per lux value */ + counts_per_lux = (int_time_fval * gain_multi) / TSL2591_LUX_COEFFICIENT; + + dev_dbg(&client->dev, "Counts Per Lux: %d\n", counts_per_lux); + + /* Calculate lux value */ + lux = ((als_ch0 - als_ch1) * + (1000 - ((als_ch1 * 1000) / als_ch0))) / counts_per_lux; + + dev_dbg(&client->dev, "Raw lux calculation: %d\n", lux); + + /* Divide by 1000 to get real lux value before scaling */ + *val = lux / 1000; + + /* Get the decimal part of lux reading */ + *val2 = (lux - (*val * 1000)) * 1000; + + break; + default: + return -EINVAL; + } + + return 0; +} + +static int tsl2591_set_als_gain_int_time(struct tsl2591_chip *chip) +{ + struct tsl2591_als_settings als_settings = chip->als_settings; + struct i2c_client *client = chip->client; + int ret; + + ret = i2c_smbus_write_byte_data(client, + TSL2591_CMD_NOP | TSL2591_CONTROL, + als_settings.als_int_time | als_settings.als_gain); + if (ret) + dev_err(&client->dev, "Failed to set als gain & int time\n"); + + return ret; +} + +static int tsl2591_set_als_lower_threshold(struct tsl2591_chip *chip, + u16 als_lower_threshold) +{ + struct tsl2591_als_settings als_settings = chip->als_settings; + struct i2c_client *client = chip->client; + u16 als_upper_threshold; + u8 als_lower_l; + u8 als_lower_h; + int ret; + + chip->als_settings.als_lower_thresh = als_lower_threshold; + + /* + * Lower threshold should not be greater or equal to upper. + * If this is the case, then assert upper threshold to new lower + * threshold + 1 to avoid ordering issues when setting thresholds. + */ + if (als_lower_threshold >= als_settings.als_upper_thresh) { + als_upper_threshold = als_lower_threshold + 1; + tsl2591_set_als_upper_threshold(chip, als_upper_threshold); + } + + als_lower_l = als_lower_threshold; + als_lower_h = als_lower_threshold >> 8; + + ret = i2c_smbus_write_byte_data(client, + TSL2591_CMD_NOP | TSL2591_AILTL, + als_lower_l); + if (ret) { + dev_err(&client->dev, "Failed to set als lower threshold\n"); + return ret; + } + + ret = i2c_smbus_write_byte_data(client, + TSL2591_CMD_NOP | TSL2591_AILTH, + als_lower_h); + if (ret) { + dev_err(&client->dev, "Failed to set als lower threshold\n"); + return ret; + } + + return 0; +} + +static int tsl2591_set_als_upper_threshold(struct tsl2591_chip *chip, + u16 als_upper_threshold) +{ + struct tsl2591_als_settings als_settings = chip->als_settings; + struct i2c_client *client = chip->client; + u16 als_lower_threshold; + u8 als_upper_l; + u8 als_upper_h; + int ret; + + if (als_upper_threshold > TSL2591_ALS_MAX_VALUE) + return -EINVAL; + + chip->als_settings.als_upper_thresh = als_upper_threshold; + + /* + * Upper threshold should not be less than lower. If this + * is the case, then assert lower threshold to new upper + * threshold - 1 to avoid ordering issues when setting thresholds. + */ + if (als_upper_threshold < als_settings.als_lower_thresh) { + als_lower_threshold = als_upper_threshold - 1; + tsl2591_set_als_lower_threshold(chip, als_lower_threshold); + } + + als_upper_l = als_upper_threshold; + als_upper_h = als_upper_threshold >> 8; + + ret = i2c_smbus_write_byte_data(client, + TSL2591_CMD_NOP | TSL2591_AIHTL, + als_upper_l); + if (ret) { + dev_err(&client->dev, "Failed to set als upper threshold\n"); + return ret; + } + + ret = i2c_smbus_write_byte_data(client, + TSL2591_CMD_NOP | TSL2591_AIHTH, + als_upper_h); + if (ret) { + dev_err(&client->dev, "Failed to set als upper threshold\n"); + return ret; + } + + return 0; +} + +static int tsl2591_set_als_persist_cycle(struct tsl2591_chip *chip, + u8 als_persist) +{ + struct i2c_client *client = chip->client; + int ret; + + ret = i2c_smbus_write_byte_data(client, + TSL2591_CMD_NOP | TSL2591_PERSIST, + als_persist); + if (ret) + dev_err(&client->dev, "Failed to set als persist cycle\n"); + + chip->als_settings.als_persist = als_persist; + + return ret; +} + +static int tsl2591_set_power_state(struct tsl2591_chip *chip, u8 state) +{ + struct i2c_client *client = chip->client; + int ret; + + ret = i2c_smbus_write_byte_data(client, + TSL2591_CMD_NOP | TSL2591_ENABLE, + state); + if (ret) + dev_err(&client->dev, + "Failed to set the power state to %#04x\n", state); + + return ret; +} + +static ssize_t tsl2591_in_illuminance_period_available_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct tsl2591_chip *chip = iio_priv(indio_dev); + + return sysfs_emit(buf, "%s\n", + tsl2591_als_period_list[chip->als_settings.als_int_time]); +} + +static IIO_DEVICE_ATTR_RO(tsl2591_in_illuminance_period_available, 0); + +static struct attribute *tsl2591_event_attrs_ctrl[] = { + &iio_dev_attr_tsl2591_in_illuminance_period_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group tsl2591_event_attribute_group = { + .attrs = tsl2591_event_attrs_ctrl, +}; + +static const struct iio_event_spec tsl2591_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_EITHER, + .mask_separate = BIT(IIO_EV_INFO_PERIOD) | + BIT(IIO_EV_INFO_ENABLE), + }, +}; + +static const struct iio_chan_spec tsl2591_channels[] = { + { + .type = IIO_INTENSITY, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_IR, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_CALIBSCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_CALIBSCALE) + }, + { + .type = IIO_INTENSITY, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_BOTH, + .event_spec = tsl2591_events, + .num_event_specs = ARRAY_SIZE(tsl2591_events), + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_CALIBSCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_CALIBSCALE) + }, + { + .type = IIO_LIGHT, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_CALIBSCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_CALIBSCALE) + }, +}; + +static int tsl2591_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct tsl2591_chip *chip = iio_priv(indio_dev); + struct i2c_client *client = chip->client; + int ret; + + pm_runtime_get_sync(&client->dev); + + mutex_lock(&chip->als_mutex); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (chan->type != IIO_INTENSITY) { + ret = -EINVAL; + goto err_unlock; + } + + ret = tsl2591_read_channel_data(indio_dev, chan, val, val2); + if (ret < 0) + goto err_unlock; + + ret = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_PROCESSED: + if (chan->type != IIO_LIGHT) { + ret = -EINVAL; + goto err_unlock; + } + + ret = tsl2591_read_channel_data(indio_dev, chan, val, val2); + if (ret < 0) + break; + + ret = IIO_VAL_INT_PLUS_MICRO; + break; + case IIO_CHAN_INFO_INT_TIME: + if (chan->type != IIO_INTENSITY) { + ret = -EINVAL; + goto err_unlock; + } + + *val = TSL2591_FVAL_TO_SEC(chip->als_settings.als_int_time); + ret = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_CALIBSCALE: + if (chan->type != IIO_INTENSITY) { + ret = -EINVAL; + goto err_unlock; + } + + *val = tsl2591_gain_to_multiplier(chip->als_settings.als_gain); + ret = IIO_VAL_INT; + break; + default: + ret = -EINVAL; + break; + } + +err_unlock: + mutex_unlock(&chip->als_mutex); + + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + + return ret; +} + +static int tsl2591_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct tsl2591_chip *chip = iio_priv(indio_dev); + u32 int_time; + u8 gain; + int ret; + + mutex_lock(&chip->als_mutex); + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + int_time = tsl2591_als_time_to_fval(val); + if (int_time < 0) { + ret = int_time; + goto err_unlock; + } + ret = tsl2591_compatible_int_time(chip, int_time); + if (ret < 0) + goto err_unlock; + + chip->als_settings.als_int_time = int_time; + break; + case IIO_CHAN_INFO_CALIBSCALE: + gain = tsl2591_multiplier_to_gain(val); + if (gain < 0) { + ret = gain; + goto err_unlock; + } + ret = tsl2591_compatible_gain(chip, gain); + if (ret < 0) + goto err_unlock; + + chip->als_settings.als_gain = gain; + break; + default: + ret = -EINVAL; + goto err_unlock; + } + + ret = tsl2591_set_als_gain_int_time(chip); + +err_unlock: + mutex_unlock(&chip->als_mutex); + return ret; +} + +static int tsl2591_read_available(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + *length = ARRAY_SIZE(tsl2591_int_time_available); + *vals = tsl2591_int_time_available; + *type = IIO_VAL_INT; + return IIO_AVAIL_LIST; + + case IIO_CHAN_INFO_CALIBSCALE: + *length = ARRAY_SIZE(tsl2591_calibscale_available); + *vals = tsl2591_calibscale_available; + *type = IIO_VAL_INT; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int tsl2591_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 tsl2591_chip *chip = iio_priv(indio_dev); + struct i2c_client *client = chip->client; + int als_persist, int_time, period; + int ret; + + mutex_lock(&chip->als_mutex); + + switch (info) { + case IIO_EV_INFO_VALUE: + switch (dir) { + case IIO_EV_DIR_RISING: + *val = chip->als_settings.als_upper_thresh; + break; + case IIO_EV_DIR_FALLING: + *val = chip->als_settings.als_lower_thresh; + break; + default: + ret = -EINVAL; + goto err_unlock; + } + ret = IIO_VAL_INT; + break; + case IIO_EV_INFO_PERIOD: + ret = i2c_smbus_read_byte_data(client, + TSL2591_CMD_NOP | TSL2591_PERSIST); + if (ret <= 0 || ret > TSL2591_PRST_ALS_INT_CYCLE_MAX) + goto err_unlock; + + als_persist = tsl2591_persist_cycle_to_lit(ret); + int_time = TSL2591_FVAL_TO_MSEC(chip->als_settings.als_int_time); + period = als_persist * (int_time * MSEC_PER_SEC); + + *val = period / USEC_PER_SEC; + *val2 = period % USEC_PER_SEC; + + ret = IIO_VAL_INT_PLUS_MICRO; + break; + default: + ret = -EINVAL; + break; + } + +err_unlock: + mutex_unlock(&chip->als_mutex); + return ret; +} + +static int tsl2591_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 tsl2591_chip *chip = iio_priv(indio_dev); + int period, int_time, als_persist; + int ret; + + if (val < 0 || val2 < 0) + return -EINVAL; + + mutex_lock(&chip->als_mutex); + + switch (info) { + case IIO_EV_INFO_VALUE: + if (val > TSL2591_ALS_MAX_VALUE) { + ret = -EINVAL; + goto err_unlock; + } + + switch (dir) { + case IIO_EV_DIR_RISING: + ret = tsl2591_set_als_upper_threshold(chip, val); + if (ret < 0) + goto err_unlock; + break; + case IIO_EV_DIR_FALLING: + ret = tsl2591_set_als_lower_threshold(chip, val); + if (ret < 0) + goto err_unlock; + break; + default: + ret = -EINVAL; + goto err_unlock; + } + break; + case IIO_EV_INFO_PERIOD: + int_time = TSL2591_FVAL_TO_MSEC(chip->als_settings.als_int_time); + + period = ((val * MSEC_PER_SEC) + + (val2 / MSEC_PER_SEC)) / int_time; + + als_persist = tsl2591_persist_lit_to_cycle(period); + if (als_persist < 0) { + ret = -EINVAL; + goto err_unlock; + } + + ret = tsl2591_compatible_als_persist_cycle(chip, als_persist); + if (ret < 0) + goto err_unlock; + + ret = tsl2591_set_als_persist_cycle(chip, als_persist); + if (ret < 0) + goto err_unlock; + break; + default: + ret = -EINVAL; + break; + } + +err_unlock: + mutex_unlock(&chip->als_mutex); + return ret; +} + +static int tsl2591_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 tsl2591_chip *chip = iio_priv(indio_dev); + + return chip->events_enabled; +} + +static int tsl2591_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + int state) +{ + struct tsl2591_chip *chip = iio_priv(indio_dev); + struct i2c_client *client = chip->client; + + if (state && !chip->events_enabled) { + chip->events_enabled = true; + pm_runtime_get_sync(&client->dev); + } else if (!state && chip->events_enabled) { + chip->events_enabled = false; + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + } + + return 0; +} + +static const struct iio_info tsl2591_info = { + .event_attrs = &tsl2591_event_attribute_group, + .read_raw = tsl2591_read_raw, + .write_raw = tsl2591_write_raw, + .read_avail = tsl2591_read_available, + .read_event_value = tsl2591_read_event_value, + .write_event_value = tsl2591_write_event_value, + .read_event_config = tsl2591_read_event_config, + .write_event_config = tsl2591_write_event_config, +}; + +static const struct iio_info tsl2591_info_no_irq = { + .read_raw = tsl2591_read_raw, + .write_raw = tsl2591_write_raw, + .read_avail = tsl2591_read_available, +}; + +static int __maybe_unused tsl2591_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2591_chip *chip = iio_priv(indio_dev); + int ret; + + mutex_lock(&chip->als_mutex); + ret = tsl2591_set_power_state(chip, TSL2591_PWR_OFF); + mutex_unlock(&chip->als_mutex); + + return ret; +} + +static int __maybe_unused tsl2591_resume(struct device *dev) +{ + int power_state = TSL2591_PWR_ON | TSL2591_ENABLE_ALS; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2591_chip *chip = iio_priv(indio_dev); + int ret; + + if (chip->events_enabled) + power_state |= TSL2591_ENABLE_ALS_INT; + + mutex_lock(&chip->als_mutex); + ret = tsl2591_set_power_state(chip, power_state); + mutex_unlock(&chip->als_mutex); + + return ret; +} + +static const struct dev_pm_ops tsl2591_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(tsl2591_suspend, tsl2591_resume, NULL) +}; + +static irqreturn_t tsl2591_event_handler(int irq, void *private) +{ + struct iio_dev *dev_info = private; + struct tsl2591_chip *chip = iio_priv(dev_info); + struct i2c_client *client = chip->client; + + if (!chip->events_enabled) + return IRQ_NONE; + + iio_push_event(dev_info, + IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + iio_get_time_ns(dev_info)); + + /* Clear ALS irq */ + i2c_smbus_write_byte(client, TSL2591_CMD_SF_CALS_NPI); + + return IRQ_HANDLED; +} + +static int tsl2591_load_defaults(struct tsl2591_chip *chip) +{ + int ret; + + chip->als_settings.als_int_time = TSL2591_DEFAULT_ALS_INT_TIME; + chip->als_settings.als_gain = TSL2591_DEFAULT_ALS_GAIN; + chip->als_settings.als_lower_thresh = TSL2591_DEFAULT_ALS_LOWER_THRESH; + chip->als_settings.als_upper_thresh = TSL2591_DEFAULT_ALS_UPPER_THRESH; + + ret = tsl2591_set_als_gain_int_time(chip); + if (ret < 0) + return ret; + + ret = tsl2591_set_als_persist_cycle(chip, TSL2591_DEFAULT_ALS_PERSIST); + if (ret < 0) + return ret; + + ret = tsl2591_set_als_lower_threshold(chip, TSL2591_DEFAULT_ALS_LOWER_THRESH); + if (ret < 0) + return ret; + + ret = tsl2591_set_als_upper_threshold(chip, TSL2591_DEFAULT_ALS_UPPER_THRESH); + if (ret < 0) + return ret; + + return 0; +} + +static void tsl2591_chip_off(void *data) +{ + struct iio_dev *indio_dev = data; + struct tsl2591_chip *chip = iio_priv(indio_dev); + struct i2c_client *client = chip->client; + + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + pm_runtime_put_noidle(&client->dev); + + tsl2591_set_power_state(chip, TSL2591_PWR_OFF); +} + +static int tsl2591_probe(struct i2c_client *client) +{ + struct tsl2591_chip *chip; + struct iio_dev *indio_dev; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, + "I2C smbus byte data functionality is not supported\n"); + return -EOPNOTSUPP; + } + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip)); + if (!indio_dev) + return -ENOMEM; + + chip = iio_priv(indio_dev); + chip->client = client; + i2c_set_clientdata(client, indio_dev); + + if (client->irq) { + ret = devm_request_threaded_irq(&client->dev, client->irq, + NULL, tsl2591_event_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "tsl2591_irq", indio_dev); + if (ret) { + dev_err_probe(&client->dev, ret, "IRQ request error\n"); + return -EINVAL; + } + indio_dev->info = &tsl2591_info; + } else { + indio_dev->info = &tsl2591_info_no_irq; + } + + mutex_init(&chip->als_mutex); + + ret = i2c_smbus_read_byte_data(client, + TSL2591_CMD_NOP | TSL2591_DEVICE_ID); + if (ret < 0) { + dev_err(&client->dev, + "Failed to read the device ID register\n"); + return ret; + } + ret = FIELD_GET(TSL2591_DEVICE_ID_MASK, ret); + if (ret != TSL2591_DEVICE_ID_VAL) { + dev_err(&client->dev, "Device ID: %#04x unknown\n", ret); + return -EINVAL; + } + + indio_dev->channels = tsl2591_channels; + indio_dev->num_channels = ARRAY_SIZE(tsl2591_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->name = chip->client->name; + chip->events_enabled = false; + + pm_runtime_enable(&client->dev); + pm_runtime_set_autosuspend_delay(&client->dev, + TSL2591_POWER_OFF_DELAY_MS); + pm_runtime_use_autosuspend(&client->dev); + + /* + * Add chip off to automatically managed path and disable runtime + * power management. This ensures that the chip power management + * is handled correctly on driver remove. tsl2591_chip_off() must be + * added to the managed path after pm runtime is enabled and before + * any error exit paths are met to ensure we're not left in a state + * of pm runtime not being disabled properly. + */ + ret = devm_add_action_or_reset(&client->dev, tsl2591_chip_off, + indio_dev); + if (ret < 0) + return -EINVAL; + + ret = tsl2591_load_defaults(chip); + if (ret < 0) { + dev_err(&client->dev, "Failed to load sensor defaults\n"); + return -EINVAL; + } + + ret = i2c_smbus_write_byte(client, TSL2591_CMD_SF_CALS_NPI); + if (ret < 0) { + dev_err(&client->dev, "Failed to clear als irq\n"); + return -EINVAL; + } + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static const struct of_device_id tsl2591_of_match[] = { + { .compatible = "amstaos,tsl2591"}, + {} +}; +MODULE_DEVICE_TABLE(of, tsl2591_of_match); + +static struct i2c_driver tsl2591_driver = { + .driver = { + .name = "tsl2591", + .pm = &tsl2591_pm_ops, + .of_match_table = tsl2591_of_match, + }, + .probe_new = tsl2591_probe +}; +module_i2c_driver(tsl2591_driver); + +MODULE_AUTHOR("Joe Sandom "); +MODULE_DESCRIPTION("TAOS tsl2591 ambient light sensor driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 4e023c4dcfc555e9a5f87435cae19412c0684343 Mon Sep 17 00:00:00 2001 From: Yicong Yang Date: Thu, 8 Apr 2021 19:38:10 +0800 Subject: iio: adc: adi-axi-adc: simplify devm_adi_axi_adc_conv_register() Use devm_add_action_or_reset() instead of devres_alloc() and devres_add(), which works the same. This will simplify the code. There is no functional changes. Signed-off-by: Yicong Yang Reviewed-by: Alexandru Ardelean Reviewed-by: Lars-Peter Clausen Reviewed-by: Nuno Sa Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/1617881896-3164-2-git-send-email-yangyicong@hisilicon.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/adi-axi-adc.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c index d5f6ffc5b5bc..a73e3c2d212f 100644 --- a/drivers/iio/adc/adi-axi-adc.c +++ b/drivers/iio/adc/adi-axi-adc.c @@ -202,29 +202,25 @@ static void adi_axi_adc_conv_unregister(struct adi_axi_adc_conv *conv) kfree(cl); } -static void devm_adi_axi_adc_conv_release(struct device *dev, void *res) +static void devm_adi_axi_adc_conv_release(void *conv) { - adi_axi_adc_conv_unregister(*(struct adi_axi_adc_conv **)res); + adi_axi_adc_conv_unregister(conv); } struct adi_axi_adc_conv *devm_adi_axi_adc_conv_register(struct device *dev, size_t sizeof_priv) { - struct adi_axi_adc_conv **ptr, *conv; - - ptr = devres_alloc(devm_adi_axi_adc_conv_release, sizeof(*ptr), - GFP_KERNEL); - if (!ptr) - return ERR_PTR(-ENOMEM); + struct adi_axi_adc_conv *conv; + int ret; conv = adi_axi_adc_conv_register(dev, sizeof_priv); - if (IS_ERR(conv)) { - devres_free(ptr); - return ERR_CAST(conv); - } + if (IS_ERR(conv)) + return conv; - *ptr = conv; - devres_add(dev, ptr); + ret = devm_add_action_or_reset(dev, devm_adi_axi_adc_conv_release, + conv); + if (ret) + return ERR_PTR(ret); return conv; } -- cgit v1.2.3 From 2c6a958789f79dedef3d661569f7faa7b375b538 Mon Sep 17 00:00:00 2001 From: Yicong Yang Date: Thu, 8 Apr 2021 19:38:11 +0800 Subject: iio: buffer-dmaengine: simplify __devm_iio_dmaengine_buffer_free() Use devm_add_action_or_reset() instead of devres_alloc() and devres_add(), which works the same. This will simplify the code. There is no functional changes. Signed-off-by: Yicong Yang Reviewed-by: Lars-Peter Clausen Reviewed-by: Nuno Sa Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/1617881896-3164-3-git-send-email-yangyicong@hisilicon.com Signed-off-by: Jonathan Cameron --- drivers/iio/buffer/industrialio-buffer-dmaengine.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index d76179878ff9..1ac94c4e9792 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -228,9 +228,9 @@ static void iio_dmaengine_buffer_free(struct iio_buffer *buffer) iio_buffer_put(buffer); } -static void __devm_iio_dmaengine_buffer_free(struct device *dev, void *res) +static void __devm_iio_dmaengine_buffer_free(void *buffer) { - iio_dmaengine_buffer_free(*(struct iio_buffer **)res); + iio_dmaengine_buffer_free(buffer); } /** @@ -247,21 +247,17 @@ static void __devm_iio_dmaengine_buffer_free(struct device *dev, void *res) static struct iio_buffer *devm_iio_dmaengine_buffer_alloc(struct device *dev, const char *channel) { - struct iio_buffer **bufferp, *buffer; - - bufferp = devres_alloc(__devm_iio_dmaengine_buffer_free, - sizeof(*bufferp), GFP_KERNEL); - if (!bufferp) - return ERR_PTR(-ENOMEM); + struct iio_buffer *buffer; + int ret; buffer = iio_dmaengine_buffer_alloc(dev, channel); - if (IS_ERR(buffer)) { - devres_free(bufferp); + if (IS_ERR(buffer)) return buffer; - } - *bufferp = buffer; - devres_add(dev, bufferp); + ret = devm_add_action_or_reset(dev, __devm_iio_dmaengine_buffer_free, + buffer); + if (ret) + return ERR_PTR(ret); return buffer; } -- cgit v1.2.3 From bfc1807acf85a22a17ea22635d4f546c3c53a73f Mon Sep 17 00:00:00 2001 From: Yicong Yang Date: Thu, 8 Apr 2021 19:38:12 +0800 Subject: iio: hw_consumer: simplify devm_iio_hw_consumer_alloc() Use devm_add_action_or_reset() instead of devres_alloc() and devres_add(), which works the same. This will simplify the code. There is no functional changes. Signed-off-by: Yicong Yang Reviewed-by: Lars-Peter Clausen Reviewed-by: Nuno Sa Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/1617881896-3164-4-git-send-email-yangyicong@hisilicon.com Signed-off-by: Jonathan Cameron --- drivers/iio/buffer/industrialio-hw-consumer.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/buffer/industrialio-hw-consumer.c b/drivers/iio/buffer/industrialio-hw-consumer.c index f2d27788f666..87d9aabd20c7 100644 --- a/drivers/iio/buffer/industrialio-hw-consumer.c +++ b/drivers/iio/buffer/industrialio-hw-consumer.c @@ -137,9 +137,9 @@ void iio_hw_consumer_free(struct iio_hw_consumer *hwc) } EXPORT_SYMBOL_GPL(iio_hw_consumer_free); -static void devm_iio_hw_consumer_release(struct device *dev, void *res) +static void devm_iio_hw_consumer_release(void *iio_hwc) { - iio_hw_consumer_free(*(struct iio_hw_consumer **)res); + iio_hw_consumer_free(iio_hwc); } /** @@ -153,20 +153,17 @@ static void devm_iio_hw_consumer_release(struct device *dev, void *res) */ struct iio_hw_consumer *devm_iio_hw_consumer_alloc(struct device *dev) { - struct iio_hw_consumer **ptr, *iio_hwc; - - ptr = devres_alloc(devm_iio_hw_consumer_release, sizeof(*ptr), - GFP_KERNEL); - if (!ptr) - return NULL; + struct iio_hw_consumer *iio_hwc; + int ret; iio_hwc = iio_hw_consumer_alloc(dev); - if (IS_ERR(iio_hwc)) { - devres_free(ptr); - } else { - *ptr = iio_hwc; - devres_add(dev, ptr); - } + if (IS_ERR(iio_hwc)) + return iio_hwc; + + ret = devm_add_action_or_reset(dev, devm_iio_hw_consumer_release, + iio_hwc); + if (ret) + return ERR_PTR(ret); return iio_hwc; } -- cgit v1.2.3 From 8e39d4723a00cfc7029e61f7bd9ffa357409f9d2 Mon Sep 17 00:00:00 2001 From: Yicong Yang Date: Thu, 8 Apr 2021 19:38:13 +0800 Subject: iio: triggered-buffer: simplify devm_iio_triggered_buffer_setup_ext() Use devm_add_action_or_reset() instead of devres_alloc() and devres_add(), which works the same. This will simplify the code. There is no functional changes. Signed-off-by: Yicong Yang Reviewed-by: Lars-Peter Clausen Reviewed-by: Nuno Sa Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/1617881896-3164-5-git-send-email-yangyicong@hisilicon.com Signed-off-by: Jonathan Cameron --- drivers/iio/buffer/industrialio-triggered-buffer.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/buffer/industrialio-triggered-buffer.c b/drivers/iio/buffer/industrialio-triggered-buffer.c index b2b1b7d27af4..ebb4520ac291 100644 --- a/drivers/iio/buffer/industrialio-triggered-buffer.c +++ b/drivers/iio/buffer/industrialio-triggered-buffer.c @@ -96,9 +96,9 @@ void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev) } EXPORT_SYMBOL(iio_triggered_buffer_cleanup); -static void devm_iio_triggered_buffer_clean(struct device *dev, void *res) +static void devm_iio_triggered_buffer_clean(void *indio_dev) { - iio_triggered_buffer_cleanup(*(struct iio_dev **)res); + iio_triggered_buffer_cleanup(indio_dev); } int devm_iio_triggered_buffer_setup_ext(struct device *dev, @@ -108,24 +108,15 @@ int devm_iio_triggered_buffer_setup_ext(struct device *dev, const struct iio_buffer_setup_ops *ops, const struct attribute **buffer_attrs) { - struct iio_dev **ptr; int ret; - ptr = devres_alloc(devm_iio_triggered_buffer_clean, sizeof(*ptr), - GFP_KERNEL); - if (!ptr) - return -ENOMEM; - - *ptr = indio_dev; - ret = iio_triggered_buffer_setup_ext(indio_dev, h, thread, ops, buffer_attrs); - if (!ret) - devres_add(dev, ptr); - else - devres_free(ptr); + if (ret) + return ret; - return ret; + return devm_add_action_or_reset(dev, devm_iio_triggered_buffer_clean, + indio_dev); } EXPORT_SYMBOL_GPL(devm_iio_triggered_buffer_setup_ext); -- cgit v1.2.3 From cf5724e91515e8b016019b148c99bdf7c58f3ab7 Mon Sep 17 00:00:00 2001 From: Yicong Yang Date: Thu, 8 Apr 2021 19:38:14 +0800 Subject: iio: core: simplify some devm functions Use devm_add_action_or_reset() instead of devres_alloc() and devres_add(), which works the same. This will simplify the code. There is no functional changes. Signed-off-by: Yicong Yang Reviewed-by: Lars-Peter Clausen Reviewed-by: Nuno Sa Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/1617881896-3164-6-git-send-email-yangyicong@hisilicon.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 41 +++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 59efb36db2c7..3fdcf2d4997a 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1657,9 +1657,9 @@ void iio_device_free(struct iio_dev *dev) } EXPORT_SYMBOL(iio_device_free); -static void devm_iio_device_release(struct device *dev, void *res) +static void devm_iio_device_release(void *iio_dev) { - iio_device_free(*(struct iio_dev **)res); + iio_device_free(iio_dev); } /** @@ -1675,20 +1675,17 @@ static void devm_iio_device_release(struct device *dev, void *res) */ struct iio_dev *devm_iio_device_alloc(struct device *parent, int sizeof_priv) { - struct iio_dev **ptr, *iio_dev; + struct iio_dev *iio_dev; + int ret; - ptr = devres_alloc(devm_iio_device_release, sizeof(*ptr), - GFP_KERNEL); - if (!ptr) + iio_dev = iio_device_alloc(parent, sizeof_priv); + if (!iio_dev) return NULL; - iio_dev = iio_device_alloc(parent, sizeof_priv); - if (iio_dev) { - *ptr = iio_dev; - devres_add(parent, ptr); - } else { - devres_free(ptr); - } + ret = devm_add_action_or_reset(parent, devm_iio_device_release, + iio_dev); + if (ret) + return ERR_PTR(ret); return iio_dev; } @@ -1944,29 +1941,21 @@ void iio_device_unregister(struct iio_dev *indio_dev) } EXPORT_SYMBOL(iio_device_unregister); -static void devm_iio_device_unreg(struct device *dev, void *res) +static void devm_iio_device_unreg(void *indio_dev) { - iio_device_unregister(*(struct iio_dev **)res); + iio_device_unregister(indio_dev); } int __devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev, struct module *this_mod) { - struct iio_dev **ptr; int ret; - ptr = devres_alloc(devm_iio_device_unreg, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return -ENOMEM; - - *ptr = indio_dev; ret = __iio_device_register(indio_dev, this_mod); - if (!ret) - devres_add(dev, ptr); - else - devres_free(ptr); + if (ret) + return ret; - return ret; + return devm_add_action_or_reset(dev, devm_iio_device_unreg, indio_dev); } EXPORT_SYMBOL_GPL(__devm_iio_device_register); -- cgit v1.2.3 From 171a70afbde9a3e7499d7d3efde8ca49f7e5f00d Mon Sep 17 00:00:00 2001 From: Yicong Yang Date: Thu, 8 Apr 2021 19:38:15 +0800 Subject: iio: trigger: simplify __devm_iio_trigger_register Use devm_add_action_or_reset() instead of devres_alloc() and devres_add(), which works the same. This will simplify the code. There is no functional changes. Signed-off-by: Yicong Yang Reviewed-by: Lars-Peter Clausen Reviewed-by: Nuno Sa Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/1617881896-3164-7-git-send-email-yangyicong@hisilicon.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-trigger.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index b2c94abbb487..3236647b2c37 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -634,9 +634,9 @@ struct iio_trigger *devm_iio_trigger_alloc(struct device *parent, const char *fm } EXPORT_SYMBOL_GPL(devm_iio_trigger_alloc); -static void devm_iio_trigger_unreg(struct device *dev, void *res) +static void devm_iio_trigger_unreg(void *trigger_info) { - iio_trigger_unregister(*(struct iio_trigger **)res); + iio_trigger_unregister(trigger_info); } /** @@ -657,21 +657,13 @@ int __devm_iio_trigger_register(struct device *dev, struct iio_trigger *trig_info, struct module *this_mod) { - struct iio_trigger **ptr; int ret; - ptr = devres_alloc(devm_iio_trigger_unreg, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return -ENOMEM; - - *ptr = trig_info; ret = __iio_trigger_register(trig_info, this_mod); - if (!ret) - devres_add(dev, ptr); - else - devres_free(ptr); + if (ret) + return ret; - return ret; + return devm_add_action_or_reset(dev, devm_iio_trigger_unreg, trig_info); } EXPORT_SYMBOL_GPL(__devm_iio_trigger_register); -- cgit v1.2.3 From 7349e8a36caa11c07e71b05f42c384bc540446c8 Mon Sep 17 00:00:00 2001 From: Yicong Yang Date: Thu, 8 Apr 2021 19:38:16 +0800 Subject: iio: inkern: simplify some devm functions Use devm_add_action_or_reset() instead of devres_alloc() and devres_add(), which works the same. This will simplify the code. There is no functional changes. Signed-off-by: Yicong Yang Reviewed-by: Lars-Peter Clausen Reviewed-by: Nuno Sa Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/1617881896-3164-8-git-send-email-yangyicong@hisilicon.com Signed-off-by: Jonathan Cameron --- drivers/iio/inkern.c | 61 ++++++++++++++++++++-------------------------------- 1 file changed, 23 insertions(+), 38 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 9c22697b7e83..5aa740cea661 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -359,30 +359,24 @@ void iio_channel_release(struct iio_channel *channel) } EXPORT_SYMBOL_GPL(iio_channel_release); -static void devm_iio_channel_free(struct device *dev, void *res) +static void devm_iio_channel_free(void *iio_channel) { - struct iio_channel *channel = *(struct iio_channel **)res; - - iio_channel_release(channel); + iio_channel_release(iio_channel); } struct iio_channel *devm_iio_channel_get(struct device *dev, const char *channel_name) { - struct iio_channel **ptr, *channel; - - ptr = devres_alloc(devm_iio_channel_free, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return ERR_PTR(-ENOMEM); + struct iio_channel *channel; + int ret; channel = iio_channel_get(dev, channel_name); - if (IS_ERR(channel)) { - devres_free(ptr); + if (IS_ERR(channel)) return channel; - } - *ptr = channel; - devres_add(dev, ptr); + ret = devm_add_action_or_reset(dev, devm_iio_channel_free, channel); + if (ret) + return ERR_PTR(ret); return channel; } @@ -392,20 +386,16 @@ struct iio_channel *devm_of_iio_channel_get_by_name(struct device *dev, struct device_node *np, const char *channel_name) { - struct iio_channel **ptr, *channel; - - ptr = devres_alloc(devm_iio_channel_free, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return ERR_PTR(-ENOMEM); + struct iio_channel *channel; + int ret; channel = of_iio_channel_get_by_name(np, channel_name); - if (IS_ERR(channel)) { - devres_free(ptr); + if (IS_ERR(channel)) return channel; - } - *ptr = channel; - devres_add(dev, ptr); + ret = devm_add_action_or_reset(dev, devm_iio_channel_free, channel); + if (ret) + return ERR_PTR(ret); return channel; } @@ -496,29 +486,24 @@ void iio_channel_release_all(struct iio_channel *channels) } EXPORT_SYMBOL_GPL(iio_channel_release_all); -static void devm_iio_channel_free_all(struct device *dev, void *res) +static void devm_iio_channel_free_all(void *iio_channels) { - struct iio_channel *channels = *(struct iio_channel **)res; - - iio_channel_release_all(channels); + iio_channel_release_all(iio_channels); } struct iio_channel *devm_iio_channel_get_all(struct device *dev) { - struct iio_channel **ptr, *channels; - - ptr = devres_alloc(devm_iio_channel_free_all, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return ERR_PTR(-ENOMEM); + struct iio_channel *channels; + int ret; channels = iio_channel_get_all(dev); - if (IS_ERR(channels)) { - devres_free(ptr); + if (IS_ERR(channels)) return channels; - } - *ptr = channels; - devres_add(dev, ptr); + ret = devm_add_action_or_reset(dev, devm_iio_channel_free_all, + channels); + if (ret) + return ERR_PTR(ret); return channels; } -- cgit v1.2.3 From 6e5566e72d2a9c81db1ab0effb5cb67ba94637dc Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 1 Apr 2021 15:42:26 +0100 Subject: iio:accel:stk8312: Add lowercase i2c device id These are never upper case. Chances are that all users of this driver were using the ACPI binding but just in case keep the uppercase version but mark it deprecated. Whilst here tidy up some spacing. Signed-off-by: Jonathan Cameron Link: https://lore.kernel.org/r/20210401144226.225928-1-jic23@kernel.org --- drivers/iio/accel/stk8312.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index 157d8faefb9e..60aecfa9fd92 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -635,13 +635,15 @@ static SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend, stk8312_resume); #endif static const struct i2c_device_id stk8312_i2c_id[] = { - {"STK8312", 0}, + /* Deprecated in favour of lowercase form */ + { "STK8312", 0 }, + { "stk8312", 0 }, {} }; MODULE_DEVICE_TABLE(i2c, stk8312_i2c_id); static const struct acpi_device_id stk8312_acpi_id[] = { - {"STK8312", 0}, + { "STK8312", 0 }, {} }; -- cgit v1.2.3 From 7bf50a968a1cd02728e9120ad0216dc80f7a6fb0 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 25 Apr 2021 17:31:53 +0100 Subject: iio:adc:ad7476: Handle the different regulators used by various parts. Not all of the parts supported by this driver use single supply. Hence we add chip_info fields to say what additional supplies exist and in the case of vref, ensure that is used for the reference voltage rather than vcc. One corner case is the ad7091r which has an internal reference that can be over-driven by an external reference connected on the vref pin. To handle that force_ext_vref is introduced and set if an optional vref regulator is present. Tested using really simple QEMU model and some fixed regulators. The devm_add_action_or_reset() callback is changed to take the regulator as it's parameter so we can use one callback for all the different regulators without having to store pointers to them in the iio_priv() structure. Signed-off-by: Jonathan Cameron Cc: Michael Hennerich Reported-by: kernel test robot Reviewed-by: Lars-Peter Clausen Link: https://lore.kernel.org/r/20210425163154.73209-2-jic23@kernel.org --- drivers/iio/adc/ad7476.c | 118 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 103 insertions(+), 15 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index 9e9ff07cf972..9d5a71df02b0 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -32,12 +32,14 @@ struct ad7476_chip_info { /* channels used when convst gpio is defined */ struct iio_chan_spec convst_channel[2]; void (*reset)(struct ad7476_state *); + bool has_vref; + bool has_vdrive; }; struct ad7476_state { struct spi_device *spi; const struct ad7476_chip_info *chip_info; - struct regulator *reg; + struct regulator *ref_reg; struct gpio_desc *convst_gpio; struct spi_transfer xfer; struct spi_message msg; @@ -52,13 +54,17 @@ struct ad7476_state { }; enum ad7476_supported_device_ids { + ID_AD7091, ID_AD7091R, + ID_AD7273, + ID_AD7274, ID_AD7276, ID_AD7277, ID_AD7278, ID_AD7466, ID_AD7467, ID_AD7468, + ID_AD7475, ID_AD7495, ID_AD7940, ID_ADC081S, @@ -145,8 +151,8 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, GENMASK(st->chip_info->channel[0].scan_type.realbits - 1, 0); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - if (!st->chip_info->int_vref_uv) { - scale_uv = regulator_get_voltage(st->reg); + if (st->ref_reg) { + scale_uv = regulator_get_voltage(st->ref_reg); if (scale_uv < 0) return scale_uv; } else { @@ -187,13 +193,32 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, BIT(IIO_CHAN_INFO_RAW)) static const struct ad7476_chip_info ad7476_chip_info_tbl[] = { + [ID_AD7091] = { + .channel[0] = AD7091R_CHAN(12), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + .convst_channel[0] = AD7091R_CONVST_CHAN(12), + .convst_channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + .reset = ad7091_reset, + }, [ID_AD7091R] = { .channel[0] = AD7091R_CHAN(12), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .convst_channel[0] = AD7091R_CONVST_CHAN(12), .convst_channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + .int_vref_uv = 2500000, + .has_vref = true, .reset = ad7091_reset, }, + [ID_AD7273] = { + .channel[0] = AD7940_CHAN(10), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + .has_vref = true, + }, + [ID_AD7274] = { + .channel[0] = AD7940_CHAN(12), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + .has_vref = true, + }, [ID_AD7276] = { .channel[0] = AD7940_CHAN(12), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), @@ -218,10 +243,17 @@ static const struct ad7476_chip_info ad7476_chip_info_tbl[] = { .channel[0] = AD7476_CHAN(8), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, + [ID_AD7475] = { + .channel[0] = AD7476_CHAN(12), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + .has_vref = true, + .has_vdrive = true, + }, [ID_AD7495] = { .channel[0] = AD7476_CHAN(12), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .int_vref_uv = 2500000, + .has_vdrive = true, }, [ID_AD7940] = { .channel[0] = AD7940_CHAN(14), @@ -254,6 +286,7 @@ static const struct ad7476_chip_info ad7476_chip_info_tbl[] = { [ID_LTC2314_14] = { .channel[0] = AD7940_CHAN(14), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + .has_vref = true, }, }; @@ -263,15 +296,16 @@ static const struct iio_info ad7476_info = { static void ad7476_reg_disable(void *data) { - struct ad7476_state *st = data; + struct regulator *reg = data; - regulator_disable(st->reg); + regulator_disable(reg); } static int ad7476_probe(struct spi_device *spi) { struct ad7476_state *st; struct iio_dev *indio_dev; + struct regulator *reg; int ret; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); @@ -282,19 +316,73 @@ static int ad7476_probe(struct spi_device *spi) st->chip_info = &ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data]; - st->reg = devm_regulator_get(&spi->dev, "vcc"); - if (IS_ERR(st->reg)) - return PTR_ERR(st->reg); + reg = devm_regulator_get(&spi->dev, "vcc"); + if (IS_ERR(reg)) + return PTR_ERR(reg); - ret = regulator_enable(st->reg); + ret = regulator_enable(reg); if (ret) return ret; - ret = devm_add_action_or_reset(&spi->dev, ad7476_reg_disable, - st); + ret = devm_add_action_or_reset(&spi->dev, ad7476_reg_disable, reg); if (ret) return ret; + /* Either vcc or vref (below) as appropriate */ + if (!st->chip_info->int_vref_uv) + st->ref_reg = reg; + + if (st->chip_info->has_vref) { + + /* If a device has an internal reference vref is optional */ + if (st->chip_info->int_vref_uv) { + reg = devm_regulator_get_optional(&spi->dev, "vref"); + if (IS_ERR(reg) && (PTR_ERR(reg) != -ENODEV)) + return PTR_ERR(reg); + } else { + reg = devm_regulator_get(&spi->dev, "vref"); + if (IS_ERR(reg)) + return PTR_ERR(reg); + } + + if (!IS_ERR(reg)) { + ret = regulator_enable(reg); + if (ret) + return ret; + + ret = devm_add_action_or_reset(&spi->dev, + ad7476_reg_disable, + reg); + if (ret) + return ret; + st->ref_reg = reg; + } else { + /* + * Can only get here if device supports both internal + * and external reference, but the regulator connected + * to the external reference is not connected. + * Set the reference regulator pointer to NULL to + * indicate this. + */ + st->ref_reg = NULL; + } + } + + if (st->chip_info->has_vdrive) { + reg = devm_regulator_get(&spi->dev, "vdrive"); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + ret = regulator_enable(reg); + if (ret) + return ret; + + ret = devm_add_action_or_reset(&spi->dev, ad7476_reg_disable, + reg); + if (ret) + return ret; + } + st->convst_gpio = devm_gpiod_get_optional(&spi->dev, "adi,conversion-start", GPIOD_OUT_LOW); @@ -333,17 +421,17 @@ static int ad7476_probe(struct spi_device *spi) } static const struct spi_device_id ad7476_id[] = { - {"ad7091", ID_AD7091R}, + {"ad7091", ID_AD7091}, {"ad7091r", ID_AD7091R}, - {"ad7273", ID_AD7277}, - {"ad7274", ID_AD7276}, + {"ad7273", ID_AD7273}, + {"ad7274", ID_AD7274}, {"ad7276", ID_AD7276}, {"ad7277", ID_AD7277}, {"ad7278", ID_AD7278}, {"ad7466", ID_AD7466}, {"ad7467", ID_AD7467}, {"ad7468", ID_AD7468}, - {"ad7475", ID_AD7466}, + {"ad7475", ID_AD7475}, {"ad7476", ID_AD7466}, {"ad7476a", ID_AD7466}, {"ad7477", ID_AD7467}, -- cgit v1.2.3 From 9cc9806e22178e5dbeb4e058df23427454d8d287 Mon Sep 17 00:00:00 2001 From: Tomas Melin Date: Mon, 26 Apr 2021 11:10:41 +0300 Subject: iio: accel: Add driver for Murata SCA3300 accelerometer Add initial support for Murata SCA3300 3-axis industrial accelerometer with digital SPI interface. This device also provides a temperature measurement. Datasheet: https://www.murata.com/en-global/products/sensor/accel/sca3300 Signed-off-by: Tomas Melin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210426081041.59807-3-tomas.melin@vaisala.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 13 ++ drivers/iio/accel/Makefile | 1 + drivers/iio/accel/sca3300.c | 472 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 486 insertions(+) create mode 100644 drivers/iio/accel/sca3300.c (limited to 'drivers/iio') diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 8b1723635cce..ba4ffc2212cb 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -449,6 +449,19 @@ config SCA3000 To compile this driver as a module, say M here: the module will be called sca3000. +config SCA3300 + tristate "Murata SCA3300 3-Axis Accelerometer Driver" + depends on SPI + select CRC8 + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for Murata SCA3300 3-Axis + accelerometer. + + To compile this driver as a module, choose M here: the module will be + called sca3300. + config STK8312 tristate "Sensortek STK8312 3-Axis Accelerometer Driver" depends on I2C diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index 32cd1342a31a..4b56527a2b97 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_MXC4005) += mxc4005.o obj-$(CONFIG_MXC6255) += mxc6255.o obj-$(CONFIG_SCA3000) += sca3000.o +obj-$(CONFIG_SCA3300) += sca3300.o obj-$(CONFIG_STK8312) += stk8312.o obj-$(CONFIG_STK8BA50) += stk8ba50.o diff --git a/drivers/iio/accel/sca3300.c b/drivers/iio/accel/sca3300.c new file mode 100644 index 000000000000..f7ef8ecfd34a --- /dev/null +++ b/drivers/iio/accel/sca3300.c @@ -0,0 +1,472 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Murata SCA3300 3-axis industrial accelerometer + * + * Copyright (c) 2021 Vaisala Oyj. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#define SCA3300_ALIAS "sca3300" + +#define SCA3300_CRC8_POLYNOMIAL 0x1d + +/* Device mode register */ +#define SCA3300_REG_MODE 0xd +#define SCA3300_MODE_SW_RESET 0x20 + +/* Last register in map */ +#define SCA3300_REG_SELBANK 0x1f + +/* Device status and mask */ +#define SCA3300_REG_STATUS 0x6 +#define SCA3300_STATUS_MASK GENMASK(8, 0) + +/* Device ID */ +#define SCA3300_REG_WHOAMI 0x10 +#define SCA3300_WHOAMI_ID 0x51 + +/* Device return status and mask */ +#define SCA3300_VALUE_RS_ERROR 0x3 +#define SCA3300_MASK_RS_STATUS GENMASK(1, 0) + +enum sca3300_scan_indexes { + SCA3300_ACC_X = 0, + SCA3300_ACC_Y, + SCA3300_ACC_Z, + SCA3300_TEMP, + SCA3300_TIMESTAMP, +}; + +#define SCA3300_ACCEL_CHANNEL(index, reg, axis) { \ + .type = IIO_ACCEL, \ + .address = reg, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ + .scan_index = index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + }, \ +} + +static const struct iio_chan_spec sca3300_channels[] = { + SCA3300_ACCEL_CHANNEL(SCA3300_ACC_X, 0x1, X), + SCA3300_ACCEL_CHANNEL(SCA3300_ACC_Y, 0x2, Y), + SCA3300_ACCEL_CHANNEL(SCA3300_ACC_Z, 0x3, Z), + { + .type = IIO_TEMP, + .address = 0x5, + .scan_index = SCA3300_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_CPU, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(4), +}; + +static const int sca3300_lp_freq[] = {70, 70, 70, 10}; +static const int sca3300_accel_scale[][2] = {{0, 370}, {0, 741}, {0, 185}, {0, 185}}; + +static const unsigned long sca3300_scan_masks[] = { + BIT(SCA3300_ACC_X) | BIT(SCA3300_ACC_Y) | BIT(SCA3300_ACC_Z) | + BIT(SCA3300_TEMP), + 0 +}; + +/** + * struct sca3300_data - device data + * @spi: SPI device structure + * @lock: Data buffer lock + * @scan: Triggered buffer. Four channel 16-bit data + 64-bit timestamp + * @txbuf: Transmit buffer + * @rxbuf: Receive buffer + */ +struct sca3300_data { + struct spi_device *spi; + struct mutex lock; + struct { + s16 channels[4]; + s64 ts __aligned(sizeof(s64)); + } scan; + u8 txbuf[4] ____cacheline_aligned; + u8 rxbuf[4]; +}; + +DECLARE_CRC8_TABLE(sca3300_crc_table); + +static int sca3300_transfer(struct sca3300_data *sca_data, int *val) +{ + /* Consecutive requests min. 10 us delay (Datasheet section 5.1.2) */ + struct spi_delay delay = { .value = 10, .unit = SPI_DELAY_UNIT_USECS }; + int32_t ret; + int rs; + u8 crc; + struct spi_transfer xfers[2] = { + { + .tx_buf = sca_data->txbuf, + .len = ARRAY_SIZE(sca_data->txbuf), + .delay = delay, + .cs_change = 1, + }, + { + .rx_buf = sca_data->rxbuf, + .len = ARRAY_SIZE(sca_data->rxbuf), + .delay = delay, + } + }; + + /* inverted crc value as described in device data sheet */ + crc = ~crc8(sca3300_crc_table, &sca_data->txbuf[0], 3, CRC8_INIT_VALUE); + sca_data->txbuf[3] = crc; + + ret = spi_sync_transfer(sca_data->spi, xfers, ARRAY_SIZE(xfers)); + if (ret) { + dev_err(&sca_data->spi->dev, + "transfer error, error: %d\n", ret); + return -EIO; + } + + crc = ~crc8(sca3300_crc_table, &sca_data->rxbuf[0], 3, CRC8_INIT_VALUE); + if (sca_data->rxbuf[3] != crc) { + dev_err(&sca_data->spi->dev, "CRC checksum mismatch"); + return -EIO; + } + + /* get return status */ + rs = sca_data->rxbuf[0] & SCA3300_MASK_RS_STATUS; + if (rs == SCA3300_VALUE_RS_ERROR) + ret = -EINVAL; + + *val = sign_extend32(get_unaligned_be16(&sca_data->rxbuf[1]), 15); + + return ret; +} + +static int sca3300_error_handler(struct sca3300_data *sca_data) +{ + int ret; + int val; + + mutex_lock(&sca_data->lock); + sca_data->txbuf[0] = SCA3300_REG_STATUS << 2; + ret = sca3300_transfer(sca_data, &val); + mutex_unlock(&sca_data->lock); + /* + * Return status error is cleared after reading status register once, + * expect EINVAL here. + */ + if (ret != -EINVAL) { + dev_err(&sca_data->spi->dev, + "error reading device status: %d\n", ret); + return ret; + } + + dev_err(&sca_data->spi->dev, "device status: 0x%lx\n", + val & SCA3300_STATUS_MASK); + + return 0; +} + +static int sca3300_read_reg(struct sca3300_data *sca_data, u8 reg, int *val) +{ + int ret; + + mutex_lock(&sca_data->lock); + sca_data->txbuf[0] = reg << 2; + ret = sca3300_transfer(sca_data, val); + mutex_unlock(&sca_data->lock); + if (ret != -EINVAL) + return ret; + + return sca3300_error_handler(sca_data); +} + +static int sca3300_write_reg(struct sca3300_data *sca_data, u8 reg, int val) +{ + int reg_val = 0; + int ret; + + mutex_lock(&sca_data->lock); + /* BIT(7) for write operation */ + sca_data->txbuf[0] = BIT(7) | (reg << 2); + put_unaligned_be16(val, &sca_data->txbuf[1]); + ret = sca3300_transfer(sca_data, ®_val); + mutex_unlock(&sca_data->lock); + if (ret != -EINVAL) + return ret; + + return sca3300_error_handler(sca_data); +} + +static int sca3300_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct sca3300_data *data = iio_priv(indio_dev); + int reg_val; + int ret; + int i; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + if (val) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(sca3300_accel_scale); i++) { + if (val2 == sca3300_accel_scale[i][1]) + return sca3300_write_reg(data, SCA3300_REG_MODE, i); + } + return -EINVAL; + + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + ret = sca3300_read_reg(data, SCA3300_REG_MODE, ®_val); + if (ret) + return ret; + /* freq. change is possible only for mode 3 and 4 */ + if (reg_val == 2 && val == sca3300_lp_freq[3]) + return sca3300_write_reg(data, SCA3300_REG_MODE, 3); + if (reg_val == 3 && val == sca3300_lp_freq[2]) + return sca3300_write_reg(data, SCA3300_REG_MODE, 2); + return -EINVAL; + default: + return -EINVAL; + } +} + +static int sca3300_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct sca3300_data *data = iio_priv(indio_dev); + int ret; + int reg_val; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = sca3300_read_reg(data, chan->address, val); + if (ret) + return ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + ret = sca3300_read_reg(data, SCA3300_REG_MODE, ®_val); + if (ret) + return ret; + *val = 0; + *val2 = sca3300_accel_scale[reg_val][1]; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + ret = sca3300_read_reg(data, SCA3300_REG_MODE, ®_val); + if (ret) + return ret; + *val = sca3300_lp_freq[reg_val]; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static irqreturn_t sca3300_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct sca3300_data *data = iio_priv(indio_dev); + int bit, ret, val, i = 0; + + for_each_set_bit(bit, indio_dev->active_scan_mask, + indio_dev->masklength) { + ret = sca3300_read_reg(data, sca3300_channels[bit].address, + &val); + if (ret) { + dev_err_ratelimited(&data->spi->dev, + "failed to read register, error: %d\n", ret); + /* handled, but bailing out due to errors */ + goto out; + } + data->scan.channels[i++] = val; + } + + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, + iio_get_time_ns(indio_dev)); +out: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +/* + * sca3300_init - Device init sequence. See datasheet rev 2 section + * 4.2 Start-Up Sequence for details. + */ +static int sca3300_init(struct sca3300_data *sca_data, + struct iio_dev *indio_dev) +{ + int value = 0; + int ret; + + ret = sca3300_write_reg(sca_data, SCA3300_REG_MODE, + SCA3300_MODE_SW_RESET); + if (ret) + return ret; + + /* + * Wait 1ms after SW-reset command. + * Wait 15ms for settling of signal paths. + */ + usleep_range(16e3, 50e3); + + ret = sca3300_read_reg(sca_data, SCA3300_REG_WHOAMI, &value); + if (ret) + return ret; + + if (value != SCA3300_WHOAMI_ID) { + dev_err(&sca_data->spi->dev, + "device id not expected value, %d != %u\n", + value, SCA3300_WHOAMI_ID); + return -ENODEV; + } + return 0; +} + +static int sca3300_debugfs_reg_access(struct iio_dev *indio_dev, + unsigned int reg, unsigned int writeval, + unsigned int *readval) +{ + struct sca3300_data *data = iio_priv(indio_dev); + int value; + int ret; + + if (reg > SCA3300_REG_SELBANK) + return -EINVAL; + + if (!readval) + return sca3300_write_reg(data, reg, writeval); + + ret = sca3300_read_reg(data, reg, &value); + if (ret) + return ret; + + *readval = value; + + return 0; +} + +static int sca3300_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + *vals = (const int *)sca3300_accel_scale; + *length = ARRAY_SIZE(sca3300_accel_scale) * 2 - 2; + *type = IIO_VAL_INT_PLUS_MICRO; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + *vals = &sca3300_lp_freq[2]; + *length = 2; + *type = IIO_VAL_INT; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static const struct iio_info sca3300_info = { + .read_raw = sca3300_read_raw, + .write_raw = sca3300_write_raw, + .debugfs_reg_access = &sca3300_debugfs_reg_access, + .read_avail = sca3300_read_avail, +}; + +static int sca3300_probe(struct spi_device *spi) +{ + struct sca3300_data *sca_data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*sca_data)); + if (!indio_dev) + return -ENOMEM; + + sca_data = iio_priv(indio_dev); + mutex_init(&sca_data->lock); + sca_data->spi = spi; + + crc8_populate_msb(sca3300_crc_table, SCA3300_CRC8_POLYNOMIAL); + + indio_dev->info = &sca3300_info; + indio_dev->name = SCA3300_ALIAS; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = sca3300_channels; + indio_dev->num_channels = ARRAY_SIZE(sca3300_channels); + indio_dev->available_scan_masks = sca3300_scan_masks; + + ret = sca3300_init(sca_data, indio_dev); + if (ret) { + dev_err(&spi->dev, "failed to init device, error: %d\n", ret); + return ret; + } + + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, + iio_pollfunc_store_time, + sca3300_trigger_handler, NULL); + if (ret) { + dev_err(&spi->dev, + "iio triggered buffer setup failed, error: %d\n", ret); + return ret; + } + + ret = devm_iio_device_register(&spi->dev, indio_dev); + if (ret) { + dev_err(&spi->dev, "iio device register failed, error: %d\n", + ret); + } + + return ret; +} + +static const struct of_device_id sca3300_dt_ids[] = { + { .compatible = "murata,sca3300"}, + {} +}; +MODULE_DEVICE_TABLE(of, sca3300_dt_ids); + +static struct spi_driver sca3300_driver = { + .driver = { + .name = SCA3300_ALIAS, + .of_match_table = sca3300_dt_ids, + }, + .probe = sca3300_probe, +}; +module_spi_driver(sca3300_driver); + +MODULE_AUTHOR("Tomas Melin "); +MODULE_DESCRIPTION("Murata SCA3300 SPI Accelerometer"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 00a72db718fa198da3946286dcad222399ccd4fb Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Tue, 27 Apr 2021 10:54:49 +0200 Subject: iio: adis16475: do not return ints in irq handlers On an IRQ handler we should not return normal error codes as 'irqreturn_t' is expected. This is done by jumping to the 'check_burst32' label where we return 'IRQ_HANDLED'. Note that it is fine to do the burst32 check in this error path. If we have proper settings to apply burst32, we might just do the setup now so that the next sample already uses it. Fixes: fff7352bf7a3c ("iio: imu: Add support for adis16475") Reviewed-by: Alexandru Ardelean Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20210427085454.30616-2-nuno.sa@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16475.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index 1de62fc79e0f..51b76444db0b 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -1068,7 +1068,7 @@ static irqreturn_t adis16475_trigger_handler(int irq, void *p) ret = spi_sync(adis->spi, &adis->msg); if (ret) - return ret; + goto check_burst32; adis->spi->max_speed_hz = cached_spi_speed_hz; buffer = adis->buffer; -- cgit v1.2.3 From 0ae157081ca33d4ec5a997b67b8942bd149305b6 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Tue, 27 Apr 2021 10:54:50 +0200 Subject: iio: adis_buffer: update device page after changing it It makes more sense to update the device page as soon as we we successfully changed it. Moreover, a follow up patch will handle 'spi_sync' error path which would leave 'current_page' in a inconsistent state. Signed-off-by: Nuno Sa Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210427085454.30616-3-nuno.sa@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis_buffer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index 0ae551a748eb..4fc0e0ca7561 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -140,6 +140,8 @@ static irqreturn_t adis_trigger_handler(int irq, void *p) mutex_unlock(&adis->state_lock); goto irq_done; } + + adis->current_page = 0; } } @@ -148,10 +150,8 @@ static irqreturn_t adis_trigger_handler(int irq, void *p) dev_err(&adis->spi->dev, "Failed to read data: %d", ret); - if (adis->data->has_paging) { - adis->current_page = 0; + if (adis->data->has_paging) mutex_unlock(&adis->state_lock); - } iio_push_to_buffers_with_timestamp(indio_dev, adis->buffer, pf->timestamp); -- cgit v1.2.3 From 669da56a7eafb9b4025261a07f1d27364159cac9 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Tue, 27 Apr 2021 10:54:51 +0200 Subject: iio: adis_buffer: don't push data to buffers on failure There's no point in pushing data to IIO buffers in case 'spi_sync()' fails. Reviewed-by: Alexandru Ardelean Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20210427085454.30616-4-nuno.sa@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis_buffer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index 4fc0e0ca7561..f6dbfbd17d41 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -146,12 +146,12 @@ static irqreturn_t adis_trigger_handler(int irq, void *p) } ret = spi_sync(adis->spi, &adis->msg); - if (ret) - dev_err(&adis->spi->dev, "Failed to read data: %d", ret); - - if (adis->data->has_paging) mutex_unlock(&adis->state_lock); + if (ret) { + dev_err(&adis->spi->dev, "Failed to read data: %d", ret); + goto irq_done; + } iio_push_to_buffers_with_timestamp(indio_dev, adis->buffer, pf->timestamp); -- cgit v1.2.3 From dbf20809d6e0072ad189c937761d58bf98a47b43 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Tue, 27 Apr 2021 10:54:52 +0200 Subject: iio: adis: add burst_max_speed_hz variable Typically, in burst mode, the device cannot operate at it's full spi speed. Hence, the spi transfers for burst mode have to take this into account. With this change we avoid a potential race with the spi core as drivers were 'hacking' the device 'max_speed_hz' directly in the trigger handler. Reviewed-by: Alexandru Ardelean Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20210427085454.30616-5-nuno.sa@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis_buffer.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/iio') diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index f6dbfbd17d41..351c303c8a8c 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -51,9 +51,13 @@ static int adis_update_scan_mode_burst(struct iio_dev *indio_dev, adis->xfer[0].tx_buf = tx; adis->xfer[0].bits_per_word = 8; adis->xfer[0].len = 2; + if (adis->data->burst_max_speed_hz) + adis->xfer[0].speed_hz = adis->data->burst_max_speed_hz; adis->xfer[1].rx_buf = adis->buffer; adis->xfer[1].bits_per_word = 8; adis->xfer[1].len = burst_length; + if (adis->data->burst_max_speed_hz) + adis->xfer[1].speed_hz = adis->data->burst_max_speed_hz; spi_message_init(&adis->msg); spi_message_add_tail(&adis->xfer[0], &adis->msg); -- cgit v1.2.3 From 256e69ab96934486a9da1c251d276134fdf61e32 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Tue, 27 Apr 2021 10:54:53 +0200 Subject: iio: adis16475: do not directly change spi 'max_speed_hz' With commit 3ba10e37371d ("iio: adis: add burst_max_speed_hz variable"), we just need to define 'burst_max_speed_hz' and the adis core will take care of setting up the spi transfers for burst mode. Hence, we fix a potential race with the spi core where we could be left with an invalid 'max_speed_hz'. Reviewed-by: Alexandru Ardelean Fixes: fff7352bf7a3c ("iio: imu: Add support for adis16475") Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20210427085454.30616-6-nuno.sa@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16475.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index 51b76444db0b..5654c0c15426 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -645,7 +645,8 @@ static int adis16475_enable_irq(struct adis *adis, bool enable) .timeouts = (_timeouts), \ .burst_reg_cmd = ADIS16475_REG_GLOB_CMD, \ .burst_len = ADIS16475_BURST_MAX_DATA, \ - .burst_max_len = ADIS16475_BURST32_MAX_DATA \ + .burst_max_len = ADIS16475_BURST32_MAX_DATA, \ + .burst_max_speed_hz = ADIS16475_BURST_MAX_SPEED \ } static const struct adis16475_sync adis16475_sync_mode[] = { @@ -1062,15 +1063,11 @@ static irqreturn_t adis16475_trigger_handler(int irq, void *p) bool valid; /* offset until the first element after gyro and accel */ const u8 offset = st->burst32 ? 13 : 7; - const u32 cached_spi_speed_hz = adis->spi->max_speed_hz; - - adis->spi->max_speed_hz = ADIS16475_BURST_MAX_SPEED; ret = spi_sync(adis->spi, &adis->msg); if (ret) goto check_burst32; - adis->spi->max_speed_hz = cached_spi_speed_hz; buffer = adis->buffer; crc = be16_to_cpu(buffer[offset + 2]); -- cgit v1.2.3 From b27e1970aa1ed94135cd185d50c3d34b9114d547 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Tue, 27 Apr 2021 10:54:54 +0200 Subject: iio: adis16400: do not directly change spi 'max_speed_hz' With commit 3ba10e37371d ("iio: adis: add burst_max_speed_hz variable"), we just need to define 'burst_max_speed_hz' and the adis core will take care of setting up the spi transfers for burst mode. Hence, we fix a potential race with the spi core where we could be left witn an invalid 'max_speed_hz'. Reviewed-by: Alexandru Ardelean Fixes: 5eda3550a3cc1 ("staging:iio:adis16400: Preallocate transfer message") Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20210427085454.30616-7-nuno.sa@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16400.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c index b2f92b55b910..cb8d3ffab6fc 100644 --- a/drivers/iio/imu/adis16400.c +++ b/drivers/iio/imu/adis16400.c @@ -641,25 +641,13 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct adis16400_state *st = iio_priv(indio_dev); struct adis *adis = &st->adis; - u32 old_speed_hz = st->adis.spi->max_speed_hz; void *buffer; int ret; - if (!(st->variant->flags & ADIS16400_NO_BURST) && - st->adis.spi->max_speed_hz > ADIS16400_SPI_BURST) { - st->adis.spi->max_speed_hz = ADIS16400_SPI_BURST; - spi_setup(st->adis.spi); - } - ret = spi_sync(adis->spi, &adis->msg); if (ret) dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret); - if (!(st->variant->flags & ADIS16400_NO_BURST)) { - st->adis.spi->max_speed_hz = old_speed_hz; - spi_setup(st->adis.spi); - } - if (st->variant->flags & ADIS16400_BURST_DIAG_STAT) buffer = adis->buffer + sizeof(u16); else @@ -965,7 +953,8 @@ static const char * const adis16400_status_error_msgs[] = { BIT(ADIS16400_DIAG_STAT_POWER_LOW), \ .timeouts = (_timeouts), \ .burst_reg_cmd = ADIS16400_GLOB_CMD, \ - .burst_len = (_burst_len) \ + .burst_len = (_burst_len), \ + .burst_max_speed_hz = ADIS16400_SPI_BURST \ } static const struct adis_timeout adis16300_timeouts = { -- cgit v1.2.3 From 8f3f130852785dac0759843835ca97c3bacc2b10 Mon Sep 17 00:00:00 2001 From: Tomasz Duszynski Date: Mon, 3 May 2021 08:00:12 +0200 Subject: iio: sps30: separate core and interface specific code Move code responsible for handling i2c communication to a separate file. Rationale for this change is preparation for adding support for serial communication. Signed-off-by: Tomasz Duszynski Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/Kconfig | 16 ++- drivers/iio/chemical/Makefile | 1 + drivers/iio/chemical/sps30.c | 269 +++++++-------------------------------- drivers/iio/chemical/sps30.h | 35 +++++ drivers/iio/chemical/sps30_i2c.c | 258 +++++++++++++++++++++++++++++++++++++ 5 files changed, 353 insertions(+), 226 deletions(-) create mode 100644 drivers/iio/chemical/sps30.h create mode 100644 drivers/iio/chemical/sps30_i2c.c (limited to 'drivers/iio') diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig index 10bb431bc3ce..2b45a76ab7bc 100644 --- a/drivers/iio/chemical/Kconfig +++ b/drivers/iio/chemical/Kconfig @@ -132,17 +132,21 @@ config SENSIRION_SGP30 module will be called sgp30. config SPS30 - tristate "SPS30 particulate matter sensor" - depends on I2C - select CRC8 + tristate select IIO_BUFFER select IIO_TRIGGERED_BUFFER + +config SPS30_I2C + tristate "SPS30 particulate matter sensor I2C driver" + depends on I2C + select SPS30 + select CRC8 help - Say Y here to build support for the Sensirion SPS30 particulate - matter sensor. + Say Y here to build support for the Sensirion SPS30 I2C interface + driver. To compile this driver as a module, choose M here: the module will - be called sps30. + be called sps30_i2c. config VZ89X tristate "SGX Sensortech MiCS VZ89X VOC sensor" diff --git a/drivers/iio/chemical/Makefile b/drivers/iio/chemical/Makefile index fef63dd5bf92..41c264a229c0 100644 --- a/drivers/iio/chemical/Makefile +++ b/drivers/iio/chemical/Makefile @@ -17,4 +17,5 @@ obj-$(CONFIG_SCD30_I2C) += scd30_i2c.o obj-$(CONFIG_SCD30_SERIAL) += scd30_serial.o obj-$(CONFIG_SENSIRION_SGP30) += sgp30.o obj-$(CONFIG_SPS30) += sps30.o +obj-$(CONFIG_SPS30_I2C) += sps30_i2c.o obj-$(CONFIG_VZ89X) += vz89x.o diff --git a/drivers/iio/chemical/sps30.c b/drivers/iio/chemical/sps30.c index 7486591588c3..d51314505115 100644 --- a/drivers/iio/chemical/sps30.c +++ b/drivers/iio/chemical/sps30.c @@ -3,11 +3,8 @@ * Sensirion SPS30 particulate matter sensor driver * * Copyright (c) Tomasz Duszynski - * - * I2C slave address: 0x69 */ -#include #include #include #include @@ -19,27 +16,14 @@ #include #include -#define SPS30_CRC8_POLYNOMIAL 0x31 -/* max number of bytes needed to store PM measurements or serial string */ -#define SPS30_MAX_READ_SIZE 48 +#include "sps30.h" + /* sensor measures reliably up to 3000 ug / m3 */ #define SPS30_MAX_PM 3000 /* minimum and maximum self cleaning periods in seconds */ #define SPS30_AUTO_CLEANING_PERIOD_MIN 0 #define SPS30_AUTO_CLEANING_PERIOD_MAX 604800 -/* SPS30 commands */ -#define SPS30_START_MEAS 0x0010 -#define SPS30_STOP_MEAS 0x0104 -#define SPS30_RESET 0xd304 -#define SPS30_READ_DATA_READY_FLAG 0x0202 -#define SPS30_READ_DATA 0x0300 -#define SPS30_READ_SERIAL 0xd033 -#define SPS30_START_FAN_CLEANING 0x5607 -#define SPS30_AUTO_CLEANING_PERIOD 0x8004 -/* not a sensor command per se, used only to distinguish write from read */ -#define SPS30_READ_AUTO_CLEANING_PERIOD 0x8005 - enum { PM1, PM2P5, @@ -52,114 +36,9 @@ enum { MEASURING, }; -struct sps30_state { - struct i2c_client *client; - /* - * Guards against concurrent access to sensor registers. - * Must be held whenever sequence of commands is to be executed. - */ - struct mutex lock; - int state; -}; - -DECLARE_CRC8_TABLE(sps30_crc8_table); - -static int sps30_write_then_read(struct sps30_state *state, u8 *txbuf, - int txsize, u8 *rxbuf, int rxsize) -{ - int ret; - - /* - * Sensor does not support repeated start so instead of - * sending two i2c messages in a row we just send one by one. - */ - ret = i2c_master_send(state->client, txbuf, txsize); - if (ret != txsize) - return ret < 0 ? ret : -EIO; - - if (!rxbuf) - return 0; - - ret = i2c_master_recv(state->client, rxbuf, rxsize); - if (ret != rxsize) - return ret < 0 ? ret : -EIO; - - return 0; -} - -static int sps30_do_cmd(struct sps30_state *state, u16 cmd, u8 *data, int size) -{ - /* - * Internally sensor stores measurements in a following manner: - * - * PM1: upper two bytes, crc8, lower two bytes, crc8 - * PM2P5: upper two bytes, crc8, lower two bytes, crc8 - * PM4: upper two bytes, crc8, lower two bytes, crc8 - * PM10: upper two bytes, crc8, lower two bytes, crc8 - * - * What follows next are number concentration measurements and - * typical particle size measurement which we omit. - */ - u8 buf[SPS30_MAX_READ_SIZE] = { cmd >> 8, cmd }; - int i, ret = 0; - - switch (cmd) { - case SPS30_START_MEAS: - buf[2] = 0x03; - buf[3] = 0x00; - buf[4] = crc8(sps30_crc8_table, &buf[2], 2, CRC8_INIT_VALUE); - ret = sps30_write_then_read(state, buf, 5, NULL, 0); - break; - case SPS30_STOP_MEAS: - case SPS30_RESET: - case SPS30_START_FAN_CLEANING: - ret = sps30_write_then_read(state, buf, 2, NULL, 0); - break; - case SPS30_READ_AUTO_CLEANING_PERIOD: - buf[0] = SPS30_AUTO_CLEANING_PERIOD >> 8; - buf[1] = (u8)(SPS30_AUTO_CLEANING_PERIOD & 0xff); - fallthrough; - case SPS30_READ_DATA_READY_FLAG: - case SPS30_READ_DATA: - case SPS30_READ_SERIAL: - /* every two data bytes are checksummed */ - size += size / 2; - ret = sps30_write_then_read(state, buf, 2, buf, size); - break; - case SPS30_AUTO_CLEANING_PERIOD: - buf[2] = data[0]; - buf[3] = data[1]; - buf[4] = crc8(sps30_crc8_table, &buf[2], 2, CRC8_INIT_VALUE); - buf[5] = data[2]; - buf[6] = data[3]; - buf[7] = crc8(sps30_crc8_table, &buf[5], 2, CRC8_INIT_VALUE); - ret = sps30_write_then_read(state, buf, 8, NULL, 0); - break; - } - - if (ret) - return ret; - - /* validate received data and strip off crc bytes */ - for (i = 0; i < size; i += 3) { - u8 crc = crc8(sps30_crc8_table, &buf[i], 2, CRC8_INIT_VALUE); - - if (crc != buf[i + 2]) { - dev_err(&state->client->dev, - "data integrity check failed\n"); - return -EIO; - } - - *data++ = buf[i]; - *data++ = buf[i + 1]; - } - - return 0; -} - -static s32 sps30_float_to_int_clamped(const u8 *fp) +static s32 sps30_float_to_int_clamped(__be32 *fp) { - int val = get_unaligned_be32(fp); + int val = be32_to_cpup(fp); int mantissa = val & GENMASK(22, 0); /* this is fine since passed float is always non-negative */ int exp = val >> 23; @@ -188,38 +67,35 @@ static s32 sps30_float_to_int_clamped(const u8 *fp) static int sps30_do_meas(struct sps30_state *state, s32 *data, int size) { - int i, ret, tries = 5; - u8 tmp[16]; + int i, ret; if (state->state == RESET) { - ret = sps30_do_cmd(state, SPS30_START_MEAS, NULL, 0); + ret = state->ops->start_meas(state); if (ret) return ret; state->state = MEASURING; } - while (tries--) { - ret = sps30_do_cmd(state, SPS30_READ_DATA_READY_FLAG, tmp, 2); - if (ret) - return -EIO; + ret = state->ops->read_meas(state, (__be32 *)data, size); + if (ret) + return ret; - /* new measurements ready to be read */ - if (tmp[1] == 1) - break; + for (i = 0; i < size; i++) + data[i] = sps30_float_to_int_clamped((__be32 *)&data[i]); - msleep_interruptible(300); - } + return 0; +} - if (tries == -1) - return -ETIMEDOUT; +static int sps30_do_reset(struct sps30_state *state) +{ + int ret; - ret = sps30_do_cmd(state, SPS30_READ_DATA, tmp, sizeof(int) * size); + ret = state->ops->reset(state); if (ret) return ret; - for (i = 0; i < size; i++) - data[i] = sps30_float_to_int_clamped(&tmp[4 * i]); + state->state = RESET; return 0; } @@ -310,24 +186,6 @@ static int sps30_read_raw(struct iio_dev *indio_dev, return -EINVAL; } -static int sps30_do_cmd_reset(struct sps30_state *state) -{ - int ret; - - ret = sps30_do_cmd(state, SPS30_RESET, NULL, 0); - msleep(300); - /* - * Power-on-reset causes sensor to produce some glitch on i2c bus and - * some controllers end up in error state. Recover simply by placing - * some data on the bus, for example STOP_MEAS command, which - * is NOP in this case. - */ - sps30_do_cmd(state, SPS30_STOP_MEAS, NULL, 0); - state->state = RESET; - - return ret; -} - static ssize_t start_cleaning_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) @@ -340,7 +198,7 @@ static ssize_t start_cleaning_store(struct device *dev, return -EINVAL; mutex_lock(&state->lock); - ret = sps30_do_cmd(state, SPS30_START_FAN_CLEANING, NULL, 0); + ret = state->ops->clean_fan(state); mutex_unlock(&state->lock); if (ret) return ret; @@ -349,31 +207,29 @@ static ssize_t start_cleaning_store(struct device *dev, } static ssize_t cleaning_period_show(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct sps30_state *state = iio_priv(indio_dev); - u8 tmp[4]; + __be32 val; int ret; mutex_lock(&state->lock); - ret = sps30_do_cmd(state, SPS30_READ_AUTO_CLEANING_PERIOD, tmp, 4); + ret = state->ops->read_cleaning_period(state, &val); mutex_unlock(&state->lock); if (ret) return ret; - return sprintf(buf, "%d\n", get_unaligned_be32(tmp)); + return sprintf(buf, "%d\n", be32_to_cpu(val)); } -static ssize_t cleaning_period_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) +static ssize_t cleaning_period_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct sps30_state *state = iio_priv(indio_dev); int val, ret; - u8 tmp[4]; if (kstrtoint(buf, 0, &val)) return -EINVAL; @@ -382,10 +238,8 @@ static ssize_t cleaning_period_store(struct device *dev, (val > SPS30_AUTO_CLEANING_PERIOD_MAX)) return -EINVAL; - put_unaligned_be32(val, tmp); - mutex_lock(&state->lock); - ret = sps30_do_cmd(state, SPS30_AUTO_CLEANING_PERIOD, tmp, 0); + ret = state->ops->write_cleaning_period(state, cpu_to_be32(val)); if (ret) { mutex_unlock(&state->lock); return ret; @@ -397,7 +251,7 @@ static ssize_t cleaning_period_store(struct device *dev, * sensor requires reset in order to return up to date self cleaning * period */ - ret = sps30_do_cmd_reset(state); + ret = sps30_do_reset(state); if (ret) dev_warn(dev, "period changed but reads will return the old value\n"); @@ -460,90 +314,65 @@ static const struct iio_chan_spec sps30_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(4), }; -static void sps30_stop_meas(void *data) +static void sps30_devm_stop_meas(void *data) { struct sps30_state *state = data; - sps30_do_cmd(state, SPS30_STOP_MEAS, NULL, 0); + if (state->state == MEASURING) + state->ops->stop_meas(state); } static const unsigned long sps30_scan_masks[] = { 0x0f, 0x00 }; -static int sps30_probe(struct i2c_client *client) +int sps30_probe(struct device *dev, const char *name, void *priv, const struct sps30_ops *ops) { struct iio_dev *indio_dev; struct sps30_state *state; - u8 buf[32]; int ret; - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) - return -EOPNOTSUPP; - - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*state)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*state)); if (!indio_dev) return -ENOMEM; + dev_set_drvdata(dev, indio_dev); + state = iio_priv(indio_dev); - i2c_set_clientdata(client, indio_dev); - state->client = client; - state->state = RESET; + state->dev = dev; + state->priv = priv; + state->ops = ops; + mutex_init(&state->lock); + indio_dev->info = &sps30_info; - indio_dev->name = client->name; + indio_dev->name = name; indio_dev->channels = sps30_channels; indio_dev->num_channels = ARRAY_SIZE(sps30_channels); indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->available_scan_masks = sps30_scan_masks; - mutex_init(&state->lock); - crc8_populate_msb(sps30_crc8_table, SPS30_CRC8_POLYNOMIAL); - - ret = sps30_do_cmd_reset(state); + ret = sps30_do_reset(state); if (ret) { - dev_err(&client->dev, "failed to reset device\n"); + dev_err(dev, "failed to reset device\n"); return ret; } - ret = sps30_do_cmd(state, SPS30_READ_SERIAL, buf, sizeof(buf)); + ret = state->ops->show_info(state); if (ret) { - dev_err(&client->dev, "failed to read serial number\n"); + dev_err(dev, "failed to read device info\n"); return ret; } - /* returned serial number is already NUL terminated */ - dev_info(&client->dev, "serial number: %s\n", buf); - ret = devm_add_action_or_reset(&client->dev, sps30_stop_meas, state); + ret = devm_add_action_or_reset(dev, sps30_devm_stop_meas, state); if (ret) return ret; - ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL, + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, sps30_trigger_handler, NULL); if (ret) return ret; - return devm_iio_device_register(&client->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } - -static const struct i2c_device_id sps30_id[] = { - { "sps30" }, - { } -}; -MODULE_DEVICE_TABLE(i2c, sps30_id); - -static const struct of_device_id sps30_of_match[] = { - { .compatible = "sensirion,sps30" }, - { } -}; -MODULE_DEVICE_TABLE(of, sps30_of_match); - -static struct i2c_driver sps30_driver = { - .driver = { - .name = "sps30", - .of_match_table = sps30_of_match, - }, - .id_table = sps30_id, - .probe_new = sps30_probe, -}; -module_i2c_driver(sps30_driver); +EXPORT_SYMBOL_GPL(sps30_probe); MODULE_AUTHOR("Tomasz Duszynski "); MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor driver"); diff --git a/drivers/iio/chemical/sps30.h b/drivers/iio/chemical/sps30.h new file mode 100644 index 000000000000..a58ee43cf45d --- /dev/null +++ b/drivers/iio/chemical/sps30.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _SPS30_H +#define _SPS30_H + +#include + +struct sps30_state; +struct sps30_ops { + int (*start_meas)(struct sps30_state *state); + int (*stop_meas)(struct sps30_state *state); + int (*read_meas)(struct sps30_state *state, __be32 *meas, size_t num); + int (*reset)(struct sps30_state *state); + int (*clean_fan)(struct sps30_state *state); + int (*read_cleaning_period)(struct sps30_state *state, __be32 *period); + int (*write_cleaning_period)(struct sps30_state *state, __be32 period); + int (*show_info)(struct sps30_state *state); +}; + +struct sps30_state { + /* serialize access to the device */ + struct mutex lock; + struct device *dev; + int state; + /* + * priv pointer is solely for serdev driver private data. We keep it + * here because driver_data inside dev has been already used for iio and + * struct serdev_device doesn't have one. + */ + void *priv; + const struct sps30_ops *ops; +}; + +int sps30_probe(struct device *dev, const char *name, void *priv, const struct sps30_ops *ops); + +#endif diff --git a/drivers/iio/chemical/sps30_i2c.c b/drivers/iio/chemical/sps30_i2c.c new file mode 100644 index 000000000000..d33560ed7184 --- /dev/null +++ b/drivers/iio/chemical/sps30_i2c.c @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sensirion SPS30 particulate matter sensor i2c driver + * + * Copyright (c) 2020 Tomasz Duszynski + * + * I2C slave address: 0x69 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sps30.h" + +#define SPS30_I2C_CRC8_POLYNOMIAL 0x31 +/* max number of bytes needed to store PM measurements or serial string */ +#define SPS30_I2C_MAX_BUF_SIZE 48 + +DECLARE_CRC8_TABLE(sps30_i2c_crc8_table); + +#define SPS30_I2C_START_MEAS 0x0010 +#define SPS30_I2C_STOP_MEAS 0x0104 +#define SPS30_I2C_READ_MEAS 0x0300 +#define SPS30_I2C_MEAS_READY 0x0202 +#define SPS30_I2C_RESET 0xd304 +#define SPS30_I2C_CLEAN_FAN 0x5607 +#define SPS30_I2C_PERIOD 0x8004 +#define SPS30_I2C_READ_SERIAL 0xd033 +#define SPS30_I2C_READ_VERSION 0xd100 + +static int sps30_i2c_xfer(struct sps30_state *state, unsigned char *txbuf, size_t txsize, + unsigned char *rxbuf, size_t rxsize) +{ + struct i2c_client *client = to_i2c_client(state->dev); + int ret; + + /* + * Sensor does not support repeated start so instead of + * sending two i2c messages in a row we just send one by one. + */ + ret = i2c_master_send(client, txbuf, txsize); + if (ret < 0) + return ret; + if (ret != txsize) + return -EIO; + + if (!rxsize) + return 0; + + ret = i2c_master_recv(client, rxbuf, rxsize); + if (ret < 0) + return ret; + if (ret != rxsize) + return -EIO; + + return 0; +} + +static int sps30_i2c_command(struct sps30_state *state, u16 cmd, void *arg, size_t arg_size, + void *rsp, size_t rsp_size) +{ + /* + * Internally sensor stores measurements in a following manner: + * + * PM1: upper two bytes, crc8, lower two bytes, crc8 + * PM2P5: upper two bytes, crc8, lower two bytes, crc8 + * PM4: upper two bytes, crc8, lower two bytes, crc8 + * PM10: upper two bytes, crc8, lower two bytes, crc8 + * + * What follows next are number concentration measurements and + * typical particle size measurement which we omit. + */ + unsigned char buf[SPS30_I2C_MAX_BUF_SIZE]; + unsigned char *tmp; + unsigned char crc; + size_t i; + int ret; + + put_unaligned_be16(cmd, buf); + i = 2; + + if (rsp) { + /* each two bytes are followed by a crc8 */ + rsp_size += rsp_size / 2; + } else { + tmp = arg; + + while (arg_size) { + buf[i] = *tmp++; + buf[i + 1] = *tmp++; + buf[i + 2] = crc8(sps30_i2c_crc8_table, buf + i, 2, CRC8_INIT_VALUE); + arg_size -= 2; + i += 3; + } + } + + ret = sps30_i2c_xfer(state, buf, i, buf, rsp_size); + if (ret) + return ret; + + /* validate received data and strip off crc bytes */ + tmp = rsp; + for (i = 0; i < rsp_size; i += 3) { + crc = crc8(sps30_i2c_crc8_table, buf + i, 2, CRC8_INIT_VALUE); + if (crc != buf[i + 2]) { + dev_err(state->dev, "data integrity check failed\n"); + return -EIO; + } + + *tmp++ = buf[i]; + *tmp++ = buf[i + 1]; + } + + return 0; +} + +static int sps30_i2c_start_meas(struct sps30_state *state) +{ + /* request BE IEEE754 formatted data */ + unsigned char buf[] = { 0x03, 0x00 }; + + return sps30_i2c_command(state, SPS30_I2C_START_MEAS, buf, sizeof(buf), NULL, 0); +} + +static int sps30_i2c_stop_meas(struct sps30_state *state) +{ + return sps30_i2c_command(state, SPS30_I2C_STOP_MEAS, NULL, 0, NULL, 0); +} + +static int sps30_i2c_reset(struct sps30_state *state) +{ + int ret; + + ret = sps30_i2c_command(state, SPS30_I2C_RESET, NULL, 0, NULL, 0); + msleep(500); + /* + * Power-on-reset causes sensor to produce some glitch on i2c bus and + * some controllers end up in error state. Recover simply by placing + * some data on the bus, for example STOP_MEAS command, which + * is NOP in this case. + */ + sps30_i2c_stop_meas(state); + + return ret; +} + +static bool sps30_i2c_meas_ready(struct sps30_state *state) +{ + unsigned char buf[2]; + int ret; + + ret = sps30_i2c_command(state, SPS30_I2C_MEAS_READY, NULL, 0, buf, sizeof(buf)); + if (ret) + return false; + + return buf[1]; +} + +static int sps30_i2c_read_meas(struct sps30_state *state, __be32 *meas, size_t num) +{ + /* measurements are ready within a second */ + if (msleep_interruptible(1000)) + return -EINTR; + + if (!sps30_i2c_meas_ready(state)) + return -ETIMEDOUT; + + return sps30_i2c_command(state, SPS30_I2C_READ_MEAS, NULL, 0, meas, sizeof(num) * num); +} + +static int sps30_i2c_clean_fan(struct sps30_state *state) +{ + return sps30_i2c_command(state, SPS30_I2C_CLEAN_FAN, NULL, 0, NULL, 0); +} + +static int sps30_i2c_read_cleaning_period(struct sps30_state *state, __be32 *period) +{ + return sps30_i2c_command(state, SPS30_I2C_PERIOD, NULL, 0, period, sizeof(*period)); +} + +static int sps30_i2c_write_cleaning_period(struct sps30_state *state, __be32 period) +{ + return sps30_i2c_command(state, SPS30_I2C_PERIOD, &period, sizeof(period), NULL, 0); +} + +static int sps30_i2c_show_info(struct sps30_state *state) +{ + /* extra nul just in case */ + unsigned char buf[32 + 1] = { 0x00 }; + int ret; + + ret = sps30_i2c_command(state, SPS30_I2C_READ_SERIAL, NULL, 0, buf, sizeof(buf) - 1); + if (ret) + return ret; + + dev_info(state->dev, "serial number: %s\n", buf); + + ret = sps30_i2c_command(state, SPS30_I2C_READ_VERSION, NULL, 0, buf, 2); + if (ret) + return ret; + + dev_info(state->dev, "fw version: %u.%u\n", buf[0], buf[1]); + + return 0; +} + +static const struct sps30_ops sps30_i2c_ops = { + .start_meas = sps30_i2c_start_meas, + .stop_meas = sps30_i2c_stop_meas, + .read_meas = sps30_i2c_read_meas, + .reset = sps30_i2c_reset, + .clean_fan = sps30_i2c_clean_fan, + .read_cleaning_period = sps30_i2c_read_cleaning_period, + .write_cleaning_period = sps30_i2c_write_cleaning_period, + .show_info = sps30_i2c_show_info, +}; + +static int sps30_i2c_probe(struct i2c_client *client) +{ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -EOPNOTSUPP; + + crc8_populate_msb(sps30_i2c_crc8_table, SPS30_I2C_CRC8_POLYNOMIAL); + + return sps30_probe(&client->dev, client->name, NULL, &sps30_i2c_ops); +} + +static const struct i2c_device_id sps30_i2c_id[] = { + { "sps30" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sps30_i2c_id); + +static const struct of_device_id sps30_i2c_of_match[] = { + { .compatible = "sensirion,sps30" }, + { } +}; +MODULE_DEVICE_TABLE(of, sps30_i2c_of_match); + +static struct i2c_driver sps30_i2c_driver = { + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = sps30_i2c_of_match, + }, + .id_table = sps30_i2c_id, + .probe_new = sps30_i2c_probe, +}; +module_i2c_driver(sps30_i2c_driver); + +MODULE_AUTHOR("Tomasz Duszynski "); +MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor i2c driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From b2e171f5a5c6003bd2e9a8f7dfd8acf714af429b Mon Sep 17 00:00:00 2001 From: Tomasz Duszynski Date: Mon, 3 May 2021 08:00:13 +0200 Subject: iio: sps30: add support for serial interface Sensor has support for both i2c and serial communication interfaces. Both offer very similar set of features. Minor differences don't impact overall functionality like doing measurements, etc. Support for i2c have already been added, this patch adds support for the latter ie. serial interface. Signed-off-by: Tomasz Duszynski Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/Kconfig | 11 + drivers/iio/chemical/Makefile | 1 + drivers/iio/chemical/sps30_serial.c | 431 ++++++++++++++++++++++++++++++++++++ 3 files changed, 443 insertions(+) create mode 100644 drivers/iio/chemical/sps30_serial.c (limited to 'drivers/iio') diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig index 2b45a76ab7bc..a4920646e9be 100644 --- a/drivers/iio/chemical/Kconfig +++ b/drivers/iio/chemical/Kconfig @@ -148,6 +148,17 @@ config SPS30_I2C To compile this driver as a module, choose M here: the module will be called sps30_i2c. +config SPS30_SERIAL + tristate "SPS30 particulate matter sensor serial driver" + depends on SERIAL_DEV_BUS + select SPS30 + help + Say Y here to build support for the Sensirion SPS30 serial interface + driver. + + To compile this driver as a module, choose M here: the module will + be called sps30_serial. + config VZ89X tristate "SGX Sensortech MiCS VZ89X VOC sensor" depends on I2C diff --git a/drivers/iio/chemical/Makefile b/drivers/iio/chemical/Makefile index 41c264a229c0..4898690cc155 100644 --- a/drivers/iio/chemical/Makefile +++ b/drivers/iio/chemical/Makefile @@ -18,4 +18,5 @@ obj-$(CONFIG_SCD30_SERIAL) += scd30_serial.o obj-$(CONFIG_SENSIRION_SGP30) += sgp30.o obj-$(CONFIG_SPS30) += sps30.o obj-$(CONFIG_SPS30_I2C) += sps30_i2c.o +obj-$(CONFIG_SPS30_SERIAL) += sps30_serial.o obj-$(CONFIG_VZ89X) += vz89x.o diff --git a/drivers/iio/chemical/sps30_serial.c b/drivers/iio/chemical/sps30_serial.c new file mode 100644 index 000000000000..3f311d50087c --- /dev/null +++ b/drivers/iio/chemical/sps30_serial.c @@ -0,0 +1,431 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sensirion SPS30 particulate matter sensor serial driver + * + * Copyright (c) 2021 Tomasz Duszynski + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sps30.h" + +#define SPS30_SERIAL_DEV_NAME "sps30" + +#define SPS30_SERIAL_SOF_EOF 0x7e +#define SPS30_SERIAL_TIMEOUT msecs_to_jiffies(20) +#define SPS30_SERIAL_MAX_BUF_SIZE 263 +#define SPS30_SERIAL_ESCAPE_CHAR 0x7d + +#define SPS30_SERIAL_FRAME_MIN_SIZE 7 +#define SPS30_SERIAL_FRAME_ADR_OFFSET 1 +#define SPS30_SERIAL_FRAME_CMD_OFFSET 2 +#define SPS30_SERIAL_FRAME_MOSI_LEN_OFFSET 3 +#define SPS30_SERIAL_FRAME_MISO_STATE_OFFSET 3 +#define SPS30_SERIAL_FRAME_MISO_LEN_OFFSET 4 +#define SPS30_SERIAL_FRAME_MISO_DATA_OFFSET 5 + +#define SPS30_SERIAL_START_MEAS 0x00 +#define SPS30_SERIAL_STOP_MEAS 0x01 +#define SPS30_SERIAL_READ_MEAS 0x03 +#define SPS30_SERIAL_RESET 0xd3 +#define SPS30_SERIAL_CLEAN_FAN 0x56 +#define SPS30_SERIAL_PERIOD 0x80 +#define SPS30_SERIAL_DEV_INFO 0xd0 +#define SPS30_SERIAL_READ_VERSION 0xd1 + +struct sps30_serial_priv { + struct completion new_frame; + unsigned char buf[SPS30_SERIAL_MAX_BUF_SIZE]; + size_t num; + bool escaped; + bool done; +}; + +static int sps30_serial_xfer(struct sps30_state *state, const unsigned char *buf, size_t size) +{ + struct serdev_device *serdev = to_serdev_device(state->dev); + struct sps30_serial_priv *priv = state->priv; + int ret; + + priv->num = 0; + priv->escaped = false; + priv->done = false; + + ret = serdev_device_write(serdev, buf, size, SPS30_SERIAL_TIMEOUT); + if (ret < 0) + return ret; + if (ret != size) + return -EIO; + + ret = wait_for_completion_interruptible_timeout(&priv->new_frame, SPS30_SERIAL_TIMEOUT); + if (ret < 0) + return ret; + if (!ret) + return -ETIMEDOUT; + + return 0; +} + +static const struct { + unsigned char byte; + unsigned char byte2; +} sps30_serial_bytes[] = { + { 0x11, 0x31 }, + { 0x13, 0x33 }, + { 0x7e, 0x5e }, + { 0x7d, 0x5d }, +}; + +static int sps30_serial_put_byte(unsigned char *buf, unsigned char byte) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sps30_serial_bytes); i++) { + if (sps30_serial_bytes[i].byte != byte) + continue; + + buf[0] = SPS30_SERIAL_ESCAPE_CHAR; + buf[1] = sps30_serial_bytes[i].byte2; + + return 2; + } + + buf[0] = byte; + + return 1; +} + +static char sps30_serial_get_byte(bool escaped, unsigned char byte2) +{ + int i; + + if (!escaped) + return byte2; + + for (i = 0; i < ARRAY_SIZE(sps30_serial_bytes); i++) { + if (sps30_serial_bytes[i].byte2 != byte2) + continue; + + return sps30_serial_bytes[i].byte; + } + + return 0; +} + +static unsigned char sps30_serial_calc_chksum(const unsigned char *buf, size_t num) +{ + unsigned int chksum = 0; + size_t i; + + for (i = 0; i < num; i++) + chksum += buf[i]; + + return ~chksum; +} + +static int sps30_serial_prep_frame(unsigned char *buf, unsigned char cmd, + const unsigned char *arg, size_t arg_size) +{ + unsigned char chksum; + int num = 0; + size_t i; + + buf[num++] = SPS30_SERIAL_SOF_EOF; + buf[num++] = 0; + num += sps30_serial_put_byte(buf + num, cmd); + num += sps30_serial_put_byte(buf + num, arg_size); + + for (i = 0; i < arg_size; i++) + num += sps30_serial_put_byte(buf + num, arg[i]); + + /* SOF isn't checksummed */ + chksum = sps30_serial_calc_chksum(buf + 1, num - 1); + num += sps30_serial_put_byte(buf + num, chksum); + buf[num++] = SPS30_SERIAL_SOF_EOF; + + return num; +} + +static bool sps30_serial_frame_valid(struct sps30_state *state, const unsigned char *buf) +{ + struct sps30_serial_priv *priv = state->priv; + unsigned char chksum; + + if ((priv->num < SPS30_SERIAL_FRAME_MIN_SIZE) || + (priv->num != SPS30_SERIAL_FRAME_MIN_SIZE + + priv->buf[SPS30_SERIAL_FRAME_MISO_LEN_OFFSET])) { + dev_err(state->dev, "frame has invalid number of bytes\n"); + return false; + } + + if ((priv->buf[SPS30_SERIAL_FRAME_ADR_OFFSET] != buf[SPS30_SERIAL_FRAME_ADR_OFFSET]) || + (priv->buf[SPS30_SERIAL_FRAME_CMD_OFFSET] != buf[SPS30_SERIAL_FRAME_CMD_OFFSET])) { + dev_err(state->dev, "frame has wrong ADR and CMD bytes\n"); + return false; + } + + if (priv->buf[SPS30_SERIAL_FRAME_MISO_STATE_OFFSET]) { + dev_err(state->dev, "frame with non-zero state received (0x%02x)\n", + priv->buf[SPS30_SERIAL_FRAME_MISO_STATE_OFFSET]); + return false; + } + + /* SOF, checksum and EOF are not checksummed */ + chksum = sps30_serial_calc_chksum(priv->buf + 1, priv->num - 3); + if (priv->buf[priv->num - 2] != chksum) { + dev_err(state->dev, "frame integrity check failed\n"); + return false; + } + + return true; +} + +static int sps30_serial_command(struct sps30_state *state, unsigned char cmd, + const void *arg, size_t arg_size, void *rsp, size_t rsp_size) +{ + struct sps30_serial_priv *priv = state->priv; + unsigned char buf[SPS30_SERIAL_MAX_BUF_SIZE]; + int ret, size; + + size = sps30_serial_prep_frame(buf, cmd, arg, arg_size); + ret = sps30_serial_xfer(state, buf, size); + if (ret) + return ret; + + if (!sps30_serial_frame_valid(state, buf)) + return -EIO; + + if (rsp) { + rsp_size = min_t(size_t, priv->buf[SPS30_SERIAL_FRAME_MISO_LEN_OFFSET], rsp_size); + memcpy(rsp, &priv->buf[SPS30_SERIAL_FRAME_MISO_DATA_OFFSET], rsp_size); + } + + return rsp_size; +} + +static int sps30_serial_receive_buf(struct serdev_device *serdev, + const unsigned char *buf, size_t size) +{ + struct iio_dev *indio_dev = dev_get_drvdata(&serdev->dev); + struct sps30_serial_priv *priv; + struct sps30_state *state; + unsigned char byte; + size_t i; + + if (!indio_dev) + return 0; + + state = iio_priv(indio_dev); + priv = state->priv; + + /* just in case device put some unexpected data on the bus */ + if (priv->done) + return size; + + /* wait for the start of frame */ + if (!priv->num && size && buf[0] != SPS30_SERIAL_SOF_EOF) + return 1; + + if (priv->num + size >= ARRAY_SIZE(priv->buf)) + size = ARRAY_SIZE(priv->buf) - priv->num; + + for (i = 0; i < size; i++) { + byte = buf[i]; + /* remove stuffed bytes on-the-fly */ + if (byte == SPS30_SERIAL_ESCAPE_CHAR) { + priv->escaped = true; + continue; + } + + byte = sps30_serial_get_byte(priv->escaped, byte); + if (priv->escaped && !byte) + dev_warn(state->dev, "unrecognized escaped char (0x%02x)\n", byte); + + priv->buf[priv->num++] = byte; + + /* EOF received */ + if (!priv->escaped && byte == SPS30_SERIAL_SOF_EOF) { + if (priv->num < SPS30_SERIAL_FRAME_MIN_SIZE) + continue; + + priv->done = true; + complete(&priv->new_frame); + i++; + break; + } + + priv->escaped = false; + } + + return i; +} + +static const struct serdev_device_ops sps30_serial_device_ops = { + .receive_buf = sps30_serial_receive_buf, + .write_wakeup = serdev_device_write_wakeup, +}; + +static int sps30_serial_start_meas(struct sps30_state *state) +{ + /* request BE IEEE754 formatted data */ + unsigned char buf[] = { 0x01, 0x03 }; + + return sps30_serial_command(state, SPS30_SERIAL_START_MEAS, buf, sizeof(buf), NULL, 0); +} + +static int sps30_serial_stop_meas(struct sps30_state *state) +{ + return sps30_serial_command(state, SPS30_SERIAL_STOP_MEAS, NULL, 0, NULL, 0); +} + +static int sps30_serial_reset(struct sps30_state *state) +{ + int ret; + + ret = sps30_serial_command(state, SPS30_SERIAL_RESET, NULL, 0, NULL, 0); + msleep(500); + + return ret; +} + +static int sps30_serial_read_meas(struct sps30_state *state, __be32 *meas, size_t num) +{ + int ret; + + /* measurements are ready within a second */ + if (msleep_interruptible(1000)) + return -EINTR; + + ret = sps30_serial_command(state, SPS30_SERIAL_READ_MEAS, NULL, 0, meas, num * sizeof(num)); + if (ret < 0) + return ret; + /* if measurements aren't ready sensor returns empty frame */ + if (ret == SPS30_SERIAL_FRAME_MIN_SIZE) + return -ETIMEDOUT; + if (ret != num * sizeof(*meas)) + return -EIO; + + return 0; +} + +static int sps30_serial_clean_fan(struct sps30_state *state) +{ + return sps30_serial_command(state, SPS30_SERIAL_CLEAN_FAN, NULL, 0, NULL, 0); +} + +static int sps30_serial_read_cleaning_period(struct sps30_state *state, __be32 *period) +{ + unsigned char buf[] = { 0x00 }; + int ret; + + ret = sps30_serial_command(state, SPS30_SERIAL_PERIOD, buf, sizeof(buf), + period, sizeof(*period)); + if (ret < 0) + return ret; + if (ret != sizeof(*period)) + return -EIO; + + return 0; +} + +static int sps30_serial_write_cleaning_period(struct sps30_state *state, __be32 period) +{ + unsigned char buf[5] = { 0x00 }; + + memcpy(buf + 1, &period, sizeof(period)); + + return sps30_serial_command(state, SPS30_SERIAL_PERIOD, buf, sizeof(buf), NULL, 0); +} + +static int sps30_serial_show_info(struct sps30_state *state) +{ + /* + * tell device do return serial number and add extra nul byte just in case + * serial number isn't a valid string + */ + unsigned char buf[32 + 1] = { 0x03 }; + struct device *dev = state->dev; + int ret; + + ret = sps30_serial_command(state, SPS30_SERIAL_DEV_INFO, buf, 1, buf, sizeof(buf) - 1); + if (ret < 0) + return ret; + if (ret != sizeof(buf) - 1) + return -EIO; + + dev_info(dev, "serial number: %s\n", buf); + + ret = sps30_serial_command(state, SPS30_SERIAL_READ_VERSION, NULL, 0, buf, sizeof(buf) - 1); + if (ret < 0) + return ret; + if (ret < 2) + return -EIO; + + dev_info(dev, "fw version: %u.%u\n", buf[0], buf[1]); + + return 0; +} + +static const struct sps30_ops sps30_serial_ops = { + .start_meas = sps30_serial_start_meas, + .stop_meas = sps30_serial_stop_meas, + .read_meas = sps30_serial_read_meas, + .reset = sps30_serial_reset, + .clean_fan = sps30_serial_clean_fan, + .read_cleaning_period = sps30_serial_read_cleaning_period, + .write_cleaning_period = sps30_serial_write_cleaning_period, + .show_info = sps30_serial_show_info, +}; + +static int sps30_serial_probe(struct serdev_device *serdev) +{ + struct device *dev = &serdev->dev; + struct sps30_serial_priv *priv; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + init_completion(&priv->new_frame); + serdev_device_set_client_ops(serdev, &sps30_serial_device_ops); + + ret = devm_serdev_device_open(dev, serdev); + if (ret) + return ret; + + serdev_device_set_baudrate(serdev, 115200); + serdev_device_set_flow_control(serdev, false); + + ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE); + if (ret) + return ret; + + return sps30_probe(dev, SPS30_SERIAL_DEV_NAME, priv, &sps30_serial_ops); +} + +static const struct of_device_id sps30_serial_of_match[] = { + { .compatible = "sensirion,sps30" }, + { } +}; +MODULE_DEVICE_TABLE(of, sps30_serial_of_match); + +static struct serdev_device_driver sps30_serial_driver = { + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = sps30_serial_of_match, + }, + .probe = sps30_serial_probe, +}; +module_serdev_device_driver(sps30_serial_driver); + +MODULE_AUTHOR("Tomasz Duszynski "); +MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor serial driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From fb6da706ff1ef7b81a6cbd6c1cbd3ff3f8267990 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Wed, 28 Apr 2021 20:26:12 +0100 Subject: iio: adc: stm32-adc: Fix docs wrongly marked as kernel-doc W=1 highlights these two cases that are obviously not in kernel-doc format. Signed-off-by: Jonathan Cameron Cc: Fabrice Gasnier Reviewed-by: Fabrice Gasnier --- drivers/iio/adc/stm32-adc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index b25386b19373..c9d36c88ee6a 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -449,7 +449,7 @@ static const struct stm32_adc_regspec stm32h7_adc_regspec = { .smp_bits = stm32h7_smp_bits, }; -/** +/* * STM32 ADC registers access routines * @adc: stm32 adc instance * @reg: reg offset in adc instance @@ -851,7 +851,7 @@ static int stm32h7_adc_restore_selfcalib(struct iio_dev *indio_dev) return 0; } -/** +/* * Fixed timeout value for ADC calibration. * worst cases: * - low clock frequency -- cgit v1.2.3 From 9374e8f5a38defe90bc65b2decf317c1c62d91dd Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Wed, 28 Apr 2021 09:32:08 +0200 Subject: iio: adc: add ADC driver for the TI TSC2046 controller Basically the TI TSC2046 touchscreen controller is 8 channel ADC optimized for the touchscreen use case. By implementing it as an IIO ADC device, we can make use of resistive-adc-touch and iio-hwmon drivers. Polled readings are currently not implemented to keep this patch small, so iio-hwmon will not work out of the box for now. So far, this driver was tested with a custom version of resistive-adc-touch driver, since it needs to be extended to make use of Z1 and Z2 channels. The X/Y are working without additional changes. Signed-off-by: Oleksij Rempel Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210428073208.19570-4-o.rempel@pengutronix.de Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 12 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ti-tsc2046.c | 714 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 727 insertions(+) create mode 100644 drivers/iio/adc/ti-tsc2046.c (limited to 'drivers/iio') diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index c7946c439612..db0c8fb60515 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -1190,6 +1190,18 @@ config TI_TLC4541 This driver can also be built as a module. If so, the module will be called ti-tlc4541. +config TI_TSC2046 + tristate "Texas Instruments TSC2046 ADC driver" + depends on SPI + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for ADC functionality of Texas + Instruments TSC2046 touch screen controller. + + This driver can also be built as a module. If so, the module will be + called ti-tsc2046. + config TWL4030_MADC tristate "TWL4030 MADC (Monitoring A/D Converter)" depends on TWL4030_CORE diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index a226657d19c0..f70d877c555a 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -106,6 +106,7 @@ obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o obj-$(CONFIG_TI_ADS131E08) += ti-ads131e08.o obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o obj-$(CONFIG_TI_TLC4541) += ti-tlc4541.o +obj-$(CONFIG_TI_TSC2046) += ti-tsc2046.o obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o obj-$(CONFIG_VF610_ADC) += vf610_adc.o diff --git a/drivers/iio/adc/ti-tsc2046.c b/drivers/iio/adc/ti-tsc2046.c new file mode 100644 index 000000000000..89a818b653b4 --- /dev/null +++ b/drivers/iio/adc/ti-tsc2046.c @@ -0,0 +1,714 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Texas Instruments TSC2046 SPI ADC driver + * + * Copyright (c) 2021 Oleksij Rempel , Pengutronix + */ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +/* + * The PENIRQ of TSC2046 controller is implemented as level shifter attached to + * the X+ line. If voltage of the X+ line reaches a specific level the IRQ will + * be activated or deactivated. + * To make this kind of IRQ reusable as trigger following additions were + * implemented: + * - rate limiting: + * For typical touchscreen use case, we need to trigger about each 10ms. + * - hrtimer: + * Continue triggering at least once after the IRQ was deactivated. Then + * deactivate this trigger to stop sampling in order to reduce power + * consumption. + */ + +#define TI_TSC2046_NAME "tsc2046" + +/* This driver doesn't aim at the peak continuous sample rate */ +#define TI_TSC2046_MAX_SAMPLE_RATE 125000 +#define TI_TSC2046_SAMPLE_BITS \ + BITS_PER_TYPE(struct tsc2046_adc_atom) +#define TI_TSC2046_MAX_CLK_FREQ \ + (TI_TSC2046_MAX_SAMPLE_RATE * TI_TSC2046_SAMPLE_BITS) + +#define TI_TSC2046_SAMPLE_INTERVAL_US 10000 + +#define TI_TSC2046_START BIT(7) +#define TI_TSC2046_ADDR GENMASK(6, 4) +#define TI_TSC2046_ADDR_TEMP1 7 +#define TI_TSC2046_ADDR_AUX 6 +#define TI_TSC2046_ADDR_X 5 +#define TI_TSC2046_ADDR_Z2 4 +#define TI_TSC2046_ADDR_Z1 3 +#define TI_TSC2046_ADDR_VBAT 2 +#define TI_TSC2046_ADDR_Y 1 +#define TI_TSC2046_ADDR_TEMP0 0 + +/* + * The mode bit sets the resolution of the ADC. With this bit low, the next + * conversion has 12-bit resolution, whereas with this bit high, the next + * conversion has 8-bit resolution. This driver is optimized for 12-bit mode. + * So, for this driver, this bit should stay zero. + */ +#define TI_TSC2046_8BIT_MODE BIT(3) + +/* + * SER/DFR - The SER/DFR bit controls the reference mode, either single-ended + * (high) or differential (low). + */ +#define TI_TSC2046_SER BIT(2) + +/* + * If VREF_ON and ADC_ON are both zero, then the chip operates in + * auto-wake/suspend mode. In most case this bits should stay zero. + */ +#define TI_TSC2046_PD1_VREF_ON BIT(1) +#define TI_TSC2046_PD0_ADC_ON BIT(0) + +/* + * All supported devices can do 8 or 12bit resolution. This driver + * supports only 12bit mode, here we have a 16bit data transfer, where + * the MSB and the 3 LSB are 0. + */ +#define TI_TSC2046_DATA_12BIT GENMASK(14, 3) + +#define TI_TSC2046_MAX_CHAN 8 + +/* Represents a HW sample */ +struct tsc2046_adc_atom { + /* + * Command transmitted to the controller. This field is empty on the RX + * buffer. + */ + u8 cmd; + /* + * Data received from the controller. This field is empty for the TX + * buffer + */ + __be16 data; +} __packed; + +/* Layout of atomic buffers within big buffer */ +struct tsc2046_adc_group_layout { + /* Group offset within the SPI RX buffer */ + unsigned int offset; + /* + * Amount of tsc2046_adc_atom structs within the same command gathered + * within same group. + */ + unsigned int count; + /* + * Settling samples (tsc2046_adc_atom structs) which should be skipped + * before good samples will start. + */ + unsigned int skip; +}; + +struct tsc2046_adc_dcfg { + const struct iio_chan_spec *channels; + unsigned int num_channels; +}; + +struct tsc2046_adc_ch_cfg { + unsigned int settling_time_us; + unsigned int oversampling_ratio; +}; + +struct tsc2046_adc_priv { + struct spi_device *spi; + const struct tsc2046_adc_dcfg *dcfg; + + struct iio_trigger *trig; + struct hrtimer trig_timer; + spinlock_t trig_lock; + unsigned int trig_more_count; + + struct spi_transfer xfer; + struct spi_message msg; + + struct { + /* Scan data for each channel */ + u16 data[TI_TSC2046_MAX_CHAN]; + /* Timestamp */ + s64 ts __aligned(8); + } scan_buf; + + /* + * Lock to protect the layout and the SPI transfer buffer. + * tsc2046_adc_group_layout can be changed within update_scan_mode(), + * in this case the l[] and tx/rx buffer will be out of sync to each + * other. + */ + struct mutex slock; + struct tsc2046_adc_group_layout l[TI_TSC2046_MAX_CHAN]; + struct tsc2046_adc_atom *rx; + struct tsc2046_adc_atom *tx; + + struct tsc2046_adc_atom *rx_one; + struct tsc2046_adc_atom *tx_one; + + unsigned int count; + unsigned int groups; + u32 effective_speed_hz; + u32 scan_interval_us; + u32 time_per_scan_us; + u32 time_per_bit_ns; + + struct tsc2046_adc_ch_cfg ch_cfg[TI_TSC2046_MAX_CHAN]; +}; + +#define TI_TSC2046_V_CHAN(index, bits, name) \ +{ \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = index, \ + .datasheet_name = "#name", \ + .scan_index = index, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = bits, \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + }, \ +} + +#define DECLARE_TI_TSC2046_8_CHANNELS(name, bits) \ +const struct iio_chan_spec name ## _channels[] = { \ + TI_TSC2046_V_CHAN(0, bits, TEMP0), \ + TI_TSC2046_V_CHAN(1, bits, Y), \ + TI_TSC2046_V_CHAN(2, bits, VBAT), \ + TI_TSC2046_V_CHAN(3, bits, Z1), \ + TI_TSC2046_V_CHAN(4, bits, Z2), \ + TI_TSC2046_V_CHAN(5, bits, X), \ + TI_TSC2046_V_CHAN(6, bits, AUX), \ + TI_TSC2046_V_CHAN(7, bits, TEMP1), \ + IIO_CHAN_SOFT_TIMESTAMP(8), \ +} + +static DECLARE_TI_TSC2046_8_CHANNELS(tsc2046_adc, 12); + +static const struct tsc2046_adc_dcfg tsc2046_adc_dcfg_tsc2046e = { + .channels = tsc2046_adc_channels, + .num_channels = ARRAY_SIZE(tsc2046_adc_channels), +}; + +/* + * Convert time to a number of samples which can be transferred within this + * time. + */ +static unsigned int tsc2046_adc_time_to_count(struct tsc2046_adc_priv *priv, + unsigned long time) +{ + unsigned int bit_count, sample_count; + + bit_count = DIV_ROUND_UP(time * NSEC_PER_USEC, priv->time_per_bit_ns); + sample_count = DIV_ROUND_UP(bit_count, TI_TSC2046_SAMPLE_BITS); + + dev_dbg(&priv->spi->dev, "Effective speed %u, time per bit: %u, count bits: %u, count samples: %u\n", + priv->effective_speed_hz, priv->time_per_bit_ns, + bit_count, sample_count); + + return sample_count; +} + +static u8 tsc2046_adc_get_cmd(struct tsc2046_adc_priv *priv, int ch_idx, + bool keep_power) +{ + u32 pd; + + /* + * if PD bits are 0, controller will automatically disable ADC, VREF and + * enable IRQ. + */ + if (keep_power) + pd = TI_TSC2046_PD0_ADC_ON; + else + pd = 0; + + return TI_TSC2046_START | FIELD_PREP(TI_TSC2046_ADDR, ch_idx) | pd; +} + +static u16 tsc2046_adc_get_value(struct tsc2046_adc_atom *buf) +{ + return FIELD_GET(TI_TSC2046_DATA_12BIT, get_unaligned_be16(&buf->data)); +} + +static int tsc2046_adc_read_one(struct tsc2046_adc_priv *priv, int ch_idx, + u32 *effective_speed_hz) +{ + struct spi_transfer xfer; + struct spi_message msg; + int ret; + + memset(&xfer, 0, sizeof(xfer)); + priv->tx_one->cmd = tsc2046_adc_get_cmd(priv, ch_idx, false); + priv->tx_one->data = 0; + xfer.tx_buf = priv->tx_one; + xfer.rx_buf = priv->rx_one; + xfer.len = sizeof(*priv->tx_one); + spi_message_init_with_transfers(&msg, &xfer, 1); + + /* + * We aren't using spi_write_then_read() because we need to be able + * to get hold of the effective_speed_hz from the xfer + */ + ret = spi_sync(priv->spi, &msg); + if (ret) { + dev_err_ratelimited(&priv->spi->dev, "SPI transfer failed %pe\n", + ERR_PTR(ret)); + return ret; + } + + if (effective_speed_hz) + *effective_speed_hz = xfer.effective_speed_hz; + + return tsc2046_adc_get_value(priv->rx_one); +} + +static size_t tsc2046_adc_group_set_layout(struct tsc2046_adc_priv *priv, + unsigned int group, + unsigned int ch_idx) +{ + struct tsc2046_adc_ch_cfg *ch = &priv->ch_cfg[ch_idx]; + struct tsc2046_adc_group_layout *cur; + unsigned int max_count, count_skip; + unsigned int offset = 0; + + if (group) + offset = priv->l[group - 1].offset + priv->l[group - 1].count; + + count_skip = tsc2046_adc_time_to_count(priv, ch->settling_time_us); + max_count = count_skip + ch->oversampling_ratio; + + cur = &priv->l[group]; + cur->offset = offset; + cur->count = max_count; + cur->skip = count_skip; + + return sizeof(*priv->tx) * max_count; +} + +static void tsc2046_adc_group_set_cmd(struct tsc2046_adc_priv *priv, + unsigned int group, int ch_idx) +{ + struct tsc2046_adc_group_layout *l = &priv->l[group]; + unsigned int i; + u8 cmd; + + /* + * Do not enable automatic power down on working samples. Otherwise the + * plates will never be completely charged. + */ + cmd = tsc2046_adc_get_cmd(priv, ch_idx, true); + + for (i = 0; i < l->count - 1; i++) + priv->tx[l->offset + i].cmd = cmd; + + /* automatically power down on last sample */ + priv->tx[l->offset + i].cmd = tsc2046_adc_get_cmd(priv, ch_idx, false); +} + +static u16 tsc2046_adc_get_val(struct tsc2046_adc_priv *priv, int group) +{ + struct tsc2046_adc_group_layout *l; + unsigned int val, val_normalized = 0; + int valid_count, i; + + l = &priv->l[group]; + valid_count = l->count - l->skip; + + for (i = 0; i < valid_count; i++) { + val = tsc2046_adc_get_value(&priv->rx[l->offset + l->skip + i]); + val_normalized += val; + } + + return DIV_ROUND_UP(val_normalized, valid_count); +} + +static int tsc2046_adc_scan(struct iio_dev *indio_dev) +{ + struct tsc2046_adc_priv *priv = iio_priv(indio_dev); + struct device *dev = &priv->spi->dev; + int group; + int ret; + + ret = spi_sync(priv->spi, &priv->msg); + if (ret < 0) { + dev_err_ratelimited(dev, "SPI transfer failed: %pe\n", ERR_PTR(ret)); + return ret; + } + + for (group = 0; group < priv->groups; group++) + priv->scan_buf.data[group] = tsc2046_adc_get_val(priv, group); + + ret = iio_push_to_buffers_with_timestamp(indio_dev, &priv->scan_buf, + iio_get_time_ns(indio_dev)); + /* If the consumer is kfifo, we may get a EBUSY here - ignore it. */ + if (ret < 0 && ret != -EBUSY) { + dev_err_ratelimited(dev, "Failed to push scan buffer %pe\n", + ERR_PTR(ret)); + + return ret; + } + + return 0; +} + +static irqreturn_t tsc2046_adc_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct tsc2046_adc_priv *priv = iio_priv(indio_dev); + + mutex_lock(&priv->slock); + tsc2046_adc_scan(indio_dev); + mutex_unlock(&priv->slock); + + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int tsc2046_adc_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *active_scan_mask) +{ + struct tsc2046_adc_priv *priv = iio_priv(indio_dev); + unsigned int ch_idx, group = 0; + size_t size; + + mutex_lock(&priv->slock); + + size = 0; + for_each_set_bit(ch_idx, active_scan_mask, indio_dev->num_channels) { + size += tsc2046_adc_group_set_layout(priv, group, ch_idx); + tsc2046_adc_group_set_cmd(priv, group, ch_idx); + group++; + } + + priv->groups = group; + priv->xfer.len = size; + priv->time_per_scan_us = size * 8 * priv->time_per_bit_ns / NSEC_PER_USEC; + + if ((priv->scan_interval_us - priv->time_per_scan_us) < 0) + dev_warn(&priv->spi->dev, "The scan interval (%d) is less then calculated scan time (%d)\n", + priv->scan_interval_us, priv->time_per_scan_us); + + mutex_unlock(&priv->slock); + + return 0; +} + +static const struct iio_info tsc2046_adc_info = { + .update_scan_mode = tsc2046_adc_update_scan_mode, +}; + +static enum hrtimer_restart tsc2046_adc_trig_more(struct hrtimer *hrtimer) +{ + struct tsc2046_adc_priv *priv = container_of(hrtimer, + struct tsc2046_adc_priv, + trig_timer); + unsigned long flags; + + spin_lock_irqsave(&priv->trig_lock, flags); + + disable_irq_nosync(priv->spi->irq); + + priv->trig_more_count++; + iio_trigger_poll(priv->trig); + + spin_unlock_irqrestore(&priv->trig_lock, flags); + + return HRTIMER_NORESTART; +} + +static irqreturn_t tsc2046_adc_irq(int irq, void *dev_id) +{ + struct iio_dev *indio_dev = dev_id; + struct tsc2046_adc_priv *priv = iio_priv(indio_dev); + + spin_lock(&priv->trig_lock); + + hrtimer_try_to_cancel(&priv->trig_timer); + + priv->trig_more_count = 0; + disable_irq_nosync(priv->spi->irq); + iio_trigger_poll(priv->trig); + + spin_unlock(&priv->trig_lock); + + return IRQ_HANDLED; +} + +static void tsc2046_adc_reenable_trigger(struct iio_trigger *trig) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct tsc2046_adc_priv *priv = iio_priv(indio_dev); + unsigned long flags; + int delta; + + /* + * We can sample it as fast as we can, but usually we do not need so + * many samples. Reduce the sample rate for default (touchscreen) use + * case. + * Currently we do not need a highly precise sample rate. It is enough + * to have calculated numbers. + */ + delta = priv->scan_interval_us - priv->time_per_scan_us; + if (delta > 0) + fsleep(delta); + + spin_lock_irqsave(&priv->trig_lock, flags); + + /* + * We need to trigger at least one extra sample to detect state + * difference on ADC side. + */ + if (!priv->trig_more_count) { + int timeout_ms = DIV_ROUND_UP(priv->scan_interval_us, + USEC_PER_MSEC); + + hrtimer_start(&priv->trig_timer, ms_to_ktime(timeout_ms), + HRTIMER_MODE_REL_SOFT); + } + + enable_irq(priv->spi->irq); + + spin_unlock_irqrestore(&priv->trig_lock, flags); +} + +static int tsc2046_adc_set_trigger_state(struct iio_trigger *trig, bool enable) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct tsc2046_adc_priv *priv = iio_priv(indio_dev); + + if (enable) { + enable_irq(priv->spi->irq); + } else { + disable_irq(priv->spi->irq); + hrtimer_try_to_cancel(&priv->trig_timer); + } + + return 0; +} + +static const struct iio_trigger_ops tsc2046_adc_trigger_ops = { + .set_trigger_state = tsc2046_adc_set_trigger_state, + .reenable = tsc2046_adc_reenable_trigger, +}; + +static int tsc2046_adc_setup_spi_msg(struct tsc2046_adc_priv *priv) +{ + unsigned int ch_idx; + size_t size; + int ret; + + priv->tx_one = devm_kzalloc(&priv->spi->dev, sizeof(*priv->tx_one), + GFP_KERNEL); + if (!priv->tx_one) + return -ENOMEM; + + priv->rx_one = devm_kzalloc(&priv->spi->dev, sizeof(*priv->rx_one), + GFP_KERNEL); + if (!priv->rx_one) + return -ENOMEM; + + /* + * Make dummy read to set initial power state and get real SPI clock + * freq. It seems to be not important which channel is used for this + * case. + */ + ret = tsc2046_adc_read_one(priv, TI_TSC2046_ADDR_TEMP0, + &priv->effective_speed_hz); + if (ret < 0) + return ret; + + /* + * In case SPI controller do not report effective_speed_hz, use + * configure value and hope it will match. + */ + if (!priv->effective_speed_hz) + priv->effective_speed_hz = priv->spi->max_speed_hz; + + + priv->scan_interval_us = TI_TSC2046_SAMPLE_INTERVAL_US; + priv->time_per_bit_ns = DIV_ROUND_UP(NSEC_PER_SEC, + priv->effective_speed_hz); + + /* + * Calculate and allocate maximal size buffer if all channels are + * enabled. + */ + size = 0; + for (ch_idx = 0; ch_idx < priv->dcfg->num_channels; ch_idx++) + size += tsc2046_adc_group_set_layout(priv, ch_idx, ch_idx); + + priv->tx = devm_kzalloc(&priv->spi->dev, size, GFP_KERNEL); + if (!priv->tx) + return -ENOMEM; + + priv->rx = devm_kzalloc(&priv->spi->dev, size, GFP_KERNEL); + if (!priv->rx) + return -ENOMEM; + + priv->xfer.tx_buf = priv->tx; + priv->xfer.rx_buf = priv->rx; + priv->xfer.len = size; + spi_message_init_with_transfers(&priv->msg, &priv->xfer, 1); + + return 0; +} + +static void tsc2046_adc_parse_fwnode(struct tsc2046_adc_priv *priv) +{ + struct fwnode_handle *child; + struct device *dev = &priv->spi->dev; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(priv->ch_cfg); i++) { + priv->ch_cfg[i].settling_time_us = 1; + priv->ch_cfg[i].oversampling_ratio = 1; + } + + device_for_each_child_node(dev, child) { + u32 stl, overs, reg; + int ret; + + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret) { + dev_err(dev, "invalid reg on %pfw, err: %pe\n", child, + ERR_PTR(ret)); + continue; + } + + if (reg >= ARRAY_SIZE(priv->ch_cfg)) { + dev_err(dev, "%pfw: Unsupported reg value: %i, max supported is: %zu.\n", + child, reg, ARRAY_SIZE(priv->ch_cfg)); + continue; + } + + ret = fwnode_property_read_u32(child, "settling-time-us", &stl); + if (!ret) + priv->ch_cfg[reg].settling_time_us = stl; + + ret = fwnode_property_read_u32(child, "oversampling-ratio", + &overs); + if (!ret) + priv->ch_cfg[reg].oversampling_ratio = overs; + } +} + +static int tsc2046_adc_probe(struct spi_device *spi) +{ + const struct tsc2046_adc_dcfg *dcfg; + struct device *dev = &spi->dev; + struct tsc2046_adc_priv *priv; + struct iio_dev *indio_dev; + struct iio_trigger *trig; + int ret; + + if (spi->max_speed_hz > TI_TSC2046_MAX_CLK_FREQ) { + dev_err(dev, "SPI max_speed_hz is too high: %d Hz. Max supported freq is %zu Hz\n", + spi->max_speed_hz, TI_TSC2046_MAX_CLK_FREQ); + return -EINVAL; + } + + dcfg = device_get_match_data(dev); + if (!dcfg) + return -EINVAL; + + spi->bits_per_word = 8; + spi->mode &= ~SPI_MODE_X_MASK; + spi->mode |= SPI_MODE_0; + ret = spi_setup(spi); + if (ret < 0) + return dev_err_probe(dev, ret, "Error in SPI setup\n"); + + indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); + if (!indio_dev) + return -ENOMEM; + + priv = iio_priv(indio_dev); + priv->dcfg = dcfg; + + spi_set_drvdata(spi, indio_dev); + + priv->spi = spi; + + indio_dev->name = TI_TSC2046_NAME; + indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_TRIGGERED; + indio_dev->channels = dcfg->channels; + indio_dev->num_channels = dcfg->num_channels; + indio_dev->info = &tsc2046_adc_info; + + tsc2046_adc_parse_fwnode(priv); + + ret = tsc2046_adc_setup_spi_msg(priv); + if (ret) + return ret; + + mutex_init(&priv->slock); + + ret = devm_request_irq(dev, spi->irq, &tsc2046_adc_irq, + IRQF_NO_AUTOEN, indio_dev->name, indio_dev); + if (ret) + return ret; + + trig = devm_iio_trigger_alloc(dev, "touchscreen-%s", indio_dev->name); + if (!trig) + return -ENOMEM; + + priv->trig = trig; + iio_trigger_set_drvdata(trig, indio_dev); + trig->ops = &tsc2046_adc_trigger_ops; + + spin_lock_init(&priv->trig_lock); + hrtimer_init(&priv->trig_timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL_SOFT); + priv->trig_timer.function = tsc2046_adc_trig_more; + + ret = devm_iio_trigger_register(dev, trig); + if (ret) { + dev_err(dev, "failed to register trigger\n"); + return ret; + } + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, + &tsc2046_adc_trigger_handler, NULL); + if (ret) { + dev_err(dev, "Failed to setup triggered buffer\n"); + return ret; + } + + /* set default trigger */ + indio_dev->trig = iio_trigger_get(priv->trig); + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id ads7950_of_table[] = { + { .compatible = "ti,tsc2046e-adc", .data = &tsc2046_adc_dcfg_tsc2046e }, + { } +}; +MODULE_DEVICE_TABLE(of, ads7950_of_table); + +static struct spi_driver tsc2046_adc_driver = { + .driver = { + .name = "tsc2046", + .of_match_table = ads7950_of_table, + }, + .probe = tsc2046_adc_probe, +}; +module_spi_driver(tsc2046_adc_driver); + +MODULE_AUTHOR("Oleksij Rempel "); +MODULE_DESCRIPTION("TI TSC2046 ADC"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From cb25d770cf9d3c4071693912bee9a48126072649 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 26 Apr 2021 18:02:44 +0100 Subject: iio: accel: bmi088: Drop manual assignment of iio_dev.dev.parent The core already set this to the same value in devm_iio_device_alloc() Signed-off-by: Jonathan Cameron Cc: Mike Looijmans Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210426170251.351957-2-jic23@kernel.org --- drivers/iio/accel/bmi088-accel-core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/bmi088-accel-core.c b/drivers/iio/accel/bmi088-accel-core.c index 12d00658e46f..61aaaf48c040 100644 --- a/drivers/iio/accel/bmi088-accel-core.c +++ b/drivers/iio/accel/bmi088-accel-core.c @@ -496,7 +496,6 @@ int bmi088_accel_core_probe(struct device *dev, struct regmap *regmap, if (ret) return ret; - indio_dev->dev.parent = dev; indio_dev->channels = data->chip_info->channels; indio_dev->num_channels = data->chip_info->num_channels; indio_dev->name = name ? name : data->chip_info->name; -- cgit v1.2.3 From e42523c11f2a182a0969b0e7462337fc190f8ca2 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 26 Apr 2021 18:02:45 +0100 Subject: iio: dac: ad5766: Drop duplicate setting of iio_dev.dev.parent and of_node This is set to the same value in devm_iio_device_alloc() so no need to do it again. Signed-off-by: Jonathan Cameron Cc: Cristian Pop Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210426170251.351957-3-jic23@kernel.org --- drivers/iio/dac/ad5766.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/dac/ad5766.c b/drivers/iio/dac/ad5766.c index 79837a4b3a41..3104ec32dfac 100644 --- a/drivers/iio/dac/ad5766.c +++ b/drivers/iio/dac/ad5766.c @@ -597,8 +597,6 @@ static int ad5766_probe(struct spi_device *spi) indio_dev->channels = st->chip_info->channels; indio_dev->num_channels = st->chip_info->num_channels; indio_dev->info = &ad5766_info; - indio_dev->dev.parent = &spi->dev; - indio_dev->dev.of_node = spi->dev.of_node; indio_dev->name = spi_get_device_id(spi)->name; indio_dev->modes = INDIO_DIRECT_MODE; -- cgit v1.2.3 From 806e657b0f7e79473f242a2435e5c4e027c632a6 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 26 Apr 2021 18:02:46 +0100 Subject: iio: adc: mp2629: Drop duplicate setting iio_dev.dev.parent This is already set to the same value in devm_iio_device_alloc() Signed-off-by: Jonathan Cameron Cc: Saravanan Sekar Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210426170251.351957-4-jic23@kernel.org --- drivers/iio/adc/mp2629_adc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/mp2629_adc.c b/drivers/iio/adc/mp2629_adc.c index 331a9a728217..aca084f1e78a 100644 --- a/drivers/iio/adc/mp2629_adc.c +++ b/drivers/iio/adc/mp2629_adc.c @@ -144,7 +144,6 @@ static int mp2629_adc_probe(struct platform_device *pdev) } indio_dev->name = "mp2629-adc"; - indio_dev->dev.parent = dev; indio_dev->channels = mp2629_channels; indio_dev->num_channels = ARRAY_SIZE(mp2629_channels); indio_dev->modes = INDIO_DIRECT_MODE; -- cgit v1.2.3 From 85493b9ae8188d3eb0083816086411496165c882 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 26 Apr 2021 18:02:47 +0100 Subject: iio: adc: mt6360: Drop duplicate setting of iio_dev.dev.parent Already set to the same value in devm_iio_device_alloc() Signed-off-by: Jonathan Cameron Cc: Gene Chen Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210426170251.351957-5-jic23@kernel.org --- drivers/iio/adc/mt6360-adc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/mt6360-adc.c b/drivers/iio/adc/mt6360-adc.c index 6b39a139ce28..07c0e6768391 100644 --- a/drivers/iio/adc/mt6360-adc.c +++ b/drivers/iio/adc/mt6360-adc.c @@ -337,7 +337,6 @@ static int mt6360_adc_probe(struct platform_device *pdev) } indio_dev->name = dev_name(&pdev->dev); - indio_dev->dev.parent = &pdev->dev; indio_dev->info = &mt6360_adc_iio_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = mt6360_adc_channels; -- cgit v1.2.3 From 9eb04878e4af245f0988de7800e32ec958a997a0 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 26 Apr 2021 18:02:48 +0100 Subject: iio: adc: ti-ads131e08: Drop duplicate setting of iio_dev.dev.parent Already set to same value in devm_iio_device_alloc() Signed-off-by: Jonathan Cameron Cc: Tomislav Denis Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210426170251.351957-6-jic23@kernel.org --- drivers/iio/adc/ti-ads131e08.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/ti-ads131e08.c b/drivers/iio/adc/ti-ads131e08.c index 764dab087b41..2c20dbed8ada 100644 --- a/drivers/iio/adc/ti-ads131e08.c +++ b/drivers/iio/adc/ti-ads131e08.c @@ -830,7 +830,6 @@ static int ads131e08_probe(struct spi_device *spi) return ret; indio_dev->name = st->info->name; - indio_dev->dev.parent = &spi->dev; indio_dev->info = &ads131e08_iio_info; indio_dev->modes = INDIO_DIRECT_MODE; -- cgit v1.2.3 From 932bf4710ee19841e660492da581558482034c55 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 26 Apr 2021 18:02:49 +0100 Subject: iio: humidity: hdc2010: Drop duplicate setting of iio_dev.dev.parent Already set to same value in devm_iio_device_alloc() Signed-off-by: Jonathan Cameron Cc: Eugene Zaikonnikov Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210426170251.351957-7-jic23@kernel.org --- drivers/iio/humidity/hdc2010.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/humidity/hdc2010.c b/drivers/iio/humidity/hdc2010.c index 83f5b9f60780..1381df46187c 100644 --- a/drivers/iio/humidity/hdc2010.c +++ b/drivers/iio/humidity/hdc2010.c @@ -272,7 +272,6 @@ static int hdc2010_probe(struct i2c_client *client, data->client = client; mutex_init(&data->lock); - indio_dev->dev.parent = &client->dev; /* * As DEVICE ID register does not differentiate between * HDC2010 and HDC2080, we have the name hardcoded -- cgit v1.2.3 From 63027b34189a6f4a788c536be6495e93d75fb4c3 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 26 Apr 2021 18:02:50 +0100 Subject: iio: position: hid-sensor-custom-intel-hinge: Drop duplicate parent setting. iio_dev.dev.parent is already set to the same value in devm_iio_device_alloc() Signed-off-by: Jonathan Cameron Cc: Ye Xiang Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210426170251.351957-8-jic23@kernel.org --- drivers/iio/position/hid-sensor-custom-intel-hinge.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/position/hid-sensor-custom-intel-hinge.c b/drivers/iio/position/hid-sensor-custom-intel-hinge.c index fd77e7ee87f3..738b5f4626ce 100644 --- a/drivers/iio/position/hid-sensor-custom-intel-hinge.c +++ b/drivers/iio/position/hid-sensor-custom-intel-hinge.c @@ -303,7 +303,6 @@ static int hid_hinge_probe(struct platform_device *pdev) return ret; } - indio_dev->dev.parent = &pdev->dev; indio_dev->info = &hinge_info; indio_dev->name = "hinge"; indio_dev->modes = INDIO_DIRECT_MODE; -- cgit v1.2.3 From e6cc8f2b7616f9d85e281d903f82d6f99819cd08 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 26 Apr 2021 18:02:51 +0100 Subject: iio: common: scmi_sensors: Drop duplicate setting of iio_dev.dev.parent This is already set to the same value in devm_iio_device_alloc() Signed-off-by: Jonathan Cameron Cc: Jyoti Bhayana Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210426170251.351957-9-jic23@kernel.org --- drivers/iio/common/scmi_sensors/scmi_iio.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/common/scmi_sensors/scmi_iio.c b/drivers/iio/common/scmi_sensors/scmi_iio.c index 141e8aa6911e..7cf2bf282cef 100644 --- a/drivers/iio/common/scmi_sensors/scmi_iio.c +++ b/drivers/iio/common/scmi_sensors/scmi_iio.c @@ -525,7 +525,6 @@ scmi_alloc_iiodev(struct scmi_device *sdev, return ERR_PTR(-ENOMEM); iiodev->modes = INDIO_DIRECT_MODE; - iiodev->dev.parent = dev; sensor = iio_priv(iiodev); sensor->sensor_ops = ops; sensor->ph = ph; -- cgit v1.2.3 From 15ea2878bfb255099092634d28f31177f237ccd7 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 26 Apr 2021 18:49:03 +0100 Subject: iio: core: move @id from struct iio_dev to struct iio_dev_opaque Continuing from Alexandru Ardelean's introduction of the split between driver modifiable fields and those that should only be set by the core. This could have been done in two steps to make the actual move after introducing iio_device_id() but there seemed limited point to that given how mechanical the majority of the patch is. Includes fixup from Alex for missing mxs-lradc-adc conversion. Signed-off-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210426174911.397061-2-jic23@kernel.org --- drivers/iio/accel/adxl372.c | 4 ++-- drivers/iio/accel/bma180.c | 2 +- drivers/iio/accel/bmc150-accel-core.c | 4 ++-- drivers/iio/accel/kxcjk-1013.c | 4 ++-- drivers/iio/accel/mma8452.c | 2 +- drivers/iio/accel/mxc4005.c | 2 +- drivers/iio/accel/stk8312.c | 2 +- drivers/iio/accel/stk8ba50.c | 2 +- drivers/iio/adc/ad7606.c | 3 ++- drivers/iio/adc/ad7766.c | 3 ++- drivers/iio/adc/ad7768-1.c | 3 ++- drivers/iio/adc/ad_sigma_delta.c | 2 +- drivers/iio/adc/at91-sama5d2_adc.c | 2 +- drivers/iio/adc/at91_adc.c | 4 ++-- drivers/iio/adc/dln2-adc.c | 3 ++- drivers/iio/adc/ina2xx-adc.c | 3 ++- drivers/iio/adc/mxs-lradc-adc.c | 2 +- drivers/iio/adc/ti-ads131e08.c | 2 +- drivers/iio/adc/xilinx-xadc-core.c | 2 +- drivers/iio/buffer/industrialio-triggered-buffer.c | 2 +- drivers/iio/chemical/atlas-sensor.c | 2 +- drivers/iio/chemical/ccs811.c | 2 +- drivers/iio/chemical/scd30_core.c | 3 ++- .../iio/common/hid-sensors/hid-sensor-trigger.c | 2 +- drivers/iio/gyro/adxrs290.c | 2 +- drivers/iio/gyro/bmg160_core.c | 4 ++-- drivers/iio/gyro/fxas21002c_core.c | 2 +- drivers/iio/gyro/itg3200_buffer.c | 2 +- drivers/iio/gyro/mpu3050-core.c | 2 +- drivers/iio/health/afe4403.c | 2 +- drivers/iio/health/afe4404.c | 2 +- drivers/iio/imu/adis_trigger.c | 3 ++- drivers/iio/imu/bmi160/bmi160_core.c | 3 ++- drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c | 2 +- drivers/iio/imu/kmx61.c | 2 +- drivers/iio/industrialio-core.c | 24 +++++++++++++++++----- drivers/iio/industrialio-triggered-event.c | 2 +- drivers/iio/light/acpi-als.c | 3 ++- drivers/iio/light/rpr0521.c | 2 +- drivers/iio/light/si1145.c | 2 +- drivers/iio/light/vcnl4000.c | 3 ++- drivers/iio/light/vcnl4035.c | 2 +- drivers/iio/magnetometer/bmc150_magn.c | 2 +- drivers/iio/magnetometer/rm3100-core.c | 2 +- drivers/iio/potentiostat/lmp91000.c | 3 ++- drivers/iio/pressure/zpa2326.c | 3 ++- drivers/iio/proximity/as3935.c | 3 ++- drivers/iio/proximity/sx9310.c | 2 +- drivers/iio/proximity/sx9500.c | 2 +- 49 files changed, 85 insertions(+), 58 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c index 9c9a896a872a..fc9592407717 100644 --- a/drivers/iio/accel/adxl372.c +++ b/drivers/iio/accel/adxl372.c @@ -1223,14 +1223,14 @@ int adxl372_probe(struct device *dev, struct regmap *regmap, st->dready_trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (st->dready_trig == NULL) return -ENOMEM; st->peak_datardy_trig = devm_iio_trigger_alloc(dev, "%s-dev%d-peak", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (!st->peak_datardy_trig) return -ENOMEM; diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index b8a7469cdae4..68d91a70de03 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -1045,7 +1045,7 @@ static int bma180_probe(struct i2c_client *client, if (client->irq > 0) { data->trig = iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (!data->trig) { ret = -ENOMEM; goto err_chip_disable; diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index 04d85ce34e9f..62a164a7b852 100644 --- a/drivers/iio/accel/bmc150-accel-core.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -1470,9 +1470,9 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev, struct bmc150_accel_trigger *t = &data->triggers[i]; t->indio_trig = devm_iio_trigger_alloc(dev, - bmc150_accel_triggers[i].name, + bmc150_accel_triggers[i].name, indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (!t->indio_trig) { ret = -ENOMEM; break; diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index ff724bc17a45..283e6a3feffc 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -1404,7 +1404,7 @@ static int kxcjk1013_probe(struct i2c_client *client, data->dready_trig = devm_iio_trigger_alloc(&client->dev, "%s-dev%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (!data->dready_trig) { ret = -ENOMEM; goto err_poweroff; @@ -1413,7 +1413,7 @@ static int kxcjk1013_probe(struct i2c_client *client, data->motion_trig = devm_iio_trigger_alloc(&client->dev, "%s-any-motion-dev%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (!data->motion_trig) { ret = -ENOMEM; goto err_poweroff; diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 4d307dfb9169..464a6bfe6746 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -1461,7 +1461,7 @@ static int mma8452_trigger_setup(struct iio_dev *indio_dev) trig = devm_iio_trigger_alloc(&data->client->dev, "%s-dev%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (!trig) return -ENOMEM; diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c index fb3cbaa62bd8..98c7f5f59011 100644 --- a/drivers/iio/accel/mxc4005.c +++ b/drivers/iio/accel/mxc4005.c @@ -433,7 +433,7 @@ static int mxc4005_probe(struct i2c_client *client, data->dready_trig = devm_iio_trigger_alloc(&client->dev, "%s-dev%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (!data->dready_trig) return -ENOMEM; diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index 60aecfa9fd92..aeab108c457d 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -552,7 +552,7 @@ static int stk8312_probe(struct i2c_client *client, data->dready_trig = devm_iio_trigger_alloc(&client->dev, "%s-dev%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (!data->dready_trig) { ret = -ENOMEM; goto err_power_off; diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index 7cf9cb7e8666..3e7cf23be7e1 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -448,7 +448,7 @@ static int stk8ba50_probe(struct i2c_client *client, data->dready_trig = devm_iio_trigger_alloc(&client->dev, "%s-dev%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (!data->dready_trig) { ret = -ENOMEM; goto err_power_off; diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index 0af0bb4d5a7f..0a60ecc69d38 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -663,7 +663,8 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, } st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", - indio_dev->name, indio_dev->id); + indio_dev->name, + iio_device_id(indio_dev)); if (!st->trig) return -ENOMEM; diff --git a/drivers/iio/adc/ad7766.c b/drivers/iio/adc/ad7766.c index 1e41759f3ee5..236a455aaa18 100644 --- a/drivers/iio/adc/ad7766.c +++ b/drivers/iio/adc/ad7766.c @@ -248,7 +248,8 @@ static int ad7766_probe(struct spi_device *spi) if (spi->irq > 0) { ad7766->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d", - indio_dev->name, indio_dev->id); + indio_dev->name, + iio_device_id(indio_dev)); if (!ad7766->trig) return -ENOMEM; diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index c945f1349623..41752777e96c 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -626,7 +626,8 @@ static int ad7768_probe(struct spi_device *spi) } st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d", - indio_dev->name, indio_dev->id); + indio_dev->name, + iio_device_id(indio_dev)); if (!st->trig) return -ENOMEM; diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index e777ec718973..69b979331ccd 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -477,7 +477,7 @@ static int ad_sd_probe_trigger(struct iio_dev *indio_dev) sigma_delta->trig = iio_trigger_alloc(&sigma_delta->spi->dev, "%s-dev%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (sigma_delta->trig == NULL) { ret = -ENOMEM; goto error_ret; diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c index a7826f097b95..6e8c28675947 100644 --- a/drivers/iio/adc/at91-sama5d2_adc.c +++ b/drivers/iio/adc/at91-sama5d2_adc.c @@ -997,7 +997,7 @@ static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *indio, int ret; trig = devm_iio_trigger_alloc(&indio->dev, "%s-dev%d-%s", indio->name, - indio->id, trigger_name); + iio_device_id(indio), trigger_name); if (!trig) return NULL; diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 0b5f0c91d0d7..5a7d3a3a5fa8 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -547,7 +547,7 @@ static int at91_adc_get_trigger_value_by_name(struct iio_dev *idev, char *name = kasprintf(GFP_KERNEL, "%s-dev%d-%s", idev->name, - idev->id, + iio_device_id(idev), triggers[i].name); if (!name) return -ENOMEM; @@ -626,7 +626,7 @@ static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *idev, int ret; trig = iio_trigger_alloc(idev->dev.parent, "%s-dev%d-%s", idev->name, - idev->id, trigger->name); + iio_device_id(idev), trigger->name); if (trig == NULL) return NULL; diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c index 0d53ef18e045..16407664182c 100644 --- a/drivers/iio/adc/dln2-adc.c +++ b/drivers/iio/adc/dln2-adc.c @@ -649,7 +649,8 @@ static int dln2_adc_probe(struct platform_device *pdev) indio_dev->setup_ops = &dln2_adc_buffer_setup_ops; dln2->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", - indio_dev->name, indio_dev->id); + indio_dev->name, + iio_device_id(indio_dev)); if (!dln2->trig) { dev_err(dev, "failed to allocate trigger\n"); return -ENOMEM; diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 2ae54258b221..a4b2ff9e0dd5 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -843,7 +843,8 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev) chip->allow_async_readout); task = kthread_create(ina2xx_capture_thread, (void *)indio_dev, - "%s:%d-%uus", indio_dev->name, indio_dev->id, + "%s:%d-%uus", indio_dev->name, + iio_device_id(indio_dev), sampling_us); if (IS_ERR(task)) return PTR_ERR(task); diff --git a/drivers/iio/adc/mxs-lradc-adc.c b/drivers/iio/adc/mxs-lradc-adc.c index 30e29f44ebd2..1d99170d3328 100644 --- a/drivers/iio/adc/mxs-lradc-adc.c +++ b/drivers/iio/adc/mxs-lradc-adc.c @@ -455,7 +455,7 @@ static int mxs_lradc_adc_trigger_init(struct iio_dev *iio) struct mxs_lradc_adc *adc = iio_priv(iio); trig = devm_iio_trigger_alloc(&iio->dev, "%s-dev%i", iio->name, - iio->id); + iio_device_id(iio)); if (!trig) return -ENOMEM; diff --git a/drivers/iio/adc/ti-ads131e08.c b/drivers/iio/adc/ti-ads131e08.c index 2c20dbed8ada..0c2025a22575 100644 --- a/drivers/iio/adc/ti-ads131e08.c +++ b/drivers/iio/adc/ti-ads131e08.c @@ -849,7 +849,7 @@ static int ads131e08_probe(struct spi_device *spi) } st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d", - indio_dev->name, indio_dev->id); + indio_dev->name, iio_device_id(indio_dev)); if (!st->trig) { dev_err(&spi->dev, "failed to allocate IIO trigger\n"); return -ENOMEM; diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index 6914c1900ed0..198d2916266d 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -743,7 +743,7 @@ static struct iio_trigger *xadc_alloc_trigger(struct iio_dev *indio_dev, int ret; trig = devm_iio_trigger_alloc(dev, "%s%d-%s", indio_dev->name, - indio_dev->id, name); + iio_device_id(indio_dev), name); if (trig == NULL) return ERR_PTR(-ENOMEM); diff --git a/drivers/iio/buffer/industrialio-triggered-buffer.c b/drivers/iio/buffer/industrialio-triggered-buffer.c index ebb4520ac291..f77c4538141e 100644 --- a/drivers/iio/buffer/industrialio-triggered-buffer.c +++ b/drivers/iio/buffer/industrialio-triggered-buffer.c @@ -56,7 +56,7 @@ int iio_triggered_buffer_setup_ext(struct iio_dev *indio_dev, indio_dev, "%s_consumer%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (indio_dev->pollfunc == NULL) { ret = -ENOMEM; goto error_kfifo_free; diff --git a/drivers/iio/chemical/atlas-sensor.c b/drivers/iio/chemical/atlas-sensor.c index 56ba6c82b501..d10f921b233a 100644 --- a/drivers/iio/chemical/atlas-sensor.c +++ b/drivers/iio/chemical/atlas-sensor.c @@ -640,7 +640,7 @@ static int atlas_probe(struct i2c_client *client, indio_dev->modes = INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE; trig = devm_iio_trigger_alloc(&client->dev, "%s-dev%d", - indio_dev->name, indio_dev->id); + indio_dev->name, iio_device_id(indio_dev)); if (!trig) return -ENOMEM; diff --git a/drivers/iio/chemical/ccs811.c b/drivers/iio/chemical/ccs811.c index 886e96496dbf..847194fa1e46 100644 --- a/drivers/iio/chemical/ccs811.c +++ b/drivers/iio/chemical/ccs811.c @@ -491,7 +491,7 @@ static int ccs811_probe(struct i2c_client *client, data->drdy_trig = devm_iio_trigger_alloc(&client->dev, "%s-dev%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (!data->drdy_trig) { ret = -ENOMEM; goto err_poweroff; diff --git a/drivers/iio/chemical/scd30_core.c b/drivers/iio/chemical/scd30_core.c index d89f117dd0ef..9fe6bbe9ee04 100644 --- a/drivers/iio/chemical/scd30_core.c +++ b/drivers/iio/chemical/scd30_core.c @@ -640,7 +640,8 @@ static int scd30_setup_trigger(struct iio_dev *indio_dev) struct iio_trigger *trig; int ret; - trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, indio_dev->id); + trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, + iio_device_id(indio_dev)); if (!trig) { dev_err(dev, "failed to allocate trigger\n"); return -ENOMEM; diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index 95ddccb44f1c..5a7b3e253e58 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -256,7 +256,7 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, } trig = iio_trigger_alloc(indio_dev->dev.parent, - "%s-dev%d", name, indio_dev->id); + "%s-dev%d", name, iio_device_id(indio_dev)); if (trig == NULL) { dev_err(&indio_dev->dev, "Trigger Allocate Failed\n"); ret = -ENOMEM; diff --git a/drivers/iio/gyro/adxrs290.c b/drivers/iio/gyro/adxrs290.c index cec5e1f17c22..3e0734ddafe3 100644 --- a/drivers/iio/gyro/adxrs290.c +++ b/drivers/iio/gyro/adxrs290.c @@ -589,7 +589,7 @@ static int adxrs290_probe_trigger(struct iio_dev *indio_dev) st->dready_trig = devm_iio_trigger_alloc(&st->spi->dev, "%s-dev%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (!st->dready_trig) return -ENOMEM; diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c index b11ebd9bb7a4..26a9ed5770c6 100644 --- a/drivers/iio/gyro/bmg160_core.c +++ b/drivers/iio/gyro/bmg160_core.c @@ -1137,14 +1137,14 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq, data->dready_trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (!data->dready_trig) return -ENOMEM; data->motion_trig = devm_iio_trigger_alloc(dev, "%s-any-motion-dev%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (!data->motion_trig) return -ENOMEM; diff --git a/drivers/iio/gyro/fxas21002c_core.c b/drivers/iio/gyro/fxas21002c_core.c index 1a20c6b88e7d..5af7b48ff01a 100644 --- a/drivers/iio/gyro/fxas21002c_core.c +++ b/drivers/iio/gyro/fxas21002c_core.c @@ -852,7 +852,7 @@ static int fxas21002c_trigger_probe(struct fxas21002c_data *data) data->dready_trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (!data->dready_trig) return -ENOMEM; diff --git a/drivers/iio/gyro/itg3200_buffer.c b/drivers/iio/gyro/itg3200_buffer.c index af0aaa146f0c..04dd6a7969ea 100644 --- a/drivers/iio/gyro/itg3200_buffer.c +++ b/drivers/iio/gyro/itg3200_buffer.c @@ -114,7 +114,7 @@ int itg3200_probe_trigger(struct iio_dev *indio_dev) struct itg3200 *st = iio_priv(indio_dev); st->trig = iio_trigger_alloc(&st->i2c->dev, "%s-dev%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (!st->trig) return -ENOMEM; diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c index f17a93519535..2b930c7f4d86 100644 --- a/drivers/iio/gyro/mpu3050-core.c +++ b/drivers/iio/gyro/mpu3050-core.c @@ -1058,7 +1058,7 @@ static int mpu3050_trigger_probe(struct iio_dev *indio_dev, int irq) mpu3050->trig = devm_iio_trigger_alloc(&indio_dev->dev, "%s-dev%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (!mpu3050->trig) return -ENOMEM; diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c index 1fa8d51d5080..d4921385aaf7 100644 --- a/drivers/iio/health/afe4403.c +++ b/drivers/iio/health/afe4403.c @@ -521,7 +521,7 @@ static int afe4403_probe(struct spi_device *spi) afe->trig = devm_iio_trigger_alloc(afe->dev, "%s-dev%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (!afe->trig) { dev_err(afe->dev, "Unable to allocate IIO trigger\n"); ret = -ENOMEM; diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index e1476bf79fe2..d8a27dfe074a 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -528,7 +528,7 @@ static int afe4404_probe(struct i2c_client *client, afe->trig = devm_iio_trigger_alloc(afe->dev, "%s-dev%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (!afe->trig) { dev_err(afe->dev, "Unable to allocate IIO trigger\n"); ret = -ENOMEM; diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c index fa5540fabacc..48eedc29b28a 100644 --- a/drivers/iio/imu/adis_trigger.c +++ b/drivers/iio/imu/adis_trigger.c @@ -62,7 +62,8 @@ int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) int ret; adis->trig = devm_iio_trigger_alloc(&adis->spi->dev, "%s-dev%d", - indio_dev->name, indio_dev->id); + indio_dev->name, + iio_device_id(indio_dev)); if (!adis->trig) return -ENOMEM; diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c index 290b5ef83f77..b63bd7e5e5e5 100644 --- a/drivers/iio/imu/bmi160/bmi160_core.c +++ b/drivers/iio/imu/bmi160/bmi160_core.c @@ -785,7 +785,8 @@ int bmi160_probe_trigger(struct iio_dev *indio_dev, int irq, u32 irq_type) int ret; data->trig = devm_iio_trigger_alloc(&indio_dev->dev, "%s-dev%d", - indio_dev->name, indio_dev->id); + indio_dev->name, + iio_device_id(indio_dev)); if (data->trig == NULL) return -ENOMEM; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c index de8ed1446d60..e21ba778595a 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c @@ -238,7 +238,7 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev, int irq_type) st->trig = devm_iio_trigger_alloc(&indio_dev->dev, "%s-dev%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (!st->trig) return -ENOMEM; diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index fc5a60fcfec0..d3e06ce99c1e 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -1264,7 +1264,7 @@ static struct iio_trigger *kmx61_trigger_setup(struct kmx61_data *data, "%s-%s-dev%d", indio_dev->name, tag, - indio_dev->id); + iio_device_id(indio_dev)); if (!trig) return ERR_PTR(-ENOMEM); diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 3fdcf2d4997a..ec21341c6322 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -169,6 +169,20 @@ static const char * const iio_chan_info_postfix[] = { [IIO_CHAN_INFO_THERMOCOUPLE_TYPE] = "thermocouple_type", [IIO_CHAN_INFO_CALIBAMBIENT] = "calibambient", }; +/** + * iio_device_id() - query the unique ID for the device + * @indio_dev: Device structure whose ID is being queried + * + * The IIO device ID is a unique index used for example for the naming + * of the character device /dev/iio\:device[ID] + */ +int iio_device_id(struct iio_dev *indio_dev) +{ + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + + return iio_dev_opaque->id; +} +EXPORT_SYMBOL_GPL(iio_device_id); /** * iio_sysfs_match_string_with_gaps - matches given string in an array with gaps @@ -1588,7 +1602,7 @@ static void iio_dev_release(struct device *device) iio_device_detach_buffers(indio_dev); - ida_simple_remove(&iio_ida, indio_dev->id); + ida_simple_remove(&iio_ida, iio_dev_opaque->id); kfree(iio_dev_opaque); } @@ -1631,14 +1645,14 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv) mutex_init(&indio_dev->info_exist_lock); INIT_LIST_HEAD(&iio_dev_opaque->channel_attr_list); - indio_dev->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL); - if (indio_dev->id < 0) { + iio_dev_opaque->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL); + if (iio_dev_opaque->id < 0) { /* cannot use a dev_err as the name isn't available */ pr_err("failed to get device id\n"); kfree(iio_dev_opaque); return NULL; } - dev_set_name(&indio_dev->dev, "iio:device%d", indio_dev->id); + dev_set_name(&indio_dev->dev, "iio:device%d", iio_dev_opaque->id); INIT_LIST_HEAD(&iio_dev_opaque->buffer_list); INIT_LIST_HEAD(&iio_dev_opaque->ioctl_handlers); @@ -1891,7 +1905,7 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod) cdev_init(&indio_dev->chrdev, &iio_event_fileops); if (iio_dev_opaque->attached_buffers_cnt || iio_dev_opaque->event_interface) { - indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id); + indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), iio_dev_opaque->id); indio_dev->chrdev.owner = this_mod; } diff --git a/drivers/iio/industrialio-triggered-event.c b/drivers/iio/industrialio-triggered-event.c index 53da9ab17a62..4bedc65c9fe3 100644 --- a/drivers/iio/industrialio-triggered-event.c +++ b/drivers/iio/industrialio-triggered-event.c @@ -37,7 +37,7 @@ int iio_triggered_event_setup(struct iio_dev *indio_dev, indio_dev, "%s_consumer%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (indio_dev->pollfunc_event == NULL) return -ENOMEM; diff --git a/drivers/iio/light/acpi-als.c b/drivers/iio/light/acpi-als.c index 0a6ab5761eec..e1ff6f524f4b 100644 --- a/drivers/iio/light/acpi-als.c +++ b/drivers/iio/light/acpi-als.c @@ -204,7 +204,8 @@ static int acpi_als_add(struct acpi_device *device) indio_dev->channels = acpi_als_channels; indio_dev->num_channels = ARRAY_SIZE(acpi_als_channels); - als->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, indio_dev->id); + als->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, + iio_device_id(indio_dev)); if (!als->trig) return -ENOMEM; diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index 033578f444e4..7e332de0e6a5 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -985,7 +985,7 @@ static int rpr0521_probe(struct i2c_client *client, /* Trigger0 producer setup */ data->drdy_trigger0 = devm_iio_trigger_alloc( indio_dev->dev.parent, - "%s-dev%d", indio_dev->name, indio_dev->id); + "%s-dev%d", indio_dev->name, iio_device_id(indio_dev)); if (!data->drdy_trigger0) { ret = -ENOMEM; goto err_pm_disable; diff --git a/drivers/iio/light/si1145.c b/drivers/iio/light/si1145.c index 9b5c99823943..3fb52402fcc3 100644 --- a/drivers/iio/light/si1145.c +++ b/drivers/iio/light/si1145.c @@ -1243,7 +1243,7 @@ static int si1145_probe_trigger(struct iio_dev *indio_dev) int ret; trig = devm_iio_trigger_alloc(&client->dev, - "%s-dev%d", indio_dev->name, indio_dev->id); + "%s-dev%d", indio_dev->name, iio_device_id(indio_dev)); if (!trig) return -ENOMEM; diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index 2f7916f95689..4a61865d01cd 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -998,7 +998,8 @@ static int vcnl4010_probe_trigger(struct iio_dev *indio_dev) struct iio_trigger *trigger; trigger = devm_iio_trigger_alloc(&client->dev, "%s-dev%d", - indio_dev->name, indio_dev->id); + indio_dev->name, + iio_device_id(indio_dev)); if (!trigger) return -ENOMEM; diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c index ae87740d9cef..691a54b763e1 100644 --- a/drivers/iio/light/vcnl4035.c +++ b/drivers/iio/light/vcnl4035.c @@ -507,7 +507,7 @@ static int vcnl4035_probe_trigger(struct iio_dev *indio_dev) data->drdy_trigger0 = devm_iio_trigger_alloc( indio_dev->dev.parent, - "%s-dev%d", indio_dev->name, indio_dev->id); + "%s-dev%d", indio_dev->name, iio_device_id(indio_dev)); if (!data->drdy_trigger0) return -ENOMEM; diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index 00f9766bad5c..d75b437a43f2 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -915,7 +915,7 @@ int bmc150_magn_probe(struct device *dev, struct regmap *regmap, data->dready_trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (!data->dready_trig) { ret = -ENOMEM; dev_err(dev, "iio trigger alloc failed\n"); diff --git a/drivers/iio/magnetometer/rm3100-core.c b/drivers/iio/magnetometer/rm3100-core.c index dd811da9cb6d..4df5887fd04c 100644 --- a/drivers/iio/magnetometer/rm3100-core.c +++ b/drivers/iio/magnetometer/rm3100-core.c @@ -575,7 +575,7 @@ int rm3100_common_probe(struct device *dev, struct regmap *regmap, int irq) data->drdy_trig = devm_iio_trigger_alloc(dev, "%s-drdy%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (!data->drdy_trig) return -ENOMEM; diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c index 8a9c576616ee..1948e2d22c27 100644 --- a/drivers/iio/potentiostat/lmp91000.c +++ b/drivers/iio/potentiostat/lmp91000.c @@ -323,7 +323,8 @@ static int lmp91000_probe(struct i2c_client *client, } data->trig = devm_iio_trigger_alloc(dev, "%s-mux%d", - indio_dev->name, indio_dev->id); + indio_dev->name, + iio_device_id(indio_dev)); if (!data->trig) { dev_err(dev, "cannot allocate iio trigger.\n"); return -ENOMEM; diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c index a93411216aee..89295c90f801 100644 --- a/drivers/iio/pressure/zpa2326.c +++ b/drivers/iio/pressure/zpa2326.c @@ -1408,7 +1408,8 @@ static int zpa2326_init_managed_trigger(struct device *parent, return 0; trigger = devm_iio_trigger_alloc(parent, "%s-dev%d", - indio_dev->name, indio_dev->id); + indio_dev->name, + iio_device_id(indio_dev)); if (!trigger) return -ENOMEM; diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index edc4a35ae66d..dc20fe81232c 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -404,7 +404,8 @@ static int as3935_probe(struct spi_device *spi) indio_dev->info = &as3935_info; trig = devm_iio_trigger_alloc(dev, "%s-dev%d", - indio_dev->name, indio_dev->id); + indio_dev->name, + iio_device_id(indio_dev)); if (!trig) return -ENOMEM; diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c index 327ebb7ddbb9..175f3b7c61d7 100644 --- a/drivers/iio/proximity/sx9310.c +++ b/drivers/iio/proximity/sx9310.c @@ -1473,7 +1473,7 @@ static int sx9310_probe(struct i2c_client *client) data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, - indio_dev->id); + iio_device_id(indio_dev)); if (!data->trig) return -ENOMEM; diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index a87f4a8e4327..3e4ddb2e8c2b 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -946,7 +946,7 @@ static int sx9500_probe(struct i2c_client *client, return ret; data->trig = devm_iio_trigger_alloc(&client->dev, - "%s-dev%d", indio_dev->name, indio_dev->id); + "%s-dev%d", indio_dev->name, iio_device_id(indio_dev)); if (!data->trig) return -ENOMEM; -- cgit v1.2.3 From 6eaf9f6a2738789dedb1e962096f61aaddd81464 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 26 Apr 2021 18:49:05 +0100 Subject: iio: core: move @driver_module from struct iio_dev to struct iio_dev_opaque Continuing move to hide internal elements from drivers, move this structure element over. It's only accessed from iio core files so this one was straight forward and no accessor functions are needed. Signed-off-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210426174911.397061-4-jic23@kernel.org --- drivers/iio/industrialio-core.c | 2 +- drivers/iio/industrialio-trigger.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index ec21341c6322..58b35db00a81 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1858,7 +1858,7 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod) if (!indio_dev->info) return -EINVAL; - indio_dev->driver_module = this_mod; + iio_dev_opaque->driver_module = this_mod; /* If the calling driver did not initialize of_node, do it here */ if (!indio_dev->dev.of_node && indio_dev->dev.parent) indio_dev->dev.of_node = indio_dev->dev.parent->of_node; diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index 3236647b2c37..b489eeeb0004 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -13,6 +13,7 @@ #include #include +#include #include #include "iio_core.h" #include "iio_core_trigger.h" @@ -240,12 +241,13 @@ static void iio_trigger_put_irq(struct iio_trigger *trig, int irq) int iio_trigger_attach_poll_func(struct iio_trigger *trig, struct iio_poll_func *pf) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(pf->indio_dev); bool notinuse = bitmap_empty(trig->pool, CONFIG_IIO_CONSUMERS_PER_TRIGGER); int ret = 0; /* Prevent the module from being removed whilst attached to a trigger */ - __module_get(pf->indio_dev->driver_module); + __module_get(iio_dev_opaque->driver_module); /* Get irq number */ pf->irq = iio_trigger_get_irq(trig); @@ -284,13 +286,14 @@ out_free_irq: out_put_irq: iio_trigger_put_irq(trig, pf->irq); out_put_module: - module_put(pf->indio_dev->driver_module); + module_put(iio_dev_opaque->driver_module); return ret; } int iio_trigger_detach_poll_func(struct iio_trigger *trig, struct iio_poll_func *pf) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(pf->indio_dev); bool no_other_users = bitmap_weight(trig->pool, CONFIG_IIO_CONSUMERS_PER_TRIGGER) == 1; int ret = 0; @@ -304,7 +307,7 @@ int iio_trigger_detach_poll_func(struct iio_trigger *trig, trig->attached_own_device = false; iio_trigger_put_irq(trig, pf->irq); free_irq(pf->irq, pf); - module_put(pf->indio_dev->driver_module); + module_put(iio_dev_opaque->driver_module); return ret; } -- cgit v1.2.3 From 3028e0c2af95dd476ccd71f4fc025990385168c2 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 26 Apr 2021 18:49:06 +0100 Subject: iio: core: move @trig_readonly from struct iio_dev to struct iio_dev_opaque This is only set via the iio_trig_set_immutable() call and later used by the IIO core so there is no benefit in drivers being able to access it. Signed-off-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210426174911.397061-5-jic23@kernel.org --- drivers/iio/industrialio-trigger.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index b489eeeb0004..b23caa2f2aa1 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -117,14 +117,17 @@ EXPORT_SYMBOL(iio_trigger_unregister); int iio_trigger_set_immutable(struct iio_dev *indio_dev, struct iio_trigger *trig) { + struct iio_dev_opaque *iio_dev_opaque; + if (!indio_dev || !trig) return -EINVAL; + iio_dev_opaque = to_iio_dev_opaque(indio_dev); mutex_lock(&indio_dev->mlock); - WARN_ON(indio_dev->trig_readonly); + WARN_ON(iio_dev_opaque->trig_readonly); indio_dev->trig = iio_trigger_get(trig); - indio_dev->trig_readonly = true; + iio_dev_opaque->trig_readonly = true; mutex_unlock(&indio_dev->mlock); return 0; @@ -402,6 +405,7 @@ static ssize_t iio_trigger_write_current(struct device *dev, size_t len) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); struct iio_trigger *oldtrig = indio_dev->trig; struct iio_trigger *trig; int ret; @@ -411,7 +415,7 @@ static ssize_t iio_trigger_write_current(struct device *dev, mutex_unlock(&indio_dev->mlock); return -EBUSY; } - if (indio_dev->trig_readonly) { + if (iio_dev_opaque->trig_readonly) { mutex_unlock(&indio_dev->mlock); return -EPERM; } -- cgit v1.2.3 From 62f4f36cdfcdbb961bbbeab15e6595dd391d2205 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 26 Apr 2021 18:49:07 +0100 Subject: iio: core: move @scan_index_timestamp to struct iio_dev_opaque No reason for this cached value to be exposed to drivers so move it to the opaque structure. Signed-off-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210426174911.397061-6-jic23@kernel.org --- drivers/iio/industrialio-buffer.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 9a8e16c7e9af..9ecb3c58d94c 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -601,8 +601,10 @@ static unsigned int iio_storage_bytes_for_si(struct iio_dev *indio_dev, static unsigned int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + return iio_storage_bytes_for_si(indio_dev, - indio_dev->scan_index_timestamp); + iio_dev_opaque->scan_index_timestamp); } static int iio_compute_scan_bytes(struct iio_dev *indio_dev, @@ -1469,6 +1471,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, struct iio_dev *indio_dev, int index) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); struct iio_dev_attr *p; struct attribute **attr; int ret, i, attrn, scan_el_attrcount, buffer_attrcount; @@ -1495,7 +1498,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, goto error_cleanup_dynamic; scan_el_attrcount += ret; if (channels[i].type == IIO_TIMESTAMP) - indio_dev->scan_index_timestamp = + iio_dev_opaque->scan_index_timestamp = channels[i].scan_index; } if (indio_dev->masklength && buffer->scan_mask == NULL) { -- cgit v1.2.3 From b804e2b76ac6d5559b99588e0190ac97b5597497 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 26 Apr 2021 18:49:08 +0100 Subject: iio: core: move @info_exist_lock to struct iio_dev_opaque This lock is only of interest to the IIO core, so make it only visible there. Signed-off-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210426174911.397061-7-jic23@kernel.org --- drivers/iio/industrialio-buffer.c | 5 +++-- drivers/iio/industrialio-core.c | 10 ++++----- drivers/iio/inkern.c | 46 ++++++++++++++++++++++++--------------- 3 files changed, 36 insertions(+), 25 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 9ecb3c58d94c..10923b40c76d 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -1150,12 +1150,13 @@ int iio_update_buffers(struct iio_dev *indio_dev, struct iio_buffer *insert_buffer, struct iio_buffer *remove_buffer) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); int ret; if (insert_buffer == remove_buffer) return 0; - mutex_lock(&indio_dev->info_exist_lock); + mutex_lock(&iio_dev_opaque->info_exist_lock); mutex_lock(&indio_dev->mlock); if (insert_buffer && iio_buffer_is_active(insert_buffer)) @@ -1178,7 +1179,7 @@ int iio_update_buffers(struct iio_dev *indio_dev, out_unlock: mutex_unlock(&indio_dev->mlock); - mutex_unlock(&indio_dev->info_exist_lock); + mutex_unlock(&iio_dev_opaque->info_exist_lock); return ret; } diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 58b35db00a81..74bb977e2357 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1642,7 +1642,7 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv) device_initialize(&indio_dev->dev); iio_device_set_drvdata(indio_dev, (void *)indio_dev); mutex_init(&indio_dev->mlock); - mutex_init(&indio_dev->info_exist_lock); + mutex_init(&iio_dev_opaque->info_exist_lock); INIT_LIST_HEAD(&iio_dev_opaque->channel_attr_list); iio_dev_opaque->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL); @@ -1779,7 +1779,7 @@ static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) struct iio_ioctl_handler *h; int ret = -ENODEV; - mutex_lock(&indio_dev->info_exist_lock); + mutex_lock(&iio_dev_opaque->info_exist_lock); /** * The NULL check here is required to prevent crashing when a device @@ -1799,7 +1799,7 @@ static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ret = -ENODEV; out_unlock: - mutex_unlock(&indio_dev->info_exist_lock); + mutex_unlock(&iio_dev_opaque->info_exist_lock); return ret; } @@ -1938,7 +1938,7 @@ void iio_device_unregister(struct iio_dev *indio_dev) { cdev_device_del(&indio_dev->chrdev, &indio_dev->dev); - mutex_lock(&indio_dev->info_exist_lock); + mutex_lock(&iio_dev_opaque->info_exist_lock); iio_device_unregister_debugfs(indio_dev); @@ -1949,7 +1949,7 @@ void iio_device_unregister(struct iio_dev *indio_dev) iio_device_wakeup_eventset(indio_dev); iio_buffer_wakeup_poll(indio_dev); - mutex_unlock(&indio_dev->info_exist_lock); + mutex_unlock(&iio_dev_opaque->info_exist_lock); iio_buffers_free_sysfs_and_mask(indio_dev); } diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 5aa740cea661..391a3380a1d1 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -10,6 +10,7 @@ #include #include +#include #include "iio_core.h" #include #include @@ -538,9 +539,10 @@ static int iio_channel_read(struct iio_channel *chan, int *val, int *val2, int iio_read_channel_raw(struct iio_channel *chan, int *val) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); int ret; - mutex_lock(&chan->indio_dev->info_exist_lock); + mutex_lock(&iio_dev_opaque->info_exist_lock); if (chan->indio_dev->info == NULL) { ret = -ENODEV; goto err_unlock; @@ -548,7 +550,7 @@ int iio_read_channel_raw(struct iio_channel *chan, int *val) ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW); err_unlock: - mutex_unlock(&chan->indio_dev->info_exist_lock); + mutex_unlock(&iio_dev_opaque->info_exist_lock); return ret; } @@ -556,9 +558,10 @@ EXPORT_SYMBOL_GPL(iio_read_channel_raw); int iio_read_channel_average_raw(struct iio_channel *chan, int *val) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); int ret; - mutex_lock(&chan->indio_dev->info_exist_lock); + mutex_lock(&iio_dev_opaque->info_exist_lock); if (chan->indio_dev->info == NULL) { ret = -ENODEV; goto err_unlock; @@ -566,7 +569,7 @@ int iio_read_channel_average_raw(struct iio_channel *chan, int *val) ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_AVERAGE_RAW); err_unlock: - mutex_unlock(&chan->indio_dev->info_exist_lock); + mutex_unlock(&iio_dev_opaque->info_exist_lock); return ret; } @@ -631,9 +634,10 @@ static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan, int iio_convert_raw_to_processed(struct iio_channel *chan, int raw, int *processed, unsigned int scale) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); int ret; - mutex_lock(&chan->indio_dev->info_exist_lock); + mutex_lock(&iio_dev_opaque->info_exist_lock); if (chan->indio_dev->info == NULL) { ret = -ENODEV; goto err_unlock; @@ -642,7 +646,7 @@ int iio_convert_raw_to_processed(struct iio_channel *chan, int raw, ret = iio_convert_raw_to_processed_unlocked(chan, raw, processed, scale); err_unlock: - mutex_unlock(&chan->indio_dev->info_exist_lock); + mutex_unlock(&iio_dev_opaque->info_exist_lock); return ret; } @@ -651,9 +655,10 @@ EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed); int iio_read_channel_attribute(struct iio_channel *chan, int *val, int *val2, enum iio_chan_info_enum attribute) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); int ret; - mutex_lock(&chan->indio_dev->info_exist_lock); + mutex_lock(&iio_dev_opaque->info_exist_lock); if (chan->indio_dev->info == NULL) { ret = -ENODEV; goto err_unlock; @@ -661,7 +666,7 @@ int iio_read_channel_attribute(struct iio_channel *chan, int *val, int *val2, ret = iio_channel_read(chan, val, val2, attribute); err_unlock: - mutex_unlock(&chan->indio_dev->info_exist_lock); + mutex_unlock(&iio_dev_opaque->info_exist_lock); return ret; } @@ -676,9 +681,10 @@ EXPORT_SYMBOL_GPL(iio_read_channel_offset); int iio_read_channel_processed_scale(struct iio_channel *chan, int *val, unsigned int scale) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); int ret; - mutex_lock(&chan->indio_dev->info_exist_lock); + mutex_lock(&iio_dev_opaque->info_exist_lock); if (chan->indio_dev->info == NULL) { ret = -ENODEV; goto err_unlock; @@ -699,7 +705,7 @@ int iio_read_channel_processed_scale(struct iio_channel *chan, int *val, } err_unlock: - mutex_unlock(&chan->indio_dev->info_exist_lock); + mutex_unlock(&iio_dev_opaque->info_exist_lock); return ret; } @@ -733,9 +739,10 @@ int iio_read_avail_channel_attribute(struct iio_channel *chan, const int **vals, int *type, int *length, enum iio_chan_info_enum attribute) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); int ret; - mutex_lock(&chan->indio_dev->info_exist_lock); + mutex_lock(&iio_dev_opaque->info_exist_lock); if (!chan->indio_dev->info) { ret = -ENODEV; goto err_unlock; @@ -743,7 +750,7 @@ int iio_read_avail_channel_attribute(struct iio_channel *chan, ret = iio_channel_read_avail(chan, vals, type, length, attribute); err_unlock: - mutex_unlock(&chan->indio_dev->info_exist_lock); + mutex_unlock(&iio_dev_opaque->info_exist_lock); return ret; } @@ -815,10 +822,11 @@ static int iio_channel_read_max(struct iio_channel *chan, int iio_read_max_channel_raw(struct iio_channel *chan, int *val) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); int ret; int type; - mutex_lock(&chan->indio_dev->info_exist_lock); + mutex_lock(&iio_dev_opaque->info_exist_lock); if (!chan->indio_dev->info) { ret = -ENODEV; goto err_unlock; @@ -826,7 +834,7 @@ int iio_read_max_channel_raw(struct iio_channel *chan, int *val) ret = iio_channel_read_max(chan, val, NULL, &type, IIO_CHAN_INFO_RAW); err_unlock: - mutex_unlock(&chan->indio_dev->info_exist_lock); + mutex_unlock(&iio_dev_opaque->info_exist_lock); return ret; } @@ -834,10 +842,11 @@ EXPORT_SYMBOL_GPL(iio_read_max_channel_raw); int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); int ret = 0; /* Need to verify underlying driver has not gone away */ - mutex_lock(&chan->indio_dev->info_exist_lock); + mutex_lock(&iio_dev_opaque->info_exist_lock); if (chan->indio_dev->info == NULL) { ret = -ENODEV; goto err_unlock; @@ -845,7 +854,7 @@ int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type) *type = chan->channel->type; err_unlock: - mutex_unlock(&chan->indio_dev->info_exist_lock); + mutex_unlock(&iio_dev_opaque->info_exist_lock); return ret; } @@ -861,9 +870,10 @@ static int iio_channel_write(struct iio_channel *chan, int val, int val2, int iio_write_channel_attribute(struct iio_channel *chan, int val, int val2, enum iio_chan_info_enum attribute) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev); int ret; - mutex_lock(&chan->indio_dev->info_exist_lock); + mutex_lock(&iio_dev_opaque->info_exist_lock); if (chan->indio_dev->info == NULL) { ret = -ENODEV; goto err_unlock; @@ -871,7 +881,7 @@ int iio_write_channel_attribute(struct iio_channel *chan, int val, int val2, ret = iio_channel_write(chan, val, val2, attribute); err_unlock: - mutex_unlock(&chan->indio_dev->info_exist_lock); + mutex_unlock(&iio_dev_opaque->info_exist_lock); return ret; } -- cgit v1.2.3 From 396f7234856956eb29f009da6e5d846f29f87ebd Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 26 Apr 2021 18:49:09 +0100 Subject: iio: core: move @chrdev from struct iio_dev to struct iio_dev_opaque No reason for this to be exposed to the drivers, so lets move it to the opaque structure. Signed-off-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210426174911.397061-8-jic23@kernel.org --- drivers/iio/industrialio-core.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 74bb977e2357..0aba0a0085eb 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1715,8 +1715,9 @@ EXPORT_SYMBOL_GPL(devm_iio_device_alloc); **/ static int iio_chrdev_open(struct inode *inode, struct file *filp) { - struct iio_dev *indio_dev = container_of(inode->i_cdev, - struct iio_dev, chrdev); + struct iio_dev_opaque *iio_dev_opaque = + container_of(inode->i_cdev, struct iio_dev_opaque, chrdev); + struct iio_dev *indio_dev = &iio_dev_opaque->indio_dev; struct iio_dev_buffer_pair *ib; if (test_and_set_bit(IIO_BUSY_BIT_POS, &indio_dev->flags)) @@ -1749,8 +1750,9 @@ static int iio_chrdev_open(struct inode *inode, struct file *filp) static int iio_chrdev_release(struct inode *inode, struct file *filp) { struct iio_dev_buffer_pair *ib = filp->private_data; - struct iio_dev *indio_dev = container_of(inode->i_cdev, - struct iio_dev, chrdev); + struct iio_dev_opaque *iio_dev_opaque = + container_of(inode->i_cdev, struct iio_dev_opaque, chrdev); + struct iio_dev *indio_dev = &iio_dev_opaque->indio_dev; kfree(ib); clear_bit(IIO_BUSY_BIT_POS, &indio_dev->flags); iio_device_put(indio_dev); @@ -1900,19 +1902,19 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod) indio_dev->setup_ops = &noop_ring_setup_ops; if (iio_dev_opaque->attached_buffers_cnt) - cdev_init(&indio_dev->chrdev, &iio_buffer_fileops); + cdev_init(&iio_dev_opaque->chrdev, &iio_buffer_fileops); else if (iio_dev_opaque->event_interface) - cdev_init(&indio_dev->chrdev, &iio_event_fileops); + cdev_init(&iio_dev_opaque->chrdev, &iio_event_fileops); if (iio_dev_opaque->attached_buffers_cnt || iio_dev_opaque->event_interface) { indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), iio_dev_opaque->id); - indio_dev->chrdev.owner = this_mod; + iio_dev_opaque->chrdev.owner = this_mod; } /* assign device groups now; they should be all registered now */ indio_dev->dev.groups = iio_dev_opaque->groups; - ret = cdev_device_add(&indio_dev->chrdev, &indio_dev->dev); + ret = cdev_device_add(&iio_dev_opaque->chrdev, &indio_dev->dev); if (ret < 0) goto error_unreg_eventset; @@ -1936,7 +1938,9 @@ EXPORT_SYMBOL(__iio_device_register); **/ void iio_device_unregister(struct iio_dev *indio_dev) { - cdev_device_del(&indio_dev->chrdev, &indio_dev->dev); + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + + cdev_device_del(&iio_dev_opaque->chrdev, &indio_dev->dev); mutex_lock(&iio_dev_opaque->info_exist_lock); -- cgit v1.2.3 From 8b1c82cb849f8f7c758891099f2128b8fbc05744 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 26 Apr 2021 18:49:10 +0100 Subject: iio: core: move @flags from struct iio_dev to struct iio_dev_opaque No reason any driver should ever need access to this field, so hide it. Signed-off-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210426174911.397061-9-jic23@kernel.org --- drivers/iio/industrialio-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 0aba0a0085eb..29ff7668297e 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1720,7 +1720,7 @@ static int iio_chrdev_open(struct inode *inode, struct file *filp) struct iio_dev *indio_dev = &iio_dev_opaque->indio_dev; struct iio_dev_buffer_pair *ib; - if (test_and_set_bit(IIO_BUSY_BIT_POS, &indio_dev->flags)) + if (test_and_set_bit(IIO_BUSY_BIT_POS, &iio_dev_opaque->flags)) return -EBUSY; iio_device_get(indio_dev); @@ -1728,7 +1728,7 @@ static int iio_chrdev_open(struct inode *inode, struct file *filp) ib = kmalloc(sizeof(*ib), GFP_KERNEL); if (!ib) { iio_device_put(indio_dev); - clear_bit(IIO_BUSY_BIT_POS, &indio_dev->flags); + clear_bit(IIO_BUSY_BIT_POS, &iio_dev_opaque->flags); return -ENOMEM; } @@ -1754,7 +1754,7 @@ static int iio_chrdev_release(struct inode *inode, struct file *filp) container_of(inode->i_cdev, struct iio_dev_opaque, chrdev); struct iio_dev *indio_dev = &iio_dev_opaque->indio_dev; kfree(ib); - clear_bit(IIO_BUSY_BIT_POS, &indio_dev->flags); + clear_bit(IIO_BUSY_BIT_POS, &iio_dev_opaque->flags); iio_device_put(indio_dev); return 0; -- cgit v1.2.3 From 62a486c46d61bc684967fc3f83eed15dde49cf9b Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 26 Apr 2021 18:49:11 +0100 Subject: iio: core: move @clock_id from struct iio_dev to struct iio_dev_opaque There is already an acessor function used to access it, making this move straight forward. Signed-off-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210426174911.397061-10-jic23@kernel.org --- drivers/iio/industrialio-core.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 29ff7668297e..bfa20a346f71 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -271,13 +271,25 @@ int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id) mutex_unlock(&indio_dev->mlock); return -EBUSY; } - indio_dev->clock_id = clock_id; + iio_dev_opaque->clock_id = clock_id; mutex_unlock(&indio_dev->mlock); return 0; } EXPORT_SYMBOL(iio_device_set_clock); +/** + * iio_device_get_clock() - Retrieve current timestamping clock for the device + * @indio_dev: IIO device structure containing the device + */ +clockid_t iio_device_get_clock(const struct iio_dev *indio_dev) +{ + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + + return iio_dev_opaque->clock_id; +} +EXPORT_SYMBOL(iio_device_get_clock); + /** * iio_get_time_ns() - utility function to get a time stamp for events etc * @indio_dev: device -- cgit v1.2.3 From 3b91452032c4f2df58df014063dc6146b2378b22 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 14 Apr 2021 22:54:48 +0300 Subject: iio: accel: st_accel: Move platform data from header to C file Platform data is solely used by one file. Don't share it with others. While at it, drop unneeded anymore __maybe_unused and fix kernel doc to avoid warning: st_accel_core.c:1079: error: Cannot parse struct or union! by converting to a simple comment. It is described at the declaration. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210414195454.84183-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/st_accel.h | 8 -------- drivers/iio/accel/st_accel_core.c | 5 +++++ 2 files changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h index 5d356288e001..181ebe79c4eb 100644 --- a/drivers/iio/accel/st_accel.h +++ b/drivers/iio/accel/st_accel.h @@ -62,14 +62,6 @@ enum st_accel_type { #define LIS2DE12_ACCEL_DEV_NAME "lis2de12" #define LIS2HH12_ACCEL_DEV_NAME "lis2hh12" -/** -* struct st_sensors_platform_data - default accel platform data -* @drdy_int_pin: default accel DRDY is available on INT1 pin. -*/ -static __maybe_unused const struct st_sensors_platform_data default_accel_pdata = { - .drdy_int_pin = 1, -}; - const struct st_sensor_settings *st_accel_get_settings(const char *name); int st_accel_common_probe(struct iio_dev *indio_dev); void st_accel_common_remove(struct iio_dev *indio_dev); diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 43c50167d220..a1bd7e3b912e 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -983,6 +983,11 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { }; +/* Default accel DRDY is available on INT1 pin */ +static const struct st_sensors_platform_data default_accel_pdata = { + .drdy_int_pin = 1, +}; + static int st_accel_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask) -- cgit v1.2.3 From dffdd75678745e9eccf31ad16e4849b663645e3b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 14 Apr 2021 22:54:49 +0300 Subject: iio: gyro: st_gyro: Move platform data from header to C file Platform data is solely used by one file. Don't share it with others. While at it, drop unneeded anymore __maybe_unused and fix kernel doc to avoid warning: st_gyro_core.c:366: error: Cannot parse struct or union! by converting to a simple comment. It is described at the declaration. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210414195454.84183-2-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/st_gyro.h | 8 -------- drivers/iio/gyro/st_gyro_core.c | 5 +++++ 2 files changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/gyro/st_gyro.h b/drivers/iio/gyro/st_gyro.h index fd9171cc3aba..b385fe664dcc 100644 --- a/drivers/iio/gyro/st_gyro.h +++ b/drivers/iio/gyro/st_gyro.h @@ -24,14 +24,6 @@ #define LSM330_GYRO_DEV_NAME "lsm330_gyro" #define LSM9DS0_GYRO_DEV_NAME "lsm9ds0_gyro" -/** - * struct st_sensors_platform_data - gyro platform data - * @drdy_int_pin: DRDY on gyros is available only on INT2 pin. - */ -static __maybe_unused const struct st_sensors_platform_data gyro_pdata = { - .drdy_int_pin = 2, -}; - const struct st_sensor_settings *st_gyro_get_settings(const char *name); int st_gyro_common_probe(struct iio_dev *indio_dev); void st_gyro_common_remove(struct iio_dev *indio_dev); diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index c8aa051995d3..e000504e1df4 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -357,6 +357,11 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = { }, }; +/* DRDY on gyros is available only on INT2 pin */ +static const struct st_sensors_platform_data gyro_pdata = { + .drdy_int_pin = 2, +}; + static int st_gyro_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask) -- cgit v1.2.3 From 38934daf7b5c1b35a01748cb7d4272282cc3a890 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 14 Apr 2021 22:54:50 +0300 Subject: iio: magnetometer: st_magn: Provide default platform data Provide default platform data for magnetometer in case it supports DRDY. One case is LSM9DS0 IMU, on which it is the case. Since accelerometer is using INT1, default magnetometer to INT2. While at it, update description of the drdy_int_pin field. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210414195454.84183-3-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/st_magn_core.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 71faebd07feb..55357f266b8b 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -383,6 +383,11 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = { }, }; +/* Default magn DRDY is available on INT2 pin */ +static const struct st_sensors_platform_data default_magn_pdata = { + .drdy_int_pin = 2, +}; + static int st_magn_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask) @@ -490,6 +495,7 @@ EXPORT_SYMBOL(st_magn_get_settings); int st_magn_common_probe(struct iio_dev *indio_dev) { struct st_sensor_data *mdata = iio_priv(indio_dev); + struct st_sensors_platform_data *pdata = dev_get_platdata(mdata->dev); int err; indio_dev->modes = INDIO_DIRECT_MODE; @@ -510,7 +516,10 @@ int st_magn_common_probe(struct iio_dev *indio_dev) mdata->current_fullscale = &mdata->sensor_settings->fs.fs_avl[0]; mdata->odr = mdata->sensor_settings->odr.odr_avl[0].hz; - err = st_sensors_init_sensor(indio_dev, NULL); + if (!pdata) + pdata = (struct st_sensors_platform_data *)&default_magn_pdata; + + err = st_sensors_init_sensor(indio_dev, pdata); if (err < 0) goto st_magn_power_off; -- cgit v1.2.3 From 7db4f2cacbede1c6d95552c0d10e77398665a733 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 14 Apr 2021 22:54:51 +0300 Subject: iio: st_sensors: Call st_sensors_power_enable() from bus drivers In case we would initialize two IIO devices from one physical device, we shouldn't have a clash on regulators. That's why move st_sensors_power_enable() call from core to bus drivers. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210414195454.84183-4-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/st_accel_core.c | 21 +++++---------------- drivers/iio/accel/st_accel_i2c.c | 17 +++++++++++++++-- drivers/iio/accel/st_accel_spi.c | 17 +++++++++++++++-- drivers/iio/gyro/st_gyro_core.c | 15 +++------------ drivers/iio/gyro/st_gyro_i2c.c | 17 +++++++++++++++-- drivers/iio/gyro/st_gyro_spi.c | 17 +++++++++++++++-- drivers/iio/magnetometer/st_magn_core.c | 15 +++------------ drivers/iio/magnetometer/st_magn_i2c.c | 14 +++++++++++++- drivers/iio/magnetometer/st_magn_spi.c | 14 +++++++++++++- drivers/iio/pressure/st_pressure_core.c | 15 +++------------ drivers/iio/pressure/st_pressure_i2c.c | 17 +++++++++++++++-- drivers/iio/pressure/st_pressure_spi.c | 17 +++++++++++++++-- 12 files changed, 130 insertions(+), 66 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index a1bd7e3b912e..5c258c1ca62d 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -1260,13 +1260,9 @@ int st_accel_common_probe(struct iio_dev *indio_dev) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &accel_info; - err = st_sensors_power_enable(indio_dev); - if (err) - return err; - err = st_sensors_verify_id(indio_dev); if (err < 0) - goto st_accel_power_off; + return err; adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS; indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS; @@ -1275,10 +1271,8 @@ int st_accel_common_probe(struct iio_dev *indio_dev) channels = devm_kmemdup(&indio_dev->dev, adata->sensor_settings->ch, channels_size, GFP_KERNEL); - if (!channels) { - err = -ENOMEM; - goto st_accel_power_off; - } + if (!channels) + return -ENOMEM; if (apply_acpi_orientation(indio_dev, channels)) dev_warn(&indio_dev->dev, @@ -1293,11 +1287,11 @@ int st_accel_common_probe(struct iio_dev *indio_dev) err = st_sensors_init_sensor(indio_dev, pdata); if (err < 0) - goto st_accel_power_off; + return err; err = st_accel_allocate_ring(indio_dev); if (err < 0) - goto st_accel_power_off; + return err; if (adata->irq > 0) { err = st_sensors_allocate_trigger(indio_dev, @@ -1320,9 +1314,6 @@ st_accel_device_register_error: st_sensors_deallocate_trigger(indio_dev); st_accel_probe_trigger_error: st_accel_deallocate_ring(indio_dev); -st_accel_power_off: - st_sensors_power_disable(indio_dev); - return err; } EXPORT_SYMBOL(st_accel_common_probe); @@ -1331,8 +1322,6 @@ void st_accel_common_remove(struct iio_dev *indio_dev) { struct st_sensor_data *adata = iio_priv(indio_dev); - st_sensors_power_disable(indio_dev); - iio_device_unregister(indio_dev); if (adata->irq > 0) st_sensors_deallocate_trigger(indio_dev); diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index 360e16f2cadb..95e305b88d5e 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -174,16 +174,29 @@ static int st_accel_i2c_probe(struct i2c_client *client) if (ret < 0) return ret; + ret = st_sensors_power_enable(indio_dev); + if (ret) + return ret; + ret = st_accel_common_probe(indio_dev); if (ret < 0) - return ret; + goto st_accel_power_off; return 0; + +st_accel_power_off: + st_sensors_power_disable(indio_dev); + + return ret; } static int st_accel_i2c_remove(struct i2c_client *client) { - st_accel_common_remove(i2c_get_clientdata(client)); + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + st_sensors_power_disable(indio_dev); + + st_accel_common_remove(indio_dev); return 0; } diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index 568ff1bae0ee..83d3308ce5cc 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -123,16 +123,29 @@ static int st_accel_spi_probe(struct spi_device *spi) if (err < 0) return err; + err = st_sensors_power_enable(indio_dev); + if (err) + return err; + err = st_accel_common_probe(indio_dev); if (err < 0) - return err; + goto st_accel_power_off; return 0; + +st_accel_power_off: + st_sensors_power_disable(indio_dev); + + return err; } static int st_accel_spi_remove(struct spi_device *spi) { - st_accel_common_remove(spi_get_drvdata(spi)); + struct iio_dev *indio_dev = spi_get_drvdata(spi); + + st_sensors_power_disable(indio_dev); + + st_accel_common_remove(indio_dev); return 0; } diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index e000504e1df4..ee3f0ea96ac5 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -471,13 +471,9 @@ int st_gyro_common_probe(struct iio_dev *indio_dev) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &gyro_info; - err = st_sensors_power_enable(indio_dev); - if (err) - return err; - err = st_sensors_verify_id(indio_dev); if (err < 0) - goto st_gyro_power_off; + return err; gdata->num_data_channels = ST_GYRO_NUMBER_DATA_CHANNELS; indio_dev->channels = gdata->sensor_settings->ch; @@ -490,11 +486,11 @@ int st_gyro_common_probe(struct iio_dev *indio_dev) err = st_sensors_init_sensor(indio_dev, pdata); if (err < 0) - goto st_gyro_power_off; + return err; err = st_gyro_allocate_ring(indio_dev); if (err < 0) - goto st_gyro_power_off; + return err; if (gdata->irq > 0) { err = st_sensors_allocate_trigger(indio_dev, @@ -517,9 +513,6 @@ st_gyro_device_register_error: st_sensors_deallocate_trigger(indio_dev); st_gyro_probe_trigger_error: st_gyro_deallocate_ring(indio_dev); -st_gyro_power_off: - st_sensors_power_disable(indio_dev); - return err; } EXPORT_SYMBOL(st_gyro_common_probe); @@ -528,8 +521,6 @@ void st_gyro_common_remove(struct iio_dev *indio_dev) { struct st_sensor_data *gdata = iio_priv(indio_dev); - st_sensors_power_disable(indio_dev); - iio_device_unregister(indio_dev); if (gdata->irq > 0) st_sensors_deallocate_trigger(indio_dev); diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c index 8190966e6ff0..a25cc0379e16 100644 --- a/drivers/iio/gyro/st_gyro_i2c.c +++ b/drivers/iio/gyro/st_gyro_i2c.c @@ -86,16 +86,29 @@ static int st_gyro_i2c_probe(struct i2c_client *client, if (err < 0) return err; + err = st_sensors_power_enable(indio_dev); + if (err) + return err; + err = st_gyro_common_probe(indio_dev); if (err < 0) - return err; + goto st_gyro_power_off; return 0; + +st_gyro_power_off: + st_sensors_power_disable(indio_dev); + + return err; } static int st_gyro_i2c_remove(struct i2c_client *client) { - st_gyro_common_remove(i2c_get_clientdata(client)); + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + st_sensors_power_disable(indio_dev); + + st_gyro_common_remove(indio_dev); return 0; } diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c index efb862763ca3..18d6a2aeda45 100644 --- a/drivers/iio/gyro/st_gyro_spi.c +++ b/drivers/iio/gyro/st_gyro_spi.c @@ -90,16 +90,29 @@ static int st_gyro_spi_probe(struct spi_device *spi) if (err < 0) return err; + err = st_sensors_power_enable(indio_dev); + if (err) + return err; + err = st_gyro_common_probe(indio_dev); if (err < 0) - return err; + goto st_gyro_power_off; return 0; + +st_gyro_power_off: + st_sensors_power_disable(indio_dev); + + return err; } static int st_gyro_spi_remove(struct spi_device *spi) { - st_gyro_common_remove(spi_get_drvdata(spi)); + struct iio_dev *indio_dev = spi_get_drvdata(spi); + + st_sensors_power_disable(indio_dev); + + st_gyro_common_remove(indio_dev); return 0; } diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 55357f266b8b..58da48434a25 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -501,13 +501,9 @@ int st_magn_common_probe(struct iio_dev *indio_dev) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &magn_info; - err = st_sensors_power_enable(indio_dev); - if (err) - return err; - err = st_sensors_verify_id(indio_dev); if (err < 0) - goto st_magn_power_off; + return err; mdata->num_data_channels = ST_MAGN_NUMBER_DATA_CHANNELS; indio_dev->channels = mdata->sensor_settings->ch; @@ -521,11 +517,11 @@ int st_magn_common_probe(struct iio_dev *indio_dev) err = st_sensors_init_sensor(indio_dev, pdata); if (err < 0) - goto st_magn_power_off; + return err; err = st_magn_allocate_ring(indio_dev); if (err < 0) - goto st_magn_power_off; + return err; if (mdata->irq > 0) { err = st_sensors_allocate_trigger(indio_dev, @@ -548,9 +544,6 @@ st_magn_device_register_error: st_sensors_deallocate_trigger(indio_dev); st_magn_probe_trigger_error: st_magn_deallocate_ring(indio_dev); -st_magn_power_off: - st_sensors_power_disable(indio_dev); - return err; } EXPORT_SYMBOL(st_magn_common_probe); @@ -559,8 +552,6 @@ void st_magn_common_remove(struct iio_dev *indio_dev) { struct st_sensor_data *mdata = iio_priv(indio_dev); - st_sensors_power_disable(indio_dev); - iio_device_unregister(indio_dev); if (mdata->irq > 0) st_sensors_deallocate_trigger(indio_dev); diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c index 36f4e7b53b24..3e23c117de8e 100644 --- a/drivers/iio/magnetometer/st_magn_i2c.c +++ b/drivers/iio/magnetometer/st_magn_i2c.c @@ -82,16 +82,28 @@ static int st_magn_i2c_probe(struct i2c_client *client, if (err < 0) return err; + err = st_sensors_power_enable(indio_dev); + if (err) + return err; + err = st_magn_common_probe(indio_dev); if (err < 0) - return err; + goto st_magn_power_off; return 0; + +st_magn_power_off: + st_sensors_power_disable(indio_dev); + + return err; } static int st_magn_i2c_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); + + st_sensors_power_disable(indio_dev); + st_magn_common_remove(indio_dev); return 0; diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c index 0e2323dfc687..03c0a737aba6 100644 --- a/drivers/iio/magnetometer/st_magn_spi.c +++ b/drivers/iio/magnetometer/st_magn_spi.c @@ -76,16 +76,28 @@ static int st_magn_spi_probe(struct spi_device *spi) if (err < 0) return err; + err = st_sensors_power_enable(indio_dev); + if (err) + return err; + err = st_magn_common_probe(indio_dev); if (err < 0) - return err; + goto st_magn_power_off; return 0; + +st_magn_power_off: + st_sensors_power_disable(indio_dev); + + return err; } static int st_magn_spi_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); + + st_sensors_power_disable(indio_dev); + st_magn_common_remove(indio_dev); return 0; diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index 789a2928504a..7912b5a68395 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -689,13 +689,9 @@ int st_press_common_probe(struct iio_dev *indio_dev) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &press_info; - err = st_sensors_power_enable(indio_dev); - if (err) - return err; - err = st_sensors_verify_id(indio_dev); if (err < 0) - goto st_press_power_off; + return err; /* * Skip timestamping channel while declaring available channels to @@ -718,11 +714,11 @@ int st_press_common_probe(struct iio_dev *indio_dev) err = st_sensors_init_sensor(indio_dev, pdata); if (err < 0) - goto st_press_power_off; + return err; err = st_press_allocate_ring(indio_dev); if (err < 0) - goto st_press_power_off; + return err; if (press_data->irq > 0) { err = st_sensors_allocate_trigger(indio_dev, @@ -745,9 +741,6 @@ st_press_device_register_error: st_sensors_deallocate_trigger(indio_dev); st_press_probe_trigger_error: st_press_deallocate_ring(indio_dev); -st_press_power_off: - st_sensors_power_disable(indio_dev); - return err; } EXPORT_SYMBOL(st_press_common_probe); @@ -756,8 +749,6 @@ void st_press_common_remove(struct iio_dev *indio_dev) { struct st_sensor_data *press_data = iio_priv(indio_dev); - st_sensors_power_disable(indio_dev); - iio_device_unregister(indio_dev); if (press_data->irq > 0) st_sensors_deallocate_trigger(indio_dev); diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c index 09c6903f99b8..f0a5af314ceb 100644 --- a/drivers/iio/pressure/st_pressure_i2c.c +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -98,16 +98,29 @@ static int st_press_i2c_probe(struct i2c_client *client, if (ret < 0) return ret; + ret = st_sensors_power_enable(indio_dev); + if (ret) + return ret; + ret = st_press_common_probe(indio_dev); if (ret < 0) - return ret; + goto st_press_power_off; return 0; + +st_press_power_off: + st_sensors_power_disable(indio_dev); + + return ret; } static int st_press_i2c_remove(struct i2c_client *client) { - st_press_common_remove(i2c_get_clientdata(client)); + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + st_sensors_power_disable(indio_dev); + + st_press_common_remove(indio_dev); return 0; } diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c index b5ee3ec2764f..b48cf7d01cd7 100644 --- a/drivers/iio/pressure/st_pressure_spi.c +++ b/drivers/iio/pressure/st_pressure_spi.c @@ -82,16 +82,29 @@ static int st_press_spi_probe(struct spi_device *spi) if (err < 0) return err; + err = st_sensors_power_enable(indio_dev); + if (err) + return err; + err = st_press_common_probe(indio_dev); if (err < 0) - return err; + goto st_press_power_off; return 0; + +st_press_power_off: + st_sensors_power_disable(indio_dev); + + return err; } static int st_press_spi_remove(struct spi_device *spi) { - st_press_common_remove(spi_get_drvdata(spi)); + struct iio_dev *indio_dev = spi_get_drvdata(spi); + + st_sensors_power_disable(indio_dev); + + st_press_common_remove(indio_dev); return 0; } -- cgit v1.2.3 From d61881ef7f08aef02d9bfc8c66f4c89c59cdf112 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 14 Apr 2021 22:54:52 +0300 Subject: iio: st_sensors: Make accel, gyro, magn and pressure probe shared Some IMUs may utilize existing library code for STMicro accelerometer, gyroscope, magnetometer and pressure. Let's share them via st_sensors.h. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210414195454.84183-5-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/st_accel.h | 4 ---- drivers/iio/gyro/st_gyro.h | 4 ---- drivers/iio/magnetometer/st_magn.h | 4 ---- drivers/iio/pressure/st_pressure.h | 4 ---- 4 files changed, 16 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h index 181ebe79c4eb..f5b0b8bbaff7 100644 --- a/drivers/iio/accel/st_accel.h +++ b/drivers/iio/accel/st_accel.h @@ -62,10 +62,6 @@ enum st_accel_type { #define LIS2DE12_ACCEL_DEV_NAME "lis2de12" #define LIS2HH12_ACCEL_DEV_NAME "lis2hh12" -const struct st_sensor_settings *st_accel_get_settings(const char *name); -int st_accel_common_probe(struct iio_dev *indio_dev); -void st_accel_common_remove(struct iio_dev *indio_dev); - #ifdef CONFIG_IIO_BUFFER int st_accel_allocate_ring(struct iio_dev *indio_dev); void st_accel_deallocate_ring(struct iio_dev *indio_dev); diff --git a/drivers/iio/gyro/st_gyro.h b/drivers/iio/gyro/st_gyro.h index b385fe664dcc..6537f5cb8320 100644 --- a/drivers/iio/gyro/st_gyro.h +++ b/drivers/iio/gyro/st_gyro.h @@ -24,10 +24,6 @@ #define LSM330_GYRO_DEV_NAME "lsm330_gyro" #define LSM9DS0_GYRO_DEV_NAME "lsm9ds0_gyro" -const struct st_sensor_settings *st_gyro_get_settings(const char *name); -int st_gyro_common_probe(struct iio_dev *indio_dev); -void st_gyro_common_remove(struct iio_dev *indio_dev); - #ifdef CONFIG_IIO_BUFFER int st_gyro_allocate_ring(struct iio_dev *indio_dev); void st_gyro_deallocate_ring(struct iio_dev *indio_dev); diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h index 7ba6a6ba5c58..fb6c906c4c0c 100644 --- a/drivers/iio/magnetometer/st_magn.h +++ b/drivers/iio/magnetometer/st_magn.h @@ -23,10 +23,6 @@ #define LSM9DS1_MAGN_DEV_NAME "lsm9ds1_magn" #define IIS2MDC_MAGN_DEV_NAME "iis2mdc" -const struct st_sensor_settings *st_magn_get_settings(const char *name); -int st_magn_common_probe(struct iio_dev *indio_dev); -void st_magn_common_remove(struct iio_dev *indio_dev); - #ifdef CONFIG_IIO_BUFFER int st_magn_allocate_ring(struct iio_dev *indio_dev); void st_magn_deallocate_ring(struct iio_dev *indio_dev); diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h index 5c746ff6087e..9417b3bd7513 100644 --- a/drivers/iio/pressure/st_pressure.h +++ b/drivers/iio/pressure/st_pressure.h @@ -41,10 +41,6 @@ static __maybe_unused const struct st_sensors_platform_data default_press_pdata .drdy_int_pin = 1, }; -const struct st_sensor_settings *st_press_get_settings(const char *name); -int st_press_common_probe(struct iio_dev *indio_dev); -void st_press_common_remove(struct iio_dev *indio_dev); - #ifdef CONFIG_IIO_BUFFER int st_press_allocate_ring(struct iio_dev *indio_dev); void st_press_deallocate_ring(struct iio_dev *indio_dev); -- cgit v1.2.3 From 6731ca3999ffa4c878a661b980759300dfb0237e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 14 Apr 2021 22:54:53 +0300 Subject: iio: st_sensors: Add lsm9ds0 IMU support We can utilize separate drivers for accelerometer and magnetometer, so here is the glue driver to enable LSM9DS0 IMU support. The idea was suggested by Crestez Dan Leonard in [1]. The proposed change was sent as RFC due to race condition concerns, which are indeed possible. In order to amend the initial change, I went further by providing a specific multi-instantiate probe driver that reuses existing accelerometer and magnetometer. [1]: https://lore.kernel.org/patchwork/patch/670353/ Suggested-by: Crestez Dan Leonard Cc: mr.lahorde@laposte.net Cc: Matija Podravec Cc: Sergey Borishchenko Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210414195454.84183-6-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/st_accel_core.c | 89 ++++++++++++++- drivers/iio/imu/Kconfig | 1 + drivers/iio/imu/Makefile | 1 + drivers/iio/imu/st_lsm9ds0/Kconfig | 28 +++++ drivers/iio/imu/st_lsm9ds0/Makefile | 5 + drivers/iio/imu/st_lsm9ds0/st_lsm9ds0.h | 23 ++++ drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c | 163 +++++++++++++++++++++++++++ drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c | 84 ++++++++++++++ drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c | 83 ++++++++++++++ drivers/iio/magnetometer/st_magn_core.c | 98 ++++++++++++++++ 10 files changed, 574 insertions(+), 1 deletion(-) create mode 100644 drivers/iio/imu/st_lsm9ds0/Kconfig create mode 100644 drivers/iio/imu/st_lsm9ds0/Makefile create mode 100644 drivers/iio/imu/st_lsm9ds0/st_lsm9ds0.h create mode 100644 drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c create mode 100644 drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c create mode 100644 drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c (limited to 'drivers/iio') diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 5c258c1ca62d..dc32ebefe3fc 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -980,7 +980,94 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .multi_read_bit = true, .bootime = 2, }, - + { + .wai = 0x49, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, + .sensors_supported = { + [0] = LSM9DS0_IMU_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_accel_16bit_channels, + .odr = { + .addr = 0x20, + .mask = GENMASK(7, 4), + .odr_avl = { + { 3, 0x01, }, + { 6, 0x02, }, + { 12, 0x03, }, + { 25, 0x04, }, + { 50, 0x05, }, + { 100, 0x06, }, + { 200, 0x07, }, + { 400, 0x08, }, + { 800, 0x09, }, + { 1600, 0x0a, }, + }, + }, + .pw = { + .addr = 0x20, + .mask = GENMASK(7, 4), + .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, + }, + .enable_axis = { + .addr = ST_SENSORS_DEFAULT_AXIS_ADDR, + .mask = ST_SENSORS_DEFAULT_AXIS_MASK, + }, + .fs = { + .addr = 0x21, + .mask = GENMASK(5, 3), + .fs_avl = { + [0] = { + .num = ST_ACCEL_FS_AVL_2G, + .value = 0x00, + .gain = IIO_G_TO_M_S_2(61), + }, + [1] = { + .num = ST_ACCEL_FS_AVL_4G, + .value = 0x01, + .gain = IIO_G_TO_M_S_2(122), + }, + [2] = { + .num = ST_ACCEL_FS_AVL_6G, + .value = 0x02, + .gain = IIO_G_TO_M_S_2(183), + }, + [3] = { + .num = ST_ACCEL_FS_AVL_8G, + .value = 0x03, + .gain = IIO_G_TO_M_S_2(244), + }, + [4] = { + .num = ST_ACCEL_FS_AVL_16G, + .value = 0x04, + .gain = IIO_G_TO_M_S_2(732), + }, + }, + }, + .bdu = { + .addr = 0x20, + .mask = BIT(3), + }, + .drdy_irq = { + .int1 = { + .addr = 0x22, + .mask = BIT(2), + }, + .int2 = { + .addr = 0x23, + .mask = BIT(3), + }, + .stat_drdy = { + .addr = ST_SENSORS_DEFAULT_STAT_ADDR, + .mask = GENMASK(2, 0), + }, + }, + .sim = { + .addr = 0x21, + .value = BIT(0), + }, + .multi_read_bit = true, + .bootime = 2, + }, }; /* Default accel DRDY is available on INT1 pin */ diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index f02883b08480..001ca2c3ff95 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -94,6 +94,7 @@ config KMX61 source "drivers/iio/imu/inv_icm42600/Kconfig" source "drivers/iio/imu/inv_mpu6050/Kconfig" source "drivers/iio/imu/st_lsm6dsx/Kconfig" +source "drivers/iio/imu/st_lsm9ds0/Kconfig" endmenu diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index 13e9ff442b11..c82748096c77 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -26,3 +26,4 @@ obj-y += inv_mpu6050/ obj-$(CONFIG_KMX61) += kmx61.o obj-y += st_lsm6dsx/ +obj-y += st_lsm9ds0/ diff --git a/drivers/iio/imu/st_lsm9ds0/Kconfig b/drivers/iio/imu/st_lsm9ds0/Kconfig new file mode 100644 index 000000000000..53b7017014f8 --- /dev/null +++ b/drivers/iio/imu/st_lsm9ds0/Kconfig @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config IIO_ST_LSM9DS0 + tristate "STMicroelectronics LSM9DS0 IMU driver" + depends on (I2C || SPI_MASTER) && SYSFS + depends on !SENSORS_LIS3_I2C + depends on !SENSORS_LIS3_SPI + select IIO_ST_LSM9DS0_I2C if I2C + select IIO_ST_LSM9DS0_SPI if SPI_MASTER + select IIO_ST_ACCEL_3AXIS + select IIO_ST_MAGN_3AXIS + + help + Say yes here to build support for STMicroelectronics LSM9DS0 IMU + sensor. Supported devices: accelerometer/magnetometer of lsm9ds0. + + To compile this driver as a module, choose M here: the module + will be called st_lsm9ds0. + +config IIO_ST_LSM9DS0_I2C + tristate + depends on IIO_ST_LSM9DS0 + select REGMAP_I2C + +config IIO_ST_LSM9DS0_SPI + tristate + depends on IIO_ST_LSM9DS0 + select REGMAP_SPI diff --git a/drivers/iio/imu/st_lsm9ds0/Makefile b/drivers/iio/imu/st_lsm9ds0/Makefile new file mode 100644 index 000000000000..488af523f648 --- /dev/null +++ b/drivers/iio/imu/st_lsm9ds0/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_IIO_ST_LSM9DS0) += st_lsm9ds0.o +st_lsm9ds0-y := st_lsm9ds0_core.o +obj-$(CONFIG_IIO_ST_LSM9DS0_I2C) += st_lsm9ds0_i2c.o +obj-$(CONFIG_IIO_ST_LSM9DS0_SPI) += st_lsm9ds0_spi.o diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0.h b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0.h new file mode 100644 index 000000000000..146393afd9a7 --- /dev/null +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +// STMicroelectronics LSM9DS0 IMU driver + +#ifndef ST_LSM9DS0_H +#define ST_LSM9DS0_H + +struct iio_dev; +struct regulator; + +struct st_lsm9ds0 { + struct device *dev; + const char *name; + int irq; + struct iio_dev *accel; + struct iio_dev *magn; + struct regulator *vdd; + struct regulator *vdd_io; +}; + +int st_lsm9ds0_probe(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap); +int st_lsm9ds0_remove(struct st_lsm9ds0 *lsm9ds0); + +#endif /* ST_LSM9DS0_H */ diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c new file mode 100644 index 000000000000..8204f7303fd7 --- /dev/null +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * STMicroelectronics LSM9DS0 IMU driver + * + * Copyright (C) 2021, Intel Corporation + * + * Author: Andy Shevchenko + */ + +#include +#include +#include +#include + +#include +#include + +#include "st_lsm9ds0.h" + +static int st_lsm9ds0_power_enable(struct device *dev, struct st_lsm9ds0 *lsm9ds0) +{ + int ret; + + /* Regulators not mandatory, but if requested we should enable them. */ + lsm9ds0->vdd = devm_regulator_get(dev, "vdd"); + if (IS_ERR(lsm9ds0->vdd)) { + dev_err(dev, "unable to get Vdd supply\n"); + return PTR_ERR(lsm9ds0->vdd); + } + ret = regulator_enable(lsm9ds0->vdd); + if (ret) { + dev_warn(dev, "Failed to enable specified Vdd supply\n"); + return ret; + } + + lsm9ds0->vdd_io = devm_regulator_get(dev, "vddio"); + if (IS_ERR(lsm9ds0->vdd_io)) { + dev_err(dev, "unable to get Vdd_IO supply\n"); + regulator_disable(lsm9ds0->vdd); + return PTR_ERR(lsm9ds0->vdd_io); + } + ret = regulator_enable(lsm9ds0->vdd_io); + if (ret) { + dev_warn(dev, "Failed to enable specified Vdd_IO supply\n"); + regulator_disable(lsm9ds0->vdd); + return ret; + } + + return 0; +} + +static void st_lsm9ds0_power_disable(void *data) +{ + struct st_lsm9ds0 *lsm9ds0 = data; + + regulator_disable(lsm9ds0->vdd_io); + regulator_disable(lsm9ds0->vdd); +} + +static int devm_st_lsm9ds0_power_enable(struct st_lsm9ds0 *lsm9ds0) +{ + struct device *dev = lsm9ds0->dev; + int ret; + + ret = st_lsm9ds0_power_enable(dev, lsm9ds0); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, st_lsm9ds0_power_disable, lsm9ds0); +} + +static int st_lsm9ds0_probe_accel(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap) +{ + const struct st_sensor_settings *settings; + struct device *dev = lsm9ds0->dev; + struct st_sensor_data *data; + + settings = st_accel_get_settings(lsm9ds0->name); + if (!settings) { + dev_err(dev, "device name %s not recognized.\n", lsm9ds0->name); + return -ENODEV; + } + + lsm9ds0->accel = devm_iio_device_alloc(dev, sizeof(*data)); + if (!lsm9ds0->accel) + return -ENOMEM; + + lsm9ds0->accel->name = lsm9ds0->name; + + data = iio_priv(lsm9ds0->accel); + data->sensor_settings = (struct st_sensor_settings *)settings; + data->dev = dev; + data->irq = lsm9ds0->irq; + data->regmap = regmap; + data->vdd = lsm9ds0->vdd; + data->vdd_io = lsm9ds0->vdd_io; + + return st_accel_common_probe(lsm9ds0->accel); +} + +static int st_lsm9ds0_probe_magn(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap) +{ + const struct st_sensor_settings *settings; + struct device *dev = lsm9ds0->dev; + struct st_sensor_data *data; + + settings = st_magn_get_settings(lsm9ds0->name); + if (!settings) { + dev_err(dev, "device name %s not recognized.\n", lsm9ds0->name); + return -ENODEV; + } + + lsm9ds0->magn = devm_iio_device_alloc(dev, sizeof(*data)); + if (!lsm9ds0->magn) + return -ENOMEM; + + lsm9ds0->magn->name = lsm9ds0->name; + + data = iio_priv(lsm9ds0->magn); + data->sensor_settings = (struct st_sensor_settings *)settings; + data->dev = dev; + data->irq = lsm9ds0->irq; + data->regmap = regmap; + data->vdd = lsm9ds0->vdd; + data->vdd_io = lsm9ds0->vdd_io; + + return st_magn_common_probe(lsm9ds0->magn); +} + +int st_lsm9ds0_probe(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap) +{ + int ret; + + ret = devm_st_lsm9ds0_power_enable(lsm9ds0); + if (ret) + return ret; + + /* Setup accelerometer device */ + ret = st_lsm9ds0_probe_accel(lsm9ds0, regmap); + if (ret) + return ret; + + /* Setup magnetometer device */ + ret = st_lsm9ds0_probe_magn(lsm9ds0, regmap); + if (ret) + st_accel_common_remove(lsm9ds0->accel); + + return ret; +} +EXPORT_SYMBOL_GPL(st_lsm9ds0_probe); + +int st_lsm9ds0_remove(struct st_lsm9ds0 *lsm9ds0) +{ + st_magn_common_remove(lsm9ds0->magn); + st_accel_common_remove(lsm9ds0->accel); + + return 0; +} +EXPORT_SYMBOL_GPL(st_lsm9ds0_remove); + +MODULE_AUTHOR("Andy Shevchenko "); +MODULE_DESCRIPTION("STMicroelectronics LSM9DS0 IMU core driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c new file mode 100644 index 000000000000..50a36ab53bc3 --- /dev/null +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * STMicroelectronics LSM9DS0 IMU driver + * + * Copyright (C) 2021, Intel Corporation + * + * Author: Andy Shevchenko + */ + +#include +#include +#include +#include + +#include + +#include "st_lsm9ds0.h" + +static const struct of_device_id st_lsm9ds0_of_match[] = { + { + .compatible = "st,lsm9ds0-imu", + .data = LSM9DS0_IMU_DEV_NAME, + }, + {} +}; +MODULE_DEVICE_TABLE(of, st_lsm9ds0_of_match); + +static const struct i2c_device_id st_lsm9ds0_id_table[] = { + { LSM9DS0_IMU_DEV_NAME }, + {} +}; +MODULE_DEVICE_TABLE(i2c, st_lsm9ds0_id_table); + +static const struct regmap_config st_lsm9ds0_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .read_flag_mask = 0x80, +}; + +static int st_lsm9ds0_i2c_probe(struct i2c_client *client) +{ + const struct regmap_config *config = &st_lsm9ds0_regmap_config; + struct device *dev = &client->dev; + struct st_lsm9ds0 *lsm9ds0; + struct regmap *regmap; + + st_sensors_dev_name_probe(dev, client->name, sizeof(client->name)); + + lsm9ds0 = devm_kzalloc(dev, sizeof(*lsm9ds0), GFP_KERNEL); + if (!lsm9ds0) + return -ENOMEM; + + lsm9ds0->dev = dev; + lsm9ds0->name = client->name; + lsm9ds0->irq = client->irq; + + regmap = devm_regmap_init_i2c(client, config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + i2c_set_clientdata(client, lsm9ds0); + + return st_lsm9ds0_probe(lsm9ds0, regmap); +} + +static int st_lsm9ds0_i2c_remove(struct i2c_client *client) +{ + return st_lsm9ds0_remove(i2c_get_clientdata(client)); +} + +static struct i2c_driver st_lsm9ds0_driver = { + .driver = { + .name = "st-lsm9ds0-i2c", + .of_match_table = st_lsm9ds0_of_match, + }, + .probe_new = st_lsm9ds0_i2c_probe, + .remove = st_lsm9ds0_i2c_remove, + .id_table = st_lsm9ds0_id_table, +}; +module_i2c_driver(st_lsm9ds0_driver); + +MODULE_AUTHOR("Andy Shevchenko "); +MODULE_DESCRIPTION("STMicroelectronics LSM9DS0 IMU I2C driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c new file mode 100644 index 000000000000..272c88990dd0 --- /dev/null +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * STMicroelectronics LSM9DS0 IMU driver + * + * Copyright (C) 2021, Intel Corporation + * + * Author: Andy Shevchenko + */ + +#include +#include +#include +#include + +#include + +#include "st_lsm9ds0.h" + +static const struct of_device_id st_lsm9ds0_of_match[] = { + { + .compatible = "st,lsm9ds0-imu", + .data = LSM9DS0_IMU_DEV_NAME, + }, + {} +}; +MODULE_DEVICE_TABLE(of, st_lsm9ds0_of_match); + +static const struct spi_device_id st_lsm9ds0_id_table[] = { + { LSM9DS0_IMU_DEV_NAME }, + {} +}; +MODULE_DEVICE_TABLE(spi, st_lsm9ds0_id_table); + +static const struct regmap_config st_lsm9ds0_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .read_flag_mask = 0xc0, +}; + +static int st_lsm9ds0_spi_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct st_lsm9ds0 *lsm9ds0; + struct regmap *regmap; + + st_sensors_dev_name_probe(dev, spi->modalias, sizeof(spi->modalias)); + + lsm9ds0 = devm_kzalloc(dev, sizeof(*lsm9ds0), GFP_KERNEL); + if (!lsm9ds0) + return -ENOMEM; + + lsm9ds0->dev = dev; + lsm9ds0->name = spi->modalias; + lsm9ds0->irq = spi->irq; + + regmap = devm_regmap_init_spi(spi, &st_lsm9ds0_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + spi_set_drvdata(spi, lsm9ds0); + + return st_lsm9ds0_probe(lsm9ds0, regmap); +} + +static int st_lsm9ds0_spi_remove(struct spi_device *spi) +{ + return st_lsm9ds0_remove(spi_get_drvdata(spi)); +} + +static struct spi_driver st_lsm9ds0_driver = { + .driver = { + .name = "st-lsm9ds0-spi", + .of_match_table = st_lsm9ds0_of_match, + }, + .probe = st_lsm9ds0_spi_probe, + .remove = st_lsm9ds0_spi_remove, + .id_table = st_lsm9ds0_id_table, +}; +module_spi_driver(st_lsm9ds0_driver); + +MODULE_AUTHOR("Andy Shevchenko "); +MODULE_DESCRIPTION("STMicroelectronics LSM9DS0 IMU SPI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 58da48434a25..1596faa74da9 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -33,6 +33,7 @@ /* FULLSCALE */ #define ST_MAGN_FS_AVL_1300MG 1300 #define ST_MAGN_FS_AVL_1900MG 1900 +#define ST_MAGN_FS_AVL_2000MG 2000 #define ST_MAGN_FS_AVL_2500MG 2500 #define ST_MAGN_FS_AVL_4000MG 4000 #define ST_MAGN_FS_AVL_4700MG 4700 @@ -53,6 +54,11 @@ #define ST_MAGN_3_OUT_Y_L_ADDR 0x6a #define ST_MAGN_3_OUT_Z_L_ADDR 0x6c +/* Special L addresses for sensor 4 */ +#define ST_MAGN_4_OUT_X_L_ADDR 0x08 +#define ST_MAGN_4_OUT_Y_L_ADDR 0x0a +#define ST_MAGN_4_OUT_Z_L_ADDR 0x0c + static const struct iio_chan_spec st_magn_16bit_channels[] = { ST_SENSORS_LSM_CHANNELS(IIO_MAGN, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), @@ -101,6 +107,22 @@ static const struct iio_chan_spec st_magn_3_16bit_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(3) }; +static const struct iio_chan_spec st_magn_4_16bit_channels[] = { + ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16, + ST_MAGN_4_OUT_X_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16, + ST_MAGN_4_OUT_Y_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16, + ST_MAGN_4_OUT_Z_L_ADDR), + IIO_CHAN_SOFT_TIMESTAMP(3) +}; + static const struct st_sensor_settings st_magn_sensors_settings[] = { { .wai = 0, /* This sensor has no valid WhoAmI report 0 */ @@ -381,6 +403,82 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = { .multi_read_bit = false, .bootime = 2, }, + { + .wai = 0x49, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, + .sensors_supported = { + [0] = LSM9DS0_IMU_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_magn_4_16bit_channels, + .odr = { + .addr = 0x24, + .mask = GENMASK(4, 2), + .odr_avl = { + { 3, 0x00, }, + { 6, 0x01, }, + { 12, 0x02, }, + { 25, 0x03, }, + { 50, 0x04, }, + { 100, 0x05, }, + }, + }, + .pw = { + .addr = 0x26, + .mask = GENMASK(1, 0), + .value_on = 0x00, + .value_off = 0x03, + }, + .fs = { + .addr = 0x25, + .mask = GENMASK(6, 5), + .fs_avl = { + [0] = { + .num = ST_MAGN_FS_AVL_2000MG, + .value = 0x00, + .gain = 73, + }, + [1] = { + .num = ST_MAGN_FS_AVL_4000MG, + .value = 0x01, + .gain = 146, + }, + [2] = { + .num = ST_MAGN_FS_AVL_8000MG, + .value = 0x02, + .gain = 292, + }, + [3] = { + .num = ST_MAGN_FS_AVL_12000MG, + .value = 0x03, + .gain = 438, + }, + }, + }, + .bdu = { + .addr = 0x20, + .mask = BIT(3), + }, + .drdy_irq = { + .int1 = { + .addr = 0x22, + .mask = BIT(1), + }, + .int2 = { + .addr = 0x23, + .mask = BIT(2), + }, + .stat_drdy = { + .addr = 0x07, + .mask = GENMASK(2, 0), + }, + }, + .sim = { + .addr = 0x21, + .value = BIT(0), + }, + .multi_read_bit = true, + .bootime = 2, + }, }; /* Default magn DRDY is available on INT2 pin */ -- cgit v1.2.3 From 3a57abfaa5a67e94624625a6e020874dde883ece Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 4 May 2021 08:37:46 -0700 Subject: iio: am2315: Remove acpi_device_id table With CONFIG_ACPI=n and -Werror, 0-day reports: drivers/iio/humidity/am2315.c:259:36: error: 'am2315_acpi_id' defined but not used According to Andy Shevchenko, the ACPI ID used in this driver is fake and does not really exist. Remove it and with it ACPI support from the driver. Note that, if an explicit of_device_id table is added to the driver it could support the PRP0001 based ACPI approach. Reported-by: kernel test robot Signed-off-by: Guenter Roeck Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/am2315.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/humidity/am2315.c b/drivers/iio/humidity/am2315.c index 23bc9c784ef4..8d7ec2f5acf8 100644 --- a/drivers/iio/humidity/am2315.c +++ b/drivers/iio/humidity/am2315.c @@ -7,7 +7,6 @@ * 7-bit I2C address: 0x5C. */ -#include #include #include #include @@ -256,17 +255,9 @@ static const struct i2c_device_id am2315_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, am2315_i2c_id); -static const struct acpi_device_id am2315_acpi_id[] = { - {"AOS2315", 0}, - {} -}; - -MODULE_DEVICE_TABLE(acpi, am2315_acpi_id); - static struct i2c_driver am2315_driver = { .driver = { .name = "am2315", - .acpi_match_table = ACPI_PTR(am2315_acpi_id), }, .probe = am2315_probe, .id_table = am2315_i2c_id, -- cgit v1.2.3 From aff35afb0190bb02a0fe4bfa0a59a08f9bf538b4 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 5 May 2021 20:56:59 -0700 Subject: iio:accel:stk8312: Remove acpi_device_id table With CONFIG_ACPI=n, W=1 and -Werror, 0-day reports: drivers/iio/accel/stk8312.c:644:36: error: 'stk8312_acpi_id' defined but not used Apparently STK8312 is not a valid ACPI ID. Remove the ID table as this is the only entry. If ACPI support is desired an explicit of_device_id table should be added (rather than relying on the fallback to the existing ID table). Reported-by: kernel test robot Signed-off-by: Guenter Roeck Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/accel/stk8312.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index aeab108c457d..34dc9bd78fb8 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -7,7 +7,6 @@ * IIO driver for STK8312; 7-bit I2C address: 0x3D. */ -#include #include #include #include @@ -642,18 +641,10 @@ static const struct i2c_device_id stk8312_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, stk8312_i2c_id); -static const struct acpi_device_id stk8312_acpi_id[] = { - { "STK8312", 0 }, - {} -}; - -MODULE_DEVICE_TABLE(acpi, stk8312_acpi_id); - static struct i2c_driver stk8312_driver = { .driver = { .name = STK8312_DRIVER_NAME, .pm = STK8312_PM_OPS, - .acpi_match_table = ACPI_PTR(stk8312_acpi_id), }, .probe = stk8312_probe, .remove = stk8312_remove, -- cgit v1.2.3 From f0e4057e97c1af9a55052f5fb024d69cf961ccf2 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 6 May 2021 06:31:45 -0700 Subject: iio: bme680_spi: Remove acpi_device_id table BME0680 is not an official ACPI ID, so let's remove it before someone starts using it. Note that ACPI can still be used with this driver via the PRP0001 method which will use the of_device_id table to match. Signed-off-by: Guenter Roeck Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/bme680_spi.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/chemical/bme680_spi.c b/drivers/iio/chemical/bme680_spi.c index 6f56ad48cc40..cc579a7ac5ce 100644 --- a/drivers/iio/chemical/bme680_spi.c +++ b/drivers/iio/chemical/bme680_spi.c @@ -4,7 +4,6 @@ * * Copyright (C) 2018 Himanshu Jha */ -#include #include #include #include @@ -145,12 +144,6 @@ static const struct spi_device_id bme680_spi_id[] = { }; MODULE_DEVICE_TABLE(spi, bme680_spi_id); -static const struct acpi_device_id bme680_acpi_match[] = { - {"BME0680", 0}, - {}, -}; -MODULE_DEVICE_TABLE(acpi, bme680_acpi_match); - static const struct of_device_id bme680_of_spi_match[] = { { .compatible = "bosch,bme680", }, {}, @@ -160,7 +153,6 @@ MODULE_DEVICE_TABLE(of, bme680_of_spi_match); static struct spi_driver bme680_spi_driver = { .driver = { .name = "bme680_spi", - .acpi_match_table = ACPI_PTR(bme680_acpi_match), .of_match_table = bme680_of_spi_match, }, .probe = bme680_spi_probe, -- cgit v1.2.3 From b73d21dccf6826b2768c15da931f982d5812b044 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 5 May 2021 20:43:32 -0700 Subject: iio: bme680_i2c: Remove acpi_device_id table With CONFIG_ACPI=n and -Werror, 0-day reports: drivers/iio/chemical/bme680_i2c.c:46:36: error: 'bme680_acpi_match' defined but not used Apparently BME0680 is not a valid ACPI ID. Remove the ID. Note the driver will still work with ACPI bindings that use the PRP0001 mechanism as that uses the of_device_id table instead. Reported-by: kernel test robot Signed-off-by: Guenter Roeck Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/bme680_i2c.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/chemical/bme680_i2c.c b/drivers/iio/chemical/bme680_i2c.c index 29c0dfa4702b..74cf89c82c0a 100644 --- a/drivers/iio/chemical/bme680_i2c.c +++ b/drivers/iio/chemical/bme680_i2c.c @@ -11,7 +11,6 @@ * Note: SDO pin cannot be left floating otherwise I2C address * will be undefined. */ -#include #include #include #include @@ -42,12 +41,6 @@ static const struct i2c_device_id bme680_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, bme680_i2c_id); -static const struct acpi_device_id bme680_acpi_match[] = { - {"BME0680", 0}, - {}, -}; -MODULE_DEVICE_TABLE(acpi, bme680_acpi_match); - static const struct of_device_id bme680_of_i2c_match[] = { { .compatible = "bosch,bme680", }, {}, @@ -57,7 +50,6 @@ MODULE_DEVICE_TABLE(of, bme680_of_i2c_match); static struct i2c_driver bme680_i2c_driver = { .driver = { .name = "bme680_i2c", - .acpi_match_table = ACPI_PTR(bme680_acpi_match), .of_match_table = bme680_of_i2c_match, }, .probe = bme680_i2c_probe, -- cgit v1.2.3 From f7d5c18a8c371c306d73757547c2e0d6cfc764b3 Mon Sep 17 00:00:00 2001 From: Sean Nyekjaer Date: Fri, 7 May 2021 12:31:49 +0200 Subject: iio: imu: st_lsm6dsx: correct ODR in header Fix wrongly stated 13 Hz ODR for accelerometers, the correct ODR is 12.5 Hz Signed-off-by: Sean Nyekjaer Acked-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 7cedaab096a7..e8d242ee6743 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -15,19 +15,19 @@ * * Supported sensors: * - LSM6DS3: - * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416 + * - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416 * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 * - FIFO size: 8KB * * - LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC/LSM6DS3TR-C: - * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416 + * - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416 * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 * - FIFO size: 4KB * * - LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR/ISM330DHCX/LSM6DST/LSM6DSOP: - * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416, + * - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416, * 833 * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 -- cgit v1.2.3 From a3e0b51884ee3a5d890bd5124d9a270f61589e57 Mon Sep 17 00:00:00 2001 From: Sean Nyekjaer Date: Thu, 6 May 2021 09:09:35 +0200 Subject: iio: accel: add support for FXLS8962AF/FXLS8964AF accelerometers Add basic support for NXP FXLS8962AF/FXLS8964AF Automotive accelerometers. It will allow setting up scale/gain and reading x,y,z axis. Datasheet: https://www.nxp.com/docs/en/data-sheet/FXLS8962AF.pdf Datasheet: https://www.nxp.com/docs/en/data-sheet/FXLS8964AF.pdf Signed-off-by: Sean Nyekjaer Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 27 ++ drivers/iio/accel/Makefile | 3 + drivers/iio/accel/fxls8962af-core.c | 560 ++++++++++++++++++++++++++++++++++++ drivers/iio/accel/fxls8962af-i2c.c | 57 ++++ drivers/iio/accel/fxls8962af-spi.c | 57 ++++ drivers/iio/accel/fxls8962af.h | 22 ++ 6 files changed, 726 insertions(+) create mode 100644 drivers/iio/accel/fxls8962af-core.c create mode 100644 drivers/iio/accel/fxls8962af-i2c.c create mode 100644 drivers/iio/accel/fxls8962af-spi.c create mode 100644 drivers/iio/accel/fxls8962af.h (limited to 'drivers/iio') diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index ba4ffc2212cb..17f6bdcf1db3 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -226,6 +226,33 @@ config DMARD10 Choosing M will build the driver as a module. If so, the module will be called dmard10. +config FXLS8962AF + tristate + +config FXLS8962AF_I2C + tristate "NXP FXLS8962AF/FXLS8964AF Accelerometer I2C Driver" + depends on I2C + select FXLS8962AF + select REGMAP_I2C + help + Say yes here to build support for the NXP 3-axis automotive + accelerometer FXLS8962AF/FXLS8964AF with I2C support. + + To compile this driver as a module, choose M here: the module + will be called fxls8962af_i2c. + +config FXLS8962AF_SPI + tristate "NXP FXLS8962AF/FXLS8964AF Accelerometer SPI Driver" + depends on SPI + select FXLS8962AF + select REGMAP_SPI + help + Say yes here to build support for the NXP 3-axis automotive + accelerometer FXLS8962AF/FXLS8964AF with SPI support. + + To compile this driver as a module, choose M here: the module + will be called fxls8962af_spi. + config HID_SENSOR_ACCEL_3D depends on HID_SENSOR_HUB select IIO_BUFFER diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index 4b56527a2b97..89280e823bcd 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -27,6 +27,9 @@ obj-$(CONFIG_DA311) += da311.o obj-$(CONFIG_DMARD06) += dmard06.o obj-$(CONFIG_DMARD09) += dmard09.o obj-$(CONFIG_DMARD10) += dmard10.o +obj-$(CONFIG_FXLS8962AF) += fxls8962af-core.o +obj-$(CONFIG_FXLS8962AF_I2C) += fxls8962af-i2c.o +obj-$(CONFIG_FXLS8962AF_SPI) += fxls8962af-spi.o obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o obj-$(CONFIG_KXSD9) += kxsd9.o diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c new file mode 100644 index 000000000000..61b1825c85d1 --- /dev/null +++ b/drivers/iio/accel/fxls8962af-core.c @@ -0,0 +1,560 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NXP FXLS8962AF/FXLS8964AF Accelerometer Core Driver + * + * Copyright 2021 Connected Cars A/S + * + * Datasheet: + * https://www.nxp.com/docs/en/data-sheet/FXLS8962AF.pdf + * https://www.nxp.com/docs/en/data-sheet/FXLS8964AF.pdf + * + * Errata: + * https://www.nxp.com/docs/en/errata/ES_FXLS8962AF.pdf + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "fxls8962af.h" + +#define FXLS8962AF_INT_STATUS 0x00 +#define FXLS8962AF_INT_STATUS_SRC_BOOT BIT(0) +#define FXLS8962AF_INT_STATUS_SRC_DRDY BIT(7) +#define FXLS8962AF_TEMP_OUT 0x01 +#define FXLS8962AF_VECM_LSB 0x02 +#define FXLS8962AF_OUT_X_LSB 0x04 +#define FXLS8962AF_OUT_Y_LSB 0x06 +#define FXLS8962AF_OUT_Z_LSB 0x08 +#define FXLS8962AF_BUF_STATUS 0x0b +#define FXLS8962AF_BUF_X_LSB 0x0c +#define FXLS8962AF_BUF_Y_LSB 0x0e +#define FXLS8962AF_BUF_Z_LSB 0x10 + +#define FXLS8962AF_PROD_REV 0x12 +#define FXLS8962AF_WHO_AM_I 0x13 + +#define FXLS8962AF_SYS_MODE 0x14 +#define FXLS8962AF_SENS_CONFIG1 0x15 +#define FXLS8962AF_SENS_CONFIG1_ACTIVE BIT(0) +#define FXLS8962AF_SENS_CONFIG1_RST BIT(7) +#define FXLS8962AF_SC1_FSR_MASK GENMASK(2, 1) +#define FXLS8962AF_SC1_FSR_PREP(x) FIELD_PREP(FXLS8962AF_SC1_FSR_MASK, (x)) +#define FXLS8962AF_SC1_FSR_GET(x) FIELD_GET(FXLS8962AF_SC1_FSR_MASK, (x)) + +#define FXLS8962AF_SENS_CONFIG2 0x16 +#define FXLS8962AF_SENS_CONFIG3 0x17 +#define FXLS8962AF_SENS_CONFIG4 0x18 +#define FXLS8962AF_SENS_CONFIG5 0x19 + +#define FXLS8962AF_WAKE_IDLE_LSB 0x1b +#define FXLS8962AF_SLEEP_IDLE_LSB 0x1c +#define FXLS8962AF_ASLP_COUNT_LSB 0x1e + +#define FXLS8962AF_INT_EN 0x20 +#define FXLS8962AF_INT_PIN_SEL 0x21 + +#define FXLS8962AF_OFF_X 0x22 +#define FXLS8962AF_OFF_Y 0x23 +#define FXLS8962AF_OFF_Z 0x24 + +#define FXLS8962AF_BUF_CONFIG1 0x26 +#define FXLS8962AF_BUF_CONFIG2 0x27 + +#define FXLS8962AF_ORIENT_STATUS 0x28 +#define FXLS8962AF_ORIENT_CONFIG 0x29 +#define FXLS8962AF_ORIENT_DBCOUNT 0x2a +#define FXLS8962AF_ORIENT_BF_ZCOMP 0x2b +#define FXLS8962AF_ORIENT_THS_REG 0x2c + +#define FXLS8962AF_SDCD_INT_SRC1 0x2d +#define FXLS8962AF_SDCD_INT_SRC2 0x2e +#define FXLS8962AF_SDCD_CONFIG1 0x2f +#define FXLS8962AF_SDCD_CONFIG2 0x30 +#define FXLS8962AF_SDCD_OT_DBCNT 0x31 +#define FXLS8962AF_SDCD_WT_DBCNT 0x32 +#define FXLS8962AF_SDCD_LTHS_LSB 0x33 +#define FXLS8962AF_SDCD_UTHS_LSB 0x35 + +#define FXLS8962AF_SELF_TEST_CONFIG1 0x37 +#define FXLS8962AF_SELF_TEST_CONFIG2 0x38 + +#define FXLS8962AF_MAX_REG 0x38 + +#define FXLS8962AF_DEVICE_ID 0x62 +#define FXLS8964AF_DEVICE_ID 0x84 + +/* Raw temp channel offset */ +#define FXLS8962AF_TEMP_CENTER_VAL 25 + +#define FXLS8962AF_AUTO_SUSPEND_DELAY_MS 2000 + +#define FXLS8962AF_SCALE_TABLE_LEN 4 + +static const int fxls8962af_scale_table[FXLS8962AF_SCALE_TABLE_LEN][2] = { + {0, IIO_G_TO_M_S_2(980000)}, + {0, IIO_G_TO_M_S_2(1950000)}, + {0, IIO_G_TO_M_S_2(3910000)}, + {0, IIO_G_TO_M_S_2(7810000)}, +}; + +struct fxls8962af_chip_info { + const char *name; + const struct iio_chan_spec *channels; + int num_channels; + u8 chip_id; +}; + +struct fxls8962af_data { + struct regmap *regmap; + const struct fxls8962af_chip_info *chip_info; + struct regulator *vdd_reg; + struct iio_mount_matrix orientation; +}; + +const struct regmap_config fxls8962af_regmap_conf = { + .reg_bits = 8, + .val_bits = 8, + .max_register = FXLS8962AF_MAX_REG, +}; +EXPORT_SYMBOL_GPL(fxls8962af_regmap_conf); + +enum { + fxls8962af_idx_x, + fxls8962af_idx_y, + fxls8962af_idx_z, + fxls8962af_idx_ts, +}; + +static int fxls8962af_power_on(struct fxls8962af_data *data) +{ + struct device *dev = regmap_get_device(data->regmap); + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + dev_err(dev, "failed to power on\n"); + + return ret; +} + +static int fxls8962af_power_off(struct fxls8962af_data *data) +{ + struct device *dev = regmap_get_device(data->regmap); + int ret; + + pm_runtime_mark_last_busy(dev); + ret = pm_runtime_put_autosuspend(dev); + if (ret) + dev_err(dev, "failed to power off\n"); + + return ret; +} + +static int fxls8962af_standby(struct fxls8962af_data *data) +{ + return regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1, + FXLS8962AF_SENS_CONFIG1_ACTIVE, 0); +} + +static int fxls8962af_active(struct fxls8962af_data *data) +{ + return regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1, + FXLS8962AF_SENS_CONFIG1_ACTIVE, 1); +} + +static int fxls8962af_is_active(struct fxls8962af_data *data) +{ + unsigned int reg; + int ret; + + ret = regmap_read(data->regmap, FXLS8962AF_SENS_CONFIG1, ®); + if (ret) + return ret; + + return reg & FXLS8962AF_SENS_CONFIG1_ACTIVE; +} + +static int fxls8962af_get_out(struct fxls8962af_data *data, + struct iio_chan_spec const *chan, int *val) +{ + struct device *dev = regmap_get_device(data->regmap); + __le16 raw_val; + int is_active; + int ret; + + is_active = fxls8962af_is_active(data); + if (!is_active) { + ret = fxls8962af_power_on(data); + if (ret) + return ret; + } + + ret = regmap_bulk_read(data->regmap, chan->address, + &raw_val, (chan->scan_type.storagebits / 8)); + + if (!is_active) + fxls8962af_power_off(data); + + if (ret) { + dev_err(dev, "failed to get out reg 0x%lx\n", chan->address); + return ret; + } + + *val = sign_extend32(le16_to_cpu(raw_val), + chan->scan_type.realbits - 1); + + return IIO_VAL_INT; +} + +static int fxls8962af_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + *type = IIO_VAL_INT_PLUS_NANO; + *vals = (int *)fxls8962af_scale_table; + *length = ARRAY_SIZE(fxls8962af_scale_table) * 2; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int fxls8962af_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + return IIO_VAL_INT_PLUS_NANO; +} + +static int fxls8962af_update_config(struct fxls8962af_data *data, u8 reg, + u8 mask, u8 val) +{ + int ret; + int is_active; + + is_active = fxls8962af_is_active(data); + if (is_active) { + ret = fxls8962af_standby(data); + if (ret) + return ret; + } + + ret = regmap_update_bits(data->regmap, reg, mask, val); + if (ret) + return ret; + + if (is_active) { + ret = fxls8962af_active(data); + if (ret) + return ret; + } + + return 0; +} + +static int fxls8962af_set_full_scale(struct fxls8962af_data *data, u32 scale) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(fxls8962af_scale_table); i++) + if (scale == fxls8962af_scale_table[i][1]) + break; + + if (i == ARRAY_SIZE(fxls8962af_scale_table)) + return -EINVAL; + + return fxls8962af_update_config(data, FXLS8962AF_SENS_CONFIG1, + FXLS8962AF_SC1_FSR_MASK, + FXLS8962AF_SC1_FSR_PREP(i)); +} + +static unsigned int fxls8962af_read_full_scale(struct fxls8962af_data *data, + int *val) +{ + int ret; + unsigned int reg; + u8 range_idx; + + ret = regmap_read(data->regmap, FXLS8962AF_SENS_CONFIG1, ®); + if (ret) + return ret; + + range_idx = FXLS8962AF_SC1_FSR_GET(reg); + + *val = fxls8962af_scale_table[range_idx][1]; + + return IIO_VAL_INT_PLUS_NANO; +} + +static int fxls8962af_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct fxls8962af_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_TEMP: + case IIO_ACCEL: + return fxls8962af_get_out(data, chan, val); + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + if (chan->type != IIO_TEMP) + return -EINVAL; + + *val = FXLS8962AF_TEMP_CENTER_VAL; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + return fxls8962af_read_full_scale(data, val2); + default: + return -EINVAL; + } +} + +static int fxls8962af_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct fxls8962af_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + if (val != 0) + return -EINVAL; + + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + ret = fxls8962af_set_full_scale(data, val2); + + iio_device_release_direct_mode(indio_dev); + return ret; + default: + return -EINVAL; + } +} + +#define FXLS8962AF_CHANNEL(axis, reg, idx) { \ + .type = IIO_ACCEL, \ + .address = reg, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index = idx, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 12, \ + .storagebits = 16, \ + .shift = 4, \ + .endianness = IIO_BE, \ + }, \ +} + +#define FXLS8962AF_TEMP_CHANNEL { \ + .type = IIO_TEMP, \ + .address = FXLS8962AF_TEMP_OUT, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_OFFSET),\ + .scan_index = -1, \ + .scan_type = { \ + .realbits = 8, \ + .storagebits = 8, \ + }, \ +} + +static const struct iio_chan_spec fxls8962af_channels[] = { + FXLS8962AF_CHANNEL(X, FXLS8962AF_OUT_X_LSB, fxls8962af_idx_x), + FXLS8962AF_CHANNEL(Y, FXLS8962AF_OUT_Y_LSB, fxls8962af_idx_y), + FXLS8962AF_CHANNEL(Z, FXLS8962AF_OUT_Z_LSB, fxls8962af_idx_z), + IIO_CHAN_SOFT_TIMESTAMP(fxls8962af_idx_ts), + FXLS8962AF_TEMP_CHANNEL, +}; + +static const struct fxls8962af_chip_info fxls_chip_info_table[] = { + [fxls8962af] = { + .chip_id = FXLS8962AF_DEVICE_ID, + .name = "fxls8962af", + .channels = fxls8962af_channels, + .num_channels = ARRAY_SIZE(fxls8962af_channels), + }, + [fxls8964af] = { + .chip_id = FXLS8964AF_DEVICE_ID, + .name = "fxls8964af", + .channels = fxls8962af_channels, + .num_channels = ARRAY_SIZE(fxls8962af_channels), + }, +}; + +static const struct iio_info fxls8962af_info = { + .read_raw = &fxls8962af_read_raw, + .write_raw = &fxls8962af_write_raw, + .write_raw_get_fmt = fxls8962af_write_raw_get_fmt, + .read_avail = fxls8962af_read_avail, +}; + +static int fxls8962af_reset(struct fxls8962af_data *data) +{ + struct device *dev = regmap_get_device(data->regmap); + unsigned int reg; + int ret; + + ret = regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1, + FXLS8962AF_SENS_CONFIG1_RST, + FXLS8962AF_SENS_CONFIG1_RST); + if (ret) + return ret; + + /* TBOOT1, TBOOT2, specifies we have to wait between 1 - 17.7ms */ + ret = regmap_read_poll_timeout(data->regmap, FXLS8962AF_INT_STATUS, reg, + (reg & FXLS8962AF_INT_STATUS_SRC_BOOT), + 1000, 18000); + if (ret == -ETIMEDOUT) + dev_err(dev, "reset timeout, int_status = 0x%x\n", reg); + + return ret; +} + +static void fxls8962af_regulator_disable(void *data_ptr) +{ + struct fxls8962af_data *data = data_ptr; + + regulator_disable(data->vdd_reg); +} + +static void fxls8962af_pm_disable(void *dev_ptr) +{ + struct device *dev = dev_ptr; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_put_noidle(dev); + + fxls8962af_standby(iio_priv(indio_dev)); +} + +int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq) +{ + struct fxls8962af_data *data; + struct iio_dev *indio_dev; + unsigned int reg; + int ret, i; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + dev_set_drvdata(dev, indio_dev); + data->regmap = regmap; + + ret = iio_read_mount_matrix(dev, "mount-matrix", &data->orientation); + if (ret) + return ret; + + data->vdd_reg = devm_regulator_get(dev, "vdd"); + if (IS_ERR(data->vdd_reg)) + return dev_err_probe(dev, PTR_ERR(data->vdd_reg), + "Failed to get vdd regulator\n"); + + ret = regulator_enable(data->vdd_reg); + if (ret) { + dev_err(dev, "Failed to enable vdd regulator: %d\n", ret); + return ret; + } + + ret = devm_add_action_or_reset(dev, fxls8962af_regulator_disable, data); + if (ret) + return ret; + + ret = regmap_read(data->regmap, FXLS8962AF_WHO_AM_I, ®); + if (ret) + return ret; + + for (i = 0; i < ARRAY_SIZE(fxls_chip_info_table); i++) { + if (fxls_chip_info_table[i].chip_id == reg) { + data->chip_info = &fxls_chip_info_table[i]; + break; + } + } + if (i == ARRAY_SIZE(fxls_chip_info_table)) { + dev_err(dev, "failed to match device in table\n"); + return -ENXIO; + } + + indio_dev->channels = data->chip_info->channels; + indio_dev->num_channels = data->chip_info->num_channels; + indio_dev->name = data->chip_info->name; + indio_dev->info = &fxls8962af_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = fxls8962af_reset(data); + if (ret) + return ret; + + ret = pm_runtime_set_active(dev); + if (ret) + return ret; + + pm_runtime_enable(dev); + pm_runtime_set_autosuspend_delay(dev, FXLS8962AF_AUTO_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(dev); + + ret = devm_add_action_or_reset(dev, fxls8962af_pm_disable, dev); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} +EXPORT_SYMBOL_GPL(fxls8962af_core_probe); + +static int __maybe_unused fxls8962af_runtime_suspend(struct device *dev) +{ + struct fxls8962af_data *data = iio_priv(dev_get_drvdata(dev)); + int ret; + + ret = fxls8962af_standby(data); + if (ret) { + dev_err(dev, "powering off device failed\n"); + return ret; + } + + return 0; +} + +static int __maybe_unused fxls8962af_runtime_resume(struct device *dev) +{ + struct fxls8962af_data *data = iio_priv(dev_get_drvdata(dev)); + + return fxls8962af_active(data); +} + +const struct dev_pm_ops fxls8962af_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(fxls8962af_runtime_suspend, + fxls8962af_runtime_resume, NULL) +}; +EXPORT_SYMBOL_GPL(fxls8962af_pm_ops); + +MODULE_AUTHOR("Sean Nyekjaer "); +MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/accel/fxls8962af-i2c.c b/drivers/iio/accel/fxls8962af-i2c.c new file mode 100644 index 000000000000..cfb004b20455 --- /dev/null +++ b/drivers/iio/accel/fxls8962af-i2c.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NXP FXLS8962AF/FXLS8964AF Accelerometer I2C Driver + * + * Copyright 2021 Connected Cars A/S + */ + +#include +#include +#include +#include +#include +#include + +#include "fxls8962af.h" + +static int fxls8962af_probe(struct i2c_client *client) +{ + struct regmap *regmap; + + regmap = devm_regmap_init_i2c(client, &fxls8962af_regmap_conf); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "Failed to initialize i2c regmap\n"); + return PTR_ERR(regmap); + } + + return fxls8962af_core_probe(&client->dev, regmap, client->irq); +} + +static const struct i2c_device_id fxls8962af_id[] = { + { "fxls8962af", fxls8962af }, + { "fxls8964af", fxls8964af }, + {} +}; +MODULE_DEVICE_TABLE(i2c, fxls8962af_id); + +static const struct of_device_id fxls8962af_of_match[] = { + { .compatible = "nxp,fxls8962af" }, + { .compatible = "nxp,fxls8964af" }, + {} +}; +MODULE_DEVICE_TABLE(of, fxls8962af_of_match); + +static struct i2c_driver fxls8962af_driver = { + .driver = { + .name = "fxls8962af_i2c", + .of_match_table = fxls8962af_of_match, + .pm = &fxls8962af_pm_ops, + }, + .probe_new = fxls8962af_probe, + .id_table = fxls8962af_id, +}; +module_i2c_driver(fxls8962af_driver); + +MODULE_AUTHOR("Sean Nyekjaer "); +MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer i2c driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/accel/fxls8962af-spi.c b/drivers/iio/accel/fxls8962af-spi.c new file mode 100644 index 000000000000..57108d3d480b --- /dev/null +++ b/drivers/iio/accel/fxls8962af-spi.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NXP FXLS8962AF/FXLS8964AF Accelerometer SPI Driver + * + * Copyright 2021 Connected Cars A/S + */ + +#include +#include +#include +#include +#include +#include + +#include "fxls8962af.h" + +static int fxls8962af_probe(struct spi_device *spi) +{ + struct regmap *regmap; + + regmap = devm_regmap_init_spi(spi, &fxls8962af_regmap_conf); + if (IS_ERR(regmap)) { + dev_err(&spi->dev, "Failed to initialize spi regmap\n"); + return PTR_ERR(regmap); + } + + return fxls8962af_core_probe(&spi->dev, regmap, spi->irq); +} + +static const struct of_device_id fxls8962af_spi_of_match[] = { + { .compatible = "nxp,fxls8962af" }, + { .compatible = "nxp,fxls8964af" }, + {} +}; +MODULE_DEVICE_TABLE(of, fxls8962af_spi_of_match); + +static const struct spi_device_id fxls8962af_spi_id_table[] = { + { "fxls8962af", fxls8962af }, + { "fxls8964af", fxls8964af }, + {} +}; +MODULE_DEVICE_TABLE(spi, fxls8962af_spi_id_table); + +static struct spi_driver fxls8962af_driver = { + .driver = { + .name = "fxls8962af_spi", + .pm = &fxls8962af_pm_ops, + .of_match_table = fxls8962af_spi_of_match, + }, + .probe = fxls8962af_probe, + .id_table = fxls8962af_spi_id_table, +}; +module_spi_driver(fxls8962af_driver); + +MODULE_AUTHOR("Sean Nyekjaer "); +MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer spi driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/accel/fxls8962af.h b/drivers/iio/accel/fxls8962af.h new file mode 100644 index 000000000000..b67572c3ef06 --- /dev/null +++ b/drivers/iio/accel/fxls8962af.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2021 Connected Cars A/S + */ +#ifndef _FXLS8962AF_H_ +#define _FXLS8962AF_H_ + +struct regmap; +struct device; + +enum { + fxls8962af, + fxls8964af, +}; + +int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq); +int fxls8962af_core_remove(struct device *dev); + +extern const struct dev_pm_ops fxls8962af_pm_ops; +extern const struct regmap_config fxls8962af_regmap_conf; + +#endif /* _FXLS8962AF_H_ */ -- cgit v1.2.3 From 90cc5ec5488ed22803a1a004a4be24a807f41dcd Mon Sep 17 00:00:00 2001 From: Sean Nyekjaer Date: Thu, 6 May 2021 09:09:37 +0200 Subject: iio: accel: fxls8962af: add set/get of samplerate This adds support for setting de accelerometers output data rate. Primarily used for hardware buffered reads. Signed-off-by: Sean Nyekjaer Signed-off-by: Jonathan Cameron --- drivers/iio/accel/fxls8962af-core.c | 78 +++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index 61b1825c85d1..13167bae9e67 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -50,6 +50,9 @@ #define FXLS8962AF_SENS_CONFIG2 0x16 #define FXLS8962AF_SENS_CONFIG3 0x17 +#define FXLS8962AF_SC3_WAKE_ODR_MASK GENMASK(7, 4) +#define FXLS8962AF_SC3_WAKE_ODR_PREP(x) FIELD_PREP(FXLS8962AF_SC3_WAKE_ODR_MASK, (x)) +#define FXLS8962AF_SC3_WAKE_ODR_GET(x) FIELD_GET(FXLS8962AF_SC3_WAKE_ODR_MASK, (x)) #define FXLS8962AF_SENS_CONFIG4 0x18 #define FXLS8962AF_SENS_CONFIG5 0x19 @@ -96,6 +99,7 @@ #define FXLS8962AF_AUTO_SUSPEND_DELAY_MS 2000 #define FXLS8962AF_SCALE_TABLE_LEN 4 +#define FXLS8962AF_SAMP_FREQ_TABLE_LEN 13 static const int fxls8962af_scale_table[FXLS8962AF_SCALE_TABLE_LEN][2] = { {0, IIO_G_TO_M_S_2(980000)}, @@ -104,6 +108,12 @@ static const int fxls8962af_scale_table[FXLS8962AF_SCALE_TABLE_LEN][2] = { {0, IIO_G_TO_M_S_2(7810000)}, }; +static const int fxls8962af_samp_freq_table[FXLS8962AF_SAMP_FREQ_TABLE_LEN][2] = { + {3200, 0}, {1600, 0}, {800, 0}, {400, 0}, {200, 0}, {100, 0}, + {50, 0}, {25, 0}, {12, 500000}, {6, 250000}, {3, 125000}, + {1, 563000}, {0, 781000}, +}; + struct fxls8962af_chip_info { const char *name; const struct iio_chan_spec *channels; @@ -224,6 +234,11 @@ static int fxls8962af_read_avail(struct iio_dev *indio_dev, *vals = (int *)fxls8962af_scale_table; *length = ARRAY_SIZE(fxls8962af_scale_table) * 2; return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SAMP_FREQ: + *type = IIO_VAL_INT_PLUS_MICRO; + *vals = (int *)fxls8962af_samp_freq_table; + *length = ARRAY_SIZE(fxls8962af_samp_freq_table) * 2; + return IIO_AVAIL_LIST; default: return -EINVAL; } @@ -233,7 +248,14 @@ static int fxls8962af_write_raw_get_fmt(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, long mask) { - return IIO_VAL_INT_PLUS_NANO; + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_SAMP_FREQ: + return IIO_VAL_INT_PLUS_MICRO; + default: + return IIO_VAL_INT_PLUS_NANO; + } } static int fxls8962af_update_config(struct fxls8962af_data *data, u8 reg, @@ -296,6 +318,43 @@ static unsigned int fxls8962af_read_full_scale(struct fxls8962af_data *data, return IIO_VAL_INT_PLUS_NANO; } +static int fxls8962af_set_samp_freq(struct fxls8962af_data *data, u32 val, + u32 val2) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(fxls8962af_samp_freq_table); i++) + if (val == fxls8962af_samp_freq_table[i][0] && + val2 == fxls8962af_samp_freq_table[i][1]) + break; + + if (i == ARRAY_SIZE(fxls8962af_samp_freq_table)) + return -EINVAL; + + return fxls8962af_update_config(data, FXLS8962AF_SENS_CONFIG3, + FXLS8962AF_SC3_WAKE_ODR_MASK, + FXLS8962AF_SC3_WAKE_ODR_PREP(i)); +} + +static unsigned int fxls8962af_read_samp_freq(struct fxls8962af_data *data, + int *val, int *val2) +{ + int ret; + unsigned int reg; + u8 range_idx; + + ret = regmap_read(data->regmap, FXLS8962AF_SENS_CONFIG3, ®); + if (ret) + return ret; + + range_idx = FXLS8962AF_SC3_WAKE_ODR_GET(reg); + + *val = fxls8962af_samp_freq_table[range_idx][0]; + *val2 = fxls8962af_samp_freq_table[range_idx][1]; + + return IIO_VAL_INT_PLUS_MICRO; +} + static int fxls8962af_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -320,6 +379,8 @@ static int fxls8962af_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: *val = 0; return fxls8962af_read_full_scale(data, val2); + case IIO_CHAN_INFO_SAMP_FREQ: + return fxls8962af_read_samp_freq(data, val, val2); default: return -EINVAL; } @@ -343,6 +404,15 @@ static int fxls8962af_write_raw(struct iio_dev *indio_dev, ret = fxls8962af_set_full_scale(data, val2); + iio_device_release_direct_mode(indio_dev); + return ret; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + ret = fxls8962af_set_samp_freq(data, val, val2); + iio_device_release_direct_mode(indio_dev); return ret; default: @@ -356,8 +426,10 @@ static int fxls8962af_write_raw(struct iio_dev *indio_dev, .modified = 1, \ .channel2 = IIO_MOD_##axis, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ - .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .scan_index = idx, \ .scan_type = { \ .sign = 's', \ -- cgit v1.2.3 From 9ab2c60e6b26034b90d3bd446bca3dc8b157f61a Mon Sep 17 00:00:00 2001 From: Sean Nyekjaer Date: Thu, 6 May 2021 09:09:38 +0200 Subject: iio: accel: fxls8962af: add interrupt support Preparation commit for the next that adds hw buffered sampling. Adds the interrupt function and reads the devicetree for which interrupt pin that is used. Signed-off-by: Sean Nyekjaer Signed-off-by: Jonathan Cameron --- drivers/iio/accel/fxls8962af-core.c | 114 ++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index 13167bae9e67..b909ba23e47c 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -54,6 +55,10 @@ #define FXLS8962AF_SC3_WAKE_ODR_PREP(x) FIELD_PREP(FXLS8962AF_SC3_WAKE_ODR_MASK, (x)) #define FXLS8962AF_SC3_WAKE_ODR_GET(x) FIELD_GET(FXLS8962AF_SC3_WAKE_ODR_MASK, (x)) #define FXLS8962AF_SENS_CONFIG4 0x18 +#define FXLS8962AF_SC4_INT_PP_OD_MASK BIT(1) +#define FXLS8962AF_SC4_INT_PP_OD_PREP(x) FIELD_PREP(FXLS8962AF_SC4_INT_PP_OD_MASK, (x)) +#define FXLS8962AF_SC4_INT_POL_MASK BIT(0) +#define FXLS8962AF_SC4_INT_POL_PREP(x) FIELD_PREP(FXLS8962AF_SC4_INT_POL_MASK, (x)) #define FXLS8962AF_SENS_CONFIG5 0x19 #define FXLS8962AF_WAKE_IDLE_LSB 0x1b @@ -62,6 +67,9 @@ #define FXLS8962AF_INT_EN 0x20 #define FXLS8962AF_INT_PIN_SEL 0x21 +#define FXLS8962AF_INT_PIN_SEL_MASK GENMASK(7, 0) +#define FXLS8962AF_INT_PIN_SEL_INT1 0x00 +#define FXLS8962AF_INT_PIN_SEL_INT2 GENMASK(7, 0) #define FXLS8962AF_OFF_X 0x22 #define FXLS8962AF_OFF_Y 0x23 @@ -142,6 +150,11 @@ enum { fxls8962af_idx_ts, }; +enum fxls8962af_int_pin { + FXLS8962AF_PIN_INT1, + FXLS8962AF_PIN_INT2, +}; + static int fxls8962af_power_on(struct fxls8962af_data *data) { struct device *dev = regmap_get_device(data->regmap); @@ -504,6 +517,20 @@ static int fxls8962af_reset(struct fxls8962af_data *data) return ret; } +static irqreturn_t fxls8962af_interrupt(int irq, void *p) +{ + struct iio_dev *indio_dev = p; + struct fxls8962af_data *data = iio_priv(indio_dev); + unsigned int reg; + int ret; + + ret = regmap_read(data->regmap, FXLS8962AF_INT_STATUS, ®); + if (ret) + return IRQ_NONE; + + return IRQ_NONE; +} + static void fxls8962af_regulator_disable(void *data_ptr) { struct fxls8962af_data *data = data_ptr; @@ -523,6 +550,87 @@ static void fxls8962af_pm_disable(void *dev_ptr) fxls8962af_standby(iio_priv(indio_dev)); } +static void fxls8962af_get_irq(struct device_node *of_node, + enum fxls8962af_int_pin *pin) +{ + int irq; + + irq = of_irq_get_byname(of_node, "INT2"); + if (irq > 0) { + *pin = FXLS8962AF_PIN_INT2; + return; + } + + *pin = FXLS8962AF_PIN_INT1; +} + +static int fxls8962af_irq_setup(struct iio_dev *indio_dev, int irq) +{ + struct fxls8962af_data *data = iio_priv(indio_dev); + struct device *dev = regmap_get_device(data->regmap); + unsigned long irq_type; + bool irq_active_high; + enum fxls8962af_int_pin int_pin; + u8 int_pin_sel; + int ret; + + fxls8962af_get_irq(dev->of_node, &int_pin); + switch (int_pin) { + case FXLS8962AF_PIN_INT1: + int_pin_sel = FXLS8962AF_INT_PIN_SEL_INT1; + break; + case FXLS8962AF_PIN_INT2: + int_pin_sel = FXLS8962AF_INT_PIN_SEL_INT2; + break; + default: + dev_err(dev, "unsupported int pin selected\n"); + return -EINVAL; + } + + ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_PIN_SEL, + FXLS8962AF_INT_PIN_SEL_MASK, int_pin_sel); + if (ret) + return ret; + + irq_type = irqd_get_trigger_type(irq_get_irq_data(irq)); + + switch (irq_type) { + case IRQF_TRIGGER_HIGH: + case IRQF_TRIGGER_RISING: + irq_active_high = true; + break; + case IRQF_TRIGGER_LOW: + case IRQF_TRIGGER_FALLING: + irq_active_high = false; + break; + default: + dev_info(dev, "mode %lx unsupported\n", irq_type); + return -EINVAL; + } + + ret = regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG4, + FXLS8962AF_SC4_INT_POL_MASK, + FXLS8962AF_SC4_INT_POL_PREP(irq_active_high)); + if (ret) + return ret; + + if (device_property_read_bool(dev, "drive-open-drain")) { + ret = regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG4, + FXLS8962AF_SC4_INT_PP_OD_MASK, + FXLS8962AF_SC4_INT_PP_OD_PREP(1)); + if (ret) + return ret; + + irq_type |= IRQF_SHARED; + } + + return devm_request_threaded_irq(dev, + irq, + NULL, fxls8962af_interrupt, + irq_type | IRQF_ONESHOT, + indio_dev->name, indio_dev); +} + int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq) { struct fxls8962af_data *data; @@ -582,6 +690,12 @@ int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq) if (ret) return ret; + if (irq) { + ret = fxls8962af_irq_setup(indio_dev, irq); + if (ret) + return ret; + } + ret = pm_runtime_set_active(dev); if (ret) return ret; -- cgit v1.2.3 From 79e3a5bdd9efbdf4e1069793d7735b432d641e7c Mon Sep 17 00:00:00 2001 From: Sean Nyekjaer Date: Thu, 6 May 2021 09:09:39 +0200 Subject: iio: accel: fxls8962af: add hw buffered sampling When buffered sampling is enabled, the accelerometer will dump data into the internal fifo and interrupt at watermark. Then the driver flushes all data to the iio buffer. As the accelerometer doesn't have internal timestamps, they are approximated between the current and last interrupt. Signed-off-by: Sean Nyekjaer Signed-off-by: Jonathan Cameron --- drivers/iio/accel/fxls8962af-core.c | 195 ++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index b909ba23e47c..3ea8488ed4c2 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -20,13 +20,16 @@ #include #include +#include #include +#include #include #include "fxls8962af.h" #define FXLS8962AF_INT_STATUS 0x00 #define FXLS8962AF_INT_STATUS_SRC_BOOT BIT(0) +#define FXLS8962AF_INT_STATUS_SRC_BUF BIT(5) #define FXLS8962AF_INT_STATUS_SRC_DRDY BIT(7) #define FXLS8962AF_TEMP_OUT 0x01 #define FXLS8962AF_VECM_LSB 0x02 @@ -34,6 +37,9 @@ #define FXLS8962AF_OUT_Y_LSB 0x06 #define FXLS8962AF_OUT_Z_LSB 0x08 #define FXLS8962AF_BUF_STATUS 0x0b +#define FXLS8962AF_BUF_STATUS_BUF_CNT GENMASK(5, 0) +#define FXLS8962AF_BUF_STATUS_BUF_OVF BIT(6) +#define FXLS8962AF_BUF_STATUS_BUF_WMRK BIT(7) #define FXLS8962AF_BUF_X_LSB 0x0c #define FXLS8962AF_BUF_Y_LSB 0x0e #define FXLS8962AF_BUF_Z_LSB 0x10 @@ -66,6 +72,7 @@ #define FXLS8962AF_ASLP_COUNT_LSB 0x1e #define FXLS8962AF_INT_EN 0x20 +#define FXLS8962AF_INT_EN_BUF_EN BIT(6) #define FXLS8962AF_INT_PIN_SEL 0x21 #define FXLS8962AF_INT_PIN_SEL_MASK GENMASK(7, 0) #define FXLS8962AF_INT_PIN_SEL_INT1 0x00 @@ -76,7 +83,10 @@ #define FXLS8962AF_OFF_Z 0x24 #define FXLS8962AF_BUF_CONFIG1 0x26 +#define FXLS8962AF_BC1_BUF_MODE_MASK GENMASK(6, 5) +#define FXLS8962AF_BC1_BUF_MODE_PREP(x) FIELD_PREP(FXLS8962AF_BC1_BUF_MODE_MASK, (x)) #define FXLS8962AF_BUF_CONFIG2 0x27 +#define FXLS8962AF_BUF_CONFIG2_BUF_WMRK GENMASK(5, 0) #define FXLS8962AF_ORIENT_STATUS 0x28 #define FXLS8962AF_ORIENT_CONFIG 0x29 @@ -106,6 +116,7 @@ #define FXLS8962AF_AUTO_SUSPEND_DELAY_MS 2000 +#define FXLS8962AF_FIFO_LENGTH 32 #define FXLS8962AF_SCALE_TABLE_LEN 4 #define FXLS8962AF_SAMP_FREQ_TABLE_LEN 13 @@ -133,7 +144,13 @@ struct fxls8962af_data { struct regmap *regmap; const struct fxls8962af_chip_info *chip_info; struct regulator *vdd_reg; + struct { + __le16 channels[3]; + s64 ts __aligned(8); + } scan; + int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */ struct iio_mount_matrix orientation; + u8 watermark; }; const struct regmap_config fxls8962af_regmap_conf = { @@ -433,6 +450,18 @@ static int fxls8962af_write_raw(struct iio_dev *indio_dev, } } +static int fxls8962af_set_watermark(struct iio_dev *indio_dev, unsigned val) +{ + struct fxls8962af_data *data = iio_priv(indio_dev); + + if (val > FXLS8962AF_FIFO_LENGTH) + val = FXLS8962AF_FIFO_LENGTH; + + data->watermark = val; + + return 0; +} + #define FXLS8962AF_CHANNEL(axis, reg, idx) { \ .type = IIO_ACCEL, \ .address = reg, \ @@ -493,6 +522,7 @@ static const struct iio_info fxls8962af_info = { .write_raw = &fxls8962af_write_raw, .write_raw_get_fmt = fxls8962af_write_raw_get_fmt, .read_avail = fxls8962af_read_avail, + .hwfifo_set_watermark = fxls8962af_set_watermark, }; static int fxls8962af_reset(struct fxls8962af_data *data) @@ -517,6 +547,157 @@ static int fxls8962af_reset(struct fxls8962af_data *data) return ret; } +static int __fxls8962af_fifo_set_mode(struct fxls8962af_data *data, bool onoff) +{ + int ret; + + /* Enable watermark at max fifo size */ + ret = regmap_update_bits(data->regmap, FXLS8962AF_BUF_CONFIG2, + FXLS8962AF_BUF_CONFIG2_BUF_WMRK, + data->watermark); + if (ret) + return ret; + + return regmap_update_bits(data->regmap, FXLS8962AF_BUF_CONFIG1, + FXLS8962AF_BC1_BUF_MODE_MASK, + FXLS8962AF_BC1_BUF_MODE_PREP(onoff)); +} + +static int fxls8962af_buffer_preenable(struct iio_dev *indio_dev) +{ + return fxls8962af_power_on(iio_priv(indio_dev)); +} + +static int fxls8962af_buffer_postenable(struct iio_dev *indio_dev) +{ + struct fxls8962af_data *data = iio_priv(indio_dev); + int ret; + + fxls8962af_standby(data); + + /* Enable buffer interrupt */ + ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_EN, + FXLS8962AF_INT_EN_BUF_EN, + FXLS8962AF_INT_EN_BUF_EN); + if (ret) + return ret; + + ret = __fxls8962af_fifo_set_mode(data, true); + + fxls8962af_active(data); + + return ret; +} + +static int fxls8962af_buffer_predisable(struct iio_dev *indio_dev) +{ + struct fxls8962af_data *data = iio_priv(indio_dev); + int ret; + + fxls8962af_standby(data); + + /* Disable buffer interrupt */ + ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_EN, + FXLS8962AF_INT_EN_BUF_EN, 0); + if (ret) + return ret; + + ret = __fxls8962af_fifo_set_mode(data, false); + + fxls8962af_active(data); + + return ret; +} + +static int fxls8962af_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct fxls8962af_data *data = iio_priv(indio_dev); + + return fxls8962af_power_off(data); +} + +static const struct iio_buffer_setup_ops fxls8962af_buffer_ops = { + .preenable = fxls8962af_buffer_preenable, + .postenable = fxls8962af_buffer_postenable, + .predisable = fxls8962af_buffer_predisable, + .postdisable = fxls8962af_buffer_postdisable, +}; + +static int fxls8962af_fifo_transfer(struct fxls8962af_data *data, + u16 *buffer, int samples) +{ + struct device *dev = regmap_get_device(data->regmap); + int sample_length = 3 * sizeof(*buffer); + int ret; + int total_length = samples * sample_length; + + ret = regmap_raw_read(data->regmap, FXLS8962AF_BUF_X_LSB, buffer, + total_length); + if (ret) + dev_err(dev, "Error transferring data from fifo: %d\n", ret); + + return ret; +} + +static int fxls8962af_fifo_flush(struct iio_dev *indio_dev) +{ + struct fxls8962af_data *data = iio_priv(indio_dev); + struct device *dev = regmap_get_device(data->regmap); + u16 buffer[FXLS8962AF_FIFO_LENGTH * 3]; + uint64_t sample_period; + unsigned int reg; + int64_t tstamp; + int ret, i; + u8 count; + + ret = regmap_read(data->regmap, FXLS8962AF_BUF_STATUS, ®); + if (ret) + return ret; + + if (reg & FXLS8962AF_BUF_STATUS_BUF_OVF) { + dev_err(dev, "Buffer overflow"); + return -EOVERFLOW; + } + + count = reg & FXLS8962AF_BUF_STATUS_BUF_CNT; + if (!count) + return 0; + + data->old_timestamp = data->timestamp; + data->timestamp = iio_get_time_ns(indio_dev); + + /* + * Approximate timestamps for each of the sample based on the sampling, + * frequency, timestamp for last sample and number of samples. + */ + sample_period = (data->timestamp - data->old_timestamp); + do_div(sample_period, count); + tstamp = data->timestamp - (count - 1) * sample_period; + + ret = fxls8962af_fifo_transfer(data, buffer, count); + if (ret) + return ret; + + /* Demux hw FIFO into kfifo. */ + for (i = 0; i < count; i++) { + int j, bit; + + j = 0; + for_each_set_bit(bit, indio_dev->active_scan_mask, + indio_dev->masklength) { + memcpy(&data->scan.channels[j++], &buffer[i * 3 + bit], + sizeof(data->scan.channels[0])); + } + + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, + tstamp); + + tstamp += sample_period; + } + + return count; +} + static irqreturn_t fxls8962af_interrupt(int irq, void *p) { struct iio_dev *indio_dev = p; @@ -528,6 +709,14 @@ static irqreturn_t fxls8962af_interrupt(int irq, void *p) if (ret) return IRQ_NONE; + if (reg & FXLS8962AF_INT_STATUS_SRC_BUF) { + ret = fxls8962af_fifo_flush(indio_dev); + if (ret) + return IRQ_NONE; + + return IRQ_HANDLED; + } + return IRQ_NONE; } @@ -694,6 +883,12 @@ int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq) ret = fxls8962af_irq_setup(indio_dev, irq); if (ret) return ret; + + ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, + INDIO_BUFFER_SOFTWARE, + &fxls8962af_buffer_ops); + if (ret) + return ret; } ret = pm_runtime_set_active(dev); -- cgit v1.2.3 From af959b7b96b87aee13ed5b0041fc14ca2e72cc84 Mon Sep 17 00:00:00 2001 From: Sean Nyekjaer Date: Thu, 6 May 2021 09:09:40 +0200 Subject: iio: accel: fxls8962af: fix errata bug E3 - I2C burst reads When flushing the hw fifo there is a bug in the I2C that prevents burst reads of more than one sample pair. Signed-off-by: Sean Nyekjaer Signed-off-by: Jonathan Cameron --- drivers/iio/accel/fxls8962af-core.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index 3ea8488ed4c2..9fe5a18a605c 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -623,16 +624,42 @@ static const struct iio_buffer_setup_ops fxls8962af_buffer_ops = { .postdisable = fxls8962af_buffer_postdisable, }; +static int fxls8962af_i2c_raw_read_errata3(struct fxls8962af_data *data, + u16 *buffer, int samples, + int sample_length) +{ + int i, ret; + + for (i = 0; i < samples; i++) { + ret = regmap_raw_read(data->regmap, FXLS8962AF_BUF_X_LSB, + &buffer[i * 3], sample_length); + if (ret) + return ret; + } + + return ret; +} + static int fxls8962af_fifo_transfer(struct fxls8962af_data *data, u16 *buffer, int samples) { struct device *dev = regmap_get_device(data->regmap); int sample_length = 3 * sizeof(*buffer); - int ret; int total_length = samples * sample_length; + int ret; + + if (i2c_verify_client(dev)) + /* + * Due to errata bug: + * E3: FIFO burst read operation error using I2C interface + * We have to avoid burst reads on I2C.. + */ + ret = fxls8962af_i2c_raw_read_errata3(data, buffer, samples, + sample_length); + else + ret = regmap_raw_read(data->regmap, FXLS8962AF_BUF_X_LSB, buffer, + total_length); - ret = regmap_raw_read(data->regmap, FXLS8962AF_BUF_X_LSB, buffer, - total_length); if (ret) dev_err(dev, "Error transferring data from fifo: %d\n", ret); -- cgit v1.2.3 From f42590c4cb41353c12cac5b30c5c3c1498b15ee2 Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Tue, 11 May 2021 19:39:12 +0800 Subject: iio: ep93xx: Remove redundant error printing in ep93xx_adc_probe() When devm_ioremap_resource() fails, a clear enough error message will be printed by its subfunction __devm_ioremap_resource(). The error information contains the device name, failure cause, and possibly resource information. Therefore, remove the error printing here to simplify code and reduce the binary size. Reported-by: Hulk Robot Signed-off-by: Zhen Lei Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ep93xx_adc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c index c08ab3c6dfaf..a10a4e8d94fd 100644 --- a/drivers/iio/adc/ep93xx_adc.c +++ b/drivers/iio/adc/ep93xx_adc.c @@ -165,10 +165,8 @@ static int ep93xx_adc_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(priv->base)) { - dev_err(&pdev->dev, "Cannot map memory resource\n"); + if (IS_ERR(priv->base)) return PTR_ERR(priv->base); - } iiodev->name = dev_name(&pdev->dev); iiodev->modes = INDIO_DIRECT_MODE; -- cgit v1.2.3 From f5abfa40a755f70194af3d227e5f2bad86d5c4fc Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Wed, 12 May 2021 17:38:44 +0800 Subject: iio: adc: Add missing MODULE_DEVICE_TABLE MODULE_DEVICE_TABLE is used to extract the device information out of the driver and builds a table when being compiled. If using this macro, kernel can find the driver if available when the device is plugged in, and then loads that driver and initializes the device. Signed-off-by: Chunyan Zhang Signed-off-by: Jonathan Cameron --- drivers/iio/adc/sc27xx_adc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/sc27xx_adc.c b/drivers/iio/adc/sc27xx_adc.c index 301cf66de695..00098caf6d9e 100644 --- a/drivers/iio/adc/sc27xx_adc.c +++ b/drivers/iio/adc/sc27xx_adc.c @@ -549,6 +549,7 @@ static const struct of_device_id sc27xx_adc_of_match[] = { { .compatible = "sprd,sc2731-adc", }, { } }; +MODULE_DEVICE_TABLE(of, sc27xx_adc_of_match); static struct platform_driver sc27xx_adc_driver = { .probe = sc27xx_adc_probe, -- cgit v1.2.3 From ae4467f6884ea16f6338295e9951eae3544aac87 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 11 May 2021 16:24:01 +0200 Subject: iio: accel: kxcjk-1013: Refactor configuration registers into struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most Kionix accelerometers seem to use fairly consistent register bits, but the register addresses are not necessarily the same. This is already partially the case for the KXTF9 (added in commit 1540d0106bcb ("iio: accel: kxcjk1013: add support for KXTF9")), which has some registers at different addresses. However, it's even much worse for the KX023-1025. All register bits used by the kxcjk-1013 driver seem to be fully compatible with KX023, but it has most registers at totally different addresses. In preparation to add support for KX023-1025, move the fixed register addresses into a struct so we can change them for KX023 more easily. Cc: Michał Mirosław Cc: Srinivas Pandruvada Reviewed-by: Hans de Goede Signed-off-by: Stephan Gerhold Signed-off-by: Jonathan Cameron --- drivers/iio/accel/kxcjk-1013.c | 124 +++++++++++++++++++++++++++-------------- 1 file changed, 82 insertions(+), 42 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 283e6a3feffc..ab8c972e1a35 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -51,13 +51,15 @@ #define KXTF9_REG_TILT_POS_CUR 0x10 #define KXTF9_REG_TILT_POS_PREV 0x11 #define KXTF9_REG_INT_SRC1 0x15 -#define KXCJK1013_REG_INT_SRC1 0x16 /* compatible, but called INT_SRC2 in KXTF9 ds */ +#define KXTF9_REG_INT_SRC2 0x16 +#define KXCJK1013_REG_INT_SRC1 0x16 #define KXCJK1013_REG_INT_SRC2 0x17 #define KXCJK1013_REG_STATUS_REG 0x18 #define KXCJK1013_REG_INT_REL 0x1A #define KXCJK1013_REG_CTRL1 0x1B #define KXTF9_REG_CTRL2 0x1C -#define KXCJK1013_REG_CTRL2 0x1D /* mostly compatible, CTRL_REG3 in KTXF9 ds */ +#define KXTF9_REG_CTRL3 0x1D +#define KXCJK1013_REG_CTRL2 0x1D #define KXCJK1013_REG_INT_CTRL1 0x1E #define KXCJK1013_REG_INT_CTRL2 0x1F #define KXTF9_REG_INT_CTRL3 0x20 @@ -133,6 +135,43 @@ enum kx_acpi_type { ACPI_KIOX010A, }; +struct kx_chipset_regs { + u8 int_src1; + u8 int_src2; + u8 int_rel; + u8 ctrl1; + u8 wuf_ctrl; + u8 int_ctrl1; + u8 data_ctrl; + u8 wake_timer; + u8 wake_thres; +}; + +static const struct kx_chipset_regs kxcjk1013_regs = { + .int_src1 = KXCJK1013_REG_INT_SRC1, + .int_src2 = KXCJK1013_REG_INT_SRC2, + .int_rel = KXCJK1013_REG_INT_REL, + .ctrl1 = KXCJK1013_REG_CTRL1, + .wuf_ctrl = KXCJK1013_REG_CTRL2, + .int_ctrl1 = KXCJK1013_REG_INT_CTRL1, + .data_ctrl = KXCJK1013_REG_DATA_CTRL, + .wake_timer = KXCJK1013_REG_WAKE_TIMER, + .wake_thres = KXCJK1013_REG_WAKE_THRES, +}; + +static const struct kx_chipset_regs kxtf9_regs = { + /* .int_src1 was moved to INT_SRC2 on KXTF9 */ + .int_src1 = KXTF9_REG_INT_SRC2, + /* .int_src2 is not available */ + .int_rel = KXCJK1013_REG_INT_REL, + .ctrl1 = KXCJK1013_REG_CTRL1, + .wuf_ctrl = KXTF9_REG_CTRL3, + .int_ctrl1 = KXCJK1013_REG_INT_CTRL1, + .data_ctrl = KXCJK1013_REG_DATA_CTRL, + .wake_timer = KXCJK1013_REG_WAKE_TIMER, + .wake_thres = KXTF9_REG_WAKE_THRESH, +}; + struct kxcjk1013_data { struct regulator_bulk_data regulators[2]; struct i2c_client *client; @@ -152,6 +191,7 @@ struct kxcjk1013_data { int64_t timestamp; enum kx_chipset chipset; enum kx_acpi_type acpi_type; + const struct kx_chipset_regs *regs; }; enum kxcjk1013_axis { @@ -309,7 +349,7 @@ static int kxcjk1013_set_mode(struct kxcjk1013_data *data, { int ret; - ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1); + ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); return ret; @@ -320,8 +360,7 @@ static int kxcjk1013_set_mode(struct kxcjk1013_data *data, else ret |= KXCJK1013_REG_CTRL1_BIT_PC1; - ret = i2c_smbus_write_byte_data(data->client, - KXCJK1013_REG_CTRL1, ret); + ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_ctrl1\n"); return ret; @@ -335,7 +374,7 @@ static int kxcjk1013_get_mode(struct kxcjk1013_data *data, { int ret; - ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1); + ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); return ret; @@ -353,7 +392,7 @@ static int kxcjk1013_set_range(struct kxcjk1013_data *data, int range_index) { int ret; - ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1); + ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); return ret; @@ -364,9 +403,7 @@ static int kxcjk1013_set_range(struct kxcjk1013_data *data, int range_index) ret |= (KXCJK1013_scale_table[range_index].gsel_0 << 3); ret |= (KXCJK1013_scale_table[range_index].gsel_1 << 4); - ret = i2c_smbus_write_byte_data(data->client, - KXCJK1013_REG_CTRL1, - ret); + ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_ctrl1\n"); return ret; @@ -400,7 +437,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) if (ret < 0) return ret; - ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1); + ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); return ret; @@ -409,8 +446,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) /* Set 12 bit mode */ ret |= KXCJK1013_REG_CTRL1_BIT_RES; - ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_CTRL1, - ret); + ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_ctrl\n"); return ret; @@ -421,7 +457,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) if (ret < 0) return ret; - ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_DATA_CTRL); + ret = i2c_smbus_read_byte_data(data->client, data->regs->data_ctrl); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_data_ctrl\n"); return ret; @@ -430,7 +466,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) data->odr_bits = ret; /* Set up INT polarity */ - ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_CTRL1); + ret = i2c_smbus_read_byte_data(data->client, data->regs->int_ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n"); return ret; @@ -441,8 +477,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) else ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEA; - ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1, - ret); + ret = i2c_smbus_write_byte_data(data->client, data->regs->int_ctrl1, ret); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n"); return ret; @@ -497,10 +532,9 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on) static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data) { - int waketh_reg, ret; + int ret; - ret = i2c_smbus_write_byte_data(data->client, - KXCJK1013_REG_WAKE_TIMER, + ret = i2c_smbus_write_byte_data(data->client, data->regs->wake_timer, data->wake_dur); if (ret < 0) { dev_err(&data->client->dev, @@ -508,9 +542,7 @@ static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data) return ret; } - waketh_reg = data->chipset == KXTF9 ? - KXTF9_REG_WAKE_THRESH : KXCJK1013_REG_WAKE_THRES; - ret = i2c_smbus_write_byte_data(data->client, waketh_reg, + ret = i2c_smbus_write_byte_data(data->client, data->regs->wake_thres, data->wake_thres); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_wake_thres\n"); @@ -539,7 +571,7 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data, if (ret < 0) return ret; - ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_CTRL1); + ret = i2c_smbus_read_byte_data(data->client, data->regs->int_ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n"); return ret; @@ -550,14 +582,13 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data, else ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEN; - ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1, - ret); + ret = i2c_smbus_write_byte_data(data->client, data->regs->int_ctrl1, ret); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n"); return ret; } - ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1); + ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); return ret; @@ -568,8 +599,7 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data, else ret &= ~KXCJK1013_REG_CTRL1_BIT_WUFE; - ret = i2c_smbus_write_byte_data(data->client, - KXCJK1013_REG_CTRL1, ret); + ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_ctrl1\n"); return ret; @@ -599,7 +629,7 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data, if (ret < 0) return ret; - ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_CTRL1); + ret = i2c_smbus_read_byte_data(data->client, data->regs->int_ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n"); return ret; @@ -610,14 +640,13 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data, else ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEN; - ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1, - ret); + ret = i2c_smbus_write_byte_data(data->client, data->regs->int_ctrl1, ret); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n"); return ret; } - ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1); + ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); return ret; @@ -628,8 +657,7 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data, else ret &= ~KXCJK1013_REG_CTRL1_BIT_DRDY; - ret = i2c_smbus_write_byte_data(data->client, - KXCJK1013_REG_CTRL1, ret); + ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_ctrl1\n"); return ret; @@ -701,7 +729,7 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2) if (ret < 0) return ret; - ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_DATA_CTRL, + ret = i2c_smbus_write_byte_data(data->client, data->regs->data_ctrl, odr_setting->odr_bits); if (ret < 0) { dev_err(&data->client->dev, "Error writing data_ctrl\n"); @@ -710,7 +738,7 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2) data->odr_bits = odr_setting->odr_bits; - ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_CTRL2, + ret = i2c_smbus_write_byte_data(data->client, data->regs->wuf_ctrl, odr_setting->wuf_bits); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_ctrl2\n"); @@ -1113,7 +1141,7 @@ static void kxcjk1013_trig_reen(struct iio_trigger *trig) struct kxcjk1013_data *data = iio_priv(indio_dev); int ret; - ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_REL); + ret = i2c_smbus_read_byte_data(data->client, data->regs->int_rel); if (ret < 0) dev_err(&data->client->dev, "Error reading reg_int_rel\n"); } @@ -1166,8 +1194,7 @@ static void kxcjk1013_report_motion_event(struct iio_dev *indio_dev) { struct kxcjk1013_data *data = iio_priv(indio_dev); - int ret = i2c_smbus_read_byte_data(data->client, - KXCJK1013_REG_INT_SRC2); + int ret = i2c_smbus_read_byte_data(data->client, data->regs->int_src2); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_int_src2\n"); return; @@ -1234,7 +1261,7 @@ static irqreturn_t kxcjk1013_event_handler(int irq, void *private) struct kxcjk1013_data *data = iio_priv(indio_dev); int ret; - ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_SRC1); + ret = i2c_smbus_read_byte_data(data->client, data->regs->int_src1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_int_src1\n"); goto ack_intr; @@ -1257,7 +1284,7 @@ ack_intr: if (data->dready_trigger_on) return IRQ_HANDLED; - ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_REL); + ret = i2c_smbus_read_byte_data(data->client, data->regs->int_rel); if (ret < 0) dev_err(&data->client->dev, "Error reading reg_int_rel\n"); @@ -1378,6 +1405,19 @@ static int kxcjk1013_probe(struct i2c_client *client, } else return -ENODEV; + switch (data->chipset) { + case KXCJK1013: + case KXCJ91008: + case KXTJ21009: + data->regs = &kxcjk1013_regs; + break; + case KXTF9: + data->regs = &kxtf9_regs; + break; + default: + return -EINVAL; + } + ret = kxcjk1013_chip_init(data); if (ret < 0) return ret; -- cgit v1.2.3 From c630c1768522d5728e51470ea4f292a35919bb6d Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 11 May 2021 16:24:02 +0200 Subject: iio: accel: kxcjk-1013: Add support for KX023-1025 The KX023-1025 accelerometer [1] seems to be some mixture of KXCJK and KXTF9. It has the motion interrupt functionality from KXCJK but also the tap detection from KXTF9, and a lot more functionality. The configuration register map seems fairly different at first, but actually all register bits used by the kxcjk-1013 driver are available at the same bit positions on KX023-1025. It's just quite misleading because: 1. The registers have entirely different names and are at different addresses, but the bits are mostly named the same (and mean the same). 2. There are many more registers and bits used that are reserved on KXCJK to enable additional functionality. Ignoring all additionally available functionality for now, the KX023 works just fine after setting up the struct with the correct register addresses. The only difference that needs to be handled additionally is that the KX023 supports two configurable interrupt lines (INT1/2). For now only INT1 is supported so we route all interrupts used by the driver there. [1]: https://kionixfs.azureedge.net/en/datasheet/KX023-1025%20Specifications%20Rev%2012.0.pdf Cc: Srinivas Pandruvada Reviewed-by: Hans de Goede Signed-off-by: Stephan Gerhold Signed-off-by: Jonathan Cameron --- drivers/iio/accel/kxcjk-1013.c | 93 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index ab8c972e1a35..18a96828f6be 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -79,6 +79,45 @@ #define KXTF9_REG_HYST_SET 0x5F #define KXCJK1013_REG_WAKE_THRES 0x6A +/* Everything up to 0x11 is equal to KXCJK1013/KXTF9 above */ +#define KX023_REG_INS1 0x12 +#define KX023_REG_INS2 0x13 +#define KX023_REG_INS3 0x14 +#define KX023_REG_STAT 0x15 +#define KX023_REG_INT_REL 0x17 +#define KX023_REG_CNTL1 0x18 +#define KX023_REG_CNTL2 0x19 +#define KX023_REG_CNTL3 0x1A +#define KX023_REG_ODCNTL 0x1B +#define KX023_REG_INC1 0x1C +#define KX023_REG_INC2 0x1D +#define KX023_REG_INC3 0x1E +#define KX023_REG_INC4 0x1F +#define KX023_REG_INC5 0x20 +#define KX023_REG_INC6 0x21 +#define KX023_REG_TILT_TIMER 0x22 +#define KX023_REG_WUFC 0x23 +#define KX023_REG_TDTRC 0x24 +#define KX023_REG_TDTC 0x25 +#define KX023_REG_TTH 0x26 +#define KX023_REG_TTL 0x27 +#define KX023_REG_FTD 0x28 +#define KX023_REG_STD 0x29 +#define KX023_REG_TLT 0x2A +#define KX023_REG_TWS 0x2B +#define KX023_REG_ATH 0x30 +#define KX023_REG_TILT_ANGLE_LL 0x32 +#define KX023_REG_TILT_ANGLE_HL 0x33 +#define KX023_REG_HYST_SET 0x34 +#define KX023_REG_LP_CNTL 0x35 +#define KX023_REG_BUF_CNTL1 0x3A +#define KX023_REG_BUF_CNTL2 0x3B +#define KX023_REG_BUF_STATUS_1 0x3C +#define KX023_REG_BUF_STATUS_2 0x3D +#define KX023_REG_BUF_CLEAR 0x3E +#define KX023_REG_BUF_READ 0x3F +#define KX023_REG_SELF_TEST 0x60 + #define KXCJK1013_REG_CTRL1_BIT_PC1 BIT(7) #define KXCJK1013_REG_CTRL1_BIT_RES BIT(6) #define KXCJK1013_REG_CTRL1_BIT_DRDY BIT(5) @@ -119,6 +158,14 @@ #define KXCJK1013_REG_INT_SRC2_BIT_XP BIT(4) #define KXCJK1013_REG_INT_SRC2_BIT_XN BIT(5) +/* KX023 interrupt routing to INT1. INT2 can be configured with INC6 */ +#define KX023_REG_INC4_BFI1 BIT(6) +#define KX023_REG_INC4_WMI1 BIT(5) +#define KX023_REG_INC4_DRDY1 BIT(4) +#define KX023_REG_INC4_TDTI1 BIT(2) +#define KX023_REG_INC4_WUFI1 BIT(1) +#define KX023_REG_INC4_TPI1 BIT(0) + #define KXCJK1013_DEFAULT_WAKE_THRES 1 enum kx_chipset { @@ -126,6 +173,7 @@ enum kx_chipset { KXCJ91008, KXTJ21009, KXTF9, + KX0231025, KX_MAX_CHIPS /* this must be last */ }; @@ -172,6 +220,19 @@ static const struct kx_chipset_regs kxtf9_regs = { .wake_thres = KXTF9_REG_WAKE_THRESH, }; +/* The registers have totally different names but the bits are compatible */ +static const struct kx_chipset_regs kx0231025_regs = { + .int_src1 = KX023_REG_INS2, + .int_src2 = KX023_REG_INS3, + .int_rel = KX023_REG_INT_REL, + .ctrl1 = KX023_REG_CNTL1, + .wuf_ctrl = KX023_REG_CNTL3, + .int_ctrl1 = KX023_REG_INC1, + .data_ctrl = KX023_REG_ODCNTL, + .wake_timer = KX023_REG_WUFC, + .wake_thres = KX023_REG_ATH, +}; + struct kxcjk1013_data { struct regulator_bulk_data regulators[2]; struct i2c_client *client; @@ -308,6 +369,22 @@ static const struct { {0x05, 5100}, {0x06, 2700}, }, + /* KX023-1025 */ + { + /* First 4 are not in datasheet, taken from KXCTJ2-1009 */ + {0x08, 1240000}, + {0x09, 621000}, + {0x0A, 309000}, + {0x0B, 151000}, + {0, 81000}, + {0x01, 40000}, + {0x02, 22000}, + {0x03, 12000}, + {0x04, 7000}, + {0x05, 4400}, + {0x06, 3000}, + {0x07, 3000}, + }, }; static const struct { @@ -483,6 +560,17 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) return ret; } + /* On KX023, route all used interrupts to INT1 for now */ + if (data->chipset == KX0231025 && data->client->irq > 0) { + ret = i2c_smbus_write_byte_data(data->client, KX023_REG_INC4, + KX023_REG_INC4_DRDY1 | + KX023_REG_INC4_WUFI1); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_inc4\n"); + return ret; + } + } + ret = kxcjk1013_set_mode(data, OPERATION); if (ret < 0) return ret; @@ -1414,6 +1502,9 @@ static int kxcjk1013_probe(struct i2c_client *client, case KXTF9: data->regs = &kxtf9_regs; break; + case KX0231025: + data->regs = &kx0231025_regs; + break; default: return -EINVAL; } @@ -1633,6 +1724,7 @@ static const struct i2c_device_id kxcjk1013_id[] = { {"kxcj91008", KXCJ91008}, {"kxtj21009", KXTJ21009}, {"kxtf9", KXTF9}, + {"kx023-1025", KX0231025}, {"SMO8500", KXCJ91008}, {} }; @@ -1644,6 +1736,7 @@ static const struct of_device_id kxcjk1013_of_match[] = { { .compatible = "kionix,kxcj91008", }, { .compatible = "kionix,kxtj21009", }, { .compatible = "kionix,kxtf9", }, + { .compatible = "kionix,kx023-1025", }, { } }; MODULE_DEVICE_TABLE(of, kxcjk1013_of_match); -- cgit v1.2.3 From 41120ebbb1eb5e9dec93320e259d5b2c93226073 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 May 2021 12:33:27 +0100 Subject: iio: gyro: fxa21002c: Balance runtime pm + use pm_runtime_resume_and_get(). In both the probe() error path and remove() pm_runtime_put_noidle() is called which will decrement the runtime pm reference count. However, there is no matching function to have raised the reference count. Not this isn't a fix as the runtime pm core will stop the reference count going negative anyway. An alternative would have been to raise the count in these paths, but it is not clear why that would be necessary. Whilst we are here replace some boilerplate with pm_runtime_resume_and_get() Found using coccicheck script under review at: https://lore.kernel.org/lkml/20210427141946.2478411-1-Julia.Lawall@inria.fr/ Signed-off-by: Jonathan Cameron Reviewed-by: Rui Miguel Silva Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210509113354.660190-2-jic23@kernel.org --- drivers/iio/gyro/fxas21002c_core.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/gyro/fxas21002c_core.c b/drivers/iio/gyro/fxas21002c_core.c index 5af7b48ff01a..539585b0d300 100644 --- a/drivers/iio/gyro/fxas21002c_core.c +++ b/drivers/iio/gyro/fxas21002c_core.c @@ -366,14 +366,7 @@ out_unlock: static int fxas21002c_pm_get(struct fxas21002c_data *data) { - struct device *dev = regmap_get_device(data->regmap); - int ret; - - ret = pm_runtime_get_sync(dev); - if (ret < 0) - pm_runtime_put_noidle(dev); - - return ret; + return pm_runtime_resume_and_get(regmap_get_device(data->regmap)); } static int fxas21002c_pm_put(struct fxas21002c_data *data) @@ -1002,7 +995,6 @@ int fxas21002c_core_probe(struct device *dev, struct regmap *regmap, int irq, pm_disable: pm_runtime_disable(dev); pm_runtime_set_suspended(dev); - pm_runtime_put_noidle(dev); return ret; } @@ -1016,7 +1008,6 @@ void fxas21002c_core_remove(struct device *dev) pm_runtime_disable(dev); pm_runtime_set_suspended(dev); - pm_runtime_put_noidle(dev); } EXPORT_SYMBOL_GPL(fxas21002c_core_remove); -- cgit v1.2.3 From a2fa3debc12e4a401a4c6febc1804036a62f1e31 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 May 2021 12:33:28 +0100 Subject: iio: light: isl29028: Balance runtime pm + use pm_runtime_resume_and_get() In remove this driver called pm_runtime_put_noidle() but there is no matching get operation. This does not cause any problems because the reference counter will not change if already zero, but it does make the code harder to reason about so should be dropped. Whilst we are here, use pm_runtime_resume_and_get() to replace open coded version. Found using coccicheck script under review at: https://lore.kernel.org/lkml/20210427141946.2478411-1-Julia.Lawall@inria.fr/ Signed-off-by: Jonathan Cameron Cc: Sebastian Reichel Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210509113354.660190-3-jic23@kernel.org --- drivers/iio/light/isl29028.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/light/isl29028.c b/drivers/iio/light/isl29028.c index 2f8b494f3e08..9de3262aa688 100644 --- a/drivers/iio/light/isl29028.c +++ b/drivers/iio/light/isl29028.c @@ -339,9 +339,7 @@ static int isl29028_set_pm_runtime_busy(struct isl29028_chip *chip, bool on) int ret; if (on) { - ret = pm_runtime_get_sync(dev); - if (ret < 0) - pm_runtime_put_noidle(dev); + ret = pm_runtime_resume_and_get(dev); } else { pm_runtime_mark_last_busy(dev); ret = pm_runtime_put_autosuspend(dev); @@ -647,7 +645,6 @@ static int isl29028_remove(struct i2c_client *client) pm_runtime_disable(&client->dev); pm_runtime_set_suspended(&client->dev); - pm_runtime_put_noidle(&client->dev); return isl29028_clear_configure_reg(chip); } -- cgit v1.2.3 From 6fbaebae758dd68c6bda22164e61038eb72ce036 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 May 2021 12:33:29 +0100 Subject: iio: light: tsl2583: Balance runtime pm + use pm_runtime_resume_and_get() Error paths in read_raw() and write_raw() callbacks failed to perform and type of runtime pm put(). Remove called pm_runtime_put_noidle() but there is no equivalent get (this is safe because the reference count is protected against going below zero, but it is misleading. Whilst here use pm_runtime_resume_and_get() to replace boilerplate. Signed-off-by: Jonathan Cameron Cc: Brian Masney Reviewed-by: Brian Masney Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210509113354.660190-4-jic23@kernel.org --- drivers/iio/light/tsl2583.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/light/tsl2583.c b/drivers/iio/light/tsl2583.c index c9d8f07a6fcd..7e101d5f72ee 100644 --- a/drivers/iio/light/tsl2583.c +++ b/drivers/iio/light/tsl2583.c @@ -644,9 +644,7 @@ static int tsl2583_set_pm_runtime_busy(struct tsl2583_chip *chip, bool on) int ret; if (on) { - ret = pm_runtime_get_sync(&chip->client->dev); - if (ret < 0) - pm_runtime_put_noidle(&chip->client->dev); + ret = pm_runtime_resume_and_get(&chip->client->dev); } else { pm_runtime_mark_last_busy(&chip->client->dev); ret = pm_runtime_put_autosuspend(&chip->client->dev); @@ -729,8 +727,10 @@ static int tsl2583_read_raw(struct iio_dev *indio_dev, read_done: mutex_unlock(&chip->als_mutex); - if (ret < 0) + if (ret < 0) { + tsl2583_set_pm_runtime_busy(chip, false); return ret; + } /* * Preserve the ret variable if the call to @@ -791,8 +791,10 @@ static int tsl2583_write_raw(struct iio_dev *indio_dev, mutex_unlock(&chip->als_mutex); - if (ret < 0) + if (ret < 0) { + tsl2583_set_pm_runtime_busy(chip, false); return ret; + } ret = tsl2583_set_pm_runtime_busy(chip, false); if (ret < 0) @@ -880,7 +882,6 @@ static int tsl2583_remove(struct i2c_client *client) pm_runtime_disable(&client->dev); pm_runtime_set_suspended(&client->dev); - pm_runtime_put_noidle(&client->dev); return tsl2583_set_power_state(chip, TSL2583_CNTL_PWR_OFF); } -- cgit v1.2.3 From d3a8969dde088fed979d0c7bebc33752c719d30c Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 May 2021 12:33:30 +0100 Subject: iio: accel: bmc150-accel: Balanced runtime pm + use pm_runtime_resume_and_get() A call to pm_runtime_put_noidle() doesn't match any call that would result in a get(). It is safe because runtime pm core protects against the reference counter going 0, but it makes it harder to understand the code. Whilst here use pm_runtime_resume_and_get() to tidy things up. The Coccinelle script didn't get this one due to more complex code structure. Signed-off-by: Jonathan Cameron Cc: Hans de Goede Reviewed-by: Hans de Goede Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210509113354.660190-5-jic23@kernel.org --- drivers/iio/accel/bmc150-accel-core.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index 62a164a7b852..43cfadf8f6b7 100644 --- a/drivers/iio/accel/bmc150-accel-core.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -389,7 +389,7 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) int ret; if (on) { - ret = pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); } else { pm_runtime_mark_last_busy(dev); ret = pm_runtime_put_autosuspend(dev); @@ -398,9 +398,6 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) if (ret < 0) { dev_err(dev, "Failed: %s for %d\n", __func__, on); - if (on) - pm_runtime_put_noidle(dev); - return ret; } @@ -1836,7 +1833,6 @@ int bmc150_accel_core_remove(struct device *dev) pm_runtime_disable(dev); pm_runtime_set_suspended(dev); - pm_runtime_put_noidle(dev); bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1); -- cgit v1.2.3 From 2d980d7efd5fdac70505a5b82cfaef411fa72393 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 May 2021 12:33:32 +0100 Subject: iio: accel: mma9551/3: Balance untime pm + use pm_runtime_resume_and_get() Both these drivers call pm_runtime_put_no_idle() when the reference count should already be zero as there is no matching get() Whilst here use pm_runtime_resume_and_get() rather than open coding. Signed-off-by: Jonathan Cameron Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210509113354.660190-7-jic23@kernel.org --- drivers/iio/accel/mma9551.c | 1 - drivers/iio/accel/mma9551_core.c | 4 +--- drivers/iio/accel/mma9553.c | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c index 08a2303cc9df..4c359fb05480 100644 --- a/drivers/iio/accel/mma9551.c +++ b/drivers/iio/accel/mma9551.c @@ -515,7 +515,6 @@ static int mma9551_remove(struct i2c_client *client) pm_runtime_disable(&client->dev); pm_runtime_set_suspended(&client->dev); - pm_runtime_put_noidle(&client->dev); mutex_lock(&data->mutex); mma9551_set_device_state(data->client, false); diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c index 666e7a04a7d7..fbf2e2c45678 100644 --- a/drivers/iio/accel/mma9551_core.c +++ b/drivers/iio/accel/mma9551_core.c @@ -664,7 +664,7 @@ int mma9551_set_power_state(struct i2c_client *client, bool on) int ret; if (on) - ret = pm_runtime_get_sync(&client->dev); + ret = pm_runtime_resume_and_get(&client->dev); else { pm_runtime_mark_last_busy(&client->dev); ret = pm_runtime_put_autosuspend(&client->dev); @@ -673,8 +673,6 @@ int mma9551_set_power_state(struct i2c_client *client, bool on) if (ret < 0) { dev_err(&client->dev, "failed to change power state to %d\n", on); - if (on) - pm_runtime_put_noidle(&client->dev); return ret; } diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index c15908faa381..ba3ecb3b57dc 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -1154,7 +1154,6 @@ static int mma9553_remove(struct i2c_client *client) pm_runtime_disable(&client->dev); pm_runtime_set_suspended(&client->dev); - pm_runtime_put_noidle(&client->dev); mutex_lock(&data->mutex); mma9551_set_device_state(data->client, false); -- cgit v1.2.3 From 19611aec50aed607fe161e8a2b8f40df9d97df60 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 May 2021 12:33:33 +0100 Subject: iio: accel: kxcjk-1013: Balance runtime pm + use pm_runtime_resume_and_get() This driver alls pm_runtime_put_noidle() in it's remove function, but there is no matching get call. This isn't a bug as runtime pm will not allow the reference counter to go negative, but it is missleading so lets remove it. Whilst here use pm_runtime_resume_and_get() to tidy up some boilerplate. The coccicheck script didn't get this one due to the less obvious structure. Found by inspection. Signed-off-by: Jonathan Cameron Cc: Hans de Goede Reviewed-by: Hans de Goede Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210509113354.660190-8-jic23@kernel.org --- drivers/iio/accel/kxcjk-1013.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 18a96828f6be..961803296abc 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -601,7 +601,7 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on) int ret; if (on) - ret = pm_runtime_get_sync(&data->client->dev); + ret = pm_runtime_resume_and_get(&data->client->dev); else { pm_runtime_mark_last_busy(&data->client->dev); ret = pm_runtime_put_autosuspend(&data->client->dev); @@ -609,8 +609,6 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on) if (ret < 0) { dev_err(&data->client->dev, "Failed: %s for %d\n", __func__, on); - if (on) - pm_runtime_put_noidle(&data->client->dev); return ret; } #endif @@ -1616,7 +1614,6 @@ static int kxcjk1013_remove(struct i2c_client *client) pm_runtime_disable(&client->dev); pm_runtime_set_suspended(&client->dev); - pm_runtime_put_noidle(&client->dev); if (data->dready_trig) { iio_triggered_buffer_cleanup(indio_dev); -- cgit v1.2.3 From 2d082b6ed26472342beb23ec275c8531afb502b2 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 May 2021 12:33:35 +0100 Subject: iio: imu: kmx61: Balance runtime pm + use pm_runtime_resume_and_get() No point in calling pm_runtime_put_noidle() that isn't balancing a get. Note no actual impact because the runtime pm core protects against a negative reference counter. For the pm_runtime_resume_and_get() main interest is in clearing out this old pattern to avoid it getting coppied into new submissions. Signed-off-by: Jonathan Cameron Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210509113354.660190-10-jic23@kernel.org --- drivers/iio/imu/kmx61.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index d3e06ce99c1e..1dabfd615dab 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -750,7 +750,7 @@ static int kmx61_set_power_state(struct kmx61_data *data, bool on, u8 device) } if (on) { - ret = pm_runtime_get_sync(&data->client->dev); + ret = pm_runtime_resume_and_get(&data->client->dev); } else { pm_runtime_mark_last_busy(&data->client->dev); ret = pm_runtime_put_autosuspend(&data->client->dev); @@ -759,8 +759,6 @@ static int kmx61_set_power_state(struct kmx61_data *data, bool on, u8 device) dev_err(&data->client->dev, "Failed: kmx61_set_power_state for %d, ret %d\n", on, ret); - if (on) - pm_runtime_put_noidle(&data->client->dev); return ret; } @@ -1426,7 +1424,6 @@ static int kmx61_remove(struct i2c_client *client) pm_runtime_disable(&client->dev); pm_runtime_set_suspended(&client->dev); - pm_runtime_put_noidle(&client->dev); if (client->irq > 0) { iio_triggered_buffer_cleanup(data->acc_indio_dev); -- cgit v1.2.3 From 265028b8d989a47e9ef996e3dc178eb63127661f Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 May 2021 12:33:40 +0100 Subject: iio: adc: stm32-adc: Use pm_runtime_resume_and_get() to replace open coding. Found using coccicheck script under review at: https://lore.kernel.org/lkml/20210427141946.2478411-1-Julia.Lawall@inria.fr/ This is a prequel to taking a closer look at the runtime pm in IIO drivers in general. Signed-off-by: Jonathan Cameron Cc: Fabrice Gasnier Reviewed-by: Fabrice Gasnier Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210509113354.660190-15-jic23@kernel.org --- drivers/iio/adc/stm32-adc.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index c9d36c88ee6a..5088de835bb1 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -1158,11 +1158,9 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, adc->bufi = 0; - ret = pm_runtime_get_sync(dev); - if (ret < 0) { - pm_runtime_put_noidle(dev); + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) return ret; - } /* Apply sampling time settings */ stm32_adc_writel(adc, regs->smpr[0], adc->smpr_val[0]); @@ -1364,11 +1362,9 @@ static int stm32_adc_update_scan_mode(struct iio_dev *indio_dev, struct device *dev = indio_dev->dev.parent; int ret; - ret = pm_runtime_get_sync(dev); - if (ret < 0) { - pm_runtime_put_noidle(dev); + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) return ret; - } adc->num_conv = bitmap_weight(scan_mask, indio_dev->masklength); @@ -1413,11 +1409,9 @@ static int stm32_adc_debugfs_reg_access(struct iio_dev *indio_dev, struct device *dev = indio_dev->dev.parent; int ret; - ret = pm_runtime_get_sync(dev); - if (ret < 0) { - pm_runtime_put_noidle(dev); + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) return ret; - } if (!readval) stm32_adc_writel(adc, reg, writeval); @@ -1537,11 +1531,9 @@ static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev) struct device *dev = indio_dev->dev.parent; int ret; - ret = pm_runtime_get_sync(dev); - if (ret < 0) { - pm_runtime_put_noidle(dev); + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) return ret; - } ret = stm32_adc_set_trig(indio_dev, indio_dev->trig); if (ret) { -- cgit v1.2.3 From 29534eb2e242b4ecac1aa7229bbe92aa7e379945 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 May 2021 12:33:41 +0100 Subject: iio: adc: stm32-dfsdm: Use pm_runtime_resume_and_get() to replace open coding. Found using coccicheck script under review at: https://lore.kernel.org/lkml/20210427141946.2478411-1-Julia.Lawall@inria.fr/ This is a prequel to taking a closer look at the runtime pm in IIO drivers in general. Signed-off-by: Jonathan Cameron Cc: Fabrice Gasnier Reviewed-by: Fabrice Gasnier Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210509113354.660190-16-jic23@kernel.org --- drivers/iio/adc/stm32-dfsdm-core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c index bb925a11c8ae..a627af9a825e 100644 --- a/drivers/iio/adc/stm32-dfsdm-core.c +++ b/drivers/iio/adc/stm32-dfsdm-core.c @@ -135,11 +135,9 @@ int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm) int ret; if (atomic_inc_return(&priv->n_active_ch) == 1) { - ret = pm_runtime_get_sync(dev); - if (ret < 0) { - pm_runtime_put_noidle(dev); + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) goto error_ret; - } /* select clock source, e.g. 0 for "dfsdm" or 1 for "audio" */ clk_src = priv->aclk ? 1 : 0; -- cgit v1.2.3 From 54e81f6818b899ef621b2d513014da004add8845 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 May 2021 12:33:42 +0100 Subject: iio: dac: stm32-dac: Use pm_runtime_resume_and_get() to replace open coding. Found using coccicheck script under review at: https://lore.kernel.org/lkml/20210427141946.2478411-1-Julia.Lawall@inria.fr/ This is a prequel to taking a closer look at the runtime pm in IIO drivers in general Signed-off-by: Jonathan Cameron Cc: Fabrice Gasnier Reviewed-by: Fabrice Gasnier Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210509113354.660190-17-jic23@kernel.org --- drivers/iio/dac/stm32-dac.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c index a5b0a52bf86e..dd2e306824e7 100644 --- a/drivers/iio/dac/stm32-dac.c +++ b/drivers/iio/dac/stm32-dac.c @@ -69,9 +69,8 @@ static int stm32_dac_set_enable_state(struct iio_dev *indio_dev, int ch, } if (enable) { - ret = pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); if (ret < 0) { - pm_runtime_put_noidle(dev); mutex_unlock(&dac->lock); return ret; } -- cgit v1.2.3 From 6e4183ec8dfdbce1a48a82d8b8d5648c98d5bfd8 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 May 2021 12:33:46 +0100 Subject: iio: light: us5182: Use pm_runtime_resume_and_get() to replace open coding. Found using coccicheck script under review at: https://lore.kernel.org/lkml/20210427141946.2478411-1-Julia.Lawall@inria.fr/ This is a prequel to taking a closer look at the runtime pm in IIO drivers in general. Signed-off-by: Jonathan Cameron Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210509113354.660190-21-jic23@kernel.org --- drivers/iio/light/us5182d.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c index 393f27b75c75..96e4a66ddf28 100644 --- a/drivers/iio/light/us5182d.c +++ b/drivers/iio/light/us5182d.c @@ -367,9 +367,7 @@ static int us5182d_set_power_state(struct us5182d_data *data, bool on) return 0; if (on) { - ret = pm_runtime_get_sync(&data->client->dev); - if (ret < 0) - pm_runtime_put_noidle(&data->client->dev); + ret = pm_runtime_resume_and_get(&data->client->dev); } else { pm_runtime_mark_last_busy(&data->client->dev); ret = pm_runtime_put_autosuspend(&data->client->dev); -- cgit v1.2.3 From 66e748ae7f82301af3b2c2bd0b3bd46d01fd7471 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 May 2021 12:33:50 +0100 Subject: iio: temp: mlx90614: Handle failure in pm_runtime_resume_and_get() Converts from using pm_runtime_get_sync() with no error handling over to pm_runtime_resume_and_get() which will ensure we don't end up holding a reference. Ensure this error return is then handled at calls to mlx90614_power_get(). These are all direct returns. Signed-off-by: Jonathan Cameron Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210509113354.660190-25-jic23@kernel.org --- drivers/iio/temperature/mlx90614.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c index ef0fec94d269..afcb10ea7c44 100644 --- a/drivers/iio/temperature/mlx90614.c +++ b/drivers/iio/temperature/mlx90614.c @@ -176,11 +176,14 @@ static inline s32 mlx90614_iir_search(const struct i2c_client *client, static int mlx90614_power_get(struct mlx90614_data *data, bool startup) { unsigned long now; + int ret; if (!data->wakeup_gpio) return 0; - pm_runtime_get_sync(&data->client->dev); + ret = pm_runtime_resume_and_get(&data->client->dev); + if (ret < 0) + return ret; if (startup) { now = jiffies; @@ -267,7 +270,10 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev, *val = MLX90614_CONST_SCALE; return IIO_VAL_INT; case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/65535 / LSB */ - mlx90614_power_get(data, false); + ret = mlx90614_power_get(data, false); + if (ret < 0) + return ret; + mutex_lock(&data->lock); ret = i2c_smbus_read_word_data(data->client, MLX90614_EMISSIVITY); @@ -287,7 +293,10 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT_PLUS_NANO; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: /* IIR setting with FIR = 1024 */ - mlx90614_power_get(data, false); + ret = mlx90614_power_get(data, false); + if (ret < 0) + return ret; + mutex_lock(&data->lock); ret = i2c_smbus_read_word_data(data->client, MLX90614_CONFIG); mutex_unlock(&data->lock); @@ -319,7 +328,10 @@ static int mlx90614_write_raw(struct iio_dev *indio_dev, val = val * MLX90614_CONST_RAW_EMISSIVITY_MAX + val2 / MLX90614_CONST_EMISSIVITY_RESOLUTION; - mlx90614_power_get(data, false); + ret = mlx90614_power_get(data, false); + if (ret < 0) + return ret; + mutex_lock(&data->lock); ret = mlx90614_write_word(data->client, MLX90614_EMISSIVITY, val); @@ -331,7 +343,10 @@ static int mlx90614_write_raw(struct iio_dev *indio_dev, if (val < 0 || val2 < 0) return -EINVAL; - mlx90614_power_get(data, false); + ret = mlx90614_power_get(data, false); + if (ret < 0) + return ret; + mutex_lock(&data->lock); ret = mlx90614_iir_search(data->client, val * 100 + val2 / 10000); -- cgit v1.2.3 From db9c6c2ec4a8789e2445d4a861dfce6d66b10df9 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 May 2021 12:33:54 +0100 Subject: iio: adc: rcar-gyroadc: Use pm_runtime_resume_and_get() and check in probe() 1 instance found using coccicheck script under review at: https://lore.kernel.org/lkml/20210427141946.2478411-1-Julia.Lawall@inria.fr/ The other instance changed did not check for failure of the pm_runtime_get_sync() so that is added. Note the remaining pm_runtime_get_sync() call is left alone because it is not obvious what to do on failure to power up in remove() This is a prequel to taking a closer look at the runtime pm in IIO drivers in general. Signed-off-by: Jonathan Cameron Cc: Marek Vasut Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210509113354.660190-29-jic23@kernel.org --- drivers/iio/adc/rcar-gyroadc.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c index 9f38cf3c7dc2..a48895046408 100644 --- a/drivers/iio/adc/rcar-gyroadc.c +++ b/drivers/iio/adc/rcar-gyroadc.c @@ -162,18 +162,13 @@ static const struct iio_chan_spec rcar_gyroadc_iio_channels_3[] = { static int rcar_gyroadc_set_power(struct rcar_gyroadc *priv, bool on) { struct device *dev = priv->dev; - int ret; if (on) { - ret = pm_runtime_get_sync(dev); - if (ret < 0) - pm_runtime_put_noidle(dev); + return pm_runtime_resume_and_get(dev); } else { pm_runtime_mark_last_busy(dev); - ret = pm_runtime_put_autosuspend(dev); + return pm_runtime_put_autosuspend(dev); } - - return ret; } static int rcar_gyroadc_read_raw(struct iio_dev *indio_dev, @@ -535,7 +530,10 @@ static int rcar_gyroadc_probe(struct platform_device *pdev) pm_runtime_use_autosuspend(dev); pm_runtime_enable(dev); - pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); + if (ret) + goto err_power_up; + rcar_gyroadc_hw_init(priv); rcar_gyroadc_hw_start(priv); @@ -552,6 +550,7 @@ static int rcar_gyroadc_probe(struct platform_device *pdev) err_iio_device_register: rcar_gyroadc_hw_stop(priv); pm_runtime_put_sync(dev); +err_power_up: pm_runtime_disable(dev); pm_runtime_set_suspended(dev); clk_disable_unprepare(priv->clk); -- cgit v1.2.3 From 9009a732a87fd6598a5791e0cc4fd2f7d2d602c5 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 May 2021 12:33:51 +0100 Subject: iio: proximity: srf04: Use pm_runtime_resume_and_get() and handle error Previously this driver used pm_runtime_sync_get() and did not handle any errors that occurred. Moving to the new pm_runtime_resume_and_get() + handle errors. Signed-off-by: Jonathan Cameron Cc: Andreas Klinger Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210509113354.660190-26-jic23@kernel.org --- drivers/iio/proximity/srf04.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/proximity/srf04.c b/drivers/iio/proximity/srf04.c index 420c37c72de4..fe88b2bb60bc 100644 --- a/drivers/iio/proximity/srf04.c +++ b/drivers/iio/proximity/srf04.c @@ -100,9 +100,11 @@ static int srf04_read(struct srf04_data *data) u64 dt_ns; u32 time_ns, distance_mm; - if (data->gpiod_power) - pm_runtime_get_sync(data->dev); - + if (data->gpiod_power) { + ret = pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return ret; + } /* * just one read-echo-cycle can take place at a time * ==> lock against concurrent reading calls -- cgit v1.2.3 From db27fdb33d10b582371f2be294d2b6b2ca501043 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 May 2021 12:33:47 +0100 Subject: iio: light: vcnl4000: Use pm_runtime_resume_and_get() to replace open coding. Found using coccicheck script under review at: https://lore.kernel.org/lkml/20210427141946.2478411-1-Julia.Lawall@inria.fr/ This is a prequel to taking a closer look at the runtime pm in IIO drivers in general. Signed-off-by: Jonathan Cameron Cc: Mathieu Othacehe Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210509113354.660190-22-jic23@kernel.org --- drivers/iio/light/vcnl4000.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index 4a61865d01cd..01772327a947 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -413,9 +413,7 @@ static int vcnl4000_set_pm_runtime_state(struct vcnl4000_data *data, bool on) int ret; if (on) { - ret = pm_runtime_get_sync(dev); - if (ret < 0) - pm_runtime_put_noidle(dev); + ret = pm_runtime_resume_and_get(dev); } else { pm_runtime_mark_last_busy(dev); ret = pm_runtime_put_autosuspend(dev); -- cgit v1.2.3 From f30172723ce270d6d60ac03748a6cbacc35b8f84 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 May 2021 12:33:48 +0100 Subject: iio: light: vcnl4035: Use pm_runtime_resume_and_get() to replace open coding. Found using coccicheck script under review at: https://lore.kernel.org/lkml/20210427141946.2478411-1-Julia.Lawall@inria.fr/ This is a prequel to taking a closer look at the runtime pm in IIO drivers in general. Signed-off-by: Jonathan Cameron Cc: Parthiban Nallathambi Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210509113354.660190-23-jic23@kernel.org --- drivers/iio/light/vcnl4035.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c index 691a54b763e1..fd2f181b16db 100644 --- a/drivers/iio/light/vcnl4035.c +++ b/drivers/iio/light/vcnl4035.c @@ -144,9 +144,7 @@ static int vcnl4035_set_pm_runtime_state(struct vcnl4035_data *data, bool on) struct device *dev = &data->client->dev; if (on) { - ret = pm_runtime_get_sync(dev); - if (ret < 0) - pm_runtime_put_noidle(dev); + ret = pm_runtime_resume_and_get(dev); } else { pm_runtime_mark_last_busy(dev); ret = pm_runtime_put_autosuspend(dev); -- cgit v1.2.3 From 9a20795c60276e66f57ee7ecf88d124b1f769fcf Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 May 2021 12:33:38 +0100 Subject: iio: accel: bmi088: Balance runtime pm + use pm_runtime_resume_and_get() The call to pm_runtime_put_noidle() in remove() is not balanced by a get so drop it. Using pm_runtime_resume_and_get() allows for simple introduction of error handling to allow for runtime resume failing. Signed-off-by: Jonathan Cameron Cc: Mike Looijmans Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210509113354.660190-13-jic23@kernel.org --- drivers/iio/accel/bmi088-accel-core.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/bmi088-accel-core.c b/drivers/iio/accel/bmi088-accel-core.c index 61aaaf48c040..a06dae5c971d 100644 --- a/drivers/iio/accel/bmi088-accel-core.c +++ b/drivers/iio/accel/bmi088-accel-core.c @@ -285,11 +285,17 @@ static int bmi088_accel_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_RAW: switch (chan->type) { case IIO_TEMP: - pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + ret = bmi088_accel_get_temp(data, val); goto out_read_raw_pm_put; case IIO_ACCEL: - pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + ret = iio_device_claim_direct_mode(indio_dev); if (ret) goto out_read_raw_pm_put; @@ -319,7 +325,10 @@ static int bmi088_accel_read_raw(struct iio_dev *indio_dev, *val = BMI088_ACCEL_TEMP_UNIT; return IIO_VAL_INT; case IIO_ACCEL: - pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + ret = regmap_read(data->regmap, BMI088_ACCEL_REG_ACC_RANGE, val); if (ret) @@ -334,7 +343,10 @@ static int bmi088_accel_read_raw(struct iio_dev *indio_dev, return -EINVAL; } case IIO_CHAN_INFO_SAMP_FREQ: - pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + ret = bmi088_accel_get_sample_freq(data, val, val2); goto out_read_raw_pm_put; default: @@ -376,7 +388,10 @@ static int bmi088_accel_write_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: - pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + ret = bmi088_accel_set_sample_freq(data, val); pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); @@ -530,7 +545,6 @@ int bmi088_accel_core_remove(struct device *dev) pm_runtime_disable(dev); pm_runtime_set_suspended(dev); - pm_runtime_put_noidle(dev); bmi088_accel_power_down(data); return 0; -- cgit v1.2.3 From 264da512431495e542fcaf56ffe75e7df0e7db74 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 May 2021 12:33:37 +0100 Subject: iio: magn: bmc150: Balance runtime pm + use pm_runtime_resume_and_get() probe() error paths after runtime pm is enabled, should disable it. remove() should not call pm_runtime_put_noidle() as there is no matching get() to have raised the reference count. This case has no affect a the runtime pm core protects against going negative. Whilst here use pm_runtime_resume_and_get() to tidy things up a little. coccicheck script didn't get this one due to complex code structure so found by inspection. Signed-off-by: Jonathan Cameron Cc: Linus Walleij Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210509113354.660190-12-jic23@kernel.org --- drivers/iio/magnetometer/bmc150_magn.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index d75b437a43f2..39920cb764bf 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -262,7 +262,7 @@ static int bmc150_magn_set_power_state(struct bmc150_magn_data *data, bool on) int ret; if (on) { - ret = pm_runtime_get_sync(data->dev); + ret = pm_runtime_resume_and_get(data->dev); } else { pm_runtime_mark_last_busy(data->dev); ret = pm_runtime_put_autosuspend(data->dev); @@ -271,9 +271,6 @@ static int bmc150_magn_set_power_state(struct bmc150_magn_data *data, bool on) if (ret < 0) { dev_err(data->dev, "failed to change power state to %d\n", on); - if (on) - pm_runtime_put_noidle(data->dev); - return ret; } #endif @@ -963,12 +960,14 @@ int bmc150_magn_probe(struct device *dev, struct regmap *regmap, ret = iio_device_register(indio_dev); if (ret < 0) { dev_err(dev, "unable to register iio device\n"); - goto err_buffer_cleanup; + goto err_disable_runtime_pm; } dev_dbg(dev, "Registered device %s\n", name); return 0; +err_disable_runtime_pm: + pm_runtime_disable(dev); err_buffer_cleanup: iio_triggered_buffer_cleanup(indio_dev); err_free_irq: @@ -992,7 +991,6 @@ int bmc150_magn_remove(struct device *dev) pm_runtime_disable(dev); pm_runtime_set_suspended(dev); - pm_runtime_put_noidle(dev); iio_triggered_buffer_cleanup(indio_dev); -- cgit v1.2.3 From 934616e8ebe162d93b82aef44d154b6b0d200dc1 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 May 2021 12:33:36 +0100 Subject: iio: light: rpr0521: Balance runtime pm + use pm_runtime_resume_and_get() Calls to pm_runtime_put_noidle in probe() error path and remove() are not match to any get() calls. The runtime pm core protects against negative reference counts, so this doesn't have any visible impact beyond confusing the reader. Whilst here use pm_runtime_resume_and_get() to replace boilerplate. Signed-off-by: Jonathan Cameron Cc: Mikko Koivunen Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210509113354.660190-11-jic23@kernel.org --- drivers/iio/light/rpr0521.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index 7e332de0e6a5..c2dd8a3d4217 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -360,7 +360,7 @@ static int rpr0521_set_power_state(struct rpr0521_data *data, bool on, * both stay enabled until _suspend(). */ if (on) { - ret = pm_runtime_get_sync(&data->client->dev); + ret = pm_runtime_resume_and_get(&data->client->dev); } else { pm_runtime_mark_last_busy(&data->client->dev); ret = pm_runtime_put_autosuspend(&data->client->dev); @@ -369,9 +369,6 @@ static int rpr0521_set_power_state(struct rpr0521_data *data, bool on, dev_err(&data->client->dev, "Failed: rpr0521_set_power_state for %d, ret %d\n", on, ret); - if (on) - pm_runtime_put_noidle(&data->client->dev); - return ret; } @@ -1038,7 +1035,6 @@ static int rpr0521_probe(struct i2c_client *client, err_pm_disable: pm_runtime_disable(&client->dev); pm_runtime_set_suspended(&client->dev); - pm_runtime_put_noidle(&client->dev); err_poweroff: rpr0521_poweroff(data); @@ -1053,7 +1049,6 @@ static int rpr0521_remove(struct i2c_client *client) pm_runtime_disable(&client->dev); pm_runtime_set_suspended(&client->dev); - pm_runtime_put_noidle(&client->dev); rpr0521_poweroff(iio_priv(indio_dev)); -- cgit v1.2.3 From 5937b860e9252637681c49ac097b712839213cce Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 May 2021 12:33:31 +0100 Subject: iio: accel: mma8452: Balance runtime pm + use pm_runtime_resume_and_get() Remove() callback calls pm_runtime_put_noidle() but there it is not balancing a get. No actual affect because the runtime pm core prevents the reference count going negative. Whilst here use pm_runtime_resume_and_get() rather than open coded version. Again, coccinelle script missed this one due to more complex code structure. Signed-off-by: Jonathan Cameron Cc: Sean Nyekjaer Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210509113354.660190-6-jic23@kernel.org --- drivers/iio/accel/mma8452.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 464a6bfe6746..715b8138fb71 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -221,7 +221,7 @@ static int mma8452_set_runtime_pm_state(struct i2c_client *client, bool on) int ret; if (on) { - ret = pm_runtime_get_sync(&client->dev); + ret = pm_runtime_resume_and_get(&client->dev); } else { pm_runtime_mark_last_busy(&client->dev); ret = pm_runtime_put_autosuspend(&client->dev); @@ -230,8 +230,6 @@ static int mma8452_set_runtime_pm_state(struct i2c_client *client, bool on) if (ret < 0) { dev_err(&client->dev, "failed to change power state to %d\n", on); - if (on) - pm_runtime_put_noidle(&client->dev); return ret; } @@ -1711,7 +1709,6 @@ static int mma8452_remove(struct i2c_client *client) pm_runtime_disable(&client->dev); pm_runtime_set_suspended(&client->dev); - pm_runtime_put_noidle(&client->dev); iio_triggered_buffer_cleanup(indio_dev); mma8452_trigger_cleanup(indio_dev); -- cgit v1.2.3 From fc36da3131a747a9367a05caf06de19be1bcc972 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 1 May 2021 18:01:03 +0100 Subject: iio: accel: bma180: Fix buffer alignment in iio_push_to_buffers_with_timestamp() To make code more readable, use a structure to express the channel layout and ensure the timestamp is 8 byte aligned. Found during an audit of all calls of this function. Fixes: b9a6a237ffc9 ("iio:bma180: Drop _update_scan_mode()") Signed-off-by: Jonathan Cameron Cc: Peter Meerwald Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210501170121.512209-2-jic23@kernel.org --- drivers/iio/accel/bma180.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 68d91a70de03..71c76bbd81d4 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -162,7 +162,11 @@ struct bma180_data { int scale; int bw; bool pmode; - u8 buff[16]; /* 3x 16-bit + 8-bit + padding + timestamp */ + /* Ensure timestamp is naturally aligned */ + struct { + s16 chan[4]; + s64 timestamp __aligned(8); + } scan; }; enum bma180_chan { @@ -938,12 +942,12 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p) mutex_unlock(&data->mutex); goto err; } - ((s16 *)data->buff)[i++] = ret; + data->scan.chan[i++] = ret; } mutex_unlock(&data->mutex); - iio_push_to_buffers_with_timestamp(indio_dev, data->buff, time_ns); + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, time_ns); err: iio_trigger_notify_done(indio_dev->trig); -- cgit v1.2.3 From 151dbf0078da98206817ee0b87d499035479ef11 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 1 May 2021 18:01:04 +0100 Subject: iio: accel: bma220: Fix buffer alignment in iio_push_to_buffers_with_timestamp() To make code more readable, use a structure to express the channel layout and ensure the timestamp is 8 byte aligned. Found during an audit of all calls of this function. Fixes: 194dc4c71413 ("iio: accel: Add triggered buffer support for BMA220") Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210501170121.512209-3-jic23@kernel.org --- drivers/iio/accel/bma220_spi.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c index 36fc9876dbca..0622c7936499 100644 --- a/drivers/iio/accel/bma220_spi.c +++ b/drivers/iio/accel/bma220_spi.c @@ -63,7 +63,11 @@ static const int bma220_scale_table[][2] = { struct bma220_data { struct spi_device *spi_device; struct mutex lock; - s8 buffer[16]; /* 3x8-bit channels + 5x8 padding + 8x8 timestamp */ + struct { + s8 chans[3]; + /* Ensure timestamp is naturally aligned. */ + s64 timestamp __aligned(8); + } scan; u8 tx_buf[2] ____cacheline_aligned; }; @@ -94,12 +98,12 @@ static irqreturn_t bma220_trigger_handler(int irq, void *p) mutex_lock(&data->lock); data->tx_buf[0] = BMA220_REG_ACCEL_X | BMA220_READ_MASK; - ret = spi_write_then_read(spi, data->tx_buf, 1, data->buffer, + ret = spi_write_then_read(spi, data->tx_buf, 1, &data->scan.chans, ARRAY_SIZE(bma220_channels) - 1); if (ret < 0) goto err; - iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, pf->timestamp); err: mutex_unlock(&data->lock); -- cgit v1.2.3 From c6559bf796ccdb3a0c79db846af96c8f7046880b Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 1 May 2021 18:01:05 +0100 Subject: iio: accel: hid: Fix buffer alignment in iio_push_to_buffers_with_timestamp() To make code more readable, use a structure to express the channel layout and ensure the timestamp is 8 byte aligned. Note this matches what was done in all the other hid sensor drivers. This one was missed previously due to an extra level of indirection. Found during an audit of all calls of this function. Fixes: a96cd0f901ee ("iio: accel: hid-sensor-accel-3d: Add timestamp") Signed-off-by: Jonathan Cameron Cc: Srinivas Pandruvada Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210501170121.512209-4-jic23@kernel.org --- drivers/iio/accel/hid-sensor-accel-3d.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index 2f9465cb382f..27f47e1c251e 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -28,8 +28,11 @@ struct accel_3d_state { struct hid_sensor_hub_callbacks callbacks; struct hid_sensor_common common_attributes; struct hid_sensor_hub_attribute_info accel[ACCEL_3D_CHANNEL_MAX]; - /* Reserve for 3 channels + padding + timestamp */ - u32 accel_val[ACCEL_3D_CHANNEL_MAX + 3]; + /* Ensure timestamp is naturally aligned */ + struct { + u32 accel_val[3]; + s64 timestamp __aligned(8); + } scan; int scale_pre_decml; int scale_post_decml; int scale_precision; @@ -245,8 +248,8 @@ static int accel_3d_proc_event(struct hid_sensor_hub_device *hsdev, accel_state->timestamp = iio_get_time_ns(indio_dev); hid_sensor_push_data(indio_dev, - accel_state->accel_val, - sizeof(accel_state->accel_val), + &accel_state->scan, + sizeof(accel_state->scan), accel_state->timestamp); accel_state->timestamp = 0; @@ -271,7 +274,7 @@ static int accel_3d_capture_sample(struct hid_sensor_hub_device *hsdev, case HID_USAGE_SENSOR_ACCEL_Y_AXIS: case HID_USAGE_SENSOR_ACCEL_Z_AXIS: offset = usage_id - HID_USAGE_SENSOR_ACCEL_X_AXIS; - accel_state->accel_val[CHANNEL_SCAN_INDEX_X + offset] = + accel_state->scan.accel_val[CHANNEL_SCAN_INDEX_X + offset] = *(u32 *)raw_data; ret = 0; break; -- cgit v1.2.3 From 3ab3aa2e7bd57497f9a7c6275c00dce237d2c9ba Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 1 May 2021 18:01:06 +0100 Subject: iio: accel: kxcjk-1013: Fix buffer alignment in iio_push_to_buffers_with_timestamp() To make code more readable, use a structure to express the channel layout and ensure the timestamp is 8 byte aligned. Found during an audit of all calls of this function. Fixes: 1a4fbf6a9286 ("iio: accel: kxcjk1013 3-axis accelerometer driver") Signed-off-by: Jonathan Cameron Cc: Srinivas Pandruvada Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210501170121.512209-5-jic23@kernel.org --- drivers/iio/accel/kxcjk-1013.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 961803296abc..7cd647315194 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -233,6 +233,13 @@ static const struct kx_chipset_regs kx0231025_regs = { .wake_thres = KX023_REG_ATH, }; +enum kxcjk1013_axis { + AXIS_X, + AXIS_Y, + AXIS_Z, + AXIS_MAX +}; + struct kxcjk1013_data { struct regulator_bulk_data regulators[2]; struct i2c_client *client; @@ -240,7 +247,11 @@ struct kxcjk1013_data { struct iio_trigger *motion_trig; struct iio_mount_matrix orientation; struct mutex mutex; - s16 buffer[8]; + /* Ensure timestamp naturally aligned */ + struct { + s16 chans[AXIS_MAX]; + s64 timestamp __aligned(8); + } scan; u8 odr_bits; u8 range; int wake_thres; @@ -255,13 +266,6 @@ struct kxcjk1013_data { const struct kx_chipset_regs *regs; }; -enum kxcjk1013_axis { - AXIS_X, - AXIS_Y, - AXIS_Z, - AXIS_MAX, -}; - enum kxcjk1013_mode { STANDBY, OPERATION, @@ -1208,12 +1212,12 @@ static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p) ret = i2c_smbus_read_i2c_block_data_or_emulated(data->client, KXCJK1013_REG_XOUT_L, AXIS_MAX * 2, - (u8 *)data->buffer); + (u8 *)data->scan.chans); mutex_unlock(&data->mutex); if (ret < 0) goto err; - iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, data->timestamp); err: iio_trigger_notify_done(indio_dev->trig); -- cgit v1.2.3 From f65802284a3a337510d7f8f916c97d66c74f2e71 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 1 May 2021 18:01:07 +0100 Subject: iio: accel: mxc4005: Fix overread of data and alignment issue. The bulk read size is based on the size of an array that also has space for the timestamp alongside the channels. Fix that and also fix alignment of the buffer passed to iio_push_to_buffers_with_timestamp. Found during an audit of all calls to this function. Fixes: 1ce0eda0f757 ("iio: mxc4005: add triggered buffer mode for mxc4005") Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210501170121.512209-6-jic23@kernel.org --- drivers/iio/accel/mxc4005.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c index 98c7f5f59011..b3afbf064915 100644 --- a/drivers/iio/accel/mxc4005.c +++ b/drivers/iio/accel/mxc4005.c @@ -56,7 +56,11 @@ struct mxc4005_data { struct mutex mutex; struct regmap *regmap; struct iio_trigger *dready_trig; - __be16 buffer[8]; + /* Ensure timestamp is naturally aligned */ + struct { + __be16 chans[3]; + s64 timestamp __aligned(8); + } scan; bool trigger_enabled; }; @@ -135,7 +139,7 @@ static int mxc4005_read_xyz(struct mxc4005_data *data) int ret; ret = regmap_bulk_read(data->regmap, MXC4005_REG_XOUT_UPPER, - data->buffer, sizeof(data->buffer)); + data->scan.chans, sizeof(data->scan.chans)); if (ret < 0) { dev_err(data->dev, "failed to read axes\n"); return ret; @@ -301,7 +305,7 @@ static irqreturn_t mxc4005_trigger_handler(int irq, void *private) if (ret < 0) goto err; - iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, pf->timestamp); err: -- cgit v1.2.3 From f40a71ffec808e7e51848f63f0c0d3c32d65081b Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 1 May 2021 18:01:08 +0100 Subject: iio: accel: stk8312: Fix buffer alignment in iio_push_to_buffers_with_timestamp() To make code more readable, use a structure to express the channel layout and ensure the timestamp is 8 byte aligned. Found during an audit of all calls of this function. Fixes: 95c12bba51c3 ("iio: accel: Add buffer mode for Sensortek STK8312") Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210501170121.512209-7-jic23@kernel.org --- drivers/iio/accel/stk8312.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index 34dc9bd78fb8..43c621d0f11e 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -102,7 +102,11 @@ struct stk8312_data { u8 mode; struct iio_trigger *dready_trig; bool dready_trigger_on; - s8 buffer[16]; /* 3x8-bit channels + 5x8 padding + 64-bit timestamp */ + /* Ensure timestamp is naturally aligned */ + struct { + s8 chans[3]; + s64 timestamp __aligned(8); + } scan; }; static IIO_CONST_ATTR(in_accel_scale_available, STK8312_SCALE_AVAIL); @@ -437,7 +441,7 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p) ret = i2c_smbus_read_i2c_block_data(data->client, STK8312_REG_XOUT, STK8312_ALL_CHANNEL_SIZE, - data->buffer); + data->scan.chans); if (ret < STK8312_ALL_CHANNEL_SIZE) { dev_err(&data->client->dev, "register read failed\n"); mutex_unlock(&data->lock); @@ -451,12 +455,12 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p) mutex_unlock(&data->lock); goto err; } - data->buffer[i++] = ret; + data->scan.chans[i++] = ret; } } mutex_unlock(&data->lock); - iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, pf->timestamp); err: iio_trigger_notify_done(indio_dev->trig); -- cgit v1.2.3 From 334883894bc1e145a1e0f5de1b0d1b6a1133f0e6 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 1 May 2021 18:01:09 +0100 Subject: iio: accel: stk8ba50: Fix buffer alignment in iio_push_to_buffers_with_timestamp() To make code more readable, use a structure to express the channel layout and ensure the timestamp is 8 byte aligned. Found during an audit of all calls of this function. Fixes: db6a19b8251f ("iio: accel: Add trigger support for STK8BA50") Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210501170121.512209-8-jic23@kernel.org --- drivers/iio/accel/stk8ba50.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index 3e7cf23be7e1..e137a34b5c9a 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -91,12 +91,11 @@ struct stk8ba50_data { u8 sample_rate_idx; struct iio_trigger *dready_trig; bool dready_trigger_on; - /* - * 3 x 16-bit channels (10-bit data, 6-bit padding) + - * 1 x 16 padding + - * 4 x 16 64-bit timestamp - */ - s16 buffer[8]; + /* Ensure timestamp is naturally aligned */ + struct { + s16 chans[3]; + s64 timetamp __aligned(8); + } scan; }; #define STK8BA50_ACCEL_CHANNEL(index, reg, axis) { \ @@ -324,7 +323,7 @@ static irqreturn_t stk8ba50_trigger_handler(int irq, void *p) ret = i2c_smbus_read_i2c_block_data(data->client, STK8BA50_REG_XOUT, STK8BA50_ALL_CHANNEL_SIZE, - (u8 *)data->buffer); + (u8 *)data->scan.chans); if (ret < STK8BA50_ALL_CHANNEL_SIZE) { dev_err(&data->client->dev, "register read failed\n"); goto err; @@ -337,10 +336,10 @@ static irqreturn_t stk8ba50_trigger_handler(int irq, void *p) if (ret < 0) goto err; - data->buffer[i++] = ret; + data->scan.chans[i++] = ret; } } - iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, pf->timestamp); err: mutex_unlock(&data->lock); -- cgit v1.2.3 From d85d71dd1ab67eaa7351f69fec512d8f09d164e1 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 1 May 2021 18:01:10 +0100 Subject: iio: adc: ti-ads1015: Fix buffer alignment in iio_push_to_buffers_with_timestamp() To make code more readable, use a structure to express the channel layout and ensure the timestamp is 8 byte aligned. Found during an audit of all calls of this function. Fixes: ecc24e72f437 ("iio: adc: Add TI ADS1015 ADC driver support") Signed-off-by: Jonathan Cameron Cc: Daniel Baluta Cc: Andy Shevchenko Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210501170121.512209-9-jic23@kernel.org --- drivers/iio/adc/ti-ads1015.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index 9fef39bcf997..5b828428be77 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -395,10 +395,14 @@ static irqreturn_t ads1015_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct ads1015_data *data = iio_priv(indio_dev); - s16 buf[8]; /* 1x s16 ADC val + 3x s16 padding + 4x s16 timestamp */ + /* Ensure natural alignment of timestamp */ + struct { + s16 chan; + s64 timestamp __aligned(8); + } scan; int chan, ret, res; - memset(buf, 0, sizeof(buf)); + memset(&scan, 0, sizeof(scan)); mutex_lock(&data->lock); chan = find_first_bit(indio_dev->active_scan_mask, @@ -409,10 +413,10 @@ static irqreturn_t ads1015_trigger_handler(int irq, void *p) goto err; } - buf[0] = res; + scan.chan = res; mutex_unlock(&data->lock); - iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_push_to_buffers_with_timestamp(indio_dev, &scan, iio_get_time_ns(indio_dev)); err: -- cgit v1.2.3 From 7765dfaa22ea08abf0c175e7553826ba2a939632 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 1 May 2021 18:01:11 +0100 Subject: iio: adc: vf610: Fix buffer alignment in iio_push_to_buffers_with_timestamp() To make code more readable, use a structure to express the channel layout and ensure the timestamp is 8 byte aligned. Found during an audit of all calls of uses of iio_push_to_buffers_with_timestamp() Fixes: 0010d6b44406 ("iio: adc: vf610: Add IIO buffer support for Vybrid ADC") Signed-off-by: Jonathan Cameron Cc: Stefan-Gabriel Mirea Cc: Sanchayan Maity Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210501170121.512209-10-jic23@kernel.org --- drivers/iio/adc/vf610_adc.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index 1d794cf3e3f1..fd57fc43e8e5 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -167,7 +167,11 @@ struct vf610_adc { u32 sample_freq_avail[5]; struct completion completion; - u16 buffer[8]; + /* Ensure the timestamp is naturally aligned */ + struct { + u16 chan; + s64 timestamp __aligned(8); + } scan; }; static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 }; @@ -579,9 +583,9 @@ static irqreturn_t vf610_adc_isr(int irq, void *dev_id) if (coco & VF610_ADC_HS_COCO0) { info->value = vf610_adc_read_data(info); if (iio_buffer_enabled(indio_dev)) { - info->buffer[0] = info->value; + info->scan.chan = info->value; iio_push_to_buffers_with_timestamp(indio_dev, - info->buffer, + &info->scan, iio_get_time_ns(indio_dev)); iio_trigger_notify_done(indio_dev->trig); } else -- cgit v1.2.3 From 06778d881f3798ce93ffbbbf801234292250b598 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 1 May 2021 18:01:12 +0100 Subject: iio: gyro: bmg160: Fix buffer alignment in iio_push_to_buffers_with_timestamp() To make code more readable, use a structure to express the channel layout and ensure the timestamp is 8 byte aligned. Found during an audit of all calls of uses of iio_push_to_buffers_with_timestamp() Fixes: 13426454b649 ("iio: bmg160: Separate i2c and core driver") Signed-off-by: Jonathan Cameron Cc: Stephan Gerhold Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210501170121.512209-11-jic23@kernel.org --- drivers/iio/gyro/bmg160_core.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c index 26a9ed5770c6..a7cc2cad8bbf 100644 --- a/drivers/iio/gyro/bmg160_core.c +++ b/drivers/iio/gyro/bmg160_core.c @@ -98,7 +98,11 @@ struct bmg160_data { struct iio_trigger *motion_trig; struct iio_mount_matrix orientation; struct mutex mutex; - s16 buffer[8]; + /* Ensure naturally aligned timestamp */ + struct { + s16 chans[3]; + s64 timestamp __aligned(8); + } scan; u32 dps_range; int ev_enable_state; int slope_thres; @@ -882,12 +886,12 @@ static irqreturn_t bmg160_trigger_handler(int irq, void *p) mutex_lock(&data->mutex); ret = regmap_bulk_read(data->regmap, BMG160_REG_XOUT_L, - data->buffer, AXIS_MAX * 2); + data->scan.chans, AXIS_MAX * 2); mutex_unlock(&data->mutex); if (ret < 0) goto err; - iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, pf->timestamp); err: iio_trigger_notify_done(indio_dev->trig); -- cgit v1.2.3 From f4ca2e2595d9fee65d5ce0d218b22ce00e5b2915 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 1 May 2021 18:01:13 +0100 Subject: iio: humidity: am2315: Fix buffer alignment in iio_push_to_buffers_with_timestamp() To make code more readable, use a structure to express the channel layout and ensure the timestamp is 8 byte aligned. Found during an audit of all calls of uses of iio_push_to_buffers_with_timestamp() Fixes: 0d96d5ead3f7 ("iio: humidity: Add triggered buffer support for AM2315") Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210501170121.512209-12-jic23@kernel.org --- drivers/iio/humidity/am2315.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/humidity/am2315.c b/drivers/iio/humidity/am2315.c index 8d7ec2f5acf8..4a39f1019347 100644 --- a/drivers/iio/humidity/am2315.c +++ b/drivers/iio/humidity/am2315.c @@ -32,7 +32,11 @@ struct am2315_data { struct i2c_client *client; struct mutex lock; - s16 buffer[8]; /* 2x16-bit channels + 2x16 padding + 4x16 timestamp */ + /* Ensure timestamp is naturally aligned */ + struct { + s16 chans[2]; + s64 timestamp __aligned(8); + } scan; }; struct am2315_sensor_data { @@ -166,20 +170,20 @@ static irqreturn_t am2315_trigger_handler(int irq, void *p) mutex_lock(&data->lock); if (*(indio_dev->active_scan_mask) == AM2315_ALL_CHANNEL_MASK) { - data->buffer[0] = sensor_data.hum_data; - data->buffer[1] = sensor_data.temp_data; + data->scan.chans[0] = sensor_data.hum_data; + data->scan.chans[1] = sensor_data.temp_data; } else { i = 0; for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) { - data->buffer[i] = (bit ? sensor_data.temp_data : - sensor_data.hum_data); + data->scan.chans[i] = (bit ? sensor_data.temp_data : + sensor_data.hum_data); i++; } } mutex_unlock(&data->lock); - iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, pf->timestamp); err: iio_trigger_notify_done(indio_dev->trig); -- cgit v1.2.3 From 19f1a254fe4949fff1e67db386409f48cf438bd7 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 1 May 2021 18:01:14 +0100 Subject: iio: prox: srf08: Fix buffer alignment in iio_push_to_buffers_with_timestamp() To make code more readable, use a structure to express the channel layout and ensure the timestamp is 8 byte aligned. Found during an audit of all calls of uses of iio_push_to_buffers_with_timestamp() Fixes: 78f839029e1d ("iio: distance: srf08: add IIO driver for us ranger") Signed-off-by: Jonathan Cameron Cc: Andreas Klinger Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210501170121.512209-13-jic23@kernel.org --- drivers/iio/proximity/srf08.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/proximity/srf08.c b/drivers/iio/proximity/srf08.c index 70beac5c9c1d..9b0886760f76 100644 --- a/drivers/iio/proximity/srf08.c +++ b/drivers/iio/proximity/srf08.c @@ -63,11 +63,11 @@ struct srf08_data { int range_mm; struct mutex lock; - /* - * triggered buffer - * 1x16-bit channel + 3x16 padding + 4x16 timestamp - */ - s16 buffer[8]; + /* Ensure timestamp is naturally aligned */ + struct { + s16 chan; + s64 timestamp __aligned(8); + } scan; /* Sensor-Type */ enum srf08_sensor_type sensor_type; @@ -190,9 +190,9 @@ static irqreturn_t srf08_trigger_handler(int irq, void *p) mutex_lock(&data->lock); - data->buffer[0] = sensor_data; + data->scan.chan = sensor_data; iio_push_to_buffers_with_timestamp(indio_dev, - data->buffer, pf->timestamp); + &data->scan, pf->timestamp); mutex_unlock(&data->lock); err: -- cgit v1.2.3 From 679cc377a03ff1944491eafc7355c1eb1fad4109 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 1 May 2021 18:01:15 +0100 Subject: iio: prox: pulsed-light: Fix buffer alignment in iio_push_to_buffers_with_timestamp() To make code more readable, use a structure to express the channel layout and ensure the timestamp is 8 byte aligned. Found during an audit of all calls of uses of iio_push_to_buffers_with_timestamp() Fixes: cb119d535083 ("iio: proximity: add support for PulsedLight LIDAR") Signed-off-by: Jonathan Cameron Cc: Matt Ranostay Acked-by: Matt Ranostay Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210501170121.512209-14-jic23@kernel.org --- drivers/iio/proximity/pulsedlight-lidar-lite-v2.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c index cc206bfa09c7..d854b8d5fbba 100644 --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c @@ -44,7 +44,11 @@ struct lidar_data { int (*xfer)(struct lidar_data *data, u8 reg, u8 *val, int len); int i2c_enabled; - u16 buffer[8]; /* 2 byte distance + 8 byte timestamp */ + /* Ensure timestamp is naturally aligned */ + struct { + u16 chan; + s64 timestamp __aligned(8); + } scan; }; static const struct iio_chan_spec lidar_channels[] = { @@ -230,9 +234,9 @@ static irqreturn_t lidar_trigger_handler(int irq, void *private) struct lidar_data *data = iio_priv(indio_dev); int ret; - ret = lidar_get_measurement(data, data->buffer); + ret = lidar_get_measurement(data, &data->scan.chan); if (!ret) { - iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, iio_get_time_ns(indio_dev)); } else if (ret != -EINVAL) { dev_err(&data->client->dev, "cannot read LIDAR measurement"); -- cgit v1.2.3 From 37eb8d8c64f2ecb3a5521ba1cc1fad973adfae41 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 1 May 2021 18:01:16 +0100 Subject: iio: prox: as3935: Fix buffer alignment in iio_push_to_buffers_with_timestamp() To make code more readable, use a structure to express the channel layout and ensure the timestamp is 8 byte aligned. Found during an audit of all calls of uses of iio_push_to_buffers_with_timestamp() Fixes: 37b1ba2c68cf ("iio: proximity: as3935: fix buffer stack trashing") Signed-off-by: Jonathan Cameron Cc: Matt Ranostay Acked-by: Matt Ranostay Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210501170121.512209-15-jic23@kernel.org --- drivers/iio/proximity/as3935.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index dc20fe81232c..3797a8f54276 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -59,7 +59,11 @@ struct as3935_state { unsigned long noise_tripped; u32 tune_cap; u32 nflwdth_reg; - u8 buffer[16]; /* 8-bit data + 56-bit padding + 64-bit timestamp */ + /* Ensure timestamp is naturally aligned */ + struct { + u8 chan; + s64 timestamp __aligned(8); + } scan; u8 buf[2] ____cacheline_aligned; }; @@ -225,8 +229,8 @@ static irqreturn_t as3935_trigger_handler(int irq, void *private) if (ret) goto err_read; - st->buffer[0] = val & AS3935_DATA_MASK; - iio_push_to_buffers_with_timestamp(indio_dev, &st->buffer, + st->scan.chan = val & AS3935_DATA_MASK; + iio_push_to_buffers_with_timestamp(indio_dev, &st->scan, iio_get_time_ns(indio_dev)); err_read: iio_trigger_notify_done(indio_dev->trig); -- cgit v1.2.3 From 1ef2f51e9fe424ccecca5bb0373d71b900c2cd41 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 1 May 2021 18:01:17 +0100 Subject: iio: magn: hmc5843: Fix buffer alignment in iio_push_to_buffers_with_timestamp() To make code more readable, use a structure to express the channel layout and ensure the timestamp is 8 byte aligned. Found during an audit of all calls of uses of iio_push_to_buffers_with_timestamp() Fixes: 7247645f6865 ("iio: hmc5843: Move hmc5843 out of staging") Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210501170121.512209-16-jic23@kernel.org --- drivers/iio/magnetometer/hmc5843.h | 8 ++++++-- drivers/iio/magnetometer/hmc5843_core.c | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/magnetometer/hmc5843.h b/drivers/iio/magnetometer/hmc5843.h index 3f6c0b662941..242f742f2643 100644 --- a/drivers/iio/magnetometer/hmc5843.h +++ b/drivers/iio/magnetometer/hmc5843.h @@ -33,7 +33,8 @@ enum hmc5843_ids { * @lock: update and read regmap data * @regmap: hardware access register maps * @variant: describe chip variants - * @buffer: 3x 16-bit channels + padding + 64-bit timestamp + * @scan: buffer to pack data for passing to + * iio_push_to_buffers_with_timestamp() */ struct hmc5843_data { struct device *dev; @@ -41,7 +42,10 @@ struct hmc5843_data { struct regmap *regmap; const struct hmc5843_chip_info *variant; struct iio_mount_matrix orientation; - __be16 buffer[8]; + struct { + __be16 chans[3]; + s64 timestamp __aligned(8); + } scan; }; int hmc5843_common_probe(struct device *dev, struct regmap *regmap, diff --git a/drivers/iio/magnetometer/hmc5843_core.c b/drivers/iio/magnetometer/hmc5843_core.c index 780faea61d82..221563e0c18f 100644 --- a/drivers/iio/magnetometer/hmc5843_core.c +++ b/drivers/iio/magnetometer/hmc5843_core.c @@ -446,13 +446,13 @@ static irqreturn_t hmc5843_trigger_handler(int irq, void *p) } ret = regmap_bulk_read(data->regmap, HMC5843_DATA_OUT_MSB_REGS, - data->buffer, 3 * sizeof(__be16)); + data->scan.chans, sizeof(data->scan.chans)); mutex_unlock(&data->lock); if (ret < 0) goto done; - iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, iio_get_time_ns(indio_dev)); done: -- cgit v1.2.3 From 7692088f72865c41b6b531fd09486ee99a5da930 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 1 May 2021 18:01:18 +0100 Subject: iio: magn: bmc150: Fix buffer alignment in iio_push_to_buffers_with_timestamp() To make code more readable, use a structure to express the channel layout and ensure the timestamp is 8 byte aligned. Found during an audit of all calls of uses of iio_push_to_buffers_with_timestamp() Fixes: c91746a2361d ("iio: magn: Add support for BMC150 magnetometer") Signed-off-by: Jonathan Cameron Cc: Stephan Gerhold Cc: Linus Walleij Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210501170121.512209-17-jic23@kernel.org --- drivers/iio/magnetometer/bmc150_magn.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index 39920cb764bf..5f28220a7994 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -138,8 +138,11 @@ struct bmc150_magn_data { struct regmap *regmap; struct regulator_bulk_data regulators[2]; struct iio_mount_matrix orientation; - /* 4 x 32 bits for x, y z, 4 bytes align, 64 bits timestamp */ - s32 buffer[6]; + /* Ensure timestamp is naturally aligned */ + struct { + s32 chans[3]; + s64 timestamp __aligned(8); + } scan; struct iio_trigger *dready_trig; bool dready_trigger_on; int max_odr; @@ -672,11 +675,11 @@ static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p) int ret; mutex_lock(&data->mutex); - ret = bmc150_magn_read_xyz(data, data->buffer); + ret = bmc150_magn_read_xyz(data, data->scan.chans); if (ret < 0) goto err; - iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, pf->timestamp); err: -- cgit v1.2.3 From 3d4725194de6935dba2ad7c9cc075c885008f747 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 1 May 2021 18:01:19 +0100 Subject: iio: light: isl29125: Fix buffer alignment in iio_push_to_buffers_with_timestamp() To make code more readable, use a structure to express the channel layout and ensure the timestamp is 8 byte aligned. Found during an audit of all calls of uses of iio_push_to_buffers_with_timestamp() Fixes: 6c25539cbc46 ("iio: Add Intersil isl29125 digital color light sensor driver") Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210501170121.512209-18-jic23@kernel.org --- drivers/iio/light/isl29125.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c index b93b85dbc3a6..ba53b50d711a 100644 --- a/drivers/iio/light/isl29125.c +++ b/drivers/iio/light/isl29125.c @@ -51,7 +51,11 @@ struct isl29125_data { struct i2c_client *client; u8 conf1; - u16 buffer[8]; /* 3x 16-bit, padding, 8 bytes timestamp */ + /* Ensure timestamp is naturally aligned */ + struct { + u16 chans[3]; + s64 timestamp __aligned(8); + } scan; }; #define ISL29125_CHANNEL(_color, _si) { \ @@ -184,10 +188,10 @@ static irqreturn_t isl29125_trigger_handler(int irq, void *p) if (ret < 0) goto done; - data->buffer[j++] = ret; + data->scan.chans[j++] = ret; } - iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, iio_get_time_ns(indio_dev)); done: -- cgit v1.2.3 From ff08fbc22ab32ccc6690c21b0e5e1d402dcc076f Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 1 May 2021 18:01:20 +0100 Subject: iio: light: tcs3414: Fix buffer alignment in iio_push_to_buffers_with_timestamp() To make code more readable, use a structure to express the channel layout and ensure the timestamp is 8 byte aligned. Found during an audit of all calls of uses of iio_push_to_buffers_with_timestamp() Fixes: a244e7b57f0f ("iio: Add driver for AMS/TAOS tcs3414 digital color sensor") Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210501170121.512209-19-jic23@kernel.org --- drivers/iio/light/tcs3414.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c index 6fe5d46f80d4..0593abd600ec 100644 --- a/drivers/iio/light/tcs3414.c +++ b/drivers/iio/light/tcs3414.c @@ -53,7 +53,11 @@ struct tcs3414_data { u8 control; u8 gain; u8 timing; - u16 buffer[8]; /* 4x 16-bit + 8 bytes timestamp */ + /* Ensure timestamp is naturally aligned */ + struct { + u16 chans[4]; + s64 timestamp __aligned(8); + } scan; }; #define TCS3414_CHANNEL(_color, _si, _addr) { \ @@ -209,10 +213,10 @@ static irqreturn_t tcs3414_trigger_handler(int irq, void *p) if (ret < 0) goto done; - data->buffer[j++] = ret; + data->scan.chans[j++] = ret; } - iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, iio_get_time_ns(indio_dev)); done: -- cgit v1.2.3 From df2f37cffd6ed486d613e7ee22aadc8e49ae2dd3 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 1 May 2021 18:01:21 +0100 Subject: iio: light: tcs3472: Fix buffer alignment in iio_push_to_buffers_with_timestamp() To make code more readable, use a structure to express the channel layout and ensure the timestamp is 8 byte aligned. Found during an audit of all calls of uses of iio_push_to_buffers_with_timestamp(). Fixes tag is not strictly accurate as prior to that patch there was potentially an unaligned write. However, any backport past there will need to be done manually. Fixes: 0624bf847dd0 ("iio:tcs3472: Use iio_push_to_buffers_with_timestamp()") Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210501170121.512209-20-jic23@kernel.org --- drivers/iio/light/tcs3472.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index a0dc447aeb68..90dc3fef59e6 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -64,7 +64,11 @@ struct tcs3472_data { u8 control; u8 atime; u8 apers; - u16 buffer[8]; /* 4 16-bit channels + 64-bit timestamp */ + /* Ensure timestamp is naturally aligned */ + struct { + u16 chans[4]; + s64 timestamp __aligned(8); + } scan; }; static const struct iio_event_spec tcs3472_events[] = { @@ -386,10 +390,10 @@ static irqreturn_t tcs3472_trigger_handler(int irq, void *p) if (ret < 0) goto done; - data->buffer[j++] = ret; + data->scan.chans[j++] = ret; } - iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, iio_get_time_ns(indio_dev)); done: -- cgit v1.2.3 From b0f5d8db7348a6ce5cdd79fba46ebc91eebc8fd9 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 1 May 2021 18:13:46 +0100 Subject: iio: chemical: atlas: Fix buffer alignment in iio_push_to_buffers_with_timestamp() Variable location for the timestamp, so just use __aligned(8) to ensure it is always possible to naturally align it. Found during an audit of all calls of uses of iio_push_to_buffers_with_timestamp() Fixes tag is not accurate, but it will need manual backporting beyond that point if anyone cares. Fixes: 0d15190f53b4 ("iio: chemical: atlas-ph-sensor: rename atlas-ph-sensor to atlas-sensor") Signed-off-by: Jonathan Cameron Cc: Matt Ranostay Acked-by: Matt Ranostay Link: https://lore.kernel.org/r/20210501171352.512953-6-jic23@kernel.org --- drivers/iio/chemical/atlas-sensor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/chemical/atlas-sensor.c b/drivers/iio/chemical/atlas-sensor.c index d10f921b233a..0fdb3b29c5eb 100644 --- a/drivers/iio/chemical/atlas-sensor.c +++ b/drivers/iio/chemical/atlas-sensor.c @@ -91,8 +91,8 @@ struct atlas_data { struct regmap *regmap; struct irq_work work; unsigned int interrupt_enabled; - - __be32 buffer[6]; /* 96-bit data + 32-bit pad + 64-bit timestamp */ + /* 96-bit data + 32-bit pad + 64-bit timestamp */ + __be32 buffer[6] __aligned(8); }; static const struct regmap_config atlas_regmap_config = { -- cgit v1.2.3 From 8979b67ec61abc232636400ee8c758a16a73c95f Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 1 May 2021 18:13:48 +0100 Subject: iio: potentiostat: lmp91000: Fix alignment of buffer in iio_push_to_buffers_with_timestamp() Add __aligned(8) to ensure the buffer passed to iio_push_to_buffers_with_timestamp() is suitable for the naturally aligned timestamp that will be inserted. Here structure is not used, because this buffer is also used elsewhere in the driver. Fixes: 67e17300dc1d ("iio: potentiostat: add LMP91000 support") Signed-off-by: Jonathan Cameron Cc: Matt Ranostay Acked-by: Matt Ranostay Link: https://lore.kernel.org/r/20210501171352.512953-8-jic23@kernel.org --- drivers/iio/potentiostat/lmp91000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c index 1948e2d22c27..ed30bdaa10ec 100644 --- a/drivers/iio/potentiostat/lmp91000.c +++ b/drivers/iio/potentiostat/lmp91000.c @@ -71,8 +71,8 @@ struct lmp91000_data { struct completion completion; u8 chan_select; - - u32 buffer[4]; /* 64-bit data + 64-bit timestamp */ + /* 64-bit data + 64-bit naturally aligned timestamp */ + u32 buffer[4] __aligned(8); }; static const struct iio_chan_spec lmp91000_channels[] = { -- cgit v1.2.3 From 2a1c6a7743d7425afa71f168830f5344240827cd Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 May 2021 12:33:45 +0100 Subject: iio: light: pa12203001: Use pm_runtime_resume_and_get() to replace open coding. Found using coccicheck script under review at: https://lore.kernel.org/lkml/20210427141946.2478411-1-Julia.Lawall@inria.fr/ This is a prequel to taking a closer look at the runtime pm in IIO drivers in general. Signed-off-by: Jonathan Cameron Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210509113354.660190-20-jic23@kernel.org --- drivers/iio/light/pa12203001.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/light/pa12203001.c b/drivers/iio/light/pa12203001.c index bfade6577a38..a52b2c788540 100644 --- a/drivers/iio/light/pa12203001.c +++ b/drivers/iio/light/pa12203001.c @@ -186,9 +186,7 @@ static int pa12203001_set_power_state(struct pa12203001_data *data, bool on, } if (on) { - ret = pm_runtime_get_sync(&data->client->dev); - if (ret < 0) - pm_runtime_put_noidle(&data->client->dev); + ret = pm_runtime_resume_and_get(&data->client->dev); } else { pm_runtime_mark_last_busy(&data->client->dev); -- cgit v1.2.3 From 43fa739450492a0b870802d471de923184870a4c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 15 May 2021 12:56:39 +0300 Subject: iio: core: Fix an error pointer vs NULL bug in devm_iio_device_alloc() The devm_iio_device_alloc() function is supposed to return NULL and not error pointers. Returning an error pointer will lead to a crash in the callers. Fixes: cf5724e91515 ("iio: core: simplify some devm functions") Signed-off-by: Dan Carpenter Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/YJ+a1yaMu2QNATgt@mwanda Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index bfa20a346f71..75e92bac78f3 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1711,7 +1711,7 @@ struct iio_dev *devm_iio_device_alloc(struct device *parent, int sizeof_priv) ret = devm_add_action_or_reset(parent, devm_iio_device_release, iio_dev); if (ret) - return ERR_PTR(ret); + return NULL; return iio_dev; } -- cgit v1.2.3 From bd1455615f402c63458492875dce4d848cbb2210 Mon Sep 17 00:00:00 2001 From: Tang Bin Date: Tue, 11 May 2021 21:47:39 +0800 Subject: iio:adc:ad7766: Fix unnecessary check in ad7766_probe() In the function ad7766_probe(), the return value of devm_iio_device_register() can be zero or ret, Thus it is unnecessary to repeated check here. Signed-off-by: Tang Bin Signed-off-by: Zhang Shengju Co-developed-by: Zhang Shengju Link: https://lore.kernel.org/r/20210511134739.948-1-tangbin@cmss.chinamobile.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7766.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/ad7766.c b/drivers/iio/adc/ad7766.c index 236a455aaa18..9b35c09b9313 100644 --- a/drivers/iio/adc/ad7766.c +++ b/drivers/iio/adc/ad7766.c @@ -290,10 +290,7 @@ static int ad7766_probe(struct spi_device *spi) if (ret) return ret; - ret = devm_iio_device_register(&spi->dev, indio_dev); - if (ret) - return ret; - return 0; + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id ad7766_id[] = { -- cgit v1.2.3 From 7fce54ace336f076c5bac062b80005ef575cd4d9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 14 May 2021 16:10:07 +0300 Subject: iio: light: tsl2591: fix some signedness bugs These variables need to be int for the error handling to work. Fixes: 2335f0d7c790 ("iio: light: Added AMS tsl2591 driver implementation") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/YJ52r1XZ44myD9Xx@mwanda Signed-off-by: Jonathan Cameron --- drivers/iio/light/tsl2591.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/light/tsl2591.c b/drivers/iio/light/tsl2591.c index 2bdae388ff01..26e3cb6c4ff8 100644 --- a/drivers/iio/light/tsl2591.c +++ b/drivers/iio/light/tsl2591.c @@ -213,7 +213,7 @@ static int tsl2591_gain_to_multiplier(const u8 als_gain) } } -static u8 tsl2591_multiplier_to_gain(const u32 multiplier) +static int tsl2591_multiplier_to_gain(const u32 multiplier) { switch (multiplier) { case TSL2591_CTRL_ALS_LOW_GAIN_MULTIPLIER: @@ -783,8 +783,8 @@ static int tsl2591_write_raw(struct iio_dev *indio_dev, int val, int val2, long mask) { struct tsl2591_chip *chip = iio_priv(indio_dev); - u32 int_time; - u8 gain; + int int_time; + int gain; int ret; mutex_lock(&chip->als_mutex); -- cgit v1.2.3 From 2989df460cf8d0c7085090d130e1851f94329b85 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 14 May 2021 16:10:55 +0300 Subject: iio: light: tsl2591: delete a stray tab This return statement is indented one more tab than it should be. Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/YJ523y0dhc1IwCOB@mwanda Signed-off-by: Jonathan Cameron --- drivers/iio/light/tsl2591.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/light/tsl2591.c b/drivers/iio/light/tsl2591.c index 26e3cb6c4ff8..39e68d0c9d6a 100644 --- a/drivers/iio/light/tsl2591.c +++ b/drivers/iio/light/tsl2591.c @@ -451,7 +451,7 @@ static int tsl2591_read_channel_data(struct iio_dev *indio_dev, sizeof(als_data), als_data); if (ret < 0) { dev_err(&client->dev, "Failed to read data bytes"); - return ret; + return ret; } als_ch0 = get_unaligned_le16(&als_data[0]); -- cgit v1.2.3 From 9504db5765e83cc919caf6647725f7d022874c9d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 15 May 2021 12:51:52 +0300 Subject: iio: adc: tsc2046: fix a warning message in tsc2046_adc_update_scan_mode() These variables are unsigned so the condition can't be less than zero and the warning message will never be printed. Fixes: 9374e8f5a38d ("iio: adc: add ADC driver for the TI TSC2046 controller") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/YJ+ZuO43TnguY5vq@mwanda Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-tsc2046.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/ti-tsc2046.c b/drivers/iio/adc/ti-tsc2046.c index 89a818b653b4..cf5373d5cdd7 100644 --- a/drivers/iio/adc/ti-tsc2046.c +++ b/drivers/iio/adc/ti-tsc2046.c @@ -398,7 +398,7 @@ static int tsc2046_adc_update_scan_mode(struct iio_dev *indio_dev, priv->xfer.len = size; priv->time_per_scan_us = size * 8 * priv->time_per_bit_ns / NSEC_PER_USEC; - if ((priv->scan_interval_us - priv->time_per_scan_us) < 0) + if (priv->scan_interval_us > priv->time_per_scan_us) dev_warn(&priv->spi->dev, "The scan interval (%d) is less then calculated scan time (%d)\n", priv->scan_interval_us, priv->time_per_scan_us); -- cgit v1.2.3 From af51ec8c9213ec502c3f5c9f5860dd98fceb3433 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 9 May 2021 12:33:34 +0100 Subject: iio: hid: trigger: Balance runtime pm + use pm_runtime_resume_and_get() The call to pm_runtime_put_noidle() in remove() callback is not balanced by any gets Note this doesn't cause any problems beyond reader confusion as the runtime pm core protects against the reference counter going negative. Whilst here, use pm_runtiem_resume_and_get() to simplify code a little. Signed-off-by: Jonathan Cameron Cc: Srinivas Pandruvada Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20210509113354.660190-9-jic23@kernel.org --- drivers/iio/common/hid-sensors/hid-sensor-trigger.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index 5a7b3e253e58..c06537e106e9 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -163,18 +163,15 @@ int hid_sensor_power_state(struct hid_sensor_common *st, bool state) if (state) { atomic_inc(&st->user_requested_state); - ret = pm_runtime_get_sync(&st->pdev->dev); + ret = pm_runtime_resume_and_get(&st->pdev->dev); } else { atomic_dec(&st->user_requested_state); pm_runtime_mark_last_busy(&st->pdev->dev); pm_runtime_use_autosuspend(&st->pdev->dev); ret = pm_runtime_put_autosuspend(&st->pdev->dev); } - if (ret < 0) { - if (state) - pm_runtime_put_noidle(&st->pdev->dev); + if (ret < 0) return ret; - } return 0; #else @@ -222,7 +219,6 @@ void hid_sensor_remove_trigger(struct iio_dev *indio_dev, pm_runtime_disable(&attrb->pdev->dev); pm_runtime_set_suspended(&attrb->pdev->dev); - pm_runtime_put_noidle(&attrb->pdev->dev); cancel_work_sync(&attrb->work); iio_trigger_unregister(attrb->trigger); -- cgit v1.2.3 From e50f8e0495541e827e8c3d13118dc30feaee99fb Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Mon, 17 May 2021 18:11:57 +0800 Subject: iio: buffer: Remove redundant assignment to in_loc Variable in_loc is being assigned a value from a calculation however the assignment is never read, so this redundant assignment can be removed. Clean up the following clang-analyzer warning: drivers/iio/industrialio-buffer.c:929:3: warning: Value stored to 'in_loc' is never read [clang-analyzer-deadcode.DeadStores]. Reported-by: Abaci Robot Signed-off-by: Jiapeng Chong Link: https://lore.kernel.org/r/1621246317-62725-1-git-send-email-jiapeng.chong@linux.alibaba.com Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 10923b40c76d..fdd623407b96 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -926,7 +926,6 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev, if (ret) goto error_clear_mux_table; out_loc += length; - in_loc += length; } buffer->demux_bounce = kzalloc(out_loc, GFP_KERNEL); if (buffer->demux_bounce == NULL) { -- cgit v1.2.3 From 941f130881fa9073a32944e69c26cdc15a554d96 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Thu, 22 Apr 2021 12:37:35 +0200 Subject: iio: adis16480: support burst read function Some supported devices support burst read function. This provides a method for reading a batch of data (status, temperature, gyroscopes, accelerometers, time stamp/data counter, and CRC code), which does not require a stall time between each 16-bit segment and only requires one command on the DIN line to initiate. Devices supporting this mode are: * adis16495-1 * adis16495-2 * adis16495-3 * adis16497-1 * adis16497-2 * adis16497-3 Reviewed-by: Lars-Peter Clausen Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20210422103735.136367-1-nuno.sa@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16480.c | 160 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 147 insertions(+), 13 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index f81b86690b76..a9c21a5ae05a 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -19,11 +19,15 @@ #include #include #include +#include +#include #include #include #include #include +#include +#include #include @@ -103,6 +107,12 @@ * Available only for ADIS1649x devices */ #define ADIS16495_REG_SYNC_SCALE ADIS16480_REG(0x03, 0x10) +#define ADIS16495_REG_BURST_CMD ADIS16480_REG(0x00, 0x7C) +#define ADIS16495_BURST_ID 0xA5A5 +/* total number of segments in burst */ +#define ADIS16495_BURST_MAX_DATA 20 +/* spi max speed in burst mode */ +#define ADIS16495_BURST_MAX_SPEED 6000000 #define ADIS16480_REG_SERIAL_NUM ADIS16480_REG(0x04, 0x20) @@ -163,6 +173,8 @@ struct adis16480 { struct clk *ext_clk; enum adis16480_clock_mode clk_mode; unsigned int clk_freq; + /* Alignment needed for the timestamp */ + __be16 data[ADIS16495_BURST_MAX_DATA] __aligned(8); }; static const char * const adis16480_int_pin_names[4] = { @@ -863,7 +875,7 @@ static const char * const adis16480_status_error_msgs[] = { static int adis16480_enable_irq(struct adis *adis, bool enable); -#define ADIS16480_DATA(_prod_id, _timeouts) \ +#define ADIS16480_DATA(_prod_id, _timeouts, _burst_len) \ { \ .diag_stat_reg = ADIS16480_REG_DIAG_STS, \ .glob_cmd_reg = ADIS16480_REG_GLOB_CMD, \ @@ -887,6 +899,9 @@ static int adis16480_enable_irq(struct adis *adis, bool enable); BIT(ADIS16480_DIAG_STAT_BARO_FAIL), \ .enable_irq = adis16480_enable_irq, \ .timeouts = (_timeouts), \ + .burst_reg_cmd = ADIS16495_REG_BURST_CMD, \ + .burst_len = (_burst_len), \ + .burst_max_speed_hz = ADIS16495_BURST_MAX_SPEED \ } static const struct adis_timeout adis16485_timeouts = { @@ -931,7 +946,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .int_clk = 2460000, .max_dec_rate = 2048, .filter_freqs = adis16480_def_filter_freqs, - .adis_data = ADIS16480_DATA(16375, &adis16485_timeouts), + .adis_data = ADIS16480_DATA(16375, &adis16485_timeouts, 0), }, [ADIS16480] = { .channels = adis16480_channels, @@ -944,7 +959,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .int_clk = 2460000, .max_dec_rate = 2048, .filter_freqs = adis16480_def_filter_freqs, - .adis_data = ADIS16480_DATA(16480, &adis16480_timeouts), + .adis_data = ADIS16480_DATA(16480, &adis16480_timeouts, 0), }, [ADIS16485] = { .channels = adis16485_channels, @@ -957,7 +972,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .int_clk = 2460000, .max_dec_rate = 2048, .filter_freqs = adis16480_def_filter_freqs, - .adis_data = ADIS16480_DATA(16485, &adis16485_timeouts), + .adis_data = ADIS16480_DATA(16485, &adis16485_timeouts, 0), }, [ADIS16488] = { .channels = adis16480_channels, @@ -970,7 +985,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .int_clk = 2460000, .max_dec_rate = 2048, .filter_freqs = adis16480_def_filter_freqs, - .adis_data = ADIS16480_DATA(16488, &adis16485_timeouts), + .adis_data = ADIS16480_DATA(16488, &adis16485_timeouts, 0), }, [ADIS16490] = { .channels = adis16485_channels, @@ -984,7 +999,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .max_dec_rate = 4250, .filter_freqs = adis16495_def_filter_freqs, .has_pps_clk_mode = true, - .adis_data = ADIS16480_DATA(16490, &adis16495_timeouts), + .adis_data = ADIS16480_DATA(16490, &adis16495_timeouts, 0), }, [ADIS16495_1] = { .channels = adis16485_channels, @@ -998,7 +1013,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .max_dec_rate = 4250, .filter_freqs = adis16495_def_filter_freqs, .has_pps_clk_mode = true, - .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts), + /* 20 elements of 16bits */ + .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts, + ADIS16495_BURST_MAX_DATA * 2), }, [ADIS16495_2] = { .channels = adis16485_channels, @@ -1012,7 +1029,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .max_dec_rate = 4250, .filter_freqs = adis16495_def_filter_freqs, .has_pps_clk_mode = true, - .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts), + /* 20 elements of 16bits */ + .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts, + ADIS16495_BURST_MAX_DATA * 2), }, [ADIS16495_3] = { .channels = adis16485_channels, @@ -1026,7 +1045,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .max_dec_rate = 4250, .filter_freqs = adis16495_def_filter_freqs, .has_pps_clk_mode = true, - .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts), + /* 20 elements of 16bits */ + .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts, + ADIS16495_BURST_MAX_DATA * 2), }, [ADIS16497_1] = { .channels = adis16485_channels, @@ -1040,7 +1061,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .max_dec_rate = 4250, .filter_freqs = adis16495_def_filter_freqs, .has_pps_clk_mode = true, - .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts), + /* 20 elements of 16bits */ + .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts, + ADIS16495_BURST_MAX_DATA * 2), }, [ADIS16497_2] = { .channels = adis16485_channels, @@ -1054,7 +1077,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .max_dec_rate = 4250, .filter_freqs = adis16495_def_filter_freqs, .has_pps_clk_mode = true, - .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts), + /* 20 elements of 16bits */ + .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts, + ADIS16495_BURST_MAX_DATA * 2), }, [ADIS16497_3] = { .channels = adis16485_channels, @@ -1068,10 +1093,118 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { .max_dec_rate = 4250, .filter_freqs = adis16495_def_filter_freqs, .has_pps_clk_mode = true, - .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts), + /* 20 elements of 16bits */ + .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts, + ADIS16495_BURST_MAX_DATA * 2), }, }; +static bool adis16480_validate_crc(const u16 *buf, const u8 n_elem, const u32 crc) +{ + u32 crc_calc; + u16 crc_buf[15]; + int j; + + for (j = 0; j < n_elem; j++) + crc_buf[j] = swab16(buf[j]); + + crc_calc = crc32(~0, crc_buf, n_elem * 2); + crc_calc ^= ~0; + + return (crc == crc_calc); +} + +static irqreturn_t adis16480_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct adis16480 *st = iio_priv(indio_dev); + struct adis *adis = &st->adis; + int ret, bit, offset, i = 0; + __be16 *buffer; + u32 crc; + bool valid; + + adis_dev_lock(adis); + if (adis->current_page != 0) { + adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID); + adis->tx[1] = 0; + ret = spi_write(adis->spi, adis->tx, 2); + if (ret) { + dev_err(&adis->spi->dev, "Failed to change device page: %d\n", ret); + adis_dev_unlock(adis); + goto irq_done; + } + + adis->current_page = 0; + } + + ret = spi_sync(adis->spi, &adis->msg); + if (ret) { + dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret); + adis_dev_unlock(adis); + goto irq_done; + } + + adis_dev_unlock(adis); + + /* + * After making the burst request, the response can have one or two + * 16-bit responses containing the BURST_ID depending on the sclk. If + * clk > 3.6MHz, then we will have two BURST_ID in a row. If clk < 3MHZ, + * we have only one. To manage that variation, we use the transition from the + * BURST_ID to the SYS_E_FLAG register, which will not be equal to 0xA5A5. If + * we not find this variation in the first 4 segments, then the data should + * not be valid. + */ + buffer = adis->buffer; + for (offset = 0; offset < 4; offset++) { + u16 curr = be16_to_cpu(buffer[offset]); + u16 next = be16_to_cpu(buffer[offset + 1]); + + if (curr == ADIS16495_BURST_ID && next != ADIS16495_BURST_ID) { + offset++; + break; + } + } + + if (offset == 4) { + dev_err(&adis->spi->dev, "Invalid burst data\n"); + goto irq_done; + } + + crc = be16_to_cpu(buffer[offset + 16]) << 16 | be16_to_cpu(buffer[offset + 15]); + valid = adis16480_validate_crc((u16 *)&buffer[offset], 15, crc); + if (!valid) { + dev_err(&adis->spi->dev, "Invalid crc\n"); + goto irq_done; + } + + for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) { + /* + * When burst mode is used, temperature is the first data + * channel in the sequence, but the temperature scan index + * is 10. + */ + switch (bit) { + case ADIS16480_SCAN_TEMP: + st->data[i++] = buffer[offset + 1]; + break; + case ADIS16480_SCAN_GYRO_X ... ADIS16480_SCAN_ACCEL_Z: + /* The lower register data is sequenced first */ + st->data[i++] = buffer[2 * bit + offset + 3]; + st->data[i++] = buffer[2 * bit + offset + 2]; + break; + } + } + + iio_push_to_buffers_with_timestamp(indio_dev, st->data, pf->timestamp); +irq_done: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + static const struct iio_info adis16480_info = { .read_raw = &adis16480_read_raw, .write_raw = &adis16480_write_raw, @@ -1341,7 +1474,8 @@ static int adis16480_probe(struct spi_device *spi) st->clk_freq = st->chip_info->int_clk; } - ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL); + ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev, + adis16480_trigger_handler); if (ret) return ret; -- cgit v1.2.3 From b892770a2c553fd905ebd3ced55d5a437669b54d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 18 May 2021 14:25:46 +0300 Subject: iio: Drop Duplicated "mount-matrix" parameter All of the users of iio_read_mount_matrix() are using the very same property name. Moreover, the property name is hard coded in the API documentation. Make this clear and avoid duplication now and in the future. Signed-off-by: Andy Shevchenko Reviewed-by: Sean Nyekjaer Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20210518112546.44592-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bma180.c | 3 +-- drivers/iio/accel/bma400_core.c | 2 +- drivers/iio/accel/bmc150-accel-core.c | 3 +-- drivers/iio/accel/fxls8962af-core.c | 2 +- drivers/iio/accel/kxcjk-1013.c | 3 +-- drivers/iio/accel/kxsd9.c | 2 +- drivers/iio/gyro/bmg160_core.c | 3 +-- drivers/iio/gyro/itg3200_core.c | 3 +-- drivers/iio/gyro/mpu3050-core.c | 2 +- drivers/iio/imu/bmi160/bmi160_core.c | 3 +-- drivers/iio/imu/inv_icm42600/inv_icm42600_core.c | 2 +- drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 3 +-- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 2 +- drivers/iio/industrialio-core.c | 7 ++----- drivers/iio/magnetometer/ak8974.c | 3 +-- drivers/iio/magnetometer/ak8975.c | 2 +- drivers/iio/magnetometer/bmc150_magn.c | 3 +-- drivers/iio/magnetometer/hmc5843_core.c | 3 +-- drivers/iio/magnetometer/yamaha-yas530.c | 2 +- 19 files changed, 20 insertions(+), 33 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 71c76bbd81d4..97e991581960 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -1001,8 +1001,7 @@ static int bma180_probe(struct i2c_client *client, chip = id->driver_data; data->part_info = &bma180_part_info[chip]; - ret = iio_read_mount_matrix(dev, "mount-matrix", - &data->orientation); + ret = iio_read_mount_matrix(dev, &data->orientation); if (ret) return ret; diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c index 7eeba80e32cb..21520e022a21 100644 --- a/drivers/iio/accel/bma400_core.c +++ b/drivers/iio/accel/bma400_core.c @@ -811,7 +811,7 @@ int bma400_probe(struct device *dev, struct regmap *regmap, const char *name) if (ret) return ret; - ret = iio_read_mount_matrix(dev, "mount-matrix", &data->orientation); + ret = iio_read_mount_matrix(dev, &data->orientation); if (ret) return ret; diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index 43cfadf8f6b7..46ab7675186c 100644 --- a/drivers/iio/accel/bmc150-accel-core.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -1685,8 +1685,7 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, data->regmap = regmap; if (!bmc150_apply_acpi_orientation(dev, &data->orientation)) { - ret = iio_read_mount_matrix(dev, "mount-matrix", - &data->orientation); + ret = iio_read_mount_matrix(dev, &data->orientation); if (ret) return ret; } diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index 9fe5a18a605c..078d87865fde 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -862,7 +862,7 @@ int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq) dev_set_drvdata(dev, indio_dev); data->regmap = regmap; - ret = iio_read_mount_matrix(dev, "mount-matrix", &data->orientation); + ret = iio_read_mount_matrix(dev, &data->orientation); if (ret) return ret; diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 7cd647315194..a51fdd3c9b5b 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -1455,8 +1455,7 @@ static int kxcjk1013_probe(struct i2c_client *client, } else { data->active_high_intr = true; /* default polarity */ - ret = iio_read_mount_matrix(&client->dev, "mount-matrix", - &data->orientation); + ret = iio_read_mount_matrix(&client->dev, &data->orientation); if (ret) return ret; } diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c index 0e18b92e2099..bf7ed9e7d00f 100644 --- a/drivers/iio/accel/kxsd9.c +++ b/drivers/iio/accel/kxsd9.c @@ -420,7 +420,7 @@ int kxsd9_common_probe(struct device *dev, indio_dev->available_scan_masks = kxsd9_scan_masks; /* Read the mounting matrix, if present */ - ret = iio_read_mount_matrix(dev, "mount-matrix", &st->orientation); + ret = iio_read_mount_matrix(dev, &st->orientation); if (ret) return ret; diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c index a7cc2cad8bbf..17b939a367ad 100644 --- a/drivers/iio/gyro/bmg160_core.c +++ b/drivers/iio/gyro/bmg160_core.c @@ -1106,8 +1106,7 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq, if (ret) return ret; - ret = iio_read_mount_matrix(dev, "mount-matrix", - &data->orientation); + ret = iio_read_mount_matrix(dev, &data->orientation); if (ret) return ret; diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c index e9804664db73..a7f1bbb5f289 100644 --- a/drivers/iio/gyro/itg3200_core.c +++ b/drivers/iio/gyro/itg3200_core.c @@ -308,8 +308,7 @@ static int itg3200_probe(struct i2c_client *client, st = iio_priv(indio_dev); - ret = iio_read_mount_matrix(&client->dev, "mount-matrix", - &st->orientation); + ret = iio_read_mount_matrix(&client->dev, &st->orientation); if (ret) return ret; diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c index 2b930c7f4d86..3225de1f023b 100644 --- a/drivers/iio/gyro/mpu3050-core.c +++ b/drivers/iio/gyro/mpu3050-core.c @@ -1164,7 +1164,7 @@ int mpu3050_common_probe(struct device *dev, mpu3050->divisor = 99; /* Read the mounting matrix, if present */ - ret = iio_read_mount_matrix(dev, "mount-matrix", &mpu3050->orientation); + ret = iio_read_mount_matrix(dev, &mpu3050->orientation); if (ret) return ret; diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c index b63bd7e5e5e5..824b5124a5f5 100644 --- a/drivers/iio/imu/bmi160/bmi160_core.c +++ b/drivers/iio/imu/bmi160/bmi160_core.c @@ -852,8 +852,7 @@ int bmi160_core_probe(struct device *dev, struct regmap *regmap, return ret; } - ret = iio_read_mount_matrix(dev, "mount-matrix", - &data->orientation); + ret = iio_read_mount_matrix(dev, &data->orientation); if (ret) return ret; diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c index 8bd77185ccb7..86858da9cc38 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c @@ -592,7 +592,7 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq, st->chip = chip; st->map = regmap; - ret = iio_read_mount_matrix(dev, "mount-matrix", &st->orientation); + ret = iio_read_mount_matrix(dev, &st->orientation); if (ret) { dev_err(dev, "failed to retrieve mounting matrix %d\n", ret); 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 6244a07048df..64704b55f6eb 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -1455,8 +1455,7 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, pdata = dev_get_platdata(dev); if (!pdata) { - result = iio_read_mount_matrix(dev, "mount-matrix", - &st->orientation); + result = iio_read_mount_matrix(dev, &st->orientation); if (result) { dev_err(dev, "Failed to retrieve mounting matrix %d\n", result); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index e8d242ee6743..db45f1fc0b81 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -2256,7 +2256,7 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, return err; } - err = iio_read_mount_matrix(hw->dev, "mount-matrix", &hw->orientation); + err = iio_read_mount_matrix(hw->dev, &hw->orientation); if (err) return err; diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 75e92bac78f3..6d2175eb7af2 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -617,7 +617,6 @@ EXPORT_SYMBOL_GPL(iio_show_mount_matrix); * iio_read_mount_matrix() - retrieve iio device mounting matrix from * device "mount-matrix" property * @dev: device the mounting matrix property is assigned to - * @propname: device specific mounting matrix property name * @matrix: where to store retrieved matrix * * If device is assigned no mounting matrix property, a default 3x3 identity @@ -625,14 +624,12 @@ EXPORT_SYMBOL_GPL(iio_show_mount_matrix); * * Return: 0 if success, or a negative error code on failure. */ -int iio_read_mount_matrix(struct device *dev, const char *propname, - struct iio_mount_matrix *matrix) +int iio_read_mount_matrix(struct device *dev, struct iio_mount_matrix *matrix) { size_t len = ARRAY_SIZE(iio_mount_idmatrix.rotation); int err; - err = device_property_read_string_array(dev, propname, - matrix->rotation, len); + err = device_property_read_string_array(dev, "mount-matrix", matrix->rotation, len); if (err == len) return 0; diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c index 24b2f7b1fe44..e54feacfb980 100644 --- a/drivers/iio/magnetometer/ak8974.c +++ b/drivers/iio/magnetometer/ak8974.c @@ -833,8 +833,7 @@ static int ak8974_probe(struct i2c_client *i2c, ak8974->i2c = i2c; mutex_init(&ak8974->lock); - ret = iio_read_mount_matrix(&i2c->dev, "mount-matrix", - &ak8974->orientation); + ret = iio_read_mount_matrix(&i2c->dev, &ak8974->orientation); if (ret) return ret; diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index d988b6ac3659..42b8a2680e3a 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -890,7 +890,7 @@ static int ak8975_probe(struct i2c_client *client, data->reset_gpiod = reset_gpiod; data->eoc_irq = 0; - err = iio_read_mount_matrix(&client->dev, "mount-matrix", &data->orientation); + err = iio_read_mount_matrix(&client->dev, &data->orientation); if (err) return err; diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index 5f28220a7994..f96f53175349 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -890,8 +890,7 @@ int bmc150_magn_probe(struct device *dev, struct regmap *regmap, if (ret) return dev_err_probe(dev, ret, "failed to get regulators\n"); - ret = iio_read_mount_matrix(dev, "mount-matrix", - &data->orientation); + ret = iio_read_mount_matrix(dev, &data->orientation); if (ret) return ret; diff --git a/drivers/iio/magnetometer/hmc5843_core.c b/drivers/iio/magnetometer/hmc5843_core.c index 221563e0c18f..cf62057480cf 100644 --- a/drivers/iio/magnetometer/hmc5843_core.c +++ b/drivers/iio/magnetometer/hmc5843_core.c @@ -637,8 +637,7 @@ int hmc5843_common_probe(struct device *dev, struct regmap *regmap, data->variant = &hmc5843_chip_info_tbl[id]; mutex_init(&data->lock); - ret = iio_read_mount_matrix(dev, "mount-matrix", - &data->orientation); + ret = iio_read_mount_matrix(dev, &data->orientation); if (ret) return ret; diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index 2f2f8cb3c26c..9ff7b0e56cf6 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -831,7 +831,7 @@ static int yas5xx_probe(struct i2c_client *i2c, yas5xx->dev = dev; mutex_init(&yas5xx->lock); - ret = iio_read_mount_matrix(dev, "mount-matrix", &yas5xx->orientation); + ret = iio_read_mount_matrix(dev, &yas5xx->orientation); if (ret) return ret; -- cgit v1.2.3 From 53ebee9499805add3eef630d998c40812e6a1c39 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 18 May 2021 11:27:41 +0200 Subject: iio: afe: iio-rescale: Support processed channels It happens that an ADC will only provide raw or processed voltage conversion channels. (adc/ab8500-gpadc.c). On the Samsung GT-I9070 this is used for a light sensor and current sense amplifier so we need to think of something. The idea is to allow processed channels and scale them with 1/1 and then the rescaler can modify the result on top. Link: https://lore.kernel.org/linux-iio/20201101232211.1194304-1-linus.walleij@linaro.org/ Cc: Peter Rosin Signed-off-by: Linus Walleij Reviewed-by: Peter Rosin Link: https://lore.kernel.org/r/20210518092741.403080-1-linus.walleij@linaro.org Signed-off-by: Jonathan Cameron --- drivers/iio/afe/iio-rescale.c | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c index e42ea2b1707d..774eb3044edd 100644 --- a/drivers/iio/afe/iio-rescale.c +++ b/drivers/iio/afe/iio-rescale.c @@ -29,6 +29,7 @@ struct rescale { struct iio_channel *source; struct iio_chan_spec chan; struct iio_chan_spec_ext_info *ext_info; + bool chan_processed; s32 numerator; s32 denominator; }; @@ -43,10 +44,27 @@ static int rescale_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - return iio_read_channel_raw(rescale->source, val); + if (rescale->chan_processed) + /* + * When only processed channels are supported, we + * read the processed data and scale it by 1/1 + * augmented with whatever the rescaler has calculated. + */ + return iio_read_channel_processed(rescale->source, val); + else + return iio_read_channel_raw(rescale->source, val); case IIO_CHAN_INFO_SCALE: - ret = iio_read_channel_scale(rescale->source, val, val2); + if (rescale->chan_processed) { + /* + * Processed channels are scaled 1-to-1 + */ + *val = 1; + *val2 = 1; + ret = IIO_VAL_FRACTIONAL; + } else { + ret = iio_read_channel_scale(rescale->source, val, val2); + } switch (ret) { case IIO_VAL_FRACTIONAL: *val *= rescale->numerator; @@ -130,16 +148,27 @@ static int rescale_configure_channel(struct device *dev, chan->ext_info = rescale->ext_info; chan->type = rescale->cfg->type; - if (!iio_channel_has_info(schan, IIO_CHAN_INFO_RAW) || - !iio_channel_has_info(schan, IIO_CHAN_INFO_SCALE)) { - dev_err(dev, "source channel does not support raw/scale\n"); + if (iio_channel_has_info(schan, IIO_CHAN_INFO_RAW) || + iio_channel_has_info(schan, IIO_CHAN_INFO_SCALE)) { + dev_info(dev, "using raw+scale source channel\n"); + } else if (iio_channel_has_info(schan, IIO_CHAN_INFO_PROCESSED)) { + dev_info(dev, "using processed channel\n"); + rescale->chan_processed = true; + } else { + dev_err(dev, "source channel is not supported\n"); return -EINVAL; } chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE); - if (iio_channel_has_available(schan, IIO_CHAN_INFO_RAW)) + /* + * Using .read_avail() is fringe to begin with and makes no sense + * whatsoever for processed channels, so we make sure that this cannot + * be called on a processed channel. + */ + if (iio_channel_has_available(schan, IIO_CHAN_INFO_RAW) && + !rescale->chan_processed) chan->info_mask_separate_available |= BIT(IIO_CHAN_INFO_RAW); return 0; -- cgit v1.2.3 From 0990c6e428c81faefc3e6c53291f8ad8080577fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Thu, 20 May 2021 13:59:08 +0200 Subject: iio: adis16260: make use of adis lock helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the adis lib lock helpers to lock the device. This makes things consistent with other users of the library. Signed-off-by: Nuno Sá Link: https://lore.kernel.org/r/20210520115909.466275-2-nuno.sa@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/adis16260.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c index e7c9a3e31c45..56f930bbd341 100644 --- a/drivers/iio/gyro/adis16260.c +++ b/drivers/iio/gyro/adis16260.c @@ -293,7 +293,7 @@ static int adis16260_write_raw(struct iio_dev *indio_dev, addr = adis16260_addresses[chan->scan_index][1]; return adis_write_reg_16(adis, addr, val); case IIO_CHAN_INFO_SAMP_FREQ: - mutex_lock(&adis->state_lock); + adis_dev_lock(adis); if (spi_get_device_id(adis->spi)->driver_data) t = 256 / val; else @@ -310,7 +310,7 @@ static int adis16260_write_raw(struct iio_dev *indio_dev, adis->spi->max_speed_hz = ADIS16260_SPI_FAST; ret = __adis_write_reg_8(adis, ADIS16260_SMPL_PRD, t); - mutex_unlock(&adis->state_lock); + adis_dev_unlock(adis); return ret; } return -EINVAL; -- cgit v1.2.3 From 5d142d41585f5b1fc4d774c0ac368516cbafc493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Thu, 20 May 2021 13:59:09 +0200 Subject: iio: adis16136: make use of adis lock helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the adis lib lock helpers to lock the device. This makes things consistent with other users of the library. Signed-off-by: Nuno Sá Link: https://lore.kernel.org/r/20210520115909.466275-3-nuno.sa@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/adis16136.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c index a11ae9db0d11..d248c8a4a924 100644 --- a/drivers/iio/gyro/adis16136.c +++ b/drivers/iio/gyro/adis16136.c @@ -223,13 +223,12 @@ static ssize_t adis16136_read_frequency(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct adis16136 *adis16136 = iio_priv(indio_dev); - struct mutex *slock = &adis16136->adis.state_lock; unsigned int freq; int ret; - mutex_lock(slock); + adis_dev_lock(&adis16136->adis); ret = __adis16136_get_freq(adis16136, &freq); - mutex_unlock(slock); + adis_dev_unlock(&adis16136->adis); if (ret) return ret; @@ -254,11 +253,10 @@ static const unsigned adis16136_3db_divisors[] = { static int adis16136_set_filter(struct iio_dev *indio_dev, int val) { struct adis16136 *adis16136 = iio_priv(indio_dev); - struct mutex *slock = &adis16136->adis.state_lock; unsigned int freq; int i, ret; - mutex_lock(slock); + adis_dev_lock(&adis16136->adis); ret = __adis16136_get_freq(adis16136, &freq); if (ret) goto out_unlock; @@ -270,7 +268,7 @@ static int adis16136_set_filter(struct iio_dev *indio_dev, int val) ret = __adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i); out_unlock: - mutex_unlock(slock); + adis_dev_unlock(&adis16136->adis); return ret; } @@ -278,12 +276,11 @@ out_unlock: static int adis16136_get_filter(struct iio_dev *indio_dev, int *val) { struct adis16136 *adis16136 = iio_priv(indio_dev); - struct mutex *slock = &adis16136->adis.state_lock; unsigned int freq; uint16_t val16; int ret; - mutex_lock(slock); + adis_dev_lock(&adis16136->adis); ret = __adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, &val16); @@ -297,7 +294,7 @@ static int adis16136_get_filter(struct iio_dev *indio_dev, int *val) *val = freq / adis16136_3db_divisors[val16 & 0x07]; err_unlock: - mutex_unlock(slock); + adis_dev_unlock(&adis16136->adis); return ret ? ret : IIO_VAL_INT; } -- cgit v1.2.3 From 3d8ad94bb175c2de7200569bb706d67c45903838 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 19 May 2021 01:07:19 +0200 Subject: iio: accel: st_sensors: Support generic mounting matrix The ST accelerators support a special type of quirky mounting matrix found in ACPI systems, but not a generic mounting matrix such as from the device tree. Augment the ACPI hack to be a bit more generic and accept a mounting matrix from device properties. This makes it possible to fix orientation on the Ux500 HREF device. Cc: Hans de Goede Cc: Denis Ciocca Cc: Daniel Drake Reviewed-by: Andy Shevchenko Signed-off-by: Stephan Gerhold Signed-off-by: Linus Walleij Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20210518230722.522446-2-linus.walleij@linaro.org Signed-off-by: Jonathan Cameron --- drivers/iio/accel/st_accel_core.c | 112 ++++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 53 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index dc32ebefe3fc..9abcebf767b1 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -41,51 +41,74 @@ #define ST_ACCEL_FS_AVL_200G 200 #define ST_ACCEL_FS_AVL_400G 400 +static const struct iio_mount_matrix * +st_accel_get_mount_matrix(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct st_sensor_data *adata = iio_priv(indio_dev); + + return &adata->mount_matrix; +} + +static const struct iio_chan_spec_ext_info st_accel_mount_matrix_ext_info[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, st_accel_get_mount_matrix), + { } +}; + static const struct iio_chan_spec st_accel_8bit_channels[] = { - ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, + ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 8, 8, - ST_ACCEL_DEFAULT_OUT_X_L_ADDR+1), - ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, + ST_ACCEL_DEFAULT_OUT_X_L_ADDR+1, + st_accel_mount_matrix_ext_info), + ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 8, 8, - ST_ACCEL_DEFAULT_OUT_Y_L_ADDR+1), - ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, + ST_ACCEL_DEFAULT_OUT_Y_L_ADDR+1, + st_accel_mount_matrix_ext_info), + ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 8, 8, - ST_ACCEL_DEFAULT_OUT_Z_L_ADDR+1), + ST_ACCEL_DEFAULT_OUT_Z_L_ADDR+1, + st_accel_mount_matrix_ext_info), IIO_CHAN_SOFT_TIMESTAMP(3) }; static const struct iio_chan_spec st_accel_12bit_channels[] = { - ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, + ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 12, 16, - ST_ACCEL_DEFAULT_OUT_X_L_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, + ST_ACCEL_DEFAULT_OUT_X_L_ADDR, + st_accel_mount_matrix_ext_info), + ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 12, 16, - ST_ACCEL_DEFAULT_OUT_Y_L_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, + ST_ACCEL_DEFAULT_OUT_Y_L_ADDR, + st_accel_mount_matrix_ext_info), + ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 12, 16, - ST_ACCEL_DEFAULT_OUT_Z_L_ADDR), + ST_ACCEL_DEFAULT_OUT_Z_L_ADDR, + st_accel_mount_matrix_ext_info), IIO_CHAN_SOFT_TIMESTAMP(3) }; static const struct iio_chan_spec st_accel_16bit_channels[] = { - ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, + ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16, - ST_ACCEL_DEFAULT_OUT_X_L_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, + ST_ACCEL_DEFAULT_OUT_X_L_ADDR, + st_accel_mount_matrix_ext_info), + ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16, - ST_ACCEL_DEFAULT_OUT_Y_L_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, + ST_ACCEL_DEFAULT_OUT_Y_L_ADDR, + st_accel_mount_matrix_ext_info), + ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16, - ST_ACCEL_DEFAULT_OUT_Z_L_ADDR), + ST_ACCEL_DEFAULT_OUT_Z_L_ADDR, + st_accel_mount_matrix_ext_info), IIO_CHAN_SOFT_TIMESTAMP(3) }; @@ -1162,25 +1185,10 @@ static const struct iio_trigger_ops st_accel_trigger_ops = { #endif #ifdef CONFIG_ACPI -static const struct iio_mount_matrix * -get_mount_matrix(const struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - struct st_sensor_data *adata = iio_priv(indio_dev); - - return adata->mount_matrix; -} - -static const struct iio_chan_spec_ext_info mount_matrix_ext_info[] = { - IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, get_mount_matrix), - { }, -}; - /* Read ST-specific _ONT orientation data from ACPI and generate an * appropriate mount matrix. */ -static int apply_acpi_orientation(struct iio_dev *indio_dev, - struct iio_chan_spec *channels) +static int apply_acpi_orientation(struct iio_dev *indio_dev) { struct st_sensor_data *adata = iio_priv(indio_dev); struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; @@ -1269,14 +1277,6 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev, } /* Convert our integer matrix to a string-based iio_mount_matrix */ - adata->mount_matrix = devm_kmalloc(&indio_dev->dev, - sizeof(*adata->mount_matrix), - GFP_KERNEL); - if (!adata->mount_matrix) { - ret = -ENOMEM; - goto out; - } - for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { int matrix_val = final_ont[i][j]; @@ -1295,26 +1295,25 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev, default: goto out; } - adata->mount_matrix->rotation[i * 3 + j] = str_value; + adata->mount_matrix.rotation[i * 3 + j] = str_value; } } - /* Expose the mount matrix via ext_info */ - for (i = 0; i < indio_dev->num_channels; i++) - channels[i].ext_info = mount_matrix_ext_info; - ret = 0; dev_info(&indio_dev->dev, "computed mount matrix from ACPI\n"); out: kfree(buffer.pointer); + if (ret) + dev_dbg(&indio_dev->dev, + "failed to apply ACPI orientation data: %d\n", ret); + return ret; } #else /* !CONFIG_ACPI */ -static int apply_acpi_orientation(struct iio_dev *indio_dev, - struct iio_chan_spec *channels) +static int apply_acpi_orientation(struct iio_dev *indio_dev) { - return 0; + return -EINVAL; } #endif @@ -1361,9 +1360,16 @@ int st_accel_common_probe(struct iio_dev *indio_dev) if (!channels) return -ENOMEM; - if (apply_acpi_orientation(indio_dev, channels)) - dev_warn(&indio_dev->dev, - "failed to apply ACPI orientation data: %d\n", err); + /* + * First try specific ACPI methods to retrieve orientation then try the + * generic function. + */ + err = apply_acpi_orientation(indio_dev); + if (err) { + err = iio_read_mount_matrix(adata->dev, &adata->mount_matrix); + if (err) + return err; + } indio_dev->channels = channels; adata->current_fullscale = &adata->sensor_settings->fs.fs_avl[0]; -- cgit v1.2.3 From 8d78d1e171fc9fa49900badff0bdf8dd164ce9ae Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 19 May 2021 01:07:20 +0200 Subject: iio: accel: st_sensors: Stop copying channels The channels were copied only so that the .ext_info member should become assignable. We now have compile-time static assignment so drop this code. Cc: Hans de Goede Cc: Denis Ciocca Cc: Daniel Drake Reviewed-by: Andy Shevchenko Signed-off-by: Stephan Gerhold Signed-off-by: Linus Walleij Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20210518230722.522446-3-linus.walleij@linaro.org Signed-off-by: Jonathan Cameron --- drivers/iio/accel/st_accel_core.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 9abcebf767b1..28fceac9f2f6 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -1339,8 +1339,6 @@ int st_accel_common_probe(struct iio_dev *indio_dev) { struct st_sensor_data *adata = iio_priv(indio_dev); struct st_sensors_platform_data *pdata = dev_get_platdata(adata->dev); - struct iio_chan_spec *channels; - size_t channels_size; int err; indio_dev->modes = INDIO_DIRECT_MODE; @@ -1351,15 +1349,9 @@ int st_accel_common_probe(struct iio_dev *indio_dev) return err; adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS; + indio_dev->channels = adata->sensor_settings->ch; indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS; - channels_size = indio_dev->num_channels * sizeof(struct iio_chan_spec); - channels = devm_kmemdup(&indio_dev->dev, - adata->sensor_settings->ch, - channels_size, GFP_KERNEL); - if (!channels) - return -ENOMEM; - /* * First try specific ACPI methods to retrieve orientation then try the * generic function. @@ -1371,7 +1363,6 @@ int st_accel_common_probe(struct iio_dev *indio_dev) return err; } - indio_dev->channels = channels; adata->current_fullscale = &adata->sensor_settings->fs.fs_avl[0]; adata->odr = adata->sensor_settings->odr.odr_avl[0].hz; -- cgit v1.2.3 From d5b920015f506b871073462d70ed432601393546 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 19 May 2021 01:07:21 +0200 Subject: iio: magnetometer: st_magn: Support mount matrix Add support to read and present the mounting matrix on ST magnetometers. Cc: Denis Ciocca Cc: Daniel Drake Cc: Stephan Gerhold Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20210518230722.522446-4-linus.walleij@linaro.org Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/st_magn_core.c | 63 +++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 18 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 1596faa74da9..0048c3cd36ee 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -59,51 +59,74 @@ #define ST_MAGN_4_OUT_Y_L_ADDR 0x0a #define ST_MAGN_4_OUT_Z_L_ADDR 0x0c +static const struct iio_mount_matrix * +st_magn_get_mount_matrix(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct st_sensor_data *mdata = iio_priv(indio_dev); + + return &mdata->mount_matrix; +} + +static const struct iio_chan_spec_ext_info st_magn_mount_matrix_ext_info[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, st_magn_get_mount_matrix), + { } +}; + static const struct iio_chan_spec st_magn_16bit_channels[] = { - ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + ST_SENSORS_LSM_CHANNELS_EXT(IIO_MAGN, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_BE, 16, 16, - ST_MAGN_DEFAULT_OUT_X_H_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + ST_MAGN_DEFAULT_OUT_X_H_ADDR, + st_magn_mount_matrix_ext_info), + ST_SENSORS_LSM_CHANNELS_EXT(IIO_MAGN, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_BE, 16, 16, - ST_MAGN_DEFAULT_OUT_Y_H_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + ST_MAGN_DEFAULT_OUT_Y_H_ADDR, + st_magn_mount_matrix_ext_info), + ST_SENSORS_LSM_CHANNELS_EXT(IIO_MAGN, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_BE, 16, 16, - ST_MAGN_DEFAULT_OUT_Z_H_ADDR), + ST_MAGN_DEFAULT_OUT_Z_H_ADDR, + st_magn_mount_matrix_ext_info), IIO_CHAN_SOFT_TIMESTAMP(3) }; static const struct iio_chan_spec st_magn_2_16bit_channels[] = { - ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + ST_SENSORS_LSM_CHANNELS_EXT(IIO_MAGN, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16, - ST_MAGN_2_OUT_X_L_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + ST_MAGN_2_OUT_X_L_ADDR, + st_magn_mount_matrix_ext_info), + ST_SENSORS_LSM_CHANNELS_EXT(IIO_MAGN, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16, - ST_MAGN_2_OUT_Y_L_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + ST_MAGN_2_OUT_Y_L_ADDR, + st_magn_mount_matrix_ext_info), + ST_SENSORS_LSM_CHANNELS_EXT(IIO_MAGN, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16, - ST_MAGN_2_OUT_Z_L_ADDR), + ST_MAGN_2_OUT_Z_L_ADDR, + st_magn_mount_matrix_ext_info), IIO_CHAN_SOFT_TIMESTAMP(3) }; static const struct iio_chan_spec st_magn_3_16bit_channels[] = { - ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + ST_SENSORS_LSM_CHANNELS_EXT(IIO_MAGN, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16, - ST_MAGN_3_OUT_X_L_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + ST_MAGN_3_OUT_X_L_ADDR, + st_magn_mount_matrix_ext_info), + ST_SENSORS_LSM_CHANNELS_EXT(IIO_MAGN, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16, - ST_MAGN_3_OUT_Y_L_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + ST_MAGN_3_OUT_Y_L_ADDR, + st_magn_mount_matrix_ext_info), + ST_SENSORS_LSM_CHANNELS_EXT(IIO_MAGN, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16, - ST_MAGN_3_OUT_Z_L_ADDR), + ST_MAGN_3_OUT_Z_L_ADDR, + st_magn_mount_matrix_ext_info), IIO_CHAN_SOFT_TIMESTAMP(3) }; @@ -607,6 +630,10 @@ int st_magn_common_probe(struct iio_dev *indio_dev) indio_dev->channels = mdata->sensor_settings->ch; indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS; + err = iio_read_mount_matrix(mdata->dev, &mdata->mount_matrix); + if (err) + return err; + mdata->current_fullscale = &mdata->sensor_settings->fs.fs_avl[0]; mdata->odr = mdata->sensor_settings->odr.odr_avl[0].hz; -- cgit v1.2.3 From e1c5d708bfe0e4bc1a5ce3bded023c1908ec2e19 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 19 May 2021 01:07:22 +0200 Subject: iio: gyro: st_gyro: Support mount matrix Add support to read and present the mounting matrix on ST gyroscopes. Cc: Denis Ciocca Cc: Daniel Drake Cc: Stephan Gerhold Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20210518230722.522446-5-linus.walleij@linaro.org Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/st_gyro_core.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index ee3f0ea96ac5..b86ee4d940d9 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -37,19 +37,36 @@ #define ST_GYRO_FS_AVL_500DPS 500 #define ST_GYRO_FS_AVL_2000DPS 2000 +static const struct iio_mount_matrix * +st_gyro_get_mount_matrix(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct st_sensor_data *gdata = iio_priv(indio_dev); + + return &gdata->mount_matrix; +} + +static const struct iio_chan_spec_ext_info st_gyro_mount_matrix_ext_info[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, st_gyro_get_mount_matrix), + { } +}; + static const struct iio_chan_spec st_gyro_16bit_channels[] = { - ST_SENSORS_LSM_CHANNELS(IIO_ANGL_VEL, + ST_SENSORS_LSM_CHANNELS_EXT(IIO_ANGL_VEL, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16, - ST_GYRO_DEFAULT_OUT_X_L_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_ANGL_VEL, + ST_GYRO_DEFAULT_OUT_X_L_ADDR, + st_gyro_mount_matrix_ext_info), + ST_SENSORS_LSM_CHANNELS_EXT(IIO_ANGL_VEL, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16, - ST_GYRO_DEFAULT_OUT_Y_L_ADDR), - ST_SENSORS_LSM_CHANNELS(IIO_ANGL_VEL, + ST_GYRO_DEFAULT_OUT_Y_L_ADDR, + st_gyro_mount_matrix_ext_info), + ST_SENSORS_LSM_CHANNELS_EXT(IIO_ANGL_VEL, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16, - ST_GYRO_DEFAULT_OUT_Z_L_ADDR), + ST_GYRO_DEFAULT_OUT_Z_L_ADDR, + st_gyro_mount_matrix_ext_info), IIO_CHAN_SOFT_TIMESTAMP(3) }; @@ -479,6 +496,10 @@ int st_gyro_common_probe(struct iio_dev *indio_dev) indio_dev->channels = gdata->sensor_settings->ch; indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS; + err = iio_read_mount_matrix(gdata->dev, &gdata->mount_matrix); + if (err) + return err; + gdata->current_fullscale = &gdata->sensor_settings->fs.fs_avl[0]; gdata->odr = gdata->sensor_settings->odr.odr_avl[0].hz; -- cgit v1.2.3 From 38e9d5caeedb58b5bfdf66567b534698aeb432bc Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 17 May 2021 13:55:54 +0100 Subject: iio: chemical: sgp30: Drop use of %hx in format string. Since: commit cbacb5ab0aa0 ("docs: printk-formats: Stop encouraging use of unnecessary %h[xudi] and %hh[xudi]") use of these format strings has been discouraged. As there are only a few such uses in IIO, lets clear them all out and avoid chance of them getting copied into new drivers. Signed-off-by: Jonathan Cameron Cc: Nathan Chancellor Cc: Andreas Brauchli Reviewed-by: Nathan Chancellor Link: https://lore.kernel.org/r/20210517125554.1463156-5-jic23@kernel.org --- drivers/iio/chemical/sgp30.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/chemical/sgp30.c b/drivers/iio/chemical/sgp30.c index 1029c457be15..2343d444604d 100644 --- a/drivers/iio/chemical/sgp30.c +++ b/drivers/iio/chemical/sgp30.c @@ -425,7 +425,7 @@ static int sgp_check_compat(struct sgp_data *data, product = SGP_VERS_PRODUCT(data); if (product != product_id) { - dev_err(dev, "sensor reports a different product: 0x%04hx\n", + dev_err(dev, "sensor reports a different product: 0x%04x\n", product); return -ENODEV; } -- cgit v1.2.3 From ff9111ab3e1f01cad2318c6bc989c8bf51a570ac Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 16 May 2021 18:25:13 +0100 Subject: iio: adc: max11100: Use get_unaligned_be16() rather than opencoding. The function is more explicit in showing the intent + quicker on some platforms. Signed-off-by: Jonathan Cameron Cc: Jacopo Mondi Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210516172520.1398835-2-jic23@kernel.org --- drivers/iio/adc/max11100.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/max11100.c b/drivers/iio/adc/max11100.c index 6cf21758ca66..69d607fa17aa 100644 --- a/drivers/iio/adc/max11100.c +++ b/drivers/iio/adc/max11100.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -63,7 +64,7 @@ static int max11100_read_single(struct iio_dev *indio_dev, int *val) return -EINVAL; } - *val = (state->buffer[1] << 8) | state->buffer[2]; + *val = get_unaligned_be16(&state->buffer[1]); return 0; } -- cgit v1.2.3 From 7169a78e398463df9201939b51935dc17b53f422 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 16 May 2021 18:25:14 +0100 Subject: iio: adc: max11100: Use devm_ functions for rest of probe() By using devm_add_action_or_reset() to manage the regulator disable, it becomes simple to use managed functions for all of remove. This simplifies error handling and allows us to drop the remove() function entirely. Signed-off-by: Jonathan Cameron Cc: Jacopo Mondi Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210516172520.1398835-3-jic23@kernel.org --- drivers/iio/adc/max11100.c | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/max11100.c b/drivers/iio/adc/max11100.c index 69d607fa17aa..eb1ce6a0315c 100644 --- a/drivers/iio/adc/max11100.c +++ b/drivers/iio/adc/max11100.c @@ -102,6 +102,11 @@ static const struct iio_info max11100_info = { .read_raw = max11100_read_raw, }; +static void max11100_regulator_disable(void *reg) +{ + regulator_disable(reg); +} + static int max11100_probe(struct spi_device *spi) { int ret; @@ -112,8 +117,6 @@ static int max11100_probe(struct spi_device *spi) if (!indio_dev) return -ENOMEM; - spi_set_drvdata(spi, indio_dev); - state = iio_priv(indio_dev); state->spi = spi; @@ -131,27 +134,12 @@ static int max11100_probe(struct spi_device *spi) if (ret) return ret; - ret = iio_device_register(indio_dev); + ret = devm_add_action_or_reset(&spi->dev, max11100_regulator_disable, + state->vref_reg); if (ret) - goto disable_regulator; - - return 0; - -disable_regulator: - regulator_disable(state->vref_reg); - - return ret; -} - -static int max11100_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct max11100_state *state = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - regulator_disable(state->vref_reg); + return ret; - return 0; + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct of_device_id max11100_ids[] = { @@ -166,7 +154,6 @@ static struct spi_driver max11100_driver = { .of_match_table = max11100_ids, }, .probe = max11100_probe, - .remove = max11100_remove, }; module_spi_driver(max11100_driver); -- cgit v1.2.3 From 30b527dd4fc50db0490d8e3e30b37cafd6302cf7 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 16 May 2021 18:25:15 +0100 Subject: iio: adc: max1118: Use devm_ managed functions for all of probe This simplifies error handling and allows us to drop the remove function entirely. Signed-off-by: Jonathan Cameron Cc: Akinobu Mita Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210516172520.1398835-4-jic23@kernel.org --- drivers/iio/adc/max1118.c | 46 +++++++++++++++------------------------------- 1 file changed, 15 insertions(+), 31 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/max1118.c b/drivers/iio/adc/max1118.c index 6efb0b43d938..4dfbed63ad7f 100644 --- a/drivers/iio/adc/max1118.c +++ b/drivers/iio/adc/max1118.c @@ -201,6 +201,11 @@ out: return IRQ_HANDLED; } +static void max1118_reg_disable(void *reg) +{ + regulator_disable(reg); +} + static int max1118_probe(struct spi_device *spi) { struct iio_dev *indio_dev; @@ -225,6 +230,12 @@ static int max1118_probe(struct spi_device *spi) ret = regulator_enable(adc->reg); if (ret) return ret; + + ret = devm_add_action_or_reset(&spi->dev, max1118_reg_disable, + adc->reg); + if (ret) + return ret; + } spi_set_drvdata(spi, indio_dev); @@ -243,38 +254,12 @@ static int max1118_probe(struct spi_device *spi) */ max1118_read(spi, 0); - ret = iio_triggered_buffer_setup(indio_dev, NULL, - max1118_trigger_handler, NULL); + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL, + max1118_trigger_handler, NULL); if (ret) - goto err_reg_disable; - - ret = iio_device_register(indio_dev); - if (ret) - goto err_buffer_cleanup; - - return 0; - -err_buffer_cleanup: - iio_triggered_buffer_cleanup(indio_dev); -err_reg_disable: - if (id->driver_data == max1118) - regulator_disable(adc->reg); - - return ret; -} - -static int max1118_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct max1118 *adc = iio_priv(indio_dev); - const struct spi_device_id *id = spi_get_device_id(spi); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - if (id->driver_data == max1118) - return regulator_disable(adc->reg); + return ret; - return 0; + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id max1118_id[] = { @@ -299,7 +284,6 @@ static struct spi_driver max1118_spi_driver = { .of_match_table = max1118_dt_ids, }, .probe = max1118_probe, - .remove = max1118_remove, .id_table = max1118_id, }; module_spi_driver(max1118_spi_driver); -- cgit v1.2.3 From 3c43b6e108d5fc94dd38638b561ac55a661c3adf Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 16 May 2021 18:25:16 +0100 Subject: iio: adc: max1118: Avoid jumping back and forth between spi and iio structures Changing from passing the spi structure into various functions to passing struct iio_dev avoids use of spi_get_drvdata and lets us stop setting that at all. Previous code was unnecessarily complex. Signed-off-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210516172520.1398835-5-jic23@kernel.org --- drivers/iio/adc/max1118.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/max1118.c b/drivers/iio/adc/max1118.c index 4dfbed63ad7f..8cec9d949083 100644 --- a/drivers/iio/adc/max1118.c +++ b/drivers/iio/adc/max1118.c @@ -66,9 +66,8 @@ static const struct iio_chan_spec max1118_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(2), }; -static int max1118_read(struct spi_device *spi, int channel) +static int max1118_read(struct iio_dev *indio_dev, int channel) { - struct iio_dev *indio_dev = spi_get_drvdata(spi); struct max1118 *adc = iio_priv(indio_dev); struct spi_transfer xfers[] = { /* @@ -103,9 +102,9 @@ static int max1118_read(struct spi_device *spi, int channel) int ret; if (channel == 0) - ret = spi_sync_transfer(spi, xfers + 1, 2); + ret = spi_sync_transfer(adc->spi, xfers + 1, 2); else - ret = spi_sync_transfer(spi, xfers, 3); + ret = spi_sync_transfer(adc->spi, xfers, 3); if (ret) return ret; @@ -113,11 +112,10 @@ static int max1118_read(struct spi_device *spi, int channel) return adc->data; } -static int max1118_get_vref_mV(struct spi_device *spi) +static int max1118_get_vref_mV(struct iio_dev *indio_dev) { - struct iio_dev *indio_dev = spi_get_drvdata(spi); struct max1118 *adc = iio_priv(indio_dev); - const struct spi_device_id *id = spi_get_device_id(spi); + const struct spi_device_id *id = spi_get_device_id(adc->spi); int vref_uV; switch (id->driver_data) { @@ -144,14 +142,14 @@ static int max1118_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: mutex_lock(&adc->lock); - *val = max1118_read(adc->spi, chan->channel); + *val = max1118_read(indio_dev, chan->channel); mutex_unlock(&adc->lock); if (*val < 0) return *val; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - *val = max1118_get_vref_mV(adc->spi); + *val = max1118_get_vref_mV(indio_dev); if (*val < 0) return *val; *val2 = 8; @@ -180,7 +178,7 @@ static irqreturn_t max1118_trigger_handler(int irq, void *p) indio_dev->masklength) { const struct iio_chan_spec *scan_chan = &indio_dev->channels[scan_index]; - int ret = max1118_read(adc->spi, scan_chan->channel); + int ret = max1118_read(indio_dev, scan_chan->channel); if (ret < 0) { dev_warn(&adc->spi->dev, @@ -238,8 +236,6 @@ static int max1118_probe(struct spi_device *spi) } - spi_set_drvdata(spi, indio_dev); - indio_dev->name = spi_get_device_id(spi)->name; indio_dev->info = &max1118_info; indio_dev->modes = INDIO_DIRECT_MODE; @@ -252,7 +248,7 @@ static int max1118_probe(struct spi_device *spi) * a conversion has been completed, the MAX1117/MAX1118/MAX1119 will go * into AutoShutdown mode until the next conversion is initiated. */ - max1118_read(spi, 0); + max1118_read(indio_dev, 0); ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL, max1118_trigger_handler, NULL); -- cgit v1.2.3 From 6c100eb960e785fa327b449ba920d3e83936ae7a Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 16 May 2021 18:25:17 +0100 Subject: iio: adc: ti-adc081c: Use devm managed functions for all of probe() Simplifies error handling and allows us to drop remove() entirely. Signed-off-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210516172520.1398835-6-jic23@kernel.org --- drivers/iio/adc/ti-adc081c.c | 43 ++++++++++++++----------------------------- 1 file changed, 14 insertions(+), 29 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c index b64718daa201..16fc608db36a 100644 --- a/drivers/iio/adc/ti-adc081c.c +++ b/drivers/iio/adc/ti-adc081c.c @@ -146,6 +146,11 @@ out: return IRQ_HANDLED; } +static void adc081c_reg_disable(void *reg) +{ + regulator_disable(reg); +} + static int adc081c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -175,6 +180,11 @@ static int adc081c_probe(struct i2c_client *client, if (err < 0) return err; + err = devm_add_action_or_reset(&client->dev, adc081c_reg_disable, + adc->ref); + if (err) + return err; + iio->name = dev_name(&client->dev); iio->modes = INDIO_DIRECT_MODE; iio->info = &adc081c_info; @@ -182,38 +192,14 @@ static int adc081c_probe(struct i2c_client *client, iio->channels = model->channels; iio->num_channels = ADC081C_NUM_CHANNELS; - err = iio_triggered_buffer_setup(iio, NULL, adc081c_trigger_handler, NULL); + err = devm_iio_triggered_buffer_setup(&client->dev, iio, NULL, + adc081c_trigger_handler, NULL); if (err < 0) { dev_err(&client->dev, "iio triggered buffer setup failed\n"); - goto err_regulator_disable; + return err; } - err = iio_device_register(iio); - if (err < 0) - goto err_buffer_cleanup; - - i2c_set_clientdata(client, iio); - - return 0; - -err_buffer_cleanup: - iio_triggered_buffer_cleanup(iio); -err_regulator_disable: - regulator_disable(adc->ref); - - return err; -} - -static int adc081c_remove(struct i2c_client *client) -{ - struct iio_dev *iio = i2c_get_clientdata(client); - struct adc081c *adc = iio_priv(iio); - - iio_device_unregister(iio); - iio_triggered_buffer_cleanup(iio); - regulator_disable(adc->ref); - - return 0; + return devm_iio_device_register(&client->dev, iio); } static const struct i2c_device_id adc081c_id[] = { @@ -238,7 +224,6 @@ static struct i2c_driver adc081c_driver = { .of_match_table = adc081c_of_match, }, .probe = adc081c_probe, - .remove = adc081c_remove, .id_table = adc081c_id, }; module_i2c_driver(adc081c_driver); -- cgit v1.2.3 From 55364f73a600c92ee012b2dede8d130a26c58a4a Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 16 May 2021 18:25:18 +0100 Subject: iio: adc: ti-adc0832: Use devm managed functions for all of probe() Simplifies error handling, plus allows us to drop the remove() function entirely. Signed-off-by: Jonathan Cameron Cc: Akinobu Mita Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210516172520.1398835-7-jic23@kernel.org --- drivers/iio/adc/ti-adc0832.c | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/ti-adc0832.c b/drivers/iio/adc/ti-adc0832.c index 0261b3cfc92b..fb5e72600b96 100644 --- a/drivers/iio/adc/ti-adc0832.c +++ b/drivers/iio/adc/ti-adc0832.c @@ -236,6 +236,11 @@ out: return IRQ_HANDLED; } +static void adc0832_reg_disable(void *reg) +{ + regulator_disable(reg); +} + static int adc0832_probe(struct spi_device *spi) { struct iio_dev *indio_dev; @@ -287,36 +292,17 @@ static int adc0832_probe(struct spi_device *spi) if (ret) return ret; - spi_set_drvdata(spi, indio_dev); - - ret = iio_triggered_buffer_setup(indio_dev, NULL, - adc0832_trigger_handler, NULL); + ret = devm_add_action_or_reset(&spi->dev, adc0832_reg_disable, + adc->reg); if (ret) - goto err_reg_disable; + return ret; - ret = iio_device_register(indio_dev); + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL, + adc0832_trigger_handler, NULL); if (ret) - goto err_buffer_cleanup; - - return 0; -err_buffer_cleanup: - iio_triggered_buffer_cleanup(indio_dev); -err_reg_disable: - regulator_disable(adc->reg); - - return ret; -} - -static int adc0832_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct adc0832 *adc = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - regulator_disable(adc->reg); + return ret; - return 0; + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct of_device_id adc0832_dt_ids[] = { @@ -343,7 +329,6 @@ static struct spi_driver adc0832_driver = { .of_match_table = adc0832_dt_ids, }, .probe = adc0832_probe, - .remove = adc0832_remove, .id_table = adc0832_id, }; module_spi_driver(adc0832_driver); -- cgit v1.2.3 From 9ecc2ebbb6360101fed75baa0cc7c80769d00b56 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 16 May 2021 18:25:19 +0100 Subject: iio: adc: ti-adc108s102: Use devm managed functions for all of probe() Simplifies error handling and lets us drop remove() entirely. Signed-off-by: Jonathan Cameron Cc: Bogdan Pricop Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210516172520.1398835-8-jic23@kernel.org --- drivers/iio/adc/ti-adc108s102.c | 45 ++++++++++++++--------------------------- 1 file changed, 15 insertions(+), 30 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/ti-adc108s102.c b/drivers/iio/adc/ti-adc108s102.c index 183b2245e89b..db902aef2abe 100644 --- a/drivers/iio/adc/ti-adc108s102.c +++ b/drivers/iio/adc/ti-adc108s102.c @@ -215,6 +215,11 @@ static const struct iio_info adc108s102_info = { .update_scan_mode = &adc108s102_update_scan_mode, }; +static void adc108s102_reg_disable(void *reg) +{ + regulator_disable(reg); +} + static int adc108s102_probe(struct spi_device *spi) { struct adc108s102_state *st; @@ -239,6 +244,10 @@ static int adc108s102_probe(struct spi_device *spi) dev_err(&spi->dev, "Cannot enable vref regulator\n"); return ret; } + ret = devm_add_action_or_reset(&spi->dev, adc108s102_reg_disable, + st->reg); + if (ret) + return ret; ret = regulator_get_voltage(st->reg); if (ret < 0) { @@ -249,7 +258,6 @@ static int adc108s102_probe(struct spi_device *spi) st->va_millivolt = ret / 1000; } - spi_set_drvdata(spi, indio_dev); st->spi = spi; indio_dev->name = spi->modalias; @@ -266,40 +274,18 @@ static int adc108s102_probe(struct spi_device *spi) spi_message_init_with_transfers(&st->scan_single_msg, &st->scan_single_xfer, 1); - ret = iio_triggered_buffer_setup(indio_dev, NULL, - &adc108s102_trigger_handler, NULL); + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL, + &adc108s102_trigger_handler, + NULL); if (ret) - goto error_disable_reg; + return ret; - ret = iio_device_register(indio_dev); - if (ret) { + ret = devm_iio_device_register(&spi->dev, indio_dev); + if (ret) dev_err(&spi->dev, "Failed to register IIO device\n"); - goto error_cleanup_triggered_buffer; - } - return 0; - -error_cleanup_triggered_buffer: - iio_triggered_buffer_cleanup(indio_dev); - -error_disable_reg: - regulator_disable(st->reg); - return ret; } -static int adc108s102_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct adc108s102_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - - regulator_disable(st->reg); - - return 0; -} - static const struct of_device_id adc108s102_of_match[] = { { .compatible = "ti,adc108s102" }, { } @@ -327,7 +313,6 @@ static struct spi_driver adc108s102_driver = { .acpi_match_table = ACPI_PTR(adc108s102_acpi_ids), }, .probe = adc108s102_probe, - .remove = adc108s102_remove, .id_table = adc108s102_id, }; module_spi_driver(adc108s102_driver); -- cgit v1.2.3 From 09f75a2bab0394bf1bab47a476d1d187abf93c06 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 16 May 2021 18:25:20 +0100 Subject: iio: adc: ti-adc161s626: Use devm managed functions for all of probe. Simplifies error handling and allows us to drop remove entirely. The regulator handling in this driver was unusual as it would try to acquire the regulator, but if that failed with an error would continue. We should get a stub regulator if one isn't provided in DT and an error could indicate an actual problem preventing the device being powered (perhaps a need to defer). So this handling is cleaned up (arguably that might be a fix but given no one has run into it, I haven't broken it out separately. Signed-off-by: Jonathan Cameron Cc: Matt Ranostay Acked-by: Matt Ranostay Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210516172520.1398835-9-jic23@kernel.org --- drivers/iio/adc/ti-adc161s626.c | 51 +++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 33 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/ti-adc161s626.c b/drivers/iio/adc/ti-adc161s626.c index 607791ffe7f0..75ca7f1c8726 100644 --- a/drivers/iio/adc/ti-adc161s626.c +++ b/drivers/iio/adc/ti-adc161s626.c @@ -169,6 +169,11 @@ static const struct iio_info ti_adc_info = { .read_raw = ti_adc_read_raw, }; +static void ti_adc_reg_disable(void *reg) +{ + regulator_disable(reg); +} + static int ti_adc_probe(struct spi_device *spi) { struct iio_dev *indio_dev; @@ -182,7 +187,6 @@ static int ti_adc_probe(struct spi_device *spi) indio_dev->info = &ti_adc_info; indio_dev->name = TI_ADC_DRV_NAME; indio_dev->modes = INDIO_DIRECT_MODE; - spi_set_drvdata(spi, indio_dev); data = iio_priv(indio_dev); data->spi = spi; @@ -203,42 +207,24 @@ static int ti_adc_probe(struct spi_device *spi) } data->ref = devm_regulator_get(&spi->dev, "vdda"); - if (!IS_ERR(data->ref)) { - ret = regulator_enable(data->ref); - if (ret < 0) - return ret; - } + if (IS_ERR(data->ref)) + return PTR_ERR(data->ref); - ret = iio_triggered_buffer_setup(indio_dev, NULL, - ti_adc_trigger_handler, NULL); - if (ret) - goto error_regulator_disable; + ret = regulator_enable(data->ref); + if (ret < 0) + return ret; - ret = iio_device_register(indio_dev); + ret = devm_add_action_or_reset(&spi->dev, ti_adc_reg_disable, + data->ref); if (ret) - goto error_unreg_buffer; - - return 0; + return ret; -error_unreg_buffer: - iio_triggered_buffer_cleanup(indio_dev); - -error_regulator_disable: - regulator_disable(data->ref); - - return ret; -} - -static int ti_adc_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct ti_adc_data *data = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - regulator_disable(data->ref); + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL, + ti_adc_trigger_handler, NULL); + if (ret) + return ret; - return 0; + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct of_device_id ti_adc_dt_ids[] = { @@ -261,7 +247,6 @@ static struct spi_driver ti_adc_driver = { .of_match_table = ti_adc_dt_ids, }, .probe = ti_adc_probe, - .remove = ti_adc_remove, .id_table = ti_adc_id, }; module_spi_driver(ti_adc_driver); -- cgit v1.2.3 From eb4e91f42fc9140b7e373675e03a21a7eaec68e3 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 26 May 2021 11:44:08 +0200 Subject: iio: accel: bma180: Add missing 500 Hz / 1000 Hz bandwidth According to the BMA253 datasheet [1] and BMA250 datasheet [2] BMA25x also supports a bandwidth of 500 Hz and 1000 Hz but this was not listed in the driver for some reason. Add it to the bw_table to make the driver match the datasheet. [1]: https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bma253-ds000.pdf [2]: https://datasheet.octopart.com/BMA250-Bosch-datasheet-15540103.pdf Cc: Peter Meerwald Signed-off-by: Stephan Gerhold Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20210526094408.34298-3-stephan@gerhold.net Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bma180.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 97e991581960..4a07e60c0e21 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -182,7 +182,7 @@ static int bma023_scale_table[] = { 2452, 4903, 9709, }; static int bma180_bw_table[] = { 10, 20, 40, 75, 150, 300 }; /* Hz */ static int bma180_scale_table[] = { 1275, 1863, 2452, 3727, 4903, 9709, 19417 }; -static int bma25x_bw_table[] = { 8, 16, 31, 63, 125, 250 }; /* Hz */ +static int bma25x_bw_table[] = { 8, 16, 31, 63, 125, 250, 500, 1000 }; /* Hz */ static int bma25x_scale_table[] = { 0, 0, 0, 38344, 0, 76590, 0, 0, 153180, 0, 0, 0, 306458 }; -- cgit v1.2.3 From 9654c414bfdca1a62d17e8ae1085a5a2703b6a89 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 3 Jun 2021 20:36:16 +0100 Subject: iio: adis: Cleanout unused headers 0-day recently added the include-what-you-use header checker and it gave a warning on an adis patch. As such I decided to run it on all the adis drivers and see if it made sensible suggestions. Note this doesn't represent a complete list of what it suggested changing as I filtered out a few on the basis they are standard headers used to effectively include a bunch of other headers. Could split this into a patch per driver if people prefer. Note to anyone else trying this tool is that it is somewhat of a loose cannon so you will be wanting to carefully check any suggestions before proposing patches! I thought about also reorganising the headers whilst here, but that would make this patch harder to read, or lead to another rather noisy patch across most of the files. Signed-off-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20210603193616.3708447-1-jic23@kernel.org --- drivers/iio/accel/adis16201.c | 3 --- drivers/iio/accel/adis16209.c | 3 --- drivers/iio/gyro/adis16136.c | 5 ----- drivers/iio/gyro/adis16260.c | 5 ----- drivers/iio/imu/adis.c | 4 ---- drivers/iio/imu/adis16400.c | 7 ------- drivers/iio/imu/adis16460.c | 1 - drivers/iio/imu/adis16475.c | 1 - drivers/iio/imu/adis16480.c | 6 ------ 9 files changed, 35 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/adis16201.c b/drivers/iio/accel/adis16201.c index fe225990de24..7a434e2884d4 100644 --- a/drivers/iio/accel/adis16201.c +++ b/drivers/iio/accel/adis16201.c @@ -8,10 +8,7 @@ #include #include #include -#include -#include #include -#include #include #include diff --git a/drivers/iio/accel/adis16209.c b/drivers/iio/accel/adis16209.c index 6c2d4a967de7..ac08e866d612 100644 --- a/drivers/iio/accel/adis16209.c +++ b/drivers/iio/accel/adis16209.c @@ -7,11 +7,8 @@ #include #include -#include #include #include -#include -#include #include #include diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c index d248c8a4a924..36879f01e28c 100644 --- a/drivers/iio/gyro/adis16136.c +++ b/drivers/iio/gyro/adis16136.c @@ -6,19 +6,14 @@ * Author: Lars-Peter Clausen */ -#include -#include -#include #include #include #include -#include #include #include #include #include -#include #include #include diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c index 56f930bbd341..66b6b7bd5e1b 100644 --- a/drivers/iio/gyro/adis16260.c +++ b/drivers/iio/gyro/adis16260.c @@ -5,17 +5,12 @@ * Copyright 2010 Analog Devices Inc. */ -#include -#include #include #include #include -#include #include #include -#include -#include #include #define ADIS16260_STARTUP_DELAY 220 /* ms */ diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c index 319b64b2fd88..a5b421f42287 100644 --- a/drivers/iio/imu/adis.c +++ b/drivers/iio/imu/adis.c @@ -12,14 +12,10 @@ #include #include #include -#include -#include #include #include #include -#include -#include #include #define ADIS_MSC_CTRL_DATA_RDY_EN BIT(2) diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c index cb8d3ffab6fc..641b4f7d066d 100644 --- a/drivers/iio/imu/adis16400.c +++ b/drivers/iio/imu/adis16400.c @@ -10,22 +10,15 @@ * Copyright (c) 2011 Analog Devices Inc. */ -#include #include -#include -#include #include #include #include -#include -#include -#include #include #include #include #include -#include #include #include #include diff --git a/drivers/iio/imu/adis16460.c b/drivers/iio/imu/adis16460.c index 73bf45e859b8..ba373d7aaa2b 100644 --- a/drivers/iio/imu/adis16460.c +++ b/drivers/iio/imu/adis16460.c @@ -5,7 +5,6 @@ * Copyright 2019 Analog Devices Inc. */ -#include #include #include diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index 5654c0c15426..d0e84e5dee6c 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index a9c21a5ae05a..9ec0e61b484f 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -9,24 +9,18 @@ #include #include #include -#include #include -#include #include #include #include -#include -#include #include #include #include #include #include -#include #include #include -#include #include #include -- cgit v1.2.3