diff options
Diffstat (limited to 'drivers/iio')
660 files changed, 26342 insertions, 8417 deletions
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index 661127aed2f9..652557a5b851 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -92,6 +92,7 @@ source "drivers/iio/common/Kconfig" source "drivers/iio/dac/Kconfig" source "drivers/iio/dummy/Kconfig" source "drivers/iio/filter/Kconfig" +source "drivers/iio/flow/Kconfig" source "drivers/iio/frequency/Kconfig" source "drivers/iio/gyro/Kconfig" source "drivers/iio/health/Kconfig" diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index cb80ef837e84..f03a4100c800 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -29,6 +29,7 @@ obj-y += dac/ obj-y += dummy/ obj-y += gyro/ obj-y += filter/ +obj-y += flow/ obj-y += frequency/ obj-y += health/ obj-y += humidity/ diff --git a/drivers/iio/TODO b/drivers/iio/TODO index 2ace27d1ac62..7b05308248d7 100644 --- a/drivers/iio/TODO +++ b/drivers/iio/TODO @@ -5,12 +5,17 @@ Documentation tree - Yaml conversions for abandoned drivers - ABI Documentation - - Audit driviers/iio/staging/Documentation + - Audit drivers/staging/iio/Documentation -- Converting drivers from device tree centric to more generic -property handlers. +- Converting drivers from device tree centric to generic property handlers. - Refactor old platform_data constructs from drivers and convert it -to state struct and using property handlers and readers. + to state struct and using property handlers and readers. + +- Convert selected IIO drivers to use fully device managed resource APIs. + +- Evaluate and possibly adopt cleanup.h helpers (guard()(), __free(), et cetera) + in drivers where manual resource management is still used and there is a + significant improvement to the code flow and complexity to be had. Mailing list: linux-iio@vger.kernel.org diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 3d3f8d8673dd..4094299e2ed8 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -158,24 +158,24 @@ config ADXL372 select IIO_TRIGGERED_BUFFER config ADXL372_SPI - tristate "Analog Devices ADXL372 3-Axis Accelerometer SPI Driver" + tristate "Analog Devices ADXL371/ADXL372 3-Axis Accelerometer SPI Driver" depends on SPI select ADXL372 select REGMAP_SPI help - Say yes here to add support for the Analog Devices ADXL372 triaxial - acceleration sensor. + Say yes here to add support for the Analog Devices ADXL371/ADXL372 + triaxial acceleration sensor. To compile this driver as a module, choose M here: the module will be called adxl372_spi. config ADXL372_I2C - tristate "Analog Devices ADXL372 3-Axis Accelerometer I2C Driver" + tristate "Analog Devices ADXL371/ADXL372 3-Axis Accelerometer I2C Driver" depends on I2C select ADXL372 select REGMAP_I2C help - Say yes here to add support for the Analog Devices ADXL372 triaxial - acceleration sensor. + Say yes here to add support for the Analog Devices ADXL371/ADXL372 + triaxial acceleration sensor. To compile this driver as a module, choose M here: the module will be called adxl372_i2c. diff --git a/drivers/iio/accel/adis16201.c b/drivers/iio/accel/adis16201.c index 5127e58eebc7..ba0f97944c6d 100644 --- a/drivers/iio/accel/adis16201.c +++ b/drivers/iio/accel/adis16201.c @@ -147,7 +147,7 @@ static int adis16201_read_raw(struct iio_dev *indio_dev, /* * The raw ADC value is 1278 when the temperature * is 25 degrees and the scale factor per milli - * degree celcius is -470. + * degree Celsius is -470. */ *val = 25000 / -470 - 1278; return IIO_VAL_INT; diff --git a/drivers/iio/accel/adis16209.c b/drivers/iio/accel/adis16209.c index 41ffd92f27fd..04e169f221c4 100644 --- a/drivers/iio/accel/adis16209.c +++ b/drivers/iio/accel/adis16209.c @@ -186,7 +186,7 @@ static int adis16209_read_raw(struct iio_dev *indio_dev, /* * The raw ADC value is 0x4FE when the temperature * is 45 degrees and the scale factor per milli - * degree celcius is -470. + * degree Celsius is -470. */ *val = 25000 / -470 - 0x4FE; return IIO_VAL_INT; diff --git a/drivers/iio/accel/adxl313_core.c b/drivers/iio/accel/adxl313_core.c index 9f5d4d2cb325..6dc918c4ae17 100644 --- a/drivers/iio/accel/adxl313_core.c +++ b/drivers/iio/accel/adxl313_core.c @@ -8,6 +8,7 @@ */ #include <linux/bitfield.h> +#include <linux/cleanup.h> #include <linux/interrupt.h> #include <linux/module.h> #include <linux/overflow.h> @@ -356,19 +357,15 @@ static int adxl313_read_axis(struct adxl313_data *data, { int ret; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); ret = regmap_bulk_read(data->regmap, ADXL313_REG_DATA_AXIS(chan->address), &data->transf_buf, sizeof(data->transf_buf)); if (ret) - goto unlock_ret; - - ret = le16_to_cpu(data->transf_buf); + return ret; -unlock_ret: - mutex_unlock(&data->lock); - return ret; + return le16_to_cpu(data->transf_buf); } static int adxl313_read_freq_avail(struct iio_dev *indio_dev, @@ -998,6 +995,8 @@ static int adxl313_buffer_predisable(struct iio_dev *indio_dev) ret = regmap_write(data->regmap, ADXL313_REG_FIFO_CTL, FIELD_PREP(ADXL313_REG_FIFO_CTL_MODE_MSK, ADXL313_FIFO_BYPASS)); + if (ret) + return ret; ret = regmap_write(data->regmap, ADXL313_REG_INT_ENABLE, 0); if (ret) @@ -1241,7 +1240,9 @@ int adxl313_core_probe(struct device *dev, data->regmap = regmap; data->chip_info = chip_info; - mutex_init(&data->lock); + ret = devm_mutex_init(dev, &data->lock); + if (ret) + return ret; indio_dev->name = chip_info->name; indio_dev->info = &adxl313_info; @@ -1251,10 +1252,8 @@ int adxl313_core_probe(struct device *dev, indio_dev->available_scan_masks = adxl313_scan_masks; ret = adxl313_setup(dev, data, setup); - if (ret) { - dev_err(dev, "ADXL313 setup failed\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "ADXL313 setup failed\n"); int_line = adxl313_get_int_type(dev, &irq); if (int_line == ADXL313_INT_NONE) { diff --git a/drivers/iio/accel/adxl313_i2c.c b/drivers/iio/accel/adxl313_i2c.c index b67ff0b4dc54..2eea8d4d044b 100644 --- a/drivers/iio/accel/adxl313_i2c.c +++ b/drivers/iio/accel/adxl313_i2c.c @@ -8,7 +8,6 @@ */ #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> @@ -65,6 +64,7 @@ MODULE_DEVICE_TABLE(of, adxl313_of_match); static int adxl313_i2c_probe(struct i2c_client *client) { const struct adxl313_chip_info *chip_data; + struct device *dev = &client->dev; struct regmap *regmap; /* @@ -75,13 +75,10 @@ static int adxl313_i2c_probe(struct i2c_client *client) regmap = devm_regmap_init_i2c(client, &adxl31x_i2c_regmap_config[chip_data->type]); - if (IS_ERR(regmap)) { - dev_err(&client->dev, "Error initializing i2c regmap: %ld\n", - PTR_ERR(regmap)); - return PTR_ERR(regmap); - } + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), "Error initializing i2c regmap\n"); - return adxl313_core_probe(&client->dev, regmap, chip_data, NULL); + return adxl313_core_probe(dev, regmap, chip_data, NULL); } static struct i2c_driver adxl313_i2c_driver = { diff --git a/drivers/iio/accel/adxl313_spi.c b/drivers/iio/accel/adxl313_spi.c index dedb0885c277..a61295de104f 100644 --- a/drivers/iio/accel/adxl313_spi.c +++ b/drivers/iio/accel/adxl313_spi.c @@ -7,7 +7,6 @@ * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL313.pdf */ -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> #include <linux/spi/spi.h> @@ -70,6 +69,7 @@ static int adxl313_spi_setup(struct device *dev, struct regmap *regmap) static int adxl313_spi_probe(struct spi_device *spi) { const struct adxl313_chip_info *chip_data; + struct device *dev = &spi->dev; struct regmap *regmap; int ret; @@ -83,14 +83,10 @@ static int adxl313_spi_probe(struct spi_device *spi) regmap = devm_regmap_init_spi(spi, &adxl31x_spi_regmap_config[chip_data->type]); - if (IS_ERR(regmap)) { - dev_err(&spi->dev, "Error initializing spi regmap: %ld\n", - PTR_ERR(regmap)); - return PTR_ERR(regmap); - } + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), "Error initializing spi regmap\n"); - return adxl313_core_probe(&spi->dev, regmap, - chip_data, &adxl313_spi_setup); + return adxl313_core_probe(dev, regmap, chip_data, &adxl313_spi_setup); } static const struct spi_device_id adxl313_spi_id[] = { diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index 78e3f799ecc1..6c9080d88c60 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -213,6 +213,7 @@ static const struct iio_event_spec adxl345_events[] = { .dir = IIO_EV_DIR_RISING, .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_SCALE) | BIT(IIO_EV_INFO_VALUE), }, { @@ -221,6 +222,7 @@ static const struct iio_event_spec adxl345_events[] = { .dir = IIO_EV_DIR_RISING, .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_SCALE) | BIT(IIO_EV_INFO_VALUE), }, { @@ -228,14 +230,19 @@ static const struct iio_event_spec adxl345_events[] = { .type = IIO_EV_TYPE_GESTURE, .dir = IIO_EV_DIR_SINGLETAP, .mask_separate = BIT(IIO_EV_INFO_ENABLE), - .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | + .mask_shared_by_type = + BIT(IIO_EV_INFO_SCALE) | + BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_TIMEOUT), }, { /* double tap */ .type = IIO_EV_TYPE_GESTURE, .dir = IIO_EV_DIR_DOUBLETAP, - .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) | + .mask_shared_by_type = + BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_SCALE) | + BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_RESET_TIMEOUT) | BIT(IIO_EV_INFO_TAP2_MIN_DELAY), }, @@ -274,6 +281,7 @@ static const struct iio_event_spec adxl345_fake_chan_events[] = { .dir = IIO_EV_DIR_FALLING, .mask_separate = BIT(IIO_EV_INFO_ENABLE), .mask_shared_by_type = + BIT(IIO_EV_INFO_SCALE) | BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_PERIOD), }, @@ -283,6 +291,7 @@ static const struct iio_event_spec adxl345_fake_chan_events[] = { .dir = IIO_EV_DIR_FALLING, .mask_separate = BIT(IIO_EV_INFO_ENABLE), .mask_shared_by_type = + BIT(IIO_EV_INFO_SCALE) | BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_PERIOD), }, @@ -1341,6 +1350,16 @@ static int adxl345_read_event_value(struct iio_dev *indio_dev, unsigned int tap_threshold; int ret; + /* + * The event threshold LSB is fixed at 62.5 mg/LSB + * 0.0625 * 9.80665 = 0.612915625 m/s^2 + */ + if (info == IIO_EV_INFO_SCALE) { + *val = 0; + *val2 = 612915; + return IIO_VAL_INT_PLUS_MICRO; + } + switch (type) { case IIO_EV_TYPE_MAG: return adxl345_read_mag_value(st, dir, info, @@ -1355,12 +1374,6 @@ static int adxl345_read_event_value(struct iio_dev *indio_dev, case IIO_EV_TYPE_GESTURE: switch (info) { case IIO_EV_INFO_VALUE: - /* - * The scale factor would be 62.5mg/LSB (i.e. 0xFF = 16g) but - * not applied here. In context of this general purpose sensor, - * what imports is rather signal intensity than the absolute - * measured g value. - */ ret = regmap_read(st->regmap, ADXL345_REG_THRESH_TAP, &tap_threshold); if (ret) @@ -1401,6 +1414,9 @@ static int adxl345_write_event_value(struct iio_dev *indio_dev, if (ret) return ret; + if (info == IIO_EV_INFO_SCALE) + return -EINVAL; + switch (type) { case IIO_EV_TYPE_MAG: ret = adxl345_write_mag_value(st, dir, info, diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c index af84c0043c6c..511fb610436c 100644 --- a/drivers/iio/accel/adxl345_i2c.c +++ b/drivers/iio/accel/adxl345_i2c.c @@ -43,8 +43,8 @@ static const struct adxl345_chip_info adxl375_i2c_info = { }; static const struct i2c_device_id adxl345_i2c_id[] = { - { "adxl345", (kernel_ulong_t)&adxl345_i2c_info }, - { "adxl375", (kernel_ulong_t)&adxl375_i2c_info }, + { .name = "adxl345", .driver_data = (kernel_ulong_t)&adxl345_i2c_info }, + { .name = "adxl375", .driver_data = (kernel_ulong_t)&adxl375_i2c_info }, { } }; MODULE_DEVICE_TABLE(i2c, adxl345_i2c_id); diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c index 0315f4bfd69a..4fa1b04f75b6 100644 --- a/drivers/iio/accel/adxl345_spi.c +++ b/drivers/iio/accel/adxl345_spi.c @@ -60,8 +60,8 @@ static const struct adxl345_chip_info adxl375_spi_info = { }; static const struct spi_device_id adxl345_spi_id[] = { - { "adxl345", (kernel_ulong_t)&adxl345_spi_info }, - { "adxl375", (kernel_ulong_t)&adxl375_spi_info }, + { .name = "adxl345", .driver_data = (kernel_ulong_t)&adxl345_spi_info }, + { .name = "adxl375", .driver_data = (kernel_ulong_t)&adxl375_spi_info }, { } }; MODULE_DEVICE_TABLE(spi, adxl345_spi_id); diff --git a/drivers/iio/accel/adxl355_core.c b/drivers/iio/accel/adxl355_core.c index 1c1d64d5cbcb..080c9f6f9a11 100644 --- a/drivers/iio/accel/adxl355_core.c +++ b/drivers/iio/accel/adxl355_core.c @@ -17,7 +17,6 @@ #include <linux/limits.h> #include <linux/math64.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/regmap.h> #include <linux/units.h> @@ -336,10 +335,8 @@ static int adxl355_setup(struct adxl355_data *data) return ret; do { - if (--retries == 0) { - dev_err(data->dev, "Shadow registers mismatch\n"); - return -EIO; - } + if (--retries == 0) + return dev_err_probe(data->dev, -EIO, "Shadow registers mismatch\n"); /* * Perform a software reset to make sure the device is in a consistent @@ -351,7 +348,7 @@ static int adxl355_setup(struct adxl355_data *data) return ret; /* Wait at least 5ms after software reset */ - usleep_range(5000, 10000); + fsleep(5 * USEC_PER_MSEC); /* Read shadow registers for comparison */ ret = regmap_bulk_read(data->regmap, @@ -745,7 +742,7 @@ static const struct iio_chan_spec adxl355_channels[] = { BIT(IIO_CHAN_INFO_OFFSET), .scan_index = 3, .scan_type = { - .sign = 's', + .sign = 'u', .realbits = 12, .storagebits = 16, .endianness = IIO_BE, @@ -771,14 +768,11 @@ static int adxl355_probe_trigger(struct iio_dev *indio_dev, int irq) ret = devm_request_irq(data->dev, irq, &iio_trigger_generic_data_rdy_poll, IRQF_NO_THREAD, "adxl355_irq", data->dready_trig); if (ret) - return dev_err_probe(data->dev, ret, "request irq %d failed\n", - irq); + return ret; ret = devm_iio_trigger_register(data->dev, data->dready_trig); - if (ret) { - dev_err(data->dev, "iio trigger register failed\n"); - return ret; - } + if (ret) + return dev_err_probe(data->dev, ret, "iio trigger register failed\n"); indio_dev->trig = iio_trigger_get(data->dready_trig); @@ -802,7 +796,9 @@ int adxl355_core_probe(struct device *dev, struct regmap *regmap, data->dev = dev; data->op_mode = ADXL355_STANDBY; data->chip_info = chip_info; - mutex_init(&data->lock); + ret = devm_mutex_init(dev, &data->lock); + if (ret) + return ret; indio_dev->name = chip_info->name; indio_dev->info = &adxl355_info; @@ -812,18 +808,14 @@ int adxl355_core_probe(struct device *dev, struct regmap *regmap, indio_dev->available_scan_masks = adxl355_avail_scan_masks; ret = adxl355_setup(data); - if (ret) { - dev_err(dev, "ADXL355 setup failed\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "ADXL355 setup failed\n"); ret = devm_iio_triggered_buffer_setup(dev, indio_dev, &iio_pollfunc_store_time, &adxl355_trigger_handler, NULL); - if (ret) { - dev_err(dev, "iio triggered buffer setup failed\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "iio triggered buffer setup failed\n"); irq = fwnode_irq_get_byname(dev_fwnode(dev), "DRDY"); if (irq > 0) { diff --git a/drivers/iio/accel/adxl355_i2c.c b/drivers/iio/accel/adxl355_i2c.c index 1a512c7b792b..e533a7aabd44 100644 --- a/drivers/iio/accel/adxl355_i2c.c +++ b/drivers/iio/accel/adxl355_i2c.c @@ -7,7 +7,6 @@ #include <linux/i2c.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/regmap.h> #include "adxl355.h" @@ -23,6 +22,7 @@ static const struct regmap_config adxl355_i2c_regmap_config = { static int adxl355_i2c_probe(struct i2c_client *client) { struct regmap *regmap; + struct device *dev = &client->dev; const struct adxl355_chip_info *chip_data; chip_data = i2c_get_match_data(client); @@ -30,19 +30,15 @@ static int adxl355_i2c_probe(struct i2c_client *client) return -ENODEV; regmap = devm_regmap_init_i2c(client, &adxl355_i2c_regmap_config); - if (IS_ERR(regmap)) { - dev_err(&client->dev, "Error initializing i2c regmap: %ld\n", - PTR_ERR(regmap)); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), "Error initializing i2c regmap\n"); - return PTR_ERR(regmap); - } - - return adxl355_core_probe(&client->dev, regmap, chip_data); + return adxl355_core_probe(dev, regmap, chip_data); } static const struct i2c_device_id adxl355_i2c_id[] = { - { "adxl355", (kernel_ulong_t)&adxl35x_chip_info[ADXL355] }, - { "adxl359", (kernel_ulong_t)&adxl35x_chip_info[ADXL359] }, + { .name = "adxl355", .driver_data = (kernel_ulong_t)&adxl35x_chip_info[ADXL355] }, + { .name = "adxl359", .driver_data = (kernel_ulong_t)&adxl35x_chip_info[ADXL359] }, { } }; MODULE_DEVICE_TABLE(i2c, adxl355_i2c_id); diff --git a/drivers/iio/accel/adxl355_spi.c b/drivers/iio/accel/adxl355_spi.c index 869e3e57d6f7..d2209ca8ca6e 100644 --- a/drivers/iio/accel/adxl355_spi.c +++ b/drivers/iio/accel/adxl355_spi.c @@ -6,7 +6,6 @@ */ #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/regmap.h> #include <linux/spi/spi.h> #include <linux/property.h> @@ -26,6 +25,7 @@ static const struct regmap_config adxl355_spi_regmap_config = { static int adxl355_spi_probe(struct spi_device *spi) { const struct adxl355_chip_info *chip_data; + struct device *dev = &spi->dev; struct regmap *regmap; chip_data = spi_get_device_match_data(spi); @@ -33,19 +33,15 @@ static int adxl355_spi_probe(struct spi_device *spi) return -EINVAL; regmap = devm_regmap_init_spi(spi, &adxl355_spi_regmap_config); - if (IS_ERR(regmap)) { - dev_err(&spi->dev, "Error initializing spi regmap: %ld\n", - PTR_ERR(regmap)); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), "Error initializing spi regmap\n"); - return PTR_ERR(regmap); - } - - return adxl355_core_probe(&spi->dev, regmap, chip_data); + return adxl355_core_probe(dev, regmap, chip_data); } static const struct spi_device_id adxl355_spi_id[] = { - { "adxl355", (kernel_ulong_t)&adxl35x_chip_info[ADXL355] }, - { "adxl359", (kernel_ulong_t)&adxl35x_chip_info[ADXL359] }, + { .name = "adxl355", .driver_data = (kernel_ulong_t)&adxl35x_chip_info[ADXL355] }, + { .name = "adxl359", .driver_data = (kernel_ulong_t)&adxl35x_chip_info[ADXL359] }, { } }; MODULE_DEVICE_TABLE(spi, adxl355_spi_id); diff --git a/drivers/iio/accel/adxl367.c b/drivers/iio/accel/adxl367.c index 0c04b2bb7efb..4ff1c7a0988b 100644 --- a/drivers/iio/accel/adxl367.c +++ b/drivers/iio/accel/adxl367.c @@ -13,7 +13,6 @@ #include <linux/iio/sysfs.h> #include <linux/interrupt.h> #include <linux/irq.h> -#include <linux/mod_devicetable.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/unaligned.h> @@ -1445,7 +1444,9 @@ int adxl367_probe(struct device *dev, const struct adxl367_ops *ops, st->context = context; st->ops = ops; - mutex_init(&st->lock); + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; indio_dev->channels = adxl367_channels; indio_dev->num_channels = ARRAY_SIZE(adxl367_channels); @@ -1485,7 +1486,7 @@ int adxl367_probe(struct device *dev, const struct adxl367_ops *ops, adxl367_irq_handler, IRQF_ONESHOT, indio_dev->name, indio_dev); if (ret) - return dev_err_probe(st->dev, ret, "Failed to request irq\n"); + return ret; return devm_iio_device_register(dev, indio_dev); } diff --git a/drivers/iio/accel/adxl367_i2c.c b/drivers/iio/accel/adxl367_i2c.c index 1c7d2eb054a2..42e747f5d1a1 100644 --- a/drivers/iio/accel/adxl367_i2c.c +++ b/drivers/iio/accel/adxl367_i2c.c @@ -5,7 +5,6 @@ */ #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> @@ -61,7 +60,7 @@ static int adxl367_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id adxl367_i2c_id[] = { - { "adxl367" }, + { .name = "adxl367" }, { } }; MODULE_DEVICE_TABLE(i2c, adxl367_i2c_id); diff --git a/drivers/iio/accel/adxl367_spi.c b/drivers/iio/accel/adxl367_spi.c index 3fed56bb9054..1d1418452bdc 100644 --- a/drivers/iio/accel/adxl367_spi.c +++ b/drivers/iio/accel/adxl367_spi.c @@ -4,7 +4,6 @@ * Author: Cosmin Tanislav <cosmin.tanislav@analog.com> */ -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> #include <linux/spi/spi.h> @@ -138,7 +137,7 @@ static int adxl367_spi_probe(struct spi_device *spi) } static const struct spi_device_id adxl367_spi_id[] = { - { "adxl367", 0 }, + { .name = "adxl367" }, { } }; MODULE_DEVICE_TABLE(spi, adxl367_spi_id); diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c index 28a8793a53b6..e375d068a3f5 100644 --- a/drivers/iio/accel/adxl372.c +++ b/drivers/iio/accel/adxl372.c @@ -1,12 +1,13 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * ADXL372 3-Axis Digital Accelerometer core driver + * ADXL371/ADXL372 3-Axis Digital Accelerometer core driver * * Copyright 2018 Analog Devices Inc. */ #include <linux/bitfield.h> #include <linux/bitops.h> +#include <linux/cleanup.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/module.h> @@ -180,6 +181,16 @@ enum adxl372_odr { ADXL372_ODR_1600HZ, ADXL372_ODR_3200HZ, ADXL372_ODR_6400HZ, + ADXL372_ODR_NUM +}; + +enum adxl371_odr { + ADXL371_ODR_320HZ, + ADXL371_ODR_640HZ, + ADXL371_ODR_1280HZ, + ADXL371_ODR_2560HZ, + ADXL371_ODR_5120HZ, + ADXL371_ODR_NUM }; enum adxl372_bandwidth { @@ -214,14 +225,67 @@ enum adxl372_fifo_mode { ADXL372_FIFO_OLD_SAVED }; -static const int adxl372_samp_freq_tbl[5] = { - 400, 800, 1600, 3200, 6400, +static const int adxl372_samp_freq_tbl[ADXL372_ODR_NUM] = { + [ADXL372_ODR_400HZ] = 400, + [ADXL372_ODR_800HZ] = 800, + [ADXL372_ODR_1600HZ] = 1600, + [ADXL372_ODR_3200HZ] = 3200, + [ADXL372_ODR_6400HZ] = 6400, +}; + +static const int adxl372_bw_freq_tbl[ADXL372_ODR_NUM] = { + [ADXL372_BW_200HZ] = 200, + [ADXL372_BW_400HZ] = 400, + [ADXL372_BW_800HZ] = 800, + [ADXL372_BW_1600HZ] = 1600, + [ADXL372_BW_3200HZ] = 3200, +}; + +static const int adxl371_samp_freq_tbl[ADXL371_ODR_NUM] = { + [ADXL371_ODR_320HZ] = 320, + [ADXL371_ODR_640HZ] = 640, + [ADXL371_ODR_1280HZ] = 1280, + [ADXL371_ODR_2560HZ] = 2560, + [ADXL371_ODR_5120HZ] = 5120, }; -static const int adxl372_bw_freq_tbl[5] = { - 200, 400, 800, 1600, 3200, +static const int adxl371_bw_freq_tbl[ADXL371_ODR_NUM] = { + [ADXL371_ODR_320HZ] = 160, + [ADXL371_ODR_640HZ] = 320, + [ADXL371_ODR_1280HZ] = 640, + [ADXL371_ODR_2560HZ] = 1280, + [ADXL371_ODR_5120HZ] = 2560, }; +const struct adxl372_chip_info adxl371_chip_info = { + .name = "adxl371", + .samp_freq_tbl = adxl371_samp_freq_tbl, + .bw_freq_tbl = adxl371_bw_freq_tbl, + .num_freqs = ARRAY_SIZE(adxl371_samp_freq_tbl), + .act_time_scale_us = 4125, + .act_time_scale_low_us = 8250, + .inact_time_scale_ms = 16, + .inact_time_scale_low_ms = 32, + .max_odr = ADXL371_ODR_5120HZ, + /* Silicon erratum (er001) causes FIFO data misalignment on ADXL371 */ + .fifo_supported = false, +}; +EXPORT_SYMBOL_NS_GPL(adxl371_chip_info, "IIO_ADXL372"); + +const struct adxl372_chip_info adxl372_chip_info = { + .name = "adxl372", + .samp_freq_tbl = adxl372_samp_freq_tbl, + .bw_freq_tbl = adxl372_bw_freq_tbl, + .num_freqs = ARRAY_SIZE(adxl372_samp_freq_tbl), + .act_time_scale_us = 3300, + .act_time_scale_low_us = 6600, + .inact_time_scale_ms = 13, + .inact_time_scale_low_ms = 26, + .max_odr = ADXL372_ODR_6400HZ, + .fifo_supported = true, +}; +EXPORT_SYMBOL_NS_GPL(adxl372_chip_info, "IIO_ADXL372"); + struct adxl372_axis_lookup { unsigned int bits; enum adxl372_fifo_format fifo_format; @@ -257,8 +321,12 @@ static const struct iio_event_spec adxl372_events[] = { .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_SAMP_FREQ) | \ + .info_mask_shared_by_type = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ .scan_index = index, \ .scan_type = { \ @@ -279,6 +347,7 @@ static const struct iio_chan_spec adxl372_channels[] = { }; struct adxl372_state { + const struct adxl372_chip_info *chip_info; int irq; struct device *dev; struct regmap *regmap; @@ -336,18 +405,14 @@ static ssize_t adxl372_write_threshold_value(struct iio_dev *indio_dev, unsigned struct adxl372_state *st = iio_priv(indio_dev); int ret; - mutex_lock(&st->threshold_m); + guard(mutex)(&st->threshold_m); + ret = regmap_write(st->regmap, addr, ADXL372_THRESH_VAL_H_SEL(threshold)); if (ret < 0) - goto unlock; - - ret = regmap_update_bits(st->regmap, addr + 1, GENMASK(7, 5), - ADXL372_THRESH_VAL_L_SEL(threshold) << 5); - -unlock: - mutex_unlock(&st->threshold_m); + return ret; - return ret; + return regmap_update_bits(st->regmap, addr + 1, GENMASK(7, 5), + ADXL372_THRESH_VAL_L_SEL(threshold) << 5); } static int adxl372_read_axis(struct adxl372_state *st, u8 addr) @@ -471,13 +536,14 @@ static int adxl372_set_activity_time_ms(struct adxl372_state *st, int ret; /* - * 3.3 ms per code is the scale factor of the TIME_ACT register for - * ODR = 6400 Hz. It is 6.6 ms per code for ODR = 3200 Hz and below. + * The scale factor of the TIME_ACT register depends on the ODR. + * A higher scale factor is used at the maximum ODR and a lower + * one at all other rates. */ - if (st->odr == ADXL372_ODR_6400HZ) - scale_factor = 3300; + if (st->odr == st->chip_info->max_odr) + scale_factor = st->chip_info->act_time_scale_us; else - scale_factor = 6600; + scale_factor = st->chip_info->act_time_scale_low_us; reg_val = DIV_ROUND_CLOSEST(act_time_ms * 1000, scale_factor); @@ -501,13 +567,14 @@ static int adxl372_set_inactivity_time_ms(struct adxl372_state *st, int ret; /* - * 13 ms per code is the scale factor of the TIME_INACT register for - * ODR = 6400 Hz. It is 26 ms per code for ODR = 3200 Hz and below. + * The scale factor of the TIME_INACT register depends on the ODR. + * A higher scale factor is used at the maximum ODR and a lower + * one at all other rates. */ - if (st->odr == ADXL372_ODR_6400HZ) - scale_factor = 13; + if (st->odr == st->chip_info->max_odr) + scale_factor = st->chip_info->inact_time_scale_ms; else - scale_factor = 26; + scale_factor = st->chip_info->inact_time_scale_low_ms; res = DIV_ROUND_CLOSEST(inact_time_ms, scale_factor); reg_val_h = (res >> 8) & 0xFF; @@ -717,7 +784,7 @@ static int adxl372_setup(struct adxl372_state *st) if (ret < 0) return ret; - ret = adxl372_set_odr(st, ADXL372_ODR_6400HZ); + ret = adxl372_set_odr(st, st->chip_info->max_odr); if (ret < 0) return ret; @@ -777,10 +844,10 @@ static int adxl372_read_raw(struct iio_dev *indio_dev, *val2 = ADXL372_USCALE; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SAMP_FREQ: - *val = adxl372_samp_freq_tbl[st->odr]; + *val = st->chip_info->samp_freq_tbl[st->odr]; return IIO_VAL_INT; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: - *val = adxl372_bw_freq_tbl[st->bw]; + *val = st->chip_info->bw_freq_tbl[st->bw]; return IIO_VAL_INT; } @@ -796,23 +863,17 @@ static int adxl372_write_raw(struct iio_dev *indio_dev, switch (info) { case IIO_CHAN_INFO_SAMP_FREQ: - odr_index = adxl372_find_closest_match(adxl372_samp_freq_tbl, - ARRAY_SIZE(adxl372_samp_freq_tbl), - val); + odr_index = adxl372_find_closest_match(st->chip_info->samp_freq_tbl, + st->chip_info->num_freqs, + val); ret = adxl372_set_odr(st, odr_index); if (ret < 0) return ret; - /* - * The timer period depends on the ODR selected. - * At 3200 Hz and below, it is 6.6 ms; at 6400 Hz, it is 3.3 ms - */ + /* Recalculate activity time as the timer period depends on ODR */ ret = adxl372_set_activity_time_ms(st, st->act_time_ms); if (ret < 0) return ret; - /* - * The timer period depends on the ODR selected. - * At 3200 Hz and below, it is 26 ms; at 6400 Hz, it is 13 ms - */ + /* Recalculate inactivity time as the timer period depends on ODR */ ret = adxl372_set_inactivity_time_ms(st, st->inact_time_ms); if (ret < 0) return ret; @@ -825,9 +886,9 @@ static int adxl372_write_raw(struct iio_dev *indio_dev, return ret; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: - bw_index = adxl372_find_closest_match(adxl372_bw_freq_tbl, - ARRAY_SIZE(adxl372_bw_freq_tbl), - val); + bw_index = adxl372_find_closest_match(st->chip_info->bw_freq_tbl, + st->chip_info->num_freqs, + val); return adxl372_set_bandwidth(st, bw_index); default: return -EINVAL; @@ -957,24 +1018,6 @@ static int adxl372_write_event_config(struct iio_dev *indio_dev, const struct ii return adxl372_set_interrupts(st, st->int1_bitmask, 0); } -static ssize_t adxl372_show_filter_freq_avail(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct adxl372_state *st = iio_priv(indio_dev); - int i; - size_t len = 0; - - for (i = 0; i <= st->odr; i++) - len += scnprintf(buf + len, PAGE_SIZE - len, - "%d ", adxl372_bw_freq_tbl[i]); - - buf[len - 1] = '\n'; - - return len; -} - static ssize_t adxl372_get_fifo_enabled(struct device *dev, struct device_attribute *attr, char *buf) @@ -1142,25 +1185,38 @@ static const struct iio_trigger_ops adxl372_peak_data_trigger_ops = { .set_trigger_state = adxl372_peak_dready_trig_set_state, }; -static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("400 800 1600 3200 6400"); -static IIO_DEVICE_ATTR(in_accel_filter_low_pass_3db_frequency_available, - 0444, adxl372_show_filter_freq_avail, NULL, 0); - -static struct attribute *adxl372_attributes[] = { - &iio_const_attr_sampling_frequency_available.dev_attr.attr, - &iio_dev_attr_in_accel_filter_low_pass_3db_frequency_available.dev_attr.attr, - NULL, -}; +static int adxl372_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct adxl372_state *st = iio_priv(indio_dev); -static const struct attribute_group adxl372_attrs_group = { - .attrs = adxl372_attributes, -}; + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *vals = st->chip_info->samp_freq_tbl; + *type = IIO_VAL_INT; + *length = st->chip_info->num_freqs; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + *vals = st->chip_info->bw_freq_tbl; + *type = IIO_VAL_INT; + /* + * Bandwidth cannot exceed half the sampling frequency + * (Nyquist), so limit available values based on current ODR. + */ + *length = st->odr + 1; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} static const struct iio_info adxl372_info = { .validate_trigger = &adxl372_validate_trigger, - .attrs = &adxl372_attrs_group, .read_raw = adxl372_read_raw, .write_raw = adxl372_write_raw, + .read_avail = adxl372_read_avail, .read_event_config = adxl372_read_event_config, .write_event_config = adxl372_write_event_config, .read_event_value = adxl372_read_event_value, @@ -1175,8 +1231,57 @@ bool adxl372_readable_noinc_reg(struct device *dev, unsigned int reg) } EXPORT_SYMBOL_NS_GPL(adxl372_readable_noinc_reg, "IIO_ADXL372"); +static int adxl372_buffer_setup(struct iio_dev *indio_dev) +{ + struct adxl372_state *st = iio_priv(indio_dev); + struct device *dev = st->dev; + int ret; + + ret = devm_iio_triggered_buffer_setup_ext(dev, indio_dev, NULL, + adxl372_trigger_handler, + IIO_BUFFER_DIRECTION_IN, + &adxl372_buffer_ops, + adxl372_fifo_attributes); + if (ret) + return ret; + + if (!st->irq) + return 0; + + st->dready_trig = devm_iio_trigger_alloc(dev, "%s-dev%d", + indio_dev->name, + iio_device_id(indio_dev)); + if (!st->dready_trig) + return -ENOMEM; + + st->peak_datardy_trig = devm_iio_trigger_alloc(dev, "%s-dev%d-peak", + indio_dev->name, + iio_device_id(indio_dev)); + if (!st->peak_datardy_trig) + return -ENOMEM; + + st->dready_trig->ops = &adxl372_trigger_ops; + st->peak_datardy_trig->ops = &adxl372_peak_data_trigger_ops; + iio_trigger_set_drvdata(st->dready_trig, indio_dev); + iio_trigger_set_drvdata(st->peak_datardy_trig, indio_dev); + ret = devm_iio_trigger_register(dev, st->dready_trig); + if (ret) + return ret; + + ret = devm_iio_trigger_register(dev, st->peak_datardy_trig); + if (ret) + return ret; + + indio_dev->trig = iio_trigger_get(st->dready_trig); + + return devm_request_irq(dev, st->irq, + iio_trigger_generic_data_rdy_poll, + IRQF_TRIGGER_RISING | IRQF_NO_THREAD, + indio_dev->name, st->dready_trig); +} + int adxl372_probe(struct device *dev, struct regmap *regmap, - int irq, const char *name) + int irq, const struct adxl372_chip_info *chip_info) { struct iio_dev *indio_dev; struct adxl372_state *st; @@ -1192,64 +1297,30 @@ int adxl372_probe(struct device *dev, struct regmap *regmap, st->dev = dev; st->regmap = regmap; st->irq = irq; + st->chip_info = chip_info; - mutex_init(&st->threshold_m); + ret = devm_mutex_init(dev, &st->threshold_m); + if (ret < 0) + return ret; indio_dev->channels = adxl372_channels; indio_dev->num_channels = ARRAY_SIZE(adxl372_channels); - indio_dev->available_scan_masks = adxl372_channel_masks; - indio_dev->name = name; + indio_dev->name = chip_info->name; indio_dev->info = &adxl372_info; - indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; - ret = adxl372_setup(st); - if (ret < 0) { - dev_err(dev, "ADXL372 setup failed\n"); - return ret; + if (chip_info->fifo_supported) { + indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; + indio_dev->available_scan_masks = adxl372_channel_masks; + } else { + indio_dev->modes = INDIO_DIRECT_MODE; } - ret = devm_iio_triggered_buffer_setup_ext(dev, - indio_dev, NULL, - adxl372_trigger_handler, - IIO_BUFFER_DIRECTION_IN, - &adxl372_buffer_ops, - adxl372_fifo_attributes); + ret = adxl372_setup(st); if (ret < 0) - return ret; - - if (st->irq) { - st->dready_trig = devm_iio_trigger_alloc(dev, - "%s-dev%d", - indio_dev->name, - 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, - iio_device_id(indio_dev)); - if (!st->peak_datardy_trig) - return -ENOMEM; - - st->dready_trig->ops = &adxl372_trigger_ops; - st->peak_datardy_trig->ops = &adxl372_peak_data_trigger_ops; - iio_trigger_set_drvdata(st->dready_trig, indio_dev); - iio_trigger_set_drvdata(st->peak_datardy_trig, indio_dev); - ret = devm_iio_trigger_register(dev, st->dready_trig); - if (ret < 0) - return ret; - - ret = devm_iio_trigger_register(dev, st->peak_datardy_trig); - if (ret < 0) - return ret; - - indio_dev->trig = iio_trigger_get(st->dready_trig); + return dev_err_probe(dev, ret, "ADXL372 setup failed\n"); - ret = devm_request_irq(dev, st->irq, - iio_trigger_generic_data_rdy_poll, - IRQF_TRIGGER_RISING | IRQF_NO_THREAD, - indio_dev->name, st->dready_trig); + if (chip_info->fifo_supported) { + ret = adxl372_buffer_setup(indio_dev); if (ret < 0) return ret; } @@ -1259,5 +1330,6 @@ int adxl372_probe(struct device *dev, struct regmap *regmap, EXPORT_SYMBOL_NS_GPL(adxl372_probe, "IIO_ADXL372"); MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>"); -MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer driver"); +MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>"); +MODULE_DESCRIPTION("Analog Devices ADXL371/ADXL372 3-axis accelerometer driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/accel/adxl372.h b/drivers/iio/accel/adxl372.h index 80a0aa9714fc..353a8b3a9d76 100644 --- a/drivers/iio/accel/adxl372.h +++ b/drivers/iio/accel/adxl372.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * ADXL372 3-Axis Digital Accelerometer + * ADXL371/ADXL372 3-Axis Digital Accelerometer * * Copyright 2018 Analog Devices Inc. */ @@ -10,8 +10,24 @@ #define ADXL372_REVID 0x03 +struct adxl372_chip_info { + const char *name; + const int *samp_freq_tbl; + const int *bw_freq_tbl; + unsigned int num_freqs; + unsigned int act_time_scale_us; + unsigned int act_time_scale_low_us; + unsigned int inact_time_scale_ms; + unsigned int inact_time_scale_low_ms; + unsigned int max_odr; + bool fifo_supported; +}; + +extern const struct adxl372_chip_info adxl371_chip_info; +extern const struct adxl372_chip_info adxl372_chip_info; + int adxl372_probe(struct device *dev, struct regmap *regmap, - int irq, const char *name); + int irq, const struct adxl372_chip_info *chip_info); bool adxl372_readable_noinc_reg(struct device *dev, unsigned int reg); #endif /* _ADXL372_H_ */ diff --git a/drivers/iio/accel/adxl372_i2c.c b/drivers/iio/accel/adxl372_i2c.c index 186d4fe9a556..e06ddb9c9a7b 100644 --- a/drivers/iio/accel/adxl372_i2c.c +++ b/drivers/iio/accel/adxl372_i2c.c @@ -1,12 +1,11 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * ADXL372 3-Axis Digital Accelerometer I2C driver + * ADXL371/ADXL372 3-Axis Digital Accelerometer I2C driver * * Copyright 2018 Analog Devices Inc. */ #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> @@ -20,11 +19,13 @@ static const struct regmap_config adxl372_regmap_config = { static int adxl372_i2c_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); + const struct adxl372_chip_info *chip_info; struct regmap *regmap; unsigned int regval; int ret; + chip_info = i2c_get_match_data(client); + regmap = devm_regmap_init_i2c(client, &adxl372_regmap_config); if (IS_ERR(regmap)) return PTR_ERR(regmap); @@ -38,17 +39,19 @@ static int adxl372_i2c_probe(struct i2c_client *client) dev_warn(&client->dev, "I2C might not work properly with other devices on the bus"); - return adxl372_probe(&client->dev, regmap, client->irq, id->name); + return adxl372_probe(&client->dev, regmap, client->irq, chip_info); } static const struct i2c_device_id adxl372_i2c_id[] = { - { "adxl372" }, + { .name = "adxl371", .driver_data = (kernel_ulong_t)&adxl371_chip_info }, + { .name = "adxl372", .driver_data = (kernel_ulong_t)&adxl372_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, adxl372_i2c_id); static const struct of_device_id adxl372_of_match[] = { - { .compatible = "adi,adxl372" }, + { .compatible = "adi,adxl371", .data = &adxl371_chip_info }, + { .compatible = "adi,adxl372", .data = &adxl372_chip_info }, { } }; MODULE_DEVICE_TABLE(of, adxl372_of_match); @@ -65,6 +68,7 @@ static struct i2c_driver adxl372_i2c_driver = { module_i2c_driver(adxl372_i2c_driver); MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>"); -MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer I2C driver"); +MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>"); +MODULE_DESCRIPTION("Analog Devices ADXL371/ADXL372 3-axis accelerometer I2C driver"); MODULE_LICENSE("GPL"); MODULE_IMPORT_NS("IIO_ADXL372"); diff --git a/drivers/iio/accel/adxl372_spi.c b/drivers/iio/accel/adxl372_spi.c index 39941b519c3b..128e148c4e96 100644 --- a/drivers/iio/accel/adxl372_spi.c +++ b/drivers/iio/accel/adxl372_spi.c @@ -1,12 +1,11 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * ADXL372 3-Axis Digital Accelerometer SPI driver + * ADXL371/ADXL372 3-Axis Digital Accelerometer SPI driver * * Copyright 2018 Analog Devices Inc. */ #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/regmap.h> #include <linux/spi/spi.h> @@ -22,24 +21,28 @@ static const struct regmap_config adxl372_spi_regmap_config = { static int adxl372_spi_probe(struct spi_device *spi) { - const struct spi_device_id *id = spi_get_device_id(spi); + const struct adxl372_chip_info *chip_info; struct regmap *regmap; + chip_info = spi_get_device_match_data(spi); + regmap = devm_regmap_init_spi(spi, &adxl372_spi_regmap_config); if (IS_ERR(regmap)) return PTR_ERR(regmap); - return adxl372_probe(&spi->dev, regmap, spi->irq, id->name); + return adxl372_probe(&spi->dev, regmap, spi->irq, chip_info); } static const struct spi_device_id adxl372_spi_id[] = { - { "adxl372", 0 }, + { .name = "adxl371", .driver_data = (kernel_ulong_t)&adxl371_chip_info }, + { .name = "adxl372", .driver_data = (kernel_ulong_t)&adxl372_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, adxl372_spi_id); static const struct of_device_id adxl372_of_match[] = { - { .compatible = "adi,adxl372" }, + { .compatible = "adi,adxl371", .data = &adxl371_chip_info }, + { .compatible = "adi,adxl372", .data = &adxl372_chip_info }, { } }; MODULE_DEVICE_TABLE(of, adxl372_of_match); @@ -56,6 +59,7 @@ static struct spi_driver adxl372_spi_driver = { module_spi_driver(adxl372_spi_driver); MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>"); -MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer SPI driver"); +MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>"); +MODULE_DESCRIPTION("Analog Devices ADXL371/ADXL372 3-axis accelerometer SPI driver"); MODULE_LICENSE("GPL"); MODULE_IMPORT_NS("IIO_ADXL372"); diff --git a/drivers/iio/accel/adxl380.c b/drivers/iio/accel/adxl380.c index 8fab2fdbe147..7dca5523091f 100644 --- a/drivers/iio/accel/adxl380.c +++ b/drivers/iio/accel/adxl380.c @@ -31,7 +31,7 @@ #define ADXL319_ID_VAL 382 #define ADXL380_DEVID_AD_REG 0x00 -#define ADLX380_PART_ID_REG 0x02 +#define ADXL380_PART_ID_REG 0x02 #define ADXL380_X_DATA_H_REG 0x15 #define ADXL380_Y_DATA_H_REG 0x17 @@ -877,7 +877,7 @@ static int adxl380_set_fifo_samples(struct adxl380_state *st) ret = regmap_update_bits(st->regmap, ADXL380_FIFO_CONFIG_0_REG, ADXL380_FIFO_SAMPLES_8_MSK, FIELD_PREP(ADXL380_FIFO_SAMPLES_8_MSK, - (fifo_samples & BIT(8)))); + !!(fifo_samples & BIT(8)))); if (ret) return ret; @@ -1878,7 +1878,7 @@ static int adxl380_setup(struct iio_dev *indio_dev) if (reg_val != ADXL380_DEVID_AD_VAL) dev_warn(st->dev, "Unknown chip id %x\n", reg_val); - ret = regmap_bulk_read(st->regmap, ADLX380_PART_ID_REG, + ret = regmap_bulk_read(st->regmap, ADXL380_PART_ID_REG, &st->transf_buf, 2); if (ret) return ret; @@ -1967,7 +1967,9 @@ int adxl380_probe(struct device *dev, struct regmap *regmap, st->chip_info = chip_info; st->odr = ADXL380_ODR_DSM; - mutex_init(&st->lock); + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; indio_dev->channels = adxl380_channels; indio_dev->num_channels = ARRAY_SIZE(adxl380_channels); diff --git a/drivers/iio/accel/adxl380_i2c.c b/drivers/iio/accel/adxl380_i2c.c index bd8782d08c7d..2673ddbbdc53 100644 --- a/drivers/iio/accel/adxl380_i2c.c +++ b/drivers/iio/accel/adxl380_i2c.c @@ -6,7 +6,6 @@ */ #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> @@ -33,10 +32,10 @@ static int adxl380_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id adxl380_i2c_id[] = { - { "adxl318", (kernel_ulong_t)&adxl318_chip_info }, - { "adxl319", (kernel_ulong_t)&adxl319_chip_info }, - { "adxl380", (kernel_ulong_t)&adxl380_chip_info }, - { "adxl382", (kernel_ulong_t)&adxl382_chip_info }, + { .name = "adxl318", .driver_data = (kernel_ulong_t)&adxl318_chip_info }, + { .name = "adxl319", .driver_data = (kernel_ulong_t)&adxl319_chip_info }, + { .name = "adxl380", .driver_data = (kernel_ulong_t)&adxl380_chip_info }, + { .name = "adxl382", .driver_data = (kernel_ulong_t)&adxl382_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, adxl380_i2c_id); diff --git a/drivers/iio/accel/adxl380_spi.c b/drivers/iio/accel/adxl380_spi.c index 4ead949b24f1..ae8467f4e6c0 100644 --- a/drivers/iio/accel/adxl380_spi.c +++ b/drivers/iio/accel/adxl380_spi.c @@ -5,7 +5,6 @@ * Copyright 2024 Analog Devices Inc. */ -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> #include <linux/spi/spi.h> @@ -35,10 +34,10 @@ static int adxl380_spi_probe(struct spi_device *spi) } static const struct spi_device_id adxl380_spi_id[] = { - { "adxl318", (kernel_ulong_t)&adxl318_chip_info }, - { "adxl319", (kernel_ulong_t)&adxl319_chip_info }, - { "adxl380", (kernel_ulong_t)&adxl380_chip_info }, - { "adxl382", (kernel_ulong_t)&adxl382_chip_info }, + { .name = "adxl318", .driver_data = (kernel_ulong_t)&adxl318_chip_info }, + { .name = "adxl319", .driver_data = (kernel_ulong_t)&adxl319_chip_info }, + { .name = "adxl380", .driver_data = (kernel_ulong_t)&adxl380_chip_info }, + { .name = "adxl382", .driver_data = (kernel_ulong_t)&adxl382_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, adxl380_spi_id); diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 7bc6761f5135..e7dbbd4766dd 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -13,7 +13,6 @@ */ #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/delay.h> @@ -989,10 +988,8 @@ static int bma180_probe(struct i2c_client *client) iio_trigger_generic_data_rdy_poll, IRQF_TRIGGER_RISING | IRQF_NO_THREAD, "bma180_event", data->trig); - if (ret) { - dev_err(dev, "unable to request IRQ\n"); + if (ret) goto err_trigger_free; - } data->trig->ops = &bma180_trigger_ops; iio_trigger_set_drvdata(data->trig, indio_dev); @@ -1083,11 +1080,11 @@ static int bma180_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume); static const struct i2c_device_id bma180_ids[] = { - { "bma023", (kernel_ulong_t)&bma180_part_info[BMA023] }, - { "bma150", (kernel_ulong_t)&bma180_part_info[BMA150] }, - { "bma180", (kernel_ulong_t)&bma180_part_info[BMA180] }, - { "bma250", (kernel_ulong_t)&bma180_part_info[BMA250] }, - { "smb380", (kernel_ulong_t)&bma180_part_info[BMA150] }, + { .name = "bma023", .driver_data = (kernel_ulong_t)&bma180_part_info[BMA023] }, + { .name = "bma150", .driver_data = (kernel_ulong_t)&bma180_part_info[BMA150] }, + { .name = "bma180", .driver_data = (kernel_ulong_t)&bma180_part_info[BMA180] }, + { .name = "bma250", .driver_data = (kernel_ulong_t)&bma180_part_info[BMA250] }, + { .name = "smb380", .driver_data = (kernel_ulong_t)&bma180_part_info[BMA150] }, { } }; diff --git a/drivers/iio/accel/bma220_core.c b/drivers/iio/accel/bma220_core.c index f32d875b994e..b83abfdd84fd 100644 --- a/drivers/iio/accel/bma220_core.c +++ b/drivers/iio/accel/bma220_core.c @@ -11,7 +11,6 @@ #include <linux/cleanup.h> #include <linux/device.h> #include <linux/errno.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/pm.h> @@ -545,8 +544,7 @@ int bma220_common_probe(struct device *dev, struct regmap *regmap, int irq) &bma220_irq_handler, IRQF_ONESHOT, indio_dev->name, indio_dev); if (ret) - return dev_err_probe(dev, ret, - "request irq %d failed\n", irq); + return ret; } ret = devm_add_action_or_reset(dev, bma220_deinit, data); diff --git a/drivers/iio/accel/bma220_i2c.c b/drivers/iio/accel/bma220_i2c.c index 8b6f8e305c8c..7e850e95cb06 100644 --- a/drivers/iio/accel/bma220_i2c.c +++ b/drivers/iio/accel/bma220_i2c.c @@ -10,7 +10,6 @@ #include <linux/bitfield.h> #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> #include <linux/types.h> @@ -47,7 +46,7 @@ static const struct of_device_id bma220_i2c_match[] = { MODULE_DEVICE_TABLE(of, bma220_i2c_match); static const struct i2c_device_id bma220_i2c_id[] = { - { "bma220" }, + { .name = "bma220" }, { } }; MODULE_DEVICE_TABLE(i2c, bma220_i2c_id); diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c index 383ee8a135ee..d6c1087cc3c0 100644 --- a/drivers/iio/accel/bma220_spi.c +++ b/drivers/iio/accel/bma220_spi.c @@ -5,7 +5,6 @@ * Copyright (c) 2016,2020 Intel Corporation. */ -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> #include <linux/types.h> @@ -26,7 +25,7 @@ static int bma220_spi_probe(struct spi_device *spi) } static const struct spi_device_id bma220_spi_id[] = { - { "bma220", 0 }, + { .name = "bma220" }, { } }; diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c index 05f72707f830..7e3cff4cca91 100644 --- a/drivers/iio/accel/bma400_core.c +++ b/drivers/iio/accel/bma400_core.c @@ -1789,8 +1789,7 @@ int bma400_probe(struct device *dev, struct regmap *regmap, int irq, IRQF_TRIGGER_RISING | IRQF_ONESHOT, indio_dev->name, indio_dev); if (ret) - return dev_err_probe(data->dev, ret, - "request irq %d failed\n", irq); + return ret; } ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, diff --git a/drivers/iio/accel/bma400_i2c.c b/drivers/iio/accel/bma400_i2c.c index 24a390c3ae66..a3fb3b81b64c 100644 --- a/drivers/iio/accel/bma400_i2c.c +++ b/drivers/iio/accel/bma400_i2c.c @@ -7,7 +7,6 @@ * I2C address is either 0x14 or 0x15 depending on SDO */ #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> @@ -28,7 +27,7 @@ static int bma400_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id bma400_i2c_ids[] = { - { "bma400" }, + { .name = "bma400" }, { } }; MODULE_DEVICE_TABLE(i2c, bma400_i2c_ids); diff --git a/drivers/iio/accel/bma400_spi.c b/drivers/iio/accel/bma400_spi.c index d386f643515b..7ac0a7881b59 100644 --- a/drivers/iio/accel/bma400_spi.c +++ b/drivers/iio/accel/bma400_spi.c @@ -7,7 +7,6 @@ */ #include <linux/bits.h> #include <linux/init.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> #include <linux/spi/spi.h> @@ -88,7 +87,7 @@ static int bma400_spi_probe(struct spi_device *spi) } static const struct spi_device_id bma400_spi_ids[] = { - { "bma400", 0 }, + { .name = "bma400" }, { } }; MODULE_DEVICE_TABLE(spi, bma400_spi_ids); diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index 42ccf0316ce5..46bb36d9366e 100644 --- a/drivers/iio/accel/bmc150-accel-core.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -851,7 +851,7 @@ static ssize_t bmc150_accel_get_fifo_watermark(struct device *dev, wm = data->watermark; mutex_unlock(&data->mutex); - return sprintf(buf, "%d\n", wm); + return sysfs_emit(buf, "%d\n", wm); } static ssize_t bmc150_accel_get_fifo_state(struct device *dev, @@ -866,7 +866,7 @@ static ssize_t bmc150_accel_get_fifo_state(struct device *dev, state = data->fifo_mode; mutex_unlock(&data->mutex); - return sprintf(buf, "%d\n", state); + return sysfs_emit(buf, "%d\n", state); } static const struct iio_mount_matrix * @@ -988,8 +988,12 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev, do_div(sample_period, count); tstamp = data->timestamp - (count - 1) * sample_period; - if (samples && count > samples) - count = samples; + if (samples) + count = min3(count, samples, BMC150_ACCEL_FIFO_LENGTH); + else + count = min(count, BMC150_ACCEL_FIFO_LENGTH); + + count = min_t(u8, count, BMC150_ACCEL_FIFO_LENGTH); ret = bmc150_accel_fifo_transfer(data, (u8 *)buffer, count); if (ret) diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c index b4604f441553..336866aad20c 100644 --- a/drivers/iio/accel/bmc150-accel-i2c.c +++ b/drivers/iio/accel/bmc150-accel-i2c.c @@ -5,7 +5,6 @@ */ #include <linux/device.h> -#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/acpi.h> @@ -245,16 +244,16 @@ static const struct acpi_device_id bmc150_accel_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match); static const struct i2c_device_id bmc150_accel_id[] = { - {"bma222"}, - {"bma222e"}, - {"bma250e"}, - {"bma253"}, - {"bma254"}, - {"bma255"}, - {"bma280"}, - {"bmc150_accel"}, - {"bmc156_accel", BOSCH_BMC156}, - {"bmi055_accel"}, + { .name = "bma222", .driver_data = BOSCH_UNKNOWN }, + { .name = "bma222e", .driver_data = BOSCH_UNKNOWN }, + { .name = "bma250e", .driver_data = BOSCH_UNKNOWN }, + { .name = "bma253", .driver_data = BOSCH_UNKNOWN }, + { .name = "bma254", .driver_data = BOSCH_UNKNOWN }, + { .name = "bma255", .driver_data = BOSCH_UNKNOWN }, + { .name = "bma280", .driver_data = BOSCH_UNKNOWN }, + { .name = "bmc150_accel", .driver_data = BOSCH_UNKNOWN }, + { .name = "bmc156_accel", .driver_data = BOSCH_BMC156 }, + { .name = "bmi055_accel", .driver_data = BOSCH_UNKNOWN }, { } }; diff --git a/drivers/iio/accel/bmc150-accel-spi.c b/drivers/iio/accel/bmc150-accel-spi.c index 26ce50b37716..405bd7b2d199 100644 --- a/drivers/iio/accel/bmc150-accel-spi.c +++ b/drivers/iio/accel/bmc150-accel-spi.c @@ -5,7 +5,6 @@ */ #include <linux/device.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> #include <linux/spi/spi.h> @@ -53,15 +52,15 @@ static const struct acpi_device_id bmc150_accel_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match); static const struct spi_device_id bmc150_accel_id[] = { - {"bma222"}, - {"bma222e"}, - {"bma250e"}, - {"bma253"}, - {"bma255"}, - {"bma280"}, - {"bmc150_accel"}, - {"bmc156_accel", BOSCH_BMC156}, - {"bmi055_accel"}, + { .name = "bma222", .driver_data = BOSCH_UNKNOWN }, + { .name = "bma222e", .driver_data = BOSCH_UNKNOWN }, + { .name = "bma250e", .driver_data = BOSCH_UNKNOWN }, + { .name = "bma253", .driver_data = BOSCH_UNKNOWN }, + { .name = "bma255", .driver_data = BOSCH_UNKNOWN }, + { .name = "bma280", .driver_data = BOSCH_UNKNOWN }, + { .name = "bmc150_accel", .driver_data = BOSCH_UNKNOWN }, + { .name = "bmc156_accel", .driver_data = BOSCH_BMC156 }, + { .name = "bmi055_accel", .driver_data = BOSCH_UNKNOWN }, { } }; MODULE_DEVICE_TABLE(spi, bmc150_accel_id); diff --git a/drivers/iio/accel/bmi088-accel-i2c.c b/drivers/iio/accel/bmi088-accel-i2c.c index 310f863029bb..aecd66e5685e 100644 --- a/drivers/iio/accel/bmi088-accel-i2c.c +++ b/drivers/iio/accel/bmi088-accel-i2c.c @@ -9,7 +9,6 @@ */ #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> #include <linux/slab.h> @@ -45,9 +44,9 @@ static const struct of_device_id bmi088_of_match[] = { MODULE_DEVICE_TABLE(of, bmi088_of_match); static const struct i2c_device_id bmi088_accel_id[] = { - { "bmi085-accel", BOSCH_BMI085 }, - { "bmi088-accel", BOSCH_BMI088 }, - { "bmi090l-accel", BOSCH_BMI090L }, + { .name = "bmi085-accel", .driver_data = BOSCH_BMI085 }, + { .name = "bmi088-accel", .driver_data = BOSCH_BMI088 }, + { .name = "bmi090l-accel", .driver_data = BOSCH_BMI090L }, { } }; MODULE_DEVICE_TABLE(i2c, bmi088_accel_id); diff --git a/drivers/iio/accel/bmi088-accel-spi.c b/drivers/iio/accel/bmi088-accel-spi.c index 44cb50c76cb1..ae89e162e097 100644 --- a/drivers/iio/accel/bmi088-accel-spi.c +++ b/drivers/iio/accel/bmi088-accel-spi.c @@ -72,9 +72,9 @@ static const struct of_device_id bmi088_of_match[] = { MODULE_DEVICE_TABLE(of, bmi088_of_match); static const struct spi_device_id bmi088_accel_id[] = { - {"bmi085-accel", BOSCH_BMI085}, - {"bmi088-accel", BOSCH_BMI088}, - {"bmi090l-accel", BOSCH_BMI090L}, + { .name = "bmi085-accel", .driver_data = BOSCH_BMI085 }, + { .name = "bmi088-accel", .driver_data = BOSCH_BMI088 }, + { .name = "bmi090l-accel", .driver_data = BOSCH_BMI090L }, { } }; MODULE_DEVICE_TABLE(spi, bmi088_accel_id); diff --git a/drivers/iio/accel/da280.c b/drivers/iio/accel/da280.c index c2dd123b9021..15acbe1c2cbd 100644 --- a/drivers/iio/accel/da280.c +++ b/drivers/iio/accel/da280.c @@ -162,9 +162,9 @@ static const struct acpi_device_id da280_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, da280_acpi_match); static const struct i2c_device_id da280_i2c_id[] = { - { "da217", (kernel_ulong_t)&da217_match_data }, - { "da226", (kernel_ulong_t)&da226_match_data }, - { "da280", (kernel_ulong_t)&da280_match_data }, + { .name = "da217", .driver_data = (kernel_ulong_t)&da217_match_data }, + { .name = "da226", .driver_data = (kernel_ulong_t)&da226_match_data }, + { .name = "da280", .driver_data = (kernel_ulong_t)&da280_match_data }, { } }; MODULE_DEVICE_TABLE(i2c, da280_i2c_id); diff --git a/drivers/iio/accel/da311.c b/drivers/iio/accel/da311.c index e1df7b009d89..dcb69c8eaf09 100644 --- a/drivers/iio/accel/da311.c +++ b/drivers/iio/accel/da311.c @@ -268,7 +268,7 @@ static int da311_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(da311_pm_ops, da311_suspend, da311_resume); static const struct i2c_device_id da311_i2c_id[] = { - { "da311" }, + { .name = "da311" }, { } }; MODULE_DEVICE_TABLE(i2c, da311_i2c_id); diff --git a/drivers/iio/accel/dmard06.c b/drivers/iio/accel/dmard06.c index 33f225d73e7b..82816fa44354 100644 --- a/drivers/iio/accel/dmard06.c +++ b/drivers/iio/accel/dmard06.c @@ -6,7 +6,6 @@ */ #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/iio/iio.h> @@ -199,9 +198,9 @@ static DEFINE_SIMPLE_DEV_PM_OPS(dmard06_pm_ops, dmard06_suspend, dmard06_resume); static const struct i2c_device_id dmard06_id[] = { - { "dmard05" }, - { "dmard06" }, - { "dmard07" }, + { .name = "dmard05" }, + { .name = "dmard06" }, + { .name = "dmard07" }, { } }; MODULE_DEVICE_TABLE(i2c, dmard06_id); diff --git a/drivers/iio/accel/dmard09.c b/drivers/iio/accel/dmard09.c index d9290e3b9c46..6f0497ab6133 100644 --- a/drivers/iio/accel/dmard09.c +++ b/drivers/iio/accel/dmard09.c @@ -8,6 +8,7 @@ #include <linux/unaligned.h> #include <linux/module.h> #include <linux/i2c.h> +#include <linux/units.h> #include <linux/iio/iio.h> #define DMARD09_DRV_NAME "dmard09" @@ -79,6 +80,12 @@ static int dmard09_read_raw(struct iio_dev *indio_dev, *val = accel; return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + /* 1 g / 32 LSB, in m/s^2 */ + *val2 = IIO_G_TO_M_S_2(NANO / 32); + + return IIO_VAL_INT_PLUS_NANO; default: return -EINVAL; } @@ -123,7 +130,7 @@ static int dmard09_probe(struct i2c_client *client) } static const struct i2c_device_id dmard09_id[] = { - { "dmard09" }, + { .name = "dmard09" }, { } }; diff --git a/drivers/iio/accel/dmard10.c b/drivers/iio/accel/dmard10.c index 575e8510e1bd..8ba00fd57901 100644 --- a/drivers/iio/accel/dmard10.c +++ b/drivers/iio/accel/dmard10.c @@ -229,7 +229,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(dmard10_pm_ops, dmard10_suspend, dmard10_resume); static const struct i2c_device_id dmard10_i2c_id[] = { - { "dmard10" }, + { .name = "dmard10" }, { } }; MODULE_DEVICE_TABLE(i2c, dmard10_i2c_id); diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index 8763e91c63d2..18d7b09bddd2 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -17,7 +17,6 @@ #include <linux/i2c.h> #include <linux/irq.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/pm_runtime.h> #include <linux/property.h> #include <linux/regulator/consumer.h> @@ -970,6 +969,8 @@ static int fxls8962af_fifo_flush(struct iio_dev *indio_dev) if (!count) return 0; + count = min(count, FXLS8962AF_FIFO_LENGTH); + data->old_timestamp = data->timestamp; data->timestamp = iio_get_time_ns(indio_dev); diff --git a/drivers/iio/accel/fxls8962af-i2c.c b/drivers/iio/accel/fxls8962af-i2c.c index 106198a12474..e72842b1459e 100644 --- a/drivers/iio/accel/fxls8962af-i2c.c +++ b/drivers/iio/accel/fxls8962af-i2c.c @@ -8,7 +8,6 @@ #include <linux/dev_printk.h> #include <linux/err.h> #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> @@ -28,10 +27,10 @@ static int fxls8962af_probe(struct i2c_client *client) } static const struct i2c_device_id fxls8962af_id[] = { - { "fxls8962af", fxls8962af }, - { "fxls8964af", fxls8964af }, - { "fxls8967af", fxls8967af }, - { "fxls8974cf", fxls8974cf }, + { .name = "fxls8962af", .driver_data = fxls8962af }, + { .name = "fxls8964af", .driver_data = fxls8964af }, + { .name = "fxls8967af", .driver_data = fxls8967af }, + { .name = "fxls8974cf", .driver_data = fxls8974cf }, { } }; MODULE_DEVICE_TABLE(i2c, fxls8962af_id); diff --git a/drivers/iio/accel/fxls8962af-spi.c b/drivers/iio/accel/fxls8962af-spi.c index bdafd1f615d9..baf3c4352f14 100644 --- a/drivers/iio/accel/fxls8962af-spi.c +++ b/drivers/iio/accel/fxls8962af-spi.c @@ -8,7 +8,6 @@ #include <linux/dev_printk.h> #include <linux/err.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/spi/spi.h> #include <linux/regmap.h> @@ -35,8 +34,8 @@ static const struct of_device_id fxls8962af_spi_of_match[] = { MODULE_DEVICE_TABLE(of, fxls8962af_spi_of_match); static const struct spi_device_id fxls8962af_spi_id_table[] = { - { "fxls8962af", fxls8962af }, - { "fxls8964af", fxls8964af }, + { .name = "fxls8962af", .driver_data = fxls8962af }, + { .name = "fxls8964af", .driver_data = fxls8964af }, { } }; MODULE_DEVICE_TABLE(spi, fxls8962af_spi_id_table); diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index 2ff591b3458f..eb521125f4eb 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -3,10 +3,10 @@ * HID Sensors Driver * Copyright (c) 2012, Intel Corporation. */ +#include <linux/bitops.h> #include <linux/device.h> #include <linux/platform_device.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/slab.h> #include <linux/hid-sensor-hub.h> #include <linux/iio/iio.h> @@ -119,22 +119,10 @@ static const struct iio_chan_spec gravity_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP), }; -/* Adjust channel real bits based on report descriptor */ -static void accel_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels, - int channel, int size) -{ - channels[channel].scan_type.sign = 's'; - /* Real storage bits will change based on the report desc. */ - channels[channel].scan_type.realbits = size * 8; - /* Maximum size of a sample to capture is u32 */ - channels[channel].scan_type.storagebits = sizeof(u32) * 8; -} - /* Channel read_raw handler */ static int accel_3d_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, - long mask) + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { struct accel_3d_state *accel_state = iio_priv(indio_dev); int report_id = -1; @@ -161,7 +149,7 @@ static int accel_3d_read_raw(struct iio_dev *indio_dev, else { *val = 0; hid_sensor_power_state(&accel_state->common_attributes, - false); + false); return -EINVAL; } hid_sensor_power_state(&accel_state->common_attributes, false); @@ -194,10 +182,8 @@ static int accel_3d_read_raw(struct iio_dev *indio_dev, /* Channel write_raw handler */ static int accel_3d_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct accel_3d_state *accel_state = iio_priv(indio_dev); int ret = 0; @@ -233,8 +219,7 @@ static void hid_sensor_push_data(struct iio_dev *indio_dev, void *data, /* Callback handler to send event after all samples are received and captured */ static int accel_3d_proc_event(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - void *priv) + u32 usage_id, void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct accel_3d_state *accel_state = iio_priv(indio_dev); @@ -257,9 +242,9 @@ static int accel_3d_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int accel_3d_capture_sample(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - size_t raw_len, char *raw_data, - void *priv) + u32 usage_id, + size_t raw_len, char *raw_data, + void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct accel_3d_state *accel_state = iio_priv(indio_dev); @@ -291,31 +276,32 @@ static int accel_3d_capture_sample(struct hid_sensor_hub_device *hsdev, /* Parse report which is specific to an usage id*/ static int accel_3d_parse_report(struct platform_device *pdev, - struct hid_sensor_hub_device *hsdev, - struct iio_chan_spec *channels, - unsigned usage_id, - struct accel_3d_state *st) + struct hid_sensor_hub_device *hsdev, + struct iio_chan_spec *channels, + u32 usage_id, + struct accel_3d_state *st) { int ret; - int i; - for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) { + for (unsigned int ch = CHANNEL_SCAN_INDEX_X; ch <= CHANNEL_SCAN_INDEX_Z; ch++) { ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT, usage_id, - HID_USAGE_SENSOR_ACCEL_X_AXIS + i, - &st->accel[CHANNEL_SCAN_INDEX_X + i]); + HID_USAGE_SENSOR_ACCEL_X_AXIS + ch, + &st->accel[ch]); if (ret < 0) break; - accel_3d_adjust_channel_bit_mask(channels, - CHANNEL_SCAN_INDEX_X + i, - st->accel[CHANNEL_SCAN_INDEX_X + i].size); + channels[ch].scan_type = (struct iio_scan_type) { + .format = 's', + .realbits = BYTES_TO_BITS(st->accel[ch].size), + .storagebits = BITS_PER_TYPE(u32), + }; } dev_dbg(&pdev->dev, "accel_3d %x:%x, %x:%x, %x:%x\n", - st->accel[0].index, - st->accel[0].report_id, - st->accel[1].index, st->accel[1].report_id, - st->accel[2].index, st->accel[2].report_id); + st->accel[0].index, + st->accel[0].report_id, + st->accel[1].index, st->accel[1].report_id, + st->accel[2].index, st->accel[2].report_id); st->scale_precision = hid_sensor_format_scale( hsdev->usage, @@ -338,7 +324,7 @@ static int hid_accel_3d_probe(struct platform_device *pdev) indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct accel_3d_state)); - if (indio_dev == NULL) + if (!indio_dev) return -ENOMEM; platform_set_drvdata(pdev, indio_dev); @@ -375,8 +361,8 @@ static int hid_accel_3d_probe(struct platform_device *pdev) return -ENOMEM; } ret = accel_3d_parse_report(pdev, hsdev, - (struct iio_chan_spec *)indio_dev->channels, - hsdev->usage, accel_state); + (struct iio_chan_spec *)indio_dev->channels, + hsdev->usage, accel_state); if (ret) { dev_err(&pdev->dev, "failed to setup attributes\n"); return ret; @@ -389,32 +375,32 @@ static int hid_accel_3d_probe(struct platform_device *pdev) atomic_set(&accel_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, - &accel_state->common_attributes); + &accel_state->common_attributes); if (ret < 0) { dev_err(&pdev->dev, "trigger setup failed\n"); return ret; } - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(&pdev->dev, "device register failed\n"); - goto error_remove_trigger; - } - accel_state->callbacks.send_event = accel_3d_proc_event; accel_state->callbacks.capture_sample = accel_3d_capture_sample; accel_state->callbacks.pdev = pdev; ret = sensor_hub_register_callback(hsdev, hsdev->usage, - &accel_state->callbacks); + &accel_state->callbacks); if (ret < 0) { dev_err(&pdev->dev, "callback reg failed\n"); - goto error_iio_unreg; + goto error_remove_trigger; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "device register failed\n"); + goto error_remove_callback; } return ret; -error_iio_unreg: - iio_device_unregister(indio_dev); +error_remove_callback: + sensor_hub_remove_callback(hsdev, hsdev->usage); error_remove_trigger: hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes); return ret; @@ -427,8 +413,8 @@ static void hid_accel_3d_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct accel_3d_state *accel_state = iio_priv(indio_dev); - sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); + sensor_hub_remove_callback(hsdev, hsdev->usage); hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes); } diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c index 39485572a76b..02dd1db7a646 100644 --- a/drivers/iio/accel/kionix-kx022a.c +++ b/drivers/iio/accel/kionix-kx022a.c @@ -1435,7 +1435,7 @@ int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chi &kx022a_irq_thread_handler, IRQF_ONESHOT, name, idev); if (ret) - return dev_err_probe(data->dev, ret, "Could not request IRQ\n"); + return ret; ret = devm_iio_trigger_register(dev, indio_trig); if (ret) diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 2823ddde4bf2..166fb786425f 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -8,7 +8,6 @@ #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/bitops.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/string.h> @@ -1630,11 +1629,11 @@ static const struct dev_pm_ops kxcjk1013_pm_ops = { }; static const struct i2c_device_id kxcjk1013_id[] = { - { "kxcjk1013", (kernel_ulong_t)&kxcjk1013_info }, - { "kxcj91008", (kernel_ulong_t)&kxcj91008_info }, - { "kxtj21009", (kernel_ulong_t)&kxtj21009_info }, - { "kxtf9", (kernel_ulong_t)&kxtf9_info }, - { "kx023-1025", (kernel_ulong_t)&kx0231025_info }, + { .name = "kxcjk1013", .driver_data = (kernel_ulong_t)&kxcjk1013_info }, + { .name = "kxcj91008", .driver_data = (kernel_ulong_t)&kxcj91008_info }, + { .name = "kxtj21009", .driver_data = (kernel_ulong_t)&kxtj21009_info }, + { .name = "kxtf9", .driver_data = (kernel_ulong_t)&kxtf9_info }, + { .name = "kx023-1025", .driver_data = (kernel_ulong_t)&kx0231025_info }, { } }; MODULE_DEVICE_TABLE(i2c, kxcjk1013_id); diff --git a/drivers/iio/accel/kxsd9-i2c.c b/drivers/iio/accel/kxsd9-i2c.c index 1fa88b99149e..f19626c2f70f 100644 --- a/drivers/iio/accel/kxsd9-i2c.c +++ b/drivers/iio/accel/kxsd9-i2c.c @@ -2,7 +2,6 @@ #include <linux/device.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/slab.h> #include <linux/i2c.h> #include <linux/delay.h> @@ -43,7 +42,7 @@ static const struct of_device_id kxsd9_of_match[] = { MODULE_DEVICE_TABLE(of, kxsd9_of_match); static const struct i2c_device_id kxsd9_i2c_id[] = { - { "kxsd9" }, + { .name = "kxsd9" }, { } }; MODULE_DEVICE_TABLE(i2c, kxsd9_i2c_id); diff --git a/drivers/iio/accel/kxsd9-spi.c b/drivers/iio/accel/kxsd9-spi.c index cbb6c6412665..71da958d4051 100644 --- a/drivers/iio/accel/kxsd9-spi.c +++ b/drivers/iio/accel/kxsd9-spi.c @@ -3,7 +3,6 @@ #include <linux/kernel.h> #include <linux/spi/spi.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/slab.h> #include <linux/regmap.h> @@ -37,7 +36,7 @@ static void kxsd9_spi_remove(struct spi_device *spi) } static const struct spi_device_id kxsd9_spi_id[] = { - {"kxsd9", 0}, + { .name = "kxsd9" }, { } }; MODULE_DEVICE_TABLE(spi, kxsd9_spi_id); diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c index 4717d80fc24a..7ac885d94d7f 100644 --- a/drivers/iio/accel/kxsd9.c +++ b/drivers/iio/accel/kxsd9.c @@ -147,8 +147,9 @@ static int kxsd9_write_raw(struct iio_dev *indio_dev, if (mask == IIO_CHAN_INFO_SCALE) { /* Check no integer component */ if (val) - return -EINVAL; - ret = kxsd9_write_scale(indio_dev, val2); + ret = -EINVAL; + else + ret = kxsd9_write_scale(indio_dev, val2); } pm_runtime_put_autosuspend(st->dev); diff --git a/drivers/iio/accel/mc3230.c b/drivers/iio/accel/mc3230.c index 3e494f9ddc56..b45897210a62 100644 --- a/drivers/iio/accel/mc3230.c +++ b/drivers/iio/accel/mc3230.c @@ -230,8 +230,8 @@ static int mc3230_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(mc3230_pm_ops, mc3230_suspend, mc3230_resume); static const struct i2c_device_id mc3230_i2c_id[] = { - { "mc3230", (kernel_ulong_t)&mc3230_chip_info }, - { "mc3510c", (kernel_ulong_t)&mc3510c_chip_info }, + { .name = "mc3230", .driver_data = (kernel_ulong_t)&mc3230_chip_info }, + { .name = "mc3510c", .driver_data = (kernel_ulong_t)&mc3510c_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, mc3230_i2c_id); diff --git a/drivers/iio/accel/mma7455_i2c.c b/drivers/iio/accel/mma7455_i2c.c index 2ff8eb1f9ce9..9588fd133b1e 100644 --- a/drivers/iio/accel/mma7455_i2c.c +++ b/drivers/iio/accel/mma7455_i2c.c @@ -32,8 +32,8 @@ static void mma7455_i2c_remove(struct i2c_client *i2c) } static const struct i2c_device_id mma7455_i2c_ids[] = { - { "mma7455" }, - { "mma7456" }, + { .name = "mma7455" }, + { .name = "mma7456" }, { } }; MODULE_DEVICE_TABLE(i2c, mma7455_i2c_ids); diff --git a/drivers/iio/accel/mma7455_spi.c b/drivers/iio/accel/mma7455_spi.c index aca02e83f789..872c47acf882 100644 --- a/drivers/iio/accel/mma7455_spi.c +++ b/drivers/iio/accel/mma7455_spi.c @@ -28,8 +28,8 @@ static void mma7455_spi_remove(struct spi_device *spi) } static const struct spi_device_id mma7455_spi_ids[] = { - { "mma7455", 0 }, - { "mma7456", 0 }, + { .name = "mma7455" }, + { .name = "mma7456" }, { } }; MODULE_DEVICE_TABLE(spi, mma7455_spi_ids); diff --git a/drivers/iio/accel/mma7660.c b/drivers/iio/accel/mma7660.c index be3213600cf4..38b4df76cff3 100644 --- a/drivers/iio/accel/mma7660.c +++ b/drivers/iio/accel/mma7660.c @@ -8,7 +8,6 @@ */ #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -259,7 +258,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mma7660_pm_ops, mma7660_suspend, mma7660_resume); static const struct i2c_device_id mma7660_i2c_id[] = { - { "mma7660" }, + { .name = "mma7660" }, { } }; MODULE_DEVICE_TABLE(i2c, mma7660_i2c_id); diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 15172ba2972c..7d683686dd9d 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -18,21 +18,21 @@ * TODO: orientation events */ +#include <linux/delay.h> +#include <linux/i2c.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> +#include <linux/pm_runtime.h> #include <linux/property.h> -#include <linux/i2c.h> +#include <linux/types.h> +#include <linux/regulator/consumer.h> + +#include <linux/iio/buffer.h> +#include <linux/iio/events.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> -#include <linux/iio/buffer.h> #include <linux/iio/trigger.h> #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> -#include <linux/iio/events.h> -#include <linux/delay.h> -#include <linux/pm_runtime.h> -#include <linux/regulator/consumer.h> -#include <linux/types.h> #define MMA8452_STATUS 0x00 #define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0)) @@ -252,6 +252,8 @@ static int mma8452_read(struct mma8452_data *data, __be16 buf[3]) ret = i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X, 3 * sizeof(__be16), (u8 *)buf); + if (ret < 0) + return ret; ret = mma8452_set_runtime_pm_state(data->client, false); @@ -704,8 +706,8 @@ static int mma8452_set_hp_filter_frequency(struct mma8452_data *data, } static int __mma8452_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct mma8452_data *data = iio_priv(indio_dev); int i, j, ret; @@ -786,8 +788,9 @@ static int mma8452_write_raw(struct iio_dev *indio_dev, } static int mma8452_get_event_regs(struct mma8452_data *data, - const struct iio_chan_spec *chan, enum iio_event_direction dir, - const struct mma8452_event_regs **ev_reg) + const struct iio_chan_spec *chan, + enum iio_event_direction dir, + const struct mma8452_event_regs **ev_reg) { if (!chan) return -EINVAL; @@ -816,11 +819,11 @@ static int mma8452_get_event_regs(struct mma8452_data *data, } static int mma8452_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) + 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 mma8452_data *data = iio_priv(indio_dev); int ret, us, power_mode; @@ -879,11 +882,11 @@ static int mma8452_read_event_value(struct iio_dev *indio_dev, } static int mma8452_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) + 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 mma8452_data *data = iio_priv(indio_dev); int ret, reg, steps; @@ -953,8 +956,7 @@ static int mma8452_read_event_config(struct iio_dev *indio_dev, case IIO_EV_DIR_FALLING: return mma8452_freefall_mode_enabled(data); case IIO_EV_DIR_RISING: - ret = i2c_smbus_read_byte_data(data->client, - ev_regs->ev_cfg); + ret = i2c_smbus_read_byte_data(data->client, ev_regs->ev_cfg); if (ret < 0) return ret; @@ -1191,7 +1193,7 @@ static const struct attribute_group mma8452_event_attribute_group = { static const struct iio_mount_matrix * mma8452_get_mount_matrix(const struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) + const struct iio_chan_spec *chan) { struct mma8452_data *data = iio_priv(indio_dev); @@ -1514,8 +1516,9 @@ static int mma8452_reset(struct i2c_client *client) * The following code will read the reset register, and check whether * this reset works. */ - i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG2, - MMA8452_CTRL_REG2_RST); + i2c_smbus_write_byte_data(client, + MMA8452_CTRL_REG2, + MMA8452_CTRL_REG2_RST); for (i = 0; i < 10; i++) { usleep_range(100, 200); @@ -1544,6 +1547,7 @@ MODULE_DEVICE_TABLE(of, mma8452_dt_ids); static int mma8452_probe(struct i2c_client *client) { + struct device *dev = &client->dev; struct mma8452_data *data; struct iio_dev *indio_dev; int ret; @@ -1576,14 +1580,12 @@ static int mma8452_probe(struct i2c_client *client) "failed to get VDDIO regulator!\n"); ret = regulator_enable(data->vdd_reg); - if (ret) { - dev_err(&client->dev, "failed to enable VDD regulator!\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to enable VDD regulator!\n"); ret = regulator_enable(data->vddio_reg); if (ret) { - dev_err(&client->dev, "failed to enable VDDIO regulator!\n"); + dev_err_probe(dev, ret, "failed to enable VDDIO regulator!\n"); goto disable_regulator_vdd; } @@ -1645,8 +1647,8 @@ static int mma8452_probe(struct i2c_client *client) dev_dbg(&client->dev, "using interrupt line INT2\n"); } else { ret = i2c_smbus_write_byte_data(client, - MMA8452_CTRL_REG5, - data->chip_info->all_events); + MMA8452_CTRL_REG5, + data->chip_info->all_events); if (ret < 0) goto disable_regulators; @@ -1654,8 +1656,8 @@ static int mma8452_probe(struct i2c_client *client) } ret = i2c_smbus_write_byte_data(client, - MMA8452_CTRL_REG4, - data->chip_info->enabled_events); + MMA8452_CTRL_REG4, + data->chip_info->enabled_events); if (ret < 0) goto disable_regulators; @@ -1680,18 +1682,16 @@ static int mma8452_probe(struct i2c_client *client) goto trigger_cleanup; if (client->irq) { - ret = devm_request_threaded_irq(&client->dev, - client->irq, - NULL, mma8452_interrupt, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - client->name, indio_dev); + ret = request_threaded_irq(client->irq, NULL, mma8452_interrupt, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + client->name, indio_dev); if (ret) goto buffer_cleanup; } ret = pm_runtime_set_active(&client->dev); if (ret < 0) - goto buffer_cleanup; + goto free_irq; pm_runtime_enable(&client->dev); pm_runtime_set_autosuspend_delay(&client->dev, @@ -1700,7 +1700,7 @@ static int mma8452_probe(struct i2c_client *client) ret = iio_device_register(indio_dev); if (ret < 0) - goto buffer_cleanup; + goto free_irq; ret = mma8452_set_freefall_mode(data, false); if (ret < 0) @@ -1711,6 +1711,10 @@ static int mma8452_probe(struct i2c_client *client) unregister_device: iio_device_unregister(indio_dev); +free_irq: + if (client->irq) + free_irq(client->irq, indio_dev); + buffer_cleanup: iio_triggered_buffer_cleanup(indio_dev); @@ -1736,6 +1740,9 @@ static void mma8452_remove(struct i2c_client *client) pm_runtime_disable(&client->dev); pm_runtime_set_suspended(&client->dev); + if (client->irq) + free_irq(client->irq, indio_dev); + iio_triggered_buffer_cleanup(indio_dev); mma8452_trigger_cleanup(indio_dev); mma8452_standby(iio_priv(indio_dev)); @@ -1821,12 +1828,12 @@ static const struct dev_pm_ops mma8452_pm_ops = { }; static const struct i2c_device_id mma8452_id[] = { - { "fxls8471", (kernel_ulong_t)&mma_chip_info_table[fxls8471] }, - { "mma8451", (kernel_ulong_t)&mma_chip_info_table[mma8451] }, - { "mma8452", (kernel_ulong_t)&mma_chip_info_table[mma8452] }, - { "mma8453", (kernel_ulong_t)&mma_chip_info_table[mma8453] }, - { "mma8652", (kernel_ulong_t)&mma_chip_info_table[mma8652] }, - { "mma8653", (kernel_ulong_t)&mma_chip_info_table[mma8653] }, + { .name = "fxls8471", .driver_data = (kernel_ulong_t)&mma_chip_info_table[fxls8471] }, + { .name = "mma8451", .driver_data = (kernel_ulong_t)&mma_chip_info_table[mma8451] }, + { .name = "mma8452", .driver_data = (kernel_ulong_t)&mma_chip_info_table[mma8452] }, + { .name = "mma8453", .driver_data = (kernel_ulong_t)&mma_chip_info_table[mma8453] }, + { .name = "mma8652", .driver_data = (kernel_ulong_t)&mma_chip_info_table[mma8652] }, + { .name = "mma8653", .driver_data = (kernel_ulong_t)&mma_chip_info_table[mma8653] }, { } }; MODULE_DEVICE_TABLE(i2c, mma8452_id); diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c index 02195deada49..7e01427fd9c4 100644 --- a/drivers/iio/accel/mma9551.c +++ b/drivers/iio/accel/mma9551.c @@ -6,7 +6,6 @@ #include <linux/i2c.h> #include <linux/interrupt.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/delay.h> @@ -421,10 +420,8 @@ static int mma9551_gpio_probe(struct iio_dev *indio_dev) NULL, mma9551_event_handler, IRQF_TRIGGER_RISING | IRQF_ONESHOT, "mma9551_event", indio_dev); - if (ret < 0) { - dev_err(dev, "request irq %d failed\n", data->irqs[i]); + if (ret) return ret; - } dev_dbg(dev, "gpio resource, no:%d irq:%d\n", desc_to_gpio(gpio), data->irqs[i]); @@ -582,7 +579,7 @@ static const struct acpi_device_id mma9551_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, mma9551_acpi_match); static const struct i2c_device_id mma9551_id[] = { - { "mma9551" }, + { .name = "mma9551" }, { } }; diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index f85384a7908f..8e7aaac89d47 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -6,7 +6,6 @@ #include <linux/i2c.h> #include <linux/interrupt.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/iio/iio.h> @@ -1100,11 +1099,8 @@ static int mma9553_probe(struct i2c_client *client) mma9553_event_handler, IRQF_TRIGGER_RISING, "mma9553_event", indio_dev); - if (ret < 0) { - dev_err(&client->dev, "request irq %d failed\n", - client->irq); + if (ret) goto out_poweroff; - } } ret = pm_runtime_set_active(&client->dev); @@ -1219,7 +1215,7 @@ static const struct acpi_device_id mma9553_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, mma9553_acpi_match); static const struct i2c_device_id mma9553_id[] = { - { "mma9553" }, + { .name = "mma9553" }, { } }; diff --git a/drivers/iio/accel/msa311.c b/drivers/iio/accel/msa311.c index 5eace0de3750..caf9b1b6397f 100644 --- a/drivers/iio/accel/msa311.c +++ b/drivers/iio/accel/msa311.c @@ -28,7 +28,6 @@ */ #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/pm.h> #include <linux/pm_runtime.h> @@ -1060,7 +1059,7 @@ static int msa311_setup_interrupts(struct msa311_priv *msa311) msa311_irq_thread, IRQF_ONESHOT, msa311->chip_name, indio_dev); if (err) - return dev_err_probe(dev, err, "failed to request IRQ\n"); + return err; trig = devm_iio_trigger_alloc(dev, "%s-new-data", msa311->chip_name); if (!trig) diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c index a2c3cf13d098..a66fee828ec1 100644 --- a/drivers/iio/accel/mxc4005.c +++ b/drivers/iio/accel/mxc4005.c @@ -9,7 +9,6 @@ #include <linux/module.h> #include <linux/i2c.h> #include <linux/iio/iio.h> -#include <linux/mod_devicetable.h> #include <linux/regmap.h> #include <linux/types.h> #include <linux/iio/sysfs.h> @@ -490,11 +489,8 @@ static int mxc4005_probe(struct i2c_client *client) iio_trigger_generic_data_rdy_poll, IRQF_TRIGGER_FALLING | IRQF_NO_THREAD, "mxc4005_event", data->dready_trig); - if (ret) { - dev_err(&client->dev, - "failed to init threaded irq\n"); + if (ret) return ret; - } data->dready_trig->ops = &mxc4005_trigger_ops; iio_trigger_set_drvdata(data->dready_trig, indio_dev); @@ -580,8 +576,8 @@ static const struct of_device_id mxc4005_of_match[] = { MODULE_DEVICE_TABLE(of, mxc4005_of_match); static const struct i2c_device_id mxc4005_id[] = { - { "mxc4005" }, - { "mxc6655" }, + { .name = "mxc4005" }, + { .name = "mxc6655" }, { } }; MODULE_DEVICE_TABLE(i2c, mxc4005_id); diff --git a/drivers/iio/accel/mxc6255.c b/drivers/iio/accel/mxc6255.c index fc3ed84d1933..a9f41cf27ad9 100644 --- a/drivers/iio/accel/mxc6255.c +++ b/drivers/iio/accel/mxc6255.c @@ -12,7 +12,6 @@ #include <linux/init.h> #include <linux/iio/iio.h> #include <linux/delay.h> -#include <linux/mod_devicetable.h> #include <linux/regmap.h> #include <linux/iio/sysfs.h> @@ -171,8 +170,8 @@ static const struct acpi_device_id mxc6255_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, mxc6255_acpi_match); static const struct i2c_device_id mxc6255_id[] = { - { "mxc6225" }, - { "mxc6255" }, + { .name = "mxc6225" }, + { .name = "mxc6255" }, { } }; MODULE_DEVICE_TABLE(i2c, mxc6255_id); diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c index 4a827be439a2..a92a563f6a4b 100644 --- a/drivers/iio/accel/sca3000.c +++ b/drivers/iio/accel/sca3000.c @@ -7,6 +7,7 @@ * See industrialio/accels/sca3000.h for comments. */ +#include <linux/cleanup.h> #include <linux/interrupt.h> #include <linux/fs.h> #include <linux/device.h> @@ -171,6 +172,7 @@ struct sca3000_state { /** * struct sca3000_chip_info - model dependent parameters + * @name: name of the chip * @scale: scale * 10^-6 * @temp_output: some devices have temperature sensors. * @measurement_mode_freq: normal mode sampling frequency @@ -193,6 +195,7 @@ struct sca3000_state { * sca3000 variant. **/ struct sca3000_chip_info { + const char *name; unsigned int scale; bool temp_output; int measurement_mode_freq; @@ -207,69 +210,59 @@ struct sca3000_chip_info { int mot_det_mult_y[7]; }; -enum sca3000_variant { - d01, - e02, - e04, - e05, +static const struct sca3000_chip_info sca3000_chip_info_d01 = { + .name = "sca3000_d01", + .scale = 7357, + .temp_output = true, + .measurement_mode_freq = 250, + .measurement_mode_3db_freq = 45, + .option_mode_1 = SCA3000_OP_MODE_BYPASS, + .option_mode_1_freq = 250, + .option_mode_1_3db_freq = 70, + .mot_det_mult_xz = { 50, 100, 200, 350, 650, 1300 }, + .mot_det_mult_y = { 50, 100, 150, 250, 450, 850, 1750 }, }; -/* - * Note where option modes are not defined, the chip simply does not - * support any. - * Other chips in the sca3000 series use i2c and are not included here. - * - * Some of these devices are only listed in the family data sheet and - * do not actually appear to be available. - */ -static const struct sca3000_chip_info sca3000_spi_chip_info_tbl[] = { - [d01] = { - .scale = 7357, - .temp_output = true, - .measurement_mode_freq = 250, - .measurement_mode_3db_freq = 45, - .option_mode_1 = SCA3000_OP_MODE_BYPASS, - .option_mode_1_freq = 250, - .option_mode_1_3db_freq = 70, - .mot_det_mult_xz = {50, 100, 200, 350, 650, 1300}, - .mot_det_mult_y = {50, 100, 150, 250, 450, 850, 1750}, - }, - [e02] = { - .scale = 9810, - .measurement_mode_freq = 125, - .measurement_mode_3db_freq = 40, - .option_mode_1 = SCA3000_OP_MODE_NARROW, - .option_mode_1_freq = 63, - .option_mode_1_3db_freq = 11, - .mot_det_mult_xz = {100, 150, 300, 550, 1050, 2050}, - .mot_det_mult_y = {50, 100, 200, 350, 700, 1350, 2700}, - }, - [e04] = { - .scale = 19620, - .measurement_mode_freq = 100, - .measurement_mode_3db_freq = 38, - .option_mode_1 = SCA3000_OP_MODE_NARROW, - .option_mode_1_freq = 50, - .option_mode_1_3db_freq = 9, - .option_mode_2 = SCA3000_OP_MODE_WIDE, - .option_mode_2_freq = 400, - .option_mode_2_3db_freq = 70, - .mot_det_mult_xz = {200, 300, 600, 1100, 2100, 4100}, - .mot_det_mult_y = {100, 200, 400, 7000, 1400, 2700, 54000}, - }, - [e05] = { - .scale = 61313, - .measurement_mode_freq = 200, - .measurement_mode_3db_freq = 60, - .option_mode_1 = SCA3000_OP_MODE_NARROW, - .option_mode_1_freq = 50, - .option_mode_1_3db_freq = 9, - .option_mode_2 = SCA3000_OP_MODE_WIDE, - .option_mode_2_freq = 400, - .option_mode_2_3db_freq = 75, - .mot_det_mult_xz = {600, 900, 1700, 3200, 6100, 11900}, - .mot_det_mult_y = {300, 600, 1200, 2000, 4100, 7800, 15600}, - }, +static const struct sca3000_chip_info sca3000_chip_info_e02 = { + .name = "sca3000_e02", + .scale = 9810, + .measurement_mode_freq = 125, + .measurement_mode_3db_freq = 40, + .option_mode_1 = SCA3000_OP_MODE_NARROW, + .option_mode_1_freq = 63, + .option_mode_1_3db_freq = 11, + .mot_det_mult_xz = { 100, 150, 300, 550, 1050, 2050 }, + .mot_det_mult_y = { 50, 100, 200, 350, 700, 1350, 2700 }, +}; + +static const struct sca3000_chip_info sca3000_chip_info_e04 = { + .name = "sca3000_e04", + .scale = 19620, + .measurement_mode_freq = 100, + .measurement_mode_3db_freq = 38, + .option_mode_1 = SCA3000_OP_MODE_NARROW, + .option_mode_1_freq = 50, + .option_mode_1_3db_freq = 9, + .option_mode_2 = SCA3000_OP_MODE_WIDE, + .option_mode_2_freq = 400, + .option_mode_2_3db_freq = 70, + .mot_det_mult_xz = { 200, 300, 600, 1100, 2100, 4100 }, + .mot_det_mult_y = { 100, 200, 400, 7000, 1400, 2700, 54000 }, +}; + +static const struct sca3000_chip_info sca3000_chip_info_e05 = { + .name = "sca3000_e05", + .scale = 61313, + .measurement_mode_freq = 200, + .measurement_mode_3db_freq = 60, + .option_mode_1 = SCA3000_OP_MODE_NARROW, + .option_mode_1_freq = 50, + .option_mode_1_3db_freq = 9, + .option_mode_2 = SCA3000_OP_MODE_WIDE, + .option_mode_2_freq = 400, + .option_mode_2_3db_freq = 75, + .mot_det_mult_xz = { 600, 900, 1700, 3200, 6100, 11900 }, + .mot_det_mult_y = { 300, 600, 1200, 2000, 4100, 7800, 15600 }, }; static int sca3000_write_reg(struct sca3000_state *st, u8 address, u8 val) @@ -1435,24 +1428,42 @@ static const struct iio_info sca3000_info = { .write_event_config = &sca3000_write_event_config, }; -static int sca3000_probe(struct spi_device *spi) +static void sca3000_stop_all_interrupts(void *data) { + struct iio_dev *indio_dev = data; + struct sca3000_state *st = iio_priv(indio_dev); int ret; + + guard(mutex)(&st->lock); + + ret = sca3000_read_data_short(st, SCA3000_REG_INT_MASK_ADDR, 1); + if (ret) + return; + + sca3000_write_reg(st, SCA3000_REG_INT_MASK_ADDR, + (st->rx[0] & + ~(SCA3000_REG_INT_MASK_RING_THREE_QUARTER | + SCA3000_REG_INT_MASK_RING_HALF | + SCA3000_REG_INT_MASK_ALL_INTS))); +} + +static int sca3000_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; struct sca3000_state *st; struct iio_dev *indio_dev; + int ret; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; st = iio_priv(indio_dev); - spi_set_drvdata(spi, indio_dev); st->us = spi; mutex_init(&st->lock); - st->info = &sca3000_spi_chip_info_tbl[spi_get_device_id(spi) - ->driver_data]; + st->info = spi_get_device_match_data(spi); - indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->name = st->info->name; indio_dev->info = &sca3000_info; if (st->info->temp_output) { indio_dev->channels = sca3000_channels_with_temp; @@ -1464,78 +1475,39 @@ static int sca3000_probe(struct spi_device *spi) } indio_dev->modes = INDIO_DIRECT_MODE; - ret = devm_iio_kfifo_buffer_setup(&spi->dev, indio_dev, - &sca3000_ring_setup_ops); + ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, &sca3000_ring_setup_ops); if (ret) return ret; if (spi->irq) { - ret = request_threaded_irq(spi->irq, - NULL, - &sca3000_event_handler, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - "sca3000", - indio_dev); + ret = devm_request_threaded_irq(dev, spi->irq, NULL, + &sca3000_event_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "sca3000", + indio_dev); if (ret) return ret; } ret = sca3000_clean_setup(st); if (ret) - goto error_free_irq; + return ret; ret = sca3000_print_rev(indio_dev); if (ret) - goto error_free_irq; - - ret = iio_device_register(indio_dev); - if (ret) - goto error_free_irq; - - return 0; - -error_free_irq: - if (spi->irq) - free_irq(spi->irq, indio_dev); - - return ret; -} - -static int sca3000_stop_all_interrupts(struct sca3000_state *st) -{ - int ret; + return ret; - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_INT_MASK_ADDR, 1); + ret = devm_add_action_or_reset(dev, sca3000_stop_all_interrupts, indio_dev); if (ret) - goto error_ret; - ret = sca3000_write_reg(st, SCA3000_REG_INT_MASK_ADDR, - (st->rx[0] & - ~(SCA3000_REG_INT_MASK_RING_THREE_QUARTER | - SCA3000_REG_INT_MASK_RING_HALF | - SCA3000_REG_INT_MASK_ALL_INTS))); -error_ret: - mutex_unlock(&st->lock); - return ret; -} - -static void sca3000_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct sca3000_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); + return ret; - /* Must ensure no interrupts can be generated after this! */ - sca3000_stop_all_interrupts(st); - if (spi->irq) - free_irq(spi->irq, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct spi_device_id sca3000_id[] = { - {"sca3000_d01", d01}, - {"sca3000_e02", e02}, - {"sca3000_e04", e04}, - {"sca3000_e05", e05}, + { .name = "sca3000_d01", .driver_data = (kernel_ulong_t)&sca3000_chip_info_d01 }, + { .name = "sca3000_e02", .driver_data = (kernel_ulong_t)&sca3000_chip_info_e02 }, + { .name = "sca3000_e04", .driver_data = (kernel_ulong_t)&sca3000_chip_info_e04 }, + { .name = "sca3000_e05", .driver_data = (kernel_ulong_t)&sca3000_chip_info_e05 }, { } }; MODULE_DEVICE_TABLE(spi, sca3000_id); @@ -1545,7 +1517,6 @@ static struct spi_driver sca3000_driver = { .name = "sca3000", }, .probe = sca3000_probe, - .remove = sca3000_remove, .id_table = sca3000_id, }; module_spi_driver(sca3000_driver); diff --git a/drivers/iio/accel/sca3300.c b/drivers/iio/accel/sca3300.c index 8380b237831c..67582cc34149 100644 --- a/drivers/iio/accel/sca3300.c +++ b/drivers/iio/accel/sca3300.c @@ -664,8 +664,8 @@ static const struct of_device_id sca3300_dt_ids[] = { MODULE_DEVICE_TABLE(of, sca3300_dt_ids); static const struct spi_device_id sca3300_ids[] = { - { "sca3300" }, - { "scl3300" }, + { .name = "sca3300" }, + { .name = "scl3300" }, { } }; MODULE_DEVICE_TABLE(spi, sca3300_ids); diff --git a/drivers/iio/accel/ssp_accel_sensor.c b/drivers/iio/accel/ssp_accel_sensor.c index 3e572af2ec03..d1687cdd33ea 100644 --- a/drivers/iio/accel/ssp_accel_sensor.c +++ b/drivers/iio/accel/ssp_accel_sensor.c @@ -76,7 +76,7 @@ static const struct iio_chan_spec ssp_acc_channels[] = { SSP_CHANNEL_AG(IIO_ACCEL, IIO_MOD_X, SSP_CHANNEL_SCAN_INDEX_X), SSP_CHANNEL_AG(IIO_ACCEL, IIO_MOD_Y, SSP_CHANNEL_SCAN_INDEX_Y), SSP_CHANNEL_AG(IIO_ACCEL, IIO_MOD_Z, SSP_CHANNEL_SCAN_INDEX_Z), - SSP_CHAN_TIMESTAMP(SSP_CHANNEL_SCAN_INDEX_TIME), + IIO_CHAN_SOFT_TIMESTAMP(SSP_CHANNEL_SCAN_INDEX_TIME), }; static int ssp_process_accel_data(struct iio_dev *indio_dev, void *buf, diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index f24449500533..99522a885d71 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -9,7 +9,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/iio/iio.h> @@ -138,32 +137,32 @@ static const struct acpi_device_id st_accel_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, st_accel_acpi_match); static const struct i2c_device_id st_accel_id_table[] = { - { LSM303DLH_ACCEL_DEV_NAME }, - { LSM303DLHC_ACCEL_DEV_NAME }, - { LIS3DH_ACCEL_DEV_NAME }, - { LSM330D_ACCEL_DEV_NAME }, - { LSM330DL_ACCEL_DEV_NAME }, - { LSM330DLC_ACCEL_DEV_NAME }, - { LIS331DLH_ACCEL_DEV_NAME }, - { LSM303DL_ACCEL_DEV_NAME }, - { LSM303DLM_ACCEL_DEV_NAME }, - { LSM330_ACCEL_DEV_NAME }, - { LSM303AGR_ACCEL_DEV_NAME }, - { LIS2DH12_ACCEL_DEV_NAME }, - { LIS3L02DQ_ACCEL_DEV_NAME }, - { LNG2DM_ACCEL_DEV_NAME }, - { H3LIS331DL_ACCEL_DEV_NAME }, - { LIS331DL_ACCEL_DEV_NAME }, - { LIS3LV02DL_ACCEL_DEV_NAME }, - { LIS2DW12_ACCEL_DEV_NAME }, - { LIS3DE_ACCEL_DEV_NAME }, - { LIS2DE12_ACCEL_DEV_NAME }, - { LIS2DS12_ACCEL_DEV_NAME }, - { LIS2HH12_ACCEL_DEV_NAME }, - { LIS302DL_ACCEL_DEV_NAME }, - { LSM303C_ACCEL_DEV_NAME }, - { SC7A20_ACCEL_DEV_NAME }, - { IIS328DQ_ACCEL_DEV_NAME }, + { .name = LSM303DLH_ACCEL_DEV_NAME }, + { .name = LSM303DLHC_ACCEL_DEV_NAME }, + { .name = LIS3DH_ACCEL_DEV_NAME }, + { .name = LSM330D_ACCEL_DEV_NAME }, + { .name = LSM330DL_ACCEL_DEV_NAME }, + { .name = LSM330DLC_ACCEL_DEV_NAME }, + { .name = LIS331DLH_ACCEL_DEV_NAME }, + { .name = LSM303DL_ACCEL_DEV_NAME }, + { .name = LSM303DLM_ACCEL_DEV_NAME }, + { .name = LSM330_ACCEL_DEV_NAME }, + { .name = LSM303AGR_ACCEL_DEV_NAME }, + { .name = LIS2DH12_ACCEL_DEV_NAME }, + { .name = LIS3L02DQ_ACCEL_DEV_NAME }, + { .name = LNG2DM_ACCEL_DEV_NAME }, + { .name = H3LIS331DL_ACCEL_DEV_NAME }, + { .name = LIS331DL_ACCEL_DEV_NAME }, + { .name = LIS3LV02DL_ACCEL_DEV_NAME }, + { .name = LIS2DW12_ACCEL_DEV_NAME }, + { .name = LIS3DE_ACCEL_DEV_NAME }, + { .name = LIS2DE12_ACCEL_DEV_NAME }, + { .name = LIS2DS12_ACCEL_DEV_NAME }, + { .name = LIS2HH12_ACCEL_DEV_NAME }, + { .name = LIS302DL_ACCEL_DEV_NAME }, + { .name = LSM303C_ACCEL_DEV_NAME }, + { .name = SC7A20_ACCEL_DEV_NAME }, + { .name = IIS328DQ_ACCEL_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, st_accel_id_table); diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index d8ec0555f42a..171f241c0a30 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -9,7 +9,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/spi/spi.h> #include <linux/iio/iio.h> @@ -147,26 +146,26 @@ static int st_accel_spi_probe(struct spi_device *spi) } static const struct spi_device_id st_accel_id_table[] = { - { LIS3DH_ACCEL_DEV_NAME }, - { LSM330D_ACCEL_DEV_NAME }, - { LSM330DL_ACCEL_DEV_NAME }, - { LSM330DLC_ACCEL_DEV_NAME }, - { LIS331DLH_ACCEL_DEV_NAME }, - { LSM330_ACCEL_DEV_NAME }, - { LSM303AGR_ACCEL_DEV_NAME }, - { LIS2DH12_ACCEL_DEV_NAME }, - { LIS2DS12_ACCEL_DEV_NAME }, - { LIS3L02DQ_ACCEL_DEV_NAME }, - { LNG2DM_ACCEL_DEV_NAME }, - { H3LIS331DL_ACCEL_DEV_NAME }, - { LIS331DL_ACCEL_DEV_NAME }, - { LIS3LV02DL_ACCEL_DEV_NAME }, - { LIS2DW12_ACCEL_DEV_NAME }, - { LIS3DHH_ACCEL_DEV_NAME }, - { LIS3DE_ACCEL_DEV_NAME }, - { LIS302DL_ACCEL_DEV_NAME }, - { LSM303C_ACCEL_DEV_NAME }, - { IIS328DQ_ACCEL_DEV_NAME }, + { .name = LIS3DH_ACCEL_DEV_NAME }, + { .name = LSM330D_ACCEL_DEV_NAME }, + { .name = LSM330DL_ACCEL_DEV_NAME }, + { .name = LSM330DLC_ACCEL_DEV_NAME }, + { .name = LIS331DLH_ACCEL_DEV_NAME }, + { .name = LSM330_ACCEL_DEV_NAME }, + { .name = LSM303AGR_ACCEL_DEV_NAME }, + { .name = LIS2DH12_ACCEL_DEV_NAME }, + { .name = LIS2DS12_ACCEL_DEV_NAME }, + { .name = LIS3L02DQ_ACCEL_DEV_NAME }, + { .name = LNG2DM_ACCEL_DEV_NAME }, + { .name = H3LIS331DL_ACCEL_DEV_NAME }, + { .name = LIS331DL_ACCEL_DEV_NAME }, + { .name = LIS3LV02DL_ACCEL_DEV_NAME }, + { .name = LIS2DW12_ACCEL_DEV_NAME }, + { .name = LIS3DHH_ACCEL_DEV_NAME }, + { .name = LIS3DE_ACCEL_DEV_NAME }, + { .name = LIS302DL_ACCEL_DEV_NAME }, + { .name = LSM303C_ACCEL_DEV_NAME }, + { .name = IIS328DQ_ACCEL_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(spi, st_accel_id_table); diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index f31c6ab3392d..50840c3440c4 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -7,12 +7,20 @@ * IIO driver for STK8312; 7-bit I2C address: 0x3D. */ +#include <linux/array_size.h> +#include <linux/bits.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> +#include <linux/errno.h> #include <linux/i2c.h> #include <linux/interrupt.h> -#include <linux/kernel.h> #include <linux/module.h> -#include <linux/delay.h> +#include <linux/mod_devicetable.h> +#include <linux/mutex.h> +#include <linux/pm.h> +#include <linux/sysfs.h> #include <linux/types.h> + #include <linux/iio/buffer.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -542,11 +550,8 @@ static int stk8312_probe(struct i2c_client *client) IRQF_ONESHOT, "stk8312_event", indio_dev); - if (ret < 0) { - dev_err(&client->dev, "request irq %d failed\n", - client->irq); + if (ret) goto err_power_off; - } data->dready_trig = devm_iio_trigger_alloc(&client->dev, "%s-dev%d", @@ -630,8 +635,8 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend, static const struct i2c_device_id stk8312_i2c_id[] = { /* Deprecated in favour of lowercase form */ - { "STK8312" }, - { "stk8312" }, + { .name = "STK8312" }, + { .name = "stk8312" }, { } }; MODULE_DEVICE_TABLE(i2c, stk8312_i2c_id); diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index a9ff2a273fe1..6c1e286c0a1d 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -7,12 +7,18 @@ * STK8BA50 7-bit I2C address: 0x18. */ +#include <linux/array_size.h> +#include <linux/bitops.h> +#include <linux/dev_printk.h> +#include <linux/errno.h> #include <linux/i2c.h> #include <linux/interrupt.h> -#include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> +#include <linux/mutex.h> +#include <linux/pm.h> +#include <linux/sysfs.h> #include <linux/types.h> + #include <linux/iio/buffer.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -432,11 +438,8 @@ static int stk8ba50_probe(struct i2c_client *client) stk8ba50_data_rdy_trig_poll, IRQF_TRIGGER_RISING | IRQF_NO_THREAD, "stk8ba50_event", indio_dev); - if (ret < 0) { - dev_err(&client->dev, "request irq %d failed\n", - client->irq); + if (ret) goto err_power_off; - } data->dready_trig = devm_iio_trigger_alloc(&client->dev, "%s-dev%d", @@ -519,7 +522,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stk8ba50_pm_ops, stk8ba50_suspend, stk8ba50_resume); static const struct i2c_device_id stk8ba50_i2c_id[] = { - { "stk8ba50" }, + { .name = "stk8ba50" }, { } }; MODULE_DEVICE_TABLE(i2c, stk8ba50_i2c_id); diff --git a/drivers/iio/adc/88pm886-gpadc.c b/drivers/iio/adc/88pm886-gpadc.c index cffe35136685..938ba43c2c35 100644 --- a/drivers/iio/adc/88pm886-gpadc.c +++ b/drivers/iio/adc/88pm886-gpadc.c @@ -10,7 +10,6 @@ #include <linux/err.h> #include <linux/i2c.h> #include <linux/math.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> @@ -280,7 +279,7 @@ static int pm886_gpadc_read_raw(struct iio_dev *iio, struct iio_chan_spec const static int pm886_gpadc_hw_enable(struct regmap *map) { - const u8 config[] = { + static const u8 config[] = { PM886_GPADC_CONFIG1_EN_ALL, PM886_GPADC_CONFIG2_EN_ALL, PM886_GPADC_GND_DET2_EN, @@ -373,7 +372,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(pm886_gpadc_pm_ops, pm886_gpadc_runtime_resume, NULL); static const struct platform_device_id pm886_gpadc_id[] = { - { "88pm886-gpadc" }, + { .name = "88pm886-gpadc" }, { } }; MODULE_DEVICE_TABLE(platform, pm886_gpadc_id); diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 60038ae8dfc4..415e519ad4eb 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -33,7 +33,8 @@ config AB8500_GPADC and USB voltages integral to the U8500 platform. config AD_SIGMA_DELTA - tristate + tristate "Analog Devices Sigma-Delta Modulator support" if COMPILE_TEST + depends on SPI select IIO_BUFFER select IIO_BUFFER_DMAENGINE select IIO_TRIGGERED_BUFFER @@ -60,9 +61,14 @@ config AD4030 tristate "Analog Devices AD4030 ADC Driver" depends on SPI depends on GPIOLIB + depends on PWM select REGMAP select IIO_BUFFER + select IIO_BUFFER_DMA + select IIO_BUFFER_DMAENGINE select IIO_TRIGGERED_BUFFER + select SPI_OFFLOAD + select SPI_OFFLOAD_TRIGGER_PWM help Say yes here to build support for Analog Devices AD4030 and AD4630 high speed SPI analog to digital converters (ADC). @@ -73,6 +79,7 @@ config AD4030 config AD4062 tristate "Analog Devices AD4062 Driver" depends on I3C + depends on GPIOLIB select REGMAP_I3C select IIO_BUFFER select IIO_TRIGGERED_BUFFER @@ -102,6 +109,7 @@ config AD4130 depends on SPI depends on GPIOLIB select IIO_BUFFER + select IIO_TRIGGERED_BUFFER select IIO_KFIFO_BUF select REGMAP_SPI depends on COMMON_CLK @@ -139,6 +147,22 @@ config AD4170_4 To compile this driver as a module, choose M here: the module will be called ad4170-4. +config AD4691 + tristate "Analog Devices AD4691 Family ADC Driver" + depends on SPI + depends on REGULATOR || COMPILE_TEST + select IIO_BUFFER + select IIO_BUFFER_DMAENGINE + select IIO_TRIGGERED_BUFFER + select REGMAP + select SPI_OFFLOAD + help + Say yes here to build support for Analog Devices AD4691 Family MuxSAR + SPI analog to digital converters (ADC). + + To compile this driver as a module, choose M here: the module will be + called ad4691. + config AD4695 tristate "Analog Device AD4695 ADC Driver" depends on SPI @@ -306,6 +330,7 @@ config AD7298 config AD7380 tristate "Analog Devices AD7380 ADC driver" depends on SPI_MASTER + select REGMAP select SPI_OFFLOAD select IIO_BUFFER select IIO_BUFFER_DMAENGINE @@ -409,12 +434,15 @@ config AD7766 config AD7768_1 tristate "Analog Devices AD7768-1 ADC driver" depends on SPI + select GPIOLIB select REGULATOR select REGMAP_SPI select RATIONAL select IIO_BUFFER + select IIO_BUFFER_DMAENGINE select IIO_TRIGGER select IIO_TRIGGERED_BUFFER + select SPI_OFFLOAD help Say yes here to build support for Analog Devices AD7768-1 SPI simultaneously sampling sigma-delta analog to digital converter (ADC). @@ -427,6 +455,7 @@ config AD7779 depends on SPI select CRC8 select IIO_BUFFER + select IIO_TRIGGERED_BUFFER select IIO_BACKEND help Say yes here to build support for Analog Devices AD777X family @@ -917,6 +946,25 @@ config LTC2309 This driver can also be built as a module. If so, the module will be called ltc2309. +config LTC2378 + tristate "Analog Devices LTC2378 ADC driver" + depends on SPI + depends on REGULATOR || COMPILE_TEST + depends on GPIOLIB + depends on PWM + select IIO_BUFFER + select IIO_BUFFER_DMA + select IIO_BUFFER_DMAENGINE + select IIO_TRIGGERED_BUFFER + select SPI_OFFLOAD + select SPI_OFFLOAD_TRIGGER_PWM + help + Say yes here to build support for Analog Devices LTC2378-20 and + similar analog to digital converters. + + This driver can also be built as a module. If so, the module will + be called ltc2378. + config LTC2471 tristate "Linear Technology LTC2471 and LTC2473 ADC driver" depends on I2C @@ -1048,6 +1096,7 @@ config MAX1363 config MAX14001 tristate "Analog Devices MAX14001/MAX14002 ADC driver" depends on SPI + select REGMAP help Say yes here to build support for Analog Devices MAX14001/MAX14002 Configurable, Isolated 10-bit ADCs for Multi-Range Binary Inputs. @@ -1058,6 +1107,7 @@ config MAX14001 config MAX34408 tristate "Maxim max34408/max344089 ADC driver" depends on I2C + select REGMAP_I2C help Say yes here to build support for Maxim max34408/max34409 current sense monitor with 8-bits ADC interface with overcurrent delay/threshold and @@ -1137,6 +1187,17 @@ config MCP3911 This driver can also be built as a module. If so, the module will be called mcp3911. +config MEDIATEK_MT6323_AUXADC + tristate "MediaTek MT6323 PMIC AUXADC driver" + depends on MFD_MT6397 + help + Say yes here to enable support for MediaTek MT6323 PMIC Auxiliary ADC. + This driver provides multiple channels for system monitoring, + such as battery voltage, PMIC temperature, and others. + + This driver can also be built as a module. If so, the module will be + called mt6323-auxadc. + config MEDIATEK_MT6359_AUXADC tristate "MediaTek MT6359 PMIC AUXADC driver" depends on MFD_MT6397 @@ -1347,7 +1408,7 @@ config QCOM_SPMI_VADC be called qcom-spmi-vadc. config QCOM_SPMI_ADC5 - tristate "Qualcomm Technologies Inc. SPMI PMIC5 ADC" + tristate "Qualcomm SPMI PMIC5 ADC" depends on SPMI select REGMAP_SPMI select QCOM_VADC_COMMON @@ -1366,6 +1427,32 @@ config QCOM_SPMI_ADC5 To compile this driver as a module, choose M here: the module will be called qcom-spmi-adc5. +config QCOM_SPMI_ADC5_GEN3 + tristate "Qualcomm SPMI PMIC5 GEN3 ADC" + depends on SPMI && THERMAL + select REGMAP_SPMI + select QCOM_VADC_COMMON + select AUXILIARY_BUS + help + IIO Voltage PMIC5 Gen3 ADC driver for Qualcomm Technologies Inc. + + The driver supports reading multiple channels. The ADC is a 16-bit + sigma-delta ADC. The hardware supports calibrated results for + conversion requests and clients include reading phone power supply + voltage, on board system thermistors connected to the PMIC ADC, + PMIC die temperature, charger temperature, battery current, USB + voltage input and voltage signals connected to supported PMIC GPIO + pins. The hardware supports internal pull-up for thermistors and can + choose between a 30k, 100k or 400k ohm pull up using the ADC channels. + + In addition, the same driver supports ADC thermal monitoring devices + too. They appear as thermal zones with multiple trip points. A thermal + client sets threshold temperature for both warm and cool trips and + gets updated when a threshold is reached. + + To compile this driver as a module, choose M here: the module will + be called qcom-spmi-adc5-gen3. + config RCAR_GYRO_ADC tristate "Renesas R-Car GyroADC driver" depends on ARCH_RCAR_GEN2 || COMPILE_TEST @@ -1735,6 +1822,18 @@ config TI_ADS1119 This driver can also be built as a module. If so, the module will be called ti-ads1119. +config TI_ADS112C14 + tristate "Texas Instruments ADS112C14/ADS122C14" + depends on I2C + select CRC8 + select REGMAP + help + If you say yes here you get support for Texas Instruments ADS112C14, + ADS122C14 ADC chips. + + This driver can also be built as a module. If so, the module will be + called ti-ads112c14. + config TI_ADS124S08 tristate "Texas Instruments ADS124S08" depends on SPI @@ -1910,6 +2009,39 @@ config TWL6030_GPADC This driver can also be built as a module. If so, the module will be called twl6030-gpadc. +config VERSAL_SYSMON_CORE + tristate + select REGMAP + +config VERSAL_SYSMON + tristate "AMD Versal SysMon driver" + depends on ARCH_ZYNQMP || COMPILE_TEST + depends on HAS_IOMEM + select VERSAL_SYSMON_CORE + help + Say yes here to have support for the AMD/Xilinx Versal System + Monitor (SysMon). This driver provides voltage and temperature + monitoring through the IIO subsystem. + + The SysMon measures up to 160 supply voltages and reads up to + 64 temperature satellites distributed across the SoC. + + To compile this driver as a module, choose M here: the module + will be called versal-sysmon. + +config VERSAL_SYSMON_I2C + tristate "AMD Versal SysMon I2C driver" + depends on I2C + select VERSAL_SYSMON_CORE + help + Say yes here to have support for the AMD/Xilinx Versal System + Monitor (SysMon) via I2C interface. This driver enables voltage + and temperature monitoring when the Versal chip has SysMon + configured with I2C access. + + To compile this driver as a module, choose M here: the module + will be called versal-sysmon-i2c. + config VF610_ADC tristate "Freescale vf610 ADC driver" depends on HAS_IOMEM diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index c76550415ff1..dcec0abb03b7 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_AD4080) += ad4080.o obj-$(CONFIG_AD4130) += ad4130.o obj-$(CONFIG_AD4134) += ad4134.o obj-$(CONFIG_AD4170_4) += ad4170-4.o +obj-$(CONFIG_AD4691) += ad4691.o obj-$(CONFIG_AD4695) += ad4695.o obj-$(CONFIG_AD4851) += ad4851.o obj-$(CONFIG_AD7091R) += ad7091r-base.o @@ -80,6 +81,7 @@ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o obj-$(CONFIG_LTC2309) += ltc2309.o +obj-$(CONFIG_LTC2378) += ltc2378.o obj-$(CONFIG_LTC2471) += ltc2471.o obj-$(CONFIG_LTC2485) += ltc2485.o obj-$(CONFIG_LTC2496) += ltc2496.o ltc2497-core.o @@ -99,6 +101,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_MCP3564) += mcp3564.o obj-$(CONFIG_MCP3911) += mcp3911.o +obj-$(CONFIG_MEDIATEK_MT6323_AUXADC) += mt6323-auxadc.o obj-$(CONFIG_MEDIATEK_MT6359_AUXADC) += mt6359-auxadc.o obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o obj-$(CONFIG_MEDIATEK_MT6370_ADC) += mt6370-adc.o @@ -116,6 +119,7 @@ obj-$(CONFIG_PAC1934) += pac1934.o obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o obj-$(CONFIG_QCOM_SPMI_ADC5) += qcom-spmi-adc5.o +obj-$(CONFIG_QCOM_SPMI_ADC5_GEN3) += qcom-spmi-adc5-gen3.o obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o obj-$(CONFIG_QCOM_SPMI_RRADC) += qcom-spmi-rradc.o obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o @@ -151,6 +155,7 @@ obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o obj-$(CONFIG_TI_ADS1018) += ti-ads1018.o obj-$(CONFIG_TI_ADS1100) += ti-ads1100.o obj-$(CONFIG_TI_ADS1119) += ti-ads1119.o +obj-$(CONFIG_TI_ADS112C14) += ti-ads112c14.o obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o obj-$(CONFIG_TI_ADS1298) += ti-ads1298.o obj-$(CONFIG_TI_ADS131E08) += ti-ads131e08.o @@ -166,6 +171,9 @@ 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_VERSAL_SYSMON_CORE) += versal-sysmon-core.o +obj-$(CONFIG_VERSAL_SYSMON) += versal-sysmon.o +obj-$(CONFIG_VERSAL_SYSMON_I2C) += versal-sysmon-i2c.o obj-$(CONFIG_VF610_ADC) += vf610_adc.o obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o obj-$(CONFIG_XILINX_AMS) += xilinx-ams.o diff --git a/drivers/iio/adc/ad4000.c b/drivers/iio/adc/ad4000.c index fd3d79fca785..a33896b2cf97 100644 --- a/drivers/iio/adc/ad4000.c +++ b/drivers/iio/adc/ad4000.c @@ -12,7 +12,6 @@ #include <linux/err.h> #include <linux/math.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/gpio/consumer.h> #include <linux/regulator/consumer.h> #include <linux/spi/offload/consumer.h> @@ -1177,37 +1176,37 @@ static int ad4000_probe(struct spi_device *spi) } static const struct spi_device_id ad4000_id[] = { - { "ad4000", (kernel_ulong_t)&ad4000_chip_info }, - { "ad4001", (kernel_ulong_t)&ad4001_chip_info }, - { "ad4002", (kernel_ulong_t)&ad4002_chip_info }, - { "ad4003", (kernel_ulong_t)&ad4003_chip_info }, - { "ad4004", (kernel_ulong_t)&ad4004_chip_info }, - { "ad4005", (kernel_ulong_t)&ad4005_chip_info }, - { "ad4006", (kernel_ulong_t)&ad4006_chip_info }, - { "ad4007", (kernel_ulong_t)&ad4007_chip_info }, - { "ad4008", (kernel_ulong_t)&ad4008_chip_info }, - { "ad4010", (kernel_ulong_t)&ad4010_chip_info }, - { "ad4011", (kernel_ulong_t)&ad4011_chip_info }, - { "ad4020", (kernel_ulong_t)&ad4020_chip_info }, - { "ad4021", (kernel_ulong_t)&ad4021_chip_info }, - { "ad4022", (kernel_ulong_t)&ad4022_chip_info }, - { "adaq4001", (kernel_ulong_t)&adaq4001_chip_info }, - { "adaq4003", (kernel_ulong_t)&adaq4003_chip_info }, - { "ad7685", (kernel_ulong_t)&ad7685_chip_info }, - { "ad7686", (kernel_ulong_t)&ad7686_chip_info }, - { "ad7687", (kernel_ulong_t)&ad7687_chip_info }, - { "ad7688", (kernel_ulong_t)&ad7688_chip_info }, - { "ad7690", (kernel_ulong_t)&ad7690_chip_info }, - { "ad7691", (kernel_ulong_t)&ad7691_chip_info }, - { "ad7693", (kernel_ulong_t)&ad7693_chip_info }, - { "ad7942", (kernel_ulong_t)&ad7942_chip_info }, - { "ad7946", (kernel_ulong_t)&ad7946_chip_info }, - { "ad7980", (kernel_ulong_t)&ad7980_chip_info }, - { "ad7982", (kernel_ulong_t)&ad7982_chip_info }, - { "ad7983", (kernel_ulong_t)&ad7983_chip_info }, - { "ad7984", (kernel_ulong_t)&ad7984_chip_info }, - { "ad7988-1", (kernel_ulong_t)&ad7988_1_chip_info }, - { "ad7988-5", (kernel_ulong_t)&ad7988_5_chip_info }, + { .name = "ad4000", .driver_data = (kernel_ulong_t)&ad4000_chip_info }, + { .name = "ad4001", .driver_data = (kernel_ulong_t)&ad4001_chip_info }, + { .name = "ad4002", .driver_data = (kernel_ulong_t)&ad4002_chip_info }, + { .name = "ad4003", .driver_data = (kernel_ulong_t)&ad4003_chip_info }, + { .name = "ad4004", .driver_data = (kernel_ulong_t)&ad4004_chip_info }, + { .name = "ad4005", .driver_data = (kernel_ulong_t)&ad4005_chip_info }, + { .name = "ad4006", .driver_data = (kernel_ulong_t)&ad4006_chip_info }, + { .name = "ad4007", .driver_data = (kernel_ulong_t)&ad4007_chip_info }, + { .name = "ad4008", .driver_data = (kernel_ulong_t)&ad4008_chip_info }, + { .name = "ad4010", .driver_data = (kernel_ulong_t)&ad4010_chip_info }, + { .name = "ad4011", .driver_data = (kernel_ulong_t)&ad4011_chip_info }, + { .name = "ad4020", .driver_data = (kernel_ulong_t)&ad4020_chip_info }, + { .name = "ad4021", .driver_data = (kernel_ulong_t)&ad4021_chip_info }, + { .name = "ad4022", .driver_data = (kernel_ulong_t)&ad4022_chip_info }, + { .name = "adaq4001", .driver_data = (kernel_ulong_t)&adaq4001_chip_info }, + { .name = "adaq4003", .driver_data = (kernel_ulong_t)&adaq4003_chip_info }, + { .name = "ad7685", .driver_data = (kernel_ulong_t)&ad7685_chip_info }, + { .name = "ad7686", .driver_data = (kernel_ulong_t)&ad7686_chip_info }, + { .name = "ad7687", .driver_data = (kernel_ulong_t)&ad7687_chip_info }, + { .name = "ad7688", .driver_data = (kernel_ulong_t)&ad7688_chip_info }, + { .name = "ad7690", .driver_data = (kernel_ulong_t)&ad7690_chip_info }, + { .name = "ad7691", .driver_data = (kernel_ulong_t)&ad7691_chip_info }, + { .name = "ad7693", .driver_data = (kernel_ulong_t)&ad7693_chip_info }, + { .name = "ad7942", .driver_data = (kernel_ulong_t)&ad7942_chip_info }, + { .name = "ad7946", .driver_data = (kernel_ulong_t)&ad7946_chip_info }, + { .name = "ad7980", .driver_data = (kernel_ulong_t)&ad7980_chip_info }, + { .name = "ad7982", .driver_data = (kernel_ulong_t)&ad7982_chip_info }, + { .name = "ad7983", .driver_data = (kernel_ulong_t)&ad7983_chip_info }, + { .name = "ad7984", .driver_data = (kernel_ulong_t)&ad7984_chip_info }, + { .name = "ad7988-1", .driver_data = (kernel_ulong_t)&ad7988_1_chip_info }, + { .name = "ad7988-5", .driver_data = (kernel_ulong_t)&ad7988_5_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad4000_id); diff --git a/drivers/iio/adc/ad4030.c b/drivers/iio/adc/ad4030.c index 68446db9bef1..e97400a1aa48 100644 --- a/drivers/iio/adc/ad4030.c +++ b/drivers/iio/adc/ad4030.c @@ -14,15 +14,26 @@ */ #include <linux/bitfield.h> +#include <linux/cleanup.h> #include <linux/clk.h> -#include <linux/iio/iio.h> -#include <linux/iio/trigger_consumer.h> -#include <linux/iio/triggered_buffer.h> +#include <linux/dmaengine.h> +#include <linux/limits.h> +#include <linux/log2.h> +#include <linux/math64.h> +#include <linux/minmax.h> +#include <linux/pwm.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> +#include <linux/spi/offload/consumer.h> #include <linux/spi/spi.h> #include <linux/unaligned.h> #include <linux/units.h> +#include <linux/types.h> + +#include <linux/iio/buffer-dmaengine.h> +#include <linux/iio/iio.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> #define AD4030_REG_INTERFACE_CONFIG_A 0x00 #define AD4030_REG_INTERFACE_CONFIG_A_SW_RESET (BIT(0) | BIT(7)) @@ -37,6 +48,8 @@ #define AD4030_REG_CHIP_GRADE_AD4630_24_GRADE 0x00 #define AD4030_REG_CHIP_GRADE_AD4632_16_GRADE 0x05 #define AD4030_REG_CHIP_GRADE_AD4632_24_GRADE 0x02 +#define AD4030_REG_CHIP_GRADE_ADAQ4216_GRADE 0x1E +#define AD4030_REG_CHIP_GRADE_ADAQ4224_GRADE 0x1C #define AD4030_REG_CHIP_GRADE_MASK_CHIP_GRADE GENMASK(7, 3) #define AD4030_REG_SCRATCH_PAD 0x0A #define AD4030_REG_SPI_REVISION 0x0B @@ -111,6 +124,12 @@ #define AD4632_TCYC_NS 2000 #define AD4632_TCYC_ADJUSTED_NS (AD4632_TCYC_NS - AD4030_TCNVL_NS) #define AD4030_TRESET_COM_DELAY_MS 750 +/* Datasheet says 9.8ns, so use the closest integer value */ +#define AD4030_TQUIET_CNV_DELAY_NS 10 + +/* HARDWARE_GAIN */ +#define ADAQ4616_PGA_PINS 2 +#define ADAQ4616_PGA_GAIN_MAX_NANO (NANO * 2 / 3) enum ad4030_out_mode { AD4030_OUT_DATA_MD_DIFF, @@ -132,15 +151,35 @@ enum { AD4030_SCAN_TYPE_AVG, }; +/* + * Gains computed as fractions of 1000 so they can be expressed by integers. + */ +static const int adaq4216_hw_gains_vpv[] = { + 1 * MILLI / 3, /* 0.333 */ + 5 * MILLI / 9, /* 0.555 */ + 20 * MILLI / 9, /* 0.2222 */ + 20 * MILLI / 3, /* 0.6666 */ +}; + +static const int adaq4216_hw_gains_frac[][2] = { + { 1, 3 }, /* 1/3 V/V gain */ + { 5, 9 }, /* 5/9 V/V gain */ + { 20, 9 }, /* 20/9 V/V gain */ + { 20, 3 }, /* 20/3 V/V gain */ +}; + struct ad4030_chip_info { const char *name; const unsigned long *available_masks; const struct iio_chan_spec channels[AD4030_MAX_IIO_CHANNEL_NB]; + const struct iio_chan_spec offload_channels[AD4030_MAX_IIO_CHANNEL_NB]; u8 grade; u8 precision_bits; + bool has_pga; /* Number of hardware channels */ int num_voltage_inputs; unsigned int tcyc_ns; + unsigned int max_sample_rate_hz; }; struct ad4030_state { @@ -153,6 +192,18 @@ struct ad4030_state { int offset_avail[3]; unsigned int avg_log2; enum ad4030_out_mode mode; + /* Offload sampling */ + struct spi_transfer offload_xfer; + struct spi_message offload_msg; + struct spi_offload *offload; + struct spi_offload_trigger *offload_trigger; + struct spi_offload_trigger_config offload_trigger_config; + struct pwm_device *cnv_trigger; + size_t scale_avail_size; + struct pwm_waveform cnv_wf; + unsigned int scale_avail[ARRAY_SIZE(adaq4216_hw_gains_vpv)][2]; + struct gpio_descs *pga_gpios; + unsigned int pga_index; /* * DMA (thus cache coherency maintenance) requires the transfer buffers @@ -209,8 +260,9 @@ struct ad4030_state { * - voltage0-voltage1 * - voltage2-voltage3 */ -#define AD4030_CHAN_DIFF(_idx, _scan_type) { \ +#define __AD4030_CHAN_DIFF(_idx, _scan_type, _offload, _pga) { \ .info_mask_shared_by_all = \ + (_offload ? BIT(IIO_CHAN_INFO_SAMP_FREQ) : 0) | \ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ .info_mask_shared_by_all_available = \ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ @@ -219,6 +271,7 @@ struct ad4030_state { BIT(IIO_CHAN_INFO_CALIBBIAS) | \ BIT(IIO_CHAN_INFO_RAW), \ .info_mask_separate_available = BIT(IIO_CHAN_INFO_CALIBBIAS) | \ + (_pga ? BIT(IIO_CHAN_INFO_SCALE) : 0) | \ BIT(IIO_CHAN_INFO_CALIBSCALE), \ .type = IIO_VOLTAGE, \ .indexed = 1, \ @@ -232,10 +285,33 @@ struct ad4030_state { .num_ext_scan_type = ARRAY_SIZE(_scan_type), \ } +#define AD4030_CHAN_DIFF(_idx, _scan_type) \ + __AD4030_CHAN_DIFF(_idx, _scan_type, 0, 0) + +#define AD4030_OFFLOAD_CHAN_DIFF(_idx, _scan_type) \ + __AD4030_CHAN_DIFF(_idx, _scan_type, 1, 0) + +#define ADAQ4216_CHAN_DIFF(_idx, _scan_type) \ + __AD4030_CHAN_DIFF(_idx, _scan_type, 0, 1) + +#define ADAQ4216_OFFLOAD_CHAN_DIFF(_idx, _scan_type) \ + __AD4030_CHAN_DIFF(_idx, _scan_type, 1, 1) + +/* + * AD4030 can average over 2^N samples, where N = 1, 2, 3, ..., 16. + * We use N = 0 to mean no sample averaging. + */ static const int ad4030_average_modes[] = { - 1, 2, 4, 8, 16, 32, 64, 128, - 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, - 65536, + BIT(0), /* No sampling average */ + BIT(1), BIT(2), BIT(3), BIT(4), + BIT(5), BIT(6), BIT(7), BIT(8), + BIT(9), BIT(10), BIT(11), BIT(12), + BIT(13), BIT(14), BIT(15), BIT(16), +}; + +static const struct spi_offload_config ad4030_offload_config = { + .capability_flags = SPI_OFFLOAD_CAP_TRIGGER | + SPI_OFFLOAD_CAP_RX_STREAM_DMA, }; static int ad4030_enter_config_mode(struct ad4030_state *st) @@ -377,6 +453,65 @@ static const struct regmap_config ad4030_regmap_config = { .max_register = AD4030_REG_DIG_ERR, }; +static void ad4030_fill_scale_avail(struct ad4030_state *st) +{ + unsigned int mag_bits, int_part, fract_part; + u64 range; + + /* + * The maximum precision of differential channels is retrieved from the + * chip properties. The output code of differential channels is in two's + * complement format (i.e. signed), so the MSB is the sign bit and only + * (precision_bits - 1) bits express voltage magnitude. + */ + mag_bits = st->chip->precision_bits - 1; + + for (unsigned int i = 0; i < ARRAY_SIZE(adaq4216_hw_gains_frac); i++) { + range = mult_frac(st->vref_uv, adaq4216_hw_gains_frac[i][1], + adaq4216_hw_gains_frac[i][0]); + /* + * If range were in mV, we would multiply it by NANO below. + * Though, range is in µV so multiply it by MICRO only so the + * result after right shift and division scales output codes to + * millivolts. + */ + int_part = div_u64_rem((range * MICRO) >> mag_bits, NANO, &fract_part); + st->scale_avail[i][0] = int_part; + st->scale_avail[i][1] = fract_part; + } +} + +static int ad4030_set_pga_gain(struct ad4030_state *st) +{ + DECLARE_BITMAP(bitmap, ADAQ4616_PGA_PINS) = { }; + + bitmap_write(bitmap, st->pga_index, 0, ADAQ4616_PGA_PINS); + + return gpiod_multi_set_value_cansleep(st->pga_gpios, bitmap); +} + +static int ad4030_set_pga(struct iio_dev *indio_dev, int gain_int, int gain_fract) +{ + struct ad4030_state *st = iio_priv(indio_dev); + unsigned int mag_bits = st->chip->precision_bits - 1; + unsigned int tmp; + u64 gain_nano; + + if (!st->pga_gpios) + return -EINVAL; + + gain_nano = gain_int * NANO + gain_fract; + if (!in_range(gain_nano, 1, ADAQ4616_PGA_GAIN_MAX_NANO)) + return -EINVAL; + + tmp = DIV_ROUND_CLOSEST_ULL(gain_nano << mag_bits, NANO); + gain_nano = DIV_ROUND_CLOSEST(st->vref_uv, tmp); + st->pga_index = find_closest(gain_nano, adaq4216_hw_gains_vpv, + ARRAY_SIZE(adaq4216_hw_gains_vpv)); + + return ad4030_set_pga_gain(st); +} + static int ad4030_get_chan_scale(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, @@ -389,6 +524,13 @@ static int ad4030_get_chan_scale(struct iio_dev *indio_dev, if (IS_ERR(scan_type)) return PTR_ERR(scan_type); + /* The LSB of the 8-bit common-mode data is always vref/256. */ + if (st->chip->has_pga && scan_type->realbits != 8) { + *val = st->scale_avail[st->pga_index][0]; + *val2 = st->scale_avail[st->pga_index][1]; + return IIO_VAL_INT_PLUS_NANO; + } + if (chan->differential) *val = (st->vref_uv * 2) / MILLI; else @@ -451,6 +593,102 @@ static int ad4030_get_chan_calibbias(struct iio_dev *indio_dev, } } +static void ad4030_get_sampling_freq(struct ad4030_state *st, int *freq) +{ + struct spi_offload_trigger_config *config = &st->offload_trigger_config; + + /* + * Conversion data is fetched from the device when the offload transfer + * is triggered. Thus, provide the SPI offload trigger frequency as the + * sampling frequency. + */ + *freq = config->periodic.frequency_hz; +} + +static int ad4030_update_conversion_rate(struct ad4030_state *st, + unsigned int freq_hz, unsigned int avg_log2) +{ + struct spi_offload_trigger_config *config = &st->offload_trigger_config; + unsigned int offload_period_ns, cnv_rate_hz; + struct pwm_waveform cnv_wf = { }; + u64 target = AD4030_TCNVH_NS; + u64 offload_offset_ns; + int ret; + + /* + * When averaging/oversampling over N samples, we fire the offload + * trigger once at every N pulses of the CNV signal. Conversely, the CNV + * signal needs to be N times faster than the offload trigger. Take that + * into account to correctly re-evaluate both the PWM waveform connected + * to CNV and the SPI offload trigger. + */ + cnv_rate_hz = freq_hz << avg_log2; + + cnv_wf.period_length_ns = DIV_ROUND_CLOSEST(NSEC_PER_SEC, cnv_rate_hz); + /* + * The datasheet lists a minimum time of 9.8 ns, but no maximum. If the + * rounded PWM's value is less than 10, increase the target value by 10 + * and attempt to round the waveform again, until the value is at least + * 10 ns. Use a separate variable to represent the target in case the + * rounding is severe enough to keep putting the first few results under + * the minimum 10ns condition checked by the while loop. + */ + do { + cnv_wf.duty_length_ns = target; + ret = pwm_round_waveform_might_sleep(st->cnv_trigger, &cnv_wf); + if (ret) + return ret; + target += AD4030_TCNVH_NS; + } while (cnv_wf.duty_length_ns < AD4030_TCNVH_NS); + + /* + * The CNV waveform period (period_length_ns) might get rounded down by + * pwm_round_waveform_might_sleep(). Check the resultant PWM period + * is not smaller than the minimum data conversion cycle time. + */ + if (!in_range(cnv_wf.period_length_ns, AD4030_TCYC_NS, INT_MAX)) + return -EINVAL; + + offload_period_ns = DIV_ROUND_CLOSEST(NSEC_PER_SEC, freq_hz); + + config->periodic.frequency_hz = DIV_ROUND_UP(HZ_PER_GHZ, offload_period_ns); + + /* + * The hardware does the capture on zone 2 (when SPI trigger PWM + * is used). This means that the SPI trigger signal should happen at + * tsync + tquiet_con_delay being tsync the conversion signal period + * and tquiet_con_delay 9.8ns. Hence set the PWM phase accordingly. + * + * The PWM waveform API only supports nanosecond resolution right now, + * so round this setting to the closest available value. + */ + offload_offset_ns = AD4030_TQUIET_CNV_DELAY_NS; + do { + config->periodic.offset_ns = offload_offset_ns; + ret = spi_offload_trigger_validate(st->offload_trigger, config); + if (ret) + return ret; + offload_offset_ns += AD4030_TQUIET_CNV_DELAY_NS; + } while (config->periodic.offset_ns < AD4030_TQUIET_CNV_DELAY_NS); + + st->cnv_wf = cnv_wf; + + return 0; +} + +static int ad4030_set_sampling_freq(struct iio_dev *indio_dev, int freq_hz) +{ + struct ad4030_state *st = iio_priv(indio_dev); + + if (freq_hz == 0) + return -EINVAL; + + if (!in_range(freq_hz, 0, st->chip->max_sample_rate_hz)) + return -ERANGE; + + return ad4030_update_conversion_rate(st, freq_hz, st->avg_log2); +} + static int ad4030_set_chan_calibscale(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int gain_int, @@ -510,11 +748,30 @@ static int ad4030_set_avg_frame_len(struct iio_dev *dev, int avg_val) struct ad4030_state *st = iio_priv(dev); unsigned int avg_log2 = ilog2(avg_val); unsigned int last_avg_idx = ARRAY_SIZE(ad4030_average_modes) - 1; + int freq_hz; int ret; if (avg_val < 0 || avg_val > ad4030_average_modes[last_avg_idx]) return -EINVAL; + if (st->offload_trigger) { + /* + * The sample averaging and sampling frequency configurations + * are mutually dependent on each other. That's because the + * effective data sample rate is fCNV / 2^N, where N is the + * number of samples being averaged. + * + * When SPI offload is supported and we have control over the + * sample rate, the conversion start signal (CNV) and the SPI + * offload trigger frequencies must be re-evaluated so data is + * fetched only after 'avg_val' conversions. + */ + ad4030_get_sampling_freq(st, &freq_hz); + ret = ad4030_update_conversion_rate(st, freq_hz, avg_log2); + if (ret) + return ret; + } + ret = regmap_write(st->regmap, AD4030_REG_AVG, AD4030_REG_AVG_MASK_AVG_SYNC | FIELD_PREP(AD4030_REG_AVG_MASK_AVG_VAL, avg_log2)); @@ -623,7 +880,7 @@ static int ad4030_conversion(struct iio_dev *indio_dev) /* Add one byte if we are using a differential + common byte mode */ bytes_to_read += (st->mode == AD4030_OUT_DATA_MD_24_DIFF_8_COM || st->mode == AD4030_OUT_DATA_MD_16_DIFF_8_COM) ? 1 : 0; - /* Mulitiply by the number of hardware channels */ + /* Multiply by the number of hardware channels */ bytes_to_read *= st->chip->num_voltage_inputs; for (i = 0; i < cnv_nb; i++) { @@ -742,6 +999,15 @@ static int ad4030_read_avail(struct iio_dev *indio_dev, *length = ARRAY_SIZE(ad4030_average_modes); return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SCALE: + if (st->scale_avail_size == 1) + *vals = (int *)st->scale_avail[st->pga_index]; + else + *vals = (int *)st->scale_avail; + *length = st->scale_avail_size * 2; /* print int and nano part */ + *type = IIO_VAL_INT_PLUS_NANO; + return IIO_AVAIL_LIST; + default: return -EINVAL; } @@ -767,6 +1033,10 @@ static int ad4030_read_raw_dispatch(struct iio_dev *indio_dev, *val = BIT(st->avg_log2); return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + ad4030_get_sampling_freq(st, val); + return IIO_VAL_INT; + default: return -EINVAL; } @@ -807,6 +1077,12 @@ static int ad4030_write_raw_dispatch(struct iio_dev *indio_dev, case IIO_CHAN_INFO_OVERSAMPLING_RATIO: return ad4030_set_avg_frame_len(indio_dev, val); + case IIO_CHAN_INFO_SAMP_FREQ: + return ad4030_set_sampling_freq(indio_dev, val); + + case IIO_CHAN_INFO_SCALE: + return ad4030_set_pga(indio_dev, val, val2); + default: return -EINVAL; } @@ -828,6 +1104,17 @@ static int ad4030_write_raw(struct iio_dev *indio_dev, return ret; } +static int ad4030_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; + default: + return IIO_VAL_INT_PLUS_MICRO; + } +} + static int ad4030_reg_access(struct iio_dev *indio_dev, unsigned int reg, unsigned int writeval, unsigned int *readval) { @@ -874,6 +1161,7 @@ static const struct iio_info ad4030_iio_info = { .read_avail = ad4030_read_avail, .read_raw = ad4030_read_raw, .write_raw = ad4030_write_raw, + .write_raw_get_fmt = &ad4030_write_raw_get_fmt, .debugfs_reg_access = ad4030_reg_access, .read_label = ad4030_read_label, .get_current_scan_type = ad4030_get_current_scan_type, @@ -896,6 +1184,86 @@ static const struct iio_buffer_setup_ops ad4030_buffer_setup_ops = { .validate_scan_mask = ad4030_validate_scan_mask, }; +static void ad4030_prepare_offload_msg(struct iio_dev *indio_dev) +{ + struct ad4030_state *st = iio_priv(indio_dev); + u8 offload_bpw; + + if (st->mode == AD4030_OUT_DATA_MD_30_AVERAGED_DIFF) + offload_bpw = 32; + else + offload_bpw = st->chip->precision_bits; + + st->offload_xfer.bits_per_word = offload_bpw; + st->offload_xfer.len = spi_bpw_to_bytes(offload_bpw); + st->offload_xfer.offload_flags = SPI_OFFLOAD_XFER_RX_STREAM; + spi_message_init_with_transfers(&st->offload_msg, &st->offload_xfer, 1); +} + +static int ad4030_offload_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ad4030_state *st = iio_priv(indio_dev); + unsigned int reg_modes; + int ret; + + /* + * When data from 2 analog input channels is output through a single + * bus line (interleaved mode (LANE_MD == 0b11)) and gets pushed through + * DMA, extra hardware is required to do the de-interleaving. While we + * don't support such hardware configurations, disallow interleaved mode + * when using SPI offload. + */ + ret = regmap_read(st->regmap, AD4030_REG_MODES, ®_modes); + if (ret) + return ret; + + if (st->chip->num_voltage_inputs > 1 && + FIELD_GET(AD4030_REG_MODES_MASK_LANE_MODE, reg_modes) == AD4030_LANE_MD_INTERLEAVED) + return -EINVAL; + + ad4030_prepare_offload_msg(indio_dev); + st->offload_msg.offload = st->offload; + ret = spi_optimize_message(st->spi, &st->offload_msg); + if (ret) + return ret; + + ret = pwm_set_waveform_might_sleep(st->cnv_trigger, &st->cnv_wf, false); + if (ret) + goto out_unoptimize; + + ret = spi_offload_trigger_enable(st->offload, st->offload_trigger, + &st->offload_trigger_config); + if (ret) + goto out_pwm_disable; + + return 0; + +out_pwm_disable: + pwm_disable(st->cnv_trigger); +out_unoptimize: + spi_unoptimize_message(&st->offload_msg); + + return ret; +} + +static int ad4030_offload_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ad4030_state *st = iio_priv(indio_dev); + + spi_offload_trigger_disable(st->offload, st->offload_trigger); + + pwm_disable(st->cnv_trigger); + + spi_unoptimize_message(&st->offload_msg); + + return 0; +} + +static const struct iio_buffer_setup_ops ad4030_offload_buffer_setup_ops = { + .postenable = &ad4030_offload_buffer_postenable, + .predisable = &ad4030_offload_buffer_predisable, +}; + static int ad4030_regulators_get(struct ad4030_state *st) { struct device *dev = &st->spi->dev; @@ -965,6 +1333,24 @@ static int ad4030_detect_chip_info(const struct ad4030_state *st) return 0; } +static int ad4030_pwm_get(struct ad4030_state *st) +{ + struct device *dev = &st->spi->dev; + + st->cnv_trigger = devm_pwm_get(dev, NULL); + if (IS_ERR(st->cnv_trigger)) + return dev_err_probe(dev, PTR_ERR(st->cnv_trigger), + "Failed to get CNV PWM\n"); + + /* + * Preemptively disable the PWM, since we only want to enable it with + * the buffer. + */ + pwm_disable(st->cnv_trigger); + + return 0; +} + static int ad4030_config(struct ad4030_state *st) { int ret; @@ -992,6 +1378,51 @@ static int ad4030_config(struct ad4030_state *st) return 0; } +static int ad4030_spi_offload_setup(struct iio_dev *indio_dev, + struct ad4030_state *st) +{ + struct device *dev = &st->spi->dev; + struct dma_chan *rx_dma; + + indio_dev->setup_ops = &ad4030_offload_buffer_setup_ops; + + st->offload_trigger = devm_spi_offload_trigger_get(dev, st->offload, + SPI_OFFLOAD_TRIGGER_PERIODIC); + if (IS_ERR(st->offload_trigger)) + return dev_err_probe(dev, PTR_ERR(st->offload_trigger), + "failed to get offload trigger\n"); + + st->offload_trigger_config.type = SPI_OFFLOAD_TRIGGER_PERIODIC; + + rx_dma = devm_spi_offload_rx_stream_request_dma_chan(dev, st->offload); + if (IS_ERR(rx_dma)) + return dev_err_probe(dev, PTR_ERR(rx_dma), + "failed to get offload RX DMA\n"); + + return devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev, rx_dma, + IIO_BUFFER_DIRECTION_IN); +} + +static int ad4030_setup_pga(struct device *dev, struct iio_dev *indio_dev, + struct ad4030_state *st) +{ + /* Setup GPIOs for PGA control */ + st->pga_gpios = devm_gpiod_get_array(dev, "pga", GPIOD_OUT_LOW); + if (IS_ERR(st->pga_gpios)) + return dev_err_probe(dev, PTR_ERR(st->pga_gpios), + "Failed to get PGA gpios.\n"); + + if (st->pga_gpios->ndescs != ADAQ4616_PGA_PINS) + return dev_err_probe(dev, -EINVAL, + "Expected %d GPIOs for PGA control.\n", + ADAQ4616_PGA_PINS); + + st->scale_avail_size = ARRAY_SIZE(adaq4216_hw_gains_vpv); + st->pga_index = 0; + + return 0; +} + static int ad4030_probe(struct spi_device *spi) { struct device *dev = &spi->dev; @@ -1034,6 +1465,14 @@ static int ad4030_probe(struct spi_device *spi) if (ret) return ret; + if (st->chip->has_pga) { + ret = ad4030_setup_pga(dev, indio_dev, st); + if (ret) + return ret; + + ad4030_fill_scale_avail(st); + } + ret = ad4030_config(st); if (ret) return ret; @@ -1043,24 +1482,58 @@ static int ad4030_probe(struct spi_device *spi) return dev_err_probe(dev, PTR_ERR(st->cnv_gpio), "Failed to get cnv gpio\n"); - /* - * One hardware channel is split in two software channels when using - * common byte mode. Add one more channel for the timestamp. - */ - indio_dev->num_channels = 2 * st->chip->num_voltage_inputs + 1; indio_dev->name = st->chip->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &ad4030_iio_info; - indio_dev->channels = st->chip->channels; indio_dev->available_scan_masks = st->chip->available_masks; - ret = devm_iio_triggered_buffer_setup(dev, indio_dev, - iio_pollfunc_store_time, - ad4030_trigger_handler, - &ad4030_buffer_setup_ops); - if (ret) - return dev_err_probe(dev, ret, - "Failed to setup triggered buffer\n"); + st->offload = devm_spi_offload_get(dev, spi, &ad4030_offload_config); + ret = PTR_ERR_OR_ZERO(st->offload); + /* Fall back to low speed usage when no SPI offload is available. */ + if (ret == -ENODEV) { + /* + * One hardware channel is split in two software channels when + * using common byte mode. Add one more channel for the timestamp. + */ + indio_dev->num_channels = 2 * st->chip->num_voltage_inputs + 1; + indio_dev->channels = st->chip->channels; + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + ad4030_trigger_handler, + &ad4030_buffer_setup_ops); + if (ret) + return dev_err_probe(dev, ret, + "Failed to setup triggered buffer\n"); + } else if (ret) { + return dev_err_probe(dev, ret, "failed to get offload\n"); + } else { + /* + * Offloaded SPI transfers can't support software timestamp so + * no additional timestamp channel is added. + */ + indio_dev->num_channels = st->chip->num_voltage_inputs; + indio_dev->channels = st->chip->offload_channels; + ret = ad4030_spi_offload_setup(indio_dev, st); + if (ret) + return dev_err_probe(dev, ret, + "Failed to setup SPI offload\n"); + + ret = ad4030_pwm_get(st); + if (ret) + return dev_err_probe(dev, ret, "Failed to get PWM\n"); + + /* + * Start with a slower sampling rate so there is some room for + * adjusting the sample averaging and the sampling frequency + * without hitting the maximum conversion rate. + */ + ret = ad4030_update_conversion_rate(st, st->chip->max_sample_rate_hz >> 4, + st->avg_log2); + if (ret) + return dev_err_probe(dev, ret, + "Failed to set offload samp freq\n"); + } return devm_iio_device_register(dev, indio_dev); } @@ -1098,11 +1571,28 @@ static const struct iio_scan_type ad4030_24_scan_types[] = { }, }; -static const struct iio_scan_type ad4030_16_scan_types[] = { +static const struct iio_scan_type ad4030_24_offload_scan_types[] = { [AD4030_SCAN_TYPE_NORMAL] = { .sign = 's', + .realbits = 24, .storagebits = 32, + .shift = 0, + .endianness = IIO_CPU, + }, + [AD4030_SCAN_TYPE_AVG] = { + .sign = 's', + .realbits = 30, + .storagebits = 32, + .shift = 2, + .endianness = IIO_CPU, + }, +}; + +static const struct iio_scan_type ad4030_16_scan_types[] = { + [AD4030_SCAN_TYPE_NORMAL] = { + .sign = 's', .realbits = 16, + .storagebits = 32, .shift = 16, .endianness = IIO_BE, }, @@ -1115,6 +1605,23 @@ static const struct iio_scan_type ad4030_16_scan_types[] = { } }; +static const struct iio_scan_type ad4030_16_offload_scan_types[] = { + [AD4030_SCAN_TYPE_NORMAL] = { + .sign = 's', + .realbits = 16, + .storagebits = 32, + .shift = 0, + .endianness = IIO_CPU, + }, + [AD4030_SCAN_TYPE_AVG] = { + .sign = 's', + .realbits = 30, + .storagebits = 32, + .shift = 2, + .endianness = IIO_CPU, + }, +}; + static const struct ad4030_chip_info ad4030_24_chip_info = { .name = "ad4030-24", .available_masks = ad4030_channel_masks, @@ -1123,10 +1630,14 @@ static const struct ad4030_chip_info ad4030_24_chip_info = { AD4030_CHAN_CMO(1, 0), IIO_CHAN_SOFT_TIMESTAMP(2), }, + .offload_channels = { + AD4030_OFFLOAD_CHAN_DIFF(0, ad4030_24_offload_scan_types), + }, .grade = AD4030_REG_CHIP_GRADE_AD4030_24_GRADE, .precision_bits = 24, .num_voltage_inputs = 1, .tcyc_ns = AD4030_TCYC_ADJUSTED_NS, + .max_sample_rate_hz = 2 * HZ_PER_MHZ, }; static const struct ad4030_chip_info ad4630_16_chip_info = { @@ -1139,10 +1650,15 @@ static const struct ad4030_chip_info ad4630_16_chip_info = { AD4030_CHAN_CMO(3, 1), IIO_CHAN_SOFT_TIMESTAMP(4), }, + .offload_channels = { + AD4030_OFFLOAD_CHAN_DIFF(0, ad4030_16_offload_scan_types), + AD4030_OFFLOAD_CHAN_DIFF(1, ad4030_16_offload_scan_types), + }, .grade = AD4030_REG_CHIP_GRADE_AD4630_16_GRADE, .precision_bits = 16, .num_voltage_inputs = 2, .tcyc_ns = AD4030_TCYC_ADJUSTED_NS, + .max_sample_rate_hz = 2 * HZ_PER_MHZ, }; static const struct ad4030_chip_info ad4630_24_chip_info = { @@ -1155,10 +1671,15 @@ static const struct ad4030_chip_info ad4630_24_chip_info = { AD4030_CHAN_CMO(3, 1), IIO_CHAN_SOFT_TIMESTAMP(4), }, + .offload_channels = { + AD4030_OFFLOAD_CHAN_DIFF(0, ad4030_24_offload_scan_types), + AD4030_OFFLOAD_CHAN_DIFF(1, ad4030_24_offload_scan_types), + }, .grade = AD4030_REG_CHIP_GRADE_AD4630_24_GRADE, .precision_bits = 24, .num_voltage_inputs = 2, .tcyc_ns = AD4030_TCYC_ADJUSTED_NS, + .max_sample_rate_hz = 2 * HZ_PER_MHZ, }; static const struct ad4030_chip_info ad4632_16_chip_info = { @@ -1171,10 +1692,15 @@ static const struct ad4030_chip_info ad4632_16_chip_info = { AD4030_CHAN_CMO(3, 1), IIO_CHAN_SOFT_TIMESTAMP(4), }, + .offload_channels = { + AD4030_OFFLOAD_CHAN_DIFF(0, ad4030_16_offload_scan_types), + AD4030_OFFLOAD_CHAN_DIFF(1, ad4030_16_offload_scan_types), + }, .grade = AD4030_REG_CHIP_GRADE_AD4632_16_GRADE, .precision_bits = 16, .num_voltage_inputs = 2, .tcyc_ns = AD4632_TCYC_ADJUSTED_NS, + .max_sample_rate_hz = 500 * HZ_PER_KHZ, }; static const struct ad4030_chip_info ad4632_24_chip_info = { @@ -1187,18 +1713,63 @@ static const struct ad4030_chip_info ad4632_24_chip_info = { AD4030_CHAN_CMO(3, 1), IIO_CHAN_SOFT_TIMESTAMP(4), }, + .offload_channels = { + AD4030_OFFLOAD_CHAN_DIFF(0, ad4030_24_offload_scan_types), + AD4030_OFFLOAD_CHAN_DIFF(1, ad4030_24_offload_scan_types), + }, .grade = AD4030_REG_CHIP_GRADE_AD4632_24_GRADE, .precision_bits = 24, .num_voltage_inputs = 2, .tcyc_ns = AD4632_TCYC_ADJUSTED_NS, + .max_sample_rate_hz = 500 * HZ_PER_KHZ, +}; + +static const struct ad4030_chip_info adaq4216_chip_info = { + .name = "adaq4216", + .available_masks = ad4030_channel_masks, + .channels = { + ADAQ4216_CHAN_DIFF(0, ad4030_16_scan_types), + AD4030_CHAN_CMO(1, 0), + IIO_CHAN_SOFT_TIMESTAMP(2), + }, + .offload_channels = { + ADAQ4216_OFFLOAD_CHAN_DIFF(0, ad4030_16_offload_scan_types), + }, + .grade = AD4030_REG_CHIP_GRADE_ADAQ4216_GRADE, + .precision_bits = 16, + .has_pga = true, + .num_voltage_inputs = 1, + .tcyc_ns = AD4030_TCYC_ADJUSTED_NS, + .max_sample_rate_hz = 2 * HZ_PER_MHZ, +}; + +static const struct ad4030_chip_info adaq4224_chip_info = { + .name = "adaq4224", + .available_masks = ad4030_channel_masks, + .channels = { + ADAQ4216_CHAN_DIFF(0, ad4030_24_scan_types), + AD4030_CHAN_CMO(1, 0), + IIO_CHAN_SOFT_TIMESTAMP(2), + }, + .offload_channels = { + ADAQ4216_OFFLOAD_CHAN_DIFF(0, ad4030_24_offload_scan_types), + }, + .grade = AD4030_REG_CHIP_GRADE_ADAQ4224_GRADE, + .precision_bits = 24, + .has_pga = true, + .num_voltage_inputs = 1, + .tcyc_ns = AD4030_TCYC_ADJUSTED_NS, + .max_sample_rate_hz = 2 * HZ_PER_MHZ, }; static const struct spi_device_id ad4030_id_table[] = { - { "ad4030-24", (kernel_ulong_t)&ad4030_24_chip_info }, - { "ad4630-16", (kernel_ulong_t)&ad4630_16_chip_info }, - { "ad4630-24", (kernel_ulong_t)&ad4630_24_chip_info }, - { "ad4632-16", (kernel_ulong_t)&ad4632_16_chip_info }, - { "ad4632-24", (kernel_ulong_t)&ad4632_24_chip_info }, + { .name = "ad4030-24", .driver_data = (kernel_ulong_t)&ad4030_24_chip_info }, + { .name = "ad4630-16", .driver_data = (kernel_ulong_t)&ad4630_16_chip_info }, + { .name = "ad4630-24", .driver_data = (kernel_ulong_t)&ad4630_24_chip_info }, + { .name = "ad4632-16", .driver_data = (kernel_ulong_t)&ad4632_16_chip_info }, + { .name = "ad4632-24", .driver_data = (kernel_ulong_t)&ad4632_24_chip_info }, + { .name = "adaq4216", .driver_data = (kernel_ulong_t)&adaq4216_chip_info }, + { .name = "adaq4224", .driver_data = (kernel_ulong_t)&adaq4224_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad4030_id_table); @@ -1209,6 +1780,8 @@ static const struct of_device_id ad4030_of_match[] = { { .compatible = "adi,ad4630-24", .data = &ad4630_24_chip_info }, { .compatible = "adi,ad4632-16", .data = &ad4632_16_chip_info }, { .compatible = "adi,ad4632-24", .data = &ad4632_24_chip_info }, + { .compatible = "adi,adaq4216", .data = &adaq4216_chip_info }, + { .compatible = "adi,adaq4224", .data = &adaq4224_chip_info }, { } }; MODULE_DEVICE_TABLE(of, ad4030_of_match); @@ -1226,3 +1799,4 @@ module_spi_driver(ad4030_driver); MODULE_AUTHOR("Esteban Blanc <eblanc@baylibre.com>"); MODULE_DESCRIPTION("Analog Devices AD4630 ADC family driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER"); diff --git a/drivers/iio/adc/ad4062.c b/drivers/iio/adc/ad4062.c index dd4ad32aa6f5..8e5984055b15 100644 --- a/drivers/iio/adc/ad4062.c +++ b/drivers/iio/adc/ad4062.c @@ -436,10 +436,9 @@ static int ad4062_check_ids(struct ad4062_state *st) return ret; val = be16_to_cpu(st->buf.be16); - if (val != AD4062_I3C_VENDOR) { - dev_err(dev, "Vendor ID x%x does not match expected value\n", val); - return -ENODEV; - } + if (val != AD4062_I3C_VENDOR) + return dev_err_probe(dev, -ENODEV, + "Vendor ID x%x does not match expected value\n", val); return 0; } @@ -719,10 +718,8 @@ static int ad4062_request_irq(struct iio_dev *indio_dev) } st->gpo_irq[1] = true; - return devm_request_threaded_irq(dev, ret, - ad4062_irq_handler_drdy, - NULL, IRQF_ONESHOT, indio_dev->name, - indio_dev); + return devm_request_irq(dev, ret, ad4062_irq_handler_drdy, + IRQF_NO_THREAD, indio_dev->name, indio_dev); } static const struct iio_trigger_ops ad4062_trigger_ops = { @@ -955,7 +952,7 @@ static int ad4062_write_raw_dispatch(struct ad4062_state *st, int val, int val2, default: return -EINVAL; } -}; +} static int ad4062_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, @@ -1199,11 +1196,14 @@ static int ad4062_write_event_value(struct iio_dev *indio_dev, * The AD4062 in burst averaging mode increases realbits from 16-bits to * 20-bits, increasing the storagebits from 16-bits to 32-bits. */ -static inline size_t ad4062_sizeof_storagebits(struct ad4062_state *st) +static inline int ad4062_sizeof_storagebits(struct ad4062_state *st) { const struct iio_scan_type *scan_type = iio_get_current_scan_type(st->indio_dev, st->chip->channels); + if (IS_ERR(scan_type)) + return PTR_ERR(scan_type); + return BITS_TO_BYTES(scan_type->storagebits); } @@ -1233,7 +1233,12 @@ static int pm_ad4062_triggered_buffer_postenable(struct ad4062_state *st) if (ret) return ret; - st->conv_sizeof = ad4062_sizeof_storagebits(st); + ret = ad4062_sizeof_storagebits(st); + if (ret < 0) + return ret; + + st->conv_sizeof = ret; + st->conv_addr = ad4062_get_conv_addr(st, st->conv_sizeof); /* CONV_READ requires read to trigger first sample. */ struct i3c_xfer xfer_sample[2] = { diff --git a/drivers/iio/adc/ad4080.c b/drivers/iio/adc/ad4080.c index 7cf3b6ed7940..04cd6628ebff 100644 --- a/drivers/iio/adc/ad4080.c +++ b/drivers/iio/adc/ad4080.c @@ -13,9 +13,9 @@ #include <linux/err.h> #include <linux/iio/backend.h> #include <linux/iio/iio.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/property.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> @@ -127,10 +127,18 @@ #define AD4080_SPI_READ BIT(7) #define AD4080_CHIP_ID 0x0050 #define AD4081_CHIP_ID 0x0051 +#define AD4082_CHIP_ID 0x0052 #define AD4083_CHIP_ID 0x0053 #define AD4084_CHIP_ID 0x0054 +#define AD4085_CHIP_ID 0x0055 #define AD4086_CHIP_ID 0x0056 #define AD4087_CHIP_ID 0x0057 +#define AD4088_CHIP_ID 0x0058 +#define AD4880_CHIP_ID 0x0059 +#define AD4883_CHIP_ID 0x005B +#define AD4884_CHIP_ID 0x005C + +#define AD4080_MAX_CHANNELS 2 #define AD4080_LVDS_CNV_CLK_CNT_MAX 7 @@ -176,8 +184,9 @@ struct ad4080_chip_info { }; struct ad4080_state { - struct regmap *regmap; - struct iio_backend *back; + struct spi_device *spi[AD4080_MAX_CHANNELS]; + struct regmap *regmap[AD4080_MAX_CHANNELS]; + struct iio_backend *back[AD4080_MAX_CHANNELS]; const struct ad4080_chip_info *info; /* * Synchronize access to members the of driver state, and ensure @@ -185,9 +194,8 @@ struct ad4080_state { */ struct mutex lock; unsigned int num_lanes; - unsigned int dec_rate; unsigned long clk_rate; - enum ad4080_filter_type filter_type; + enum ad4080_filter_type filter_type[AD4080_MAX_CHANNELS]; bool lvds_cnv_en; }; @@ -204,9 +212,9 @@ static int ad4080_reg_access(struct iio_dev *indio_dev, unsigned int reg, struct ad4080_state *st = iio_priv(indio_dev); if (readval) - return regmap_read(st->regmap, reg, readval); + return regmap_read(st->regmap[0], reg, readval); - return regmap_write(st->regmap, reg, writeval); + return regmap_write(st->regmap[0], reg, writeval); } static int ad4080_get_scale(struct ad4080_state *st, int *val, int *val2) @@ -227,8 +235,9 @@ static unsigned int ad4080_get_dec_rate(struct iio_dev *dev, struct ad4080_state *st = iio_priv(dev); int ret; unsigned int data; + unsigned int ch = chan->channel; - ret = regmap_read(st->regmap, AD4080_REG_FILTER_CONFIG, &data); + ret = regmap_read(st->regmap[ch], AD4080_REG_FILTER_CONFIG, &data); if (ret) return ret; @@ -240,13 +249,14 @@ static int ad4080_set_dec_rate(struct iio_dev *dev, unsigned int mode) { struct ad4080_state *st = iio_priv(dev); + unsigned int ch = chan->channel; guard(mutex)(&st->lock); - if ((st->filter_type >= SINC_5 && mode >= 512) || mode < 2) + if ((st->filter_type[ch] >= SINC_5 && mode >= 512) || mode < 2) return -EINVAL; - return regmap_update_bits(st->regmap, AD4080_REG_FILTER_CONFIG, + return regmap_update_bits(st->regmap[ch], AD4080_REG_FILTER_CONFIG, AD4080_FILTER_CONFIG_SINC_DEC_RATE_MSK, FIELD_PREP(AD4080_FILTER_CONFIG_SINC_DEC_RATE_MSK, (ilog2(mode) - 1))); @@ -266,15 +276,15 @@ static int ad4080_read_raw(struct iio_dev *indio_dev, dec_rate = ad4080_get_dec_rate(indio_dev, chan); if (dec_rate < 0) return dec_rate; - if (st->filter_type == SINC_5_COMP) + if (st->filter_type[chan->channel] == SINC_5_COMP) dec_rate *= 2; - if (st->filter_type) + if (st->filter_type[chan->channel]) *val = DIV_ROUND_CLOSEST(st->clk_rate, dec_rate); else *val = st->clk_rate; return IIO_VAL_INT; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - if (st->filter_type == FILTER_NONE) { + if (st->filter_type[chan->channel] == FILTER_NONE) { *val = 1; } else { *val = ad4080_get_dec_rate(indio_dev, chan); @@ -295,7 +305,7 @@ static int ad4080_write_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - if (st->filter_type == FILTER_NONE && val > 1) + if (st->filter_type[chan->channel] == FILTER_NONE && val > 1) return -EINVAL; return ad4080_set_dec_rate(indio_dev, chan, val); @@ -304,23 +314,23 @@ static int ad4080_write_raw(struct iio_dev *indio_dev, } } -static int ad4080_lvds_sync_write(struct ad4080_state *st) +static int ad4080_lvds_sync_write(struct ad4080_state *st, unsigned int ch) { - struct device *dev = regmap_get_device(st->regmap); + struct device *dev = regmap_get_device(st->regmap[ch]); int ret; - ret = regmap_set_bits(st->regmap, AD4080_REG_ADC_DATA_INTF_CONFIG_A, + ret = regmap_set_bits(st->regmap[ch], AD4080_REG_ADC_DATA_INTF_CONFIG_A, AD4080_ADC_DATA_INTF_CONFIG_A_INTF_CHK_EN); if (ret) return ret; - ret = iio_backend_interface_data_align(st->back, 10000); + ret = iio_backend_interface_data_align(st->back[ch], 10000); if (ret) return dev_err_probe(dev, ret, "Data alignment process failed\n"); dev_dbg(dev, "Success: Pattern correct and Locked!\n"); - return regmap_clear_bits(st->regmap, AD4080_REG_ADC_DATA_INTF_CONFIG_A, + return regmap_clear_bits(st->regmap[ch], AD4080_REG_ADC_DATA_INTF_CONFIG_A, AD4080_ADC_DATA_INTF_CONFIG_A_INTF_CHK_EN); } @@ -329,9 +339,10 @@ static int ad4080_get_filter_type(struct iio_dev *dev, { struct ad4080_state *st = iio_priv(dev); unsigned int data; + unsigned int ch = chan->channel; int ret; - ret = regmap_read(st->regmap, AD4080_REG_FILTER_CONFIG, &data); + ret = regmap_read(st->regmap[ch], AD4080_REG_FILTER_CONFIG, &data); if (ret) return ret; @@ -343,6 +354,7 @@ static int ad4080_set_filter_type(struct iio_dev *dev, unsigned int mode) { struct ad4080_state *st = iio_priv(dev); + unsigned int ch = chan->channel; int dec_rate; int ret; @@ -355,18 +367,18 @@ static int ad4080_set_filter_type(struct iio_dev *dev, if (mode >= SINC_5 && dec_rate >= 512) return -EINVAL; - ret = iio_backend_filter_type_set(st->back, mode); + ret = iio_backend_filter_type_set(st->back[ch], mode); if (ret) return ret; - ret = regmap_update_bits(st->regmap, AD4080_REG_FILTER_CONFIG, + ret = regmap_update_bits(st->regmap[ch], AD4080_REG_FILTER_CONFIG, AD4080_FILTER_CONFIG_FILTER_SEL_MSK, FIELD_PREP(AD4080_FILTER_CONFIG_FILTER_SEL_MSK, mode)); if (ret) return ret; - st->filter_type = mode; + st->filter_type[ch] = mode; return 0; } @@ -380,14 +392,14 @@ static int ad4080_read_avail(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - switch (st->filter_type) { + switch (st->filter_type[chan->channel]) { case FILTER_NONE: *vals = ad4080_dec_rate_none; *length = ARRAY_SIZE(ad4080_dec_rate_none); break; default: *vals = ad4080_dec_rate_avail; - *length = st->filter_type >= SINC_5 ? + *length = st->filter_type[chan->channel] >= SINC_5 ? (ARRAY_SIZE(ad4080_dec_rate_avail) - 2) : ARRAY_SIZE(ad4080_dec_rate_avail); break; @@ -399,6 +411,28 @@ static int ad4080_read_avail(struct iio_dev *indio_dev, } } +static int ad4880_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + struct ad4080_state *st = iio_priv(indio_dev); + int ret; + + for (unsigned int ch = 0; ch < st->info->num_channels; ch++) { + /* + * Each backend has a single channel (channel 0 from the + * backend's perspective), so always use channel index 0. + */ + if (test_bit(ch, scan_mask)) + ret = iio_backend_chan_enable(st->back[ch], 0); + else + ret = iio_backend_chan_disable(st->back[ch], 0); + if (ret) + return ret; + } + + return 0; +} + static const struct iio_info ad4080_iio_info = { .debugfs_reg_access = ad4080_reg_access, .read_raw = ad4080_read_raw, @@ -406,6 +440,19 @@ static const struct iio_info ad4080_iio_info = { .read_avail = ad4080_read_avail, }; +/* + * AD4880 needs update_scan_mode to enable/disable individual backend channels. + * Single-channel devices don't need this as their backends may not implement + * chan_enable/chan_disable operations. + */ +static const struct iio_info ad4880_iio_info = { + .debugfs_reg_access = ad4080_reg_access, + .read_raw = ad4080_read_raw, + .write_raw = ad4080_write_raw, + .read_avail = ad4080_read_avail, + .update_scan_mode = ad4880_update_scan_mode, +}; + static const struct iio_enum ad4080_filter_type_enum = { .items = ad4080_filter_type_iio_enum, .num_items = ARRAY_SIZE(ad4080_filter_type_iio_enum), @@ -420,17 +467,28 @@ static struct iio_chan_spec_ext_info ad4080_ext_info[] = { { } }; -#define AD4080_CHANNEL_DEFINE(bits, storage) { \ +/* + * AD4880 needs per-channel filter configuration since each channel has + * its own independent ADC with separate SPI interface. + */ +static struct iio_chan_spec_ext_info ad4880_ext_info[] = { + IIO_ENUM("filter_type", IIO_SEPARATE, &ad4080_filter_type_enum), + IIO_ENUM_AVAILABLE("filter_type", IIO_SEPARATE, + &ad4080_filter_type_enum), + { } +}; + +#define AD4080_CHANNEL_DEFINE(bits, storage, idx) { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ - .channel = 0, \ + .channel = (idx), \ .info_mask_separate = BIT(IIO_CHAN_INFO_SCALE), \ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ .info_mask_shared_by_all_available = \ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ .ext_info = ad4080_ext_info, \ - .scan_index = 0, \ + .scan_index = (idx), \ .scan_type = { \ .sign = 's', \ .realbits = (bits), \ @@ -438,17 +496,61 @@ static struct iio_chan_spec_ext_info ad4080_ext_info[] = { }, \ } -static const struct iio_chan_spec ad4080_channel = AD4080_CHANNEL_DEFINE(20, 32); +/* + * AD4880 has per-channel attributes (filter_type, oversampling_ratio, + * sampling_frequency) since each channel has its own independent ADC + * with separate SPI configuration interface. + */ +#define AD4880_CHANNEL_DEFINE(bits, storage, idx) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = (idx), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .info_mask_separate_available = \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .ext_info = ad4880_ext_info, \ + .scan_index = (idx), \ + .scan_type = { \ + .sign = 's', \ + .realbits = (bits), \ + .storagebits = (storage), \ + }, \ +} + +static const struct iio_chan_spec ad4080_channel = AD4080_CHANNEL_DEFINE(20, 32, 0); -static const struct iio_chan_spec ad4081_channel = AD4080_CHANNEL_DEFINE(20, 32); +static const struct iio_chan_spec ad4081_channel = AD4080_CHANNEL_DEFINE(20, 32, 0); -static const struct iio_chan_spec ad4083_channel = AD4080_CHANNEL_DEFINE(16, 16); +static const struct iio_chan_spec ad4082_channel = AD4080_CHANNEL_DEFINE(20, 32, 0); -static const struct iio_chan_spec ad4084_channel = AD4080_CHANNEL_DEFINE(16, 16); +static const struct iio_chan_spec ad4083_channel = AD4080_CHANNEL_DEFINE(16, 16, 0); -static const struct iio_chan_spec ad4086_channel = AD4080_CHANNEL_DEFINE(14, 16); +static const struct iio_chan_spec ad4084_channel = AD4080_CHANNEL_DEFINE(16, 16, 0); -static const struct iio_chan_spec ad4087_channel = AD4080_CHANNEL_DEFINE(14, 16); +static const struct iio_chan_spec ad4085_channel = AD4080_CHANNEL_DEFINE(16, 16, 0); + +static const struct iio_chan_spec ad4086_channel = AD4080_CHANNEL_DEFINE(14, 16, 0); + +static const struct iio_chan_spec ad4087_channel = AD4080_CHANNEL_DEFINE(14, 16, 0); + +static const struct iio_chan_spec ad4088_channel = AD4080_CHANNEL_DEFINE(14, 16, 0); + +static const struct iio_chan_spec ad4880_channels[] = { + AD4880_CHANNEL_DEFINE(20, 32, 0), + AD4880_CHANNEL_DEFINE(20, 32, 1), +}; + +static const struct iio_chan_spec ad4883_channels[] = { + AD4880_CHANNEL_DEFINE(16, 16, 0), + AD4880_CHANNEL_DEFINE(16, 16, 1), +}; + +static const struct iio_chan_spec ad4884_channels[] = { + AD4880_CHANNEL_DEFINE(16, 16, 0), + AD4880_CHANNEL_DEFINE(16, 16, 1), +}; static const struct ad4080_chip_info ad4080_chip_info = { .name = "ad4080", @@ -470,6 +572,16 @@ static const struct ad4080_chip_info ad4081_chip_info = { .lvds_cnv_clk_cnt_max = 2, }; +static const struct ad4080_chip_info ad4082_chip_info = { + .name = "ad4082", + .product_id = AD4082_CHIP_ID, + .scale_table = ad4080_scale_table, + .num_scales = ARRAY_SIZE(ad4080_scale_table), + .num_channels = 1, + .channels = &ad4082_channel, + .lvds_cnv_clk_cnt_max = 8, +}; + static const struct ad4080_chip_info ad4083_chip_info = { .name = "ad4083", .product_id = AD4083_CHIP_ID, @@ -490,6 +602,16 @@ static const struct ad4080_chip_info ad4084_chip_info = { .lvds_cnv_clk_cnt_max = 2, }; +static const struct ad4080_chip_info ad4085_chip_info = { + .name = "ad4085", + .product_id = AD4085_CHIP_ID, + .scale_table = ad4080_scale_table, + .num_scales = ARRAY_SIZE(ad4080_scale_table), + .num_channels = 1, + .channels = &ad4085_channel, + .lvds_cnv_clk_cnt_max = 8, +}; + static const struct ad4080_chip_info ad4086_chip_info = { .name = "ad4086", .product_id = AD4086_CHIP_ID, @@ -510,25 +632,64 @@ static const struct ad4080_chip_info ad4087_chip_info = { .lvds_cnv_clk_cnt_max = 1, }; -static int ad4080_setup(struct iio_dev *indio_dev) +static const struct ad4080_chip_info ad4088_chip_info = { + .name = "ad4088", + .product_id = AD4088_CHIP_ID, + .scale_table = ad4080_scale_table, + .num_scales = ARRAY_SIZE(ad4080_scale_table), + .num_channels = 1, + .channels = &ad4088_channel, + .lvds_cnv_clk_cnt_max = 8, +}; + +static const struct ad4080_chip_info ad4880_chip_info = { + .name = "ad4880", + .product_id = AD4880_CHIP_ID, + .scale_table = ad4080_scale_table, + .num_scales = ARRAY_SIZE(ad4080_scale_table), + .num_channels = 2, + .channels = ad4880_channels, + .lvds_cnv_clk_cnt_max = AD4080_LVDS_CNV_CLK_CNT_MAX, +}; + +static const struct ad4080_chip_info ad4883_chip_info = { + .name = "ad4883", + .product_id = AD4883_CHIP_ID, + .scale_table = ad4080_scale_table, + .num_scales = ARRAY_SIZE(ad4080_scale_table), + .num_channels = 2, + .channels = ad4883_channels, + .lvds_cnv_clk_cnt_max = 5, +}; + +static const struct ad4080_chip_info ad4884_chip_info = { + .name = "ad4884", + .product_id = AD4884_CHIP_ID, + .scale_table = ad4080_scale_table, + .num_scales = ARRAY_SIZE(ad4080_scale_table), + .num_channels = 2, + .channels = ad4884_channels, + .lvds_cnv_clk_cnt_max = 2, +}; + +static int ad4080_setup_channel(struct ad4080_state *st, unsigned int ch) { - struct ad4080_state *st = iio_priv(indio_dev); - struct device *dev = regmap_get_device(st->regmap); + struct device *dev = regmap_get_device(st->regmap[ch]); __le16 id_le; u16 id; int ret; - ret = regmap_write(st->regmap, AD4080_REG_INTERFACE_CONFIG_A, + ret = regmap_write(st->regmap[ch], AD4080_REG_INTERFACE_CONFIG_A, AD4080_INTERFACE_CONFIG_A_SW_RESET); if (ret) return ret; - ret = regmap_write(st->regmap, AD4080_REG_INTERFACE_CONFIG_A, + ret = regmap_write(st->regmap[ch], AD4080_REG_INTERFACE_CONFIG_A, AD4080_INTERFACE_CONFIG_A_SDO_ENABLE); if (ret) return ret; - ret = regmap_bulk_read(st->regmap, AD4080_REG_PRODUCT_ID_L, &id_le, + ret = regmap_bulk_read(st->regmap[ch], AD4080_REG_PRODUCT_ID_L, &id_le, sizeof(id_le)); if (ret) return ret; @@ -537,18 +698,23 @@ static int ad4080_setup(struct iio_dev *indio_dev) if (id != st->info->product_id) dev_info(dev, "Unrecognized CHIP_ID 0x%X\n", id); - ret = regmap_set_bits(st->regmap, AD4080_REG_GPIO_CONFIG_A, + ret = regmap_set_bits(st->regmap[ch], AD4080_REG_GPIO_CONFIG_A, AD4080_GPIO_CONFIG_A_GPO_1_EN); if (ret) return ret; - ret = regmap_write(st->regmap, AD4080_REG_GPIO_CONFIG_B, + ret = regmap_write(st->regmap[ch], AD4080_REG_GPIO_CONFIG_B, FIELD_PREP(AD4080_GPIO_CONFIG_B_GPIO_1_SEL_MSK, AD4080_GPIO_CONFIG_B_GPIO_FILTER_RES_RDY)); if (ret) return ret; - ret = iio_backend_num_lanes_set(st->back, st->num_lanes); + ret = iio_backend_num_lanes_set(st->back[ch], st->num_lanes); + if (ret) + return ret; + + ret = iio_backend_data_size_set(st->back[ch], + st->info->channels[0].scan_type.realbits); if (ret) return ret; @@ -556,7 +722,7 @@ static int ad4080_setup(struct iio_dev *indio_dev) return 0; /* Set maximum LVDS Data Transfer Latency */ - ret = regmap_update_bits(st->regmap, + ret = regmap_update_bits(st->regmap[ch], AD4080_REG_ADC_DATA_INTF_CONFIG_B, AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_CLK_CNT_MSK, FIELD_PREP(AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_CLK_CNT_MSK, @@ -565,24 +731,38 @@ static int ad4080_setup(struct iio_dev *indio_dev) return ret; if (st->num_lanes > 1) { - ret = regmap_set_bits(st->regmap, AD4080_REG_ADC_DATA_INTF_CONFIG_A, + ret = regmap_set_bits(st->regmap[ch], AD4080_REG_ADC_DATA_INTF_CONFIG_A, AD4080_ADC_DATA_INTF_CONFIG_A_SPI_LVDS_LANES); if (ret) return ret; } - ret = regmap_set_bits(st->regmap, + ret = regmap_set_bits(st->regmap[ch], AD4080_REG_ADC_DATA_INTF_CONFIG_B, AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_EN); if (ret) return ret; - return ad4080_lvds_sync_write(st); + return ad4080_lvds_sync_write(st, ch); +} + +static int ad4080_setup(struct iio_dev *indio_dev) +{ + struct ad4080_state *st = iio_priv(indio_dev); + int ret; + + for (unsigned int ch = 0; ch < st->info->num_channels; ch++) { + ret = ad4080_setup_channel(st, ch); + if (ret) + return ret; + } + + return 0; } -static int ad4080_properties_parse(struct ad4080_state *st) +static int ad4080_properties_parse(struct ad4080_state *st, + struct device *dev) { - struct device *dev = regmap_get_device(st->regmap); st->lvds_cnv_en = device_property_read_bool(dev, "adi,lvds-cnv-enable"); @@ -617,14 +797,28 @@ static int ad4080_probe(struct spi_device *spi) return dev_err_probe(dev, ret, "failed to get and enable supplies\n"); - st->regmap = devm_regmap_init_spi(spi, &ad4080_regmap_config); - if (IS_ERR(st->regmap)) - return PTR_ERR(st->regmap); + /* Setup primary SPI device (channel 0) */ + st->spi[0] = spi; + st->regmap[0] = devm_regmap_init_spi(spi, &ad4080_regmap_config); + if (IS_ERR(st->regmap[0])) + return PTR_ERR(st->regmap[0]); st->info = spi_get_device_match_data(spi); if (!st->info) return -ENODEV; + /* Setup ancillary SPI devices for additional channels */ + for (unsigned int ch = 1; ch < st->info->num_channels; ch++) { + st->spi[ch] = devm_spi_new_ancillary_device(spi, spi_get_chipselect(spi, ch)); + if (IS_ERR(st->spi[ch])) + return dev_err_probe(dev, PTR_ERR(st->spi[ch]), + "failed to register ancillary device\n"); + + st->regmap[ch] = devm_regmap_init_spi(st->spi[ch], &ad4080_regmap_config); + if (IS_ERR(st->regmap[ch])) + return PTR_ERR(st->regmap[ch]); + } + ret = devm_mutex_init(dev, &st->lock); if (ret) return ret; @@ -632,9 +826,10 @@ static int ad4080_probe(struct spi_device *spi) indio_dev->name = st->info->name; indio_dev->channels = st->info->channels; indio_dev->num_channels = st->info->num_channels; - indio_dev->info = &ad4080_iio_info; + indio_dev->info = st->info->num_channels > 1 ? + &ad4880_iio_info : &ad4080_iio_info; - ret = ad4080_properties_parse(st); + ret = ad4080_properties_parse(st, dev); if (ret) return ret; @@ -644,15 +839,25 @@ static int ad4080_probe(struct spi_device *spi) st->clk_rate = clk_get_rate(clk); - st->back = devm_iio_backend_get(dev, NULL); - if (IS_ERR(st->back)) - return PTR_ERR(st->back); + /* Get backends for all channels */ + for (unsigned int ch = 0; ch < st->info->num_channels; ch++) { + st->back[ch] = devm_iio_backend_get_by_index(dev, ch); + if (IS_ERR(st->back[ch])) + return PTR_ERR(st->back[ch]); - ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev); - if (ret) - return ret; + ret = devm_iio_backend_enable(dev, st->back[ch]); + if (ret) + return ret; + } - ret = devm_iio_backend_enable(dev, st->back); + /* + * Request buffer from the first backend only. For multi-channel + * devices (e.g., AD4880), the FPGA uses two axi_ad408x IP instances + * (one per ADC channel) whose outputs are combined by a packer block + * that interleaves all channel data into a single DMA stream routed + * through the first backend's clock domain. + */ + ret = devm_iio_backend_request_buffer(dev, st->back[0], indio_dev); if (ret) return ret; @@ -664,12 +869,18 @@ static int ad4080_probe(struct spi_device *spi) } static const struct spi_device_id ad4080_id[] = { - { "ad4080", (kernel_ulong_t)&ad4080_chip_info }, - { "ad4081", (kernel_ulong_t)&ad4081_chip_info }, - { "ad4083", (kernel_ulong_t)&ad4083_chip_info }, - { "ad4084", (kernel_ulong_t)&ad4084_chip_info }, - { "ad4086", (kernel_ulong_t)&ad4086_chip_info }, - { "ad4087", (kernel_ulong_t)&ad4087_chip_info }, + { .name = "ad4080", .driver_data = (kernel_ulong_t)&ad4080_chip_info }, + { .name = "ad4081", .driver_data = (kernel_ulong_t)&ad4081_chip_info }, + { .name = "ad4082", .driver_data = (kernel_ulong_t)&ad4082_chip_info }, + { .name = "ad4083", .driver_data = (kernel_ulong_t)&ad4083_chip_info }, + { .name = "ad4084", .driver_data = (kernel_ulong_t)&ad4084_chip_info }, + { .name = "ad4085", .driver_data = (kernel_ulong_t)&ad4085_chip_info }, + { .name = "ad4086", .driver_data = (kernel_ulong_t)&ad4086_chip_info }, + { .name = "ad4087", .driver_data = (kernel_ulong_t)&ad4087_chip_info }, + { .name = "ad4088", .driver_data = (kernel_ulong_t)&ad4088_chip_info }, + { .name = "ad4880", .driver_data = (kernel_ulong_t)&ad4880_chip_info }, + { .name = "ad4883", .driver_data = (kernel_ulong_t)&ad4883_chip_info }, + { .name = "ad4884", .driver_data = (kernel_ulong_t)&ad4884_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad4080_id); @@ -677,10 +888,16 @@ MODULE_DEVICE_TABLE(spi, ad4080_id); static const struct of_device_id ad4080_of_match[] = { { .compatible = "adi,ad4080", &ad4080_chip_info }, { .compatible = "adi,ad4081", &ad4081_chip_info }, + { .compatible = "adi,ad4082", &ad4082_chip_info }, { .compatible = "adi,ad4083", &ad4083_chip_info }, { .compatible = "adi,ad4084", &ad4084_chip_info }, + { .compatible = "adi,ad4085", &ad4085_chip_info }, { .compatible = "adi,ad4086", &ad4086_chip_info }, { .compatible = "adi,ad4087", &ad4087_chip_info }, + { .compatible = "adi,ad4088", &ad4088_chip_info }, + { .compatible = "adi,ad4880", &ad4880_chip_info }, + { .compatible = "adi,ad4883", &ad4883_chip_info }, + { .compatible = "adi,ad4884", &ad4884_chip_info }, { } }; MODULE_DEVICE_TABLE(of, ad4080_of_match); diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c index 5567ae5dee88..3ffc4b765e0e 100644 --- a/drivers/iio/adc/ad4130.c +++ b/drivers/iio/adc/ad4130.c @@ -9,6 +9,7 @@ #include <linux/cleanup.h> #include <linux/clk.h> #include <linux/clk-provider.h> +#include <linux/completion.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/err.h> @@ -21,6 +22,7 @@ #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> +#include <linux/types.h> #include <linux/units.h> #include <asm/div64.h> @@ -30,6 +32,9 @@ #include <linux/iio/iio.h> #include <linux/iio/kfifo_buf.h> #include <linux/iio/sysfs.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> #define AD4130_NAME "ad4130" @@ -40,6 +45,7 @@ #define AD4130_ADC_CONTROL_REG 0x01 #define AD4130_ADC_CONTROL_BIPOLAR_MASK BIT(14) #define AD4130_ADC_CONTROL_INT_REF_VAL_MASK BIT(13) +#define AD4130_ADC_CONTROL_CONT_READ_MASK BIT(11) #define AD4130_INT_REF_2_5V 2500000 #define AD4130_INT_REF_1_25V 1250000 #define AD4130_ADC_CONTROL_CSB_EN_MASK BIT(9) @@ -54,7 +60,9 @@ #define AD4130_IO_CONTROL_REG 0x03 #define AD4130_IO_CONTROL_INT_PIN_SEL_MASK GENMASK(9, 8) #define AD4130_IO_CONTROL_GPIO_DATA_MASK GENMASK(7, 4) +#define AD4130_4_IO_CONTROL_GPIO_DATA_MASK GENMASK(7, 6) #define AD4130_IO_CONTROL_GPIO_CTRL_MASK GENMASK(3, 0) +#define AD4130_4_IO_CONTROL_GPIO_CTRL_MASK GENMASK(3, 2) #define AD4130_VBIAS_REG 0x04 @@ -125,6 +133,28 @@ #define AD4130_INVALID_SLOT -1 +static const unsigned int ad4129_reg_size[] = { + [AD4130_STATUS_REG] = 1, + [AD4130_ADC_CONTROL_REG] = 2, + [AD4130_DATA_REG] = 2, + [AD4130_IO_CONTROL_REG] = 2, + [AD4130_VBIAS_REG] = 2, + [AD4130_ID_REG] = 1, + [AD4130_ERROR_REG] = 2, + [AD4130_ERROR_EN_REG] = 2, + [AD4130_MCLK_COUNT_REG] = 1, + [AD4130_CHANNEL_X_REG(0) ... AD4130_CHANNEL_X_REG(AD4130_MAX_CHANNELS - 1)] = 3, + [AD4130_CONFIG_X_REG(0) ... AD4130_CONFIG_X_REG(AD4130_MAX_SETUPS - 1)] = 2, + [AD4130_FILTER_X_REG(0) ... AD4130_FILTER_X_REG(AD4130_MAX_SETUPS - 1)] = 3, + [AD4130_OFFSET_X_REG(0) ... AD4130_OFFSET_X_REG(AD4130_MAX_SETUPS - 1)] = 2, + [AD4130_GAIN_X_REG(0) ... AD4130_GAIN_X_REG(AD4130_MAX_SETUPS - 1)] = 2, + [AD4130_MISC_REG] = 2, + [AD4130_FIFO_CONTROL_REG] = 3, + [AD4130_FIFO_STATUS_REG] = 1, + [AD4130_FIFO_THRESHOLD_REG] = 3, + [AD4130_FIFO_DATA_REG] = 2, +}; + static const unsigned int ad4130_reg_size[] = { [AD4130_STATUS_REG] = 1, [AD4130_ADC_CONTROL_REG] = 2, @@ -147,6 +177,24 @@ static const unsigned int ad4130_reg_size[] = { [AD4130_FIFO_DATA_REG] = 3, }; +static const unsigned int ad4131_reg_size[] = { + [AD4130_STATUS_REG] = 1, + [AD4130_ADC_CONTROL_REG] = 2, + [AD4130_DATA_REG] = 2, + [AD4130_IO_CONTROL_REG] = 2, + [AD4130_VBIAS_REG] = 2, + [AD4130_ID_REG] = 1, + [AD4130_ERROR_REG] = 2, + [AD4130_ERROR_EN_REG] = 2, + [AD4130_MCLK_COUNT_REG] = 1, + [AD4130_CHANNEL_X_REG(0) ... AD4130_CHANNEL_X_REG(AD4130_MAX_CHANNELS - 1)] = 3, + [AD4130_CONFIG_X_REG(0) ... AD4130_CONFIG_X_REG(AD4130_MAX_SETUPS - 1)] = 2, + [AD4130_FILTER_X_REG(0) ... AD4130_FILTER_X_REG(AD4130_MAX_SETUPS - 1)] = 3, + [AD4130_OFFSET_X_REG(0) ... AD4130_OFFSET_X_REG(AD4130_MAX_SETUPS - 1)] = 2, + [AD4130_GAIN_X_REG(0) ... AD4130_GAIN_X_REG(AD4130_MAX_SETUPS - 1)] = 2, + [AD4130_MISC_REG] = 2, +}; + enum ad4130_int_ref_val { AD4130_INT_REF_VAL_2_5V, AD4130_INT_REF_VAL_1_25V, @@ -224,6 +272,28 @@ enum ad4130_pin_function { AD4130_PIN_FN_VBIAS = BIT(3), }; +/* Pin mapping for AIN0..AIN7, VBIAS_0..VBIAS_7 */ +static const u8 ad4130_4_pin_map[] = { + 0x00, 0x01, 0x04, 0x05, 0x0A, 0x0B, 0x0E, 0x0F, /* 0 - 7 */ +}; + +/* Pin mapping for AIN0..AIN15, VBIAS_0..VBIAS_15 */ +static const u8 ad4130_8_pin_map[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0 - 7 */ + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 8 - 15 */ +}; + +struct ad4130_chip_info { + const char *name; + unsigned int max_analog_pins; + unsigned int num_gpios; + const struct iio_info *info; + const unsigned int *reg_size; + const unsigned int reg_size_length; + const u8 *pin_map; + bool has_fifo; +}; + /* * If you make adaptations in this struct, you most likely also have to adapt * ad4130_setup_info_eq(), too. @@ -268,6 +338,7 @@ struct ad4130_state { struct regmap *regmap; struct spi_device *spi; struct clk *mclk; + const struct ad4130_chip_info *chip_info; struct regulator_bulk_data regulators[4]; u32 irq_trigger; u32 inv_irq_trigger; @@ -294,6 +365,7 @@ struct ad4130_state { u32 mclk_sel; bool int_ref_en; bool bipolar; + bool buffer_wait_for_irq; unsigned int num_enabled_channels; unsigned int effective_watermark; @@ -301,6 +373,7 @@ struct ad4130_state { struct spi_message fifo_msg; struct spi_transfer fifo_xfer[2]; + struct iio_trigger *trig; /* * DMA (thus cache coherency maintenance) requires any transfer @@ -312,9 +385,13 @@ struct ad4130_state { u8 reg_write_tx_buf[4]; u8 reg_read_tx_buf[1]; u8 reg_read_rx_buf[3]; - u8 fifo_tx_buf[2]; - u8 fifo_rx_buf[AD4130_FIFO_SIZE * - AD4130_FIFO_MAX_SAMPLE_SIZE]; + union { + struct { + u8 fifo_tx_buf[2]; + u8 fifo_rx_buf[AD4130_FIFO_SIZE * AD4130_FIFO_MAX_SAMPLE_SIZE]; + }; + IIO_DECLARE_BUFFER_WITH_TS(u32, scan_channels, AD4130_MAX_CHANNELS); + }; }; static const char * const ad4130_int_pin_names[] = { @@ -394,10 +471,10 @@ static const char * const ad4130_filter_types_str[] = { static int ad4130_get_reg_size(struct ad4130_state *st, unsigned int reg, unsigned int *size) { - if (reg >= ARRAY_SIZE(ad4130_reg_size)) + if (reg >= st->chip_info->reg_size_length) return -EINVAL; - *size = ad4130_reg_size[reg]; + *size = st->chip_info->reg_size[reg]; return 0; } @@ -505,7 +582,8 @@ static int ad4130_gpio_init_valid_mask(struct gpio_chip *gc, /* * Output-only GPIO functionality is available on pins AIN2 through - * AIN5. If these pins are used for anything else, do not expose them. + * AIN5 for some parts and AIN2 through AIN3 for others. If these pins + * are used for anything else, do not expose them. */ for (i = 0; i < ngpios; i++) { unsigned int pin = i + AD4130_AIN2_P1; @@ -526,8 +604,14 @@ static int ad4130_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) { struct ad4130_state *st = gpiochip_get_data(gc); - unsigned int mask = FIELD_PREP(AD4130_IO_CONTROL_GPIO_DATA_MASK, - BIT(offset)); + unsigned int mask; + + if (st->chip_info->num_gpios == AD4130_MAX_GPIOS) + mask = FIELD_PREP(AD4130_IO_CONTROL_GPIO_DATA_MASK, + BIT(offset)); + else + mask = FIELD_PREP(AD4130_4_IO_CONTROL_GPIO_DATA_MASK, + BIT(offset)); return regmap_update_bits(st->regmap, AD4130_IO_CONTROL_REG, mask, value ? mask : 0); @@ -588,10 +672,43 @@ static irqreturn_t ad4130_irq_handler(int irq, void *private) struct iio_dev *indio_dev = private; struct ad4130_state *st = iio_priv(indio_dev); - if (iio_buffer_enabled(indio_dev)) - ad4130_push_fifo_data(indio_dev); - else + if (iio_buffer_enabled(indio_dev)) { + if (st->chip_info->has_fifo) + ad4130_push_fifo_data(indio_dev); + else if (st->buffer_wait_for_irq) + complete(&st->completion); + else + iio_trigger_poll(st->trig); + } else { complete(&st->completion); + } + + return IRQ_HANDLED; +} + +static irqreturn_t ad4130_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ad4130_state *st = iio_priv(indio_dev); + unsigned int data_reg_size = ad4130_data_reg_size(st); + struct spi_transfer xfer = { }; + unsigned int num_en_chn; + int ret; + + num_en_chn = bitmap_weight(indio_dev->active_scan_mask, + iio_get_masklength(indio_dev)); + xfer.rx_buf = st->scan_channels; + xfer.len = data_reg_size * num_en_chn; + ret = spi_sync_transfer(st->spi, &xfer, 1); + if (ret < 0) + goto err_out; + + iio_push_to_buffers_with_timestamp(indio_dev, &st->scan_channels, + iio_get_time_ns(indio_dev)); + +err_out: + iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; } @@ -1291,6 +1408,79 @@ static const struct iio_info ad4130_info = { .debugfs_reg_access = ad4130_reg_access, }; +static const struct iio_info ad4131_info = { + .read_raw = ad4130_read_raw, + .read_avail = ad4130_read_avail, + .write_raw_get_fmt = ad4130_write_raw_get_fmt, + .write_raw = ad4130_write_raw, + .update_scan_mode = ad4130_update_scan_mode, + .debugfs_reg_access = ad4130_reg_access, +}; + +static const struct ad4130_chip_info ad4129_4_chip_info = { + .name = "ad4129-4", + .max_analog_pins = 8, + .num_gpios = 2, + .info = &ad4130_info, + .reg_size = ad4129_reg_size, + .reg_size_length = ARRAY_SIZE(ad4129_reg_size), + .has_fifo = true, + .pin_map = ad4130_4_pin_map, +}; + +static const struct ad4130_chip_info ad4129_8_chip_info = { + .name = "ad4129-8", + .max_analog_pins = 16, + .num_gpios = 4, + .info = &ad4130_info, + .reg_size = ad4129_reg_size, + .reg_size_length = ARRAY_SIZE(ad4129_reg_size), + .has_fifo = true, + .pin_map = ad4130_8_pin_map, +}; + +static const struct ad4130_chip_info ad4130_4_chip_info = { + .name = "ad4130-4", + .max_analog_pins = 16, + .num_gpios = 2, + .info = &ad4130_info, + .reg_size = ad4130_reg_size, + .reg_size_length = ARRAY_SIZE(ad4130_reg_size), + .has_fifo = true, + .pin_map = ad4130_4_pin_map, +}; + +static const struct ad4130_chip_info ad4130_8_chip_info = { + .name = "ad4130-8", + .max_analog_pins = 16, + .num_gpios = 4, + .info = &ad4130_info, + .reg_size = ad4130_reg_size, + .reg_size_length = ARRAY_SIZE(ad4130_reg_size), + .has_fifo = true, + .pin_map = ad4130_8_pin_map, +}; + +static const struct ad4130_chip_info ad4131_4_chip_info = { + .name = "ad4131-4", + .max_analog_pins = 8, + .num_gpios = 2, + .info = &ad4131_info, + .reg_size = ad4131_reg_size, + .reg_size_length = ARRAY_SIZE(ad4131_reg_size), + .pin_map = ad4130_4_pin_map, +}; + +static const struct ad4130_chip_info ad4131_8_chip_info = { + .name = "ad4131-8", + .max_analog_pins = 16, + .num_gpios = 4, + .info = &ad4131_info, + .reg_size = ad4131_reg_size, + .reg_size_length = ARRAY_SIZE(ad4131_reg_size), + .pin_map = ad4130_8_pin_map, +}; + static int ad4130_buffer_postenable(struct iio_dev *indio_dev) { struct ad4130_state *st = iio_priv(indio_dev); @@ -1298,44 +1488,89 @@ static int ad4130_buffer_postenable(struct iio_dev *indio_dev) guard(mutex)(&st->lock); - ret = ad4130_set_watermark_interrupt_en(st, true); - if (ret) - return ret; + if (st->chip_info->has_fifo) { + ret = ad4130_set_watermark_interrupt_en(st, true); + if (ret) + return ret; - ret = irq_set_irq_type(st->spi->irq, st->inv_irq_trigger); - if (ret) - return ret; + ret = irq_set_irq_type(st->spi->irq, st->inv_irq_trigger); + if (ret) + return ret; + + ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_WM); + if (ret) + return ret; + } - ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_WM); + ret = ad4130_set_mode(st, AD4130_MODE_CONTINUOUS); if (ret) return ret; - return ad4130_set_mode(st, AD4130_MODE_CONTINUOUS); + /* + * When using triggered buffer, Entering continuous read mode must + * be the last command sent. No configuration changes are allowed until + * exiting this mode. + */ + if (!st->chip_info->has_fifo) { + ret = regmap_update_bits(st->regmap, AD4130_ADC_CONTROL_REG, + AD4130_ADC_CONTROL_CONT_READ_MASK, + FIELD_PREP(AD4130_ADC_CONTROL_CONT_READ_MASK, 1)); + if (ret) + return ret; + } + + return 0; } static int ad4130_buffer_predisable(struct iio_dev *indio_dev) { struct ad4130_state *st = iio_priv(indio_dev); unsigned int i; + u32 temp; int ret; guard(mutex)(&st->lock); + if (!st->chip_info->has_fifo) { + temp = 0x42; + reinit_completion(&st->completion); + + /* + * In continuous read mode, when all samples are read, the data + * ready signal returns high until the next conversion result is + * ready. To exit this mode, the command must be sent when data + * ready is low. In order to ensure that condition, wait for the + * next interrupt (when the new conversion is finished), allowing + * data ready to return low before sending the exit command. + */ + st->buffer_wait_for_irq = true; + if (!wait_for_completion_timeout(&st->completion, msecs_to_jiffies(1000))) + dev_warn(&st->spi->dev, "Conversion timed out\n"); + st->buffer_wait_for_irq = false; + + /* Perform a read data command to exit continuous read mode (0x42) */ + ret = spi_write(st->spi, &temp, 1); + if (ret) + return ret; + } + ret = ad4130_set_mode(st, AD4130_MODE_IDLE); if (ret) return ret; - ret = irq_set_irq_type(st->spi->irq, st->irq_trigger); - if (ret) - return ret; + if (st->chip_info->has_fifo) { + ret = irq_set_irq_type(st->spi->irq, st->irq_trigger); + if (ret) + return ret; - ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_DISABLED); - if (ret) - return ret; + ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_DISABLED); + if (ret) + return ret; - ret = ad4130_set_watermark_interrupt_en(st, false); - if (ret) - return ret; + ret = ad4130_set_watermark_interrupt_en(st, false); + if (ret) + return ret; + } /* * update_scan_mode() is not called in the disable path, disable all @@ -1410,6 +1645,34 @@ static const struct iio_dev_attr *ad4130_fifo_attributes[] = { NULL }; +static const struct iio_trigger_ops ad4130_trigger_ops = { + .validate_device = iio_trigger_validate_own_device, +}; + +static int ad4130_triggered_buffer_setup(struct iio_dev *indio_dev) +{ + struct ad4130_state *st = iio_priv(indio_dev); + int ret; + + st->trig = devm_iio_trigger_alloc(indio_dev->dev.parent, "%s-dev%d", + indio_dev->name, iio_device_id(indio_dev)); + if (!st->trig) + return -ENOMEM; + + st->trig->ops = &ad4130_trigger_ops; + iio_trigger_set_drvdata(st->trig, indio_dev); + ret = devm_iio_trigger_register(indio_dev->dev.parent, st->trig); + if (ret) + return ret; + + indio_dev->trig = iio_trigger_get(st->trig); + + return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev, + &iio_pollfunc_store_time, + &ad4130_trigger_handler, + &ad4130_buffer_ops); +} + static int _ad4130_find_table_index(const unsigned int *tbl, size_t len, unsigned int val) { @@ -1496,6 +1759,17 @@ static int ad4130_parse_fw_setup(struct ad4130_state *st, return 0; } +static unsigned int ad4130_translate_pin(struct ad4130_state *st, + unsigned int logical_pin) +{ + /* For analog input pins, use the chip-specific pin mapping */ + if (logical_pin < st->chip_info->max_analog_pins) + return st->chip_info->pin_map[logical_pin]; + + /* For internal channels, pass through unchanged */ + return logical_pin; +} + static int ad4130_validate_diff_channel(struct ad4130_state *st, u32 pin) { struct device *dev = &st->spi->dev; @@ -1504,7 +1778,7 @@ static int ad4130_validate_diff_channel(struct ad4130_state *st, u32 pin) return dev_err_probe(dev, -EINVAL, "Invalid differential channel %u\n", pin); - if (pin >= AD4130_MAX_ANALOG_PINS) + if (pin >= st->chip_info->max_analog_pins) return 0; if (st->pins_fn[pin] == AD4130_PIN_FN_SPECIAL) @@ -1536,7 +1810,7 @@ static int ad4130_validate_excitation_pin(struct ad4130_state *st, u32 pin) { struct device *dev = &st->spi->dev; - if (pin >= AD4130_MAX_ANALOG_PINS) + if (pin >= st->chip_info->max_analog_pins) return dev_err_probe(dev, -EINVAL, "Invalid excitation pin %u\n", pin); @@ -1554,7 +1828,7 @@ static int ad4130_validate_vbias_pin(struct ad4130_state *st, u32 pin) { struct device *dev = &st->spi->dev; - if (pin >= AD4130_MAX_ANALOG_PINS) + if (pin >= st->chip_info->max_analog_pins) return dev_err_probe(dev, -EINVAL, "Invalid vbias pin %u\n", pin); @@ -1730,7 +2004,7 @@ static int ad4310_parse_fw(struct iio_dev *indio_dev) ret = device_property_count_u32(dev, "adi,vbias-pins"); if (ret > 0) { - if (ret > AD4130_MAX_ANALOG_PINS) + if (ret > st->chip_info->max_analog_pins) return dev_err_probe(dev, -EINVAL, "Too many vbias pins %u\n", ret); @@ -1914,9 +2188,14 @@ static int ad4130_setup(struct iio_dev *indio_dev) * function of P2 takes priority over the GPIO out function. */ val = 0; - for (i = 0; i < AD4130_MAX_GPIOS; i++) - if (st->pins_fn[i + AD4130_AIN2_P1] == AD4130_PIN_FN_NONE) - val |= FIELD_PREP(AD4130_IO_CONTROL_GPIO_CTRL_MASK, BIT(i)); + for (i = 0; i < st->chip_info->num_gpios; i++) { + if (st->pins_fn[i + AD4130_AIN2_P1] == AD4130_PIN_FN_NONE) { + if (st->chip_info->num_gpios == 2) + val |= FIELD_PREP(AD4130_4_IO_CONTROL_GPIO_CTRL_MASK, BIT(i)); + else + val |= FIELD_PREP(AD4130_IO_CONTROL_GPIO_CTRL_MASK, BIT(i)); + } + } val |= FIELD_PREP(AD4130_IO_CONTROL_INT_PIN_SEL_MASK, st->int_pin_sel); @@ -1926,21 +2205,23 @@ static int ad4130_setup(struct iio_dev *indio_dev) val = 0; for (i = 0; i < st->num_vbias_pins; i++) - val |= BIT(st->vbias_pins[i]); + val |= BIT(ad4130_translate_pin(st, st->vbias_pins[i])); ret = regmap_write(st->regmap, AD4130_VBIAS_REG, val); if (ret) return ret; - ret = regmap_clear_bits(st->regmap, AD4130_FIFO_CONTROL_REG, - AD4130_FIFO_CONTROL_HEADER_MASK); - if (ret) - return ret; + if (st->chip_info->has_fifo) { + ret = regmap_clear_bits(st->regmap, AD4130_FIFO_CONTROL_REG, + AD4130_FIFO_CONTROL_HEADER_MASK); + if (ret) + return ret; - /* FIFO watermark interrupt starts out as enabled, disable it. */ - ret = ad4130_set_watermark_interrupt_en(st, false); - if (ret) - return ret; + /* FIFO watermark interrupt starts out as enabled, disable it. */ + ret = ad4130_set_watermark_interrupt_en(st, false); + if (ret) + return ret; + } /* Setup channels. */ for (i = 0; i < indio_dev->num_channels; i++) { @@ -1948,10 +2229,14 @@ static int ad4130_setup(struct iio_dev *indio_dev) struct iio_chan_spec *chan = &st->chans[i]; unsigned int val; - val = FIELD_PREP(AD4130_CHANNEL_AINP_MASK, chan->channel) | - FIELD_PREP(AD4130_CHANNEL_AINM_MASK, chan->channel2) | - FIELD_PREP(AD4130_CHANNEL_IOUT1_MASK, chan_info->iout0) | - FIELD_PREP(AD4130_CHANNEL_IOUT2_MASK, chan_info->iout1); + val = FIELD_PREP(AD4130_CHANNEL_AINP_MASK, + ad4130_translate_pin(st, chan->channel)) | + FIELD_PREP(AD4130_CHANNEL_AINM_MASK, + ad4130_translate_pin(st, chan->channel2)) | + FIELD_PREP(AD4130_CHANNEL_IOUT1_MASK, + ad4130_translate_pin(st, chan_info->iout0)) | + FIELD_PREP(AD4130_CHANNEL_IOUT2_MASK, + ad4130_translate_pin(st, chan_info->iout1)); ret = regmap_write(st->regmap, AD4130_CHANNEL_X_REG(i), val); if (ret) @@ -1994,26 +2279,30 @@ static int ad4130_probe(struct spi_device *spi) st = iio_priv(indio_dev); + st->chip_info = device_get_match_data(dev); + memset(st->reset_buf, 0xff, sizeof(st->reset_buf)); init_completion(&st->completion); mutex_init(&st->lock); st->spi = spi; - /* - * Xfer: [ XFR1 ] [ XFR2 ] - * Master: 0x7D N ...................... - * Slave: ...... DATA1 DATA2 ... DATAN - */ - st->fifo_tx_buf[0] = AD4130_COMMS_READ_MASK | AD4130_FIFO_DATA_REG; - st->fifo_xfer[0].tx_buf = st->fifo_tx_buf; - st->fifo_xfer[0].len = sizeof(st->fifo_tx_buf); - st->fifo_xfer[1].rx_buf = st->fifo_rx_buf; - spi_message_init_with_transfers(&st->fifo_msg, st->fifo_xfer, - ARRAY_SIZE(st->fifo_xfer)); - - indio_dev->name = AD4130_NAME; + if (st->chip_info->has_fifo) { + /* + * Xfer: [ XFR1 ] [ XFR2 ] + * Master: 0x7D N ...................... + * Slave: ...... DATA1 DATA2 ... DATAN + */ + st->fifo_tx_buf[0] = AD4130_COMMS_READ_MASK | AD4130_FIFO_DATA_REG; + st->fifo_xfer[0].tx_buf = st->fifo_tx_buf; + st->fifo_xfer[0].len = sizeof(st->fifo_tx_buf); + st->fifo_xfer[1].rx_buf = st->fifo_rx_buf; + spi_message_init_with_transfers(&st->fifo_msg, st->fifo_xfer, + ARRAY_SIZE(st->fifo_xfer)); + } + + indio_dev->name = st->chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->info = &ad4130_info; + indio_dev->info = st->chip_info->info; st->regmap = devm_regmap_init(dev, NULL, st, &ad4130_regmap_config); if (IS_ERR(st->regmap)) @@ -2056,9 +2345,9 @@ static int ad4130_probe(struct spi_device *spi) ad4130_fill_scale_tbls(st); st->gc.owner = THIS_MODULE; - st->gc.label = AD4130_NAME; + st->gc.label = st->chip_info->name; st->gc.base = -1; - st->gc.ngpio = AD4130_MAX_GPIOS; + st->gc.ngpio = st->chip_info->num_gpios; st->gc.parent = dev; st->gc.can_sleep = true; st->gc.init_valid_mask = ad4130_gpio_init_valid_mask; @@ -2069,9 +2358,12 @@ static int ad4130_probe(struct spi_device *spi) if (ret) return ret; - ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev, - &ad4130_buffer_ops, - ad4130_fifo_attributes); + if (st->chip_info->has_fifo) + ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev, + &ad4130_buffer_ops, + ad4130_fifo_attributes); + else + ret = ad4130_triggered_buffer_setup(indio_dev); if (ret) return ret; @@ -2081,40 +2373,75 @@ static int ad4130_probe(struct spi_device *spi) if (ret) return dev_err_probe(dev, ret, "Failed to request irq\n"); - /* - * When the chip enters FIFO mode, IRQ polarity is inverted. - * When the chip exits FIFO mode, IRQ polarity returns to normal. - * See datasheet pages: 65, FIFO Watermark Interrupt section, - * and 71, Bit Descriptions for STATUS Register, RDYB. - * Cache the normal and inverted IRQ triggers to set them when - * entering and exiting FIFO mode. - */ - st->irq_trigger = irq_get_trigger_type(spi->irq); - if (st->irq_trigger & IRQF_TRIGGER_RISING) - st->inv_irq_trigger = IRQF_TRIGGER_FALLING; - else if (st->irq_trigger & IRQF_TRIGGER_FALLING) - st->inv_irq_trigger = IRQF_TRIGGER_RISING; - else - return dev_err_probe(dev, -EINVAL, "Invalid irq flags: %u\n", - st->irq_trigger); + if (st->chip_info->has_fifo) { + /* + * When the chip enters FIFO mode, IRQ polarity is inverted. + * When the chip exits FIFO mode, IRQ polarity returns to normal. + * See datasheet pages: 65, FIFO Watermark Interrupt section, + * and 71, Bit Descriptions for STATUS Register, RDYB. + * Cache the normal and inverted IRQ triggers to set them when + * entering and exiting FIFO mode. + */ + st->irq_trigger = irq_get_trigger_type(spi->irq); + if (st->irq_trigger & IRQF_TRIGGER_RISING) + st->inv_irq_trigger = IRQF_TRIGGER_FALLING; + else if (st->irq_trigger & IRQF_TRIGGER_FALLING) + st->inv_irq_trigger = IRQF_TRIGGER_RISING; + else + return dev_err_probe(dev, -EINVAL, "Invalid irq flags: %u\n", + st->irq_trigger); + } return devm_iio_device_register(dev, indio_dev); } static const struct of_device_id ad4130_of_match[] = { { + .compatible = "adi,ad4129-4", + .data = &ad4129_4_chip_info + }, + { + .compatible = "adi,ad4129-8", + .data = &ad4129_8_chip_info + }, + { + .compatible = "adi,ad4130-4", + .data = &ad4130_4_chip_info + }, + { .compatible = "adi,ad4130", + .data = &ad4130_8_chip_info + }, + { + .compatible = "adi,ad4131-4", + .data = &ad4131_4_chip_info + }, + { + .compatible = "adi,ad4131-8", + .data = &ad4131_8_chip_info }, { } }; MODULE_DEVICE_TABLE(of, ad4130_of_match); +static const struct spi_device_id ad4130_id_table[] = { + { .name = "ad4129-4", .driver_data = (kernel_ulong_t)&ad4129_4_chip_info }, + { .name = "ad4129-8", .driver_data = (kernel_ulong_t)&ad4129_8_chip_info }, + { .name = "ad4130-4", .driver_data = (kernel_ulong_t)&ad4130_4_chip_info }, + { .name = "ad4130", .driver_data = (kernel_ulong_t)&ad4130_8_chip_info }, + { .name = "ad4131-4", .driver_data = (kernel_ulong_t)&ad4131_4_chip_info }, + { .name = "ad4131-8", .driver_data = (kernel_ulong_t)&ad4131_8_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(spi, ad4130_id_table); + static struct spi_driver ad4130_driver = { .driver = { .name = AD4130_NAME, .of_match_table = ad4130_of_match, }, .probe = ad4130_probe, + .id_table = ad4130_id_table, }; module_spi_driver(ad4130_driver); diff --git a/drivers/iio/adc/ad4134.c b/drivers/iio/adc/ad4134.c index e42ee328fcbf..0490218bb0e9 100644 --- a/drivers/iio/adc/ad4134.c +++ b/drivers/iio/adc/ad4134.c @@ -17,7 +17,6 @@ #include <linux/iio/iio.h> #include <linux/iio/types.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/reset.h> @@ -473,7 +472,7 @@ static int ad4134_probe(struct spi_device *spi) } static const struct spi_device_id ad4134_id[] = { - { "ad4134" }, + { .name = "ad4134" }, { } }; MODULE_DEVICE_TABLE(spi, ad4134_id); diff --git a/drivers/iio/adc/ad4170-4.c b/drivers/iio/adc/ad4170-4.c index 82205bfae531..f7757b3a931c 100644 --- a/drivers/iio/adc/ad4170-4.c +++ b/drivers/iio/adc/ad4170-4.c @@ -275,9 +275,9 @@ static const unsigned int ad4170_reg_size[] = { }; enum ad4170_ref_buf { - AD4170_REF_BUF_PRE, /* Pre-charge referrence buffer */ - AD4170_REF_BUF_FULL, /* Full referrence buffering */ - AD4170_REF_BUF_BYPASS, /* Bypass referrence buffering */ + AD4170_REF_BUF_PRE, /* Pre-charge reference buffer */ + AD4170_REF_BUF_FULL, /* Full reference buffering */ + AD4170_REF_BUF_BYPASS, /* Bypass reference buffering */ }; /* maps adi,positive/negative-reference-buffer property values to enum */ @@ -1699,34 +1699,29 @@ err_release: return ret; } +static const unsigned long gpio_masks[] = { + AD4170_GPIO_MODE_GPIO0_MSK, + AD4170_GPIO_MODE_GPIO1_MSK, + AD4170_GPIO_MODE_GPIO2_MSK, + AD4170_GPIO_MODE_GPIO3_MSK, +}; + static int ad4170_gpio_direction_input(struct gpio_chip *gc, unsigned int offset) { struct iio_dev *indio_dev = gpiochip_get_data(gc); struct ad4170_state *st = iio_priv(indio_dev); - unsigned long gpio_mask; int ret; if (!iio_device_claim_direct(indio_dev)) return -EBUSY; - switch (offset) { - case 0: - gpio_mask = AD4170_GPIO_MODE_GPIO0_MSK; - break; - case 1: - gpio_mask = AD4170_GPIO_MODE_GPIO1_MSK; - break; - case 2: - gpio_mask = AD4170_GPIO_MODE_GPIO2_MSK; - break; - case 3: - gpio_mask = AD4170_GPIO_MODE_GPIO3_MSK; - break; - default: + if (offset >= ARRAY_SIZE(gpio_masks)) { ret = -EINVAL; goto err_release; } - ret = regmap_update_bits(st->regmap, AD4170_GPIO_MODE_REG, gpio_mask, + + ret = regmap_update_bits(st->regmap, AD4170_GPIO_MODE_REG, + gpio_masks[offset], AD4170_GPIO_MODE_GPIO_INPUT << (2 * offset)); err_release: @@ -1740,7 +1735,6 @@ static int ad4170_gpio_direction_output(struct gpio_chip *gc, { struct iio_dev *indio_dev = gpiochip_get_data(gc); struct ad4170_state *st = iio_priv(indio_dev); - unsigned long gpio_mask; int ret; ret = ad4170_gpio_set(gc, offset, value); @@ -1750,24 +1744,13 @@ static int ad4170_gpio_direction_output(struct gpio_chip *gc, if (!iio_device_claim_direct(indio_dev)) return -EBUSY; - switch (offset) { - case 0: - gpio_mask = AD4170_GPIO_MODE_GPIO0_MSK; - break; - case 1: - gpio_mask = AD4170_GPIO_MODE_GPIO1_MSK; - break; - case 2: - gpio_mask = AD4170_GPIO_MODE_GPIO2_MSK; - break; - case 3: - gpio_mask = AD4170_GPIO_MODE_GPIO3_MSK; - break; - default: + if (offset >= ARRAY_SIZE(gpio_masks)) { ret = -EINVAL; goto err_release; } - ret = regmap_update_bits(st->regmap, AD4170_GPIO_MODE_REG, gpio_mask, + + ret = regmap_update_bits(st->regmap, AD4170_GPIO_MODE_REG, + gpio_masks[offset], AD4170_GPIO_MODE_GPIO_OUTPUT << (2 * offset)); err_release: @@ -2996,9 +2979,9 @@ static int ad4170_probe(struct spi_device *spi) } static const struct spi_device_id ad4170_id_table[] = { - { "ad4170-4", (kernel_ulong_t)&ad4170_chip_info }, - { "ad4190-4", (kernel_ulong_t)&ad4190_chip_info }, - { "ad4195-4", (kernel_ulong_t)&ad4195_chip_info }, + { .name = "ad4170-4", .driver_data = (kernel_ulong_t)&ad4170_chip_info }, + { .name = "ad4190-4", .driver_data = (kernel_ulong_t)&ad4190_chip_info }, + { .name = "ad4195-4", .driver_data = (kernel_ulong_t)&ad4195_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad4170_id_table); diff --git a/drivers/iio/adc/ad4691.c b/drivers/iio/adc/ad4691.c new file mode 100644 index 000000000000..f2f7c4c6424a --- /dev/null +++ b/drivers/iio/adc/ad4691.c @@ -0,0 +1,2083 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2024-2026 Analog Devices, Inc. + * Author: Radu Sabau <radu.sabau@analog.com> + */ +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bitmap.h> +#include <linux/cleanup.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> +#include <linux/device/devres.h> +#include <linux/dmaengine.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/kstrtox.h> +#include <linux/limits.h> +#include <linux/math.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/pwm.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/reset.h> +#include <linux/string.h> +#include <linux/spi/spi.h> +#include <linux/spi/offload/consumer.h> +#include <linux/spi/offload/provider.h> +#include <linux/types.h> +#include <linux/units.h> +#include <linux/unaligned.h> + +#include <linux/iio/buffer.h> +#include <linux/iio/buffer-dma.h> +#include <linux/iio/buffer-dmaengine.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/trigger.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/iio/trigger_consumer.h> + +#define AD4691_VREF_uV_MIN 2400000 +#define AD4691_VREF_uV_MAX 5250000 +#define AD4691_VREF_2P5_uV_MAX 2750000 +#define AD4691_VREF_3P0_uV_MAX 3250000 +#define AD4691_VREF_3P3_uV_MAX 3750000 +#define AD4691_VREF_4P096_uV_MAX 4500000 + +#define AD4691_CNV_DUTY_CYCLE_NS 380 +#define AD4691_CNV_HIGH_TIME_NS 430 +/* + * Conservative default for the manual offload periodic trigger. Low enough + * to work safely out of the box across all OSR and channel count combinations. + */ +#define AD4691_OFFLOAD_INITIAL_TRIGGER_HZ (100 * HZ_PER_KHZ) + +#define AD4691_SPI_CONFIG_A_REG 0x000 +#define AD4691_SW_RESET (BIT(7) | BIT(0)) + +#define AD4691_STATUS_REG 0x014 +#define AD4691_CLAMP_STATUS1_REG 0x01A +#define AD4691_CLAMP_STATUS2_REG 0x01B +#define AD4691_DEVICE_SETUP 0x020 +#define AD4691_MANUAL_MODE BIT(2) +#define AD4691_LDO_EN BIT(4) +#define AD4691_REF_CTRL 0x021 +#define AD4691_REF_CTRL_MASK GENMASK(4, 2) +#define AD4691_REFBUF_EN BIT(0) +#define AD4691_OSC_FREQ_REG 0x023 +#define AD4691_OSC_FREQ_MASK GENMASK(3, 0) +#define AD4691_STD_SEQ_CONFIG 0x025 +#define AD4691_SEQ_ALL_CHANNELS_OFF 0x00 +#define AD4691_SPARE_CONTROL 0x02A + +#define AD4691_MAX_CHANNELS 16 + +#define AD4691_NOOP 0x00 +#define AD4691_ADC_CHAN(ch) ((0x10 + (ch)) << 3) +#define AD4691_EXIT_COMMAND 0x5000 + +#define AD4691_OSC_EN_REG 0x180 +#define AD4691_STATE_RESET_REG 0x181 +#define AD4691_STATE_RESET_ALL BIT(0) +#define AD4691_ADC_SETUP 0x182 +#define AD4691_ADC_MODE_MASK GENMASK(1, 0) +#define AD4691_CNV_BURST_MODE 0x01 +#define AD4691_AUTONOMOUS_MODE 0x02 +/* + * ACC_MASK_REG covers both mask bytes via ADDR_DESCENDING SPI: writing a + * 16-bit BE value to 0x185 auto-decrements to 0x184 for the second byte. + */ +#define AD4691_ACC_MASK_REG 0x185 +#define AD4691_ACC_DEPTH_IN(n) (0x186 + (n)) +#define AD4691_GPIO_MODE1_REG 0x196 +#define AD4691_GPIO_MODE2_REG 0x197 +#define AD4691_GP_MODE_MASK GENMASK(3, 0) +#define AD4691_GP_MODE_DATA_READY 0x06 +#define AD4691_GPIO_READ 0x1A0 +#define AD4691_ACC_STATUS_FULL1_REG 0x1B0 +#define AD4691_ACC_STATUS_FULL2_REG 0x1B1 +#define AD4691_ACC_STATUS_OVERRUN1_REG 0x1B2 +#define AD4691_ACC_STATUS_OVERRUN2_REG 0x1B3 +#define AD4691_ACC_STATUS_SAT1_REG 0x1B4 +#define AD4691_ACC_STATUS_SAT2_REG 0x1BE +#define AD4691_ACC_SAT_OVR_REG(n) (0x1C0 + (n)) +#define AD4691_AVG_IN(n) (0x201 + (2 * (n))) +#define AD4691_AVG_STS_IN(n) (0x222 + (3 * (n))) +#define AD4691_ACC_IN(n) (0x252 + (3 * (n))) +#define AD4691_ACC_STS_DATA(n) (0x283 + (4 * (n))) + + +static const char * const ad4691_supplies[] = { "avdd", "vio" }; + +enum ad4691_ref_ctrl { + AD4691_VREF_2P5, + AD4691_VREF_3P0, + AD4691_VREF_3P3, + AD4691_VREF_4P096, + AD4691_VREF_5P0 +}; + +struct ad4691_channel_info { + const struct iio_chan_spec *channels __counted_by_ptr(num_channels); + const struct iio_chan_spec *manual_channels __counted_by_ptr(num_channels); + unsigned int num_channels; +}; + +struct ad4691_chip_info { + const char *name; + unsigned int max_rate; + const struct ad4691_channel_info *sw_info; + const struct ad4691_channel_info *offload_info; +}; + +/* CNV burst mode channel — exposes oversampling ratio. */ +#define AD4691_CHANNEL(ch) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) \ + | BIT(IIO_CHAN_INFO_SAMP_FREQ) \ + | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) \ + | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .channel = ch, \ + .scan_index = ch, \ + .scan_type = { \ + .format = 'u', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ + } + +/* + * Manual mode channel — no oversampling ratio attribute. OSR is not + * supported in manual mode; ACC_DEPTH_IN is not configured during manual + * buffer enable. + */ +#define AD4691_MANUAL_CHANNEL(ch) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) \ + | BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .channel = ch, \ + .scan_index = ch, \ + .scan_type = { \ + .format = 'u', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ + } + +/* + * Offload path (bits_per_word=16): the SPI Engine assembles received + * bits into native 16-bit words before DMA, so samples are in + * CPU-native byte order (IIO_CPU). storagebits=16 matches the 16-bit + * DMA word size. + * + * CNV burst offload configures ACC_DEPTH_IN per channel, so the + * oversampling_ratio attribute is exposed. Manual offload does not; + * use AD4691_OFFLOAD_MANUAL_CHANNEL for that path. + */ +#define AD4691_OFFLOAD_CHANNEL(ch) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) \ + | BIT(IIO_CHAN_INFO_SAMP_FREQ) \ + | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) \ + | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .channel = ch, \ + .scan_index = ch, \ + .scan_type = { \ + .format = 'u', \ + .realbits = 16, \ + .storagebits = 16, \ + }, \ + } + +/* Manual offload — same IIO_CPU layout but no oversampling_ratio attribute. */ +#define AD4691_OFFLOAD_MANUAL_CHANNEL(ch) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) \ + | BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .channel = ch, \ + .scan_index = ch, \ + .scan_type = { \ + .format = 'u', \ + .realbits = 16, \ + .storagebits = 16, \ + }, \ + } + +static const struct iio_chan_spec ad4691_channels[] = { + AD4691_CHANNEL(0), + AD4691_CHANNEL(1), + AD4691_CHANNEL(2), + AD4691_CHANNEL(3), + AD4691_CHANNEL(4), + AD4691_CHANNEL(5), + AD4691_CHANNEL(6), + AD4691_CHANNEL(7), + AD4691_CHANNEL(8), + AD4691_CHANNEL(9), + AD4691_CHANNEL(10), + AD4691_CHANNEL(11), + AD4691_CHANNEL(12), + AD4691_CHANNEL(13), + AD4691_CHANNEL(14), + AD4691_CHANNEL(15), + IIO_CHAN_SOFT_TIMESTAMP(16), +}; + +static const struct iio_chan_spec ad4693_channels[] = { + AD4691_CHANNEL(0), + AD4691_CHANNEL(1), + AD4691_CHANNEL(2), + AD4691_CHANNEL(3), + AD4691_CHANNEL(4), + AD4691_CHANNEL(5), + AD4691_CHANNEL(6), + AD4691_CHANNEL(7), + IIO_CHAN_SOFT_TIMESTAMP(8), +}; + +/* + * Offload channel arrays: no IIO_CHAN_SOFT_TIMESTAMP because DMA delivers + * data directly to userspace without a software timestamp. + */ +static const struct iio_chan_spec ad4691_offload_channels[] = { + AD4691_OFFLOAD_CHANNEL(0), + AD4691_OFFLOAD_CHANNEL(1), + AD4691_OFFLOAD_CHANNEL(2), + AD4691_OFFLOAD_CHANNEL(3), + AD4691_OFFLOAD_CHANNEL(4), + AD4691_OFFLOAD_CHANNEL(5), + AD4691_OFFLOAD_CHANNEL(6), + AD4691_OFFLOAD_CHANNEL(7), + AD4691_OFFLOAD_CHANNEL(8), + AD4691_OFFLOAD_CHANNEL(9), + AD4691_OFFLOAD_CHANNEL(10), + AD4691_OFFLOAD_CHANNEL(11), + AD4691_OFFLOAD_CHANNEL(12), + AD4691_OFFLOAD_CHANNEL(13), + AD4691_OFFLOAD_CHANNEL(14), + AD4691_OFFLOAD_CHANNEL(15), +}; + +static const struct iio_chan_spec ad4693_offload_channels[] = { + AD4691_OFFLOAD_CHANNEL(0), + AD4691_OFFLOAD_CHANNEL(1), + AD4691_OFFLOAD_CHANNEL(2), + AD4691_OFFLOAD_CHANNEL(3), + AD4691_OFFLOAD_CHANNEL(4), + AD4691_OFFLOAD_CHANNEL(5), + AD4691_OFFLOAD_CHANNEL(6), + AD4691_OFFLOAD_CHANNEL(7), +}; + +static const struct iio_chan_spec ad4691_manual_channels[] = { + AD4691_MANUAL_CHANNEL(0), + AD4691_MANUAL_CHANNEL(1), + AD4691_MANUAL_CHANNEL(2), + AD4691_MANUAL_CHANNEL(3), + AD4691_MANUAL_CHANNEL(4), + AD4691_MANUAL_CHANNEL(5), + AD4691_MANUAL_CHANNEL(6), + AD4691_MANUAL_CHANNEL(7), + AD4691_MANUAL_CHANNEL(8), + AD4691_MANUAL_CHANNEL(9), + AD4691_MANUAL_CHANNEL(10), + AD4691_MANUAL_CHANNEL(11), + AD4691_MANUAL_CHANNEL(12), + AD4691_MANUAL_CHANNEL(13), + AD4691_MANUAL_CHANNEL(14), + AD4691_MANUAL_CHANNEL(15), + IIO_CHAN_SOFT_TIMESTAMP(16), +}; + +static const struct iio_chan_spec ad4693_manual_channels[] = { + AD4691_MANUAL_CHANNEL(0), + AD4691_MANUAL_CHANNEL(1), + AD4691_MANUAL_CHANNEL(2), + AD4691_MANUAL_CHANNEL(3), + AD4691_MANUAL_CHANNEL(4), + AD4691_MANUAL_CHANNEL(5), + AD4691_MANUAL_CHANNEL(6), + AD4691_MANUAL_CHANNEL(7), + IIO_CHAN_SOFT_TIMESTAMP(8), +}; + +static const struct iio_chan_spec ad4691_offload_manual_channels[] = { + AD4691_OFFLOAD_MANUAL_CHANNEL(0), + AD4691_OFFLOAD_MANUAL_CHANNEL(1), + AD4691_OFFLOAD_MANUAL_CHANNEL(2), + AD4691_OFFLOAD_MANUAL_CHANNEL(3), + AD4691_OFFLOAD_MANUAL_CHANNEL(4), + AD4691_OFFLOAD_MANUAL_CHANNEL(5), + AD4691_OFFLOAD_MANUAL_CHANNEL(6), + AD4691_OFFLOAD_MANUAL_CHANNEL(7), + AD4691_OFFLOAD_MANUAL_CHANNEL(8), + AD4691_OFFLOAD_MANUAL_CHANNEL(9), + AD4691_OFFLOAD_MANUAL_CHANNEL(10), + AD4691_OFFLOAD_MANUAL_CHANNEL(11), + AD4691_OFFLOAD_MANUAL_CHANNEL(12), + AD4691_OFFLOAD_MANUAL_CHANNEL(13), + AD4691_OFFLOAD_MANUAL_CHANNEL(14), + AD4691_OFFLOAD_MANUAL_CHANNEL(15), +}; + +static const struct iio_chan_spec ad4693_offload_manual_channels[] = { + AD4691_OFFLOAD_MANUAL_CHANNEL(0), + AD4691_OFFLOAD_MANUAL_CHANNEL(1), + AD4691_OFFLOAD_MANUAL_CHANNEL(2), + AD4691_OFFLOAD_MANUAL_CHANNEL(3), + AD4691_OFFLOAD_MANUAL_CHANNEL(4), + AD4691_OFFLOAD_MANUAL_CHANNEL(5), + AD4691_OFFLOAD_MANUAL_CHANNEL(6), + AD4691_OFFLOAD_MANUAL_CHANNEL(7), +}; + +static const int ad4691_oversampling_ratios[] = { 1, 2, 4, 8, 16, 32 }; + +static const struct ad4691_channel_info ad4691_sw_info = { + .channels = ad4691_channels, + .manual_channels = ad4691_manual_channels, + .num_channels = ARRAY_SIZE(ad4691_channels), +}; + +static const struct ad4691_channel_info ad4693_sw_info = { + .channels = ad4693_channels, + .manual_channels = ad4693_manual_channels, + .num_channels = ARRAY_SIZE(ad4693_channels), +}; + +static const struct ad4691_channel_info ad4691_offload_info = { + .channels = ad4691_offload_channels, + .manual_channels = ad4691_offload_manual_channels, + .num_channels = ARRAY_SIZE(ad4691_offload_channels), +}; + +static const struct ad4691_channel_info ad4693_offload_info = { + .channels = ad4693_offload_channels, + .manual_channels = ad4693_offload_manual_channels, + .num_channels = ARRAY_SIZE(ad4693_offload_channels), +}; + +/* + * Internal oscillator frequency table. Index is the OSC_FREQ_REG[3:0] value. + * Index 0 (1 MHz) is only valid for AD4692/AD4694; AD4691/AD4693 support + * up to 500 kHz and use index 1 as their highest valid rate. + */ +static const int ad4691_osc_freqs_Hz[] = { + [0x0] = 1000000, + [0x1] = 500000, + [0x2] = 400000, + [0x3] = 250000, + [0x4] = 200000, + [0x5] = 167000, + [0x6] = 133000, + [0x7] = 125000, + [0x8] = 100000, + [0x9] = 50000, + [0xA] = 25000, + [0xB] = 12500, + [0xC] = 10000, + [0xD] = 5000, + [0xE] = 2500, + [0xF] = 1250, +}; + +static const char * const ad4691_gp_names[] = { "gp0", "gp1", "gp2", "gp3" }; + +static const struct ad4691_chip_info ad4691_chip_info = { + .name = "ad4691", + .max_rate = 500 * HZ_PER_KHZ, + .sw_info = &ad4691_sw_info, + .offload_info = &ad4691_offload_info, +}; + +static const struct ad4691_chip_info ad4692_chip_info = { + .name = "ad4692", + .max_rate = 1 * HZ_PER_MHZ, + .sw_info = &ad4691_sw_info, + .offload_info = &ad4691_offload_info, +}; + +static const struct ad4691_chip_info ad4693_chip_info = { + .name = "ad4693", + .max_rate = 500 * HZ_PER_KHZ, + .sw_info = &ad4693_sw_info, + .offload_info = &ad4693_offload_info, +}; + +static const struct ad4691_chip_info ad4694_chip_info = { + .name = "ad4694", + .max_rate = 1 * HZ_PER_MHZ, + .sw_info = &ad4693_sw_info, + .offload_info = &ad4693_offload_info, +}; + +struct ad4691_state { + const struct ad4691_chip_info *info; + struct regmap *regmap; + struct spi_device *spi; + + struct pwm_device *conv_trigger; + int irq; + int vref_uV; + u32 cnv_period_ns; + /* + * Snapped oscillator frequency (Hz) shared by all channels. Set when + * sampling_frequency or oversampling_ratio is written; written to + * OSC_FREQ_REG at buffer enable and single-shot time so both attributes + * can be set in any order. Reading in_voltage_sampling_frequency + * returns target_osc_freq_Hz / osr — the effective rate given the + * shared oversampling ratio. + */ + u32 target_osc_freq_Hz; + /* Shared oversampling ratio across all channels; always 1 in manual mode. */ + unsigned int osr; + /* + * Precomputed effective-rate lists, one row per entry in + * ad4691_oversampling_ratios[]. Populated at probe; read_avail picks + * the row for the current shared OSR. The tables are stable after + * probe so returning a pointer into them from read_avail is race-free. + */ + int samp_freq_avail[ARRAY_SIZE(ad4691_oversampling_ratios)][ARRAY_SIZE(ad4691_osc_freqs_Hz)]; + int samp_freq_avail_len[ARRAY_SIZE(ad4691_oversampling_ratios)]; + + bool manual_mode; + bool irq_enabled; + bool refbuf_en; + bool ldo_en; + /* + * Synchronize access to members of the driver state, and ensure + * atomicity of consecutive SPI operations. + */ + struct mutex lock; + /* NULL when no SPI offload hardware is present. */ + struct spi_offload *offload; + struct spi_offload_trigger *offload_trigger; + u64 trigger_hz; + /* + * Per-buffer-enable lifetime resources: + * Manual Mode - a pre-built SPI message that clocks out N+1 + * transfers in one go. + * CNV Burst Mode - a pre-built SPI message that clocks out 2*N + * transfers in one go. + */ + struct spi_message scan_msg; + /* + * max 16 + 1 NOOP (manual) or 2*16 + 1 state-reset (CNV burst). + */ + struct spi_transfer scan_xfers[34]; + /* + * CNV burst: 16 AVG_IN addresses = 16. Manual: 16 channel cmds + + * 1 NOOP = 17. Stored as native u16. The non-offload path fills slots + * with put_unaligned_be16() (bits_per_word=8, bytes go out in memory + * order). The offload path assigns native values directly + * (bits_per_word=bpw, SPI reads each slot as a native 16-bit word and + * shifts it out MSB-first). + */ + u16 scan_tx[17] __aligned(IIO_DMA_MINALIGN); + /* + * CNV burst state-reset: 4-byte write [addr_hi, addr_lo, + * STATE_RESET_ALL, OSC_EN=1]. CS is asserted throughout, so + * ADDR_DESCENDING writes byte[3]=1 to OSC_EN_REG (0x180) as a + * deliberate side-write, keeping the oscillator enabled. Shared + * with the offload path (mutually exclusive at probe). + */ + u8 scan_tx_reset[4] __aligned(IIO_DMA_MINALIGN); + /* + * Scan buffer: one BE16 slot per active channel, plus timestamp. + * DMA-aligned because scan_xfers point rx_buf directly into vals[]. + */ + IIO_DECLARE_DMA_BUFFER_WITH_TS(__be16, vals, 16); +}; + +/* + * Configure the given GP pin (0-3) as DATA_READY output. + * GP0/GP1 → GPIO_MODE1_REG, GP2/GP3 → GPIO_MODE2_REG. + * Even pins occupy bits [3:0], odd pins bits [7:4]. + */ +static int ad4691_gpio_setup(struct ad4691_state *st, unsigned int gp_num) +{ + unsigned int bit_off = gp_num % 2; + unsigned int reg_off = gp_num / 2; + unsigned int shift = 4 * bit_off; + + return regmap_update_bits(st->regmap, + AD4691_GPIO_MODE1_REG + reg_off, + AD4691_GP_MODE_MASK << shift, + AD4691_GP_MODE_DATA_READY << shift); +} + +static const struct spi_offload_config ad4691_offload_config = { + .capability_flags = SPI_OFFLOAD_CAP_TRIGGER | + SPI_OFFLOAD_CAP_RX_STREAM_DMA, +}; + +static bool ad4691_offload_trigger_match(struct spi_offload_trigger *trigger, + enum spi_offload_trigger_type type, + u64 *args, u32 nargs) +{ + return type == SPI_OFFLOAD_TRIGGER_DATA_READY && nargs == 1 && args[0] <= 3; +} + +static int ad4691_offload_trigger_request(struct spi_offload_trigger *trigger, + enum spi_offload_trigger_type type, + u64 *args, u32 nargs) +{ + struct ad4691_state *st = spi_offload_trigger_get_priv(trigger); + + if (nargs != 1 || args[0] > 3) + return -EINVAL; + + return ad4691_gpio_setup(st, args[0]); +} + +static int ad4691_offload_trigger_validate(struct spi_offload_trigger *trigger, + struct spi_offload_trigger_config *config) +{ + if (config->type != SPI_OFFLOAD_TRIGGER_DATA_READY) + return -EINVAL; + + return 0; +} + +static const struct spi_offload_trigger_ops ad4691_offload_trigger_ops = { + .match = ad4691_offload_trigger_match, + .request = ad4691_offload_trigger_request, + .validate = ad4691_offload_trigger_validate, +}; + +static int ad4691_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + struct spi_device *spi = context; + u8 tx[2], rx[4]; + int ret; + + /* Set bit 15 to mark the operation as READ. */ + put_unaligned_be16(0x8000 | reg, tx); + + switch (reg) { + case 0 ... AD4691_OSC_FREQ_REG: + case AD4691_SPARE_CONTROL ... AD4691_ACC_MASK_REG - 1: + case AD4691_ACC_MASK_REG + 1 ... AD4691_ACC_SAT_OVR_REG(15): + ret = spi_write_then_read(spi, tx, sizeof(tx), rx, 1); + if (ret) + return ret; + *val = rx[0]; + return 0; + case AD4691_ACC_MASK_REG: + case AD4691_STD_SEQ_CONFIG: + case AD4691_AVG_IN(0) ... AD4691_AVG_IN(15): + ret = spi_write_then_read(spi, tx, sizeof(tx), rx, 2); + if (ret) + return ret; + *val = get_unaligned_be16(rx); + return 0; + case AD4691_AVG_STS_IN(0) ... AD4691_AVG_STS_IN(15): + case AD4691_ACC_IN(0) ... AD4691_ACC_IN(15): + ret = spi_write_then_read(spi, tx, sizeof(tx), rx, 3); + if (ret) + return ret; + *val = get_unaligned_be24(rx); + return 0; + case AD4691_ACC_STS_DATA(0) ... AD4691_ACC_STS_DATA(15): + ret = spi_write_then_read(spi, tx, sizeof(tx), rx, 4); + if (ret) + return ret; + *val = get_unaligned_be32(rx); + return 0; + default: + return -EINVAL; + } +} + +static int ad4691_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct spi_device *spi = context; + u8 tx[4]; + + put_unaligned_be16(reg, tx); + + switch (reg) { + case 0 ... AD4691_OSC_FREQ_REG: + case AD4691_SPARE_CONTROL ... AD4691_ACC_MASK_REG - 1: + case AD4691_ACC_MASK_REG + 1 ... AD4691_GPIO_MODE2_REG: + if (val > U8_MAX) + return -EINVAL; + tx[2] = val; + return spi_write_then_read(spi, tx, 3, NULL, 0); + case AD4691_ACC_MASK_REG: + case AD4691_STD_SEQ_CONFIG: + if (val > U16_MAX) + return -EINVAL; + put_unaligned_be16(val, &tx[2]); + return spi_write_then_read(spi, tx, 4, NULL, 0); + default: + return -EINVAL; + } +} + +static bool ad4691_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case AD4691_STATUS_REG: + case AD4691_CLAMP_STATUS1_REG: + case AD4691_CLAMP_STATUS2_REG: + case AD4691_GPIO_READ: + case AD4691_ACC_STATUS_FULL1_REG ... AD4691_ACC_STATUS_SAT2_REG: + case AD4691_ACC_SAT_OVR_REG(0) ... AD4691_ACC_SAT_OVR_REG(15): + case AD4691_AVG_IN(0) ... AD4691_AVG_IN(15): + case AD4691_AVG_STS_IN(0) ... AD4691_AVG_STS_IN(15): + case AD4691_ACC_IN(0) ... AD4691_ACC_IN(15): + case AD4691_ACC_STS_DATA(0) ... AD4691_ACC_STS_DATA(15): + return true; + default: + return false; + } +} + +static bool ad4691_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0 ... AD4691_OSC_FREQ_REG: + case AD4691_SPARE_CONTROL ... AD4691_ACC_SAT_OVR_REG(15): + case AD4691_STD_SEQ_CONFIG: + return true; + default: + break; + } + + /* + * Multi-byte result registers have non-unit strides; only the base + * address of each entry is a valid single-register read. + */ + if (reg >= AD4691_AVG_IN(0) && reg <= AD4691_AVG_IN(15)) + return (reg - AD4691_AVG_IN(0)) % 2 == 0; + if (reg >= AD4691_AVG_STS_IN(0) && reg <= AD4691_AVG_STS_IN(15)) + return (reg - AD4691_AVG_STS_IN(0)) % 3 == 0; + if (reg >= AD4691_ACC_IN(0) && reg <= AD4691_ACC_IN(15)) + return (reg - AD4691_ACC_IN(0)) % 3 == 0; + if (reg >= AD4691_ACC_STS_DATA(0) && reg <= AD4691_ACC_STS_DATA(15)) + return (reg - AD4691_ACC_STS_DATA(0)) % 4 == 0; + + return false; +} + +static bool ad4691_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0 ... AD4691_OSC_FREQ_REG: + case AD4691_STD_SEQ_CONFIG: + case AD4691_SPARE_CONTROL ... AD4691_GPIO_MODE2_REG: + return true; + default: + return false; + } +} + +static const struct regmap_config ad4691_regmap_config = { + .reg_bits = 16, + .val_bits = 32, + .reg_read = ad4691_reg_read, + .reg_write = ad4691_reg_write, + .volatile_reg = ad4691_volatile_reg, + .readable_reg = ad4691_readable_reg, + .writeable_reg = ad4691_writeable_reg, + .max_register = AD4691_ACC_STS_DATA(15), + .cache_type = REGCACHE_MAPLE, +}; + +/* + * Index 0 in ad4691_osc_freqs_Hz is 1 MHz — valid only for AD4692/AD4694 + * (max_rate == 1 MHz). AD4691/AD4693 cap at 500 kHz so their valid range + * starts at index 1. + */ +static unsigned int ad4691_samp_freq_start(const struct ad4691_chip_info *info) +{ + return (info->max_rate == 1 * HZ_PER_MHZ) ? 0 : 1; +} + +/* + * Find the largest oscillator table entry that is both <= needed_osc and + * evenly divisible by osr (guaranteeing an integer effective rate on + * read-back). Returns 0 if no such entry exists in the chip's valid range. + */ +static unsigned int ad4691_find_osc_freq(struct ad4691_state *st, + unsigned int needed_osc, + unsigned int osr) +{ + unsigned int start = ad4691_samp_freq_start(st->info); + + for (unsigned int i = start; i < ARRAY_SIZE(ad4691_osc_freqs_Hz); i++) { + if ((unsigned int)ad4691_osc_freqs_Hz[i] > needed_osc) + continue; + if (ad4691_osc_freqs_Hz[i] % osr) + continue; + return ad4691_osc_freqs_Hz[i]; + } + return 0; +} + +/* Write target_osc_freq_Hz to OSC_FREQ_REG. Called at use time. */ +static int ad4691_write_osc_freq(struct ad4691_state *st) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(ad4691_osc_freqs_Hz); i++) { + if (ad4691_osc_freqs_Hz[i] == st->target_osc_freq_Hz) + return regmap_write(st->regmap, AD4691_OSC_FREQ_REG, i); + } + return -EINVAL; +} + +/* Return the index of osr in ad4691_oversampling_ratios[], defaulting to 0. */ +static unsigned int ad4691_osr_index(unsigned int osr) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(ad4691_oversampling_ratios) - 1; i++) { + if ((unsigned int)ad4691_oversampling_ratios[i] == osr) + return i; + } + return ARRAY_SIZE(ad4691_oversampling_ratios) - 1; +} + +/* + * Precompute samp_freq_avail[][]: for each OSR value, list the oscillator + * table entries that divide evenly by that OSR, expressed as effective rates + * (osc_freq / osr). Called once at probe after st->info is set. + */ +static void ad4691_precompute_samp_freq_avail(struct ad4691_state *st) +{ + unsigned int start = ad4691_samp_freq_start(st->info); + + for (unsigned int i = 0; i < ARRAY_SIZE(ad4691_oversampling_ratios); i++) { + unsigned int osr = ad4691_oversampling_ratios[i]; + int n = 0; + + for (unsigned int j = start; j < ARRAY_SIZE(ad4691_osc_freqs_Hz); j++) { + if (ad4691_osc_freqs_Hz[j] % osr) + continue; + st->samp_freq_avail[i][n++] = ad4691_osc_freqs_Hz[j] / osr; + } + st->samp_freq_avail_len[i] = n; + } +} + +static int ad4691_set_sampling_freq(struct ad4691_state *st, int freq) +{ + unsigned int osr, found; + + /* + * Read osr under st->lock: osr and target_osc_freq_Hz are modified + * together under the lock; reading after acquiring it ensures we see + * a consistent snapshot with no concurrent write racing us. + */ + guard(mutex)(&st->lock); + osr = st->osr; + + if (freq <= 0 || (unsigned int)freq > st->info->max_rate / osr) + return -EINVAL; + + found = ad4691_find_osc_freq(st, (unsigned int)freq * osr, osr); + if (!found) + return -EINVAL; + + /* + * Store the snapped oscillator frequency; OSC_FREQ_REG is written at + * buffer enable and single-shot time so that sampling_frequency and + * oversampling_ratio can be set in any order. + */ + st->target_osc_freq_Hz = found; + return 0; +} + +static int ad4691_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, + int *length, long mask) +{ + struct ad4691_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: { + unsigned int osr_idx; + + /* + * The precomputed tables are stable after probe; only the + * current OSR needs to be read under the lock to pick the + * right row atomically. + */ + guard(mutex)(&st->lock); + osr_idx = ad4691_osr_index(st->osr); + *vals = st->samp_freq_avail[osr_idx]; + *type = IIO_VAL_INT; + *length = st->samp_freq_avail_len[osr_idx]; + return IIO_AVAIL_LIST; + } + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *vals = ad4691_oversampling_ratios; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(ad4691_oversampling_ratios); + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int ad4691_single_shot_read(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val) +{ + struct ad4691_state *st = iio_priv(indio_dev); + unsigned int reg_val, period_us; + int ret; + + guard(mutex)(&st->lock); + + /* Use AUTONOMOUS mode for single-shot reads. */ + ret = regmap_write(st->regmap, AD4691_STATE_RESET_REG, AD4691_STATE_RESET_ALL); + if (ret) + return ret; + + ret = regmap_write(st->regmap, AD4691_STD_SEQ_CONFIG, + BIT(chan->channel)); + if (ret) + return ret; + + ret = regmap_write(st->regmap, AD4691_ACC_MASK_REG, + ~BIT(chan->channel) & GENMASK(15, 0)); + if (ret) + return ret; + + ret = regmap_write(st->regmap, AD4691_ACC_DEPTH_IN(0), st->osr); + if (ret) + return ret; + + ret = ad4691_write_osc_freq(st); + if (ret) + return ret; + + ret = regmap_write(st->regmap, AD4691_OSC_EN_REG, 1); + if (ret) + return ret; + + /* + * Wait osr + 1 oscillator periods: osr for accumulation, +1 for the + * pipeline margin (one extra period ensures the final result is ready). + */ + period_us = DIV_ROUND_UP((st->osr + 1) * USEC_PER_SEC, + st->target_osc_freq_Hz); + fsleep(period_us); + + ret = regmap_write(st->regmap, AD4691_OSC_EN_REG, 0); + if (ret) + return ret; + + ret = regmap_read(st->regmap, AD4691_AVG_IN(chan->channel), ®_val); + if (ret) + return ret; + + *val = reg_val; + + ret = regmap_write(st->regmap, AD4691_STATE_RESET_REG, AD4691_STATE_RESET_ALL); + if (ret) + return ret; + + return IIO_VAL_INT; +} + +static int ad4691_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long info) +{ + struct ad4691_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_RAW: { + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + + return ad4691_single_shot_read(indio_dev, chan, val); + } + case IIO_CHAN_INFO_SAMP_FREQ: { + /* + * Read target_osc_freq_Hz and osr under st->lock to get a + * consistent snapshot: write_raw for SAMP_FREQ or OSR modifies + * both fields under the lock, so a concurrent read without the + * lock could observe a new oscillator frequency with the old OSR. + */ + guard(mutex)(&st->lock); + *val = st->target_osc_freq_Hz / st->osr; + return IIO_VAL_INT; + } + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { + guard(mutex)(&st->lock); + *val = st->osr; + return IIO_VAL_INT; + } + case IIO_CHAN_INFO_SCALE: + *val = st->vref_uV / (MICRO / MILLI); + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } +} + +static int ad4691_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct ad4691_state *st = iio_priv(indio_dev); + + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + return ad4691_set_sampling_freq(st, val); + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { + unsigned int old_effective, found, osr_idx; + + osr_idx = ad4691_osr_index(val); + if (ad4691_oversampling_ratios[osr_idx] != val) + return -EINVAL; + + /* + * Hold st->lock while computing the new oscillator frequency + * and updating both target_osc_freq_Hz and osr atomically: + * read_raw for SAMP_FREQ reads both fields under the lock and + * must see a consistent pair (new osc ↔ new osr). + * + * Snap target_osc_freq_Hz to the largest table entry that is + * both <= old_effective * new_osr and evenly divisible by + * new_osr, preserving an integer read-back of + * in_voltage_sampling_frequency after the OSR change. + */ + guard(mutex)(&st->lock); + old_effective = st->target_osc_freq_Hz / st->osr; + found = ad4691_find_osc_freq(st, old_effective * (unsigned int)val, val); + if (!found) + return -EINVAL; + st->target_osc_freq_Hz = found; + st->osr = val; + return 0; + } + default: + return -EINVAL; + } +} + +static int ad4691_reg_access(struct iio_dev *indio_dev, unsigned int reg, + unsigned int writeval, unsigned int *readval) +{ + struct ad4691_state *st = iio_priv(indio_dev); + + guard(mutex)(&st->lock); + + if (readval) + return regmap_read(st->regmap, reg, readval); + + return regmap_write(st->regmap, reg, writeval); +} + +static int ad4691_set_pwm_freq(struct ad4691_state *st, unsigned int freq) +{ + if (!freq) + return -EINVAL; + + st->cnv_period_ns = DIV_ROUND_UP(NSEC_PER_SEC, freq); + return 0; +} + +static int ad4691_sampling_enable(struct ad4691_state *st, bool enable) +{ + struct pwm_state conv_state = { + .period = st->cnv_period_ns, + .duty_cycle = AD4691_CNV_DUTY_CYCLE_NS, + .polarity = PWM_POLARITY_NORMAL, + .enabled = enable, + }; + + return pwm_apply_might_sleep(st->conv_trigger, &conv_state); +} + +/* + * ad4691_enter_conversion_mode - Switch the chip to its buffer conversion mode. + * + * Configures the ADC hardware registers for the mode selected at probe + * (CNV_BURST or MANUAL). Called from buffer preenable before starting + * sampling. The chip is in AUTONOMOUS mode during idle (for read_raw). + */ +static int ad4691_enter_conversion_mode(struct ad4691_state *st) +{ + int ret; + + if (st->manual_mode) + return regmap_update_bits(st->regmap, AD4691_DEVICE_SETUP, + AD4691_MANUAL_MODE, AD4691_MANUAL_MODE); + + ret = ad4691_write_osc_freq(st); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, AD4691_ADC_SETUP, + AD4691_ADC_MODE_MASK, AD4691_CNV_BURST_MODE); + if (ret) + return ret; + + return regmap_write(st->regmap, AD4691_STATE_RESET_REG, + AD4691_STATE_RESET_ALL); +} + +static int ad4691_transfer(struct ad4691_state *st, u16 cmd) +{ + u8 buf[2]; + + put_unaligned_be16(cmd, buf); + + return spi_write_then_read(st->spi, buf, sizeof(buf), NULL, 0); +} + +/* + * ad4691_exit_conversion_mode - Return the chip to AUTONOMOUS mode. + * + * Called from buffer postdisable to restore the chip to the + * idle state used by read_raw. Clears the sequencer and resets state. + */ +static int ad4691_exit_conversion_mode(struct ad4691_state *st) +{ + if (st->manual_mode) + return ad4691_transfer(st, AD4691_EXIT_COMMAND); + + return regmap_update_bits(st->regmap, AD4691_ADC_SETUP, + AD4691_ADC_MODE_MASK, AD4691_AUTONOMOUS_MODE); +} + +static int ad4691_manual_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ad4691_state *st = iio_priv(indio_dev); + unsigned int k, i; + int ret; + + memset(st->scan_xfers, 0, sizeof(st->scan_xfers)); + memset(st->scan_tx, 0, sizeof(st->scan_tx)); + + spi_message_init(&st->scan_msg); + + k = 0; + iio_for_each_active_channel(indio_dev, i) { + /* + * Channel-select command occupies the first (high) byte of the + * 16-bit DIN frame; the second byte is a don't-care zero pad. + * put_unaligned_be16() writes [cmd, 0x00] in memory so the + * SPI controller sends the command byte first on the wire. + */ + put_unaligned_be16((u16)(AD4691_ADC_CHAN(i) << 8), &st->scan_tx[k]); + st->scan_xfers[k].tx_buf = &st->scan_tx[k]; + /* + * The pipeline means xfer[0] receives the residual from the + * previous sequence, not a valid sample. Discard it (rx_buf=NULL) + * to avoid aliasing vals[0] across two concurrent DMA mappings. + * xfer[1] (or the NOOP when only one channel is active) writes + * the real ch[0] result to vals[0]. Subsequent transfers write + * into vals[k-1] so each result lands at the next dense slot. + */ + st->scan_xfers[k].rx_buf = (k == 0) ? NULL : &st->vals[k - 1]; + st->scan_xfers[k].len = sizeof(*st->scan_tx); + st->scan_xfers[k].cs_change = 1; + st->scan_xfers[k].cs_change_delay.value = AD4691_CNV_HIGH_TIME_NS; + st->scan_xfers[k].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; + spi_message_add_tail(&st->scan_xfers[k], &st->scan_msg); + k++; + } + + /* Final NOOP transfer retrieves the last channel's result. */ + st->scan_xfers[k].tx_buf = &st->scan_tx[k]; /* scan_tx[k] == 0 == NOOP */ + st->scan_xfers[k].rx_buf = &st->vals[k - 1]; + st->scan_xfers[k].len = sizeof(*st->scan_tx); + spi_message_add_tail(&st->scan_xfers[k], &st->scan_msg); + + ret = spi_optimize_message(st->spi, &st->scan_msg); + if (ret) + return ret; + + ret = ad4691_enter_conversion_mode(st); + if (ret) { + spi_unoptimize_message(&st->scan_msg); + return ret; + } + + return 0; +} + +static int ad4691_manual_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ad4691_state *st = iio_priv(indio_dev); + int ret; + + ret = ad4691_exit_conversion_mode(st); + spi_unoptimize_message(&st->scan_msg); + return ret; +} + +static const struct iio_buffer_setup_ops ad4691_manual_buffer_setup_ops = { + .preenable = ad4691_manual_buffer_preenable, + .postdisable = ad4691_manual_buffer_postdisable, +}; + +static int ad4691_cnv_burst_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ad4691_state *st = iio_priv(indio_dev); + unsigned int acc_mask, std_seq_config; + unsigned int k, i; + int ret; + + memset(st->scan_xfers, 0, sizeof(st->scan_xfers)); + memset(st->scan_tx, 0, sizeof(st->scan_tx)); + + spi_message_init(&st->scan_msg); + + /* + * Each AVG_IN read needs two transfers: a 2-byte address write phase + * followed by a 2-byte data read phase. CS toggles between channels + * (cs_change=1 on the read phase of all but the last channel). + */ + k = 0; + iio_for_each_active_channel(indio_dev, i) { + put_unaligned_be16(0x8000 | AD4691_AVG_IN(i), &st->scan_tx[k]); + st->scan_xfers[2 * k].tx_buf = &st->scan_tx[k]; + st->scan_xfers[2 * k].len = sizeof(*st->scan_tx); + spi_message_add_tail(&st->scan_xfers[2 * k], &st->scan_msg); + st->scan_xfers[2 * k + 1].rx_buf = &st->vals[k]; + st->scan_xfers[2 * k + 1].len = sizeof(*st->scan_tx); + st->scan_xfers[2 * k + 1].cs_change = 1; + spi_message_add_tail(&st->scan_xfers[2 * k + 1], &st->scan_msg); + k++; + } + + /* + * Append a 4-byte state-reset transfer [addr_hi, addr_lo, + * STATE_RESET_ALL, OSC_EN=1]. CS is asserted throughout, so + * ADDR_DESCENDING writes byte[3]=1 to OSC_EN_REG (0x180) as a + * deliberate side-write, keeping the oscillator enabled. + * STATE_RESET_ALL starts the next burst; the hardware does not + * accumulate new conversions until after a STATE_RESET pulse, so + * no in-progress data is lost. No cs_change here — CS must + * deassert normally at end of message to frame the next command. + */ + put_unaligned_be16(AD4691_STATE_RESET_REG, st->scan_tx_reset); + st->scan_tx_reset[2] = AD4691_STATE_RESET_ALL; + st->scan_tx_reset[3] = 1; + st->scan_xfers[2 * k].tx_buf = st->scan_tx_reset; + st->scan_xfers[2 * k].len = sizeof(st->scan_tx_reset); + spi_message_add_tail(&st->scan_xfers[2 * k], &st->scan_msg); + + ret = spi_optimize_message(st->spi, &st->scan_msg); + if (ret) + return ret; + + std_seq_config = bitmap_read(indio_dev->active_scan_mask, 0, + iio_get_masklength(indio_dev)) & GENMASK(15, 0); + ret = regmap_write(st->regmap, AD4691_STD_SEQ_CONFIG, std_seq_config); + if (ret) + goto err_unoptimize; + + acc_mask = ~std_seq_config & GENMASK(15, 0); + ret = regmap_write(st->regmap, AD4691_ACC_MASK_REG, acc_mask); + if (ret) + goto err_unoptimize; + + ret = regmap_write(st->regmap, AD4691_ACC_DEPTH_IN(0), st->osr); + if (ret) + goto err_unoptimize; + + ret = ad4691_enter_conversion_mode(st); + if (ret) + goto err_unoptimize; + + return 0; + +err_unoptimize: + spi_unoptimize_message(&st->scan_msg); + return ret; +} + +static int ad4691_cnv_burst_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ad4691_state *st = iio_priv(indio_dev); + int ret; + + /* + * Start the PWM and unmask the IRQ here in postenable, not in + * preenable. The IIO core attaches the trigger poll function between + * preenable and postenable; enabling sampling or unmasking the IRQ + * before that point risks a DATA_READY assertion landing before the + * poll function is registered. iio_trigger_poll() would drop the + * event, disable_irq_nosync() would fire, and enable_irq() would + * never be called, leaving the IRQ permanently masked. + */ + ret = ad4691_sampling_enable(st, true); + if (ret) + return ret; + + enable_irq(st->irq); + st->irq_enabled = true; + return 0; +} + +static int ad4691_cnv_burst_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ad4691_state *st = iio_priv(indio_dev); + + if (st->irq_enabled) { + disable_irq(st->irq); + st->irq_enabled = false; + } + return ad4691_sampling_enable(st, false); +} + +static int ad4691_cnv_burst_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ad4691_state *st = iio_priv(indio_dev); + int ret; + + ret = ad4691_exit_conversion_mode(st); + spi_unoptimize_message(&st->scan_msg); + return ret; +} + +static const struct iio_buffer_setup_ops ad4691_cnv_burst_buffer_setup_ops = { + .preenable = ad4691_cnv_burst_buffer_preenable, + .postenable = ad4691_cnv_burst_buffer_postenable, + .predisable = ad4691_cnv_burst_buffer_predisable, + .postdisable = ad4691_cnv_burst_buffer_postdisable, +}; + +static int ad4691_manual_offload_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ad4691_state *st = iio_priv(indio_dev); + struct device *dev = regmap_get_device(st->regmap); + struct spi_device *spi = to_spi_device(dev); + struct spi_offload_trigger_config config = { + .type = SPI_OFFLOAD_TRIGGER_PERIODIC, + }; + unsigned int bpw = indio_dev->channels[0].scan_type.realbits; + unsigned int bit, k; + int ret; + + ret = ad4691_enter_conversion_mode(st); + if (ret) + return ret; + + memset(st->scan_xfers, 0, sizeof(st->scan_xfers)); + memset(st->scan_tx, 0, sizeof(st->scan_tx)); + + /* + * N+1 transfers for N channels. Each CS-low period triggers + * a conversion AND returns the previous result (pipelined). + * TX: [AD4691_ADC_CHAN(n), 0x00] + * RX: [data_hi, data_lo] (storagebits=16, shift=0) + * Transfer 0 RX is garbage; transfers 1..N carry real data. + * scan_tx is reused for TX commands (mutually exclusive with the + * non-offload triggered-buffer path). + * + * bits_per_word=bpw: the SPI controller reads tx_buf as a native + * 16-bit word and shifts it out MSB-first. Store the exact 16-bit + * value we want on the wire as a plain native u16 — no endianness + * macro — so the wire bytes are correct on both LE and BE hosts. + * The channel-select command is a single byte; shift it to the MSB + * position so SPI sends it first, with a zero pad in the LSB. + */ + k = 0; + iio_for_each_active_channel(indio_dev, bit) { + st->scan_tx[k] = AD4691_ADC_CHAN(bit) << 8; + st->scan_xfers[k].tx_buf = &st->scan_tx[k]; + st->scan_xfers[k].len = sizeof(*st->scan_tx); + st->scan_xfers[k].bits_per_word = bpw; + st->scan_xfers[k].cs_change = 1; + st->scan_xfers[k].cs_change_delay.value = AD4691_CNV_HIGH_TIME_NS; + st->scan_xfers[k].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; + /* First transfer RX is garbage — skip it. */ + if (k > 0) + st->scan_xfers[k].offload_flags = SPI_OFFLOAD_XFER_RX_STREAM; + k++; + } + + /* Final NOOP transfer retrieves the last channel's result. */ + st->scan_xfers[k].tx_buf = &st->scan_tx[k]; /* scan_tx[k] == 0 == NOOP */ + st->scan_xfers[k].len = sizeof(*st->scan_tx); + st->scan_xfers[k].bits_per_word = bpw; + st->scan_xfers[k].offload_flags = SPI_OFFLOAD_XFER_RX_STREAM; + k++; + + spi_message_init_with_transfers(&st->scan_msg, st->scan_xfers, k); + st->scan_msg.offload = st->offload; + + ret = spi_optimize_message(spi, &st->scan_msg); + if (ret) + goto err_exit_conversion; + + config.periodic.frequency_hz = st->trigger_hz; + ret = spi_offload_trigger_enable(st->offload, st->offload_trigger, &config); + if (ret) + goto err_unoptimize; + + return 0; + +err_unoptimize: + spi_unoptimize_message(&st->scan_msg); +err_exit_conversion: + ad4691_exit_conversion_mode(st); + return ret; +} + +static int ad4691_manual_offload_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ad4691_state *st = iio_priv(indio_dev); + + spi_offload_trigger_disable(st->offload, st->offload_trigger); + spi_unoptimize_message(&st->scan_msg); + + return ad4691_exit_conversion_mode(st); +} + +static const struct iio_buffer_setup_ops ad4691_manual_offload_buffer_setup_ops = { + .postenable = ad4691_manual_offload_buffer_postenable, + .predisable = ad4691_manual_offload_buffer_predisable, +}; + +static int ad4691_cnv_burst_offload_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ad4691_state *st = iio_priv(indio_dev); + struct device *dev = regmap_get_device(st->regmap); + struct spi_device *spi = to_spi_device(dev); + struct spi_offload_trigger_config config = { + .type = SPI_OFFLOAD_TRIGGER_DATA_READY, + }; + unsigned int bpw = indio_dev->channels[0].scan_type.realbits; + unsigned int acc_mask, std_seq_config; + unsigned int bit, k; + int ret; + + std_seq_config = bitmap_read(indio_dev->active_scan_mask, 0, + iio_get_masklength(indio_dev)) & GENMASK(15, 0); + ret = regmap_write(st->regmap, AD4691_STD_SEQ_CONFIG, std_seq_config); + if (ret) + return ret; + + acc_mask = ~std_seq_config & GENMASK(15, 0); + ret = regmap_write(st->regmap, AD4691_ACC_MASK_REG, acc_mask); + if (ret) + return ret; + + ret = regmap_write(st->regmap, AD4691_ACC_DEPTH_IN(0), st->osr); + if (ret) + return ret; + + ret = ad4691_enter_conversion_mode(st); + if (ret) + return ret; + + memset(st->scan_xfers, 0, sizeof(st->scan_xfers)); + memset(st->scan_tx, 0, sizeof(st->scan_tx)); + + /* + * Each AVG_IN register read uses two transfers: + * TX: [reg_hi | 0x80, reg_lo] (address phase, CS stays asserted) + * RX: [data_hi, data_lo] (bpw-wide data phase, storagebits=16) + * Both TX and RX use bits_per_word=bpw: the SPI controller reads tx_buf + * as a native 16-bit word and shifts it out MSB-first. Store the exact + * 16-bit wire value as a plain native u16 — no endianness macro — so the + * wire bytes are correct on both LE and BE hosts. The read-address + * (0x8000 | reg) is already the 16-bit value we want on the wire. + * scan_tx is reused for TX addresses (mutually exclusive with the + * non-offload triggered-buffer path). + */ + k = 0; + iio_for_each_active_channel(indio_dev, bit) { + st->scan_tx[k] = 0x8000 | AD4691_AVG_IN(bit); + + /* TX: address phase, CS stays asserted into data phase */ + st->scan_xfers[2 * k].tx_buf = &st->scan_tx[k]; + st->scan_xfers[2 * k].len = sizeof(*st->scan_tx); + st->scan_xfers[2 * k].bits_per_word = bpw; + + /* RX: data phase, CS toggles after to delimit the next register op */ + st->scan_xfers[2 * k + 1].len = sizeof(*st->scan_tx); + st->scan_xfers[2 * k + 1].bits_per_word = bpw; + st->scan_xfers[2 * k + 1].offload_flags = SPI_OFFLOAD_XFER_RX_STREAM; + st->scan_xfers[2 * k + 1].cs_change = 1; + k++; + } + + /* + * State reset: single 4-byte write [addr_hi, addr_lo, STATE_RESET_ALL, + * OSC_EN=1]. ADDR_DESCENDING writes byte[3]=1 to OSC_EN_REG (0x180) as + * a deliberate side-write, keeping the oscillator enabled. + * scan_tx_reset is shared with the non-offload path (len=4 here vs + * len=3 there) since the two paths are mutually exclusive at probe. + */ + put_unaligned_be16(AD4691_STATE_RESET_REG, st->scan_tx_reset); + st->scan_tx_reset[2] = AD4691_STATE_RESET_ALL; + st->scan_tx_reset[3] = 1; + st->scan_xfers[2 * k].tx_buf = st->scan_tx_reset; + st->scan_xfers[2 * k].len = sizeof(st->scan_tx_reset); + /* + * 4-byte u8 buffer assembled with put_unaligned_be16(); leave + * bits_per_word at the default (8) so bytes go out in memory order. + */ + + spi_message_init_with_transfers(&st->scan_msg, st->scan_xfers, 2 * k + 1); + st->scan_msg.offload = st->offload; + + ret = spi_optimize_message(spi, &st->scan_msg); + if (ret) + goto err_exit_conversion; + + ret = spi_offload_trigger_enable(st->offload, st->offload_trigger, &config); + if (ret) + goto err_unoptimize; + + ret = ad4691_sampling_enable(st, true); + if (ret) + goto err_disable_trigger; + + return 0; + +err_disable_trigger: + spi_offload_trigger_disable(st->offload, st->offload_trigger); +err_unoptimize: + spi_unoptimize_message(&st->scan_msg); +err_exit_conversion: + ad4691_exit_conversion_mode(st); + return ret; +} + +static int ad4691_cnv_burst_offload_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ad4691_state *st = iio_priv(indio_dev); + + ad4691_sampling_enable(st, false); + spi_offload_trigger_disable(st->offload, st->offload_trigger); + spi_unoptimize_message(&st->scan_msg); + + return ad4691_exit_conversion_mode(st); +} + +static const struct iio_buffer_setup_ops ad4691_cnv_burst_offload_buffer_setup_ops = { + .postenable = ad4691_cnv_burst_offload_buffer_postenable, + .predisable = ad4691_cnv_burst_offload_buffer_predisable, +}; + +static ssize_t sampling_frequency_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct ad4691_state *st = iio_priv(indio_dev); + + if (st->manual_mode && st->offload) + return sysfs_emit(buf, "%llu\n", READ_ONCE(st->trigger_hz)); + + return sysfs_emit(buf, "%lu\n", NSEC_PER_SEC / st->cnv_period_ns); +} + +static ssize_t sampling_frequency_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 ad4691_state *st = iio_priv(indio_dev); + unsigned int freq; + int ret; + + ret = kstrtouint(buf, 10, &freq); + if (ret) + return ret; + + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + + if (st->manual_mode && st->offload) { + struct spi_offload_trigger_config config = { + .type = SPI_OFFLOAD_TRIGGER_PERIODIC, + .periodic = { .frequency_hz = freq }, + }; + + ret = spi_offload_trigger_validate(st->offload_trigger, &config); + if (ret) + return ret; + + WRITE_ONCE(st->trigger_hz, config.periodic.frequency_hz); + return len; + } + + ret = ad4691_set_pwm_freq(st, freq); + if (ret) + return ret; + + return len; +} + +static IIO_DEVICE_ATTR_RW(sampling_frequency, 0); + +static const struct iio_dev_attr *ad4691_buffer_attrs[] = { + &iio_dev_attr_sampling_frequency, + NULL +}; + +static irqreturn_t ad4691_irq(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct ad4691_state *st = iio_priv(indio_dev); + + /* + * Disable the IRQ before calling iio_trigger_poll(). The IRQ is + * re-enabled via the trigger .reenable callback, which the IIO core + * calls inside iio_trigger_notify_done() once use_count reaches zero. + * Re-enabling here (before notify_done) would race: a DATA_READY + * between enable_irq() and notify_done() calls iio_trigger_poll() + * while use_count > 0, dropping the event and permanently masking + * the IRQ. + */ + disable_irq_nosync(st->irq); + iio_trigger_poll(indio_dev->trig); + + return IRQ_HANDLED; +} + +static void ad4691_trigger_reenable(struct iio_trigger *trig) +{ + struct ad4691_state *st = iio_trigger_get_drvdata(trig); + + enable_irq(st->irq); +} + +static const struct iio_trigger_ops ad4691_trigger_ops = { + .reenable = ad4691_trigger_reenable, + .validate_device = iio_trigger_validate_own_device, +}; + +static void ad4691_read_scan(struct iio_dev *indio_dev, s64 ts) +{ + struct ad4691_state *st = iio_priv(indio_dev); + int ret; + + guard(mutex)(&st->lock); + + ret = spi_sync(st->spi, &st->scan_msg); + if (ret) { + dev_err_ratelimited(regmap_get_device(st->regmap), + "SPI scan failed: %d\n", ret); + return; + } + + /* + * rx_buf pointers in scan_xfers point directly into scan.vals, so no + * copy is needed. The scan_msg already includes a STATE_RESET at the + * end (appended in preenable), so no explicit reset is needed here. + */ + iio_push_to_buffers_with_ts(indio_dev, st->vals, sizeof(st->vals), ts); +} + +static irqreturn_t ad4691_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + + ad4691_read_scan(indio_dev, pf->timestamp); + iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; +} + +/* + * CNV burst mode: only allow our own trigger (driven by DATA_READY IRQ). + * Manual mode: external triggers (e.g. iio-trig-hrtimer) must be allowed + * because manual mode has no DATA_READY IRQ to fire the internal trigger. + * iio_trigger_ops.validate_device = iio_trigger_validate_own_device is + * correct in both modes — it prevents other devices from hijacking our + * internal trigger; the distinction here is only for iio_info.validate_trigger. + */ +static const struct iio_info ad4691_cnv_burst_info = { + .read_raw = ad4691_read_raw, + .write_raw = ad4691_write_raw, + .read_avail = ad4691_read_avail, + .debugfs_reg_access = ad4691_reg_access, + .validate_trigger = iio_validate_own_trigger, +}; + +static const struct iio_info ad4691_manual_info = { + .read_raw = ad4691_read_raw, + .write_raw = ad4691_write_raw, + .read_avail = ad4691_read_avail, + .debugfs_reg_access = ad4691_reg_access, +}; + +static int ad4691_pwm_setup(struct ad4691_state *st) +{ + struct device *dev = regmap_get_device(st->regmap); + + st->conv_trigger = devm_pwm_get(dev, "cnv"); + if (IS_ERR(st->conv_trigger)) + return dev_err_probe(dev, PTR_ERR(st->conv_trigger), + "Failed to get CNV PWM\n"); + + return ad4691_set_pwm_freq(st, st->info->max_rate); +} + +static int ad4691_regulator_setup(struct ad4691_state *st) +{ + struct device *dev = regmap_get_device(st->regmap); + int ret; + + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad4691_supplies), + ad4691_supplies); + if (ret) + return dev_err_probe(dev, ret, "Failed to get and enable supplies\n"); + + /* + * vdd-supply and ldo-in-supply are mutually exclusive: + * vdd-supply present → external 1.8V VDD; disable internal LDO. + * vdd-supply absent → enable internal LDO fed from ldo-in-supply. + * Having both simultaneously is strongly inadvisable per the datasheet. + */ + if (device_property_present(dev, "vdd-supply")) { + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, + "Failed to get and enable VDD\n"); + } else if (device_property_present(dev, "ldo-in-supply")) { + ret = devm_regulator_get_enable(dev, "ldo-in"); + if (ret) + return dev_err_probe(dev, ret, + "Failed to get and enable LDO-IN\n"); + st->ldo_en = true; + } else { + return dev_err_probe(dev, -EINVAL, + "missing one of vdd-supply, ldo-in-supply\n"); + } + + if (device_property_present(dev, "ref-supply")) { + st->vref_uV = devm_regulator_get_enable_read_voltage(dev, "ref"); + if (st->vref_uV < 0) + return dev_err_probe(dev, st->vref_uV, + "Failed to get REF supply voltage\n"); + } else if (device_property_present(dev, "refin-supply")) { + st->vref_uV = devm_regulator_get_enable_read_voltage(dev, "refin"); + if (st->vref_uV < 0) + return dev_err_probe(dev, st->vref_uV, + "Failed to get REFIN supply voltage\n"); + st->refbuf_en = true; + } else { + return dev_err_probe(dev, -EINVAL, + "missing one of ref-supply, refin-supply\n"); + } + + if (st->vref_uV < AD4691_VREF_uV_MIN || st->vref_uV > AD4691_VREF_uV_MAX) + return dev_err_probe(dev, -EINVAL, + "vref(%d) must be in the range [%u...%u]\n", + st->vref_uV, AD4691_VREF_uV_MIN, + AD4691_VREF_uV_MAX); + + return 0; +} + +static int ad4691_reset(struct ad4691_state *st) +{ + struct device *dev = regmap_get_device(st->regmap); + struct reset_control *rst; + int ret; + + rst = devm_reset_control_get_optional_exclusive(dev, NULL); + if (IS_ERR(rst)) + return dev_err_probe(dev, PTR_ERR(rst), "Failed to get reset\n"); + + if (rst) { + /* + * Assert the reset line to guarantee a clean reset pulse on + * every probe, including driver reloads where the line may + * already be deasserted (reset_control_put() does not + * re-assert on release). tRESETL (minimum pulse width) = 10 ns + * (Table 5); kernel function-call overhead alone exceeds this, + * so no explicit delay is needed between assert and deassert. + */ + reset_control_assert(rst); + ret = reset_control_deassert(rst); + if (ret) + return ret; + } else { + /* No hardware reset available, fall back to software reset. */ + ret = regmap_write(st->regmap, AD4691_SPI_CONFIG_A_REG, + AD4691_SW_RESET); + if (ret) + return ret; + } + + /* + * Wait 300 µs (Table 5) for the device to complete its internal reset + * sequence before accepting SPI commands. + */ + fsleep(300); + return 0; +} + +static int ad4691_config(struct ad4691_state *st) +{ + struct device *dev = regmap_get_device(st->regmap); + enum ad4691_ref_ctrl ref_val; + unsigned int val; + int ret; + + /* + * Determine buffer conversion mode from DT: if a PWM is provided it + * drives the CNV pin (CNV_BURST_MODE); otherwise CNV is tied to CS + * and each SPI transfer triggers a conversion (MANUAL_MODE). + * Both modes idle in AUTONOMOUS mode so that read_raw can use the + * internal oscillator without disturbing the hardware configuration. + */ + if (device_property_present(dev, "pwms")) { + st->manual_mode = false; + ret = ad4691_pwm_setup(st); + if (ret) + return ret; + } else { + st->manual_mode = true; + } + + switch (st->vref_uV) { + case AD4691_VREF_uV_MIN ... AD4691_VREF_2P5_uV_MAX: + ref_val = AD4691_VREF_2P5; + break; + case AD4691_VREF_2P5_uV_MAX + 1 ... AD4691_VREF_3P0_uV_MAX: + ref_val = AD4691_VREF_3P0; + break; + case AD4691_VREF_3P0_uV_MAX + 1 ... AD4691_VREF_3P3_uV_MAX: + ref_val = AD4691_VREF_3P3; + break; + case AD4691_VREF_3P3_uV_MAX + 1 ... AD4691_VREF_4P096_uV_MAX: + ref_val = AD4691_VREF_4P096; + break; + case AD4691_VREF_4P096_uV_MAX + 1 ... AD4691_VREF_uV_MAX: + ref_val = AD4691_VREF_5P0; + break; + default: + return dev_err_probe(dev, -EINVAL, + "Unsupported vref voltage: %d uV\n", + st->vref_uV); + } + + val = FIELD_PREP(AD4691_REF_CTRL_MASK, ref_val); + if (st->refbuf_en) + val |= AD4691_REFBUF_EN; + + ret = regmap_write(st->regmap, AD4691_REF_CTRL, val); + if (ret) + return dev_err_probe(dev, ret, "Failed to write REF_CTRL\n"); + + ret = regmap_assign_bits(st->regmap, AD4691_DEVICE_SETUP, + AD4691_LDO_EN, st->ldo_en); + if (ret) + return dev_err_probe(dev, ret, "Failed to write DEVICE_SETUP\n"); + + /* + * Set the internal oscillator to the highest rate this chip supports. + * Index 0 (1 MHz) exceeds the 500 kHz max of AD4691/AD4693, so those + * chips start at index 1 (500 kHz). + */ + ret = regmap_write(st->regmap, AD4691_OSC_FREQ_REG, + ad4691_samp_freq_start(st->info)); + if (ret) + return dev_err_probe(dev, ret, "Failed to write OSC_FREQ\n"); + + st->target_osc_freq_Hz = ad4691_osc_freqs_Hz[ad4691_samp_freq_start(st->info)]; + + ret = regmap_update_bits(st->regmap, AD4691_ADC_SETUP, + AD4691_ADC_MODE_MASK, AD4691_AUTONOMOUS_MODE); + if (ret) + return dev_err_probe(dev, ret, "Failed to write ADC_SETUP\n"); + + ad4691_precompute_samp_freq_avail(st); + + return 0; +} + +static int ad4691_setup_triggered_buffer(struct iio_dev *indio_dev, + struct ad4691_state *st) +{ + struct device *dev = regmap_get_device(st->regmap); + struct iio_trigger *trig; + unsigned int i; + int irq, ret; + + /* + * Manual mode exposes channels without the oversampling_ratio attribute + * because ACC_DEPTH_IN is not configured in manual mode. + */ + if (st->manual_mode) + indio_dev->channels = st->info->sw_info->manual_channels; + else + indio_dev->channels = st->info->sw_info->channels; + indio_dev->num_channels = st->info->sw_info->num_channels; + indio_dev->info = st->manual_mode ? &ad4691_manual_info : &ad4691_cnv_burst_info; + + /* + * Manual mode relies on an external trigger (e.g. iio-trig-hrtimer); + * no internal trigger is needed or registered. + */ + if (st->manual_mode) + return devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + ad4691_trigger_handler, + &ad4691_manual_buffer_setup_ops); + + /* + * CNV burst mode: allocate an internal trigger driven by the + * DATA_READY IRQ on the GP pin. + */ + trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, + iio_device_id(indio_dev)); + if (!trig) + return -ENOMEM; + + trig->ops = &ad4691_trigger_ops; + iio_trigger_set_drvdata(trig, st); + + ret = devm_iio_trigger_register(dev, trig); + if (ret) + return dev_err_probe(dev, ret, "IIO trigger register failed\n"); + + indio_dev->trig = iio_trigger_get(trig); + + /* + * The GP pin named in interrupt-names asserts at end-of-conversion. + * The IRQ handler fires the IIO trigger so the trigger handler can + * read and push the sample to the buffer. The IRQ is kept disabled + * until the buffer is enabled. + */ + irq = -ENXIO; + for (i = 0; i < ARRAY_SIZE(ad4691_gp_names); i++) { + irq = fwnode_irq_get_byname(dev_fwnode(dev), + ad4691_gp_names[i]); + if (irq > 0 || irq == -EPROBE_DEFER) + break; + } + if (irq < 0) + return dev_err_probe(dev, irq, "failed to get GP interrupt\n"); + + st->irq = irq; + + ret = ad4691_gpio_setup(st, i); + if (ret) + return ret; + + /* + * The handler only calls disable_irq_nosync() and iio_trigger_poll(), + * both safe in hardirq context, so register as a hard IRQ handler. + * IRQF_NO_AUTOEN keeps it disabled until the buffer is enabled. + */ + ret = devm_request_irq(dev, irq, ad4691_irq, IRQF_NO_AUTOEN, + indio_dev->name, indio_dev); + if (ret) + return ret; + + return devm_iio_triggered_buffer_setup_ext(dev, indio_dev, + iio_pollfunc_store_time, + ad4691_trigger_handler, + IIO_BUFFER_DIRECTION_IN, + &ad4691_cnv_burst_buffer_setup_ops, + ad4691_buffer_attrs); +} + +static int ad4691_setup_offload(struct iio_dev *indio_dev, + struct ad4691_state *st, + struct spi_offload *spi_offload) +{ + struct device *dev = regmap_get_device(st->regmap); + struct dma_chan *rx_dma; + int ret; + + st->offload = spi_offload; + + /* + * CNV burst offload exposes oversampling_ratio (ACC_DEPTH_IN is + * configured per channel at buffer enable). Manual offload does not + * configure ACC_DEPTH_IN, so it uses a separate channel array + * without the oversampling_ratio attribute. Both paths use IIO_CPU + * (no .endianness annotation) because bits_per_word=16 causes the + * SPI Engine to produce native 16-bit DMA words. + */ + if (st->manual_mode) + indio_dev->channels = st->info->offload_info->manual_channels; + else + indio_dev->channels = st->info->offload_info->channels; + indio_dev->num_channels = st->info->offload_info->num_channels; + /* + * Offload path uses DMA directly; no IIO trigger is involved, so + * external triggers are not restricted (no validate_trigger). + */ + indio_dev->info = &ad4691_manual_info; + + if (st->manual_mode) { + st->offload_trigger = + devm_spi_offload_trigger_get(dev, st->offload, + SPI_OFFLOAD_TRIGGER_PERIODIC); + if (IS_ERR(st->offload_trigger)) + return dev_err_probe(dev, PTR_ERR(st->offload_trigger), + "Failed to get periodic offload trigger\n"); + + st->trigger_hz = AD4691_OFFLOAD_INITIAL_TRIGGER_HZ; + } else { + struct spi_offload_trigger_info trigger_info = { + .fwnode = dev_fwnode(dev), + .ops = &ad4691_offload_trigger_ops, + .priv = st, + }; + + ret = devm_spi_offload_trigger_register(dev, &trigger_info); + if (ret) + return dev_err_probe(dev, ret, + "Failed to register offload trigger\n"); + + st->offload_trigger = + devm_spi_offload_trigger_get(dev, st->offload, + SPI_OFFLOAD_TRIGGER_DATA_READY); + if (IS_ERR(st->offload_trigger)) + return dev_err_probe(dev, PTR_ERR(st->offload_trigger), + "Failed to get DATA_READY offload trigger\n"); + } + + rx_dma = devm_spi_offload_rx_stream_request_dma_chan(dev, st->offload); + if (IS_ERR(rx_dma)) + return dev_err_probe(dev, PTR_ERR(rx_dma), + "Failed to get offload RX DMA channel\n"); + + if (st->manual_mode) + indio_dev->setup_ops = &ad4691_manual_offload_buffer_setup_ops; + else + indio_dev->setup_ops = &ad4691_cnv_burst_offload_buffer_setup_ops; + + ret = devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev, rx_dma, + IIO_BUFFER_DIRECTION_IN); + if (ret) + return ret; + + indio_dev->buffer->attrs = ad4691_buffer_attrs; + + return 0; +} + +static int ad4691_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct spi_offload *spi_offload; + struct iio_dev *indio_dev; + struct ad4691_state *st; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->spi = spi; + st->info = spi_get_device_match_data(spi); + if (!st->info) + return -ENODEV; + st->osr = 1; + + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; + + st->regmap = devm_regmap_init(dev, NULL, spi, &ad4691_regmap_config); + if (IS_ERR(st->regmap)) + return dev_err_probe(dev, PTR_ERR(st->regmap), + "Failed to initialize regmap\n"); + + ret = ad4691_regulator_setup(st); + if (ret) + return ret; + + ret = ad4691_reset(st); + if (ret) + return ret; + + ret = ad4691_config(st); + if (ret) + return ret; + + spi_offload = devm_spi_offload_get(dev, spi, &ad4691_offload_config); + ret = PTR_ERR_OR_ZERO(spi_offload); + if (ret == -ENODEV) + spi_offload = NULL; + else if (ret) + return dev_err_probe(dev, ret, "Failed to get SPI offload\n"); + + indio_dev->name = st->info->name; + indio_dev->modes = INDIO_DIRECT_MODE; + + if (spi_offload) + ret = ad4691_setup_offload(indio_dev, st, spi_offload); + else + ret = ad4691_setup_triggered_buffer(indio_dev, st); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id ad4691_of_match[] = { + { .compatible = "adi,ad4691", .data = &ad4691_chip_info }, + { .compatible = "adi,ad4692", .data = &ad4692_chip_info }, + { .compatible = "adi,ad4693", .data = &ad4693_chip_info }, + { .compatible = "adi,ad4694", .data = &ad4694_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, ad4691_of_match); + +static const struct spi_device_id ad4691_id[] = { + { .name = "ad4691", .driver_data = (kernel_ulong_t)&ad4691_chip_info }, + { .name = "ad4692", .driver_data = (kernel_ulong_t)&ad4692_chip_info }, + { .name = "ad4693", .driver_data = (kernel_ulong_t)&ad4693_chip_info }, + { .name = "ad4694", .driver_data = (kernel_ulong_t)&ad4694_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(spi, ad4691_id); + +static struct spi_driver ad4691_driver = { + .driver = { + .name = "ad4691", + .of_match_table = ad4691_of_match, + }, + .probe = ad4691_probe, + .id_table = ad4691_id, +}; +module_spi_driver(ad4691_driver); + +MODULE_AUTHOR("Radu Sabau <radu.sabau@analog.com>"); +MODULE_DESCRIPTION("Analog Devices AD4691 Family ADC Driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_DMA_BUFFER"); +MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER"); diff --git a/drivers/iio/adc/ad4695.c b/drivers/iio/adc/ad4695.c index cda419638d9a..53642de7330d 100644 --- a/drivers/iio/adc/ad4695.c +++ b/drivers/iio/adc/ad4695.c @@ -876,14 +876,14 @@ static int ad4695_offload_buffer_postenable(struct iio_dev *indio_dev) if (ret) goto err_unoptimize_message; - ret = spi_offload_trigger_enable(st->offload, st->offload_trigger, - &config); + ret = ad4695_enter_advanced_sequencer_mode(st, num_slots); if (ret) goto err_disable_busy_output; - ret = ad4695_enter_advanced_sequencer_mode(st, num_slots); + ret = spi_offload_trigger_enable(st->offload, st->offload_trigger, + &config); if (ret) - goto err_offload_trigger_disable; + goto err_exit_conversion_mode; mutex_lock(&st->cnv_pwm_lock); pwm_get_state(st->cnv_pwm, &state); @@ -895,23 +895,16 @@ static int ad4695_offload_buffer_postenable(struct iio_dev *indio_dev) ret = pwm_apply_might_sleep(st->cnv_pwm, &state); mutex_unlock(&st->cnv_pwm_lock); if (ret) - goto err_offload_exit_conversion_mode; + goto err_offload_trigger_disable; return 0; -err_offload_exit_conversion_mode: - /* - * We have to unwind in a different order to avoid triggering offload. - * ad4695_exit_conversion_mode() triggers a conversion, so it has to be - * done after spi_offload_trigger_disable(). - */ - spi_offload_trigger_disable(st->offload, st->offload_trigger); - ad4695_exit_conversion_mode(st); - goto err_disable_busy_output; - err_offload_trigger_disable: spi_offload_trigger_disable(st->offload, st->offload_trigger); +err_exit_conversion_mode: + ad4695_exit_conversion_mode(st); + err_disable_busy_output: regmap_clear_bits(st->regmap, AD4695_REG_GP_MODE, AD4695_REG_GP_MODE_BUSY_GP_EN); diff --git a/drivers/iio/adc/ad4851.c b/drivers/iio/adc/ad4851.c index 1ad77f2a4580..480d1798f17b 100644 --- a/drivers/iio/adc/ad4851.c +++ b/drivers/iio/adc/ad4851.c @@ -12,7 +12,6 @@ #include <linux/device.h> #include <linux/err.h> #include <linux/minmax.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/pwm.h> @@ -1286,15 +1285,15 @@ static const struct of_device_id ad4851_of_match[] = { }; static const struct spi_device_id ad4851_spi_id[] = { - { "ad4851", (kernel_ulong_t)&ad4851_info }, - { "ad4852", (kernel_ulong_t)&ad4852_info }, - { "ad4853", (kernel_ulong_t)&ad4853_info }, - { "ad4854", (kernel_ulong_t)&ad4854_info }, - { "ad4855", (kernel_ulong_t)&ad4855_info }, - { "ad4856", (kernel_ulong_t)&ad4856_info }, - { "ad4857", (kernel_ulong_t)&ad4857_info }, - { "ad4858", (kernel_ulong_t)&ad4858_info }, - { "ad4858i", (kernel_ulong_t)&ad4858i_info }, + { .name = "ad4851", .driver_data = (kernel_ulong_t)&ad4851_info }, + { .name = "ad4852", .driver_data = (kernel_ulong_t)&ad4852_info }, + { .name = "ad4853", .driver_data = (kernel_ulong_t)&ad4853_info }, + { .name = "ad4854", .driver_data = (kernel_ulong_t)&ad4854_info }, + { .name = "ad4855", .driver_data = (kernel_ulong_t)&ad4855_info }, + { .name = "ad4856", .driver_data = (kernel_ulong_t)&ad4856_info }, + { .name = "ad4857", .driver_data = (kernel_ulong_t)&ad4857_info }, + { .name = "ad4858", .driver_data = (kernel_ulong_t)&ad4858_info }, + { .name = "ad4858i", .driver_data = (kernel_ulong_t)&ad4858i_info }, { } }; MODULE_DEVICE_TABLE(spi, ad4851_spi_id); diff --git a/drivers/iio/adc/ad7091r5.c b/drivers/iio/adc/ad7091r5.c index bd4877268689..7bf7d538abd9 100644 --- a/drivers/iio/adc/ad7091r5.c +++ b/drivers/iio/adc/ad7091r5.c @@ -101,23 +101,17 @@ static const struct ad7091r_init_info ad7091r5_init_info = { static int ad7091r5_i2c_probe(struct i2c_client *i2c) { - const struct ad7091r_init_info *init_info; - - init_info = i2c_get_match_data(i2c); - if (!init_info) - return -EINVAL; - - return ad7091r_probe(&i2c->dev, init_info, i2c->irq); + return ad7091r_probe(&i2c->dev, &ad7091r5_init_info, i2c->irq); } static const struct of_device_id ad7091r5_dt_ids[] = { - { .compatible = "adi,ad7091r5", .data = &ad7091r5_init_info }, + { .compatible = "adi,ad7091r5" }, { } }; MODULE_DEVICE_TABLE(of, ad7091r5_dt_ids); static const struct i2c_device_id ad7091r5_i2c_ids[] = { - { "ad7091r5", (kernel_ulong_t)&ad7091r5_init_info }, + { .name = "ad7091r5" }, { } }; MODULE_DEVICE_TABLE(i2c, ad7091r5_i2c_ids); diff --git a/drivers/iio/adc/ad7091r8.c b/drivers/iio/adc/ad7091r8.c index e93b8bb60e8e..465a8ba01a22 100644 --- a/drivers/iio/adc/ad7091r8.c +++ b/drivers/iio/adc/ad7091r8.c @@ -249,9 +249,9 @@ static const struct of_device_id ad7091r8_of_match[] = { MODULE_DEVICE_TABLE(of, ad7091r8_of_match); static const struct spi_device_id ad7091r8_spi_id[] = { - { "ad7091r2", (kernel_ulong_t)&ad7091r2_init_info }, - { "ad7091r4", (kernel_ulong_t)&ad7091r4_init_info }, - { "ad7091r8", (kernel_ulong_t)&ad7091r8_init_info }, + { .name = "ad7091r2", .driver_data = (kernel_ulong_t)&ad7091r2_init_info }, + { .name = "ad7091r4", .driver_data = (kernel_ulong_t)&ad7091r4_init_info }, + { .name = "ad7091r8", .driver_data = (kernel_ulong_t)&ad7091r8_init_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7091r8_spi_id); diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index 5c1a8f886bcc..fc5dbc624856 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -19,7 +19,6 @@ #include <linux/kfifo.h> #include <linux/minmax.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> @@ -1684,8 +1683,8 @@ static const struct of_device_id ad7124_of_match[] = { MODULE_DEVICE_TABLE(of, ad7124_of_match); static const struct spi_device_id ad71124_ids[] = { - { "ad7124-4", (kernel_ulong_t)&ad7124_4_chip_info }, - { "ad7124-8", (kernel_ulong_t)&ad7124_8_chip_info }, + { .name = "ad7124-4", .driver_data = (kernel_ulong_t)&ad7124_4_chip_info }, + { .name = "ad7124-8", .driver_data = (kernel_ulong_t)&ad7124_8_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad71124_ids); diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index d36612352b44..eb47175a0528 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -26,7 +26,6 @@ #include <linux/interrupt.h> #include <linux/math64.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> @@ -561,8 +560,8 @@ out: return ret; } -static int ad7173_mask_xlate(struct gpio_regmap *gpio, unsigned int base, - unsigned int offset, unsigned int *reg, +static int ad7173_mask_xlate(struct gpio_regmap *gpio, enum gpio_regmap_operation op, + unsigned int base, unsigned int offset, unsigned int *reg, unsigned int *mask) { *mask = AD7173_GPO_DATA(offset); @@ -570,8 +569,8 @@ static int ad7173_mask_xlate(struct gpio_regmap *gpio, unsigned int base, return 0; } -static int ad4111_mask_xlate(struct gpio_regmap *gpio, unsigned int base, - unsigned int offset, unsigned int *reg, +static int ad4111_mask_xlate(struct gpio_regmap *gpio, enum gpio_regmap_operation op, + unsigned int base, unsigned int offset, unsigned int *reg, unsigned int *mask) { *mask = AD4111_GPO01_DATA(offset); @@ -1763,7 +1762,8 @@ static int ad7173_validate_openwire_ain_inputs(struct ad7173_state *st, static unsigned int ad7173_calc_openwire_thrsh_raw(struct ad7173_state *st, struct iio_chan_spec *chan, struct ad7173_channel *chan_st_priv, - unsigned int thrsh_mv) { + unsigned int thrsh_mv) +{ unsigned int thrsh_raw; thrsh_raw = @@ -2065,19 +2065,19 @@ static const struct of_device_id ad7173_of_match[] = { MODULE_DEVICE_TABLE(of, ad7173_of_match); static const struct spi_device_id ad7173_id_table[] = { - { "ad4111", (kernel_ulong_t)&ad4111_device_info }, - { "ad4112", (kernel_ulong_t)&ad4112_device_info }, - { "ad4113", (kernel_ulong_t)&ad4113_device_info }, - { "ad4114", (kernel_ulong_t)&ad4114_device_info }, - { "ad4115", (kernel_ulong_t)&ad4115_device_info }, - { "ad4116", (kernel_ulong_t)&ad4116_device_info }, - { "ad7172-2", (kernel_ulong_t)&ad7172_2_device_info }, - { "ad7172-4", (kernel_ulong_t)&ad7172_4_device_info }, - { "ad7173-8", (kernel_ulong_t)&ad7173_8_device_info }, - { "ad7175-2", (kernel_ulong_t)&ad7175_2_device_info }, - { "ad7175-8", (kernel_ulong_t)&ad7175_8_device_info }, - { "ad7176-2", (kernel_ulong_t)&ad7176_2_device_info }, - { "ad7177-2", (kernel_ulong_t)&ad7177_2_device_info }, + { .name = "ad4111", .driver_data = (kernel_ulong_t)&ad4111_device_info }, + { .name = "ad4112", .driver_data = (kernel_ulong_t)&ad4112_device_info }, + { .name = "ad4113", .driver_data = (kernel_ulong_t)&ad4113_device_info }, + { .name = "ad4114", .driver_data = (kernel_ulong_t)&ad4114_device_info }, + { .name = "ad4115", .driver_data = (kernel_ulong_t)&ad4115_device_info }, + { .name = "ad4116", .driver_data = (kernel_ulong_t)&ad4116_device_info }, + { .name = "ad7172-2", .driver_data = (kernel_ulong_t)&ad7172_2_device_info }, + { .name = "ad7172-4", .driver_data = (kernel_ulong_t)&ad7172_4_device_info }, + { .name = "ad7173-8", .driver_data = (kernel_ulong_t)&ad7173_8_device_info }, + { .name = "ad7175-2", .driver_data = (kernel_ulong_t)&ad7175_2_device_info }, + { .name = "ad7175-8", .driver_data = (kernel_ulong_t)&ad7175_8_device_info }, + { .name = "ad7176-2", .driver_data = (kernel_ulong_t)&ad7176_2_device_info }, + { .name = "ad7177-2", .driver_data = (kernel_ulong_t)&ad7177_2_device_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7173_id_table); diff --git a/drivers/iio/adc/ad7191.c b/drivers/iio/adc/ad7191.c index d9cd903ffdd2..071d26191b3c 100644 --- a/drivers/iio/adc/ad7191.c +++ b/drivers/iio/adc/ad7191.c @@ -11,7 +11,6 @@ #include <linux/err.h> #include <linux/gpio/consumer.h> #include <linux/interrupt.h> -#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/property.h> #include <linux/regulator/consumer.h> @@ -154,27 +153,18 @@ static int ad7191_config_setup(struct iio_dev *indio_dev) const u32 gain[4] = { 1, 8, 64, 128 }; static u32 scale_buffer[4][2]; int odr_value, odr_index = 0, pga_value, pga_index = 0, i, ret; + const char *propname; u64 scale_uv; st->samp_freq_index = 0; st->scale_index = 0; - ret = device_property_read_u32(dev, "adi,odr-value", &odr_value); - if (ret && ret != -EINVAL) - return dev_err_probe(dev, ret, "Failed to get odr value.\n"); + propname = "adi,odr-value"; + if (device_property_present(dev, propname)) { + ret = device_property_read_u32(dev, propname, &odr_value); + if (ret) + return dev_err_probe(dev, ret, "Failed to get %s.\n", propname); - if (ret == -EINVAL) { - st->odr_gpios = devm_gpiod_get_array(dev, "odr", GPIOD_OUT_LOW); - if (IS_ERR(st->odr_gpios)) - return dev_err_probe(dev, PTR_ERR(st->odr_gpios), - "Failed to get odr gpios.\n"); - - if (st->odr_gpios->ndescs != 2) - return dev_err_probe(dev, -EINVAL, "Expected 2 odr gpio pins.\n"); - - st->samp_freq_avail = samp_freq; - st->samp_freq_avail_size = ARRAY_SIZE(samp_freq); - } else { for (i = 0; i < ARRAY_SIZE(samp_freq); i++) { if (odr_value != samp_freq[i]) continue; @@ -186,6 +176,17 @@ static int ad7191_config_setup(struct iio_dev *indio_dev) st->samp_freq_avail_size = 1; st->odr_gpios = NULL; + } else { + st->odr_gpios = devm_gpiod_get_array(dev, "odr", GPIOD_OUT_LOW); + if (IS_ERR(st->odr_gpios)) + return dev_err_probe(dev, PTR_ERR(st->odr_gpios), + "Failed to get odr gpios.\n"); + + if (st->odr_gpios->ndescs != 2) + return dev_err_probe(dev, -EINVAL, "Expected 2 odr gpio pins.\n"); + + st->samp_freq_avail = samp_freq; + st->samp_freq_avail_size = ARRAY_SIZE(samp_freq); } mutex_lock(&st->lock); @@ -200,22 +201,12 @@ static int ad7191_config_setup(struct iio_dev *indio_dev) mutex_unlock(&st->lock); - ret = device_property_read_u32(dev, "adi,pga-value", &pga_value); - if (ret && ret != -EINVAL) - return dev_err_probe(dev, ret, "Failed to get pga value.\n"); + propname = "adi,pga-value"; + if (device_property_present(dev, propname)) { + ret = device_property_read_u32(dev, propname, &pga_value); + if (ret) + return dev_err_probe(dev, ret, "Failed to get %s.\n", propname); - if (ret == -EINVAL) { - st->pga_gpios = devm_gpiod_get_array(dev, "pga", GPIOD_OUT_LOW); - if (IS_ERR(st->pga_gpios)) - return dev_err_probe(dev, PTR_ERR(st->pga_gpios), - "Failed to get pga gpios.\n"); - - if (st->pga_gpios->ndescs != 2) - return dev_err_probe(dev, -EINVAL, "Expected 2 pga gpio pins.\n"); - - st->scale_avail = scale_buffer; - st->scale_avail_size = ARRAY_SIZE(scale_buffer); - } else { for (i = 0; i < ARRAY_SIZE(gain); i++) { if (pga_value != gain[i]) continue; @@ -227,6 +218,17 @@ static int ad7191_config_setup(struct iio_dev *indio_dev) st->scale_avail_size = 1; st->pga_gpios = NULL; + } else { + st->pga_gpios = devm_gpiod_get_array(dev, "pga", GPIOD_OUT_LOW); + if (IS_ERR(st->pga_gpios)) + return dev_err_probe(dev, PTR_ERR(st->pga_gpios), + "Failed to get pga gpios.\n"); + + if (st->pga_gpios->ndescs != 2) + return dev_err_probe(dev, -EINVAL, "Expected 2 pga gpio pins.\n"); + + st->scale_avail = scale_buffer; + st->scale_avail_size = ARRAY_SIZE(scale_buffer); } st->temp_gpio = devm_gpiod_get(dev, "temp", GPIOD_OUT_LOW); @@ -533,7 +535,7 @@ static const struct of_device_id ad7191_of_match[] = { MODULE_DEVICE_TABLE(of, ad7191_of_match); static const struct spi_device_id ad7191_id_table[] = { - { "ad7191" }, + { .name = "ad7191" }, { } }; MODULE_DEVICE_TABLE(spi, ad7191_id_table); diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index 530e1d307860..d8f5886fcf69 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -20,7 +20,6 @@ #include <linux/sched.h> #include <linux/delay.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/units.h> @@ -39,7 +38,7 @@ #define AD7192_REG_CONF 2 /* Configuration Register (RW, 24-bit) */ #define AD7192_REG_DATA 3 /* Data Register (RO, 24/32-bit) */ #define AD7192_REG_ID 4 /* ID Register (RO, 8-bit) */ -#define AD7192_REG_GPOCON 5 /* GPOCON Register (RO, 8-bit) */ +#define AD7192_REG_GPOCON 5 /* GPOCON Register (RW, 8-bit) */ #define AD7192_REG_OFFSET 6 /* Offset Register (RW, 16-bit */ /* (AD7792)/24-bit (AD7192)) */ #define AD7192_REG_FULLSALE 7 /* Full-Scale Register */ @@ -576,7 +575,12 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device *dev) ret = ad_sd_reset(&st->sd); if (ret < 0) return ret; - usleep_range(500, 1000); /* Wait for at least 500us */ + + /* + * Per AD7192 datasheet (Rev. A, page 34, RESET section), allow + * 500 us after a reset before accessing on-chip registers. + */ + fsleep(500); /* write/read test for device presence */ ret = ad_sd_read_reg(&st->sd, AD7192_REG_ID, 1, &id); @@ -1402,9 +1406,6 @@ static int ad7192_probe(struct spi_device *spi) st->int_vref_mv = ret == -ENODEV ? avdd_mv : ret / MILLI; st->chip_info = spi_get_device_match_data(spi); - if (!st->chip_info) - return -ENODEV; - indio_dev->name = st->chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = st->chip_info->info; @@ -1447,11 +1448,11 @@ static const struct of_device_id ad7192_of_match[] = { MODULE_DEVICE_TABLE(of, ad7192_of_match); static const struct spi_device_id ad7192_ids[] = { - { "ad7190", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7190] }, - { "ad7192", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7192] }, - { "ad7193", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7193] }, - { "ad7194", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7194] }, - { "ad7195", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7195] }, + { .name = "ad7190", .driver_data = (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7190] }, + { .name = "ad7192", .driver_data = (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7192] }, + { .name = "ad7193", .driver_data = (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7193] }, + { .name = "ad7194", .driver_data = (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7194] }, + { .name = "ad7195", .driver_data = (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7195] }, { } }; MODULE_DEVICE_TABLE(spi, ad7192_ids); diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c index 3364ac6c4631..594a070c3745 100644 --- a/drivers/iio/adc/ad7266.c +++ b/drivers/iio/adc/ad7266.c @@ -409,10 +409,8 @@ static int ad7266_probe(struct spi_device *spi) st->gpios[i] = devm_gpiod_get(&spi->dev, ad7266_gpio_labels[i], GPIOD_OUT_LOW); - if (IS_ERR(st->gpios[i])) { - ret = PTR_ERR(st->gpios[i]); - return ret; - } + if (IS_ERR(st->gpios[i])) + return PTR_ERR(st->gpios[i]); } } } else { @@ -455,8 +453,8 @@ static int ad7266_probe(struct spi_device *spi) } static const struct spi_device_id ad7266_id[] = { - { "ad7265", 0 }, - { "ad7266", 0 }, + { .name = "ad7265" }, + { .name = "ad7266" }, { } }; MODULE_DEVICE_TABLE(spi, ad7266_id); diff --git a/drivers/iio/adc/ad7280a.c b/drivers/iio/adc/ad7280a.c index ba12a3796e2b..5ae0d694d20c 100644 --- a/drivers/iio/adc/ad7280a.c +++ b/drivers/iio/adc/ad7280a.c @@ -15,7 +15,6 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/sysfs.h> @@ -496,7 +495,8 @@ static ssize_t ad7280_store_balance_sw(struct iio_dev *indio_dev, devaddr = chan->address >> 8; ch = chan->address & 0xFF; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); + if (readin) st->cb_mask[devaddr] |= BIT(ch); else @@ -505,7 +505,6 @@ static ssize_t ad7280_store_balance_sw(struct iio_dev *indio_dev, ret = ad7280_write(st, devaddr, AD7280A_CELL_BALANCE_REG, 0, FIELD_PREP(AD7280A_CELL_BALANCE_CHAN_BITMAP_MSK, st->cb_mask[devaddr])); - mutex_unlock(&st->lock); return ret ? ret : len; } @@ -516,14 +515,13 @@ static ssize_t ad7280_show_balance_timer(struct iio_dev *indio_dev, char *buf) { struct ad7280_state *st = iio_priv(indio_dev); + u8 devaddr = chan->address >> 8; + u8 ch = chan->address & 0xFF; unsigned int msecs; int ret; - mutex_lock(&st->lock); - ret = ad7280_read_reg(st, chan->address >> 8, - (chan->address & 0xFF) + AD7280A_CB1_TIMER_REG); - mutex_unlock(&st->lock); - + scoped_guard(mutex, &st->lock) + ret = ad7280_read_reg(st, devaddr, ch + AD7280A_CB1_TIMER_REG); if (ret < 0) return ret; @@ -538,6 +536,8 @@ static ssize_t ad7280_store_balance_timer(struct iio_dev *indio_dev, const char *buf, size_t len) { struct ad7280_state *st = iio_priv(indio_dev); + u8 devaddr = chan->address >> 8; + u8 ch = chan->address & 0xFF; int val, val2; int ret; @@ -551,11 +551,10 @@ static ssize_t ad7280_store_balance_timer(struct iio_dev *indio_dev, if (val > 31) return -EINVAL; - mutex_lock(&st->lock); - ret = ad7280_write(st, chan->address >> 8, - (chan->address & 0xFF) + AD7280A_CB1_TIMER_REG, 0, + guard(mutex)(&st->lock); + + ret = ad7280_write(st, devaddr, ch + AD7280A_CB1_TIMER_REG, 0, FIELD_PREP(AD7280A_CB_TIMER_VAL_MSK, val)); - mutex_unlock(&st->lock); return ret ? ret : len; } @@ -737,7 +736,8 @@ static int ad7280a_write_thresh(struct iio_dev *indio_dev, if (val2 != 0) return -EINVAL; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); + switch (chan->type) { case IIO_VOLTAGE: value = ((val - 1000) * 100) / 1568; /* LSB 15.68mV */ @@ -748,22 +748,20 @@ static int ad7280a_write_thresh(struct iio_dev *indio_dev, ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, 1, value); if (ret) - break; + return ret; st->cell_threshhigh = value; - break; + return 0; case IIO_EV_DIR_FALLING: addr = AD7280A_CELL_UNDERVOLTAGE_REG; ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, 1, value); if (ret) - break; + return ret; st->cell_threshlow = value; - break; + return 0; default: - ret = -EINVAL; - goto err_unlock; + return -EINVAL; } - break; case IIO_TEMP: value = (val * 10) / 196; /* LSB 19.6mV */ value = clamp(value, 0L, 0xFFL); @@ -773,31 +771,23 @@ static int ad7280a_write_thresh(struct iio_dev *indio_dev, ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, 1, value); if (ret) - break; + return ret; st->aux_threshhigh = value; - break; + return 0; case IIO_EV_DIR_FALLING: addr = AD7280A_AUX_ADC_UNDERVOLTAGE_REG; ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, 1, value); if (ret) - break; + return ret; st->aux_threshlow = value; - break; + return 0; default: - ret = -EINVAL; - goto err_unlock; + return -EINVAL; } - break; default: - ret = -EINVAL; - goto err_unlock; + return -EINVAL; } - -err_unlock: - mutex_unlock(&st->lock); - - return ret; } static irqreturn_t ad7280_event_handler(int irq, void *private) @@ -806,8 +796,8 @@ static irqreturn_t ad7280_event_handler(int irq, void *private) struct ad7280_state *st = iio_priv(indio_dev); int i, ret; - unsigned int *channels __free(kfree) = kcalloc(st->scan_cnt, sizeof(*channels), - GFP_KERNEL); + unsigned int *channels __free(kfree) = kzalloc_objs(*channels, + st->scan_cnt); if (!channels) return IRQ_HANDLED; @@ -881,17 +871,18 @@ static int ad7280_read_raw(struct iio_dev *indio_dev, long m) { struct ad7280_state *st = iio_priv(indio_dev); + u8 devaddr = chan->address >> 8; + u8 ch = chan->address & 0xFF; int ret; switch (m) { - case IIO_CHAN_INFO_RAW: - mutex_lock(&st->lock); + case IIO_CHAN_INFO_RAW: { + guard(mutex)(&st->lock); + if (chan->address == AD7280A_ALL_CELLS) ret = ad7280_read_all_channels(st, st->scan_cnt, NULL); else - ret = ad7280_read_channel(st, chan->address >> 8, - chan->address & 0xFF); - mutex_unlock(&st->lock); + ret = ad7280_read_channel(st, devaddr, ch); if (ret < 0) return ret; @@ -899,8 +890,9 @@ static int ad7280_read_raw(struct iio_dev *indio_dev, *val = ret; return IIO_VAL_INT; + } case IIO_CHAN_INFO_SCALE: - if ((chan->address & 0xFF) <= AD7280A_CELL_VOLTAGE_6_REG) + if (ch <= AD7280A_CELL_VOLTAGE_6_REG) *val = 4000; else *val = 5000; @@ -990,8 +982,8 @@ static int ad7280_probe(struct spi_device *spi) st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_1600ns; break; default: - dev_err(dev, "Firmware provided acquisition time is invalid\n"); - return -EINVAL; + return dev_err_probe(dev, -EINVAL, + "Firmware provided acquisition time is invalid\n"); } } else { st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_400ns; @@ -1090,7 +1082,7 @@ static int ad7280_probe(struct spi_device *spi) } static const struct spi_device_id ad7280_id[] = { - { "ad7280a", 0 }, + { .name = "ad7280a" }, { } }; MODULE_DEVICE_TABLE(spi, ad7280_id); diff --git a/drivers/iio/adc/ad7291.c b/drivers/iio/adc/ad7291.c index 60e12faa3207..6a1493e27a30 100644 --- a/drivers/iio/adc/ad7291.c +++ b/drivers/iio/adc/ad7291.c @@ -536,7 +536,7 @@ static int ad7291_probe(struct i2c_client *client) } static const struct i2c_device_id ad7291_id[] = { - { "ad7291" }, + { .name = "ad7291" }, { } }; diff --git a/drivers/iio/adc/ad7292.c b/drivers/iio/adc/ad7292.c index a398973f313d..1d7bf46b80e2 100644 --- a/drivers/iio/adc/ad7292.c +++ b/drivers/iio/adc/ad7292.c @@ -8,7 +8,6 @@ #include <linux/bitfield.h> #include <linux/device.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> @@ -253,12 +252,13 @@ static const struct iio_info ad7292_info = { static int ad7292_probe(struct spi_device *spi) { + struct device *dev = &spi->dev; struct ad7292_state *st; struct iio_dev *indio_dev; bool diff_channels = false; int ret; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; @@ -266,12 +266,11 @@ static int ad7292_probe(struct spi_device *spi) st->spi = spi; ret = ad7292_spi_reg_read(st, AD7292_REG_VENDOR_ID); - if (ret != ADI_VENDOR_ID) { - dev_err(&spi->dev, "Wrong vendor id 0x%x\n", ret); - return -EINVAL; - } + if (ret != ADI_VENDOR_ID) + return dev_err_probe(dev, -EINVAL, + "Wrong vendor id 0x%x\n", ret); - ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref"); + ret = devm_regulator_get_enable_read_voltage(dev, "vref"); if (ret < 0 && ret != -ENODEV) return ret; @@ -281,7 +280,7 @@ static int ad7292_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &ad7292_info; - device_for_each_child_node_scoped(&spi->dev, child) { + device_for_each_child_node_scoped(dev, child) { diff_channels = fwnode_property_read_bool(child, "diff-channels"); if (diff_channels) @@ -296,11 +295,11 @@ static int ad7292_probe(struct spi_device *spi) indio_dev->channels = ad7292_channels; } - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct spi_device_id ad7292_id_table[] = { - { "ad7292", 0 }, + { .name = "ad7292" }, { } }; MODULE_DEVICE_TABLE(spi, ad7292_id_table); diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c index 7c0538ea15c8..c669022b5dec 100644 --- a/drivers/iio/adc/ad7298.c +++ b/drivers/iio/adc/ad7298.c @@ -13,7 +13,6 @@ #include <linux/regulator/consumer.h> #include <linux/err.h> #include <linux/delay.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/bitops.h> @@ -354,7 +353,7 @@ static const struct acpi_device_id ad7298_acpi_ids[] = { MODULE_DEVICE_TABLE(acpi, ad7298_acpi_ids); static const struct spi_device_id ad7298_id[] = { - { "ad7298", 0 }, + { .name = "ad7298" }, { } }; MODULE_DEVICE_TABLE(spi, ad7298_id); diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c index bfd908deefc0..2e90f125a797 100644 --- a/drivers/iio/adc/ad7380.c +++ b/drivers/iio/adc/ad7380.c @@ -77,8 +77,7 @@ #define AD7380_CONFIG1_REFSEL BIT(1) #define AD7380_CONFIG1_PMODE BIT(0) -#define AD7380_CONFIG2_SDO2 GENMASK(9, 8) -#define AD7380_CONFIG2_SDO BIT(8) +#define AD7380_CONFIG2_SDO GENMASK(9, 8) #define AD7380_CONFIG2_RESET GENMASK(7, 0) #define AD7380_CONFIG2_RESET_SOFT 0x3C @@ -92,11 +91,6 @@ #define T_CONVERT_X_NS 500 /* xth conversion start time (oversampling) */ #define T_POWERUP_US 5000 /* Power up */ -/* - * AD738x support several SDO lines to increase throughput, but driver currently - * supports only 1 SDO line (standard SPI transaction) - */ -#define AD7380_NUM_SDO_LINES 1 #define AD7380_DEFAULT_GAIN_MILLI 1000 /* @@ -888,6 +882,8 @@ struct ad7380_state { bool resolution_boost_enabled; unsigned int ch; bool seq; + /* How many SDO lines are wired up. */ + u8 num_sdo_lines; unsigned int vref_mv; unsigned int vcm_mv[MAX_NUM_CHANNELS]; unsigned int gain_milli[MAX_NUM_CHANNELS]; @@ -1084,7 +1080,7 @@ static int ad7380_set_ch(struct ad7380_state *st, unsigned int ch) if (oversampling_ratio > 1) xfer.delay.value = T_CONVERT_0_NS + T_CONVERT_X_NS * (oversampling_ratio - 1) * - st->chip_info->num_simult_channels / AD7380_NUM_SDO_LINES; + st->chip_info->num_simult_channels / st->num_sdo_lines; return spi_sync_transfer(st->spi, &xfer, 1); } @@ -1113,7 +1109,7 @@ static int ad7380_update_xfers(struct ad7380_state *st, if (oversampling_ratio > 1) t_convert = T_CONVERT_0_NS + T_CONVERT_X_NS * (oversampling_ratio - 1) * - st->chip_info->num_simult_channels / AD7380_NUM_SDO_LINES; + st->chip_info->num_simult_channels / st->num_sdo_lines; if (st->seq) { xfer[0].delay.value = xfer[1].delay.value = t_convert; @@ -1198,6 +1194,8 @@ static int ad7380_init_offload_msg(struct ad7380_state *st, xfer->bits_per_word = scan_type->realbits; xfer->offload_flags = SPI_OFFLOAD_XFER_RX_STREAM; xfer->len = AD7380_SPI_BYTES(scan_type) * st->chip_info->num_simult_channels; + if (st->num_sdo_lines > 1) + xfer->multi_lane_mode = SPI_MULTI_LANE_MODE_STRIPE; spi_message_init_with_transfers(&st->offload_msg, xfer, 1); st->offload_msg.offload = st->offload; @@ -1793,6 +1791,7 @@ static const struct iio_info ad7380_info = { static int ad7380_init(struct ad7380_state *st, bool external_ref_en) { + u32 sdo; int ret; /* perform hard reset */ @@ -1815,11 +1814,24 @@ static int ad7380_init(struct ad7380_state *st, bool external_ref_en) st->ch = 0; st->seq = false; - /* SPI 1-wire mode */ + /* SDO field has an irregular mapping. */ + switch (st->num_sdo_lines) { + case 1: + sdo = 1; + break; + case 2: + sdo = 0; + break; + case 4: + sdo = 2; + break; + default: + return -EINVAL; + } + return regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG2, AD7380_CONFIG2_SDO, - FIELD_PREP(AD7380_CONFIG2_SDO, - AD7380_NUM_SDO_LINES)); + FIELD_PREP(AD7380_CONFIG2_SDO, sdo)); } static int ad7380_probe_spi_offload(struct iio_dev *indio_dev, @@ -1842,7 +1854,7 @@ static int ad7380_probe_spi_offload(struct iio_dev *indio_dev, "failed to get offload trigger\n"); sample_rate = st->chip_info->max_conversion_rate_hz * - AD7380_NUM_SDO_LINES / st->chip_info->num_simult_channels; + st->num_sdo_lines / st->chip_info->num_simult_channels; st->sample_freq_range[0] = 1; /* min */ st->sample_freq_range[1] = 1; /* step */ @@ -1850,7 +1862,7 @@ static int ad7380_probe_spi_offload(struct iio_dev *indio_dev, /* * Starting with a quite low frequency, to allow oversampling x32, - * user is then reponsible to adjust the frequency for the specific case. + * user is then responsible to adjust the frequency for the specific case. */ ret = ad7380_set_sample_freq(st, sample_rate / 32); if (ret) @@ -1887,6 +1899,13 @@ static int ad7380_probe(struct spi_device *spi) if (!st->chip_info) return dev_err_probe(dev, -EINVAL, "missing match data\n"); + st->num_sdo_lines = spi->num_rx_lanes; + + if (st->num_sdo_lines < 1 || st->num_sdo_lines > st->chip_info->num_simult_channels) + return dev_err_probe(dev, -EINVAL, + "invalid number of SDO lines (%d)\n", + st->num_sdo_lines); + ret = devm_regulator_bulk_get_enable(dev, st->chip_info->num_supplies, st->chip_info->supplies); @@ -2010,6 +2029,8 @@ static int ad7380_probe(struct spi_device *spi) st->normal_xfer[0].cs_change_delay.value = st->chip_info->timing_specs->t_csh_ns; st->normal_xfer[0].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; st->normal_xfer[1].rx_buf = st->scan_data; + if (st->num_sdo_lines > 1) + st->normal_xfer[1].multi_lane_mode = SPI_MULTI_LANE_MODE_STRIPE; spi_message_init_with_transfers(&st->normal_msg, st->normal_xfer, ARRAY_SIZE(st->normal_xfer)); @@ -2031,6 +2052,10 @@ static int ad7380_probe(struct spi_device *spi) st->seq_xfer[2].cs_change = 1; st->seq_xfer[2].cs_change_delay.value = st->chip_info->timing_specs->t_csh_ns; st->seq_xfer[2].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; + if (st->num_sdo_lines > 1) { + st->seq_xfer[2].multi_lane_mode = SPI_MULTI_LANE_MODE_STRIPE; + st->seq_xfer[3].multi_lane_mode = SPI_MULTI_LANE_MODE_STRIPE; + } spi_message_init_with_transfers(&st->seq_msg, st->seq_xfer, ARRAY_SIZE(st->seq_xfer)); @@ -2091,24 +2116,24 @@ static const struct of_device_id ad7380_of_match_table[] = { }; static const struct spi_device_id ad7380_id_table[] = { - { "ad7380", (kernel_ulong_t)&ad7380_chip_info }, - { "ad7381", (kernel_ulong_t)&ad7381_chip_info }, - { "ad7383", (kernel_ulong_t)&ad7383_chip_info }, - { "ad7384", (kernel_ulong_t)&ad7384_chip_info }, - { "ad7386", (kernel_ulong_t)&ad7386_chip_info }, - { "ad7387", (kernel_ulong_t)&ad7387_chip_info }, - { "ad7388", (kernel_ulong_t)&ad7388_chip_info }, - { "ad7380-4", (kernel_ulong_t)&ad7380_4_chip_info }, - { "ad7381-4", (kernel_ulong_t)&ad7381_4_chip_info }, - { "ad7383-4", (kernel_ulong_t)&ad7383_4_chip_info }, - { "ad7384-4", (kernel_ulong_t)&ad7384_4_chip_info }, - { "ad7386-4", (kernel_ulong_t)&ad7386_4_chip_info }, - { "ad7387-4", (kernel_ulong_t)&ad7387_4_chip_info }, - { "ad7388-4", (kernel_ulong_t)&ad7388_4_chip_info }, - { "ad7389-4", (kernel_ulong_t)&ad7389_4_chip_info }, - { "adaq4370-4", (kernel_ulong_t)&adaq4370_4_chip_info }, - { "adaq4380-4", (kernel_ulong_t)&adaq4380_4_chip_info }, - { "adaq4381-4", (kernel_ulong_t)&adaq4381_4_chip_info }, + { .name = "ad7380", .driver_data = (kernel_ulong_t)&ad7380_chip_info }, + { .name = "ad7381", .driver_data = (kernel_ulong_t)&ad7381_chip_info }, + { .name = "ad7383", .driver_data = (kernel_ulong_t)&ad7383_chip_info }, + { .name = "ad7384", .driver_data = (kernel_ulong_t)&ad7384_chip_info }, + { .name = "ad7386", .driver_data = (kernel_ulong_t)&ad7386_chip_info }, + { .name = "ad7387", .driver_data = (kernel_ulong_t)&ad7387_chip_info }, + { .name = "ad7388", .driver_data = (kernel_ulong_t)&ad7388_chip_info }, + { .name = "ad7380-4", .driver_data = (kernel_ulong_t)&ad7380_4_chip_info }, + { .name = "ad7381-4", .driver_data = (kernel_ulong_t)&ad7381_4_chip_info }, + { .name = "ad7383-4", .driver_data = (kernel_ulong_t)&ad7383_4_chip_info }, + { .name = "ad7384-4", .driver_data = (kernel_ulong_t)&ad7384_4_chip_info }, + { .name = "ad7386-4", .driver_data = (kernel_ulong_t)&ad7386_4_chip_info }, + { .name = "ad7387-4", .driver_data = (kernel_ulong_t)&ad7387_4_chip_info }, + { .name = "ad7388-4", .driver_data = (kernel_ulong_t)&ad7388_4_chip_info }, + { .name = "ad7389-4", .driver_data = (kernel_ulong_t)&ad7389_4_chip_info }, + { .name = "adaq4370-4", .driver_data = (kernel_ulong_t)&adaq4370_4_chip_info }, + { .name = "adaq4380-4", .driver_data = (kernel_ulong_t)&adaq4380_4_chip_info }, + { .name = "adaq4381-4", .driver_data = (kernel_ulong_t)&adaq4381_4_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7380_id_table); diff --git a/drivers/iio/adc/ad7405.c b/drivers/iio/adc/ad7405.c index 9adf85a732ce..0996f48d76f1 100644 --- a/drivers/iio/adc/ad7405.c +++ b/drivers/iio/adc/ad7405.c @@ -10,7 +10,6 @@ #include <linux/err.h> #include <linux/math64.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <linux/property.h> #include <linux/regulator/consumer.h> diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index 21d3f6aae972..c007f453ae18 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -411,42 +411,42 @@ static int ad7476_probe(struct spi_device *spi) } static const struct spi_device_id ad7476_id[] = { - { "ad7091", (kernel_ulong_t)&ad7091_chip_info }, - { "ad7091r", (kernel_ulong_t)&ad7091r_chip_info }, - { "ad7273", (kernel_ulong_t)&ad7273_chip_info }, - { "ad7274", (kernel_ulong_t)&ad7274_chip_info }, - { "ad7276", (kernel_ulong_t)&ad7276_chip_info }, - { "ad7277", (kernel_ulong_t)&ad7277_chip_info }, - { "ad7278", (kernel_ulong_t)&ad7278_chip_info }, - { "ad7466", (kernel_ulong_t)&ad7466_chip_info }, - { "ad7467", (kernel_ulong_t)&ad7467_chip_info }, - { "ad7468", (kernel_ulong_t)&ad7468_chip_info }, - { "ad7475", (kernel_ulong_t)&ad7475_chip_info }, - { "ad7476", (kernel_ulong_t)&ad7466_chip_info }, - { "ad7476a", (kernel_ulong_t)&ad7466_chip_info }, - { "ad7477", (kernel_ulong_t)&ad7467_chip_info }, - { "ad7477a", (kernel_ulong_t)&ad7467_chip_info }, - { "ad7478", (kernel_ulong_t)&ad7468_chip_info }, - { "ad7478a", (kernel_ulong_t)&ad7468_chip_info }, - { "ad7495", (kernel_ulong_t)&ad7495_chip_info }, - { "ad7910", (kernel_ulong_t)&ad7467_chip_info }, - { "ad7920", (kernel_ulong_t)&ad7466_chip_info }, - { "ad7940", (kernel_ulong_t)&ad7940_chip_info }, - { "adc081s", (kernel_ulong_t)&adc081s_chip_info }, - { "adc101s", (kernel_ulong_t)&adc101s_chip_info }, - { "adc121s", (kernel_ulong_t)&adc121s_chip_info }, - { "ads7866", (kernel_ulong_t)&ads7866_chip_info }, - { "ads7867", (kernel_ulong_t)&ads7867_chip_info }, - { "ads7868", (kernel_ulong_t)&ads7868_chip_info }, - { "bd79105", (kernel_ulong_t)&bd79105_chip_info }, + { .name = "ad7091", .driver_data = (kernel_ulong_t)&ad7091_chip_info }, + { .name = "ad7091r", .driver_data = (kernel_ulong_t)&ad7091r_chip_info }, + { .name = "ad7273", .driver_data = (kernel_ulong_t)&ad7273_chip_info }, + { .name = "ad7274", .driver_data = (kernel_ulong_t)&ad7274_chip_info }, + { .name = "ad7276", .driver_data = (kernel_ulong_t)&ad7276_chip_info }, + { .name = "ad7277", .driver_data = (kernel_ulong_t)&ad7277_chip_info }, + { .name = "ad7278", .driver_data = (kernel_ulong_t)&ad7278_chip_info }, + { .name = "ad7466", .driver_data = (kernel_ulong_t)&ad7466_chip_info }, + { .name = "ad7467", .driver_data = (kernel_ulong_t)&ad7467_chip_info }, + { .name = "ad7468", .driver_data = (kernel_ulong_t)&ad7468_chip_info }, + { .name = "ad7475", .driver_data = (kernel_ulong_t)&ad7475_chip_info }, + { .name = "ad7476", .driver_data = (kernel_ulong_t)&ad7466_chip_info }, + { .name = "ad7476a", .driver_data = (kernel_ulong_t)&ad7466_chip_info }, + { .name = "ad7477", .driver_data = (kernel_ulong_t)&ad7467_chip_info }, + { .name = "ad7477a", .driver_data = (kernel_ulong_t)&ad7467_chip_info }, + { .name = "ad7478", .driver_data = (kernel_ulong_t)&ad7468_chip_info }, + { .name = "ad7478a", .driver_data = (kernel_ulong_t)&ad7468_chip_info }, + { .name = "ad7495", .driver_data = (kernel_ulong_t)&ad7495_chip_info }, + { .name = "ad7910", .driver_data = (kernel_ulong_t)&ad7467_chip_info }, + { .name = "ad7920", .driver_data = (kernel_ulong_t)&ad7466_chip_info }, + { .name = "ad7940", .driver_data = (kernel_ulong_t)&ad7940_chip_info }, + { .name = "adc081s", .driver_data = (kernel_ulong_t)&adc081s_chip_info }, + { .name = "adc101s", .driver_data = (kernel_ulong_t)&adc101s_chip_info }, + { .name = "adc121s", .driver_data = (kernel_ulong_t)&adc121s_chip_info }, + { .name = "ads7866", .driver_data = (kernel_ulong_t)&ads7866_chip_info }, + { .name = "ads7867", .driver_data = (kernel_ulong_t)&ads7867_chip_info }, + { .name = "ads7868", .driver_data = (kernel_ulong_t)&ads7868_chip_info }, + { .name = "bd79105", .driver_data = (kernel_ulong_t)&bd79105_chip_info }, /* * The ROHM BU79100G is identical to the TI's ADS7866 from the software * point of view. The binding document mandates the ADS7866 to be * marked as a fallback for the BU79100G, but we still need the SPI ID * here to make the module loading work. */ - { "bu79100g", (kernel_ulong_t)&ads7866_chip_info }, - { "ltc2314-14", (kernel_ulong_t)<c2314_14_chip_info }, + { .name = "bu79100g", .driver_data = (kernel_ulong_t)&ads7866_chip_info }, + { .name = "ltc2314-14", .driver_data = (kernel_ulong_t)<c2314_14_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7476_id); diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index d9271894f091..cebb8ed8dcb1 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -1475,7 +1475,7 @@ static int ad7606_probe_channels(struct iio_dev *indio_dev) } if (slow_bus) - channels[i] = (struct iio_chan_spec)IIO_CHAN_SOFT_TIMESTAMP(i); + channels[i] = IIO_CHAN_SOFT_TIMESTAMP(i); indio_dev->channels = channels; diff --git a/drivers/iio/adc/ad7606_par.c b/drivers/iio/adc/ad7606_par.c index b81e707ab40c..5b137e947f0b 100644 --- a/drivers/iio/adc/ad7606_par.c +++ b/drivers/iio/adc/ad7606_par.c @@ -9,7 +9,6 @@ #include <linux/err.h> #include <linux/gpio/consumer.h> #include <linux/io.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/property.h> diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c index 7e17ccbcedd0..1ebdfb8580ab 100644 --- a/drivers/iio/adc/ad7606_spi.c +++ b/drivers/iio/adc/ad7606_spi.c @@ -463,17 +463,17 @@ static int ad7606_spi_probe(struct spi_device *spi) } static const struct spi_device_id ad7606_id_table[] = { - { "ad7605-4", (kernel_ulong_t)&ad7605_4_bus_info }, - { "ad7606-4", (kernel_ulong_t)&ad7606_4_bus_info }, - { "ad7606-6", (kernel_ulong_t)&ad7606_6_bus_info }, - { "ad7606-8", (kernel_ulong_t)&ad7606_8_bus_info }, - { "ad7606b", (kernel_ulong_t)&ad7606b_bus_info }, - { "ad7606c-16", (kernel_ulong_t)&ad7606c_16_bus_info }, - { "ad7606c-18", (kernel_ulong_t)&ad7606c_18_bus_info }, - { "ad7607", (kernel_ulong_t)&ad7607_bus_info }, - { "ad7608", (kernel_ulong_t)&ad7608_bus_info }, - { "ad7609", (kernel_ulong_t)&ad7609_bus_info }, - { "ad7616", (kernel_ulong_t)&ad7616_bus_info }, + { .name = "ad7605-4", .driver_data = (kernel_ulong_t)&ad7605_4_bus_info }, + { .name = "ad7606-4", .driver_data = (kernel_ulong_t)&ad7606_4_bus_info }, + { .name = "ad7606-6", .driver_data = (kernel_ulong_t)&ad7606_6_bus_info }, + { .name = "ad7606-8", .driver_data = (kernel_ulong_t)&ad7606_8_bus_info }, + { .name = "ad7606b", .driver_data = (kernel_ulong_t)&ad7606b_bus_info }, + { .name = "ad7606c-16", .driver_data = (kernel_ulong_t)&ad7606c_16_bus_info }, + { .name = "ad7606c-18", .driver_data = (kernel_ulong_t)&ad7606c_18_bus_info }, + { .name = "ad7607", .driver_data = (kernel_ulong_t)&ad7607_bus_info }, + { .name = "ad7608", .driver_data = (kernel_ulong_t)&ad7608_bus_info }, + { .name = "ad7609", .driver_data = (kernel_ulong_t)&ad7609_bus_info }, + { .name = "ad7616", .driver_data = (kernel_ulong_t)&ad7616_bus_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7606_id_table); diff --git a/drivers/iio/adc/ad7625.c b/drivers/iio/adc/ad7625.c index 0466c0c7eae4..e73a5c9e7f0b 100644 --- a/drivers/iio/adc/ad7625.c +++ b/drivers/iio/adc/ad7625.c @@ -17,7 +17,6 @@ #include <linux/iio/backend.h> #include <linux/iio/iio.h> #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/pwm.h> @@ -175,12 +174,12 @@ enum ad7960_mode { static int ad7625_set_sampling_freq(struct ad7625_state *st, u32 freq) { - u32 target; struct pwm_waveform clk_gate_wf = { }, cnv_wf = { }; + unsigned long target; int ret; target = DIV_ROUND_UP(NSEC_PER_SEC, freq); - cnv_wf.period_length_ns = clamp(target, 100, 10 * KILO); + cnv_wf.period_length_ns = clamp(target, 100UL, 10UL * NSEC_PER_USEC); /* * Use the maximum conversion time t_CNVH from the datasheet as diff --git a/drivers/iio/adc/ad7766.c b/drivers/iio/adc/ad7766.c index 9e4a66477d2d..92957196de59 100644 --- a/drivers/iio/adc/ad7766.c +++ b/drivers/iio/adc/ad7766.c @@ -285,12 +285,12 @@ static int ad7766_probe(struct spi_device *spi) } static const struct spi_device_id ad7766_id[] = { - { "ad7766", ID_AD7766 }, - { "ad7766-1", ID_AD7766_1 }, - { "ad7766-2", ID_AD7766_2 }, - { "ad7767", ID_AD7766 }, - { "ad7767-1", ID_AD7766_1 }, - { "ad7767-2", ID_AD7766_2 }, + { .name = "ad7766", .driver_data = ID_AD7766 }, + { .name = "ad7766-1", .driver_data = ID_AD7766_1 }, + { .name = "ad7766-2", .driver_data = ID_AD7766_2 }, + { .name = "ad7767", .driver_data = ID_AD7766 }, + { .name = "ad7767-1", .driver_data = ID_AD7766_1 }, + { .name = "ad7767-2", .driver_data = ID_AD7766_2 }, { } }; MODULE_DEVICE_TABLE(spi, ad7766_id); diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index e16dede687d3..e9060c1bbe6f 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -25,12 +25,15 @@ #include <linux/regulator/consumer.h> #include <linux/regulator/driver.h> #include <linux/sysfs.h> +#include <linux/spi/offload/consumer.h> +#include <linux/spi/offload/provider.h> #include <linux/spi/spi.h> #include <linux/unaligned.h> #include <linux/units.h> #include <linux/util_macros.h> #include <linux/iio/buffer.h> +#include <linux/iio/buffer-dmaengine.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/iio/trigger.h> @@ -161,6 +164,8 @@ enum ad7768_filter_regval { enum ad7768_scan_type { AD7768_SCAN_TYPE_NORMAL, AD7768_SCAN_TYPE_HIGH_SPEED, + AD7768_SCAN_TYPE_OFFLOAD_NORMAL, + AD7768_SCAN_TYPE_OFFLOAD_HIGH_SPEED, }; enum { @@ -266,6 +271,18 @@ static const struct iio_scan_type ad7768_scan_type[] = { .storagebits = 16, .endianness = IIO_BE, }, + [AD7768_SCAN_TYPE_OFFLOAD_NORMAL] = { + .sign = 's', + .realbits = 24, + .storagebits = 32, + .endianness = IIO_CPU, + }, + [AD7768_SCAN_TYPE_OFFLOAD_HIGH_SPEED] = { + .sign = 's', + .realbits = 16, + .storagebits = 32, + .endianness = IIO_CPU, + }, }; struct ad7768_chip_info { @@ -283,6 +300,8 @@ struct ad7768_chip_info { struct ad7768_state { struct spi_device *spi; + struct spi_offload *offload; + struct spi_offload_trigger *offload_trigger; struct regmap *regmap; struct regmap *regmap24; int vref_uv; @@ -290,7 +309,6 @@ struct ad7768_state { unsigned int vcm_output_sel; struct clk *mclk; unsigned int mclk_freq; - unsigned int mclk_div; unsigned int oversampling_ratio; enum ad7768_filter_type filter_type; unsigned int samp_freq; @@ -306,6 +324,8 @@ struct ad7768_state { struct gpio_desc *gpio_reset; const char *labels[AD7768_MAX_CHANNELS]; struct gpio_chip gpiochip; + struct spi_transfer offload_xfer; + struct spi_message offload_msg; const struct ad7768_chip_info *chip; bool en_spi_sync; struct mutex pga_lock; /* protect device internal state (PGA) */ @@ -464,13 +484,11 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev) int readval, ret; reinit_completion(&st->completion); - - ret = ad7768_set_mode(st, AD7768_ONE_SHOT); - if (ret < 0) - return ret; + enable_irq(st->spi->irq); ret = wait_for_completion_timeout(&st->completion, msecs_to_jiffies(1000)); + disable_irq(st->spi->irq); if (!ret) return -ETIMEDOUT; @@ -487,14 +505,6 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev) if (st->oversampling_ratio == 8) readval >>= 8; - /* - * Any SPI configuration of the AD7768-1 can only be - * performed in continuous conversion mode. - */ - ret = ad7768_set_mode(st, AD7768_CONTINUOUS); - if (ret < 0) - return ret; - return readval; } @@ -1138,6 +1148,10 @@ static int ad7768_get_current_scan_type(const struct iio_dev *indio_dev, { struct ad7768_state *st = iio_priv(indio_dev); + if (st->offload) + return st->oversampling_ratio == 8 ? + AD7768_SCAN_TYPE_OFFLOAD_HIGH_SPEED : AD7768_SCAN_TYPE_OFFLOAD_NORMAL; + return st->oversampling_ratio == 8 ? AD7768_SCAN_TYPE_HIGH_SPEED : AD7768_SCAN_TYPE_NORMAL; } @@ -1252,6 +1266,10 @@ static int ad7768_setup(struct iio_dev *indio_dev) return ret; } + ret = ad7768_set_mode(st, AD7768_CONTINUOUS); + if (ret) + return ret; + /* For backwards compatibility, try the adi,sync-in-gpios property */ st->gpio_sync_in = devm_gpiod_get_optional(&st->spi->dev, "adi,sync-in", GPIOD_OUT_LOW); @@ -1356,8 +1374,94 @@ static const struct iio_buffer_setup_ops ad7768_buffer_ops = { .predisable = &ad7768_buffer_predisable, }; +static int ad7768_offload_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ad7768_state *st = iio_priv(indio_dev); + struct spi_offload_trigger_config config = { + .type = SPI_OFFLOAD_TRIGGER_DATA_READY, + }; + const struct iio_scan_type *scan_type; + unsigned int unused; + int ret; + + scan_type = iio_get_current_scan_type(indio_dev, &indio_dev->channels[0]); + if (IS_ERR(scan_type)) + return PTR_ERR(scan_type); + + st->offload_xfer.len = spi_bpw_to_bytes(scan_type->realbits); + st->offload_xfer.bits_per_word = scan_type->realbits; + st->offload_xfer.offload_flags = SPI_OFFLOAD_XFER_RX_STREAM; + + spi_message_init_with_transfers(&st->offload_msg, &st->offload_xfer, 1); + st->offload_msg.offload = st->offload; + + ret = spi_optimize_message(st->spi, &st->offload_msg); + if (ret) { + dev_err(&st->spi->dev, "failed to prepare offload, err: %d\n", ret); + return ret; + } + + /* + * Write a 1 to the LSB of the INTERFACE_FORMAT register to enter + * continuous read mode. Subsequent data reads do not require an + * initial 8-bit write to query the ADC_DATA register. + */ + ret = regmap_write(st->regmap, AD7768_REG_INTERFACE_FORMAT, 0x01); + if (ret) + goto err_unoptimize_message; + + ret = spi_offload_trigger_enable(st->offload, st->offload_trigger, + &config); + if (ret) + goto err_exit_continuous_read_mode; + + return 0; + +err_exit_continuous_read_mode: + regmap_read(st->regmap24, AD7768_REG24_ADC_DATA, &unused); + +err_unoptimize_message: + spi_unoptimize_message(&st->offload_msg); + + return ret; +} + +static int ad7768_offload_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ad7768_state *st = iio_priv(indio_dev); + unsigned int unused; + + spi_offload_trigger_disable(st->offload, st->offload_trigger); + spi_unoptimize_message(&st->offload_msg); + + /* + * To exit continuous read mode, perform a single read of the ADC_DATA + * reg (0x2C), which allows further configuration of the device. + */ + return regmap_read(st->regmap24, AD7768_REG24_ADC_DATA, &unused); +} + +static const struct iio_buffer_setup_ops ad7768_offload_buffer_ops = { + .postenable = ad7768_offload_buffer_postenable, + .predisable = ad7768_offload_buffer_predisable, +}; + +static int ad7768_set_trigger_state(struct iio_trigger *trig, bool enable) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct ad7768_state *st = iio_priv(indio_dev); + + if (enable) + enable_irq(st->spi->irq); + else + disable_irq(st->spi->irq); + + return 0; +} + static const struct iio_trigger_ops ad7768_trigger_ops = { .validate_device = iio_trigger_validate_own_device, + .set_trigger_state = ad7768_set_trigger_state, }; static int ad7768_set_channel_label(struct iio_dev *indio_dev, @@ -1590,6 +1694,36 @@ static int ad7768_parse_aaf_gain(struct device *dev, struct ad7768_state *st) return 0; } +static bool ad7768_offload_trigger_match(struct spi_offload_trigger *trigger, + enum spi_offload_trigger_type type, + u64 *args, u32 nargs) +{ + if (type != SPI_OFFLOAD_TRIGGER_DATA_READY) + return false; + + /* Up to 2 args are allowed, but only 1 is used */ + if (nargs == 0 || nargs > 2 || args[0] != AD7768_TRIGGER_SOURCE_DRDY) + return false; + + return true; +} + +static int ad7768_offload_trigger_request(struct spi_offload_trigger *trigger, + enum spi_offload_trigger_type type, + u64 *args, u32 nargs) +{ + /* Should already be validated by match, but just in case */ + if (nargs == 0 || nargs > 2) + return -EINVAL; + + return 0; +} + +static const struct spi_offload_trigger_ops ad7768_offload_trigger_ops = { + .match = ad7768_offload_trigger_match, + .request = ad7768_offload_trigger_request, +}; + static const struct ad7768_chip_info ad7768_chip_info = { .name = "ad7768-1", .channel_spec = ad7768_channels, @@ -1627,10 +1761,51 @@ static const struct ad7768_chip_info adaq7769_chip_info = { .has_variable_aaf = true, }; +static const struct spi_offload_config ad7768_spi_offload_config = { + .capability_flags = SPI_OFFLOAD_CAP_TRIGGER | SPI_OFFLOAD_CAP_RX_STREAM_DMA, +}; + +static int ad7768_spi_offload_probe(struct iio_dev *indio_dev, + struct ad7768_state *st) +{ + struct device *dev = &st->spi->dev; + struct spi_offload_trigger_info trigger_info = { + .fwnode = dev_fwnode(dev), + .ops = &ad7768_offload_trigger_ops, + .priv = st, + }; + struct dma_chan *rx_dma; + int ret; + + ret = devm_spi_offload_trigger_register(dev, &trigger_info); + if (ret) + return dev_err_probe(dev, ret, "failed to register offload trigger\n"); + + st->offload_trigger = devm_spi_offload_trigger_get(dev, st->offload, + SPI_OFFLOAD_TRIGGER_DATA_READY); + if (IS_ERR(st->offload_trigger)) + return dev_err_probe(dev, PTR_ERR(st->offload_trigger), + "failed to get offload trigger\n"); + + rx_dma = devm_spi_offload_rx_stream_request_dma_chan(dev, st->offload); + if (IS_ERR(rx_dma)) + return dev_err_probe(dev, PTR_ERR(rx_dma), "failed to get offload RX DMA\n"); + + ret = devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev, rx_dma, + IIO_BUFFER_DIRECTION_IN); + if (ret) + return dev_err_probe(dev, ret, "failed to setup offload RX DMA\n"); + + indio_dev->setup_ops = &ad7768_offload_buffer_ops; + + return 0; +} + static int ad7768_probe(struct spi_device *spi) { struct ad7768_state *st; struct iio_dev *indio_dev; + struct device *dev = &spi->dev; int ret; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); @@ -1696,10 +1871,8 @@ static int ad7768_probe(struct spi_device *spi) return ret; ret = ad7768_setup(indio_dev); - if (ret < 0) { - dev_err(&spi->dev, "AD7768 setup failed\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "AD7768 setup failed\n"); init_completion(&st->completion); ret = devm_mutex_init(&spi->dev, &st->pga_lock); @@ -1721,23 +1894,34 @@ static int ad7768_probe(struct spi_device *spi) return ret; ret = devm_request_irq(&spi->dev, spi->irq, &ad7768_interrupt, - IRQF_TRIGGER_RISING | IRQF_NO_THREAD, + IRQF_TRIGGER_RISING | IRQF_NO_THREAD | IRQF_NO_AUTOEN, indio_dev->name, indio_dev); if (ret) return ret; - ret = ad7768_triggered_buffer_alloc(indio_dev); - if (ret) - return ret; + st->offload = devm_spi_offload_get(dev, spi, &ad7768_spi_offload_config); + ret = PTR_ERR_OR_ZERO(st->offload); + if (ret == -ENODEV) { + /* If not using SPI offload, fall back to low speed usage */ + ret = ad7768_triggered_buffer_alloc(indio_dev); + if (ret) + return ret; + } else if (ret) { + return dev_err_probe(dev, ret, "failed to get SPI offload\n"); + } else { + ret = ad7768_spi_offload_probe(indio_dev, st); + if (ret) + return ret; + } return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id ad7768_id_table[] = { - { "ad7768-1", (kernel_ulong_t)&ad7768_chip_info }, - { "adaq7767-1", (kernel_ulong_t)&adaq7767_chip_info }, - { "adaq7768-1", (kernel_ulong_t)&adaq7768_chip_info }, - { "adaq7769-1", (kernel_ulong_t)&adaq7769_chip_info }, + { .name = "ad7768-1", .driver_data = (kernel_ulong_t)&ad7768_chip_info }, + { .name = "adaq7767-1", .driver_data = (kernel_ulong_t)&adaq7767_chip_info }, + { .name = "adaq7768-1", .driver_data = (kernel_ulong_t)&adaq7768_chip_info }, + { .name = "adaq7769-1", .driver_data = (kernel_ulong_t)&adaq7769_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7768_id_table); @@ -1764,3 +1948,4 @@ module_spi_driver(ad7768_driver); MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>"); MODULE_DESCRIPTION("Analog Devices AD7768-1 ADC driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER"); diff --git a/drivers/iio/adc/ad7779.c b/drivers/iio/adc/ad7779.c index 695cc79e78da..79fb38d0f400 100644 --- a/drivers/iio/adc/ad7779.c +++ b/drivers/iio/adc/ad7779.c @@ -16,7 +16,6 @@ #include <linux/irq.h> #include <linux/math.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> #include <linux/string.h> @@ -143,7 +142,6 @@ struct ad7779_state { const struct ad7779_chip_info *chip_info; struct clk *mclk; struct iio_trigger *trig; - struct completion completion; unsigned int sampling_freq; enum ad7779_filter filter_enabled; struct iio_backend *back; @@ -843,8 +841,7 @@ static int ad7779_setup_without_backend(struct ad7779_state *st, struct iio_dev IRQF_NO_THREAD | IRQF_NO_AUTOEN, indio_dev->name, st->trig); if (ret) - return dev_err_probe(dev, ret, "request IRQ %d failed\n", - st->spi->irq); + return ret; ret = devm_iio_trigger_register(dev, st->trig); if (ret) @@ -852,8 +849,6 @@ static int ad7779_setup_without_backend(struct ad7779_state *st, struct iio_dev indio_dev->trig = iio_trigger_get(st->trig); - init_completion(&st->completion); - ret = devm_iio_triggered_buffer_setup(dev, indio_dev, &iio_pollfunc_store_time, &ad7779_trigger_handler, diff --git a/drivers/iio/adc/ad7780.c b/drivers/iio/adc/ad7780.c index 24d2dcad8f4d..1cfad70320fe 100644 --- a/drivers/iio/adc/ad7780.c +++ b/drivers/iio/adc/ad7780.c @@ -264,16 +264,12 @@ static const struct iio_info ad7780_info = { static int ad7780_init_gpios(struct device *dev, struct ad7780_state *st) { - int ret; - st->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_LOW); - if (IS_ERR(st->powerdown_gpio)) { - ret = PTR_ERR(st->powerdown_gpio); - dev_err(dev, "Failed to request powerdown GPIO: %d\n", ret); - return ret; - } + if (IS_ERR(st->powerdown_gpio)) + return dev_err_probe(dev, PTR_ERR(st->powerdown_gpio), + "Failed to request powerdown GPIO\n"); if (!st->chip_info->is_ad778x) return 0; @@ -282,20 +278,16 @@ static int ad7780_init_gpios(struct device *dev, struct ad7780_state *st) st->gain_gpio = devm_gpiod_get_optional(dev, "adi,gain", GPIOD_OUT_HIGH); - if (IS_ERR(st->gain_gpio)) { - ret = PTR_ERR(st->gain_gpio); - dev_err(dev, "Failed to request gain GPIO: %d\n", ret); - return ret; - } + if (IS_ERR(st->gain_gpio)) + return dev_err_probe(dev, PTR_ERR(st->gain_gpio), + "Failed to request gain GPIO\n"); st->filter_gpio = devm_gpiod_get_optional(dev, "adi,filter", GPIOD_OUT_HIGH); - if (IS_ERR(st->filter_gpio)) { - ret = PTR_ERR(st->filter_gpio); - dev_err(dev, "Failed to request filter GPIO: %d\n", ret); - return ret; - } + if (IS_ERR(st->filter_gpio)) + return dev_err_probe(dev, PTR_ERR(st->filter_gpio), + "Failed to request filter GPIO\n"); return 0; } @@ -307,11 +299,12 @@ static void ad7780_reg_disable(void *reg) static int ad7780_probe(struct spi_device *spi) { + struct device *dev = &spi->dev; struct ad7780_state *st; struct iio_dev *indio_dev; int ret; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; @@ -329,36 +322,35 @@ static int ad7780_probe(struct spi_device *spi) indio_dev->num_channels = 1; indio_dev->info = &ad7780_info; - ret = ad7780_init_gpios(&spi->dev, st); + ret = ad7780_init_gpios(dev, st); if (ret) return ret; - st->reg = devm_regulator_get(&spi->dev, "avdd"); + st->reg = devm_regulator_get(dev, "avdd"); if (IS_ERR(st->reg)) return PTR_ERR(st->reg); ret = regulator_enable(st->reg); - if (ret) { - dev_err(&spi->dev, "Failed to enable specified AVdd supply\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "Failed to enable specified AVdd supply\n"); - ret = devm_add_action_or_reset(&spi->dev, ad7780_reg_disable, st->reg); + ret = devm_add_action_or_reset(dev, ad7780_reg_disable, st->reg); if (ret) return ret; - ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev); + ret = devm_ad_sd_setup_buffer_and_trigger(dev, indio_dev); if (ret) return ret; - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct spi_device_id ad7780_id[] = { - { "ad7170", ID_AD7170 }, - { "ad7171", ID_AD7171 }, - { "ad7780", ID_AD7780 }, - { "ad7781", ID_AD7781 }, + { .name = "ad7170", .driver_data = ID_AD7170 }, + { .name = "ad7171", .driver_data = ID_AD7171 }, + { .name = "ad7780", .driver_data = ID_AD7780 }, + { .name = "ad7781", .driver_data = ID_AD7781 }, { } }; MODULE_DEVICE_TABLE(spi, ad7780_id); diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c index 041fc25e3209..c2688307bbba 100644 --- a/drivers/iio/adc/ad7791.c +++ b/drivers/iio/adc/ad7791.c @@ -407,23 +407,22 @@ static void ad7791_reg_disable(void *reg) static int ad7791_probe(struct spi_device *spi) { - const struct ad7791_platform_data *pdata = dev_get_platdata(&spi->dev); + struct device *dev = &spi->dev; + const struct ad7791_platform_data *pdata = dev_get_platdata(dev); struct iio_dev *indio_dev; struct ad7791_state *st; int ret; - if (!spi->irq) { - dev_err(&spi->dev, "Missing IRQ.\n"); - return -ENXIO; - } + if (!spi->irq) + return dev_err_probe(dev, -ENXIO, "Missing IRQ.\n"); - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; st = iio_priv(indio_dev); - st->reg = devm_regulator_get(&spi->dev, "refin"); + st->reg = devm_regulator_get(dev, "refin"); if (IS_ERR(st->reg)) return PTR_ERR(st->reg); @@ -431,7 +430,7 @@ static int ad7791_probe(struct spi_device *spi) if (ret) return ret; - ret = devm_add_action_or_reset(&spi->dev, ad7791_reg_disable, st->reg); + ret = devm_add_action_or_reset(dev, ad7791_reg_disable, st->reg); if (ret) return ret; @@ -447,7 +446,7 @@ static int ad7791_probe(struct spi_device *spi) else indio_dev->info = &ad7791_no_filter_info; - ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev); + ret = devm_ad_sd_setup_buffer_and_trigger(dev, indio_dev); if (ret) return ret; @@ -455,15 +454,15 @@ static int ad7791_probe(struct spi_device *spi) if (ret) return ret; - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct spi_device_id ad7791_spi_ids[] = { - { "ad7787", AD7787 }, - { "ad7788", AD7788 }, - { "ad7789", AD7789 }, - { "ad7790", AD7790 }, - { "ad7791", AD7791 }, + { .name = "ad7787", .driver_data = AD7787 }, + { .name = "ad7788", .driver_data = AD7788 }, + { .name = "ad7789", .driver_data = AD7789 }, + { .name = "ad7790", .driver_data = AD7790 }, + { .name = "ad7791", .driver_data = AD7791 }, { } }; MODULE_DEVICE_TABLE(spi, ad7791_spi_ids); diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c index ccf18ce48e34..b0f44c144f20 100644 --- a/drivers/iio/adc/ad7793.c +++ b/drivers/iio/adc/ad7793.c @@ -152,7 +152,6 @@ struct ad7793_chip_info { struct ad7793_state { const struct ad7793_chip_info *chip_info; - u16 int_vref_mv; u16 mode; u16 conf; u32 scale_avail[8][2]; @@ -269,7 +268,12 @@ static int ad7793_setup(struct iio_dev *indio_dev, ret = ad_sd_reset(&st->sd); if (ret < 0) goto out; - usleep_range(500, 2000); /* Wait for at least 500us */ + + /* + * Per AD7792/AD7793 datasheet (Rev. B, page 25, RESET section), + * allow 500 us after a reset before accessing on-chip registers. + */ + fsleep(500); /* write/read test for device presence */ ret = ad_sd_read_reg(&st->sd, AD7793_REG_ID, 1, &id); @@ -279,8 +283,8 @@ static int ad7793_setup(struct iio_dev *indio_dev, id &= AD7793_ID_MASK; if (id != st->chip_info->id) { - ret = -ENODEV; - dev_err(&st->sd.spi->dev, "device ID query failed\n"); + ret = dev_err_probe(&st->sd.spi->dev, -ENODEV, + "device ID query failed\n"); goto out; } @@ -339,8 +343,7 @@ static int ad7793_setup(struct iio_dev *indio_dev, return 0; out: - dev_err(&st->sd.spi->dev, "setup failed\n"); - return ret; + return dev_err_probe(&st->sd.spi->dev, ret, "setup failed\n"); } static const u16 ad7793_sample_freq_avail[16] = {0, 470, 242, 123, 62, 50, 39, @@ -775,22 +778,19 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { static int ad7793_probe(struct spi_device *spi) { - const struct ad7793_platform_data *pdata = dev_get_platdata(&spi->dev); + struct device *dev = &spi->dev; + const struct ad7793_platform_data *pdata = dev_get_platdata(dev); struct ad7793_state *st; struct iio_dev *indio_dev; int ret, vref_mv = 0; - if (!pdata) { - dev_err(&spi->dev, "no platform data?\n"); - return -ENODEV; - } + if (!pdata) + return dev_err_probe(dev, -ENODEV, "no platform data?\n"); - if (!spi->irq) { - dev_err(&spi->dev, "no IRQ?\n"); - return -ENODEV; - } + if (!spi->irq) + return dev_err_probe(dev, -ENODEV, "no IRQ?\n"); - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -799,13 +799,13 @@ static int ad7793_probe(struct spi_device *spi) ad_sd_init(&st->sd, indio_dev, spi, &ad7793_sigma_delta_info); if (pdata->refsel != AD7793_REFSEL_INTERNAL) { - ret = devm_regulator_get_enable_read_voltage(&spi->dev, "refin"); + ret = devm_regulator_get_enable_read_voltage(dev, "refin"); if (ret < 0) return ret; vref_mv = ret / 1000; } else { - vref_mv = 1170; /* Build-in ref */ + vref_mv = 1170; /* Built-in ref */ } st->chip_info = @@ -817,7 +817,7 @@ static int ad7793_probe(struct spi_device *spi) indio_dev->num_channels = st->chip_info->num_channels; indio_dev->info = st->chip_info->iio_info; - ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev); + ret = devm_ad_sd_setup_buffer_and_trigger(dev, indio_dev); if (ret) return ret; @@ -825,19 +825,19 @@ static int ad7793_probe(struct spi_device *spi) if (ret) return ret; - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct spi_device_id ad7793_id[] = { - { "ad7785", ID_AD7785 }, - { "ad7792", ID_AD7792 }, - { "ad7793", ID_AD7793 }, - { "ad7794", ID_AD7794 }, - { "ad7795", ID_AD7795 }, - { "ad7796", ID_AD7796 }, - { "ad7797", ID_AD7797 }, - { "ad7798", ID_AD7798 }, - { "ad7799", ID_AD7799 }, + { .name = "ad7785", .driver_data = ID_AD7785 }, + { .name = "ad7792", .driver_data = ID_AD7792 }, + { .name = "ad7793", .driver_data = ID_AD7793 }, + { .name = "ad7794", .driver_data = ID_AD7794 }, + { .name = "ad7795", .driver_data = ID_AD7795 }, + { .name = "ad7796", .driver_data = ID_AD7796 }, + { .name = "ad7797", .driver_data = ID_AD7797 }, + { .name = "ad7798", .driver_data = ID_AD7798 }, + { .name = "ad7799", .driver_data = ID_AD7799 }, { } }; MODULE_DEVICE_TABLE(spi, ad7793_id); diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c index 87ff95643794..62aaedbce748 100644 --- a/drivers/iio/adc/ad7887.c +++ b/drivers/iio/adc/ad7887.c @@ -104,7 +104,7 @@ static int ad7887_ring_postdisable(struct iio_dev *indio_dev) { struct ad7887_state *st = iio_priv(indio_dev); - /* dummy read: restore default CH0 settin */ + /* dummy read: restore default CH0 settings */ return spi_sync(st->spi, &st->msg[AD7887_CH0]); } @@ -328,7 +328,7 @@ static int ad7887_probe(struct spi_device *spi) } static const struct spi_device_id ad7887_id[] = { - { "ad7887", ID_AD7887 }, + { .name = "ad7887", .driver_data = ID_AD7887 }, { } }; MODULE_DEVICE_TABLE(spi, ad7887_id); diff --git a/drivers/iio/adc/ad7923.c b/drivers/iio/adc/ad7923.c index 0369151c7db1..44e014da9722 100644 --- a/drivers/iio/adc/ad7923.c +++ b/drivers/iio/adc/ad7923.c @@ -30,7 +30,7 @@ #define AD7923_PM_MODE_AS (1) /* auto shutdown */ #define AD7923_PM_MODE_FS (2) /* full shutdown */ #define AD7923_PM_MODE_OPS (3) /* normal operation */ -#define AD7923_SEQUENCE_OFF (0) /* no sequence fonction */ +#define AD7923_SEQUENCE_OFF (0) /* no sequence function */ #define AD7923_SEQUENCE_PROTECT (2) /* no interrupt write cycle */ #define AD7923_SEQUENCE_ON (3) /* continuous sequence */ @@ -39,7 +39,7 @@ #define AD7923_CHANNEL_WRITE(channel) ((channel) << 6) /* write channel */ #define AD7923_SEQUENCE_WRITE(sequence) ((((sequence) & 1) << 3) \ + (((sequence) & 2) << 9)) - /* write sequence fonction */ + /* write sequence function */ /* left shift for CR : bit 11 transmit in first */ #define AD7923_SHIFT_REGISTER 4 @@ -360,13 +360,13 @@ static int ad7923_probe(struct spi_device *spi) } static const struct spi_device_id ad7923_id[] = { - { "ad7904", AD7904 }, - { "ad7914", AD7914 }, - { "ad7923", AD7924 }, - { "ad7924", AD7924 }, - { "ad7908", AD7908 }, - { "ad7918", AD7918 }, - { "ad7928", AD7928 }, + { .name = "ad7904", .driver_data = AD7904 }, + { .name = "ad7914", .driver_data = AD7914 }, + { .name = "ad7923", .driver_data = AD7924 }, + { .name = "ad7924", .driver_data = AD7924 }, + { .name = "ad7908", .driver_data = AD7908 }, + { .name = "ad7918", .driver_data = AD7918 }, + { .name = "ad7928", .driver_data = AD7928 }, { } }; MODULE_DEVICE_TABLE(spi, ad7923_id); diff --git a/drivers/iio/adc/ad7944.c b/drivers/iio/adc/ad7944.c index 7722cf9e8214..12656d3cdcec 100644 --- a/drivers/iio/adc/ad7944.c +++ b/drivers/iio/adc/ad7944.c @@ -865,9 +865,9 @@ static const struct of_device_id ad7944_of_match[] = { MODULE_DEVICE_TABLE(of, ad7944_of_match); static const struct spi_device_id ad7944_spi_id[] = { - { "ad7944", (kernel_ulong_t)&ad7944_chip_info }, - { "ad7985", (kernel_ulong_t)&ad7985_chip_info }, - { "ad7986", (kernel_ulong_t)&ad7986_chip_info }, + { .name = "ad7944", .driver_data = (kernel_ulong_t)&ad7944_chip_info }, + { .name = "ad7985", .driver_data = (kernel_ulong_t)&ad7985_chip_info }, + { .name = "ad7986", .driver_data = (kernel_ulong_t)&ad7986_chip_info }, { } }; diff --git a/drivers/iio/adc/ad7949.c b/drivers/iio/adc/ad7949.c index b35d299a3977..93a57a3d59b8 100644 --- a/drivers/iio/adc/ad7949.c +++ b/drivers/iio/adc/ad7949.c @@ -341,8 +341,8 @@ static int ad7949_spi_probe(struct spi_device *spi) } else if (spi_is_bpw_supported(spi, 8)) { spi->bits_per_word = 8; } else { - dev_err(dev, "unable to find common BPW with spi controller\n"); - return -EINVAL; + return dev_err_probe(dev, -EINVAL, + "unable to find common BPW with spi controller\n"); } /* Setup internal voltage reference */ @@ -357,8 +357,8 @@ static int ad7949_spi_probe(struct spi_device *spi) ad7949_adc->refsel = AD7949_CFG_VAL_REF_INT_4096; break; default: - dev_err(dev, "unsupported internal voltage reference\n"); - return -EINVAL; + return dev_err_probe(dev, -EINVAL, + "unsupported internal voltage reference\n"); } /* Setup external voltage reference, buffered? */ @@ -382,10 +382,9 @@ static int ad7949_spi_probe(struct spi_device *spi) if (ad7949_adc->refsel & AD7949_CFG_VAL_REF_EXTERNAL) { ret = regulator_enable(ad7949_adc->vref); - if (ret < 0) { - dev_err(dev, "fail to enable regulator\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, + "fail to enable regulator\n"); ret = devm_add_action_or_reset(dev, ad7949_disable_reg, ad7949_adc->vref); @@ -396,16 +395,10 @@ static int ad7949_spi_probe(struct spi_device *spi) mutex_init(&ad7949_adc->lock); ret = ad7949_spi_init(ad7949_adc); - if (ret) { - dev_err(dev, "fail to init this device: %d\n", ret); - return ret; - } - - ret = devm_iio_device_register(dev, indio_dev); if (ret) - dev_err(dev, "fail to register iio device: %d\n", ret); + return dev_err_probe(dev, ret, "fail to init this device\n"); - return ret; + return devm_iio_device_register(dev, indio_dev); } static const struct of_device_id ad7949_spi_of_id[] = { @@ -417,9 +410,9 @@ static const struct of_device_id ad7949_spi_of_id[] = { MODULE_DEVICE_TABLE(of, ad7949_spi_of_id); static const struct spi_device_id ad7949_spi_id[] = { - { "ad7949", ID_AD7949 }, - { "ad7682", ID_AD7682 }, - { "ad7689", ID_AD7689 }, + { .name = "ad7949", .driver_data = ID_AD7949 }, + { .name = "ad7682", .driver_data = ID_AD7682 }, + { .name = "ad7689", .driver_data = ID_AD7689 }, { } }; MODULE_DEVICE_TABLE(spi, ad7949_spi_id); diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index 108bb22162ef..bb076d8f5dd5 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -18,27 +18,29 @@ * ad7998 and similar chips. */ -#include <linux/interrupt.h> +#include <linux/bitops.h> #include <linux/device.h> -#include <linux/kernel.h> -#include <linux/sysfs.h> +#include <linux/err.h> #include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> +#include <linux/sysfs.h> #include <linux/types.h> -#include <linux/err.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/bitops.h> +#include <linux/units.h> +#include <linux/iio/buffer.h> +#include <linux/iio/events.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> -#include <linux/iio/events.h> -#include <linux/iio/buffer.h> #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> #define AD799X_CHANNEL_SHIFT 4 +#define AD799X_MAX_CHANNELS 8 /* * AD7991, AD7995 and AD7999 defines @@ -133,8 +135,11 @@ struct ad799x_state { unsigned int id; u16 config; - u8 *rx_buf; unsigned int transfer_size; + + int vref_uV; + + IIO_DECLARE_BUFFER_WITH_TS(__be16, rx_buf, AD799X_MAX_CHANNELS); }; static int ad799x_write_config(struct ad799x_state *st, u16 val) @@ -217,7 +222,8 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p) } b_sent = i2c_smbus_read_i2c_block_data(st->client, - cmd, st->transfer_size, st->rx_buf); + cmd, st->transfer_size, + (u8 *)st->rx_buf); if (b_sent < 0) goto out; @@ -234,11 +240,6 @@ static int ad799x_update_scan_mode(struct iio_dev *indio_dev, { struct ad799x_state *st = iio_priv(indio_dev); - kfree(st->rx_buf); - st->rx_buf = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); - if (!st->rx_buf) - return -ENOMEM; - st->transfer_size = bitmap_weight(scan_mask, iio_get_masklength(indio_dev)) * 2; @@ -306,14 +307,7 @@ static int ad799x_read_raw(struct iio_dev *indio_dev, GENMASK(chan->scan_type.realbits - 1, 0); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - if (st->vref) - ret = regulator_get_voltage(st->vref); - else - ret = regulator_get_voltage(st->reg); - - if (ret < 0) - return ret; - *val = ret / 1000; + *val = st->vref_uV / (MICRO / MILLI); *val2 = chan->scan_type.realbits; return IIO_VAL_FRACTIONAL_LOG2; } @@ -781,8 +775,14 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { }, }; +static void ad799x_reg_disable(void *reg) +{ + regulator_disable(reg); +} + static int ad799x_probe(struct i2c_client *client) { + struct device *dev = &client->dev; const struct i2c_device_id *id = i2c_client_get_device_id(client); int ret; int extra_config = 0; @@ -791,7 +791,7 @@ static int ad799x_probe(struct i2c_client *client) const struct ad799x_chip_info *chip_info = &ad799x_chip_info_tbl[id->driver_data]; - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -799,6 +799,10 @@ static int ad799x_probe(struct i2c_client *client) /* this is only used for device removal purposes */ i2c_set_clientdata(client, indio_dev); + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; + st->id = id->driver_data; if (client->irq > 0 && chip_info->irq_config.info) st->chip_config = &chip_info->irq_config; @@ -807,33 +811,53 @@ static int ad799x_probe(struct i2c_client *client) /* TODO: Add pdata options for filtering and bit delay */ - st->reg = devm_regulator_get(&client->dev, "vcc"); + st->reg = devm_regulator_get(dev, "vcc"); if (IS_ERR(st->reg)) return PTR_ERR(st->reg); ret = regulator_enable(st->reg); if (ret) return ret; + ret = devm_add_action_or_reset(dev, ad799x_reg_disable, st->reg); + if (ret) + return ret; + /* check if an external reference is supplied */ if (chip_info->has_vref) { - st->vref = devm_regulator_get_optional(&client->dev, "vref"); + st->vref = devm_regulator_get_optional(dev, "vref"); ret = PTR_ERR_OR_ZERO(st->vref); - if (ret) { - if (ret != -ENODEV) - goto error_disable_reg; + if (ret == -ENODEV) { st->vref = NULL; - dev_info(&client->dev, "Using VCC reference voltage\n"); + dev_info(dev, "Using VCC reference voltage\n"); + } else if (ret) { + return ret; } if (st->vref) { - dev_info(&client->dev, "Using external reference voltage\n"); + dev_info(dev, "Using external reference voltage\n"); extra_config |= AD7991_REF_SEL; ret = regulator_enable(st->vref); if (ret) - goto error_disable_reg; + return ret; + + ret = devm_add_action_or_reset(dev, ad799x_reg_disable, st->vref); + if (ret) + return ret; + + ret = regulator_get_voltage(st->vref); + if (ret < 0) + return ret; + st->vref_uV = ret; } } + if (!st->vref) { + ret = regulator_get_voltage(st->reg); + if (ret < 0) + return ret; + st->vref_uV = ret; + } + st->client = client; indio_dev->name = id->name; @@ -845,15 +869,15 @@ static int ad799x_probe(struct i2c_client *client) ret = ad799x_update_config(st, st->chip_config->default_config | extra_config); if (ret) - goto error_disable_vref; + return ret; - ret = iio_triggered_buffer_setup(indio_dev, NULL, + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, &ad799x_trigger_handler, NULL); if (ret) - goto error_disable_vref; + return ret; if (client->irq > 0) { - ret = devm_request_threaded_irq(&client->dev, + ret = devm_request_threaded_irq(dev, client->irq, NULL, ad799x_event_handler, @@ -862,40 +886,10 @@ static int ad799x_probe(struct i2c_client *client) client->name, indio_dev); if (ret) - goto error_cleanup_ring; + return ret; } - mutex_init(&st->lock); - - ret = iio_device_register(indio_dev); - if (ret) - goto error_cleanup_ring; - - return 0; - -error_cleanup_ring: - iio_triggered_buffer_cleanup(indio_dev); -error_disable_vref: - if (st->vref) - regulator_disable(st->vref); -error_disable_reg: - regulator_disable(st->reg); - - return ret; -} - -static void ad799x_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct ad799x_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - - iio_triggered_buffer_cleanup(indio_dev); - if (st->vref) - regulator_disable(st->vref); - regulator_disable(st->reg); - kfree(st->rx_buf); + return devm_iio_device_register(dev, indio_dev); } static int ad799x_suspend(struct device *dev) @@ -946,14 +940,14 @@ static int ad799x_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(ad799x_pm_ops, ad799x_suspend, ad799x_resume); static const struct i2c_device_id ad799x_id[] = { - { "ad7991", ad7991 }, - { "ad7995", ad7995 }, - { "ad7999", ad7999 }, - { "ad7992", ad7992 }, - { "ad7993", ad7993 }, - { "ad7994", ad7994 }, - { "ad7997", ad7997 }, - { "ad7998", ad7998 }, + { .name = "ad7991", .driver_data = ad7991 }, + { .name = "ad7995", .driver_data = ad7995 }, + { .name = "ad7999", .driver_data = ad7999 }, + { .name = "ad7992", .driver_data = ad7992 }, + { .name = "ad7993", .driver_data = ad7993 }, + { .name = "ad7994", .driver_data = ad7994 }, + { .name = "ad7997", .driver_data = ad7997 }, + { .name = "ad7998", .driver_data = ad7998 }, { } }; @@ -965,7 +959,6 @@ static struct i2c_driver ad799x_driver = { .pm = pm_sleep_ptr(&ad799x_pm_ops), }, .probe = ad799x_probe, - .remove = ad799x_remove, .id_table = ad799x_id, }; module_i2c_driver(ad799x_driver); diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c index 022888545580..34b7b1256f0d 100644 --- a/drivers/iio/adc/ad9467.c +++ b/drivers/iio/adc/ad9467.c @@ -176,7 +176,6 @@ struct ad9467_state { struct clk *clk; /* used for debugfs */ struct ad9467_chan_test_mode *chan_test; - unsigned int output_mode; unsigned int (*scales)[2]; /* * Times 2 because we may also invert the signal polarity and run the @@ -925,7 +924,11 @@ static int __ad9467_update_clock(struct ad9467_state *st, long r_clk) return ret; guard(mutex)(&st->lock); - return ad9467_calibrate(st); + + if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_CALIBRATION)) + return ad9467_calibrate(st); + + return 0; } static int ad9467_write_raw(struct iio_dev *indio_dev, @@ -1131,12 +1134,15 @@ static ssize_t ad9467_chan_test_mode_read(struct file *file, len = scnprintf(buf, sizeof(buf), "Running \"%s\" Test:\n\t", ad9467_test_modes[chan->mode]); - ret = iio_backend_debugfs_print_chan_status(st->back, chan->idx, - buf + len, - sizeof(buf) - len); - if (ret < 0) - return ret; - len += ret; + if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_CALIBRATION)) { + ret = iio_backend_debugfs_print_chan_status(st->back, + chan->idx, + buf + len, + sizeof(buf) - len); + if (ret < 0) + return ret; + len += ret; + } } else if (chan->mode == AN877_ADC_TESTMODE_OFF) { len = scnprintf(buf, sizeof(buf), "No test Running...\n"); } else { @@ -1175,11 +1181,13 @@ static ssize_t ad9467_chan_test_mode_write(struct file *file, if (mode == AN877_ADC_TESTMODE_OFF) { unsigned int out_mode; - if (chan->mode == AN877_ADC_TESTMODE_PN9_SEQ || - chan->mode == AN877_ADC_TESTMODE_PN23_SEQ) { - ret = ad9467_backend_testmode_off(st, chan->idx); - if (ret) - return ret; + if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_CALIBRATION)) { + if (chan->mode == AN877_ADC_TESTMODE_PN9_SEQ || + chan->mode == AN877_ADC_TESTMODE_PN23_SEQ) { + ret = ad9467_backend_testmode_off(st, chan->idx); + if (ret) + return ret; + } } ret = ad9467_testmode_set(st, chan->idx, mode); @@ -1205,16 +1213,18 @@ static ssize_t ad9467_chan_test_mode_write(struct file *file, return ret; /* some patterns have a backend matching monitoring block */ - if (mode == AN877_ADC_TESTMODE_PN9_SEQ) { - ret = ad9467_backend_testmode_on(st, chan->idx, + if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_CALIBRATION)) { + if (mode == AN877_ADC_TESTMODE_PN9_SEQ) { + ret = ad9467_backend_testmode_on(st, chan->idx, IIO_BACKEND_ADI_PRBS_9A); - if (ret) - return ret; - } else if (mode == AN877_ADC_TESTMODE_PN23_SEQ) { - ret = ad9467_backend_testmode_on(st, chan->idx, + if (ret) + return ret; + } else if (mode == AN877_ADC_TESTMODE_PN23_SEQ) { + ret = ad9467_backend_testmode_on(st, chan->idx, IIO_BACKEND_ADI_PRBS_23A); - if (ret) - return ret; + if (ret) + return ret; + } } } @@ -1280,8 +1290,9 @@ static void ad9467_debugfs_init(struct iio_dev *indio_dev) if (!st->chan_test) return; - debugfs_create_file("calibration_table_dump", 0400, d, st, - &ad9467_calib_table_fops); + if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_CALIBRATION)) + debugfs_create_file("calibration_table_dump", 0400, d, st, + &ad9467_calib_table_fops); for (chan = 0; chan < st->info->num_channels; chan++) { snprintf(attr_name, sizeof(attr_name), "in_voltage%u_test_mode", @@ -1300,12 +1311,13 @@ static void ad9467_debugfs_init(struct iio_dev *indio_dev) static int ad9467_probe(struct spi_device *spi) { + struct device *dev = &spi->dev; struct iio_dev *indio_dev; struct ad9467_state *st; unsigned int id; int ret; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; @@ -1320,16 +1332,15 @@ static int ad9467_probe(struct spi_device *spi) if (AD9467_CAN_INVERT(st)) st->calib_map_size *= 2; - st->clk = devm_clk_get_enabled(&spi->dev, "adc-clk"); + st->clk = devm_clk_get_enabled(dev, "adc-clk"); if (IS_ERR(st->clk)) return PTR_ERR(st->clk); - st->pwrdown_gpio = devm_gpiod_get_optional(&spi->dev, "powerdown", - GPIOD_OUT_LOW); + st->pwrdown_gpio = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_LOW); if (IS_ERR(st->pwrdown_gpio)) return PTR_ERR(st->pwrdown_gpio); - ret = ad9467_reset(&spi->dev); + ret = ad9467_reset(dev); if (ret) return ret; @@ -1338,11 +1349,10 @@ static int ad9467_probe(struct spi_device *spi) return ret; id = ad9467_spi_read(st, AN877_ADC_REG_CHIP_ID); - if (id != st->info->id) { - dev_err(&spi->dev, "Mismatch CHIP_ID, got 0x%X, expected 0x%X\n", - id, st->info->id); - return -ENODEV; - } + if (id != st->info->id) + return dev_err_probe(dev, -ENODEV, + "Mismatch CHIP_ID, got 0x%X, expected 0x%X\n", + id, st->info->id); if (st->info->num_scales > 1) indio_dev->info = &ad9467_info; @@ -1356,19 +1366,25 @@ static int ad9467_probe(struct spi_device *spi) if (ret) return ret; - ret = devm_iio_backend_request_buffer(&spi->dev, st->back, indio_dev); - if (ret) - return ret; + if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_BUFFER)) { + ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev); + if (ret) + return ret; + } - ret = devm_iio_backend_enable(&spi->dev, st->back); - if (ret) - return ret; + if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_ENABLE)) { + ret = devm_iio_backend_enable(dev, st->back); + if (ret) + return ret; + } - ret = ad9467_calibrate(st); - if (ret) - return ret; + if (iio_backend_has_caps(st->back, IIO_BACKEND_CAP_CALIBRATION)) { + ret = ad9467_calibrate(st); + if (ret) + return ret; + } - ret = devm_iio_device_register(&spi->dev, indio_dev); + ret = devm_iio_device_register(dev, indio_dev); if (ret) return ret; @@ -1390,13 +1406,13 @@ static const struct of_device_id ad9467_of_match[] = { MODULE_DEVICE_TABLE(of, ad9467_of_match); static const struct spi_device_id ad9467_ids[] = { - { "ad9211", (kernel_ulong_t)&ad9211_chip_tbl }, - { "ad9265", (kernel_ulong_t)&ad9265_chip_tbl }, - { "ad9434", (kernel_ulong_t)&ad9434_chip_tbl }, - { "ad9467", (kernel_ulong_t)&ad9467_chip_tbl }, - { "ad9643", (kernel_ulong_t)&ad9643_chip_tbl }, - { "ad9649", (kernel_ulong_t)&ad9649_chip_tbl, }, - { "ad9652", (kernel_ulong_t)&ad9652_chip_tbl, }, + { .name = "ad9211", .driver_data = (kernel_ulong_t)&ad9211_chip_tbl }, + { .name = "ad9265", .driver_data = (kernel_ulong_t)&ad9265_chip_tbl }, + { .name = "ad9434", .driver_data = (kernel_ulong_t)&ad9434_chip_tbl }, + { .name = "ad9467", .driver_data = (kernel_ulong_t)&ad9467_chip_tbl }, + { .name = "ad9643", .driver_data = (kernel_ulong_t)&ad9643_chip_tbl }, + { .name = "ad9649", .driver_data = (kernel_ulong_t)&ad9649_chip_tbl }, + { .name = "ad9652", .driver_data = (kernel_ulong_t)&ad9652_chip_tbl }, { } }; MODULE_DEVICE_TABLE(spi, ad9467_ids); diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index 7852884703b0..1b410291da53 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -51,8 +51,10 @@ */ void ad_sd_set_comm(struct ad_sigma_delta *sigma_delta, u8 comm) { - /* Some variants use the lower two bits of the communications register - * to select the channel */ + /* + * Some variants use the lower two bits of the communications register + * to select the channel. + */ sigma_delta->comm = comm & AD_SD_COMM_CHAN_MASK; } EXPORT_SYMBOL_NS_GPL(ad_sd_set_comm, "IIO_AD_SIGMA_DELTA"); @@ -260,11 +262,25 @@ static int ad_sigma_delta_clear_pending_event(struct ad_sigma_delta *sigma_delta /* * Read R̅D̅Y̅ pin (if possible) or status register to check if there is an - * old event. + * old event. For devices with neither an RDY GPIO nor registers, + * ad_sd_read_reg() transmits no address byte and clocks raw MISO bytes, + * which is indistinguishable from reading conversion data and would + * partially consume a pending result. Skip the check for such devices. + * + * This is safe for all current registerless devices: ad7191 and ad7780 + * (with powerdown GPIO) are reset between conversions by CS deassertion, + * so there is no stale result to drain; ad7780 (without powerdown GPIO) + * and max11205 are continuously-converting and cycle ~DRDY at the output + * data rate regardless of whether the previous result was read, so the + * next falling edge fires naturally. + * + * A future registerless device that holds ~DRDY asserted until data is + * read would be broken by this early return and would need either + * num_resetclks set or a rdy-gpio. */ if (sigma_delta->rdy_gpiod) { pending_event = gpiod_get_value(sigma_delta->rdy_gpiod); - } else { + } else if (sigma_delta->info->has_registers) { unsigned int status_reg; ret = ad_sd_read_reg(sigma_delta, AD_SD_REG_STATUS, 1, &status_reg); @@ -272,12 +288,25 @@ static int ad_sigma_delta_clear_pending_event(struct ad_sigma_delta *sigma_delta return ret; pending_event = !(status_reg & AD_SD_REG_STATUS_RDY); + } else { + return 0; } if (!pending_event) return 0; /* + * With num_resetclks = 0, data_read_len is 0 and the drain sequence + * below would compute memset(data + 2, 0xff, 0 - 1), underflowing to + * SIZE_MAX and corrupting the heap. There is no safe way to drain the + * stale result without knowing the data register size; it will be + * consumed by the first ad_sd_read_reg() call in + * ad_sigma_delta_single_conversion(). + */ + if (!data_read_len) + return 0; + + /* * In general the size of the data register is unknown. It varies from * device to device, might be one byte longer if CONTROL.DATA_STATUS is * set and even varies on some devices depending on which input is @@ -439,11 +468,10 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev, out: ad_sd_disable_irq(sigma_delta); - ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); - ad_sigma_delta_disable_one(sigma_delta, chan->address); - out_unlock: sigma_delta->keep_cs_asserted = false; + ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); + ad_sigma_delta_disable_one(sigma_delta, chan->address); sigma_delta->bus_locked = false; spi_bus_unlock(sigma_delta->spi->controller); out_release: @@ -576,6 +604,9 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev) return 0; err_unlock: + sigma_delta->keep_cs_asserted = false; + ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); + sigma_delta->bus_locked = false; spi_bus_unlock(sigma_delta->spi->controller); spi_unoptimize_message(&sigma_delta->sample_msg); diff --git a/drivers/iio/adc/ade9000.c b/drivers/iio/adc/ade9000.c index db085dc5e526..c6c3ea953fea 100644 --- a/drivers/iio/adc/ade9000.c +++ b/drivers/iio/adc/ade9000.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * ADE9000 driver * * Copyright 2025 Analog Devices Inc. @@ -218,9 +218,6 @@ #define ADE9000_ST1_ERROR1_BIT BIT(29) #define ADE9000_ST1_ERROR2_BIT BIT(30) #define ADE9000_ST1_ERROR3_BIT BIT(31) -#define ADE9000_ST_ERROR \ - (ADE9000_ST1_ERROR0 | ADE9000_ST1_ERROR1 | \ - ADE9000_ST1_ERROR2 | ADE9000_ST1_ERROR3) #define ADE9000_ST1_CROSSING_FIRST 6 #define ADE9000_ST1_CROSSING_DEPTH 25 @@ -283,7 +280,6 @@ enum ade9000_wfb_cfg { #define ADE9000_PHASE_C_POS_BIT BIT(6) #define ADE9000_MAX_PHASE_NR 3 -#define AD9000_CHANNELS_PER_PHASE 10 /* * Calculate register address for multi-phase device. @@ -787,7 +783,7 @@ static int ade9000_iio_push_streaming(struct iio_dev *indio_dev) ADE9000_MIDDLE_PAGE_BIT); if (ret) { dev_err_ratelimited(dev, "IRQ0 WFB write fail"); - return IRQ_HANDLED; + return ret; } ade9000_configure_scan(indio_dev, ADE9000_REG_WF_BUFF); @@ -1123,7 +1119,7 @@ static int ade9000_write_raw(struct iio_dev *indio_dev, tmp &= ~ADE9000_PHASE_C_POS_BIT; switch (tmp) { - case ADE9000_REG_AWATTOS: + case ADE9000_REG_AWATT: return regmap_write(st->regmap, ADE9000_ADDR_ADJUST(ADE9000_REG_AWATTOS, chan->channel), val); @@ -1549,7 +1545,7 @@ static int ade9000_buffer_postdisable(struct iio_dev *indio_dev) ret = regmap_clear_bits(st->regmap, ADE9000_REG_MASK0, interrupts); if (ret) { - dev_err(dev, "Post-disable update maks0 fail\n"); + dev_err(dev, "Post-disable update mask0 fail\n"); return ret; } @@ -1589,10 +1585,9 @@ static int ade9000_reset(struct ade9000_state *st) /* Only wait for completion if IRQ1 is available to signal reset done */ if (fwnode_irq_get_byname(dev_fwnode(dev), "irq1") >= 0) { if (!wait_for_completion_timeout(&st->reset_completion, - msecs_to_jiffies(1000))) { - dev_err(dev, "Reset timeout after 1s\n"); - return -ETIMEDOUT; - } + msecs_to_jiffies(1000))) + return dev_err_probe(dev, -ETIMEDOUT, + "Reset timeout after 1s\n"); } /* If no IRQ available, reset is already complete after the 50ms delay above */ @@ -1706,19 +1701,19 @@ static int ade9000_probe(struct spi_device *spi) init_completion(&st->reset_completion); - ret = ade9000_request_irq(dev, "irq0", ade9000_irq0_thread, indio_dev); + ret = devm_mutex_init(dev, &st->lock); if (ret) return ret; - ret = ade9000_request_irq(dev, "irq1", ade9000_irq1_thread, indio_dev); + ret = ade9000_request_irq(dev, "irq0", ade9000_irq0_thread, indio_dev); if (ret) return ret; - ret = ade9000_request_irq(dev, "dready", ade9000_dready_thread, indio_dev); + ret = ade9000_request_irq(dev, "irq1", ade9000_irq1_thread, indio_dev); if (ret) return ret; - ret = devm_mutex_init(dev, &st->lock); + ret = ade9000_request_irq(dev, "dready", ade9000_dready_thread, indio_dev); if (ret) return ret; @@ -1773,7 +1768,7 @@ static int ade9000_probe(struct spi_device *spi) }; static const struct spi_device_id ade9000_id[] = { - { "ade9000", 0 }, + { .name = "ade9000" }, { } }; MODULE_DEVICE_TABLE(spi, ade9000_id); diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c index 5f445e0de9ea..589f03618ecf 100644 --- a/drivers/iio/adc/adi-axi-adc.c +++ b/drivers/iio/adc/adi-axi-adc.c @@ -13,7 +13,6 @@ #include <linux/err.h> #include <linux/io.h> #include <linux/delay.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/platform_device.h> @@ -54,6 +53,10 @@ #define AXI_AD485X_PACKET_FORMAT_24BIT 0x1 #define AXI_AD485X_PACKET_FORMAT_32BIT 0x2 #define AXI_AD408X_CNTRL_3_FILTER_EN_MSK BIT(0) +#define AXI_AD408X_CNTRL_3_PACKET_FORMAT_MSK GENMASK(3, 2) +#define AXI_AD408X_PACKET_FORMAT_20BIT 0x0 +#define AXI_AD408X_PACKET_FORMAT_16BIT 0x1 +#define AXI_AD408X_PACKET_FORMAT_14BIT 0x2 #define ADI_AXI_ADC_REG_SYNC_STATUS 0x0068 #define ADI_AXI_ADC_SYNC_STATUS_ADC_SYNC_MSK BIT(0) @@ -437,6 +440,31 @@ static int axi_adc_ad408x_filter_type_set(struct iio_backend *back, AXI_AD408X_CNTRL_3_FILTER_EN_MSK); } +static int axi_adc_ad408x_data_size_set(struct iio_backend *back, + unsigned int size) +{ + struct adi_axi_adc_state *st = iio_backend_get_priv(back); + unsigned int val; + + switch (size) { + case 20: + val = AXI_AD408X_PACKET_FORMAT_20BIT; + break; + case 16: + val = AXI_AD408X_PACKET_FORMAT_16BIT; + break; + case 14: + val = AXI_AD408X_PACKET_FORMAT_14BIT; + break; + default: + return -EINVAL; + } + + return regmap_update_bits(st->regmap, ADI_AXI_ADC_REG_CNTRL_3, + AXI_AD408X_CNTRL_3_PACKET_FORMAT_MSK, + FIELD_PREP(AXI_AD408X_CNTRL_3_PACKET_FORMAT_MSK, val)); +} + static int axi_adc_ad408x_interface_data_align(struct iio_backend *back, u32 timeout_us) { @@ -621,6 +649,8 @@ static const struct iio_backend_ops adi_axi_adc_ops = { static const struct iio_backend_info adi_axi_adc_generic = { .name = "axi-adc", .ops = &adi_axi_adc_ops, + .caps = IIO_BACKEND_CAP_CALIBRATION | IIO_BACKEND_CAP_BUFFER | + IIO_BACKEND_CAP_ENABLE, }; static const struct iio_backend_ops adi_ad485x_ops = { @@ -645,6 +675,8 @@ static const struct iio_backend_ops adi_ad485x_ops = { static const struct iio_backend_info axi_ad485x = { .name = "axi-ad485x", .ops = &adi_ad485x_ops, + .caps = IIO_BACKEND_CAP_CALIBRATION | IIO_BACKEND_CAP_BUFFER | + IIO_BACKEND_CAP_ENABLE, }; static const struct iio_backend_ops adi_ad408x_ops = { @@ -656,6 +688,7 @@ static const struct iio_backend_ops adi_ad408x_ops = { .free_buffer = axi_adc_free_buffer, .data_sample_trigger = axi_adc_data_sample_trigger, .filter_type_set = axi_adc_ad408x_filter_type_set, + .data_size_set = axi_adc_ad408x_data_size_set, .interface_data_align = axi_adc_ad408x_interface_data_align, .num_lanes_set = axi_adc_num_lanes_set, .debugfs_reg_access = iio_backend_debugfs_ptr(axi_adc_reg_access), @@ -665,6 +698,7 @@ static const struct iio_backend_ops adi_ad408x_ops = { static const struct iio_backend_info axi_ad408x = { .name = "axi-ad408x", .ops = &adi_ad408x_ops, + .caps = IIO_BACKEND_CAP_BUFFER | IIO_BACKEND_CAP_ENABLE, }; static int adi_axi_adc_probe(struct platform_device *pdev) diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c index 4be44c524b4d..6169ce28261e 100644 --- a/drivers/iio/adc/aspeed_adc.c +++ b/drivers/iio/adc/aspeed_adc.c @@ -75,6 +75,8 @@ #define ASPEED_ADC_INIT_POLLING_TIME 500 #define ASPEED_ADC_INIT_TIMEOUT 500000 +/* Battery sensing is typically on the last channel */ +#define ASPEED_ADC_BATTERY_CHANNEL 7 /* * When the sampling rate is too high, the ADC may not have enough charging * time, resulting in a low voltage value. Thus, the default uses a slow @@ -121,6 +123,31 @@ struct aspeed_adc_data { struct adc_gain battery_mode_gain; }; +/* + * Enable multiple consecutive channels starting from channel 0. + * This creates a bitmask for channels 0 to (num_channels - 1). + * For example: num_channels=3 creates mask 0x0007 (channels 0,1,2) + */ +static inline u32 aspeed_adc_channels_mask(unsigned int num_channels) +{ + if (num_channels > 16) + return GENMASK(15, 0); + + return BIT(num_channels) - 1; +} + +static inline unsigned int aspeed_adc_get_active_channels(const struct aspeed_adc_data *data) +{ + /* + * For controllers with battery sensing capability, the last channel + * is reserved for battery sensing and should not be included in + * normal channel operations. + */ + if (data->model_data->bat_sense_sup) + return data->model_data->num_channels - 1; + return data->model_data->num_channels; +} + #define ASPEED_CHAN(_idx, _data_reg_addr) { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ @@ -236,10 +263,10 @@ static int aspeed_adc_compensation(struct iio_dev *indio_dev) ASPEED_ADC_CTRL_CHANNEL_ENABLE(0), data->base + ASPEED_REG_ENGINE_CONTROL); /* - * After enable compensating sensing mode need to wait some time for ADC stable - * Experiment result is 1ms. + * After enable compensating sensing mode need to wait some time for the + * ADC stablize. Experiment result is 1ms. */ - mdelay(1); + fsleep(1000); for (index = 0; index < 16; index++) { /* @@ -285,31 +312,48 @@ static int aspeed_adc_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - if (data->battery_sensing && chan->channel == 7) { - adc_engine_control_reg_val = - readl(data->base + ASPEED_REG_ENGINE_CONTROL); + adc_engine_control_reg_val = readl(data->base + ASPEED_REG_ENGINE_CONTROL); + /* + * For battery sensing capable controllers, we need to enable + * the specific channel before reading. This is required because + * the battery channel may not be enabled by default. + */ + if (data->model_data->bat_sense_sup && + chan->channel == ASPEED_ADC_BATTERY_CHANNEL) { + u32 ctrl_reg = adc_engine_control_reg_val & ~ASPEED_ADC_CTRL_CHANNEL; + + ctrl_reg |= ASPEED_ADC_CTRL_CHANNEL_ENABLE(chan->channel); + writel(ctrl_reg, data->base + ASPEED_REG_ENGINE_CONTROL); + /* + * After enable a new channel need to wait some time for ADC stable + * Experiment result is 1ms. + */ + fsleep(1000); + } + + if (data->battery_sensing && chan->channel == ASPEED_ADC_BATTERY_CHANNEL) { writel(adc_engine_control_reg_val | FIELD_PREP(ASPEED_ADC_CH7_MODE, ASPEED_ADC_CH7_BAT) | ASPEED_ADC_BAT_SENSING_ENABLE, data->base + ASPEED_REG_ENGINE_CONTROL); /* - * After enable battery sensing mode need to wait some time for adc stable + * After enable battery sensing mode need to wait some time for ADC stable * Experiment result is 1ms. */ - mdelay(1); + fsleep(1000); *val = readw(data->base + chan->address); *val = (*val * data->battery_mode_gain.mult) / data->battery_mode_gain.div; - /* Restore control register value */ - writel(adc_engine_control_reg_val, - data->base + ASPEED_REG_ENGINE_CONTROL); } else *val = readw(data->base + chan->address); + /* Restore control register value */ + writel(adc_engine_control_reg_val, + data->base + ASPEED_REG_ENGINE_CONTROL); return IIO_VAL_INT; case IIO_CHAN_INFO_OFFSET: - if (data->battery_sensing && chan->channel == 7) + if (data->battery_sensing && chan->channel == ASPEED_ADC_BATTERY_CHANNEL) *val = (data->cv * data->battery_mode_gain.mult) / data->battery_mode_gain.div; else @@ -415,6 +459,7 @@ static int aspeed_adc_vref_config(struct iio_dev *indio_dev) } adc_engine_control_reg_val = readl(data->base + ASPEED_REG_ENGINE_CONTROL); + adc_engine_control_reg_val &= ~ASPEED_ADC_REF_VOLTAGE; ret = devm_regulator_get_enable_read_voltage(data->dev, "vref"); if (ret < 0 && ret != -ENODEV) @@ -610,7 +655,9 @@ static int aspeed_adc_probe(struct platform_device *pdev) /* Start all channels in normal mode. */ adc_engine_control_reg_val = readl(data->base + ASPEED_REG_ENGINE_CONTROL); - adc_engine_control_reg_val |= ASPEED_ADC_CTRL_CHANNEL; + FIELD_MODIFY(ASPEED_ADC_CTRL_CHANNEL, &adc_engine_control_reg_val, + aspeed_adc_channels_mask(aspeed_adc_get_active_channels(data))); + writel(adc_engine_control_reg_val, data->base + ASPEED_REG_ENGINE_CONTROL); diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c index aa4ba3f5a506..e8a5285bb6d4 100644 --- a/drivers/iio/adc/at91-sama5d2_adc.c +++ b/drivers/iio/adc/at91-sama5d2_adc.c @@ -17,7 +17,6 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <linux/property.h> #include <linux/sched.h> @@ -2259,7 +2258,7 @@ static int at91_adc_temp_sensor_init(struct at91_adc_state *st, return 0; /* Get the calibration data from NVMEM. */ - temp_calib = devm_nvmem_cell_get(dev, "temperature_calib"); + temp_calib = nvmem_cell_get(dev, "temperature_calib"); if (IS_ERR(temp_calib)) { ret = PTR_ERR(temp_calib); if (ret != -ENOENT) @@ -2268,6 +2267,7 @@ static int at91_adc_temp_sensor_init(struct at91_adc_state *st, } buf = nvmem_cell_read(temp_calib, &len); + nvmem_cell_put(temp_calib); if (IS_ERR(buf)) { dev_err(dev, "Failed to read calibration data!\n"); return PTR_ERR(buf); @@ -2507,7 +2507,7 @@ static int at91_adc_suspend(struct device *dev) at91_adc_buffer_postdisable(indio_dev); /* - * Do a sofware reset of the ADC before we go to suspend. + * Do a software reset of the ADC before we go to suspend. * this will ensure that all pins are free from being muxed by the ADC * and can be used by for other devices. * Otherwise, ADC will hog them and we can't go to suspend mode. diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 920dd9ffd27a..0ac74ad92fca 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -171,7 +171,7 @@ struct at91_adc_trigger { }; /** - * struct at91_adc_reg_desc - Various informations relative to registers + * struct at91_adc_reg_desc - Various information relative to registers * @channel_base: Base offset for the channel data registers * @drdy_mask: Mask of the DRDY field in the relevant registers * (Interruptions registers mostly) @@ -231,7 +231,7 @@ struct at91_adc_state { struct iio_trigger **trig; bool use_external; u32 vref_mv; - u32 res; /* resolution used for convertions */ + u32 res; /* resolution used for conversions */ wait_queue_head_t wq_data_avail; const struct at91_adc_caps *caps; @@ -304,7 +304,7 @@ static void handle_adc_eoc_trigger(int irq, struct iio_dev *idev) } } -static int at91_ts_sample(struct iio_dev *idev) +static void at91_ts_sample(struct iio_dev *idev) { struct at91_adc_state *st = iio_priv(idev); unsigned int xscale, yscale, reg, z1, z2; @@ -323,7 +323,7 @@ static int at91_ts_sample(struct iio_dev *idev) xscale = (reg >> 16) & xyz_mask; if (xscale == 0) { dev_err(&idev->dev, "Error: xscale == 0!\n"); - return -1; + return; } x /= xscale; @@ -334,7 +334,7 @@ static int at91_ts_sample(struct iio_dev *idev) yscale = (reg >> 16) & xyz_mask; if (yscale == 0) { dev_err(&idev->dev, "Error: yscale == 0!\n"); - return -1; + return; } y /= yscale; @@ -363,8 +363,6 @@ static int at91_ts_sample(struct iio_dev *idev) } else { dev_dbg(&idev->dev, "pressure too low: not reporting\n"); } - - return 0; } static irqreturn_t at91_adc_rl_interrupt(int irq, void *private) @@ -483,7 +481,7 @@ static irqreturn_t at91_adc_9x5_interrupt(int irq, void *private) static int at91_adc_channel_init(struct iio_dev *idev) { struct at91_adc_state *st = iio_priv(idev); - struct iio_chan_spec *chan_array, *timestamp; + struct iio_chan_spec *chan_array; int bit, idx = 0; unsigned long rsvd_mask = 0; @@ -521,14 +519,8 @@ static int at91_adc_channel_init(struct iio_dev *idev) chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); idx++; } - timestamp = chan_array + idx; - timestamp->type = IIO_TIMESTAMP; - timestamp->channel = -1; - timestamp->scan_index = idx; - timestamp->scan_type.sign = 's'; - timestamp->scan_type.realbits = 64; - timestamp->scan_type.storagebits = 64; + chan_array[idx] = IIO_CHAN_SOFT_TIMESTAMP(idx); idev->channels = chan_array; return idev->num_channels; @@ -996,7 +988,7 @@ static int at91_adc_probe(struct platform_device *pdev) struct iio_dev *idev; struct at91_adc_state *st; u32 reg, prop; - char *s; + const char *s; idev = devm_iio_device_alloc(&pdev->dev, sizeof(struct at91_adc_state)); if (!idev) @@ -1031,7 +1023,7 @@ static int at91_adc_probe(struct platform_device *pdev) st->res = st->caps->high_res_bits; if (st->caps->low_res_bits && - !of_property_read_string(node, "atmel,adc-use-res", (const char **)&s) + !of_property_read_string(node, "atmel,adc-use-res", &s) && !strcmp(s, "lowres")) st->res = st->caps->low_res_bits; diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c index f9a60e8b05cb..d9016fe1aca9 100644 --- a/drivers/iio/adc/axp20x_adc.c +++ b/drivers/iio/adc/axp20x_adc.c @@ -11,7 +11,6 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/property.h> diff --git a/drivers/iio/adc/bcm_iproc_adc.c b/drivers/iio/adc/bcm_iproc_adc.c index 6426c9e6ccc9..cf4738b16e62 100644 --- a/drivers/iio/adc/bcm_iproc_adc.c +++ b/drivers/iio/adc/bcm_iproc_adc.c @@ -4,7 +4,6 @@ */ #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/io.h> #include <linux/clk.h> #include <linux/mfd/syscon.h> diff --git a/drivers/iio/adc/berlin2-adc.c b/drivers/iio/adc/berlin2-adc.c index fa04e0a5f645..a67edf0bddaa 100644 --- a/drivers/iio/adc/berlin2-adc.c +++ b/drivers/iio/adc/berlin2-adc.c @@ -15,7 +15,6 @@ #include <linux/iio/machine.h> #include <linux/interrupt.h> #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> diff --git a/drivers/iio/adc/cc10001_adc.c b/drivers/iio/adc/cc10001_adc.c index 2c51b90b7101..d42b747325aa 100644 --- a/drivers/iio/adc/cc10001_adc.c +++ b/drivers/iio/adc/cc10001_adc.c @@ -262,7 +262,7 @@ static const struct iio_info cc10001_adc_info = { static int cc10001_adc_channel_init(struct iio_dev *indio_dev, unsigned long channel_map) { - struct iio_chan_spec *chan_array, *timestamp; + struct iio_chan_spec *chan_array; unsigned int bit, idx = 0; indio_dev->num_channels = bitmap_weight(&channel_map, @@ -289,13 +289,7 @@ static int cc10001_adc_channel_init(struct iio_dev *indio_dev, idx++; } - timestamp = &chan_array[idx]; - timestamp->type = IIO_TIMESTAMP; - timestamp->channel = -1; - timestamp->scan_index = idx; - timestamp->scan_type.sign = 's'; - timestamp->scan_type.realbits = 64; - timestamp->scan_type.storagebits = 64; + chan_array[idx] = IIO_CHAN_SOFT_TIMESTAMP(idx); indio_dev->channels = chan_array; diff --git a/drivers/iio/adc/cpcap-adc.c b/drivers/iio/adc/cpcap-adc.c index d9ee2ea116a7..223e2737c564 100644 --- a/drivers/iio/adc/cpcap-adc.c +++ b/drivers/iio/adc/cpcap-adc.c @@ -15,7 +15,6 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <linux/property.h> #include <linux/regmap.h> @@ -934,6 +933,17 @@ static const struct cpcap_adc_ato mapphone_adc = { .atox_ps_factor_out = 0, }; +static const struct cpcap_adc_ato mot_adc = { + .ato_in = 0x0300, + .atox_in = 0, + .adc_ps_factor_in = 0x0200, + .atox_ps_factor_in = 0, + .ato_out = 0x0780, + .atox_out = 0, + .adc_ps_factor_out = 0x0600, + .atox_ps_factor_out = 0, +}; + static const struct of_device_id cpcap_adc_id_table[] = { { .compatible = "motorola,cpcap-adc", @@ -942,6 +952,10 @@ static const struct of_device_id cpcap_adc_id_table[] = { .compatible = "motorola,mapphone-cpcap-adc", .data = &mapphone_adc, }, + { + .compatible = "motorola,mot-cpcap-adc", + .data = &mot_adc, + }, { } }; MODULE_DEVICE_TABLE(of, cpcap_adc_id_table); diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c index eb902a946efe..b01c6f5a73b1 100644 --- a/drivers/iio/adc/dln2-adc.c +++ b/drivers/iio/adc/dln2-adc.c @@ -444,16 +444,6 @@ static int dln2_update_scan_mode(struct iio_dev *indio_dev, lval.scan_type.endianness = IIO_LE; \ } -/* Assignment version of IIO_CHAN_SOFT_TIMESTAMP */ -#define IIO_CHAN_SOFT_TIMESTAMP_ASSIGN(lval, _si) { \ - lval.type = IIO_TIMESTAMP; \ - lval.channel = -1; \ - lval.scan_index = _si; \ - lval.scan_type.sign = 's'; \ - lval.scan_type.realbits = 64; \ - lval.scan_type.storagebits = 64; \ -} - static const struct iio_info dln2_adc_info = { .read_raw = dln2_adc_read_raw, .write_raw = dln2_adc_write_raw, @@ -614,7 +604,7 @@ static int dln2_adc_probe(struct platform_device *pdev) for (i = 0; i < chans; ++i) DLN2_ADC_CHAN(dln2->iio_channels[i], i) - IIO_CHAN_SOFT_TIMESTAMP_ASSIGN(dln2->iio_channels[i], i); + dln2->iio_channels[i] = IIO_CHAN_SOFT_TIMESTAMP(i); indio_dev->name = DLN2_ADC_MOD_NAME; indio_dev->info = &dln2_adc_info; diff --git a/drivers/iio/adc/envelope-detector.c b/drivers/iio/adc/envelope-detector.c index 5b16fe737659..aace7e103770 100644 --- a/drivers/iio/adc/envelope-detector.c +++ b/drivers/iio/adc/envelope-detector.c @@ -31,7 +31,6 @@ #include <linux/err.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/iio/consumer.h> #include <linux/iio/iio.h> @@ -406,3 +405,4 @@ module_platform_driver(envelope_detector_driver); MODULE_DESCRIPTION("Envelope detector using a DAC and a comparator"); MODULE_AUTHOR("Peter Rosin <peda@axentia.se>"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c index f8c220f6a7b4..dc310ed616a1 100644 --- a/drivers/iio/adc/fsl-imx25-gcq.c +++ b/drivers/iio/adc/fsl-imx25-gcq.c @@ -12,7 +12,6 @@ #include <linux/interrupt.h> #include <linux/mfd/imx25-tsadc.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <linux/property.h> #include <linux/regmap.h> @@ -47,7 +46,7 @@ struct mx25_gcq_priv { * of register writes, then a wait for a completion callback, * and finally a register read, during which userspace could issue * another read request. This lock protects a read access from - * ocurring before another one has finished. + * occurring before another one has finished. */ struct mutex lock; }; diff --git a/drivers/iio/adc/gehc-pmc-adc.c b/drivers/iio/adc/gehc-pmc-adc.c index d1167818b17d..24193e941494 100644 --- a/drivers/iio/adc/gehc-pmc-adc.c +++ b/drivers/iio/adc/gehc-pmc-adc.c @@ -207,7 +207,7 @@ static const struct of_device_id pmc_adc_of_match[] = { MODULE_DEVICE_TABLE(of, pmc_adc_of_match); static const struct i2c_device_id pmc_adc_id_table[] = { - { "pmc-adc" }, + { .name = "pmc-adc" }, { } }; MODULE_DEVICE_TABLE(i2c, pmc_adc_id_table); diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c index 86c10ea7ded4..9fa63de4b9ca 100644 --- a/drivers/iio/adc/hi8435.c +++ b/drivers/iio/adc/hi8435.c @@ -15,7 +15,6 @@ #include <linux/iio/triggered_event.h> #include <linux/interrupt.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/spi/spi.h> #include <linux/gpio/consumer.h> @@ -527,7 +526,7 @@ static const struct of_device_id hi8435_dt_ids[] = { MODULE_DEVICE_TABLE(of, hi8435_dt_ids); static const struct spi_device_id hi8435_id[] = { - { "hi8435", 0 }, + { .name = "hi8435" }, { } }; MODULE_DEVICE_TABLE(spi, hi8435_id); diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c index 1db8b68a8f64..00adafa7cbd7 100644 --- a/drivers/iio/adc/hx711.c +++ b/drivers/iio/adc/hx711.c @@ -4,10 +4,11 @@ * * Copyright (c) 2016 Andreas Klinger <ak@it-klinger.de> */ +#include <linux/array_size.h> +#include <linux/dev_printk.h> #include <linux/err.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <linux/property.h> #include <linux/slab.h> @@ -21,6 +22,8 @@ #include <linux/gpio/consumer.h> #include <linux/regulator/consumer.h> +#define HX711_DATA_BITS 24 + /* gain to pulse and scale conversion */ #define HX711_GAIN_MAX 3 #define HX711_RESET_GAIN 128 @@ -28,22 +31,20 @@ struct hx711_gain_to_scale { int gain; int gain_pulse; - int scale; int channel; }; /* * .scale depends on AVDD which in turn is known as soon as the regulator - * is available - * therefore we set .scale in hx711_probe() + * is available; it is stored per device in hx711_data.gain_scale[] * * channel A in documentation is channel 0 in source code * channel B in documentation is channel 1 in source code */ -static struct hx711_gain_to_scale hx711_gain_to_scale[HX711_GAIN_MAX] = { - { 128, 1, 0, 0 }, - { 32, 2, 0, 1 }, - { 64, 3, 0, 0 } +static const struct hx711_gain_to_scale hx711_gain_to_scale[HX711_GAIN_MAX] = { + { 128, 1, 0 }, + { 32, 2, 1 }, + { 64, 3, 0 }, }; static int hx711_get_gain_to_pulse(int gain) @@ -56,32 +57,48 @@ static int hx711_get_gain_to_pulse(int gain) return 1; } -static int hx711_get_gain_to_scale(int gain) +static int hx711_get_gain_to_scale(const int *gain_scale, int gain) { int i; for (i = 0; i < HX711_GAIN_MAX; i++) if (hx711_gain_to_scale[i].gain == gain) - return hx711_gain_to_scale[i].scale; + return gain_scale[i]; return 0; } -static int hx711_get_scale_to_gain(int scale) +static int hx711_get_scale_to_gain(const int *gain_scale, int scale) { int i; for (i = 0; i < HX711_GAIN_MAX; i++) - if (hx711_gain_to_scale[i].scale == scale) + if (gain_scale[i] == scale) return hx711_gain_to_scale[i].gain; return -EINVAL; } +/** + * struct hx711_chip_info - per-variant static configuration + * @name: IIO device name + * @channels: channel specification array + * @num_channels: number of entries in @channels + * @iio_info: IIO info ops for this variant + */ +struct hx711_chip_info { + const char *name; + const struct iio_chan_spec *channels __counted_by_ptr(num_channels); + unsigned int num_channels; + const struct iio_info *iio_info; +}; + struct hx711_data { struct device *dev; struct gpio_desc *gpiod_pd_sck; struct gpio_desc *gpiod_dout; int gain_set; /* gain set on device */ int gain_chan_a; /* gain for channel A */ + int gain_scale[HX711_GAIN_MAX]; + const struct hx711_chip_info *chip_info; struct mutex lock; /* * triggered buffer @@ -139,17 +156,18 @@ static int hx711_cycle(struct hx711_data *hx711_data) return gpiod_get_value(hx711_data->gpiod_dout); } -static int hx711_read(struct hx711_data *hx711_data) +static int hx711_read(struct hx711_data *hx711_data, int trailing_pulses) { - int i, ret; int value = 0; - int val = gpiod_get_value(hx711_data->gpiod_dout); + int val; + int ret; /* we double check if it's really down */ + val = gpiod_get_value(hx711_data->gpiod_dout); if (val) return -EIO; - for (i = 0; i < 24; i++) { + for (int i = 0; i < HX711_DATA_BITS; i++) { value <<= 1; ret = hx711_cycle(hx711_data); if (ret) @@ -158,7 +176,7 @@ static int hx711_read(struct hx711_data *hx711_data) value ^= 0x800000; - for (i = 0; i < hx711_get_gain_to_pulse(hx711_data->gain_set); i++) + for (int i = 0; i < trailing_pulses; i++) hx711_cycle(hx711_data); return value; @@ -188,8 +206,9 @@ static int hx711_wait_for_ready(struct hx711_data *hx711_data) static int hx711_reset(struct hx711_data *hx711_data) { - int val = hx711_wait_for_ready(hx711_data); + int val; + val = hx711_wait_for_ready(hx711_data); if (val) { /* * an examination with the oszilloscope indicated @@ -221,7 +240,8 @@ static int hx711_set_gain_for_channel(struct hx711_data *hx711_data, int chan) if (hx711_data->gain_set == 32) { hx711_data->gain_set = hx711_data->gain_chan_a; - ret = hx711_read(hx711_data); + ret = hx711_read(hx711_data, + hx711_get_gain_to_pulse(hx711_data->gain_set)); if (ret < 0) return ret; @@ -233,7 +253,8 @@ static int hx711_set_gain_for_channel(struct hx711_data *hx711_data, int chan) if (hx711_data->gain_set != 32) { hx711_data->gain_set = 32; - ret = hx711_read(hx711_data); + ret = hx711_read(hx711_data, + hx711_get_gain_to_pulse(hx711_data->gain_set)); if (ret < 0) return ret; @@ -246,10 +267,26 @@ static int hx711_set_gain_for_channel(struct hx711_data *hx711_data, int chan) return 0; } -static int hx711_reset_read(struct hx711_data *hx711_data, int chan) +static int hx711_set_hx711_channel(struct hx711_data *hx711_data, + const struct iio_chan_spec *chan, + int *trailing_pulses) { int ret; - int val; + + ret = hx711_set_gain_for_channel(hx711_data, chan->channel); + if (ret < 0) + return ret; + + *trailing_pulses = hx711_get_gain_to_pulse(hx711_data->gain_set); + + return 0; +} + +static int hx711_reset_read(struct hx711_data *hx711_data, + const struct iio_chan_spec *chan) +{ + int trailing_pulses; + int ret; /* * hx711_reset() must be called from here @@ -260,13 +297,11 @@ static int hx711_reset_read(struct hx711_data *hx711_data, int chan) return -EIO; } - ret = hx711_set_gain_for_channel(hx711_data, chan); + ret = hx711_set_hx711_channel(hx711_data, chan, &trailing_pulses); if (ret < 0) return ret; - val = hx711_read(hx711_data); - - return val; + return hx711_read(hx711_data, trailing_pulses); } static int hx711_read_raw(struct iio_dev *indio_dev, @@ -279,7 +314,7 @@ static int hx711_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_RAW: mutex_lock(&hx711_data->lock); - *val = hx711_reset_read(hx711_data, chan->channel); + *val = hx711_reset_read(hx711_data, chan); mutex_unlock(&hx711_data->lock); @@ -290,7 +325,8 @@ static int hx711_read_raw(struct iio_dev *indio_dev, *val = 0; mutex_lock(&hx711_data->lock); - *val2 = hx711_get_gain_to_scale(hx711_data->gain_set); + *val2 = hx711_get_gain_to_scale(hx711_data->gain_scale, + hx711_data->gain_set); mutex_unlock(&hx711_data->lock); @@ -321,7 +357,7 @@ static int hx711_write_raw(struct iio_dev *indio_dev, mutex_lock(&hx711_data->lock); - gain = hx711_get_scale_to_gain(val2); + gain = hx711_get_scale_to_gain(hx711_data->gain_scale, val2); if (gain < 0) { mutex_unlock(&hx711_data->lock); return gain; @@ -332,7 +368,8 @@ static int hx711_write_raw(struct iio_dev *indio_dev, if (gain != 32) hx711_data->gain_chan_a = gain; - ret = hx711_read(hx711_data); + ret = hx711_read(hx711_data, + hx711_get_gain_to_pulse(hx711_data->gain_set)); if (ret < 0) { mutex_unlock(&hx711_data->lock); return ret; @@ -367,8 +404,8 @@ static irqreturn_t hx711_trigger(int irq, void *p) memset(&hx711_data->buffer, 0, sizeof(hx711_data->buffer)); iio_for_each_active_channel(indio_dev, i) { - hx711_data->buffer.channel[j] = hx711_reset_read(hx711_data, - indio_dev->channels[i].channel); + hx711_data->buffer.channel[j] = + hx711_reset_read(hx711_data, &indio_dev->channels[i]); j++; } @@ -386,6 +423,7 @@ static ssize_t hx711_scale_available_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct hx711_data *hx711_data = iio_priv(dev_to_iio_dev(dev)); struct iio_dev_attr *iio_attr = to_iio_dev_attr(attr); int channel = iio_attr->address; int i, len = 0; @@ -393,7 +431,7 @@ static ssize_t hx711_scale_available_show(struct device *dev, for (i = 0; i < HX711_GAIN_MAX; i++) if (hx711_gain_to_scale[i].channel == channel) len += sprintf(buf + len, "0.%09d ", - hx711_gain_to_scale[i].scale); + hx711_data->gain_scale[i]); len += sprintf(buf + len, "\n"); @@ -455,8 +493,16 @@ static const struct iio_chan_spec hx711_chan_spec[] = { IIO_CHAN_SOFT_TIMESTAMP(2), }; +static const struct hx711_chip_info hx711_chip = { + .name = "hx711", + .channels = hx711_chan_spec, + .iio_info = &hx711_iio_info, + .num_channels = ARRAY_SIZE(hx711_chan_spec), +}; + static int hx711_probe(struct platform_device *pdev) { + const struct hx711_chip_info *chip_info; struct device *dev = &pdev->dev; struct hx711_data *hx711_data; struct iio_dev *indio_dev; @@ -472,6 +518,12 @@ static int hx711_probe(struct platform_device *pdev) mutex_init(&hx711_data->lock); + chip_info = device_get_match_data(dev); + if (!chip_info) + return dev_err_probe(dev, -ENODEV, "missing driver data\n"); + + hx711_data->chip_info = chip_info; + /* * PD_SCK stands for power down and serial clock input of HX711 * in the driver it is an output @@ -511,7 +563,7 @@ static int hx711_probe(struct platform_device *pdev) ret *= 100; for (i = 0; i < HX711_GAIN_MAX; i++) - hx711_gain_to_scale[i].scale = + hx711_data->gain_scale[i] = ret / hx711_gain_to_scale[i].gain / 1678; hx711_data->gain_set = 128; @@ -533,11 +585,11 @@ static int hx711_probe(struct platform_device *pdev) hx711_data->data_ready_delay_ns = 1000000000 / hx711_data->clock_frequency; - indio_dev->name = "hx711"; - indio_dev->info = &hx711_iio_info; + indio_dev->name = chip_info->name; + indio_dev->info = chip_info->iio_info; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = hx711_chan_spec; - indio_dev->num_channels = ARRAY_SIZE(hx711_chan_spec); + indio_dev->channels = chip_info->channels; + indio_dev->num_channels = chip_info->num_channels; ret = devm_iio_triggered_buffer_setup(dev, indio_dev, iio_pollfunc_store_time, @@ -554,7 +606,7 @@ static int hx711_probe(struct platform_device *pdev) } static const struct of_device_id of_hx711_match[] = { - { .compatible = "avia,hx711", }, + { .compatible = "avia,hx711", .data = &hx711_chip }, { } }; diff --git a/drivers/iio/adc/imx7d_adc.c b/drivers/iio/adc/imx7d_adc.c index 039c0387da23..e9a509dc11b8 100644 --- a/drivers/iio/adc/imx7d_adc.c +++ b/drivers/iio/adc/imx7d_adc.c @@ -11,7 +11,6 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/platform_device.h> diff --git a/drivers/iio/adc/imx8qxp-adc.c b/drivers/iio/adc/imx8qxp-adc.c index 6fc50394ad90..d7cc9774359e 100644 --- a/drivers/iio/adc/imx8qxp-adc.c +++ b/drivers/iio/adc/imx8qxp-adc.c @@ -19,7 +19,6 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> diff --git a/drivers/iio/adc/imx93_adc.c b/drivers/iio/adc/imx93_adc.c index 787e80db5de3..797adaf371ba 100644 --- a/drivers/iio/adc/imx93_adc.c +++ b/drivers/iio/adc/imx93_adc.c @@ -13,7 +13,6 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/iopoll.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 857e1b69d6cd..c412f5ed46a1 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -33,8 +33,6 @@ #include <linux/sched/task.h> #include <linux/util_macros.h> -#include <linux/platform_data/ina2xx.h> - /* INA2XX registers definition */ #define INA2XX_CONFIG 0x00 #define INA2XX_SHUNT_VOLTAGE 0x01 /* readonly */ @@ -121,7 +119,7 @@ static const struct regmap_config ina2xx_regmap_config = { .volatile_reg = ina2xx_is_volatile_reg, }; -enum ina2xx_ids { ina219, ina226 }; +enum ina2xx_ids { ina219, ina226, ina236 }; struct ina2xx_config { const char *name; @@ -175,6 +173,16 @@ static const struct ina2xx_config ina2xx_config[] = { .power_lsb_factor = 25, .chip_id = ina226, }, + [ina236] = { + .name = "ina236", + .config_default = INA226_CONFIG_DEFAULT, + .calibration_value = 2048, + .shunt_voltage_lsb = 2500, + .bus_voltage_shift = 0, + .bus_voltage_lsb = 1600, + .power_lsb_factor = 32, + .chip_id = ina236, + }, }; static int ina2xx_read_raw(struct iio_dev *indio_dev, @@ -499,20 +507,26 @@ static int ina2xx_write_raw(struct iio_dev *indio_dev, break; case IIO_CHAN_INFO_INT_TIME: - if (chip->config->chip_id == ina226) { + switch (chip->config->chip_id) { + case ina226: + case ina236: if (chan->address == INA2XX_SHUNT_VOLTAGE) ret = ina226_set_int_time_vshunt(chip, val2, &tmp); else ret = ina226_set_int_time_vbus(chip, val2, &tmp); - } else { + break; + case ina219: if (chan->address == INA2XX_SHUNT_VOLTAGE) ret = ina219_set_int_time_vshunt(chip, val2, &tmp); else ret = ina219_set_int_time_vbus(chip, val2, &tmp); + break; + default: + ret = -EINVAL; } break; @@ -727,19 +741,27 @@ static int ina2xx_conversion_ready(struct iio_dev *indio_dev) * For now, we do an extra read of the MASK_ENABLE register (INA226) * resp. the BUS_VOLTAGE register (INA219). */ - if (chip->config->chip_id == ina226) { + switch (chip->config->chip_id) { + case ina226: + case ina236: ret = regmap_read(chip->regmap, INA226_MASK_ENABLE, &alert); + if (ret < 0) + return ret; + alert &= INA226_CVRF; - } else { + break; + case ina219: ret = regmap_read(chip->regmap, INA2XX_BUS_VOLTAGE, &alert); + if (ret < 0) + return ret; alert &= INA219_CNVR; + break; + default: + return -EINVAL; } - if (ret < 0) - return ret; - return !!alert; } @@ -980,16 +1002,8 @@ static int ina2xx_probe(struct i2c_client *client) mutex_init(&chip->state_lock); - if (of_property_read_u32(client->dev.of_node, - "shunt-resistor", &val) < 0) { - struct ina2xx_platform_data *pdata = - dev_get_platdata(&client->dev); - - if (pdata) - val = pdata->shunt_uohms; - else - val = INA2XX_RSHUNT_DEFAULT; - } + if (of_property_read_u32(client->dev.of_node, "shunt-resistor", &val) < 0) + val = INA2XX_RSHUNT_DEFAULT; ret = set_shunt_resistor(chip, val); if (ret) @@ -998,16 +1012,22 @@ static int ina2xx_probe(struct i2c_client *client) /* Patch the current config register with default. */ val = chip->config->config_default; - if (type == ina226) { + switch (type) { + case ina226: + case ina236: ina226_set_average(chip, INA226_DEFAULT_AVG, &val); ina226_set_int_time_vbus(chip, INA226_DEFAULT_IT, &val); ina226_set_int_time_vshunt(chip, INA226_DEFAULT_IT, &val); - } else { + break; + case ina219: chip->avg = 1; ina219_set_int_time_vbus(chip, INA219_DEFAULT_IT, &val); ina219_set_int_time_vshunt(chip, INA219_DEFAULT_IT, &val); ina219_set_vbus_range_denom(chip, INA219_DEFAULT_BRNG, &val); ina219_set_vshunt_pga_gain(chip, INA219_DEFAULT_PGA, &val); + break; + default: + return -EINVAL; } ret = ina2xx_init(chip, val); @@ -1017,14 +1037,20 @@ static int ina2xx_probe(struct i2c_client *client) } indio_dev->modes = INDIO_DIRECT_MODE; - if (type == ina226) { + switch (type) { + case ina226: + case ina236: indio_dev->channels = ina226_channels; indio_dev->num_channels = ARRAY_SIZE(ina226_channels); indio_dev->info = &ina226_info; - } else { + break; + case ina219: indio_dev->channels = ina219_channels; indio_dev->num_channels = ARRAY_SIZE(ina219_channels); indio_dev->info = &ina219_info; + break; + default: + return -EINVAL; } indio_dev->name = id ? id->name : chip->config->name; @@ -1052,11 +1078,12 @@ static void ina2xx_remove(struct i2c_client *client) } static const struct i2c_device_id ina2xx_id[] = { - { "ina219", ina219 }, - { "ina220", ina219 }, - { "ina226", ina226 }, - { "ina230", ina226 }, - { "ina231", ina226 }, + { .name = "ina219", .driver_data = ina219 }, + { .name = "ina220", .driver_data = ina219 }, + { .name = "ina226", .driver_data = ina226 }, + { .name = "ina230", .driver_data = ina226 }, + { .name = "ina231", .driver_data = ina226 }, + { .name = "ina236", .driver_data = ina236 }, { } }; MODULE_DEVICE_TABLE(i2c, ina2xx_id); @@ -1082,6 +1109,10 @@ static const struct of_device_id ina2xx_of_match[] = { .compatible = "ti,ina231", .data = (void *)ina226 }, + { + .compatible = "ti,ina236", + .data = (void *)ina236 + }, { } }; MODULE_DEVICE_TABLE(of, ina2xx_of_match); diff --git a/drivers/iio/adc/ingenic-adc.c b/drivers/iio/adc/ingenic-adc.c index 1e802c8779a4..71fcdfedb041 100644 --- a/drivers/iio/adc/ingenic-adc.c +++ b/drivers/iio/adc/ingenic-adc.c @@ -7,6 +7,8 @@ */ #include <dt-bindings/iio/adc/ingenic,adc.h> + +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/iio/buffer.h> #include <linux/iio/iio.h> @@ -15,7 +17,6 @@ #include <linux/iopoll.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/of.h> #include <linux/platform_device.h> @@ -115,7 +116,7 @@ static void ingenic_adc_set_adcmd(struct iio_dev *iio_dev, unsigned long mask) { struct ingenic_adc *adc = iio_priv(iio_dev); - mutex_lock(&adc->lock); + guard(mutex)(&adc->lock); /* Init ADCMD */ readl(adc->base + JZ_ADC_REG_ADCMD); @@ -162,8 +163,6 @@ static void ingenic_adc_set_adcmd(struct iio_dev *iio_dev, unsigned long mask) /* We're done */ writel(0, adc->base + JZ_ADC_REG_ADCMD); - - mutex_unlock(&adc->lock); } static void ingenic_adc_set_config(struct ingenic_adc *adc, @@ -172,18 +171,15 @@ static void ingenic_adc_set_config(struct ingenic_adc *adc, { uint32_t cfg; - mutex_lock(&adc->lock); + guard(mutex)(&adc->lock); cfg = readl(adc->base + JZ_ADC_REG_CFG) & ~mask; cfg |= val; writel(cfg, adc->base + JZ_ADC_REG_CFG); - - mutex_unlock(&adc->lock); } -static void ingenic_adc_enable_unlocked(struct ingenic_adc *adc, - int engine, - bool enabled) +static void __ingenic_adc_enable(struct ingenic_adc *adc, int engine, + bool enabled) { u8 val; @@ -201,9 +197,8 @@ static void ingenic_adc_enable(struct ingenic_adc *adc, int engine, bool enabled) { - mutex_lock(&adc->lock); - ingenic_adc_enable_unlocked(adc, engine, enabled); - mutex_unlock(&adc->lock); + guard(mutex)(&adc->lock); + __ingenic_adc_enable(adc, engine, enabled); } static int ingenic_adc_capture(struct ingenic_adc *adc, @@ -218,18 +213,17 @@ static int ingenic_adc_capture(struct ingenic_adc *adc, * probably due to the switch of VREF. We must keep the lock here to * avoid races with the buffer enable/disable functions. */ - mutex_lock(&adc->lock); + guard(mutex)(&adc->lock); cfg = readl(adc->base + JZ_ADC_REG_CFG); writel(cfg & ~JZ_ADC_REG_CFG_CMD_SEL, adc->base + JZ_ADC_REG_CFG); - ingenic_adc_enable_unlocked(adc, engine, true); + __ingenic_adc_enable(adc, engine, true); ret = readb_poll_timeout(adc->base + JZ_ADC_REG_ENABLE, val, !(val & BIT(engine)), 250, 1000); if (ret) - ingenic_adc_enable_unlocked(adc, engine, false); + __ingenic_adc_enable(adc, engine, false); writel(cfg, adc->base + JZ_ADC_REG_CFG); - mutex_unlock(&adc->lock); return ret; } @@ -628,22 +622,12 @@ static int ingenic_adc_read_avail(struct iio_dev *iio_dev, } } -static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev, - struct iio_chan_spec const *chan, - int *val) +static int __ingenic_adc_read_chan(struct ingenic_adc *adc, + struct iio_chan_spec const *chan, + int *val) { int cmd, ret, engine = (chan->channel == INGENIC_ADC_BATTERY); - struct ingenic_adc *adc = iio_priv(iio_dev); - - ret = clk_enable(adc->clk); - if (ret) { - dev_err(iio_dev->dev.parent, "Failed to enable clock: %d\n", - ret); - return ret; - } - /* We cannot sample the aux channels in parallel. */ - mutex_lock(&adc->aux_lock); if (adc->soc_data->has_aux_md && engine == 0) { switch (chan->channel) { case INGENIC_ADC_AUX0: @@ -662,7 +646,7 @@ static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev, ret = ingenic_adc_capture(adc, engine); if (ret) - goto out; + return ret; switch (chan->channel) { case INGENIC_ADC_AUX0: @@ -675,9 +659,26 @@ static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev, break; } - ret = IIO_VAL_INT; -out: - mutex_unlock(&adc->aux_lock); + return IIO_VAL_INT; +} + +static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, + int *val) +{ + struct ingenic_adc *adc = iio_priv(iio_dev); + int ret; + + ret = clk_enable(adc->clk); + if (ret) { + dev_err(iio_dev->dev.parent, "Failed to enable clock: %d\n", ret); + return ret; + } + + /* We cannot sample the aux channels in parallel. */ + scoped_guard(mutex, &adc->aux_lock) + ret = __ingenic_adc_read_chan(adc, chan, val); + clk_disable(adc->clk); return ret; diff --git a/drivers/iio/adc/intel_dc_ti_adc.c b/drivers/iio/adc/intel_dc_ti_adc.c index 0fe34f1c338e..698a2a3049e3 100644 --- a/drivers/iio/adc/intel_dc_ti_adc.c +++ b/drivers/iio/adc/intel_dc_ti_adc.c @@ -14,7 +14,6 @@ #include <linux/device.h> #include <linux/interrupt.h> #include <linux/mfd/intel_soc_pmic.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/platform_device.h> @@ -290,8 +289,8 @@ static int dc_ti_adc_probe(struct platform_device *pdev) if (ret) return ret; - info->vbat_zse = sign_extend32(FIELD_GET(DC_TI_VBAT_ZSE, val), 3); - info->vbat_ge = sign_extend32(FIELD_GET(DC_TI_VBAT_GE, val), 3); + info->vbat_zse = FIELD_GET_SIGNED(DC_TI_VBAT_ZSE, val); + info->vbat_ge = FIELD_GET_SIGNED(DC_TI_VBAT_GE, val); dev_dbg(dev, "vbat-zse %d vbat-ge %d\n", info->vbat_zse, info->vbat_ge); diff --git a/drivers/iio/adc/intel_mrfld_adc.c b/drivers/iio/adc/intel_mrfld_adc.c index 101c1a0ce591..ff34e597944b 100644 --- a/drivers/iio/adc/intel_mrfld_adc.c +++ b/drivers/iio/adc/intel_mrfld_adc.c @@ -15,7 +15,6 @@ #include <linux/interrupt.h> #include <linux/mfd/intel_soc_pmic.h> #include <linux/mfd/intel_soc_pmic_mrfld.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/platform_device.h> diff --git a/drivers/iio/adc/lpc18xx_adc.c b/drivers/iio/adc/lpc18xx_adc.c index 7e5d181ff702..2cf2519f55f3 100644 --- a/drivers/iio/adc/lpc18xx_adc.c +++ b/drivers/iio/adc/lpc18xx_adc.c @@ -17,7 +17,6 @@ #include <linux/iio/driver.h> #include <linux/io.h> #include <linux/iopoll.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/platform_device.h> diff --git a/drivers/iio/adc/lpc32xx_adc.c b/drivers/iio/adc/lpc32xx_adc.c index 43a7bc8158b5..32a15d193d97 100644 --- a/drivers/iio/adc/lpc32xx_adc.c +++ b/drivers/iio/adc/lpc32xx_adc.c @@ -14,7 +14,6 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> @@ -179,6 +178,8 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) if (irq < 0) return irq; + init_completion(&st->completion); + retval = devm_request_irq(&pdev->dev, irq, lpc32xx_adc_isr, 0, LPC32XXAD_NAME, st); if (retval < 0) { @@ -197,8 +198,6 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, iodev); - init_completion(&st->completion); - iodev->name = LPC32XXAD_NAME; iodev->info = &lpc32xx_adc_iio_info; iodev->modes = INDIO_DIRECT_MODE; diff --git a/drivers/iio/adc/ltc2309.c b/drivers/iio/adc/ltc2309.c index 5f0d947d0615..1ad533270a39 100644 --- a/drivers/iio/adc/ltc2309.c +++ b/drivers/iio/adc/ltc2309.c @@ -1,13 +1,17 @@ // SPDX-License-Identifier: GPL-2.0 /* + * The LTC2305 is a 2-Channel, 12-Bit SAR ADC with an I2C Interface. * The LTC2309 is an 8-Channel, 12-Bit SAR ADC with an I2C Interface. * * Datasheet: + * https://www.analog.com/media/en/technical-documentation/data-sheets/23015fb.pdf * https://www.analog.com/media/en/technical-documentation/data-sheets/2309fd.pdf * * Copyright (c) 2023, Liam Beguin <liambeguin@gmail.com> */ +#include <linux/array_size.h> #include <linux/bitfield.h> +#include <linux/delay.h> #include <linux/i2c.h> #include <linux/iio/iio.h> #include <linux/kernel.h> @@ -32,32 +36,41 @@ * @client: I2C reference * @lock: Lock to serialize data access * @vref_mv: Internal voltage reference + * @read_delay_us: Chip-specific read delay in microseconds */ struct ltc2309 { struct device *dev; struct i2c_client *client; struct mutex lock; /* serialize data access */ int vref_mv; + unsigned int read_delay_us; }; /* Order matches expected channel address, See datasheet Table 1. */ +enum ltc2305_channels { + LTC2305_CH0_CH1 = 0x0, + LTC2305_CH1_CH0 = 0x4, + LTC2305_CH0 = 0x8, + LTC2305_CH1 = 0xc, +}; + enum ltc2309_channels { - LTC2309_CH0_CH1 = 0, - LTC2309_CH2_CH3, - LTC2309_CH4_CH5, - LTC2309_CH6_CH7, - LTC2309_CH1_CH0, - LTC2309_CH3_CH2, - LTC2309_CH5_CH4, - LTC2309_CH7_CH6, - LTC2309_CH0, - LTC2309_CH2, - LTC2309_CH4, - LTC2309_CH6, - LTC2309_CH1, - LTC2309_CH3, - LTC2309_CH5, - LTC2309_CH7, + LTC2309_CH0_CH1 = 0x0, + LTC2309_CH2_CH3 = 0x1, + LTC2309_CH4_CH5 = 0x2, + LTC2309_CH6_CH7 = 0x3, + LTC2309_CH1_CH0 = 0x4, + LTC2309_CH3_CH2 = 0x5, + LTC2309_CH5_CH4 = 0x6, + LTC2309_CH7_CH6 = 0x7, + LTC2309_CH0 = 0x8, + LTC2309_CH2 = 0x9, + LTC2309_CH4 = 0xa, + LTC2309_CH6 = 0xb, + LTC2309_CH1 = 0xc, + LTC2309_CH3 = 0xd, + LTC2309_CH5 = 0xe, + LTC2309_CH7 = 0xf, }; #define LTC2309_CHAN(_chan, _addr) { \ @@ -80,6 +93,13 @@ enum ltc2309_channels { .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ } +static const struct iio_chan_spec ltc2305_channels[] = { + LTC2309_CHAN(0, LTC2305_CH0), + LTC2309_CHAN(1, LTC2305_CH1), + LTC2309_DIFF_CHAN(0, 1, LTC2305_CH0_CH1), + LTC2309_DIFF_CHAN(1, 0, LTC2305_CH1_CH0), +}; + static const struct iio_chan_spec ltc2309_channels[] = { LTC2309_CHAN(0, LTC2309_CH0), LTC2309_CHAN(1, LTC2309_CH1), @@ -99,6 +119,26 @@ static const struct iio_chan_spec ltc2309_channels[] = { LTC2309_DIFF_CHAN(7, 6, LTC2309_CH7_CH6), }; +struct ltc2309_chip_info { + const char *name; + unsigned int read_delay_us; + int num_channels; + const struct iio_chan_spec *channels __counted_by_ptr(num_channels); +}; + +static const struct ltc2309_chip_info ltc2305_chip_info = { + .name = "ltc2305", + .read_delay_us = 2, + .num_channels = ARRAY_SIZE(ltc2305_channels), + .channels = ltc2305_channels, +}; + +static const struct ltc2309_chip_info ltc2309_chip_info = { + .name = "ltc2309", + .num_channels = ARRAY_SIZE(ltc2309_channels), + .channels = ltc2309_channels, +}; + static int ltc2309_read_raw_channel(struct ltc2309 *ltc2309, unsigned long address, int *val) { @@ -117,6 +157,9 @@ static int ltc2309_read_raw_channel(struct ltc2309 *ltc2309, return ret; } + if (ltc2309->read_delay_us) + fsleep(ltc2309->read_delay_us); + ret = i2c_master_recv(ltc2309->client, (char *)&buf, 2); if (ret < 0) { dev_err(ltc2309->dev, "i2c read failed: %pe\n", ERR_PTR(ret)); @@ -158,6 +201,7 @@ static const struct iio_info ltc2309_info = { static int ltc2309_probe(struct i2c_client *client) { + const struct ltc2309_chip_info *chip_info; struct iio_dev *indio_dev; struct ltc2309 *ltc2309; int ret; @@ -167,13 +211,16 @@ static int ltc2309_probe(struct i2c_client *client) return -ENOMEM; ltc2309 = iio_priv(indio_dev); + chip_info = i2c_get_match_data(client); + ltc2309->dev = &indio_dev->dev; ltc2309->client = client; + ltc2309->read_delay_us = chip_info->read_delay_us; - indio_dev->name = "ltc2309"; + indio_dev->name = chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = ltc2309_channels; - indio_dev->num_channels = ARRAY_SIZE(ltc2309_channels); + indio_dev->channels = chip_info->channels; + indio_dev->num_channels = chip_info->num_channels; indio_dev->info = <c2309_info; ret = devm_regulator_get_enable_read_voltage(&client->dev, "vref"); @@ -189,13 +236,15 @@ static int ltc2309_probe(struct i2c_client *client) } static const struct of_device_id ltc2309_of_match[] = { - { .compatible = "lltc,ltc2309" }, + { .compatible = "lltc,ltc2305", .data = <c2305_chip_info }, + { .compatible = "lltc,ltc2309", .data = <c2309_chip_info }, { } }; MODULE_DEVICE_TABLE(of, ltc2309_of_match); static const struct i2c_device_id ltc2309_id[] = { - { "ltc2309" }, + { .name = "ltc2305", .driver_data = (kernel_ulong_t)<c2305_chip_info }, + { .name = "ltc2309", .driver_data = (kernel_ulong_t)<c2309_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, ltc2309_id); diff --git a/drivers/iio/adc/ltc2378.c b/drivers/iio/adc/ltc2378.c new file mode 100644 index 000000000000..b0ff2be1aee0 --- /dev/null +++ b/drivers/iio/adc/ltc2378.c @@ -0,0 +1,857 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Analog Devices LTC2378 ADC series driver + * + * Copyright (C) 2026 Analog Devices Inc. + * Author: Marcelo Schmitt <marcelo.schmitt@analog.com> + */ + +#include <linux/array_size.h> +#include <linux/bitops.h> +#include <linux/bits.h> +#include <linux/byteorder/generic.h> +#include <linux/cleanup.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/device-id/spi.h> +#include <linux/device-id/of.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/math64.h> +#include <linux/minmax.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/regulator/consumer.h> +#include <linux/pwm.h> +#include <linux/spi/spi.h> +#include <linux/spi/offload/consumer.h> +#include <linux/spi/offload/types.h> +#include <linux/time64.h> +#include <linux/types.h> +#include <linux/units.h> + +#include <linux/iio/buffer.h> +#include <linux/iio/buffer-dmaengine.h> +#include <linux/iio/iio.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/types.h> + +#define LTC2378_TDSDOBUSYL_NS 5 +#define LTC2378_TBUSYLH_NS 13 +#define LTC2378_TCNV_HIGH_NS 20 +#define LTC2378_MAX_DATA_WAIT_US 4 /* max(TBUSYLH + TCONV + TDSDOBUSYL) */ + +#define LTC2378_CHANNEL(_sign, _real_bits, _storage_bits) \ +{ \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .differential = _sign, \ + .channel = 0, \ + .channel2 = _sign ? 1 : 0, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index = 0, \ + .scan_type = { \ + .format = _sign ? IIO_SCAN_FORMAT_SIGNED_INT : \ + IIO_SCAN_FORMAT_UNSIGNED_INT, \ + .realbits = _real_bits, \ + .storagebits = _storage_bits, \ + .shift = _storage_bits - _real_bits, \ + .endianness = IIO_BE, \ + }, \ +} + +#define LTC2378_DIFF_CHANNEL(_real_bits) \ + LTC2378_CHANNEL(1, _real_bits, (((_real_bits) > 16) ? 32 : 16)) + +#define LTC2378_PSEUDO_DIFF_CHANNEL(_real_bits) \ + LTC2378_CHANNEL(0, _real_bits, (((_real_bits) > 16) ? 32 : 16)) + +#define LTC2378_OFFLOAD_CHANNEL(_sign, _real_bits, _storage_bits) \ +{ \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .differential = _sign, \ + .channel = 0, \ + .channel2 = _sign ? 1 : 0, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_separate_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = 0, \ + .scan_type = { \ + .format = _sign ? IIO_SCAN_FORMAT_SIGNED_INT : \ + IIO_SCAN_FORMAT_UNSIGNED_INT, \ + .realbits = _real_bits, \ + .storagebits = _storage_bits, \ + .shift = 0, \ + .endianness = IIO_CPU, \ + }, \ +} + +/* + * Currently, the available offload hardware + DMA configuration only supports + * pushing 32-bit data elements to DMA IIO buffers in CPU endianness. For 16-bit + * precision parts, those 32-bit elements (in CPU endianness) contain 2 bytes + * with data and 2 bytes always zeroed out. Nevertheless, for the offload use + * case, the IIO buffer is configured for 32 storage bits in CPU endianness so + * data is correctly aligned in user space despite 2 out of the 4 bytes being + * zeros. + */ +#define LTC2378_OFFLOAD_DIFF_CHANNEL(_real_bits) \ + LTC2378_OFFLOAD_CHANNEL(1, (_real_bits), 32) + +#define LTC2378_OFFLOAD_PSEUDO_DIFF_CHANNEL(_real_bits) \ + LTC2378_OFFLOAD_CHANNEL(0, (_real_bits), 32) + +struct ltc2378_chip_info { + const char *name; + unsigned int internal_ref_uV; + struct u32_fract internal_div; + struct iio_chan_spec chan[2]; /* 1 physical chan + 1 timestamp chan */ + struct iio_chan_spec offload_chan; + unsigned int max_sample_rate_Hz; + unsigned int tconv_ns; +}; + +struct ltc2378_state { + const struct ltc2378_chip_info *info; + struct gpio_desc *cnv_gpio; + struct spi_device *spi; + struct mutex lock; /* Protect data acquisition cycle */ + int ref_uV; + struct spi_transfer xfer; + struct spi_transfer offload_xfer; + struct spi_offload *offload; + struct spi_offload_trigger *offload_trigger; + struct pwm_waveform cnv_wf; + struct spi_message offload_msg; + struct spi_offload_trigger_config offload_trigger_config; + struct pwm_device *cnv_trigger; + unsigned int cnv_Hz; + unsigned int sample_freq_range[3]; + + /* + * DMA (thus cache coherency maintenance) requires the transfer buffers + * to live in their own cache lines. + */ + struct { + union { + __be16 sample_buf16_be; + __be32 sample_buf32_be; + u16 sample_buf16; + u32 sample_buf32; + } data; + aligned_s64 timestamp; + } scan __aligned(IIO_DMA_MINALIGN); +}; + +static const struct ltc2378_chip_info ltc2338_18_chip_info = { + .name = "ltc2338-18", + .internal_ref_uV = 2048000, + .internal_div = { .numerator = 5, .denominator = 2 }, + .chan = { LTC2378_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) }, + .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(18), + .max_sample_rate_Hz = 1 * HZ_PER_MHZ, + .tconv_ns = 527, +}; + +static const struct ltc2378_chip_info ltc2364_16_chip_info = { + .name = "ltc2364-16", + .chan = { LTC2378_PSEUDO_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1) }, + .offload_chan = LTC2378_OFFLOAD_PSEUDO_DIFF_CHANNEL(16), + .max_sample_rate_Hz = 250 * HZ_PER_KHZ, + .tconv_ns = 3000, +}; + +static const struct ltc2378_chip_info ltc2364_18_chip_info = { + .name = "ltc2364-18", + .chan = { LTC2378_PSEUDO_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) }, + .offload_chan = LTC2378_OFFLOAD_PSEUDO_DIFF_CHANNEL(18), + .max_sample_rate_Hz = 250 * HZ_PER_KHZ, + .tconv_ns = 3000, +}; + +static const struct ltc2378_chip_info ltc2367_16_chip_info = { + .name = "ltc2367-16", + .chan = { LTC2378_PSEUDO_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1) }, + .offload_chan = LTC2378_OFFLOAD_PSEUDO_DIFF_CHANNEL(16), + .max_sample_rate_Hz = 500 * HZ_PER_KHZ, + .tconv_ns = 1500, +}; + +static const struct ltc2378_chip_info ltc2367_18_chip_info = { + .name = "ltc2367-18", + .chan = { LTC2378_PSEUDO_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) }, + .offload_chan = LTC2378_OFFLOAD_PSEUDO_DIFF_CHANNEL(18), + .max_sample_rate_Hz = 500 * HZ_PER_KHZ, + .tconv_ns = 1500, +}; + +static const struct ltc2378_chip_info ltc2368_16_chip_info = { + .name = "ltc2368-16", + .chan = { LTC2378_PSEUDO_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1) }, + .offload_chan = LTC2378_OFFLOAD_PSEUDO_DIFF_CHANNEL(16), + .max_sample_rate_Hz = 1 * HZ_PER_MHZ, + .tconv_ns = 527, +}; + +static const struct ltc2378_chip_info ltc2368_18_chip_info = { + .name = "ltc2368-18", + .chan = { LTC2378_PSEUDO_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) }, + .offload_chan = LTC2378_OFFLOAD_PSEUDO_DIFF_CHANNEL(18), + .max_sample_rate_Hz = 1 * HZ_PER_MHZ, + .tconv_ns = 527, +}; + +static const struct ltc2378_chip_info ltc2369_18_chip_info = { + .name = "ltc2369-18", + .chan = { LTC2378_PSEUDO_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) }, + .offload_chan = LTC2378_OFFLOAD_PSEUDO_DIFF_CHANNEL(18), + .max_sample_rate_Hz = 1600 * HZ_PER_KHZ, + .tconv_ns = 412, +}; + +static const struct ltc2378_chip_info ltc2370_16_chip_info = { + .name = "ltc2370-16", + .chan = { LTC2378_PSEUDO_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1) }, + .offload_chan = LTC2378_OFFLOAD_PSEUDO_DIFF_CHANNEL(16), + .max_sample_rate_Hz = 2 * HZ_PER_MHZ, + .tconv_ns = 322, +}; + +static const struct ltc2378_chip_info ltc2376_16_chip_info = { + .name = "ltc2376-16", + .chan = { LTC2378_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1) }, + .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(16), + .max_sample_rate_Hz = 250 * HZ_PER_KHZ, + .tconv_ns = 3000, +}; + +static const struct ltc2378_chip_info ltc2376_18_chip_info = { + .name = "ltc2376-18", + .chan = { LTC2378_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) }, + .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(18), + .max_sample_rate_Hz = 250 * HZ_PER_KHZ, + .tconv_ns = 3000, +}; + +static const struct ltc2378_chip_info ltc2376_20_chip_info = { + .name = "ltc2376-20", + .chan = { LTC2378_DIFF_CHANNEL(20), IIO_CHAN_SOFT_TIMESTAMP(1) }, + .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(20), + .max_sample_rate_Hz = 250 * HZ_PER_KHZ, + .tconv_ns = 3000, +}; + +static const struct ltc2378_chip_info ltc2377_16_chip_info = { + .name = "ltc2377-16", + .chan = { LTC2378_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1) }, + .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(16), + .max_sample_rate_Hz = 500 * HZ_PER_KHZ, + .tconv_ns = 1500, +}; + +static const struct ltc2378_chip_info ltc2377_18_chip_info = { + .name = "ltc2377-18", + .chan = { LTC2378_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) }, + .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(18), + .max_sample_rate_Hz = 500 * HZ_PER_KHZ, + .tconv_ns = 1500, +}; + +static const struct ltc2378_chip_info ltc2377_20_chip_info = { + .name = "ltc2377-20", + .chan = { LTC2378_DIFF_CHANNEL(20), IIO_CHAN_SOFT_TIMESTAMP(1) }, + .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(20), + .max_sample_rate_Hz = 500 * HZ_PER_KHZ, + .tconv_ns = 1500, +}; + +static const struct ltc2378_chip_info ltc2378_16_chip_info = { + .name = "ltc2378-16", + .chan = { LTC2378_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1) }, + .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(16), + .max_sample_rate_Hz = 1 * HZ_PER_MHZ, + .tconv_ns = 527, +}; + +static const struct ltc2378_chip_info ltc2378_18_chip_info = { + .name = "ltc2378-18", + .chan = { LTC2378_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) }, + .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(18), + .max_sample_rate_Hz = 1 * HZ_PER_MHZ, + .tconv_ns = 527, +}; + +static const struct ltc2378_chip_info ltc2378_20_chip_info = { + .name = "ltc2378-20", + .chan = { LTC2378_DIFF_CHANNEL(20), IIO_CHAN_SOFT_TIMESTAMP(1) }, + .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(20), + .max_sample_rate_Hz = 1 * HZ_PER_MHZ, + .tconv_ns = 675, +}; + +static const struct ltc2378_chip_info ltc2379_18_chip_info = { + .name = "ltc2379-18", + .chan = { LTC2378_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) }, + .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(18), + .max_sample_rate_Hz = 1600 * HZ_PER_KHZ, + .tconv_ns = 412, +}; + +static const struct ltc2378_chip_info ltc2380_16_chip_info = { + .name = "ltc2380-16", + .chan = { LTC2378_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1) }, + .offload_chan = LTC2378_OFFLOAD_DIFF_CHANNEL(16), + .max_sample_rate_Hz = 2 * HZ_PER_MHZ, + .tconv_ns = 322, +}; + +static int ltc2378_convert_and_acquire(struct ltc2378_state *st) +{ + int ret; + + /* Cause a rising edge of CNV to initiate a new ADC conversion */ + gpiod_set_value_cansleep(st->cnv_gpio, 1); + fsleep(LTC2378_MAX_DATA_WAIT_US); + ret = spi_sync_transfer(st->spi, &st->xfer, 1); + gpiod_set_value_cansleep(st->cnv_gpio, 0); + + return ret; +} + +static irqreturn_t ltc2378_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ltc2378_state *st = iio_priv(indio_dev); + int ret; + + ret = ltc2378_convert_and_acquire(st); + if (ret < 0) + goto err_out; + + iio_push_to_buffers_with_ts(indio_dev, &st->scan, sizeof(st->scan), + pf->timestamp); + +err_out: + iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; +} + +static int ltc2378_channel_single_read(const struct iio_chan_spec *chan, + struct ltc2378_state *st, int *val) +{ + const struct iio_scan_type *scan_type = &chan->scan_type; + u32 sample; + int ret; + + guard(mutex)(&st->lock); + ret = ltc2378_convert_and_acquire(st); + if (ret) + return ret; + + if (chan->scan_type.endianness == IIO_BE) { + if (chan->scan_type.realbits > 16) + sample = be32_to_cpu(st->scan.data.sample_buf32_be); + else + sample = be16_to_cpu(st->scan.data.sample_buf16_be); + } else { /* IIO_CPU */ + if (chan->scan_type.realbits > 16) + sample = st->scan.data.sample_buf32; + else + sample = st->scan.data.sample_buf16; + } + + sample >>= chan->scan_type.shift; + + if (scan_type->format == IIO_SCAN_FORMAT_SIGNED_INT) + *val = sign_extend32(sample, scan_type->realbits - 1); + else + *val = sample; + + return 0; +} + +static int ltc2378_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct ltc2378_state *st = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: { + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + + ret = ltc2378_channel_single_read(chan, st, val); + if (ret) + return ret; + + return IIO_VAL_INT; + } + case IIO_CHAN_INFO_SCALE: { + struct u32_fract fract = st->info->internal_div; + *val = st->ref_uV / MILLI; + if (fract.numerator && fract.denominator) + *val = mult_frac(*val, fract.numerator, fract.denominator); + /* + * For all LTC2378-like devices, the amount of bits that express + * voltage magnitude depend on the polarity / output code format: + * - straight binary: All precision/resolution bits are used. + * - 2's complement: One of the precision bits is used for sign. + */ + if (chan->scan_type.format == IIO_SCAN_FORMAT_SIGNED_INT) + *val2 = chan->scan_type.realbits - 1; + else + *val2 = chan->scan_type.realbits; + + return IIO_VAL_FRACTIONAL_LOG2; + } + case IIO_CHAN_INFO_SAMP_FREQ: + *val = st->cnv_Hz; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int ltc2378_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, long mask) +{ + struct ltc2378_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *vals = st->sample_freq_range; + *type = IIO_VAL_INT; + return IIO_AVAIL_RANGE; + default: + return -EINVAL; + } +} + +/* + * SPI offload wiring schema + * + * +-------------+ +-------------+ + * | CNV |<-----+--| GPIO | + * | | +--| PWM0 | + * | | | | + * | | +--| PWM1 | + * | | | +-------------+ + * | | +->| TRIGGER | + * | | | | + * | ADC | | SPI | + * | | | controller | + * | | | | + * | SDI |<--------| SDO | + * | SDO |-------->| SDI | + * | SCLK |<--------| SCLK | + * +-------------+ +-------------+ + * + */ +static int ltc2378_update_conversion_rate(struct ltc2378_state *st, int freq_Hz) +{ + struct spi_offload_trigger_config config = st->offload_trigger_config; + unsigned int min_read_offset, offload_period_ns; + struct pwm_waveform cnv_wf = { }; + u64 target = LTC2378_TCNV_HIGH_NS; + unsigned int count; + u64 offload_offset_ns; + int ret; + + if (freq_Hz == 0) + return -EINVAL; + + if (!in_range(freq_Hz, 1, st->info->max_sample_rate_Hz)) + return -ERANGE; + + /* Configure CNV PWM waveform */ + cnv_wf.period_length_ns = DIV_ROUND_CLOSEST(NSEC_PER_SEC, freq_Hz); + + /* + * Ensure CNV high time meets minimum requirement (20ns). The PWM + * hardware may round the duty cycle, so iterate until we get at least + * the minimum required high time (or reach a try count limit). + */ + count = 100; + do { + cnv_wf.duty_length_ns = target; + ret = pwm_round_waveform_might_sleep(st->cnv_trigger, &cnv_wf); + if (ret) + return ret; + target += 10; /* Increment by PWM duty cycle period */ + } while (count-- && cnv_wf.duty_length_ns < LTC2378_TCNV_HIGH_NS); + + /* Check the minimum CNV high time is met */ + if (cnv_wf.duty_length_ns < LTC2378_TCNV_HIGH_NS) + return -EDOM; + + /* + * Configure SPI offload PWM trigger. + * The trigger should fire after tBUSYLH + tCONV + tDSDOBUSYL. + * Minimum time needed: TBUSYLH (13ns) + TCONV (part-specific) + TDSDOBUSYL (5ns) + * + * Use the same period as CNV PWM to avoid timing issues. + * Convert back from period to frequency for the SPI offload API. + */ + offload_period_ns = cnv_wf.period_length_ns; + config.periodic.frequency_hz = div_u64(HZ_PER_GHZ, offload_period_ns); + min_read_offset = LTC2378_TBUSYLH_NS + st->info->tconv_ns + LTC2378_TDSDOBUSYL_NS; + offload_offset_ns = min_read_offset; + count = 100; + do { + config.periodic.offset_ns = offload_offset_ns; + ret = spi_offload_trigger_validate(st->offload_trigger, &config); + if (ret) + return ret; + offload_offset_ns += 10; + } while (count-- && config.periodic.offset_ns < min_read_offset); + + /* Check the minimum CNV to SCLK delay is met */ + if (config.periodic.offset_ns < min_read_offset) + return -EDOM; + + /* Check the PWM periods remain the same */ + offload_period_ns = div64_u64(HZ_PER_GHZ, config.periodic.frequency_hz); + if (cnv_wf.period_length_ns != offload_period_ns) + return -EDOM; + + st->offload_trigger_config = config; + st->cnv_wf = cnv_wf; + st->cnv_Hz = DIV_ROUND_CLOSEST_ULL(HZ_PER_GHZ, cnv_wf.period_length_ns); + + return 0; +} + +static int ltc2378_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct ltc2378_state *st = iio_priv(indio_dev); + + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + return ltc2378_update_conversion_rate(st, val); + default: + return -EINVAL; + } +} + +static const struct iio_info ltc2378_iio_info = { + .read_raw = <c2378_read_raw, +}; + +static const struct iio_info ltc2378_offload_iio_info = { + .read_raw = <c2378_read_raw, + .read_avail = <c2378_read_avail, + .write_raw = <c2378_write_raw, +}; + +static int ltc2378_offload_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ltc2378_state *st = iio_priv(indio_dev); + int ret; + + ret = pwm_set_waveform_might_sleep(st->cnv_trigger, &st->cnv_wf, true); + if (ret) + return ret; + + ret = spi_offload_trigger_enable(st->offload, st->offload_trigger, + &st->offload_trigger_config); + if (ret) + goto out_pwm_disable; + + return 0; + +out_pwm_disable: + pwm_disable(st->cnv_trigger); + return ret; +} + +static int ltc2378_offload_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ltc2378_state *st = iio_priv(indio_dev); + + spi_offload_trigger_disable(st->offload, st->offload_trigger); + pwm_disable(st->cnv_trigger); + + return 0; +} + +static const struct iio_buffer_setup_ops ltc2378_offload_buffer_ops = { + .postenable = <c2378_offload_buffer_postenable, + .predisable = <c2378_offload_buffer_predisable, +}; + +static int ltc2378_prepare_offload_message(struct device *dev, + struct ltc2378_state *st) +{ + unsigned int resolution = st->info->offload_chan.scan_type.realbits; + + st->offload_xfer.bits_per_word = resolution; + st->offload_xfer.len = spi_bpw_to_bytes(resolution); + st->offload_xfer.offload_flags = SPI_OFFLOAD_XFER_RX_STREAM; + + /* Initialize message with offload */ + spi_message_init_with_transfers(&st->offload_msg, &st->offload_xfer, 1); + st->offload_msg.offload = st->offload; + + return devm_spi_optimize_message(dev, st->spi, &st->offload_msg); +} + +static int ltc2378_spi_offload_setup(struct iio_dev *indio_dev, + struct ltc2378_state *st) +{ + struct device *dev = &st->spi->dev; + struct dma_chan *rx_dma; + + indio_dev->setup_ops = <c2378_offload_buffer_ops; + + st->offload_trigger = devm_spi_offload_trigger_get(dev, st->offload, + SPI_OFFLOAD_TRIGGER_PERIODIC); + if (IS_ERR(st->offload_trigger)) + return dev_err_probe(dev, PTR_ERR(st->offload_trigger), + "failed to get offload trigger\n"); + + st->offload_trigger_config.type = SPI_OFFLOAD_TRIGGER_PERIODIC; + + rx_dma = devm_spi_offload_rx_stream_request_dma_chan(dev, st->offload); + if (IS_ERR(rx_dma)) + return dev_err_probe(dev, PTR_ERR(rx_dma), "failed to get offload RX DMA\n"); + + return devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev, rx_dma, + IIO_BUFFER_DIRECTION_IN); +} + +static int ltc2378_pwm_get(struct ltc2378_state *st) +{ + struct device *dev = &st->spi->dev; + + st->cnv_trigger = devm_pwm_get(dev, NULL); + if (IS_ERR(st->cnv_trigger)) + return dev_err_probe(dev, PTR_ERR(st->cnv_trigger), + "failed to get cnv pwm\n"); + + /* + * Disable the PWM connected to CNV in case it was left running by + * something else. + */ + pwm_disable(st->cnv_trigger); + + return 0; +} + +static const struct spi_offload_config ltc2378_offload_config = { + .capability_flags = SPI_OFFLOAD_CAP_TRIGGER | + SPI_OFFLOAD_CAP_RX_STREAM_DMA, +}; + +static int ltc2378_refin_setup(struct device *dev, struct ltc2378_state *st) +{ + int ret; + + /* + * The internal reference buffer amplifies both the internal reference + * and REFIN by a factor of 2. + */ + ret = devm_regulator_get_enable_read_voltage(dev, "refin"); + if (ret == -ENODEV) { /* refin is optional */ + st->ref_uV = st->info->internal_ref_uV * 2; + return 0; + } + + if (ret < 0) + return dev_err_probe(dev, ret, "failed to read refin regulator\n"); + + st->ref_uV = ret * 2; + + return 0; +} + +static int ltc2378_ref_setup(struct device *dev, struct ltc2378_state *st) +{ + int ret; + + ret = devm_regulator_get_enable_read_voltage(dev, "ref"); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to read ref regulator\n"); + + st->ref_uV = ret; + + return 0; +} + +static int ltc2378_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct iio_dev *indio_dev; + struct ltc2378_state *st; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->spi = spi; + + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; + + st->info = spi_get_device_match_data(spi); + if (!st->info) + return -EINVAL; + + if (st->info->internal_ref_uV) + ret = ltc2378_refin_setup(dev, st); + else + ret = ltc2378_ref_setup(dev, st); + if (ret) + return ret; + + indio_dev->name = st->info->name; + indio_dev->modes = INDIO_DIRECT_MODE; + + st->cnv_gpio = devm_gpiod_get(dev, "cnv", GPIOD_OUT_LOW); + if (IS_ERR(st->cnv_gpio)) + return dev_err_probe(dev, PTR_ERR(st->cnv_gpio), + "failed to get CNV GPIO"); + + st->offload = devm_spi_offload_get(dev, spi, <c2378_offload_config); + ret = PTR_ERR_OR_ZERO(st->offload); + /* Fall back to low speed usage when no SPI offload is available. */ + if (ret == -ENODEV) { + indio_dev->info = <c2378_iio_info; + indio_dev->channels = st->info->chan; + indio_dev->num_channels = ARRAY_SIZE(st->info->chan); + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + ltc2378_trigger_handler, + NULL); + if (ret) + return ret; + } else if (ret) { + return dev_err_probe(dev, ret, "failed to get offload\n"); + } else { + indio_dev->info = <c2378_offload_iio_info; + indio_dev->channels = &st->info->offload_chan; + indio_dev->num_channels = 1; + ret = ltc2378_spi_offload_setup(indio_dev, st); + if (ret) + return dev_err_probe(dev, ret, + "failed to setup SPI offload\n"); + + ret = ltc2378_pwm_get(st); + if (ret) + return dev_err_probe(dev, ret, "failed to get PWM\n"); + + st->sample_freq_range[0] = 1; /* min */ + st->sample_freq_range[1] = 1; /* step */ + st->sample_freq_range[2] = st->info->max_sample_rate_Hz; /* max */ + + /* + * Start with a slower sampling rate so there is some room for + * adjusting the sample averaging and the sampling frequency + * without hitting the maximum conversion rate. + */ + ret = ltc2378_update_conversion_rate(st, st->info->max_sample_rate_Hz >> 4); + if (ret) + return dev_err_probe(dev, ret, + "failed to set offload samp freq\n"); + + ret = ltc2378_prepare_offload_message(&spi->dev, st); + if (ret) + return dev_err_probe(dev, ret, "failed to optimize SPI message\n"); + + /* + * Set single-read transfer bits_per_word so the SPI subsystem + * rearranges data to CPU endianness, enabling us to reuse + * offload_chan specifications for single-shot reads. + */ + st->xfer.bits_per_word = st->info->offload_chan.scan_type.realbits; + } + + st->xfer.rx_buf = &st->scan.data; + st->xfer.len = spi_bpw_to_bytes(indio_dev->channels[0].scan_type.realbits); + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct of_device_id ltc2378_of_match[] = { + { .compatible = "adi,ltc2338-18", .data = <c2338_18_chip_info }, + { .compatible = "adi,ltc2364-16", .data = <c2364_16_chip_info }, + { .compatible = "adi,ltc2364-18", .data = <c2364_18_chip_info }, + { .compatible = "adi,ltc2367-16", .data = <c2367_16_chip_info }, + { .compatible = "adi,ltc2367-18", .data = <c2367_18_chip_info }, + { .compatible = "adi,ltc2368-16", .data = <c2368_16_chip_info }, + { .compatible = "adi,ltc2368-18", .data = <c2368_18_chip_info }, + { .compatible = "adi,ltc2369-18", .data = <c2369_18_chip_info }, + { .compatible = "adi,ltc2370-16", .data = <c2370_16_chip_info }, + { .compatible = "adi,ltc2376-16", .data = <c2376_16_chip_info }, + { .compatible = "adi,ltc2376-18", .data = <c2376_18_chip_info }, + { .compatible = "adi,ltc2376-20", .data = <c2376_20_chip_info }, + { .compatible = "adi,ltc2377-16", .data = <c2377_16_chip_info }, + { .compatible = "adi,ltc2377-18", .data = <c2377_18_chip_info }, + { .compatible = "adi,ltc2377-20", .data = <c2377_20_chip_info }, + { .compatible = "adi,ltc2378-16", .data = <c2378_16_chip_info }, + { .compatible = "adi,ltc2378-18", .data = <c2378_18_chip_info }, + { .compatible = "adi,ltc2378-20", .data = <c2378_20_chip_info }, + { .compatible = "adi,ltc2379-18", .data = <c2379_18_chip_info }, + { .compatible = "adi,ltc2380-16", .data = <c2380_16_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, ltc2378_of_match); + +static const struct spi_device_id ltc2378_spi_id[] = { + { .name = "ltc2338-18", .driver_data = (kernel_ulong_t)<c2338_18_chip_info }, + { .name = "ltc2364-16", .driver_data = (kernel_ulong_t)<c2364_16_chip_info }, + { .name = "ltc2364-18", .driver_data = (kernel_ulong_t)<c2364_18_chip_info }, + { .name = "ltc2367-16", .driver_data = (kernel_ulong_t)<c2367_16_chip_info }, + { .name = "ltc2367-18", .driver_data = (kernel_ulong_t)<c2367_18_chip_info }, + { .name = "ltc2368-16", .driver_data = (kernel_ulong_t)<c2368_16_chip_info }, + { .name = "ltc2368-18", .driver_data = (kernel_ulong_t)<c2368_18_chip_info }, + { .name = "ltc2369-18", .driver_data = (kernel_ulong_t)<c2369_18_chip_info }, + { .name = "ltc2370-16", .driver_data = (kernel_ulong_t)<c2370_16_chip_info }, + { .name = "ltc2376-16", .driver_data = (kernel_ulong_t)<c2376_16_chip_info }, + { .name = "ltc2376-18", .driver_data = (kernel_ulong_t)<c2376_18_chip_info }, + { .name = "ltc2376-20", .driver_data = (kernel_ulong_t)<c2376_20_chip_info }, + { .name = "ltc2377-16", .driver_data = (kernel_ulong_t)<c2377_16_chip_info }, + { .name = "ltc2377-18", .driver_data = (kernel_ulong_t)<c2377_18_chip_info }, + { .name = "ltc2377-20", .driver_data = (kernel_ulong_t)<c2377_20_chip_info }, + { .name = "ltc2378-16", .driver_data = (kernel_ulong_t)<c2378_16_chip_info }, + { .name = "ltc2378-18", .driver_data = (kernel_ulong_t)<c2378_18_chip_info }, + { .name = "ltc2378-20", .driver_data = (kernel_ulong_t)<c2378_20_chip_info }, + { .name = "ltc2379-18", .driver_data = (kernel_ulong_t)<c2379_18_chip_info }, + { .name = "ltc2380-16", .driver_data = (kernel_ulong_t)<c2380_16_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(spi, ltc2378_spi_id); + +static struct spi_driver ltc2378_driver = { + .driver = { + .name = "ltc2378", + .of_match_table = ltc2378_of_match + }, + .probe = ltc2378_probe, + .id_table = ltc2378_spi_id, +}; +module_spi_driver(ltc2378_driver); + +MODULE_AUTHOR("Marcelo Schmitt <marcelo.schmitt@analog.com>"); +MODULE_DESCRIPTION("Analog Devices LTC2378 ADC series driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER"); +MODULE_IMPORT_NS("SPI_OFFLOAD"); diff --git a/drivers/iio/adc/ltc2471.c b/drivers/iio/adc/ltc2471.c index a579107fd5c9..369af700969f 100644 --- a/drivers/iio/adc/ltc2471.c +++ b/drivers/iio/adc/ltc2471.c @@ -136,8 +136,8 @@ static int ltc2471_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id ltc2471_i2c_id[] = { - { "ltc2471", ltc2471 }, - { "ltc2473", ltc2473 }, + { .name = "ltc2471", .driver_data = ltc2471 }, + { .name = "ltc2473", .driver_data = ltc2473 }, { } }; MODULE_DEVICE_TABLE(i2c, ltc2471_i2c_id); diff --git a/drivers/iio/adc/ltc2485.c b/drivers/iio/adc/ltc2485.c index 060651dd4130..8c3806e061dd 100644 --- a/drivers/iio/adc/ltc2485.c +++ b/drivers/iio/adc/ltc2485.c @@ -124,7 +124,7 @@ static int ltc2485_probe(struct i2c_client *client) } static const struct i2c_device_id ltc2485_id[] = { - { "ltc2485" }, + { .name = "ltc2485" }, { } }; MODULE_DEVICE_TABLE(i2c, ltc2485_id); diff --git a/drivers/iio/adc/ltc2496.c b/drivers/iio/adc/ltc2496.c index f06dd0b9a858..5b5b6ab28850 100644 --- a/drivers/iio/adc/ltc2496.c +++ b/drivers/iio/adc/ltc2496.c @@ -14,7 +14,6 @@ #include <linux/iio/iio.h> #include <linux/iio/driver.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #include "ltc2497.h" diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c index eb9d521e86e5..c1668b5a351e 100644 --- a/drivers/iio/adc/ltc2497.c +++ b/drivers/iio/adc/ltc2497.c @@ -11,7 +11,6 @@ #include <linux/iio/iio.h> #include <linux/iio/driver.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/unaligned.h> @@ -142,8 +141,8 @@ static const struct ltc2497_chip_info ltc2497_info[] = { }; static const struct i2c_device_id ltc2497_id[] = { - { "ltc2497", (kernel_ulong_t)<c2497_info[TYPE_LTC2497] }, - { "ltc2499", (kernel_ulong_t)<c2497_info[TYPE_LTC2499] }, + { .name = "ltc2497", .driver_data = (kernel_ulong_t)<c2497_info[TYPE_LTC2497] }, + { .name = "ltc2499", .driver_data = (kernel_ulong_t)<c2497_info[TYPE_LTC2499] }, { } }; MODULE_DEVICE_TABLE(i2c, ltc2497_id); diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c index 7e736e77d8bb..fb6f12316724 100644 --- a/drivers/iio/adc/max1027.c +++ b/drivers/iio/adc/max1027.c @@ -14,7 +14,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/spi/spi.h> #include <linux/delay.h> @@ -73,12 +72,12 @@ enum max1027_id { }; static const struct spi_device_id max1027_id[] = { - { "max1027", max1027 }, - { "max1029", max1029 }, - { "max1031", max1031 }, - { "max1227", max1227 }, - { "max1229", max1229 }, - { "max1231", max1231 }, + { .name = "max1027", .driver_data = max1027 }, + { .name = "max1029", .driver_data = max1029 }, + { .name = "max1031", .driver_data = max1031 }, + { .name = "max1227", .driver_data = max1227 }, + { .name = "max1229", .driver_data = max1229 }, + { .name = "max1231", .driver_data = max1231 }, { } }; MODULE_DEVICE_TABLE(spi, max1027_id); diff --git a/drivers/iio/adc/max11100.c b/drivers/iio/adc/max11100.c index 520e37f75aac..549dea6bf95c 100644 --- a/drivers/iio/adc/max11100.c +++ b/drivers/iio/adc/max11100.c @@ -8,7 +8,6 @@ */ #include <linux/delay.h> #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> diff --git a/drivers/iio/adc/max1118.c b/drivers/iio/adc/max1118.c index 7d7001e8e3d9..75e51ce3077e 100644 --- a/drivers/iio/adc/max1118.c +++ b/drivers/iio/adc/max1118.c @@ -18,7 +18,6 @@ */ #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/spi/spi.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> @@ -257,9 +256,9 @@ static int max1118_probe(struct spi_device *spi) } static const struct spi_device_id max1118_id[] = { - { "max1117", max1117 }, - { "max1118", max1118 }, - { "max1119", max1119 }, + { .name = "max1117", .driver_data = max1117 }, + { .name = "max1118", .driver_data = max1118 }, + { .name = "max1119", .driver_data = max1119 }, { } }; MODULE_DEVICE_TABLE(spi, max1118_id); diff --git a/drivers/iio/adc/max11205.c b/drivers/iio/adc/max11205.c index 6c803df220b6..63b6561dcf47 100644 --- a/drivers/iio/adc/max11205.c +++ b/drivers/iio/adc/max11205.c @@ -145,8 +145,8 @@ static int max11205_probe(struct spi_device *spi) } static const struct spi_device_id max11205_spi_ids[] = { - { "max11205a", (kernel_ulong_t)&max11205_chip_info[TYPE_MAX11205A] }, - { "max11205b", (kernel_ulong_t)&max11205_chip_info[TYPE_MAX11205B] }, + { .name = "max11205a", .driver_data = (kernel_ulong_t)&max11205_chip_info[TYPE_MAX11205A] }, + { .name = "max11205b", .driver_data = (kernel_ulong_t)&max11205_chip_info[TYPE_MAX11205B] }, { } }; MODULE_DEVICE_TABLE(spi, max11205_spi_ids); diff --git a/drivers/iio/adc/max11410.c b/drivers/iio/adc/max11410.c index 511b2f14dfaf..23ae684cf08b 100644 --- a/drivers/iio/adc/max11410.c +++ b/drivers/iio/adc/max11410.c @@ -804,7 +804,7 @@ static int max11410_parse_channels(struct max11410_state *st, chan_idx++; } - channels[chan_idx] = (struct iio_chan_spec)IIO_CHAN_SOFT_TIMESTAMP(chan_idx); + channels[chan_idx] = IIO_CHAN_SOFT_TIMESTAMP(chan_idx); indio_dev->num_channels = chan_idx + 1; indio_dev->channels = channels; @@ -912,8 +912,8 @@ static int max11410_self_calibrate(struct max11410_state *st) static int max11410_probe(struct spi_device *spi) { - const char *vrefp_regs[] = { "vref0p", "vref1p", "vref2p" }; - const char *vrefn_regs[] = { "vref0n", "vref1n", "vref2n" }; + static const char * const vrefp_regs[] = { "vref0p", "vref1p", "vref2p" }; + static const char * const vrefn_regs[] = { "vref0n", "vref1n", "vref2n" }; struct device *dev = &spi->dev; struct max11410_state *st; struct iio_dev *indio_dev; @@ -1025,7 +1025,7 @@ static const struct of_device_id max11410_spi_of_id[] = { MODULE_DEVICE_TABLE(of, max11410_spi_of_id); static const struct spi_device_id max11410_id[] = { - { "max11410" }, + { .name = "max11410" }, { } }; MODULE_DEVICE_TABLE(spi, max11410_id); diff --git a/drivers/iio/adc/max1241.c b/drivers/iio/adc/max1241.c index d62c1a011659..b3cecbf9a89e 100644 --- a/drivers/iio/adc/max1241.c +++ b/drivers/iio/adc/max1241.c @@ -15,10 +15,6 @@ #define MAX1241_VAL_MASK GENMASK(11, 0) #define MAX1241_SHUTDOWN_DELAY_USEC 4 -enum max1241_id { - max1241, -}; - struct max1241 { struct spi_device *spi; struct mutex lock; @@ -166,7 +162,7 @@ static int max1241_probe(struct spi_device *spi) else dev_dbg(dev, "no shutdown pin passed, low-power mode disabled"); - indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->name = "max1241"; indio_dev->info = &max1241_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = max1241_channels; @@ -176,9 +172,10 @@ static int max1241_probe(struct spi_device *spi) } static const struct spi_device_id max1241_id[] = { - { "max1241", max1241 }, + { .name = "max1241" }, { } }; +MODULE_DEVICE_TABLE(spi, max1241_id); static const struct of_device_id max1241_dt_ids[] = { { .compatible = "maxim,max1241" }, diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 9dd547e62b6c..65a2d92bb112 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -23,7 +23,6 @@ #include <linux/slab.h> #include <linux/err.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/unaligned.h> @@ -121,7 +120,7 @@ enum max1363_modes { }; /** - * struct max1363_chip_info - chip specifc information + * struct max1363_chip_info - chip specific information * @info: iio core function callbacks structure * @channels: channel specification * @num_channels: number of channels @@ -149,7 +148,6 @@ struct max1363_chip_info { * @configbyte: cache of current device config byte * @chip_info: chip model specific constants, available modes, etc. * @current_mode: the scan mode of this chip - * @requestedmask: a valid requested set of channels * @lock: lock to ensure state is consistent * @monitor_on: whether monitor mode is enabled * @monitor_speed: parameter corresponding to device monitor speed setting @@ -169,7 +167,6 @@ struct max1363_state { u8 configbyte; const struct max1363_chip_info *chip_info; const struct max1363_mode *current_mode; - u32 requestedmask; struct mutex lock; /* Using monitor modes and buffer at the same time is @@ -637,48 +634,51 @@ static const enum max1363_modes max11644_mode_list[] = { static const struct iio_chan_spec max11646_channels[] = MAX1363_2X_CHANS(10); static const struct iio_chan_spec max11644_channels[] = MAX1363_2X_CHANS(12); -enum { max1361, - max1362, - max1363, - max1364, - max1036, - max1037, - max1038, - max1039, - max1136, - max1137, - max1138, - max1139, - max1236, - max1237, - max1238, - max1239, - max11600, - max11601, - max11602, - max11603, - max11604, - max11605, - max11606, - max11607, - max11608, - max11609, - max11610, - max11611, - max11612, - max11613, - max11614, - max11615, - max11616, - max11617, - max11644, - max11645, - max11646, - max11647 +enum { + max1361, + max1362, + max1363, + max1364, + max1036, + max1037, + max1038, + max1039, + max1136, + max1137, + max1138, + max1139, + max1236, + max1237, + max1238, + max1239, + max11600, + max11601, + max11602, + max11603, + max11604, + max11605, + max11606, + max11607, + max11608, + max11609, + max11610, + max11611, + max11612, + max11613, + max11614, + max11615, + max11616, + max11617, + max11644, + max11645, + max11646, + max11647, }; -static const int max1363_monitor_speeds[] = { 133000, 665000, 33300, 16600, - 8300, 4200, 2000, 1000 }; +static const int max1363_monitor_speeds[] = { + 133000, 665000, 33300, 16600, + 8300, 4200, 2000, 1000, +}; static ssize_t max1363_monitor_show_freq(struct device *dev, struct device_attribute *attr, diff --git a/drivers/iio/adc/max14001.c b/drivers/iio/adc/max14001.c index 90ad4cb5868d..58adeac62dde 100644 --- a/drivers/iio/adc/max14001.c +++ b/drivers/iio/adc/max14001.c @@ -15,7 +15,6 @@ #include <linux/bits.h> #include <linux/cleanup.h> #include <linux/device.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> @@ -363,8 +362,8 @@ static struct max14001_chip_info max14002_chip_info = { }; static const struct spi_device_id max14001_id_table[] = { - { "max14001", (kernel_ulong_t)&max14001_chip_info }, - { "max14002", (kernel_ulong_t)&max14002_chip_info }, + { .name = "max14001", .driver_data = (kernel_ulong_t)&max14001_chip_info }, + { .name = "max14002", .driver_data = (kernel_ulong_t)&max14002_chip_info }, { } }; diff --git a/drivers/iio/adc/max34408.c b/drivers/iio/adc/max34408.c index 4f45fd22a90c..c96dfed6322d 100644 --- a/drivers/iio/adc/max34408.c +++ b/drivers/iio/adc/max34408.c @@ -12,7 +12,6 @@ #include <linux/init.h> #include <linux/i2c.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/regmap.h> @@ -256,8 +255,8 @@ static const struct of_device_id max34408_of_match[] = { MODULE_DEVICE_TABLE(of, max34408_of_match); static const struct i2c_device_id max34408_id[] = { - { "max34408", (kernel_ulong_t)&max34408_model_data }, - { "max34409", (kernel_ulong_t)&max34409_model_data }, + { .name = "max34408", .driver_data = (kernel_ulong_t)&max34408_model_data }, + { .name = "max34409", .driver_data = (kernel_ulong_t)&max34409_model_data }, { } }; MODULE_DEVICE_TABLE(i2c, max34408_id); diff --git a/drivers/iio/adc/max77541-adc.c b/drivers/iio/adc/max77541-adc.c index 0aa04d143ad4..6e68cad5b5ce 100644 --- a/drivers/iio/adc/max77541-adc.c +++ b/drivers/iio/adc/max77541-adc.c @@ -6,7 +6,6 @@ #include <linux/bitfield.h> #include <linux/iio/iio.h> -#include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/units.h> @@ -175,7 +174,7 @@ static int max77541_adc_probe(struct platform_device *pdev) } static const struct platform_device_id max77541_adc_platform_id[] = { - { "max77541-adc" }, + { .name = "max77541-adc" }, { } }; MODULE_DEVICE_TABLE(platform, max77541_adc_platform_id); diff --git a/drivers/iio/adc/max9611.c b/drivers/iio/adc/max9611.c index 826566d7a85e..45cea84c5d4a 100644 --- a/drivers/iio/adc/max9611.c +++ b/drivers/iio/adc/max9611.c @@ -22,7 +22,6 @@ #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> /* max9611 register addresses */ diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c index 57cff3772ebe..18cb957e7095 100644 --- a/drivers/iio/adc/mcp320x.c +++ b/drivers/iio/adc/mcp320x.c @@ -41,7 +41,6 @@ #include <linux/delay.h> #include <linux/spi/spi.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/iio/iio.h> #include <linux/regulator/consumer.h> @@ -477,19 +476,19 @@ static const struct of_device_id mcp320x_dt_ids[] = { MODULE_DEVICE_TABLE(of, mcp320x_dt_ids); static const struct spi_device_id mcp320x_id[] = { - { "mcp3001", mcp3001 }, - { "mcp3002", mcp3002 }, - { "mcp3004", mcp3004 }, - { "mcp3008", mcp3008 }, - { "mcp3201", mcp3201 }, - { "mcp3202", mcp3202 }, - { "mcp3204", mcp3204 }, - { "mcp3208", mcp3208 }, - { "mcp3301", mcp3301 }, - { "mcp3550-50", mcp3550_50 }, - { "mcp3550-60", mcp3550_60 }, - { "mcp3551", mcp3551 }, - { "mcp3553", mcp3553 }, + { .name = "mcp3001", .driver_data = mcp3001 }, + { .name = "mcp3002", .driver_data = mcp3002 }, + { .name = "mcp3004", .driver_data = mcp3004 }, + { .name = "mcp3008", .driver_data = mcp3008 }, + { .name = "mcp3201", .driver_data = mcp3201 }, + { .name = "mcp3202", .driver_data = mcp3202 }, + { .name = "mcp3204", .driver_data = mcp3204 }, + { .name = "mcp3208", .driver_data = mcp3208 }, + { .name = "mcp3301", .driver_data = mcp3301 }, + { .name = "mcp3550-50", .driver_data = mcp3550_50 }, + { .name = "mcp3550-60", .driver_data = mcp3550_60 }, + { .name = "mcp3551", .driver_data = mcp3551 }, + { .name = "mcp3553", .driver_data = mcp3553 }, { } }; MODULE_DEVICE_TABLE(spi, mcp320x_id); diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c index 50834fdcf738..36ba00edf301 100644 --- a/drivers/iio/adc/mcp3422.c +++ b/drivers/iio/adc/mcp3422.c @@ -13,10 +13,11 @@ * voltage unit is nV. */ +#include <linux/bitfield.h> +#include <linux/bits.h> #include <linux/err.h> #include <linux/i2c.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/delay.h> #include <linux/sysfs.h> #include <linux/unaligned.h> @@ -24,10 +25,10 @@ #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> -/* Masks */ -#define MCP3422_CHANNEL_MASK 0x60 -#define MCP3422_PGA_MASK 0x03 -#define MCP3422_SRATE_MASK 0x0C +#define MCP3422_CHANNEL_MASK GENMASK(6, 5) +#define MCP3422_SRATE_MASK GENMASK(3, 2) +#define MCP3422_PGA_MASK GENMASK(1, 0) + #define MCP3422_SRATE_240 0x0 #define MCP3422_SRATE_60 0x1 #define MCP3422_SRATE_15 0x2 @@ -36,15 +37,7 @@ #define MCP3422_PGA_2 1 #define MCP3422_PGA_4 2 #define MCP3422_PGA_8 3 -#define MCP3422_CONT_SAMPLING 0x10 - -#define MCP3422_CHANNEL(config) (((config) & MCP3422_CHANNEL_MASK) >> 5) -#define MCP3422_PGA(config) ((config) & MCP3422_PGA_MASK) -#define MCP3422_SAMPLE_RATE(config) (((config) & MCP3422_SRATE_MASK) >> 2) - -#define MCP3422_CHANNEL_VALUE(value) (((value) << 5) & MCP3422_CHANNEL_MASK) -#define MCP3422_PGA_VALUE(value) ((value) & MCP3422_PGA_MASK) -#define MCP3422_SAMPLE_RATE_VALUE(value) ((value << 2) & MCP3422_SRATE_MASK) +#define MCP3422_CONT_SAMPLING BIT(4) #define MCP3422_CHAN(_index) \ { \ @@ -108,7 +101,7 @@ static int mcp3422_update_config(struct mcp3422 *adc, u8 newconfig) static int mcp3422_read(struct mcp3422 *adc, int *value, u8 *config) { int ret = 0; - u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config); + u8 sample_rate = FIELD_GET(MCP3422_SRATE_MASK, adc->config); u8 buf[4] = {0, 0, 0, 0}; u32 temp; @@ -136,18 +129,18 @@ static int mcp3422_read_channel(struct mcp3422 *adc, mutex_lock(&adc->lock); - if (req_channel != MCP3422_CHANNEL(adc->config)) { + if (req_channel != FIELD_GET(MCP3422_CHANNEL_MASK, adc->config)) { config = adc->config; - config &= ~MCP3422_CHANNEL_MASK; - config |= MCP3422_CHANNEL_VALUE(req_channel); - config &= ~MCP3422_PGA_MASK; - config |= MCP3422_PGA_VALUE(adc->pga[req_channel]); + + FIELD_MODIFY(MCP3422_CHANNEL_MASK, &config, req_channel); + FIELD_MODIFY(MCP3422_PGA_MASK, &config, adc->pga[req_channel]); + ret = mcp3422_update_config(adc, config); if (ret < 0) { mutex_unlock(&adc->lock); return ret; } - msleep(mcp3422_read_times[MCP3422_SAMPLE_RATE(adc->config)]); + msleep(mcp3422_read_times[FIELD_GET(MCP3422_SRATE_MASK, adc->config)]); } ret = mcp3422_read(adc, value, &config); @@ -163,9 +156,8 @@ static int mcp3422_read_raw(struct iio_dev *iio, { struct mcp3422 *adc = iio_priv(iio); int err; - - u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config); - u8 pga = MCP3422_PGA(adc->config); + u8 sample_rate = FIELD_GET(MCP3422_SRATE_MASK, adc->config); + u8 pga = FIELD_GET(MCP3422_PGA_MASK, adc->config); switch (mask) { case IIO_CHAN_INFO_RAW: @@ -181,7 +173,7 @@ static int mcp3422_read_raw(struct iio_dev *iio, return IIO_VAL_INT_PLUS_NANO; case IIO_CHAN_INFO_SAMP_FREQ: - *val1 = mcp3422_sample_rates[MCP3422_SAMPLE_RATE(adc->config)]; + *val1 = mcp3422_sample_rates[FIELD_GET(MCP3422_SRATE_MASK, adc->config)]; return IIO_VAL_INT; default: @@ -199,7 +191,7 @@ static int mcp3422_write_raw(struct iio_dev *iio, u8 temp; u8 config = adc->config; u8 req_channel = channel->channel; - u8 sample_rate = MCP3422_SAMPLE_RATE(config); + u8 sample_rate = FIELD_GET(MCP3422_SRATE_MASK, config); u8 i; switch (mask) { @@ -211,10 +203,8 @@ static int mcp3422_write_raw(struct iio_dev *iio, if (val2 == mcp3422_scales[sample_rate][i]) { adc->pga[req_channel] = i; - config &= ~MCP3422_CHANNEL_MASK; - config |= MCP3422_CHANNEL_VALUE(req_channel); - config &= ~MCP3422_PGA_MASK; - config |= MCP3422_PGA_VALUE(adc->pga[req_channel]); + FIELD_MODIFY(MCP3422_CHANNEL_MASK, &config, req_channel); + FIELD_MODIFY(MCP3422_PGA_MASK, &config, adc->pga[req_channel]); return mcp3422_update_config(adc, config); } @@ -241,10 +231,8 @@ static int mcp3422_write_raw(struct iio_dev *iio, return -EINVAL; } - config &= ~MCP3422_CHANNEL_MASK; - config |= MCP3422_CHANNEL_VALUE(req_channel); - config &= ~MCP3422_SRATE_MASK; - config |= MCP3422_SAMPLE_RATE_VALUE(temp); + FIELD_MODIFY(MCP3422_CHANNEL_MASK, &config, req_channel); + FIELD_MODIFY(MCP3422_SRATE_MASK, &config, temp); return mcp3422_update_config(adc, config); @@ -283,7 +271,7 @@ static ssize_t mcp3422_show_scales(struct device *dev, struct device_attribute *attr, char *buf) { struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev)); - u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config); + u8 sample_rate = FIELD_GET(MCP3422_SRATE_MASK, adc->config); return sprintf(buf, "0.%09u 0.%09u 0.%09u 0.%09u\n", mcp3422_scales[sample_rate][0], @@ -376,10 +364,10 @@ static int mcp3422_probe(struct i2c_client *client) } /* meaningful default configuration */ - config = (MCP3422_CONT_SAMPLING - | MCP3422_CHANNEL_VALUE(0) - | MCP3422_PGA_VALUE(MCP3422_PGA_1) - | MCP3422_SAMPLE_RATE_VALUE(MCP3422_SRATE_240)); + config = MCP3422_CONT_SAMPLING | + FIELD_PREP(MCP3422_CHANNEL_MASK, 0) | + FIELD_PREP(MCP3422_PGA_MASK, MCP3422_PGA_1) | + FIELD_PREP(MCP3422_SRATE_MASK, MCP3422_SRATE_240); err = mcp3422_update_config(adc, config); if (err < 0) return err; @@ -394,14 +382,14 @@ static int mcp3422_probe(struct i2c_client *client) } static const struct i2c_device_id mcp3422_id[] = { - { "mcp3421", 1 }, - { "mcp3422", 2 }, - { "mcp3423", 3 }, - { "mcp3424", 4 }, - { "mcp3425", 5 }, - { "mcp3426", 6 }, - { "mcp3427", 7 }, - { "mcp3428", 8 }, + { .name = "mcp3421", .driver_data = 1 }, + { .name = "mcp3422", .driver_data = 2 }, + { .name = "mcp3423", .driver_data = 3 }, + { .name = "mcp3424", .driver_data = 4 }, + { .name = "mcp3425", .driver_data = 5 }, + { .name = "mcp3426", .driver_data = 6 }, + { .name = "mcp3427", .driver_data = 7 }, + { .name = "mcp3428", .driver_data = 8 }, { } }; MODULE_DEVICE_TABLE(i2c, mcp3422_id); diff --git a/drivers/iio/adc/mcp3564.c b/drivers/iio/adc/mcp3564.c index fcdf13f49c48..259ac4ebdedf 100644 --- a/drivers/iio/adc/mcp3564.c +++ b/drivers/iio/adc/mcp3564.c @@ -349,7 +349,7 @@ struct mcp3564_chip_info { * struct mcp3564_state - working data for a ADC device * @chip_info: chip specific data * @spi: SPI device structure - * @vref_mv: voltage reference value in miliVolts + * @vref_mv: voltage reference value in millivolts * @lock: synchronize access to driver's state members * @dev_addr: hardware device address * @oversampling: the index inside oversampling list of the ADC @@ -1451,18 +1451,18 @@ static const struct of_device_id mcp3564_dt_ids[] = { MODULE_DEVICE_TABLE(of, mcp3564_dt_ids); static const struct spi_device_id mcp3564_id[] = { - { "mcp3461", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3461] }, - { "mcp3462", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3462] }, - { "mcp3464", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3464] }, - { "mcp3561", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3561] }, - { "mcp3562", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3562] }, - { "mcp3564", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3564] }, - { "mcp3461r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3461r] }, - { "mcp3462r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3462r] }, - { "mcp3464r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3464r] }, - { "mcp3561r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3561r] }, - { "mcp3562r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3562r] }, - { "mcp3564r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3564r] }, + { .name = "mcp3461", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3461] }, + { .name = "mcp3462", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3462] }, + { .name = "mcp3464", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3464] }, + { .name = "mcp3561", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3561] }, + { .name = "mcp3562", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3562] }, + { .name = "mcp3564", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3564] }, + { .name = "mcp3461r", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3461r] }, + { .name = "mcp3462r", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3462r] }, + { .name = "mcp3464r", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3464r] }, + { .name = "mcp3561r", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3561r] }, + { .name = "mcp3562r", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3562r] }, + { .name = "mcp3564r", .driver_data = (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3564r] }, { } }; MODULE_DEVICE_TABLE(spi, mcp3564_id); diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c index ddc3721f3f68..797424f59f74 100644 --- a/drivers/iio/adc/mcp3911.c +++ b/drivers/iio/adc/mcp3911.c @@ -14,7 +14,6 @@ #include <linux/err.h> #include <linux/gpio/consumer.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> @@ -928,13 +927,13 @@ static const struct of_device_id mcp3911_dt_ids[] = { MODULE_DEVICE_TABLE(of, mcp3911_dt_ids); static const struct spi_device_id mcp3911_id[] = { - { "mcp3910", (kernel_ulong_t)&mcp3911_chip_info[MCP3910] }, - { "mcp3911", (kernel_ulong_t)&mcp3911_chip_info[MCP3911] }, - { "mcp3912", (kernel_ulong_t)&mcp3911_chip_info[MCP3912] }, - { "mcp3913", (kernel_ulong_t)&mcp3911_chip_info[MCP3913] }, - { "mcp3914", (kernel_ulong_t)&mcp3911_chip_info[MCP3914] }, - { "mcp3918", (kernel_ulong_t)&mcp3911_chip_info[MCP3918] }, - { "mcp3919", (kernel_ulong_t)&mcp3911_chip_info[MCP3919] }, + { .name = "mcp3910", .driver_data = (kernel_ulong_t)&mcp3911_chip_info[MCP3910] }, + { .name = "mcp3911", .driver_data = (kernel_ulong_t)&mcp3911_chip_info[MCP3911] }, + { .name = "mcp3912", .driver_data = (kernel_ulong_t)&mcp3911_chip_info[MCP3912] }, + { .name = "mcp3913", .driver_data = (kernel_ulong_t)&mcp3911_chip_info[MCP3913] }, + { .name = "mcp3914", .driver_data = (kernel_ulong_t)&mcp3911_chip_info[MCP3914] }, + { .name = "mcp3918", .driver_data = (kernel_ulong_t)&mcp3911_chip_info[MCP3918] }, + { .name = "mcp3919", .driver_data = (kernel_ulong_t)&mcp3911_chip_info[MCP3919] }, { } }; MODULE_DEVICE_TABLE(spi, mcp3911_id); diff --git a/drivers/iio/adc/men_z188_adc.c b/drivers/iio/adc/men_z188_adc.c index 90919d282e7b..5bd334ec5655 100644 --- a/drivers/iio/adc/men_z188_adc.c +++ b/drivers/iio/adc/men_z188_adc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * MEN 16z188 Analog to Digial Converter + * MEN 16z188 Analog to Digital Converter * * Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de) * Author: Johannes Thumshirn <johannes.thumshirn@men.de> diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index 47cd350498a0..000e39ca5c62 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -792,7 +792,7 @@ static int meson_sar_adc_temp_sensor_init(struct iio_dev *indio_dev) size_t read_len; int ret; - temperature_calib = devm_nvmem_cell_get(dev, "temperature_calib"); + temperature_calib = nvmem_cell_get(dev, "temperature_calib"); if (IS_ERR(temperature_calib)) { ret = PTR_ERR(temperature_calib); @@ -806,13 +806,9 @@ static int meson_sar_adc_temp_sensor_init(struct iio_dev *indio_dev) return dev_err_probe(dev, ret, "failed to get temperature_calib cell\n"); } - priv->tsc_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "amlogic,hhi-sysctrl"); - if (IS_ERR(priv->tsc_regmap)) - return dev_err_probe(dev, PTR_ERR(priv->tsc_regmap), - "failed to get amlogic,hhi-sysctrl regmap\n"); - read_len = MESON_SAR_ADC_EFUSE_BYTES; buf = nvmem_cell_read(temperature_calib, &read_len); + nvmem_cell_put(temperature_calib); if (IS_ERR(buf)) return dev_err_probe(dev, PTR_ERR(buf), "failed to read temperature_calib cell\n"); if (read_len != MESON_SAR_ADC_EFUSE_BYTES) { @@ -820,6 +816,13 @@ static int meson_sar_adc_temp_sensor_init(struct iio_dev *indio_dev) return dev_err_probe(dev, -EINVAL, "invalid read size of temperature_calib cell\n"); } + priv->tsc_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "amlogic,hhi-sysctrl"); + if (IS_ERR(priv->tsc_regmap)) { + kfree(buf); + return dev_err_probe(dev, PTR_ERR(priv->tsc_regmap), + "failed to get amlogic,hhi-sysctrl regmap\n"); + } + trimming_bits = priv->param->temperature_trimming_bits; trimming_mask = BIT(trimming_bits) - 1; @@ -1313,6 +1316,11 @@ static const struct meson_sar_adc_data meson_sar_adc_g12a_data = { .name = "meson-g12a-saradc", }; +static const struct meson_sar_adc_data meson_sar_adc_s4_data = { + .param = &meson_sar_adc_g12a_param, + .name = "meson-s4-saradc", +}; + static const struct of_device_id meson_sar_adc_of_match[] = { { .compatible = "amlogic,meson8-saradc", @@ -1341,6 +1349,9 @@ static const struct of_device_id meson_sar_adc_of_match[] = { }, { .compatible = "amlogic,meson-g12a-saradc", .data = &meson_sar_adc_g12a_data, + }, { + .compatible = "amlogic,meson-s4-saradc", + .data = &meson_sar_adc_s4_data, }, { } }; diff --git a/drivers/iio/adc/mp2629_adc.c b/drivers/iio/adc/mp2629_adc.c index 5a1d516f8dad..c03f89ddbd13 100644 --- a/drivers/iio/adc/mp2629_adc.c +++ b/drivers/iio/adc/mp2629_adc.c @@ -11,7 +11,6 @@ #include <linux/iio/iio.h> #include <linux/iio/machine.h> #include <linux/mfd/mp2629.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/platform_device.h> diff --git a/drivers/iio/adc/mt6323-auxadc.c b/drivers/iio/adc/mt6323-auxadc.c new file mode 100644 index 000000000000..4f73ac42abb7 --- /dev/null +++ b/drivers/iio/adc/mt6323-auxadc.c @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2026 Roman Vivchar <rva333@protonmail.com> + * + * Based on drivers/iio/adc/mt6359-auxadc.c + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/delay.h> +#include <linux/iio/iio.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/stringify.h> +#include <linux/time.h> +#include <linux/types.h> + +#include <linux/mfd/mt6323/registers.h> + +#include <dt-bindings/iio/adc/mediatek,mt6323-auxadc.h> + +#define AUXADC_STRUP_CON10_RSTB_SEL BIT(7) +#define AUXADC_STRUP_CON10_RSTB_SW BIT(5) + +#define AUXADC_TOP_CKPDN2_CTL_CK BIT(5) + +#define AUXADC_TRIM_CH2_MASK GENMASK(11, 10) +#define AUXADC_TRIM_CH4_MASK GENMASK(9, 8) +#define AUXADC_TRIM_CH5_MASK GENMASK(5, 4) +#define AUXADC_TRIM_CH6_MASK GENMASK(3, 2) + +#define AUXADC_CON27_VREF18_ENB_MD BIT(15) +#define AUXADC_CON27_MD_STATUS BIT(0) + +#define AUXADC_CON19_GPS_STATUS BIT(1) + +#define AUXADC_CON26_VREF18_SELB BIT(1) +#define AUXADC_CON26_DECI_GDLY_SEL BIT(0) + +#define AUXADC_CON11_VBUF_EN BIT(4) + +#define AUXADC_CON19_DECI_GDLY_MASK GENMASK(15, 14) +#define AUXADC_ADC19_BUSY_MASK GENMASK(15, 1) +#define AUXADC_READY_MASK BIT(15) +#define AUXADC_DATA_MASK GENMASK(14, 0) + +#define AUXADC_CON9_OSR_MASK GENMASK(12, 10) +#define AUXADC_DEFAULT_OSR 3 + +#define MTK_PMIC_IIO_CHAN(_name, _chan, _addr) \ +{ \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = _chan, \ + .address = _addr, \ + .datasheet_name = __stringify(_name), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ +} + +/* + * AUXADC reports everything in mV, including temperature and + * current channels. Channel macros are mapped such that their + * ID matches their respective hardware bit position in CON22. + */ +static const struct iio_chan_spec mt6323_auxadc_channels[] = { + MTK_PMIC_IIO_CHAN(baton2, MT6323_AUXADC_BATON2, MT6323_AUXADC_ADC6), + MTK_PMIC_IIO_CHAN(ch6, MT6323_AUXADC_CH6, MT6323_AUXADC_ADC11), + MTK_PMIC_IIO_CHAN(bat_temp, MT6323_AUXADC_BAT_TEMP, MT6323_AUXADC_ADC5), + MTK_PMIC_IIO_CHAN(chip_temp, MT6323_AUXADC_CHIP_TEMP, MT6323_AUXADC_ADC4), + MTK_PMIC_IIO_CHAN(vcdt, MT6323_AUXADC_VCDT, MT6323_AUXADC_ADC2), + MTK_PMIC_IIO_CHAN(baton1, MT6323_AUXADC_BATON1, MT6323_AUXADC_ADC3), + MTK_PMIC_IIO_CHAN(isense, MT6323_AUXADC_ISENSE, MT6323_AUXADC_ADC1), + MTK_PMIC_IIO_CHAN(batsns, MT6323_AUXADC_BATSNS, MT6323_AUXADC_ADC0), + MTK_PMIC_IIO_CHAN(accdet, MT6323_AUXADC_ACCDET, MT6323_AUXADC_ADC7), +}; + +/* + * The MediaTek MT6323 (as well as a lot of other PMICs) has the following hierarchy: + * PMIC AUXADC <- PMIC MFD <- SoC PWRAP (wrapper for PWRAP FSM) + * + * Therefore, PWRAP regmap should be obtained using dev->parent->parent. + */ +struct mt6323_auxadc { + struct regmap *regmap; + /* AUXADC doesn't support reading multiple channels simultaneously. */ + struct mutex lock; +}; + +static int mt6323_auxadc_prepare_channel(struct mt6323_auxadc *auxadc) +{ + struct regmap *map = auxadc->regmap; + u32 val; + int ret; + + ret = regmap_read(map, MT6323_AUXADC_CON19, &val); + if (ret) + return ret; + + /* The ADC is idle. */ + if (!(val & AUXADC_CON19_DECI_GDLY_MASK)) + return 0; + + ret = regmap_read_poll_timeout(map, MT6323_AUXADC_ADC19, + val, !(val & AUXADC_ADC19_BUSY_MASK), + 10, 500); + if (ret) + return ret; + + return regmap_clear_bits(map, MT6323_AUXADC_CON19, + AUXADC_CON19_DECI_GDLY_MASK); +} + +static int mt6323_auxadc_request(struct mt6323_auxadc *auxadc, + unsigned long channel) +{ + struct regmap *map = auxadc->regmap; + int ret; + + ret = regmap_set_bits(map, MT6323_AUXADC_CON11, AUXADC_CON11_VBUF_EN); + if (ret) + return ret; + + return regmap_set_bits(map, MT6323_AUXADC_CON22, BIT(channel)); +} + +static int mt6323_auxadc_release(struct mt6323_auxadc *auxadc, + unsigned long channel) +{ + struct regmap *map = auxadc->regmap; + int ret; + + ret = regmap_clear_bits(map, MT6323_AUXADC_CON22, BIT(channel)); + if (ret) + return ret; + + return regmap_clear_bits(map, MT6323_AUXADC_CON11, AUXADC_CON11_VBUF_EN); +} + +static int mt6323_auxadc_read(struct mt6323_auxadc *auxadc, + const struct iio_chan_spec *chan, int *out) +{ + struct regmap *map = auxadc->regmap; + u32 val; + int ret; + + ret = regmap_read_poll_timeout(map, chan->address, + val, (val & AUXADC_READY_MASK), + 1 * USEC_PER_MSEC, 100 * USEC_PER_MSEC); + if (ret) + return ret; + + *out = FIELD_GET(AUXADC_DATA_MASK, val); + + return 0; +} + +static int mt6323_auxadc_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct mt6323_auxadc *auxadc = iio_priv(indio_dev); + int ret, mult; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + if (chan->channel == MT6323_AUXADC_ISENSE || + chan->channel == MT6323_AUXADC_BATSNS) + mult = 4; + else + mult = 1; + + /* 1800mV full range with 15-bit resolution. */ + *val = mult * 1800; + *val2 = 15; + + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_RAW: { + guard(mutex)(&auxadc->lock); + + ret = mt6323_auxadc_prepare_channel(auxadc); + if (ret) + return ret; + + ret = mt6323_auxadc_request(auxadc, chan->channel); + if (ret) + return ret; + + /* Hardware limitation: the AUXADC needs a delay to become ready. */ + fsleep(300); + + ret = mt6323_auxadc_read(auxadc, chan, val); + + if (mt6323_auxadc_release(auxadc, chan->channel)) + dev_err(&indio_dev->dev, + "failed to release channel %d\n", chan->channel); + + if (ret) + return ret; + + return IIO_VAL_INT; + } + default: + return -EINVAL; + } +} + +static int mt6323_auxadc_init(struct mt6323_auxadc *auxadc) +{ + struct regmap *map = auxadc->regmap; + int ret; + + ret = regmap_set_bits(map, MT6323_STRUP_CON10, + AUXADC_STRUP_CON10_RSTB_SW | + AUXADC_STRUP_CON10_RSTB_SEL); + if (ret) + return ret; + + ret = regmap_set_bits(map, MT6323_TOP_CKPDN2, AUXADC_TOP_CKPDN2_CTL_CK); + if (ret) + return ret; + + ret = regmap_update_bits(map, MT6323_AUXADC_CON10, + AUXADC_TRIM_CH2_MASK | AUXADC_TRIM_CH4_MASK | + AUXADC_TRIM_CH5_MASK | AUXADC_TRIM_CH6_MASK, + FIELD_PREP(AUXADC_TRIM_CH2_MASK, 1) | + FIELD_PREP(AUXADC_TRIM_CH4_MASK, 1) | + FIELD_PREP(AUXADC_TRIM_CH5_MASK, 1) | + FIELD_PREP(AUXADC_TRIM_CH6_MASK, 1)); + if (ret) + return ret; + + ret = regmap_set_bits(map, MT6323_AUXADC_CON27, + AUXADC_CON27_VREF18_ENB_MD | + AUXADC_CON27_MD_STATUS); + if (ret) + return ret; + + ret = regmap_set_bits(map, MT6323_AUXADC_CON19, AUXADC_CON19_GPS_STATUS); + if (ret) + return ret; + + ret = regmap_set_bits(map, MT6323_AUXADC_CON26, + AUXADC_CON26_VREF18_SELB | + AUXADC_CON26_DECI_GDLY_SEL); + if (ret) + return ret; + + return regmap_update_bits(map, MT6323_AUXADC_CON9, AUXADC_CON9_OSR_MASK, + FIELD_PREP(AUXADC_CON9_OSR_MASK, AUXADC_DEFAULT_OSR)); +} + +static const struct iio_info mt6323_auxadc_iio_info = { + .read_raw = mt6323_auxadc_read_raw, +}; + +static int mt6323_auxadc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mt6323_auxadc *auxadc; + struct regmap *regmap; + struct iio_dev *iio; + int ret; + + regmap = dev_get_regmap(dev->parent->parent, NULL); + if (!regmap) + return dev_err_probe(dev, -ENODEV, "failed to get regmap\n"); + + iio = devm_iio_device_alloc(dev, sizeof(*auxadc)); + if (!iio) + return -ENOMEM; + + auxadc = iio_priv(iio); + auxadc->regmap = regmap; + + ret = devm_mutex_init(dev, &auxadc->lock); + if (ret) + return ret; + + ret = mt6323_auxadc_init(auxadc); + if (ret) + return dev_err_probe(dev, ret, "failed to initialize auxadc\n"); + + iio->name = "mt6323-auxadc"; + iio->info = &mt6323_auxadc_iio_info; + iio->modes = INDIO_DIRECT_MODE; + iio->channels = mt6323_auxadc_channels; + iio->num_channels = ARRAY_SIZE(mt6323_auxadc_channels); + + return devm_iio_device_register(dev, iio); +} + +static const struct of_device_id mt6323_auxadc_of_match[] = { + { .compatible = "mediatek,mt6323-auxadc" }, + { } +}; +MODULE_DEVICE_TABLE(of, mt6323_auxadc_of_match); + +static struct platform_driver mt6323_auxadc_driver = { + .driver = { + .name = "mt6323-auxadc", + .of_match_table = mt6323_auxadc_of_match, + }, + .probe = mt6323_auxadc_probe, +}; +module_platform_driver(mt6323_auxadc_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MediaTek MT6323 PMIC AUXADC Driver"); diff --git a/drivers/iio/adc/mt6359-auxadc.c b/drivers/iio/adc/mt6359-auxadc.c index f426a289e867..88b0e26309e5 100644 --- a/drivers/iio/adc/mt6359-auxadc.c +++ b/drivers/iio/adc/mt6359-auxadc.c @@ -12,7 +12,6 @@ #include <linux/cleanup.h> #include <linux/delay.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <linux/property.h> #include <linux/regmap.h> @@ -322,7 +321,7 @@ static const struct mtk_pmic_auxadc_chan mt6359_auxadc_ch_desc[] = { MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_IMP1, 15, 128, 7, 2), MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, PMIC_AUXADC_IMP1, 15, 8, 5, 2), MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, PMIC_AUXADC_IMP1, 15, 8, 1, 1), - MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, PMIC_AUXADC_IMP1, 15 ,8, 1, 1), + MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, PMIC_AUXADC_IMP1, 15, 8, 1, 1), MTK_PMIC_ADC_CHAN(VDCXO, PMIC_AUXADC_RQST0, 6, PMIC_AUXADC_IMP1, 15, 8, 3, 2), MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, PMIC_AUXADC_IMP1, 15, 128, 1, 1), MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, PMIC_AUXADC_IMP1, 15, 256, 1, 1), @@ -497,6 +496,7 @@ static int mt6358_read_imp(struct mt6359_auxadc *adc_dev, return ret; /* Read the params before stopping */ + val_v = 0; regmap_read(regmap, reg_adc0 + (cinfo->imp_adc_num << 1), &val_v); mt6358_stop_imp_conv(adc_dev); diff --git a/drivers/iio/adc/mt6360-adc.c b/drivers/iio/adc/mt6360-adc.c index e0e4df418612..e59b13e88aa2 100644 --- a/drivers/iio/adc/mt6360-adc.c +++ b/drivers/iio/adc/mt6360-adc.c @@ -5,7 +5,6 @@ #include <linux/irq.h> #include <linux/kernel.h> #include <linux/ktime.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/platform_device.h> diff --git a/drivers/iio/adc/mt6370-adc.c b/drivers/iio/adc/mt6370-adc.c index 7c71fe5e8d31..c250385f9d34 100644 --- a/drivers/iio/adc/mt6370-adc.c +++ b/drivers/iio/adc/mt6370-adc.c @@ -9,7 +9,6 @@ #include <linux/bitfield.h> #include <linux/iio/iio.h> #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/platform_device.h> diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c index fe9e3ece3fda..ecbae90ac2ed 100644 --- a/drivers/iio/adc/mt6577_auxadc.c +++ b/drivers/iio/adc/mt6577_auxadc.c @@ -9,7 +9,6 @@ #include <linux/err.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <linux/property.h> #include <linux/iopoll.h> diff --git a/drivers/iio/adc/nau7802.c b/drivers/iio/adc/nau7802.c index 458544cb8ee4..dccf11fbf88a 100644 --- a/drivers/iio/adc/nau7802.c +++ b/drivers/iio/adc/nau7802.c @@ -8,7 +8,6 @@ #include <linux/delay.h> #include <linux/i2c.h> #include <linux/interrupt.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/property.h> #include <linux/wait.h> @@ -55,7 +54,6 @@ struct nau7802_state { struct mutex data_lock; u32 vref_mv; u32 conversion_count; - u32 min_conversions; u8 sample_rate; u32 scale_avail[8]; struct completion value_ok; @@ -257,7 +255,7 @@ static int nau7802_read_poll(struct iio_dev *indio_dev, /* * Because there is actually only one ADC for both channels, we have to * wait for enough conversions to happen before getting a significant - * value when changing channels and the values are far appart. + * value when changing channels and the values are far apart. */ do { ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL); @@ -532,7 +530,7 @@ static int nau7802_probe(struct i2c_client *client) } static const struct i2c_device_id nau7802_i2c_id[] = { - { "nau7802" }, + { .name = "nau7802" }, { } }; MODULE_DEVICE_TABLE(i2c, nau7802_i2c_id); diff --git a/drivers/iio/adc/nct7201.c b/drivers/iio/adc/nct7201.c index d87824e5490f..bea88a9b9440 100644 --- a/drivers/iio/adc/nct7201.c +++ b/drivers/iio/adc/nct7201.c @@ -12,7 +12,6 @@ #include <linux/dev_printk.h> #include <linux/err.h> #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> #include <linux/time.h> diff --git a/drivers/iio/adc/npcm_adc.c b/drivers/iio/adc/npcm_adc.c index c8283873cdee..a25c15b38759 100644 --- a/drivers/iio/adc/npcm_adc.c +++ b/drivers/iio/adc/npcm_adc.c @@ -8,7 +8,6 @@ #include <linux/iio/iio.h> #include <linux/interrupt.h> #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/property.h> @@ -38,7 +37,7 @@ struct npcm_adc { * read access from userspace. Reading a raw value requires a sequence * of register writes, then a wait for a event and finally a register * read, during which userspace could issue another read request. - * This lock protects a read access from ocurring before another one + * This lock protects a read access from occurring before another one * has finished. */ struct mutex lock; @@ -231,7 +230,7 @@ static int npcm_adc_probe(struct platform_device *pdev) if (IS_ERR(info->reset)) return PTR_ERR(info->reset); - info->adc_clk = devm_clk_get(&pdev->dev, NULL); + info->adc_clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(info->adc_clk)) { dev_warn(&pdev->dev, "ADC clock failed: can't read clk\n"); return PTR_ERR(info->adc_clk); @@ -244,17 +243,13 @@ static int npcm_adc_probe(struct platform_device *pdev) info->adc_sample_hz = clk_get_rate(info->adc_clk) / ((div + 1) * 2); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - goto err_disable_clk; - } + if (irq < 0) + return irq; ret = devm_request_irq(&pdev->dev, irq, npcm_adc_isr, 0, "NPCM_ADC", indio_dev); - if (ret < 0) { - dev_err(dev, "failed requesting interrupt\n"); - goto err_disable_clk; - } + if (ret < 0) + return ret; reg_con = ioread32(info->regs + NPCM_ADCCON); info->vref = devm_regulator_get_optional(&pdev->dev, "vref"); @@ -262,7 +257,7 @@ static int npcm_adc_probe(struct platform_device *pdev) ret = regulator_enable(info->vref); if (ret) { dev_err(&pdev->dev, "Can't enable ADC reference voltage\n"); - goto err_disable_clk; + return ret; } iowrite32(reg_con & ~NPCM_ADCCON_REFSEL, @@ -272,10 +267,8 @@ static int npcm_adc_probe(struct platform_device *pdev) * Any error which is not ENODEV indicates the regulator * has been specified and so is a failure case. */ - if (PTR_ERR(info->vref) != -ENODEV) { - ret = PTR_ERR(info->vref); - goto err_disable_clk; - } + if (PTR_ERR(info->vref) != -ENODEV) + return PTR_ERR(info->vref); /* Use internal reference */ iowrite32(reg_con | NPCM_ADCCON_REFSEL, @@ -314,8 +307,6 @@ err_iio_register: iowrite32(reg_con & ~NPCM_ADCCON_ADC_EN, info->regs + NPCM_ADCCON); if (!IS_ERR(info->vref)) regulator_disable(info->vref); -err_disable_clk: - clk_disable_unprepare(info->adc_clk); return ret; } @@ -332,7 +323,6 @@ static void npcm_adc_remove(struct platform_device *pdev) iowrite32(regtemp & ~NPCM_ADCCON_ADC_EN, info->regs + NPCM_ADCCON); if (!IS_ERR(info->vref)) regulator_disable(info->vref); - clk_disable_unprepare(info->adc_clk); } static struct platform_driver npcm_adc_driver = { diff --git a/drivers/iio/adc/nxp-sar-adc.c b/drivers/iio/adc/nxp-sar-adc.c index 9efa883c277d..894d3211b283 100644 --- a/drivers/iio/adc/nxp-sar-adc.c +++ b/drivers/iio/adc/nxp-sar-adc.c @@ -21,7 +21,6 @@ #include <linux/iopoll.h> #include <linux/math64.h> #include <linux/minmax.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/pm.h> @@ -198,6 +197,15 @@ static void nxp_sar_adc_irq_cfg(struct nxp_sar_adc *info, bool enable) writel(0, NXP_SAR_ADC_IMR(info->regs)); } +static void nxp_sar_adc_wait_for(struct nxp_sar_adc *info, u64 cycles) +{ + u64 rate; + + rate = clk_get_rate(info->clk); + if (rate) + ndelay(div64_u64(NSEC_PER_SEC * cycles, rate)); +} + static bool nxp_sar_adc_set_enabled(struct nxp_sar_adc *info, bool enable) { u32 mcr; @@ -221,7 +229,7 @@ static bool nxp_sar_adc_set_enabled(struct nxp_sar_adc *info, bool enable) * configuration of NCMR and the setting of NSTART. */ if (enable) - ndelay(div64_u64(NSEC_PER_SEC, clk_get_rate(info->clk) * 3)); + nxp_sar_adc_wait_for(info, 3); return pwdn; } @@ -247,7 +255,8 @@ static inline void nxp_sar_adc_calibration_start(void __iomem *base) static inline int nxp_sar_adc_calibration_wait(void __iomem *base) { - u32 msr, ret; + u32 msr; + int ret; ret = readl_poll_timeout(NXP_SAR_ADC_MSR(base), msr, !FIELD_GET(NXP_SAR_ADC_MSR_CALBUSY, msr), @@ -316,11 +325,7 @@ static int nxp_sar_adc_read_data(struct nxp_sar_adc *info, unsigned int chan) ceocfr = readl(NXP_SAR_ADC_CEOCFR0(info->regs)); - /* - * FIELD_GET() can not be used here because EOC_CH is not constant. - * TODO: Switch to field_get() when it will be available. - */ - if (!(NXP_SAR_ADC_EOC_CH(chan) & ceocfr)) + if (!field_get(NXP_SAR_ADC_EOC_CH(chan), ceocfr)) return -EIO; cdr = readl(NXP_SAR_ADC_CDR(info->regs, chan)); @@ -340,6 +345,7 @@ static void nxp_sar_adc_isr_buffer(struct iio_dev *indio_dev) ret = nxp_sar_adc_read_data(info, info->buffered_chan[i]); if (ret < 0) { nxp_sar_adc_read_notify(info); + iio_trigger_notify_done(indio_dev->trig); return; } @@ -468,7 +474,7 @@ static void nxp_sar_adc_stop_conversion(struct nxp_sar_adc *info) * only when the capture finishes. The delay will be very * short, usec-ish, which is acceptable in the atomic context. */ - ndelay(div64_u64(NSEC_PER_SEC, clk_get_rate(info->clk)) * 80); + nxp_sar_adc_wait_for(info, 80); } static int nxp_sar_adc_start_conversion(struct nxp_sar_adc *info, bool raw) @@ -559,6 +565,9 @@ static int nxp_sar_adc_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: + if (val <= 0) + return -EINVAL; + /* * Configures the sample period duration in terms of the SAR * controller clock. The minimum acceptable value is 8. @@ -567,7 +576,11 @@ static int nxp_sar_adc_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec * sampling timing which gives us the number of cycles expected. * The value is 8-bit wide, consequently the max value is 0xFF. */ - inpsamp = clk_get_rate(info->clk) / val - NXP_SAR_ADC_CONV_TIME; + inpsamp = clk_get_rate(info->clk) / val; + if (inpsamp < NXP_SAR_ADC_CONV_TIME) + return -EINVAL; + + inpsamp -= NXP_SAR_ADC_CONV_TIME; nxp_sar_adc_conversion_timing_set(info, inpsamp); return 0; @@ -659,7 +672,7 @@ static void nxp_sar_adc_dma_cb(void *data) static int nxp_sar_adc_start_cyclic_dma(struct iio_dev *indio_dev) { struct nxp_sar_adc *info = iio_priv(indio_dev); - struct dma_slave_config config; + struct dma_slave_config config = { }; struct dma_async_tx_descriptor *desc; int ret; @@ -718,6 +731,10 @@ static int nxp_sar_adc_buffer_software_do_postenable(struct iio_dev *indio_dev) struct nxp_sar_adc *info = iio_priv(indio_dev); int ret; + info->dma_chan = dma_request_chan(indio_dev->dev.parent, "rx"); + if (IS_ERR(info->dma_chan)) + return PTR_ERR(info->dma_chan); + nxp_sar_adc_dma_channels_enable(info, *indio_dev->active_scan_mask); nxp_sar_adc_dma_cfg(info, true); @@ -738,6 +755,7 @@ out_stop_cyclic_dma: out_dma_channels_disable: nxp_sar_adc_dma_cfg(info, false); nxp_sar_adc_dma_channels_disable(info, *indio_dev->active_scan_mask); + dma_release_channel(info->dma_chan); return ret; } @@ -765,10 +783,6 @@ static int nxp_sar_adc_buffer_postenable(struct iio_dev *indio_dev) unsigned long channel; int ret; - info->dma_chan = dma_request_chan(indio_dev->dev.parent, "rx"); - if (IS_ERR(info->dma_chan)) - return PTR_ERR(info->dma_chan); - info->channels_used = 0; /* diff --git a/drivers/iio/adc/pac1921.c b/drivers/iio/adc/pac1921.c index a0227b57f238..f0bab94462f4 100644 --- a/drivers/iio/adc/pac1921.c +++ b/drivers/iio/adc/pac1921.c @@ -856,7 +856,7 @@ static ssize_t pac1921_format_scale_avail(const int (*const scales_tbl)[2], /* * Read available scales for a specific channel * - * NOTE: using extended info insted of iio.read_avail() because access to + * NOTE: using extended info instead of iio.read_avail() because access to * current scales must be locked as they depend on shunt resistor which may * change runtime. Caller of iio.read_avail() would access the table unlocked * instead. @@ -1037,7 +1037,7 @@ static irqreturn_t pac1921_trigger_handler(int irq, void *p) iio_for_each_active_channel(idev, bit) { u16 val; - ret = pac1921_read_res(priv, idev->channels[ch].address, &val); + ret = pac1921_read_res(priv, idev->channels[bit].address, &val); if (ret) goto done; @@ -1310,7 +1310,7 @@ static int pac1921_probe(struct i2c_client *client) } static const struct i2c_device_id pac1921_id[] = { - { .name = "pac1921", 0 }, + { .name = "pac1921" }, { } }; MODULE_DEVICE_TABLE(i2c, pac1921_id); diff --git a/drivers/iio/adc/pac1934.c b/drivers/iio/adc/pac1934.c index 712b5e9caba6..23055405a6e0 100644 --- a/drivers/iio/adc/pac1934.c +++ b/drivers/iio/adc/pac1934.c @@ -1351,7 +1351,7 @@ static int pac1934_prep_iio_channels(struct pac1934_chip_info *info, struct iio_ dyn_ch_struct = devm_kzalloc(dev, channel_size, GFP_KERNEL); if (!dyn_ch_struct) - return -EINVAL; + return -ENOMEM; tmp_data = dyn_ch_struct; diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c index 3f433064618e..f777986a6aba 100644 --- a/drivers/iio/adc/palmas_gpadc.c +++ b/drivers/iio/adc/palmas_gpadc.c @@ -105,7 +105,7 @@ struct palmas_gpadc_thresholds { * of register writes, then a wait for a completion callback, * and finally a register read, during which userspace could issue * another read request. This lock protects a read access from - * ocurring before another one has finished. + * occurring before another one has finished. * * This is the palmas_gpadc structure to store run-time information * and pointers for this driver instance. @@ -521,16 +521,16 @@ static int palmas_gpadc_get_low_threshold_raw(struct palmas_gpadc *adc, val = (val * 1000) / adc->adc_info[adc_chan].gain; - if (adc->adc_info[adc_chan].is_uncalibrated) { + if (adc->adc_info[adc_chan].is_uncalibrated) { /* 2% worse */ min_gain_error -= 20; min_offset_error = -36; - } else { + } else { val = (val * adc->adc_info[adc_chan].gain_error - adc->adc_info[adc_chan].offset) / 1000; min_offset_error = -2; - } + } return palmas_gpadc_threshold_with_tolerance(val, min_INL, diff --git a/drivers/iio/adc/qcom-pm8xxx-xoadc.c b/drivers/iio/adc/qcom-pm8xxx-xoadc.c index 31f88cf7f7f1..3cdf90c4444b 100644 --- a/drivers/iio/adc/qcom-pm8xxx-xoadc.c +++ b/drivers/iio/adc/qcom-pm8xxx-xoadc.c @@ -14,7 +14,6 @@ #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <linux/property.h> #include <linux/regmap.h> @@ -369,7 +368,7 @@ static const struct xoadc_channel pm8921_xoadc_channels[] = { /** * struct pm8xxx_chan_info - ADC channel information - * @name: name of this channel + * @label: label of this channel from device tree (defaults to datasheet name if not specified) * @hwchan: pointer to hardware channel information (muxing & scaling settings) * @calibration: whether to use absolute or ratiometric calibration * @decimation: 0,1,2,3 @@ -377,7 +376,7 @@ static const struct xoadc_channel pm8921_xoadc_channels[] = { * calibration: 0, 1, 2, 4, 5. */ struct pm8xxx_chan_info { - const char *name; + const char *label; const struct xoadc_channel *hwchan; enum vadc_calibration calibration; u8 decimation:2; @@ -446,7 +445,7 @@ static int pm8xxx_read_channel_rsv(struct pm8xxx_xoadc *adc, u8 lsb, msb; dev_dbg(adc->dev, "read channel \"%s\", amux %d, prescale/mux: %d, rsv %d\n", - ch->name, ch->hwchan->amux_channel, ch->hwchan->pre_scale_mux, rsv); + ch->label, ch->hwchan->amux_channel, ch->hwchan->pre_scale_mux, rsv); mutex_lock(&adc->lock); @@ -535,10 +534,7 @@ static int pm8xxx_read_channel_rsv(struct pm8xxx_xoadc *adc, goto unlock; /* Next the interrupt occurs */ - ret = wait_for_completion_timeout(&adc->complete, - VADC_CONV_TIME_MAX_US); - if (!ret) { - dev_err(adc->dev, "conversion timed out\n"); + if (!wait_for_completion_timeout(&adc->complete, VADC_CONV_TIME_MAX_US)) { ret = -ETIMEDOUT; goto unlock; } @@ -657,11 +653,8 @@ static int pm8xxx_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_PROCESSED: ch = pm8xxx_get_channel(adc, chan->address); - if (!ch) { - dev_err(adc->dev, "no such channel %lu\n", - chan->address); + if (!ch) return -EINVAL; - } ret = pm8xxx_read_channel(adc, ch, &adc_code); if (ret) return ret; @@ -677,11 +670,8 @@ static int pm8xxx_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_RAW: ch = pm8xxx_get_channel(adc, chan->address); - if (!ch) { - dev_err(adc->dev, "no such channel %lu\n", - chan->address); + if (!ch) return -EINVAL; - } ret = pm8xxx_read_channel(adc, ch, &adc_code); if (ret) return ret; @@ -725,8 +715,21 @@ static int pm8xxx_fwnode_xlate(struct iio_dev *indio_dev, return -EINVAL; } +static int pm8xxx_read_label(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, char *label) +{ + struct pm8xxx_xoadc *adc = iio_priv(indio_dev); + const struct pm8xxx_chan_info *ch; + + ch = pm8xxx_get_channel(adc, chan->address); + if (!ch) + return -EINVAL; + return sysfs_emit(label, "%s\n", ch->label); +} + static const struct iio_info pm8xxx_xoadc_info = { .fwnode_xlate = pm8xxx_fwnode_xlate, + .read_label = pm8xxx_read_label, .read_raw = pm8xxx_read_raw, }; @@ -770,7 +773,8 @@ static int pm8xxx_xoadc_parse_channel(struct device *dev, pre_scale_mux, amux_channel); return -EINVAL; } - ch->name = name; + ch->label = hwchan->datasheet_name; + fwnode_property_read_string(fwnode, "label", &ch->label); ch->hwchan = hwchan; /* Everyone seems to use absolute calibration except in special cases */ ch->calibration = VADC_CALIB_ABSOLUTE; @@ -812,7 +816,7 @@ static int pm8xxx_xoadc_parse_channel(struct device *dev, dev_dbg(dev, "channel [PRESCALE/MUX: %02x AMUX: %02x] \"%s\" ref voltage: %d, decimation %d prescale %d/%d, scale function %d\n", - hwchan->pre_scale_mux, hwchan->amux_channel, ch->name, + hwchan->pre_scale_mux, hwchan->amux_channel, ch->label, ch->amux_ip_rsv, ch->decimation, hwchan->prescale.numerator, hwchan->prescale.denominator, hwchan->scale_fn_type); diff --git a/drivers/iio/adc/qcom-spmi-adc5-gen3.c b/drivers/iio/adc/qcom-spmi-adc5-gen3.c new file mode 100644 index 000000000000..c68c6c5f6aca --- /dev/null +++ b/drivers/iio/adc/qcom-spmi-adc5-gen3.c @@ -0,0 +1,828 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include <linux/auxiliary_bus.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/completion.h> +#include <linux/container_of.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/device/devres.h> +#include <linux/dev_printk.h> +#include <linux/err.h> +#include <linux/export.h> +#include <linux/iio/adc/qcom-adc5-gen3-common.h> +#include <linux/iio/iio.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/types.h> +#include <linux/unaligned.h> + +#define ADC5_GEN3_VADC_SDAM 0x0 + +struct adc5_chip; + +/** + * struct adc5_channel_prop - ADC channel structure + * @common_props: structure with ADC channel properties (common to TM usage). + * @adc_tm: indicates TM type if the channel is used for TM measurements. + * @chip: pointer to top-level ADC device structure. + */ +struct adc5_channel_prop { + struct adc5_channel_common_prop common_props; + int adc_tm; + struct adc5_chip *chip; +}; + +/** + * struct adc5_chip - ADC private structure. + * @dev: SPMI ADC5 Gen3 device. + * @dev_data: Top-level ADC device data. + * @nchannels: number of ADC channels. + * @chan_props: array of ADC channel properties. + * @iio_chans: array of IIO channels specification. + * @complete: ADC result notification after interrupt is received. + * @lock: ADC lock for access to the peripheral, to prevent concurrent + * requests from multiple clients. + * @data: software configuration data. + * @n_tm_channels: number of ADC channels used for TM measurements. + */ +struct adc5_chip { + struct device *dev; + struct adc5_device_data dev_data; + unsigned int nchannels; + struct adc5_channel_prop *chan_props; + struct iio_chan_spec *iio_chans; + struct completion complete; + struct mutex lock; + const struct adc5_data *data; + unsigned int n_tm_channels; +}; + +int adc5_gen3_read(struct adc5_device_data *adc, unsigned int sdam_index, + u16 offset, u8 *data, int len) +{ + return regmap_bulk_read(adc->regmap, + adc->base[sdam_index].base_addr + offset, + data, len); +} +EXPORT_SYMBOL_NS_GPL(adc5_gen3_read, "QCOM_SPMI_ADC5_GEN3"); + +int adc5_gen3_write(struct adc5_device_data *adc, unsigned int sdam_index, + u16 offset, u8 *data, int len) +{ + return regmap_bulk_write(adc->regmap, + adc->base[sdam_index].base_addr + offset, + data, len); +} +EXPORT_SYMBOL_NS_GPL(adc5_gen3_write, "QCOM_SPMI_ADC5_GEN3"); + +static int adc5_gen3_read_voltage_data(struct adc5_chip *adc, u16 *data) +{ + u8 rslt[2]; + int ret; + + ret = adc5_gen3_read(&adc->dev_data, ADC5_GEN3_VADC_SDAM, + ADC5_GEN3_CH_DATA0(0), rslt, sizeof(rslt)); + if (ret) + return ret; + + *data = get_unaligned_le16(rslt); + + if (*data == ADC5_USR_DATA_CHECK) { + dev_err(adc->dev, "Invalid data:%#x\n", *data); + return -EINVAL; + } + + dev_dbg(adc->dev, "voltage raw code:%#x\n", *data); + + return 0; +} + +void adc5_gen3_update_dig_param(struct adc5_channel_common_prop *prop, u8 *data) +{ + /* Update calibration select and decimation ratio select */ + *data &= ~(ADC5_GEN3_DIG_PARAM_CAL_SEL_MASK | ADC5_GEN3_DIG_PARAM_DEC_RATIO_SEL_MASK); + *data |= FIELD_PREP(ADC5_GEN3_DIG_PARAM_CAL_SEL_MASK, prop->cal_method); + *data |= FIELD_PREP(ADC5_GEN3_DIG_PARAM_DEC_RATIO_SEL_MASK, prop->decimation); +} +EXPORT_SYMBOL_NS_GPL(adc5_gen3_update_dig_param, "QCOM_SPMI_ADC5_GEN3"); + +#define ADC5_GEN3_READ_CONFIG_REGS 7 + +static int adc5_gen3_configure(struct adc5_chip *adc, + struct adc5_channel_common_prop *prop) +{ + u8 buf[ADC5_GEN3_READ_CONFIG_REGS]; + u8 conv_req = 0; + int ret; + + ret = adc5_gen3_read(&adc->dev_data, ADC5_GEN3_VADC_SDAM, ADC5_GEN3_SID, + buf, sizeof(buf)); + if (ret) + return ret; + + /* Write SID */ + buf[0] = FIELD_PREP(ADC5_GEN3_SID_MASK, prop->sid); + + /* + * Use channel 0 by default for immediate conversion and to indicate + * there is an actual conversion request + */ + buf[1] = ADC5_GEN3_CHAN_CONV_REQ | 0; + + buf[2] = ADC5_GEN3_TIME_IMMEDIATE; + + /* Digital param selection */ + adc5_gen3_update_dig_param(prop, &buf[3]); + + /* Update fast average sample value */ + buf[4] = FIELD_PREP(ADC5_GEN3_FAST_AVG_CTL_SAMPLES_MASK, + prop->avg_samples) | ADC5_GEN3_FAST_AVG_CTL_EN; + + /* Select ADC channel */ + buf[5] = prop->channel; + + /* Select HW settle delay for channel */ + buf[6] = FIELD_PREP(ADC5_GEN3_HW_SETTLE_DELAY_MASK, + prop->hw_settle_time_us); + + reinit_completion(&adc->complete); + + ret = adc5_gen3_write(&adc->dev_data, ADC5_GEN3_VADC_SDAM, ADC5_GEN3_SID, + buf, sizeof(buf)); + if (ret) + return ret; + + conv_req = ADC5_GEN3_CONV_REQ_REQ; + return adc5_gen3_write(&adc->dev_data, ADC5_GEN3_VADC_SDAM, + ADC5_GEN3_CONV_REQ, &conv_req, sizeof(conv_req)); +} + +/* + * Worst case delay from PBS in readying handshake bit can be up to 15ms, when + * PBS is busy running other simultaneous transactions, while in the best case, + * it is already ready at this point. Assigning polling delay and retry count + * accordingly. + */ + +#define ADC5_GEN3_HS_DELAY_US 100 +#define ADC5_GEN3_HS_RETRY_COUNT 150 + +int adc5_gen3_poll_wait_hs(struct adc5_device_data *adc, + unsigned int sdam_index) +{ + u8 conv_req = ADC5_GEN3_CONV_REQ_REQ; + int ret, count; + u8 status = 0; + + for (count = 0; count < ADC5_GEN3_HS_RETRY_COUNT; count++) { + ret = adc5_gen3_read(adc, sdam_index, ADC5_GEN3_HS, &status, sizeof(status)); + if (ret) + return ret; + + if (status == ADC5_GEN3_HS_READY) { + ret = adc5_gen3_read(adc, sdam_index, ADC5_GEN3_CONV_REQ, + &conv_req, sizeof(conv_req)); + if (ret) + return ret; + + if (!conv_req) + return 0; + } + + fsleep(ADC5_GEN3_HS_DELAY_US); + } + + pr_err("Setting HS ready bit timed out, sdam_index:%d, status:%#x\n", + sdam_index, status); + return -ETIMEDOUT; +} +EXPORT_SYMBOL_NS_GPL(adc5_gen3_poll_wait_hs, "QCOM_SPMI_ADC5_GEN3"); + +int adc5_gen3_status_clear(struct adc5_device_data *adc, + int sdam_index, u16 offset, u8 *val, int len) +{ + u8 value; + int ret; + + ret = adc5_gen3_write(adc, sdam_index, offset, val, len); + if (ret) + return ret; + + /* To indicate conversion request is only to clear a status */ + value = 0; + ret = adc5_gen3_write(adc, sdam_index, ADC5_GEN3_PERPH_CH, &value, + sizeof(value)); + if (ret) + return ret; + + value = ADC5_GEN3_CONV_REQ_REQ; + return adc5_gen3_write(adc, sdam_index, ADC5_GEN3_CONV_REQ, &value, + sizeof(value)); +} +EXPORT_SYMBOL_NS_GPL(adc5_gen3_status_clear, "QCOM_SPMI_ADC5_GEN3"); + +/* + * Worst case delay from PBS for conversion time can be up to 500ms, when PBS + * has timed out twice, once for the initial attempt and once for a retry of + * the same transaction. + */ + +#define ADC5_GEN3_CONV_TIMEOUT_MS 501 + +static int adc5_gen3_do_conversion(struct adc5_chip *adc, + struct adc5_channel_common_prop *prop, + u16 *data_volt) +{ + unsigned long rc; + int ret; + u8 val; + + guard(mutex)(&adc->lock); + ret = adc5_gen3_poll_wait_hs(&adc->dev_data, ADC5_GEN3_VADC_SDAM); + if (ret) + return ret; + + ret = adc5_gen3_configure(adc, prop); + if (ret) { + dev_err(adc->dev, "ADC configure failed with %d\n", ret); + return ret; + } + + /* No support for polling mode at present */ + rc = wait_for_completion_timeout(&adc->complete, + msecs_to_jiffies(ADC5_GEN3_CONV_TIMEOUT_MS)); + if (!rc) { + dev_err(adc->dev, "Reading ADC channel %s timed out\n", + prop->label); + return -ETIMEDOUT; + } + + ret = adc5_gen3_read_voltage_data(adc, data_volt); + if (ret) + return ret; + + val = BIT(0); + return adc5_gen3_status_clear(&adc->dev_data, ADC5_GEN3_VADC_SDAM, + ADC5_GEN3_EOC_CLR, &val, 1); +} + +static irqreturn_t adc5_gen3_isr(int irq, void *dev_id) +{ + struct adc5_chip *adc = dev_id; + struct device *dev = adc->dev; + u8 status, eoc_status, val; + int ret; + + ret = adc5_gen3_read(&adc->dev_data, ADC5_GEN3_VADC_SDAM, + ADC5_GEN3_STATUS1, &status, sizeof(status)); + if (ret) { + dev_err(dev, "adc read status1 failed with %d\n", ret); + return IRQ_NONE; + } + + ret = adc5_gen3_read(&adc->dev_data, ADC5_GEN3_VADC_SDAM, + ADC5_GEN3_EOC_STS, &eoc_status, sizeof(eoc_status)); + if (ret) { + dev_err(dev, "adc read eoc status failed with %d\n", ret); + return IRQ_NONE; + } + + if (status & ADC5_GEN3_STATUS1_CONV_FAULT) { + dev_err_ratelimited(dev, + "Unexpected conversion fault, status:%#x, eoc_status:%#x\n", + status, eoc_status); + val = ADC5_GEN3_CONV_ERR_CLR_REQ; + adc5_gen3_status_clear(&adc->dev_data, ADC5_GEN3_VADC_SDAM, + ADC5_GEN3_CONV_ERR_CLR, &val, 1); + return IRQ_HANDLED; + } + + dev_dbg(dev, "Interrupt status:%#x, EOC status:%#x\n", status, eoc_status); + + /* CHAN0 is the preconfigured channel for immediate conversion */ + if (!(eoc_status & ADC5_GEN3_EOC_CHAN_0)) + return IRQ_NONE; + + complete(&adc->complete); + return IRQ_HANDLED; +} + +static int adc5_gen3_fwnode_xlate(struct iio_dev *indio_dev, + const struct fwnode_reference_args *iiospec) +{ + struct adc5_chip *adc = iio_priv(indio_dev); + int i, v_channel; + + for (i = 0; i < adc->nchannels; i++) { + v_channel = ADC5_GEN3_V_CHAN(adc->chan_props[i].common_props); + if (v_channel == iiospec->args[0]) + return i; + } + + return -ENOENT; +} + +static int adc5_gen3_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct adc5_chip *adc = iio_priv(indio_dev); + struct adc5_channel_common_prop *prop; + u16 adc_code_volt; + int ret; + + prop = &adc->chan_props[chan->address].common_props; + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + ret = adc5_gen3_do_conversion(adc, prop, &adc_code_volt); + if (ret) + return ret; + + ret = qcom_adc5_hw_scale(prop->scale_fn_type, prop->prescale, + adc->data, adc_code_volt, val); + if (ret) + return ret; + + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int adc5_gen3_read_label(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, char *label) +{ + struct adc5_chip *adc = iio_priv(indio_dev); + struct adc5_channel_prop *prop; + + prop = &adc->chan_props[chan->address]; + return sprintf(label, "%s\n", prop->common_props.label); +} + +static const struct iio_info adc5_gen3_info = { + .read_raw = adc5_gen3_read_raw, + .read_label = adc5_gen3_read_label, + .fwnode_xlate = adc5_gen3_fwnode_xlate, +}; + +struct adc5_channels { + unsigned int prescale_index; + enum iio_chan_type type; + long info_mask; + enum vadc_scale_fn_type scale_fn_type; +}; + +/* In these definitions, _pre refers to an index into adc5_prescale_ratios. */ +#define ADC5_CHAN(_type, _mask, _pre, _scale) \ + { \ + .prescale_index = _pre, \ + .type = _type, \ + .info_mask = _mask, \ + .scale_fn_type = _scale, \ + }, \ + +#define ADC5_CHAN_TEMP(_pre, _scale) \ + ADC5_CHAN(IIO_TEMP, BIT(IIO_CHAN_INFO_PROCESSED), _pre, _scale) \ + +#define ADC5_CHAN_VOLT(_pre, _scale) \ + ADC5_CHAN(IIO_VOLTAGE, BIT(IIO_CHAN_INFO_PROCESSED), _pre, _scale) \ + +#define ADC5_CHAN_CUR(_pre, _scale) \ + ADC5_CHAN(IIO_CURRENT, BIT(IIO_CHAN_INFO_PROCESSED), _pre, _scale) \ + +static const struct adc5_channels adc5_gen3_chans_pmic[ADC5_MAX_CHANNEL] = { + [ADC5_GEN3_REF_GND] = ADC5_CHAN_VOLT(0, SCALE_HW_CALIB_DEFAULT) + [ADC5_GEN3_1P25VREF] = ADC5_CHAN_VOLT(0, SCALE_HW_CALIB_DEFAULT) + [ADC5_GEN3_VPH_PWR] = ADC5_CHAN_VOLT(1, SCALE_HW_CALIB_DEFAULT) + [ADC5_GEN3_VBAT_SNS_QBG] = ADC5_CHAN_VOLT(1, SCALE_HW_CALIB_DEFAULT) + [ADC5_GEN3_USB_SNS_V_16] = ADC5_CHAN_TEMP(8, SCALE_HW_CALIB_DEFAULT) + [ADC5_GEN3_VIN_DIV16_MUX] = ADC5_CHAN_TEMP(8, SCALE_HW_CALIB_DEFAULT) + [ADC5_GEN3_DIE_TEMP] = ADC5_CHAN_TEMP(0, + SCALE_HW_CALIB_PMIC_THERM_PM7) + [ADC5_GEN3_AMUX1_THM_100K_PU] = ADC5_CHAN_TEMP(0, + SCALE_HW_CALIB_THERM_100K_PU_PM7) + [ADC5_GEN3_AMUX2_THM_100K_PU] = ADC5_CHAN_TEMP(0, + SCALE_HW_CALIB_THERM_100K_PU_PM7) + [ADC5_GEN3_AMUX3_THM_100K_PU] = ADC5_CHAN_TEMP(0, + SCALE_HW_CALIB_THERM_100K_PU_PM7) + [ADC5_GEN3_AMUX4_THM_100K_PU] = ADC5_CHAN_TEMP(0, + SCALE_HW_CALIB_THERM_100K_PU_PM7) + [ADC5_GEN3_AMUX5_THM_100K_PU] = ADC5_CHAN_TEMP(0, + SCALE_HW_CALIB_THERM_100K_PU_PM7) + [ADC5_GEN3_AMUX6_THM_100K_PU] = ADC5_CHAN_TEMP(0, + SCALE_HW_CALIB_THERM_100K_PU_PM7) + [ADC5_GEN3_AMUX1_GPIO_100K_PU] = ADC5_CHAN_TEMP(0, + SCALE_HW_CALIB_THERM_100K_PU_PM7) + [ADC5_GEN3_AMUX2_GPIO_100K_PU] = ADC5_CHAN_TEMP(0, + SCALE_HW_CALIB_THERM_100K_PU_PM7) + [ADC5_GEN3_AMUX3_GPIO_100K_PU] = ADC5_CHAN_TEMP(0, + SCALE_HW_CALIB_THERM_100K_PU_PM7) + [ADC5_GEN3_AMUX4_GPIO_100K_PU] = ADC5_CHAN_TEMP(0, + SCALE_HW_CALIB_THERM_100K_PU_PM7) +}; + +static int adc5_gen3_get_fw_channel_data(struct adc5_chip *adc, + struct adc5_channel_prop *prop, + struct fwnode_handle *fwnode) +{ + const char *name = fwnode_get_name(fwnode); + const struct adc5_data *data = adc->data; + struct device *dev = adc->dev; + const char *channel_name; + u32 chan, value, sid; + u32 varr[2]; + int ret; + + ret = fwnode_property_read_u32(fwnode, "reg", &chan); + if (ret < 0) + return dev_err_probe(dev, ret, "invalid channel number %s\n", + name); + + /* + * Value read from "reg" is virtual channel number + * virtual channel number = sid << 8 | channel number + */ + sid = FIELD_GET(ADC5_GEN3_VIRTUAL_SID_MASK, chan); + chan = FIELD_GET(ADC5_GEN3_CHANNEL_MASK, chan); + + if (chan >= ADC5_MAX_CHANNEL) + return dev_err_probe(dev, -EINVAL, + "%s invalid channel number %d\n", + name, chan); + + prop->common_props.channel = chan; + prop->common_props.sid = sid; + + if (!adc->data->adc_chans[chan].info_mask) + return dev_err_probe(dev, -EINVAL, "Channel %#x not supported\n", chan); + + channel_name = name; + fwnode_property_read_string(fwnode, "label", &channel_name); + prop->common_props.label = channel_name; + + value = data->decimation[ADC5_DECIMATION_DEFAULT]; + fwnode_property_read_u32(fwnode, "qcom,decimation", &value); + ret = qcom_adc5_decimation_from_dt(value, data->decimation); + if (ret < 0) + return dev_err_probe(dev, ret, "%#x invalid decimation %d\n", + chan, value); + prop->common_props.decimation = ret; + + prop->common_props.prescale = adc->data->adc_chans[chan].prescale_index; + ret = fwnode_property_read_u32_array(fwnode, "qcom,pre-scaling", varr, 2); + if (!ret) { + ret = qcom_adc5_prescaling_from_dt(varr[0], varr[1]); + if (ret < 0) + return dev_err_probe(dev, ret, + "%#x invalid pre-scaling <%d %d>\n", + chan, varr[0], varr[1]); + prop->common_props.prescale = ret; + } + + value = data->hw_settle_1[VADC_DEF_HW_SETTLE_TIME]; + fwnode_property_read_u32(fwnode, "qcom,hw-settle-time", &value); + ret = qcom_adc5_hw_settle_time_from_dt(value, data->hw_settle_1); + if (ret < 0) + return dev_err_probe(dev, ret, + "%#x invalid hw-settle-time %d us\n", + chan, value); + prop->common_props.hw_settle_time_us = ret; + + value = BIT(VADC_DEF_AVG_SAMPLES); + fwnode_property_read_u32(fwnode, "qcom,avg-samples", &value); + ret = qcom_adc5_avg_samples_from_dt(value); + if (ret < 0) + return dev_err_probe(dev, ret, "%#x invalid avg-samples %d\n", + chan, value); + prop->common_props.avg_samples = ret; + + if (fwnode_property_read_bool(fwnode, "qcom,ratiometric")) + prop->common_props.cal_method = ADC5_RATIOMETRIC_CAL; + else + prop->common_props.cal_method = ADC5_ABSOLUTE_CAL; + + prop->adc_tm = fwnode_property_read_bool(fwnode, "qcom,adc-tm"); + if (prop->adc_tm) { + adc->n_tm_channels++; + if (adc->n_tm_channels > (adc->dev_data.num_sdams * 8 - 1)) + return dev_err_probe(dev, -EINVAL, + "Number of TM nodes %u greater than channels supported:%u\n", + adc->n_tm_channels, + adc->dev_data.num_sdams * 8 - 1); + } + + return 0; +} + +static const struct adc5_data adc5_gen3_data_pmic = { + .full_scale_code_volt = 0x70e4, + .adc_chans = adc5_gen3_chans_pmic, + .info = &adc5_gen3_info, + .decimation = (unsigned int [ADC5_DECIMATION_SAMPLES_MAX]) + { 85, 340, 1360 }, + .hw_settle_1 = (unsigned int [VADC_HW_SETTLE_SAMPLES_MAX]) + { 15, 100, 200, 300, + 400, 500, 600, 700, + 1000, 2000, 4000, 8000, + 16000, 32000, 64000, 128000 }, +}; + +static const struct of_device_id adc5_match_table[] = { + { + .compatible = "qcom,spmi-adc5-gen3", + .data = &adc5_gen3_data_pmic, + }, + { } +}; +MODULE_DEVICE_TABLE(of, adc5_match_table); + +static int adc5_get_fw_data(struct adc5_chip *adc) +{ + const struct adc5_channels *adc_chan; + struct adc5_channel_prop *chan_props; + struct iio_chan_spec *iio_chan; + struct device *dev = adc->dev; + unsigned int index = 0; + int ret; + + adc->nchannels = device_get_child_node_count(dev); + if (!adc->nchannels) + return dev_err_probe(dev, -EINVAL, "No ADC channels found\n"); + + adc->iio_chans = devm_kcalloc(dev, adc->nchannels, + sizeof(*adc->iio_chans), GFP_KERNEL); + if (!adc->iio_chans) + return -ENOMEM; + + adc->chan_props = devm_kcalloc(dev, adc->nchannels, + sizeof(*adc->chan_props), GFP_KERNEL); + if (!adc->chan_props) + return -ENOMEM; + + chan_props = adc->chan_props; + adc->n_tm_channels = 0; + iio_chan = adc->iio_chans; + adc->data = device_get_match_data(dev); + + device_for_each_child_node_scoped(dev, child) { + ret = adc5_gen3_get_fw_channel_data(adc, chan_props, child); + if (ret) + return ret; + + chan_props->chip = adc; + adc_chan = &adc->data->adc_chans[chan_props->common_props.channel]; + chan_props->common_props.scale_fn_type = adc_chan->scale_fn_type; + + iio_chan->channel = ADC5_GEN3_V_CHAN(chan_props->common_props); + iio_chan->info_mask_separate = adc_chan->info_mask; + iio_chan->type = adc_chan->type; + iio_chan->address = index; + iio_chan->indexed = 1; + iio_chan++; + chan_props++; + index++; + } + + return 0; +} + +static void adc5_gen3_uninit_aux(void *data) +{ + auxiliary_device_uninit(data); +} + +static void adc5_gen3_delete_aux(void *data) +{ + auxiliary_device_delete(data); +} + +static void adc5_gen3_aux_device_release(struct device *dev) {} + +static int adc5_gen3_add_aux_tm_device(struct adc5_chip *adc) +{ + struct tm5_aux_dev_wrapper *aux_device; + int i, ret, i_tm = 0; + + aux_device = devm_kzalloc(adc->dev, sizeof(*aux_device), GFP_KERNEL); + if (!aux_device) + return -ENOMEM; + + aux_device->aux_dev.name = "adc5_tm_gen3"; + aux_device->aux_dev.dev.parent = adc->dev; + aux_device->aux_dev.dev.release = adc5_gen3_aux_device_release; + + aux_device->tm_props = devm_kcalloc(adc->dev, adc->n_tm_channels, + sizeof(*aux_device->tm_props), + GFP_KERNEL); + if (!aux_device->tm_props) + return -ENOMEM; + + aux_device->dev_data = &adc->dev_data; + + for (i = 0; i < adc->nchannels; i++) { + if (!adc->chan_props[i].adc_tm) + continue; + aux_device->tm_props[i_tm] = adc->chan_props[i].common_props; + i_tm++; + } + + device_set_of_node_from_dev(&aux_device->aux_dev.dev, adc->dev); + + aux_device->n_tm_channels = adc->n_tm_channels; + + ret = auxiliary_device_init(&aux_device->aux_dev); + if (ret) + return ret; + + ret = devm_add_action_or_reset(adc->dev, adc5_gen3_uninit_aux, + &aux_device->aux_dev); + if (ret) + return ret; + + ret = auxiliary_device_add(&aux_device->aux_dev); + if (ret) + return ret; + ret = devm_add_action_or_reset(adc->dev, adc5_gen3_delete_aux, + &aux_device->aux_dev); + if (ret) + return ret; + + return 0; +} + +void adc5_gen3_mutex_lock(struct device *dev) + __acquires(&adc->lock) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev->parent); + struct adc5_chip *adc = iio_priv(indio_dev); + + mutex_lock(&adc->lock); +} +EXPORT_SYMBOL_NS_GPL(adc5_gen3_mutex_lock, "QCOM_SPMI_ADC5_GEN3"); + +void adc5_gen3_mutex_unlock(struct device *dev) + __releases(&adc->lock) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev->parent); + struct adc5_chip *adc = iio_priv(indio_dev); + + mutex_unlock(&adc->lock); +} +EXPORT_SYMBOL_NS_GPL(adc5_gen3_mutex_unlock, "QCOM_SPMI_ADC5_GEN3"); + +int adc5_gen3_get_scaled_reading(struct device *dev, + struct adc5_channel_common_prop *common_props, + int *val) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev->parent); + struct adc5_chip *adc = iio_priv(indio_dev); + u16 adc_code_volt; + int ret; + + ret = adc5_gen3_do_conversion(adc, common_props, &adc_code_volt); + if (ret) + return ret; + + return qcom_adc5_hw_scale(common_props->scale_fn_type, + common_props->prescale, + adc->data, adc_code_volt, val); +} +EXPORT_SYMBOL_NS_GPL(adc5_gen3_get_scaled_reading, "QCOM_SPMI_ADC5_GEN3"); + +int adc5_gen3_therm_code_to_temp(struct device *dev, + struct adc5_channel_common_prop *common_props, + u16 code, int *val) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev->parent); + struct adc5_chip *adc = iio_priv(indio_dev); + + return qcom_adc5_hw_scale(common_props->scale_fn_type, + common_props->prescale, + adc->data, code, val); +} +EXPORT_SYMBOL_NS_GPL(adc5_gen3_therm_code_to_temp, "QCOM_SPMI_ADC5_GEN3"); + +static int adc5_gen3_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct iio_dev *indio_dev; + struct adc5_chip *adc; + struct regmap *regmap; + int ret, i; + u32 *reg; + + regmap = dev_get_regmap(dev->parent, NULL); + if (!regmap) + return -ENODEV; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*adc)); + if (!indio_dev) + return -ENOMEM; + + adc = iio_priv(indio_dev); + adc->dev_data.regmap = regmap; + adc->dev = dev; + + ret = device_property_count_u32(dev, "reg"); + if (ret < 0) + return ret; + + adc->dev_data.num_sdams = ret; + + reg = devm_kcalloc(dev, adc->dev_data.num_sdams, sizeof(u32), + GFP_KERNEL); + if (!reg) + return -ENOMEM; + + ret = device_property_read_u32_array(dev, "reg", reg, + adc->dev_data.num_sdams); + if (ret) + return dev_err_probe(dev, ret, + "Failed to read reg property\n"); + + adc->dev_data.base = devm_kcalloc(dev, adc->dev_data.num_sdams, + sizeof(*adc->dev_data.base), + GFP_KERNEL); + if (!adc->dev_data.base) + return -ENOMEM; + + platform_set_drvdata(pdev, indio_dev); + init_completion(&adc->complete); + ret = devm_mutex_init(dev, &adc->lock); + if (ret) + return ret; + + for (i = 0; i < adc->dev_data.num_sdams; i++) { + adc->dev_data.base[i].base_addr = reg[i]; + + ret = platform_get_irq(pdev, i); + if (ret < 0) + return dev_err_probe(dev, ret, + "Getting IRQ %d failed\n", i); + + adc->dev_data.base[i].irq = ret; + + adc->dev_data.base[i].irq_name = devm_kasprintf(dev, GFP_KERNEL, + "sdam%d", i); + if (!adc->dev_data.base[i].irq_name) + return -ENOMEM; + } + + /* + * This interrupt is shared with the ADC_TM auxiliary driver, which + * is threaded and uses IRQF_ONESHOT. Since shared interrupts need + * to agree on IRQF_ONESHOT configuration and there is a kernel + * warning for using IRQF_ONESHOT with non-threaded interrupts, + * make this also a threaded IRQ. + */ + ret = devm_request_threaded_irq(dev, adc->dev_data.base[ADC5_GEN3_VADC_SDAM].irq, + NULL, adc5_gen3_isr, IRQF_ONESHOT | IRQF_SHARED, + adc->dev_data.base[ADC5_GEN3_VADC_SDAM].irq_name, + adc); + if (ret) + return ret; + + ret = adc5_get_fw_data(adc); + if (ret) + return ret; + + if (adc->n_tm_channels > 0) { + ret = adc5_gen3_add_aux_tm_device(adc); + if (ret) + dev_err_probe(dev, ret, + "Failed to add auxiliary TM device\n"); + } + + indio_dev->name = "spmi-adc5-gen3"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &adc5_gen3_info; + indio_dev->channels = adc->iio_chans; + indio_dev->num_channels = adc->nchannels; + + return devm_iio_device_register(dev, indio_dev); +} + +static struct platform_driver adc5_gen3_driver = { + .driver = { + .name = "qcom-spmi-adc5-gen3", + .of_match_table = adc5_match_table, + }, + .probe = adc5_gen3_probe, +}; +module_platform_driver(adc5_gen3_driver); + +MODULE_DESCRIPTION("Qualcomm Technologies Inc. PMIC5 Gen3 ADC driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("QCOM_SPMI_ADC5_GEN3"); diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c index af3c2f659f5e..83ecd3adf65f 100644 --- a/drivers/iio/adc/qcom-spmi-adc5.c +++ b/drivers/iio/adc/qcom-spmi-adc5.c @@ -14,7 +14,6 @@ #include <linux/log2.h> #include <linux/math64.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <linux/property.h> #include <linux/regmap.h> diff --git a/drivers/iio/adc/qcom-spmi-iadc.c b/drivers/iio/adc/qcom-spmi-iadc.c index b64a8a407168..0ec3a0c4b1de 100644 --- a/drivers/iio/adc/qcom-spmi-iadc.c +++ b/drivers/iio/adc/qcom-spmi-iadc.c @@ -481,6 +481,11 @@ static const struct iio_chan_spec iadc_channels[] = { }, }; +static void iadc_disable_irq_wake(void *data) +{ + disable_irq_wake((unsigned long)data); +} + static int iadc_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; @@ -538,9 +543,16 @@ static int iadc_probe(struct platform_device *pdev) if (!iadc->poll_eoc) { ret = devm_request_irq(dev, irq_eoc, iadc_isr, 0, "spmi-iadc", iadc); - if (!ret) - enable_irq_wake(irq_eoc); - else + if (ret) + return ret; + + ret = enable_irq_wake(irq_eoc); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, iadc_disable_irq_wake, + (void *)(unsigned long)irq_eoc); + if (ret) return ret; } else { ret = devm_device_init_wakeup(iadc->dev); diff --git a/drivers/iio/adc/qcom-spmi-rradc.c b/drivers/iio/adc/qcom-spmi-rradc.c index 8e75665204d1..1682c6faf62c 100644 --- a/drivers/iio/adc/qcom-spmi-rradc.c +++ b/drivers/iio/adc/qcom-spmi-rradc.c @@ -12,7 +12,6 @@ #include <linux/kernel.h> #include <linux/math64.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <linux/property.h> #include <linux/regmap.h> diff --git a/drivers/iio/adc/qcom-spmi-vadc.c b/drivers/iio/adc/qcom-spmi-vadc.c index 00a7f0982025..d7a2df3c810e 100644 --- a/drivers/iio/adc/qcom-spmi-vadc.c +++ b/drivers/iio/adc/qcom-spmi-vadc.c @@ -13,7 +13,6 @@ #include <linux/kernel.h> #include <linux/math64.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <linux/property.h> #include <linux/regmap.h> diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c index 3a17b3898bf6..d38cf3caeae0 100644 --- a/drivers/iio/adc/rcar-gyroadc.c +++ b/drivers/iio/adc/rcar-gyroadc.c @@ -159,16 +159,6 @@ static const struct iio_chan_spec rcar_gyroadc_iio_channels_3[] = { RCAR_GYROADC_CHAN(7), }; -static int rcar_gyroadc_set_power(struct rcar_gyroadc *priv, bool on) -{ - struct device *dev = priv->dev; - - if (on) - return pm_runtime_resume_and_get(dev); - - return pm_runtime_put_autosuspend(dev); -} - static int rcar_gyroadc_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -200,7 +190,7 @@ static int rcar_gyroadc_read_raw(struct iio_dev *indio_dev, if (!iio_device_claim_direct(indio_dev)) return -EBUSY; - ret = rcar_gyroadc_set_power(priv, true); + ret = pm_runtime_resume_and_get(priv->dev); if (ret < 0) { iio_device_release_direct(indio_dev); return ret; @@ -209,7 +199,7 @@ static int rcar_gyroadc_read_raw(struct iio_dev *indio_dev, *val = readl(priv->regs + datareg); *val &= BIT(priv->sample_width) - 1; - ret = rcar_gyroadc_set_power(priv, false); + ret = pm_runtime_put_autosuspend(priv->dev); iio_device_release_direct(indio_dev); if (ret < 0) return ret; diff --git a/drivers/iio/adc/rohm-bd79112.c b/drivers/iio/adc/rohm-bd79112.c index 7420aa6627d5..2506fec7be84 100644 --- a/drivers/iio/adc/rohm-bd79112.c +++ b/drivers/iio/adc/rohm-bd79112.c @@ -14,7 +14,6 @@ #include <linux/err.h> #include <linux/errno.h> #include <linux/gpio/driver.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> @@ -530,7 +529,7 @@ static const struct of_device_id bd79112_of_match[] = { MODULE_DEVICE_TABLE(of, bd79112_of_match); static const struct spi_device_id bd79112_id[] = { - { "bd79112" }, + { .name = "bd79112" }, { } }; MODULE_DEVICE_TABLE(spi, bd79112_id); diff --git a/drivers/iio/adc/rohm-bd79124.c b/drivers/iio/adc/rohm-bd79124.c index fc0452749b79..ed5427288961 100644 --- a/drivers/iio/adc/rohm-bd79124.c +++ b/drivers/iio/adc/rohm-bd79124.c @@ -19,7 +19,6 @@ #include <linux/interrupt.h> #include <linux/irqreturn.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/regmap.h> #include <linux/types.h> @@ -75,7 +74,7 @@ /* * The high limit, low limit and last measurement result are each stored in - * 2 consequtive registers. 4 bits are in the high bits of the first register + * 2 consecutive registers. 4 bits are in the high bits of the first register * and 8 bits in the next register. * * These macros return the address of the first reg for the given channel. @@ -962,7 +961,7 @@ static int bd79124_hw_init(struct bd79124_data *data) if (ret) return ret; - /* Enable writing the measured values to the regsters */ + /* Enable writing the measured values to the registers */ ret = regmap_set_bits(data->map, BD79124_REG_GEN_CFG, BD79124_MSK_STATS_EN); if (ret) @@ -1104,7 +1103,7 @@ static const struct of_device_id bd79124_of_match[] = { MODULE_DEVICE_TABLE(of, bd79124_of_match); static const struct i2c_device_id bd79124_id[] = { - { "bd79124" }, + { .name = "bd79124" }, { } }; MODULE_DEVICE_TABLE(i2c, bd79124_id); diff --git a/drivers/iio/adc/rtq6056.c b/drivers/iio/adc/rtq6056.c index 2bf3a09ac6b0..2083c4351e43 100644 --- a/drivers/iio/adc/rtq6056.c +++ b/drivers/iio/adc/rtq6056.c @@ -9,7 +9,6 @@ #include <linux/delay.h> #include <linux/i2c.h> #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/property.h> @@ -728,7 +727,7 @@ static int rtq6056_probe(struct i2c_client *i2c) if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_WORD_DATA)) return -EOPNOTSUPP; - devdata = device_get_match_data(dev); + devdata = i2c_get_match_data(i2c); if (!devdata) return dev_err_probe(dev, -EINVAL, "Invalid dev data\n"); @@ -871,6 +870,13 @@ static const struct richtek_dev_data rtq6059_devdata = { .set_average = rtq6059_adc_set_average, }; +static const struct i2c_device_id rtq6056_id[] = { + { .name = "rtq6056", .driver_data = (kernel_ulong_t)&rtq6056_devdata }, + { .name = "rtq6059", .driver_data = (kernel_ulong_t)&rtq6059_devdata }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rtq6056_id); + static const struct of_device_id rtq6056_device_match[] = { { .compatible = "richtek,rtq6056", .data = &rtq6056_devdata }, { .compatible = "richtek,rtq6059", .data = &rtq6059_devdata }, @@ -885,6 +891,7 @@ static struct i2c_driver rtq6056_driver = { .pm = pm_ptr(&rtq6056_pm_ops), }, .probe = rtq6056_probe, + .id_table = rtq6056_id, }; module_i2c_driver(rtq6056_driver); diff --git a/drivers/iio/adc/rzg2l_adc.c b/drivers/iio/adc/rzg2l_adc.c index 1010e0511b3e..408fbf8c29cc 100644 --- a/drivers/iio/adc/rzg2l_adc.c +++ b/drivers/iio/adc/rzg2l_adc.c @@ -16,7 +16,6 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/iopoll.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> diff --git a/drivers/iio/adc/rzn1-adc.c b/drivers/iio/adc/rzn1-adc.c index 93b0feef8ea0..f921cd49b789 100644 --- a/drivers/iio/adc/rzn1-adc.c +++ b/drivers/iio/adc/rzn1-adc.c @@ -21,7 +21,6 @@ #include <linux/iio/iio.h> #include <linux/io.h> #include <linux/iopoll.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/platform_device.h> diff --git a/drivers/iio/adc/rzt2h_adc.c b/drivers/iio/adc/rzt2h_adc.c index 33ce5cc44ff4..4e0eb02d3d14 100644 --- a/drivers/iio/adc/rzt2h_adc.c +++ b/drivers/iio/adc/rzt2h_adc.c @@ -9,7 +9,6 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/iopoll.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> diff --git a/drivers/iio/adc/sd_adc_modulator.c b/drivers/iio/adc/sd_adc_modulator.c index 9f7a75168aac..def44d8831dc 100644 --- a/drivers/iio/adc/sd_adc_modulator.c +++ b/drivers/iio/adc/sd_adc_modulator.c @@ -10,7 +10,6 @@ #include <linux/iio/iio.h> #include <linux/iio/triggered_buffer.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <linux/property.h> #include <linux/regulator/consumer.h> @@ -77,6 +76,7 @@ static const struct iio_backend_ops sd_backend_ops = { static const struct iio_backend_info sd_backend_info = { .name = "sd-modulator", .ops = &sd_backend_ops, + .caps = IIO_BACKEND_CAP_ENABLE, }; static int iio_sd_mod_register(struct platform_device *pdev) diff --git a/drivers/iio/adc/sophgo-cv1800b-adc.c b/drivers/iio/adc/sophgo-cv1800b-adc.c index 0951deb7b111..bdc3e1326a9a 100644 --- a/drivers/iio/adc/sophgo-cv1800b-adc.c +++ b/drivers/iio/adc/sophgo-cv1800b-adc.c @@ -15,7 +15,6 @@ #include <linux/err.h> #include <linux/interrupt.h> #include <linux/iopoll.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/platform_device.h> diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c index 50b0a607baeb..91c0fb1f4da7 100644 --- a/drivers/iio/adc/spear_adc.c +++ b/drivers/iio/adc/spear_adc.c @@ -5,22 +5,24 @@ * Copyright 2012 Stefan Roese <sr@denx.de> */ -#include <linux/mod_devicetable.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/property.h> -#include <linux/interrupt.h> -#include <linux/device.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/io.h> +#include <linux/array_size.h> #include <linux/bitfield.h> +#include <linux/bits.h> #include <linux/clk.h> -#include <linux/err.h> #include <linux/completion.h> +#include <linux/dev_printk.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/math.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/types.h> #include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> +#include <linux/iio/types.h> /* SPEAR registers definitions */ #define SPEAR600_ADC_SCAN_RATE_LO(x) ((x) & 0xFFFF) @@ -82,7 +84,7 @@ struct spear_adc_state { * of register writes, then a wait for a completion callback, * and finally a register read, during which userspace could issue * another read request. This lock protects a read access from - * ocurring before another one has finished. + * occurring before another one has finished. */ struct mutex lock; u32 current_clk; @@ -280,6 +282,7 @@ static int spear_adc_probe(struct platform_device *pdev) st = iio_priv(indio_dev); st->dev = dev; + init_completion(&st->completion); mutex_init(&st->lock); /* @@ -326,8 +329,6 @@ static int spear_adc_probe(struct platform_device *pdev) spear_adc_configure(st); - init_completion(&st->completion); - indio_dev->name = SPEAR_ADC_MOD_NAME; indio_dev->info = &spear_adc_info; indio_dev->modes = INDIO_DIRECT_MODE; diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c index e39a4c0db25e..a42d82d61cb8 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -227,7 +227,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, if (priv->aclk) { /* * Asynchronous clock modes (e.g. ckmode == 0) - * From spec: PLL output musn't exceed max rate + * From spec: PLL output mustn't exceed max rate */ rate = clk_get_rate(priv->aclk); if (!rate) { diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 2d7f88459c7c..5c6c06b269be 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -23,7 +23,6 @@ #include <linux/io.h> #include <linux/iopoll.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/nvmem-consumer.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> @@ -1662,7 +1661,7 @@ static irqreturn_t stm32_adc_threaded_isr(int irq, void *data) /* * Clear ovr bit to avoid subsequent calls to IRQ handler. * This requires to stop ADC first. OVR bit state in ISR, - * is propaged to CSR register by hardware. + * is propagated to CSR register by hardware. */ adc->cfg->stop_conv(indio_dev); stm32_adc_irq_clear(indio_dev, regs->isr_ovr.mask); @@ -2443,15 +2442,7 @@ static int stm32_adc_chan_fw_init(struct iio_dev *indio_dev, bool timestamping) scan_index = ret; if (timestamping) { - struct iio_chan_spec *timestamp = &channels[scan_index]; - - timestamp->type = IIO_TIMESTAMP; - timestamp->channel = -1; - timestamp->scan_index = scan_index; - timestamp->scan_type.sign = 's'; - timestamp->scan_type.realbits = 64; - timestamp->scan_type.storagebits = 64; - + channels[scan_index] = IIO_CHAN_SOFT_TIMESTAMP(scan_index); scan_index++; } diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index 9664b9bd75d4..00f05e167afc 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -660,11 +660,8 @@ static int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm, } df_ch->src = val; - ret = of_property_read_u32_index(indio_dev->dev.of_node, - "st,adc-alt-channel", chan_idx, - &df_ch->alt_si); - if (ret < 0) - df_ch->alt_si = 0; + df_ch->alt_si = of_property_present(indio_dev->dev.of_node, + "st,adc-alt-channel"); return 0; } @@ -1815,9 +1812,8 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) adc->dfsdm->fl_list[adc->fl_id].ford = val; - ret = of_property_read_u32(dev->of_node, "st,filter0-sync", &val); - if (!ret) - adc->dfsdm->fl_list[adc->fl_id].sync_mode = val; + adc->dfsdm->fl_list[adc->fl_id].sync_mode = + of_property_read_bool(dev->of_node, "st,filter0-sync"); adc->dev_data = dev_data; ret = dev_data->init(dev, iio); diff --git a/drivers/iio/adc/sun20i-gpadc-iio.c b/drivers/iio/adc/sun20i-gpadc-iio.c index e4dfe76e6362..baa7661db13b 100644 --- a/drivers/iio/adc/sun20i-gpadc-iio.c +++ b/drivers/iio/adc/sun20i-gpadc-iio.c @@ -9,7 +9,6 @@ #include <linux/completion.h> #include <linux/interrupt.h> #include <linux/io.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/property.h> @@ -55,7 +54,7 @@ struct sun20i_gpadc_iio { * of register writes, then a wait for a completion callback, * and finally a register read, during which userspace could issue * another read request. This lock protects a read access from - * ocurring before another one has finished. + * occurring before another one has finished. */ struct mutex lock; }; @@ -139,8 +138,23 @@ static irqreturn_t sun20i_gpadc_irq_handler(int irq, void *data) return IRQ_HANDLED; } +static int +sun20i_gpadc_fwnode_xlate(struct iio_dev *indio_dev, + const struct fwnode_reference_args *iiospec) +{ + if (iiospec->nargs != 1) + return -EINVAL; + + for (unsigned int i = 0; i < indio_dev->num_channels; i++) + if (indio_dev->channels[i].channel == iiospec->args[0]) + return i; + + return -EINVAL; +} + static const struct iio_info sun20i_gpadc_iio_info = { .read_raw = sun20i_gpadc_read_raw, + .fwnode_xlate = sun20i_gpadc_fwnode_xlate, }; static void sun20i_gpadc_reset_assert(void *data) @@ -177,10 +191,10 @@ static int sun20i_gpadc_alloc_channels(struct iio_dev *indio_dev, static int sun20i_gpadc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct iio_dev *indio_dev; struct sun20i_gpadc_iio *info; + struct clk_bulk_data *clks; struct reset_control *rst; - struct clk *clk; + struct iio_dev *indio_dev; int irq; int ret; @@ -205,9 +219,11 @@ static int sun20i_gpadc_probe(struct platform_device *pdev) if (IS_ERR(info->regs)) return PTR_ERR(info->regs); - clk = devm_clk_get_enabled(dev, NULL); - if (IS_ERR(clk)) - return dev_err_probe(dev, PTR_ERR(clk), "failed to enable bus clock\n"); + ret = devm_clk_bulk_get_all_enabled(dev, &clks); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to enable clocks\n"); + if (ret == 0) + return dev_err_probe(dev, -ENODEV, "needs at least one clocks\n"); rst = devm_reset_control_get_exclusive(dev, NULL); if (IS_ERR(rst)) @@ -243,6 +259,7 @@ static int sun20i_gpadc_probe(struct platform_device *pdev) static const struct of_device_id sun20i_gpadc_of_id[] = { { .compatible = "allwinner,sun20i-d1-gpadc" }, + { .compatible = "allwinner,sun55i-a523-gpadc" }, { } }; MODULE_DEVICE_TABLE(of, sun20i_gpadc_of_id); diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c index 479115ea50bf..203459ca9907 100644 --- a/drivers/iio/adc/sun4i-gpadc-iio.c +++ b/drivers/iio/adc/sun4i-gpadc-iio.c @@ -679,9 +679,9 @@ static void sun4i_gpadc_remove(struct platform_device *pdev) } static const struct platform_device_id sun4i_gpadc_id[] = { - { "sun4i-a10-gpadc-iio", (kernel_ulong_t)&sun4i_gpadc_data }, - { "sun5i-a13-gpadc-iio", (kernel_ulong_t)&sun5i_gpadc_data }, - { "sun6i-a31-gpadc-iio", (kernel_ulong_t)&sun6i_gpadc_data }, + { .name = "sun4i-a10-gpadc-iio", .driver_data = (kernel_ulong_t)&sun4i_gpadc_data }, + { .name = "sun5i-a13-gpadc-iio", .driver_data = (kernel_ulong_t)&sun5i_gpadc_data }, + { .name = "sun6i-a31-gpadc-iio", .driver_data = (kernel_ulong_t)&sun6i_gpadc_data }, { } }; MODULE_DEVICE_TABLE(platform, sun4i_gpadc_id); diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c index 8ef51c57912d..2df8f1c21c2a 100644 --- a/drivers/iio/adc/ti-adc081c.c +++ b/drivers/iio/adc/ti-adc081c.c @@ -18,7 +18,6 @@ #include <linux/err.h> #include <linux/i2c.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/iio/iio.h> @@ -190,18 +189,16 @@ static int adc081c_probe(struct i2c_client *client) 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"); - return err; - } + if (err < 0) + return dev_err_probe(&client->dev, err, "iio triggered buffer setup failed\n"); return devm_iio_device_register(&client->dev, iio); } static const struct i2c_device_id adc081c_id[] = { - { "adc081c", (kernel_ulong_t)&adc081c_model }, - { "adc101c", (kernel_ulong_t)&adc101c_model }, - { "adc121c", (kernel_ulong_t)&adc121c_model }, + { .name = "adc081c", .driver_data = (kernel_ulong_t)&adc081c_model }, + { .name = "adc101c", .driver_data = (kernel_ulong_t)&adc101c_model }, + { .name = "adc121c", .driver_data = (kernel_ulong_t)&adc121c_model }, { } }; MODULE_DEVICE_TABLE(i2c, adc081c_id); diff --git a/drivers/iio/adc/ti-adc0832.c b/drivers/iio/adc/ti-adc0832.c index cfcdafbe284b..a522d8676034 100644 --- a/drivers/iio/adc/ti-adc0832.c +++ b/drivers/iio/adc/ti-adc0832.c @@ -8,7 +8,6 @@ */ #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/spi/spi.h> #include <linux/iio/iio.h> #include <linux/regulator/consumer.h> @@ -314,10 +313,10 @@ static const struct of_device_id adc0832_dt_ids[] = { MODULE_DEVICE_TABLE(of, adc0832_dt_ids); static const struct spi_device_id adc0832_id[] = { - { "adc0831", adc0831 }, - { "adc0832", adc0832 }, - { "adc0834", adc0834 }, - { "adc0838", adc0838 }, + { .name = "adc0831", .driver_data = adc0831 }, + { .name = "adc0832", .driver_data = adc0832 }, + { .name = "adc0834", .driver_data = adc0834 }, + { .name = "adc0838", .driver_data = adc0838 }, { } }; MODULE_DEVICE_TABLE(spi, adc0832_id); diff --git a/drivers/iio/adc/ti-adc084s021.c b/drivers/iio/adc/ti-adc084s021.c index a100f770fa1c..cf2f6ee59411 100644 --- a/drivers/iio/adc/ti-adc084s021.c +++ b/drivers/iio/adc/ti-adc084s021.c @@ -10,7 +10,6 @@ #include <linux/err.h> #include <linux/spi/spi.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/interrupt.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> @@ -229,10 +228,8 @@ static int adc084s021_probe(struct spi_device *spi) ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL, adc084s021_buffer_trigger_handler, &adc084s021_buffer_setup_ops); - if (ret) { - dev_err(&spi->dev, "Failed to setup triggered buffer\n"); - return ret; - } + if (ret) + return dev_err_probe(&spi->dev, ret, "Failed to setup triggered buffer\n"); return devm_iio_device_register(&spi->dev, indio_dev); } @@ -244,7 +241,7 @@ static const struct of_device_id adc084s021_of_match[] = { MODULE_DEVICE_TABLE(of, adc084s021_of_match); static const struct spi_device_id adc084s021_id[] = { - { ADC084S021_DRIVER_NAME, 0 }, + { .name = ADC084S021_DRIVER_NAME }, { } }; MODULE_DEVICE_TABLE(spi, adc084s021_id); diff --git a/drivers/iio/adc/ti-adc108s102.c b/drivers/iio/adc/ti-adc108s102.c index 7d615e2bbf39..10959e835cb8 100644 --- a/drivers/iio/adc/ti-adc108s102.c +++ b/drivers/iio/adc/ti-adc108s102.c @@ -20,7 +20,6 @@ #include <linux/iio/trigger_consumer.h> #include <linux/interrupt.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> @@ -277,7 +276,7 @@ static const struct acpi_device_id adc108s102_acpi_ids[] = { MODULE_DEVICE_TABLE(acpi, adc108s102_acpi_ids); static const struct spi_device_id adc108s102_id[] = { - { "adc108s102", 0 }, + { .name = "adc108s102" }, { } }; MODULE_DEVICE_TABLE(spi, adc108s102_id); diff --git a/drivers/iio/adc/ti-adc12138.c b/drivers/iio/adc/ti-adc12138.c index e5ec4b073daa..279e4999eb49 100644 --- a/drivers/iio/adc/ti-adc12138.c +++ b/drivers/iio/adc/ti-adc12138.c @@ -516,9 +516,9 @@ static const struct of_device_id adc12138_dt_ids[] = { MODULE_DEVICE_TABLE(of, adc12138_dt_ids); static const struct spi_device_id adc12138_id[] = { - { "adc12130", adc12130 }, - { "adc12132", adc12132 }, - { "adc12138", adc12138 }, + { .name = "adc12130", .driver_data = adc12130 }, + { .name = "adc12132", .driver_data = adc12132 }, + { .name = "adc12138", .driver_data = adc12138 }, { } }; MODULE_DEVICE_TABLE(spi, adc12138_id); diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c index 4ae65793ad9b..1899813c1aee 100644 --- a/drivers/iio/adc/ti-adc128s052.c +++ b/drivers/iio/adc/ti-adc128s052.c @@ -12,7 +12,6 @@ #include <linux/cleanup.h> #include <linux/err.h> #include <linux/iio/iio.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/property.h> #include <linux/regulator/consumer.h> @@ -248,18 +247,18 @@ static const struct of_device_id adc128_of_match[] = { MODULE_DEVICE_TABLE(of, adc128_of_match); static const struct spi_device_id adc128_id[] = { - { "adc128s052", (kernel_ulong_t)&adc128s_config }, - { "adc122s021", (kernel_ulong_t)&adc122s_config }, - { "adc122s051", (kernel_ulong_t)&adc122s_config }, - { "adc122s101", (kernel_ulong_t)&adc122s_config }, - { "adc124s021", (kernel_ulong_t)&adc124s_config }, - { "adc124s051", (kernel_ulong_t)&adc124s_config }, - { "adc124s101", (kernel_ulong_t)&adc124s_config }, - { "bd79100", (kernel_ulong_t)&bd79100_config }, - { "bd79101", (kernel_ulong_t)&bd79101_config }, - { "bd79102", (kernel_ulong_t)&bd79102_config }, - { "bd79103", (kernel_ulong_t)&bd79104_config }, - { "bd79104", (kernel_ulong_t)&bd79104_config }, + { .name = "adc128s052", .driver_data = (kernel_ulong_t)&adc128s_config }, + { .name = "adc122s021", .driver_data = (kernel_ulong_t)&adc122s_config }, + { .name = "adc122s051", .driver_data = (kernel_ulong_t)&adc122s_config }, + { .name = "adc122s101", .driver_data = (kernel_ulong_t)&adc122s_config }, + { .name = "adc124s021", .driver_data = (kernel_ulong_t)&adc124s_config }, + { .name = "adc124s051", .driver_data = (kernel_ulong_t)&adc124s_config }, + { .name = "adc124s101", .driver_data = (kernel_ulong_t)&adc124s_config }, + { .name = "bd79100", .driver_data = (kernel_ulong_t)&bd79100_config }, + { .name = "bd79101", .driver_data = (kernel_ulong_t)&bd79101_config }, + { .name = "bd79102", .driver_data = (kernel_ulong_t)&bd79102_config }, + { .name = "bd79103", .driver_data = (kernel_ulong_t)&bd79104_config }, + { .name = "bd79104", .driver_data = (kernel_ulong_t)&bd79104_config }, { } }; MODULE_DEVICE_TABLE(spi, adc128_id); diff --git a/drivers/iio/adc/ti-adc161s626.c b/drivers/iio/adc/ti-adc161s626.c index 28aa6b80160c..422df0685580 100644 --- a/drivers/iio/adc/ti-adc161s626.c +++ b/drivers/iio/adc/ti-adc161s626.c @@ -11,10 +11,10 @@ */ #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/init.h> #include <linux/err.h> #include <linux/spi/spi.h> +#include <linux/unaligned.h> #include <linux/iio/iio.h> #include <linux/iio/trigger.h> #include <linux/iio/buffer.h> @@ -70,8 +70,7 @@ struct ti_adc_data { u8 read_size; u8 shift; - - u8 buffer[16] __aligned(IIO_DMA_MINALIGN); + u8 buf[3] __aligned(IIO_DMA_MINALIGN); }; static int ti_adc_read_measurement(struct ti_adc_data *data, @@ -80,26 +79,20 @@ static int ti_adc_read_measurement(struct ti_adc_data *data, int ret; switch (data->read_size) { - case 2: { - __be16 buf; - - ret = spi_read(data->spi, (void *) &buf, 2); + case 2: + ret = spi_read(data->spi, data->buf, 2); if (ret) return ret; - *val = be16_to_cpu(buf); + *val = get_unaligned_be16(data->buf); break; - } - case 3: { - __be32 buf; - - ret = spi_read(data->spi, (void *) &buf, 3); + case 3: + ret = spi_read(data->spi, data->buf, 3); if (ret) return ret; - *val = be32_to_cpu(buf) >> 8; + *val = get_unaligned_be24(data->buf); break; - } default: return -EINVAL; } @@ -114,15 +107,20 @@ static irqreturn_t ti_adc_trigger_handler(int irq, void *private) struct iio_poll_func *pf = private; struct iio_dev *indio_dev = pf->indio_dev; struct ti_adc_data *data = iio_priv(indio_dev); - int ret; + struct { + s16 data; + aligned_s64 timestamp; + } scan = { }; + int ret, val; + + ret = ti_adc_read_measurement(data, &indio_dev->channels[0], &val); + if (ret) + goto exit_notify_done; - ret = ti_adc_read_measurement(data, &indio_dev->channels[0], - (int *) &data->buffer); - if (!ret) - iio_push_to_buffers_with_timestamp(indio_dev, - data->buffer, - iio_get_time_ns(indio_dev)); + scan.data = val; + iio_push_to_buffers_with_timestamp(indio_dev, &scan, iio_get_time_ns(indio_dev)); + exit_notify_done: iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; @@ -231,8 +229,8 @@ static const struct of_device_id ti_adc_dt_ids[] = { MODULE_DEVICE_TABLE(of, ti_adc_dt_ids); static const struct spi_device_id ti_adc_id[] = { - { "adc141s626", TI_ADC141S626 }, - { "adc161s626", TI_ADC161S626 }, + { .name = "adc141s626", .driver_data = TI_ADC141S626 }, + { .name = "adc161s626", .driver_data = TI_ADC161S626 }, { } }; MODULE_DEVICE_TABLE(spi, ti_adc_id); diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index f2a93c63ca14..0fbfa4e499aa 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -231,7 +231,6 @@ static const struct iio_event_spec ads1015_events[] = { } struct ads1015_channel_data { - bool enabled; unsigned int pga; unsigned int data_rate; }; @@ -931,6 +930,17 @@ static int ads1015_set_conv_mode(struct ads1015_data *data, int mode) mode << ADS1015_CFG_MOD_SHIFT); } +static void ads1015_power_down(void *p) +{ + struct ads1015_data *data = p; + int ret; + + ret = ads1015_set_conv_mode(data, ADS1015_SINGLESHOT); + if (ret) + dev_warn(regmap_get_device(data->regmap), + "Failed to power down (%pe)\n", ERR_PTR(ret)); +} + static int ads1015_probe(struct i2c_client *client) { const struct ads1015_chip_data *chip; @@ -1031,6 +1041,10 @@ static int ads1015_probe(struct i2c_client *client) if (ret) return ret; + ret = devm_add_action_or_reset(&client->dev, ads1015_power_down, data); + if (ret) + return ret; + data->conv_invalid = true; ret = pm_runtime_set_active(&client->dev); @@ -1038,33 +1052,11 @@ static int ads1015_probe(struct i2c_client *client) return ret; pm_runtime_set_autosuspend_delay(&client->dev, ADS1015_SLEEP_DELAY_MS); pm_runtime_use_autosuspend(&client->dev); - pm_runtime_enable(&client->dev); - - ret = iio_device_register(indio_dev); - if (ret < 0) { - dev_err(&client->dev, "Failed to register IIO device\n"); + ret = devm_pm_runtime_enable(&client->dev); + if (ret) return ret; - } - - return 0; -} -static void ads1015_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct ads1015_data *data = iio_priv(indio_dev); - int ret; - - iio_device_unregister(indio_dev); - - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); - - /* power down single shot mode */ - ret = ads1015_set_conv_mode(data, ADS1015_SINGLESHOT); - if (ret) - dev_warn(&client->dev, "Failed to power down (%pe)\n", - ERR_PTR(ret)); + return devm_iio_device_register(&client->dev, indio_dev); } #ifdef CONFIG_PM @@ -1129,9 +1121,9 @@ static const struct ads1015_chip_data tla2024_data = { }; static const struct i2c_device_id ads1015_id[] = { - { "ads1015", (kernel_ulong_t)&ads1015_data }, - { "ads1115", (kernel_ulong_t)&ads1115_data }, - { "tla2024", (kernel_ulong_t)&tla2024_data }, + { .name = "ads1015", .driver_data = (kernel_ulong_t)&ads1015_data }, + { .name = "ads1115", .driver_data = (kernel_ulong_t)&ads1115_data }, + { .name = "tla2024", .driver_data = (kernel_ulong_t)&tla2024_data }, { } }; MODULE_DEVICE_TABLE(i2c, ads1015_id); @@ -1151,7 +1143,6 @@ static struct i2c_driver ads1015_driver = { .pm = &ads1015_pm_ops, }, .probe = ads1015_probe, - .remove = ads1015_remove, .id_table = ads1015_id, }; diff --git a/drivers/iio/adc/ti-ads1018.c b/drivers/iio/adc/ti-ads1018.c index 6246b3cab71f..d9ec4a8d7ce5 100644 --- a/drivers/iio/adc/ti-ads1018.c +++ b/drivers/iio/adc/ti-ads1018.c @@ -12,7 +12,6 @@ #include <linux/gpio/consumer.h> #include <linux/interrupt.h> #include <linux/math.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/spi/spi.h> #include <linux/types.h> @@ -249,7 +248,7 @@ static int ads1018_single_shot(struct ads1018 *ads1018, struct iio_chan_spec const *chan, u16 *cnv) { u8 max_drate_mode = ads1018->chip_info->num_data_rate_mode_to_hz - 1; - u8 drate = ads1018->chip_info->data_rate_mode_to_hz[max_drate_mode]; + u32 drate = ads1018->chip_info->data_rate_mode_to_hz[max_drate_mode]; u8 pga_mode = ads1018->chan_data[chan->scan_index].pga_mode; struct spi_transfer xfer[2] = { { @@ -718,8 +717,8 @@ static const struct of_device_id ads1018_of_match[] = { MODULE_DEVICE_TABLE(of, ads1018_of_match); static const struct spi_device_id ads1018_spi_match[] = { - { "ads1018", (kernel_ulong_t)&ads1018_chip_info }, - { "ads1118", (kernel_ulong_t)&ads1118_chip_info }, + { .name = "ads1018", .driver_data = (kernel_ulong_t)&ads1018_chip_info }, + { .name = "ads1118", .driver_data = (kernel_ulong_t)&ads1118_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ads1018_spi_match); diff --git a/drivers/iio/adc/ti-ads1100.c b/drivers/iio/adc/ti-ads1100.c index aa8946063c7d..9fe8d54cce83 100644 --- a/drivers/iio/adc/ti-ads1100.c +++ b/drivers/iio/adc/ti-ads1100.c @@ -400,8 +400,8 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ads1100_pm_ops, NULL); static const struct i2c_device_id ads1100_id[] = { - { "ads1100" }, - { "ads1000" }, + { .name = "ads1100" }, + { .name = "ads1000" }, { } }; diff --git a/drivers/iio/adc/ti-ads1119.c b/drivers/iio/adc/ti-ads1119.c index c9cedc59cdcd..b0f04741ddc6 100644 --- a/drivers/iio/adc/ti-ads1119.c +++ b/drivers/iio/adc/ti-ads1119.c @@ -274,12 +274,15 @@ static int ads1119_single_conversion(struct ads1119_state *st, ret = pm_runtime_resume_and_get(dev); if (ret) - goto pdown; + return ret; ret = ads1119_configure_channel(st, mux, gain, datarate); if (ret) goto pdown; + if (st->client->irq) + reinit_completion(&st->completion); + ret = i2c_smbus_write_byte(st->client, ADS1119_CMD_START_SYNC); if (ret) goto pdown; @@ -456,7 +459,11 @@ static int ads1119_triggered_buffer_preenable(struct iio_dev *indio_dev) if (ret) return ret; - return i2c_smbus_write_byte(st->client, ADS1119_CMD_START_SYNC); + ret = i2c_smbus_write_byte(st->client, ADS1119_CMD_START_SYNC); + if (ret) + pm_runtime_put_autosuspend(dev); + + return ret; } static int ads1119_triggered_buffer_postdisable(struct iio_dev *indio_dev) @@ -735,13 +742,10 @@ static int ads1119_probe(struct i2c_client *client) return dev_err_probe(dev, ret, "Failed to setup IIO buffer\n"); if (client->irq > 0) { - ret = devm_request_threaded_irq(dev, client->irq, - ads1119_irq_handler, - NULL, IRQF_ONESHOT, - "ads1119", indio_dev); + ret = devm_request_irq(dev, client->irq, ads1119_irq_handler, + IRQF_NO_THREAD, "ads1119", indio_dev); if (ret) - return dev_err_probe(dev, ret, - "Failed to allocate irq\n"); + return ret; st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, @@ -804,7 +808,7 @@ static const struct of_device_id __maybe_unused ads1119_of_match[] = { MODULE_DEVICE_TABLE(of, ads1119_of_match); static const struct i2c_device_id ads1119_id[] = { - { "ads1119" }, + { .name = "ads1119" }, { } }; MODULE_DEVICE_TABLE(i2c, ads1119_id); diff --git a/drivers/iio/adc/ti-ads112c14.c b/drivers/iio/adc/ti-ads112c14.c new file mode 100644 index 000000000000..60eab4852ba2 --- /dev/null +++ b/drivers/iio/adc/ti-ads112c14.c @@ -0,0 +1,1454 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * IIO driver for Texas Instruments ADS112C14 and similar ADCs. + * + * Copyright (C) 2026 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2026 Baylibre Inc. + * + * Datasheet: https://www.ti.com/lit/ds/symlink/ads122c14.pdf + */ + +#include <linux/bitfield.h> +#include <linux/cleanup.h> +#include <linux/crc8.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> +#include <linux/device/devres.h> +#include <linux/i2c.h> +#include <linux/iio/buffer.h> +#include <linux/iio/iio.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/math64.h> +#include <linux/minmax.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/sysfs.h> +#include <linux/time64.h> +#include <linux/types.h> +#include <linux/unaligned.h> +#include <linux/units.h> + +/* Arbitrary limit since channels are dynamic. */ +#define ADS112C14_MAX_MEASUREMENT_CHANNELS 16 + +/* Datasheet t_d(RST) - time to wait after reset before next I2C use. */ +#define ADS112C14_DELAY_RESET_US 500 + +#define ADS112C14_CMD_RDATA 0x00 +#define ADS112C14_CMD_RREG 0x40 +#define ADS112C14_CMD_WREG 0x80 + +#define ADS112C14_REG_DEVICE_ID 0x00 +#define ADS112C14_DEVICE_ID_BITS GENMASK(3, 0) + +#define ADS112C14_REG_REVISION_ID 0x01 + +#define ADS112C14_REG_STATUS_MSB 0x02 +#define ADS112C14_STATUS_MSB_RESETN BIT(7) +#define ADS112C14_STATUS_MSB_AVDD_UVN BIT(6) +#define ADS112C14_STATUS_MSB_REF_UVN BIT(5) +#define ADS112C14_STATUS_MSB_REG_MAP_CRC_FAULTN BIT(3) +#define ADS112C14_STATUS_MSB_MEM_FAULTN BIT(2) +#define ADS112C14_STATUS_MSB_REG_WRITE_FAULTN BIT(1) +#define ADS112C14_STATUS_MSB_DRDY BIT(0) + +#define ADS112C14_REG_STATUS_LSB 0x03 +#define ADS112C14_STATUS_LSB_CONV_COUNT GENMASK(7, 4) +#define ADS112C14_STATUS_LSB_GPIO3_DAT_IN BIT(3) +#define ADS112C14_STATUS_LSB_GPIO2_DAT_IN BIT(2) +#define ADS112C14_STATUS_LSB_GPIO1_DAT_IN BIT(1) +#define ADS112C14_STATUS_LSB_GPIO0_DAT_IN BIT(0) + +#define ADS112C14_REG_CONVERSION_CTRL 0x04 +#define ADS112C14_CONVERSION_CTRL_RESET GENMASK(7, 2) +#define ADS112C14_CONVERSION_CTRL_START BIT(1) +#define ADS112C14_CONVERSION_CTRL_STOP BIT(0) + +#define ADS112C14_REG_DEVICE_CFG 0x05 +#define ADS112C14_DEVICE_CFG_PWDN BIT(7) +#define ADS112C14_DEVICE_CFG_STBY_MODE BIT(6) +#define ADS112C14_DEVICE_CFG_BOCS GENMASK(5, 4) +#define ADS112C14_DEVICE_CFG_CLK_SEL BIT(3) +#define ADS112C14_DEVICE_CFG_CONV_MODE BIT(2) +#define ADS112C14_DEVICE_CFG_CONV_MODE_CONTINUOUS 0 +#define ADS112C14_DEVICE_CFG_CONV_MODE_SINGLE_SHOT 1 +#define ADS112C14_DEVICE_CFG_SPEED_MODE GENMASK(1, 0) + +#define ADS112C14_REG_DATA_RATE_CFG 0x06 +#define ADS112C14_DATA_RATE_CFG_DELAY GENMASK(7, 4) +#define ADS112C14_DATA_RATE_CFG_GC_EN BIT(3) +#define ADS112C14_DATA_RATE_CFG_FLTR_OSR GENMASK(2, 0) + +#define ADS112C14_REG_MUX_CFG 0x07 +#define ADS112C14_MUX_CFG_AINP GENMASK(7, 4) +#define ADS112C14_MUX_CFG_AINN GENMASK(3, 0) +#define ADS112C14_MUX_CFG_AIN_GND 8 + +#define ADS112C14_REG_GAIN_CFG 0x08 +#define ADS112C14_GAIN_CFG_SPARE BIT(7) +#define ADS112C14_GAIN_CFG_SYS_MON GENMASK(6, 4) +#define ADS112C14_GAIN_CFG_GAIN GENMASK(3, 0) + +#define ADS112C14_REG_REFERENCE_CFG 0x09 +#define ADS112C14_REFERENCE_CFG_REF_UV_EN BIT(7) +#define ADS112C14_REFERENCE_CFG_REFP_BUF_EN BIT(5) +#define ADS112C14_REFERENCE_CFG_REFN_BUF_EN BIT(4) +#define ADS112C14_REFERENCE_CFG_REF_VAL BIT(2) +#define ADS112C14_REFERENCE_CFG_REF_VAL_1_25V 0 +#define ADS112C14_REFERENCE_CFG_REF_VAL_2_5V 1 +#define ADS112C14_REFERENCE_CFG_REF_SEL GENMASK(1, 0) +#define ADS112C14_REFERENCE_CFG_REF_SEL_INTERNAL 0 +#define ADS112C14_REFERENCE_CFG_REF_SEL_EXTERNAL 1 +#define ADS112C14_REFERENCE_CFG_REF_SEL_AVDD 2 + +#define ADS112C14_REG_DIGITAL_CFG 0x0A +#define ADS112C14_DIGITAL_CFG_REG_MAP_CRC_EN BIT(6) +#define ADS112C14_DIGITAL_CFG_I2C_CRC_EN BIT(5) +#define ADS112C14_DIGITAL_CFG_STATUS_EN BIT(4) +#define ADS112C14_DIGITAL_CFG_FAULT_PIN_BEHAVIOR BIT(3) +#define ADS112C14_DIGITAL_CFG_CODING BIT(1) + +#define ADS112C14_REG_GPIO_CFG 0x0B +#define ADS112C14_GPIO_CFG_GPIO3_CFG GENMASK(7, 6) +#define ADS112C14_GPIO_CFG_GPIO2_CFG GENMASK(5, 4) +#define ADS112C14_GPIO_CFG_GPIO1_CFG GENMASK(3, 2) +#define ADS112C14_GPIO_CFG_GPIO0_CFG GENMASK(1, 0) + +#define ADS112C14_REG_GPIO_DATA_OUTPUT 0x0C +#define ADS112C14_GPIO_DATA_OUTPUT_GPIO3_SRC BIT(7) +#define ADS112C14_GPIO_DATA_OUTPUT_GPIO2_SRC BIT(6) +#define ADS112C14_GPIO_DATA_OUTPUT_GPIO3_DAT_OUT BIT(3) +#define ADS112C14_GPIO_DATA_OUTPUT_GPIO2_DAT_OUT BIT(2) +#define ADS112C14_GPIO_DATA_OUTPUT_GPIO1_DAT_OUT BIT(1) +#define ADS112C14_GPIO_DATA_OUTPUT_GPIO0_DAT_OUT BIT(0) + +#define ADS112C14_REG_IDAC_MAG_CFG 0x0D +#define ADS112C14_IDAC_MAG_CFG_I2MAG GENMASK(7, 4) +#define ADS112C14_IDAC_MAG_CFG_I1MAG GENMASK(3, 0) + +#define ADS112C14_REG_IDAC_MUX_CFG 0x0E +#define ADS112C14_IDAC_MUX_CFG_IUNIT BIT(7) +#define ADS112C14_IDAC_MUX_CFG_I2MUX GENMASK(6, 4) +#define ADS112C14_IDAC_MUX_CFG_I1MUX GENMASK(2, 0) + +#define ADS112C14_REG_REG_MAP_CRC 0x0F + +#define ADS112C14_INT_REF0_mV 1250 +#define ADS112C14_INT_REF1_mV 2500 + +enum { + ADS112C14_VREF_SOURCE_INTERNAL_2_5V, + ADS112C14_VREF_SOURCE_INTERNAL_1_25V, + ADS112C14_VREF_SOURCE_EXTERNAL, + ADS112C14_VREF_SOURCE_AVDD, +}; + +static const char * const ads112c14_vref_source_names[] = { + [ADS112C14_VREF_SOURCE_INTERNAL_2_5V] = "internal-2.5v", + [ADS112C14_VREF_SOURCE_INTERNAL_1_25V] = "internal-1.25v", + [ADS112C14_VREF_SOURCE_EXTERNAL] = "external", + [ADS112C14_VREF_SOURCE_AVDD] = "avdd", +}; + +/* + * Available gains as tenths (e.g. value 5 == 0.5 gain). Indexes correspond to + * ADS112C14_GAIN_CFG_GAIN values. + */ +static const u32 ads112c14_pga_gains_x10[] = { + 5, 10, 20, 40, 50, 80, 100, 160, /* 0 - 7 */ + 200, 320, 500, 640, 1000, 1280, 2000, 2560, /* 8 - 15 */ +}; + +#define ADS112C14_I2C_CRC8_POLYNOMIAL 0x07 +DECLARE_CRC8_TABLE(ads112c14_crc8_table); + +struct ads112c14_chip_info { + const char *name; + u8 device_id; + u32 resolution_bits; +}; + +/* Fixed channels for system monitor measurements. */ + +#define ADS112C14_SYS_MON_CHANNEL_BASE 100 + +enum { + ADS112C14_SYS_MON_CHANNEL_TEMP = ADS112C14_SYS_MON_CHANNEL_BASE, + ADS112C14_SYS_MON_CHANNEL_EXT_REF, + ADS112C14_SYS_MON_CHANNEL_AVDD, + ADS112C14_SYS_MON_CHANNEL_DVDD, + ADS112C14_SYS_MON_CHANNEL_SHORT, +}; + +static const struct iio_chan_spec ads112c14_sys_mon_channels[] = { + { + .type = IIO_TEMP, + .indexed = 1, + .channel = ADS112C14_SYS_MON_CHANNEL_TEMP, + .address = 2, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) + | BIT(IIO_CHAN_INFO_SCALE) + | BIT(IIO_CHAN_INFO_OFFSET), + }, + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = ADS112C14_SYS_MON_CHANNEL_EXT_REF, + .address = 3, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) + | BIT(IIO_CHAN_INFO_SCALE), + }, + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = ADS112C14_SYS_MON_CHANNEL_AVDD, + .address = 4, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) + | BIT(IIO_CHAN_INFO_SCALE), + }, + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = ADS112C14_SYS_MON_CHANNEL_DVDD, + .address = 5, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) + | BIT(IIO_CHAN_INFO_SCALE), + }, + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = ADS112C14_SYS_MON_CHANNEL_SHORT, + .channel2 = ADS112C14_SYS_MON_CHANNEL_SHORT, + .differential = 1, + .address = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) + | BIT(IIO_CHAN_INFO_SCALE), + .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE), + }, +}; + +struct ads112c14_measurement { + const char *label; + u32 vref_source; + u8 iunit; + u8 idac1_mag; + u8 idac2_mag; + u8 idac1_mux; + u8 idac2_mux; + u8 iadc_count; + u8 gain_val; + bool global_chop; + bool bipolar; + int scale_available[ARRAY_SIZE(ads112c14_pga_gains_x10)][2]; +}; + +struct ads112c14_data { + const struct ads112c14_chip_info *chip_info; + struct regmap *regmap; + /* Synchronizes access to register value fields. */ + struct mutex lock; + bool i2c_crc_enabled; + u32 avdd_uV; + u32 ext_ref_uV; + bool refp_is_avdd; + bool refn_is_gnd; + u32 ext_ref_ohms; + struct ads112c14_measurement *measurements; + u32 num_measurements; + u8 sys_mon_chan_short_gain_val; + int sys_mon_chan_short_scale_available[ARRAY_SIZE(ads112c14_pga_gains_x10)][2]; + IIO_DECLARE_BUFFER_WITH_TS(__be32, scan, ADS112C14_MAX_MEASUREMENT_CHANNELS + + ARRAY_SIZE(ads112c14_sys_mon_channels)); +}; + +static bool ads112c14_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ADS112C14_REG_DEVICE_ID: + case ADS112C14_REG_REVISION_ID: + case ADS112C14_REG_STATUS_LSB: + return false; + default: + return true; + } +} + +static bool ads112c14_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ADS112C14_REG_STATUS_MSB: + case ADS112C14_REG_STATUS_LSB: + case ADS112C14_REG_CONVERSION_CTRL: + return true; + default: + return false; + } +} + +static const struct reg_default ads112c14_reg_defaults[] = { + { ADS112C14_REG_DEVICE_CFG, 0 }, + { ADS112C14_REG_DATA_RATE_CFG, 0 }, + { ADS112C14_REG_MUX_CFG, 0 }, + { ADS112C14_REG_GAIN_CFG, FIELD_PREP_CONST(ADS112C14_GAIN_CFG_GAIN, 1) }, + { ADS112C14_REG_REFERENCE_CFG, 0 }, + { ADS112C14_REG_DIGITAL_CFG, 0 }, + { ADS112C14_REG_GPIO_CFG, 0 }, + { ADS112C14_REG_GPIO_DATA_OUTPUT, 0 }, + { ADS112C14_REG_IDAC_MAG_CFG, 0 }, + { ADS112C14_REG_IDAC_MUX_CFG, FIELD_PREP_CONST(ADS112C14_IDAC_MUX_CFG_I2MUX, 1) }, +}; + +/** + * ads112c14_i2c_read_bytes() - Read bytes from the device over I2C + * @client: I2C client for the device + * @cmd: Command to send to the device before reading + * @buf: Buffer to store the read bytes + * @len: Number of bytes to read + * @use_crc: Whether to use CRC8 for data integrity check + * + * If I2C_CRC is enabled, @use_crc may be set to true to perform a CRC8 check + * on the received data. + */ +static int ads112c14_i2c_read_bytes(struct i2c_client *client, u8 cmd, + u8 *buf, u8 len, bool use_crc) +{ + u8 rx_buf[4]; /* Up to 3 data bytes + 1 CRC byte. */ + u8 rx_len; + int ret; + + rx_len = len + (use_crc ? 1 : 0); + + if (rx_len > sizeof(rx_buf)) + return -EINVAL; + + ret = i2c_smbus_read_i2c_block_data(client, cmd, rx_len, rx_buf); + if (ret < 0) + return ret; + + if (use_crc) { + u8 crc = crc8(ads112c14_crc8_table, rx_buf, len, CRC8_INIT_VALUE); + + if (crc != rx_buf[len]) + return -EBADMSG; + } + + memcpy(buf, rx_buf, len); + + return 0; +} + +/** + * ads112c14_regmap_bus_read() - Read a register from the device + * @context: Pointer to the device context + * @reg_buf: Register address to read + * @reg_size: Size of the register address (should be 1) + * @val_buf: Buffer to store the read value + * @val_size: Size of the value to read + * + * Custom regmap read function that also does CRC check when enabled. + */ +static int ads112c14_regmap_bus_read(void *context, const void *reg_buf, + size_t reg_size, void *val_buf, + size_t val_size) +{ + struct ads112c14_data *data = context; + struct device *dev = regmap_get_device(data->regmap); + struct i2c_client *client = to_i2c_client(dev); + const u8 *cmd = reg_buf; + + if (reg_size != 1) + return -EINVAL; + + return ads112c14_i2c_read_bytes(client, cmd[0], val_buf, val_size, + data->i2c_crc_enabled); +} + +/** + * ads112c14_regmap_bus_write() - Write a register to the device + * @context: Pointer to the device context + * @data_buf: Buffer containing the register address and value to write + * @count: Number of bytes to write + * + * Custom regmap write function that also does readback with CRC check of + * nonvolatile registers when CRC is enabled. + */ +static int ads112c14_regmap_bus_write(void *context, const void *data_buf, + size_t count) +{ + struct ads112c14_data *data = context; + struct device *dev = regmap_get_device(data->regmap); + struct i2c_client *client = to_i2c_client(dev); + const u8 *tx = data_buf; + u8 reg, readback; + int ret; + + if (count != 2) + return -EINVAL; + + ret = i2c_smbus_write_byte_data(client, tx[0], tx[1]); + if (ret) + return ret; + + reg = tx[0] & ~ADS112C14_CMD_WREG; + + if (!data->i2c_crc_enabled || ads112c14_volatile_reg(dev, reg)) + return 0; + + ret = ads112c14_i2c_read_bytes(client, reg | ADS112C14_CMD_RREG, + &readback, sizeof(readback), true); + if (ret) + return ret; + + if (readback != tx[1]) + return -EIO; + + return 0; +} + +static const struct regmap_bus ads112c14_regmap_bus = { + .read = ads112c14_regmap_bus_read, + .write = ads112c14_regmap_bus_write, + .reg_format_endian_default = REGMAP_ENDIAN_BIG, + .val_format_endian_default = REGMAP_ENDIAN_BIG, +}; + +static const struct regmap_config ads112c14_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .read_flag_mask = ADS112C14_CMD_RREG, + .write_flag_mask = ADS112C14_CMD_WREG, + .max_register = ADS112C14_REG_REG_MAP_CRC, + .writeable_reg = ads112c14_writeable_reg, + .volatile_reg = ads112c14_volatile_reg, + .reg_defaults = ads112c14_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(ads112c14_reg_defaults), + .cache_type = REGCACHE_MAPLE, +}; + +static int ads112c14_prepare_measurement_channel(struct ads112c14_data *data, + const struct iio_chan_spec *chan) +{ + struct ads112c14_measurement *measurement = &data->measurements[chan->scan_index]; + u32 refp_buf_en, refn_buf_en, ref_val, ref_sel; + int ret; + + ret = regmap_update_bits(data->regmap, ADS112C14_REG_MUX_CFG, + ADS112C14_MUX_CFG_AINP | ADS112C14_MUX_CFG_AINN, + FIELD_PREP(ADS112C14_MUX_CFG_AINP, chan->channel) | + FIELD_PREP(ADS112C14_MUX_CFG_AINN, chan->channel2)); + if (ret) + return ret; + + ret = regmap_assign_bits(data->regmap, ADS112C14_REG_DIGITAL_CFG, + ADS112C14_DIGITAL_CFG_CODING, + !measurement->bipolar); + if (ret) + return ret; + + ret = regmap_update_bits(data->regmap, ADS112C14_REG_GAIN_CFG, + ADS112C14_GAIN_CFG_SYS_MON | + ADS112C14_GAIN_CFG_GAIN, + FIELD_PREP(ADS112C14_GAIN_CFG_SYS_MON, 0) | + FIELD_PREP(ADS112C14_GAIN_CFG_GAIN, + measurement->gain_val)); + if (ret) + return ret; + + ret = regmap_update_bits(data->regmap, ADS112C14_REG_IDAC_MAG_CFG, + ADS112C14_IDAC_MAG_CFG_I2MAG | + ADS112C14_IDAC_MAG_CFG_I1MAG, + FIELD_PREP(ADS112C14_IDAC_MAG_CFG_I2MAG, + measurement->idac2_mag) | + FIELD_PREP(ADS112C14_IDAC_MAG_CFG_I1MAG, + measurement->idac1_mag)); + if (ret) + return ret; + + ret = regmap_update_bits(data->regmap, ADS112C14_REG_IDAC_MUX_CFG, + ADS112C14_IDAC_MUX_CFG_IUNIT | + ADS112C14_IDAC_MUX_CFG_I2MUX | + ADS112C14_IDAC_MUX_CFG_I1MUX, + FIELD_PREP(ADS112C14_IDAC_MUX_CFG_IUNIT, + measurement->iunit) | + FIELD_PREP(ADS112C14_IDAC_MUX_CFG_I2MUX, + measurement->idac2_mux) | + FIELD_PREP(ADS112C14_IDAC_MUX_CFG_I1MUX, + measurement->idac1_mux)); + if (ret) + return ret; + + ret = regmap_update_bits(data->regmap, ADS112C14_REG_DATA_RATE_CFG, + ADS112C14_DATA_RATE_CFG_GC_EN, + FIELD_PREP(ADS112C14_DATA_RATE_CFG_GC_EN, + measurement->global_chop)); + if (ret) + return ret; + + refp_buf_en = !data->refp_is_avdd && + measurement->vref_source == ADS112C14_VREF_SOURCE_EXTERNAL; + refn_buf_en = !data->refn_is_gnd && + measurement->vref_source == ADS112C14_VREF_SOURCE_EXTERNAL; + + ref_val = measurement->vref_source == ADS112C14_VREF_SOURCE_INTERNAL_2_5V ? + ADS112C14_REFERENCE_CFG_REF_VAL_2_5V : + ADS112C14_REFERENCE_CFG_REF_VAL_1_25V; + + switch (measurement->vref_source) { + case ADS112C14_VREF_SOURCE_AVDD: + ref_sel = ADS112C14_REFERENCE_CFG_REF_SEL_AVDD; + break; + case ADS112C14_VREF_SOURCE_EXTERNAL: + ref_sel = ADS112C14_REFERENCE_CFG_REF_SEL_EXTERNAL; + break; + default: + ref_sel = ADS112C14_REFERENCE_CFG_REF_SEL_INTERNAL; + break; + } + + return regmap_update_bits(data->regmap, ADS112C14_REG_REFERENCE_CFG, + ADS112C14_REFERENCE_CFG_REFP_BUF_EN | + ADS112C14_REFERENCE_CFG_REFN_BUF_EN | + ADS112C14_REFERENCE_CFG_REF_VAL | + ADS112C14_REFERENCE_CFG_REF_SEL, + FIELD_PREP(ADS112C14_REFERENCE_CFG_REFP_BUF_EN, + refp_buf_en) | + FIELD_PREP(ADS112C14_REFERENCE_CFG_REFN_BUF_EN, + refn_buf_en) | + FIELD_PREP(ADS112C14_REFERENCE_CFG_REF_VAL, + ref_val) | + FIELD_PREP(ADS112C14_REFERENCE_CFG_REF_SEL, + ref_sel)); +} + +static int ads112c14_prepare_sys_mon_channel(struct ads112c14_data *data, + const struct iio_chan_spec *chan) +{ + u32 gain_val; + int ret; + + /* + * NB: IDAC registers are left as-is in case they are generating current + * needed for the external reference measurement. + */ + + /* + * All SYS_MON channels use GAIN of 1 to keep it simple. Other than + * the internal short channel, where it is useful in practice. + */ + gain_val = chan->channel == ADS112C14_SYS_MON_CHANNEL_SHORT ? + data->sys_mon_chan_short_gain_val : 1; + + ret = regmap_update_bits(data->regmap, ADS112C14_REG_GAIN_CFG, + ADS112C14_GAIN_CFG_SYS_MON | + ADS112C14_GAIN_CFG_GAIN, + FIELD_PREP(ADS112C14_GAIN_CFG_SYS_MON, chan->address) | + FIELD_PREP(ADS112C14_GAIN_CFG_GAIN, gain_val)); + if (ret) + return ret; + + /* All SYS_MON channels use signed data to keep it simple. */ + ret = regmap_clear_bits(data->regmap, ADS112C14_REG_DIGITAL_CFG, + ADS112C14_DIGITAL_CFG_CODING); + if (ret) + return ret; + + /* + * REVISIT: if we implement regulator support for the REFOUT pin, we + * might need to make this voltage match what is required by that. In + * that case, we could also adjust GAIN so that we still get the same + * range. + */ + /* + * NB: SYS_MON channels ignore REF_SEL except for the shorted input + * channel, so we set it here to internal reference to be consistent. + * If we ever need to make a measurement of shorted input with other + * reference source, we could add additional channels for that. + */ + ret = regmap_update_bits(data->regmap, ADS112C14_REG_REFERENCE_CFG, + ADS112C14_REFERENCE_CFG_REF_VAL | + ADS112C14_REFERENCE_CFG_REF_SEL, + FIELD_PREP(ADS112C14_REFERENCE_CFG_REF_VAL, + ADS112C14_REFERENCE_CFG_REF_VAL_2_5V) | + FIELD_PREP(ADS112C14_REFERENCE_CFG_REF_SEL, + ADS112C14_REFERENCE_CFG_REF_SEL_INTERNAL)); + if (ret) + return ret; + + return 0; +} + +static int ads112c14_single_conversion(struct ads112c14_data *data, + const struct iio_chan_spec *chan, + u8 *buf, bool for_scan) +{ + struct i2c_client *client = to_i2c_client(regmap_get_device(data->regmap)); + u32 reg_val; + int ret; + + guard(mutex)(&data->lock); + + if (chan->channel < ADS112C14_SYS_MON_CHANNEL_BASE) { + ret = ads112c14_prepare_measurement_channel(data, chan); + if (ret) + return ret; + } else { + ret = ads112c14_prepare_sys_mon_channel(data, chan); + if (ret) + return ret; + } + + ret = regmap_write(data->regmap, ADS112C14_REG_CONVERSION_CTRL, + ADS112C14_CONVERSION_CTRL_START); + if (ret) + return ret; + + ret = regmap_read_poll_timeout(data->regmap, + ADS112C14_REG_STATUS_MSB, reg_val, + FIELD_GET(ADS112C14_STATUS_MSB_DRDY, reg_val), + 1 * USEC_PER_MSEC, 100 * USEC_PER_MSEC); + if (ret) + return ret; + + /* + * When doing buffered read, we don't check the CRC, but rather pass it + * along with the raw data. This way, we don't silently drop samples + * with CRC errors, but rather leave it to userspace to decide what to + * do. + */ + if (for_scan) { + u8 len = BITS_TO_BYTES(data->chip_info->resolution_bits) + + (data->i2c_crc_enabled ? 1 : 0); + + ret = i2c_smbus_read_i2c_block_data(client, ADS112C14_CMD_RDATA, + len, buf); + if (ret < 0) + return ret; + + return 0; + } + + return ads112c14_i2c_read_bytes(client, ADS112C14_CMD_RDATA, buf, + BITS_TO_BYTES(data->chip_info->resolution_bits), + data->i2c_crc_enabled); +} + +static int ads112c14_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct ads112c14_data *data = iio_priv(indio_dev); + struct ads112c14_measurement *measurement = NULL; + const int *scale_avail; + u32 vref_uV, fsr_bits; + + /* Selecting V_REF source is not implemented yet. */ + vref_uV = ADS112C14_INT_REF1_mV * (MICRO / MILLI); + + if (chan->channel < ADS112C14_SYS_MON_CHANNEL_BASE) { + measurement = &data->measurements[chan->scan_index]; + fsr_bits = data->chip_info->resolution_bits - measurement->bipolar; + } else { + /* All SYS_MON channels are using signed coding. */ + fsr_bits = data->chip_info->resolution_bits - 1; + } + + switch (mask) { + case IIO_CHAN_INFO_RAW: { + u8 buf[3]; + int ret; + + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + + ret = ads112c14_single_conversion(data, chan, buf, false); + if (ret) + return ret; + + switch (data->chip_info->resolution_bits) { + case 16: + *val = get_unaligned_be16(buf); + break; + case 24: + *val = get_unaligned_be24(buf); + break; + default: + return -EINVAL; + } + + if (!measurement || measurement->bipolar) + *val = sign_extend32(*val, fsr_bits); + + return IIO_VAL_INT; + } + case IIO_CHAN_INFO_SCALE: + if (chan->type == IIO_TEMP) { + /* TS_TC (typical) = 405 uV/°C */ + *val = MILLI * vref_uV / 405; + *val2 = fsr_bits; + return IIO_VAL_FRACTIONAL_LOG2; + } + + if (chan->channel < ADS112C14_SYS_MON_CHANNEL_BASE) { + guard(mutex)(&data->lock); + + scale_avail = measurement->scale_available[measurement->gain_val]; + *val = scale_avail[0]; + *val2 = scale_avail[1]; + + return IIO_VAL_DECIMAL64_PICO; + } + + if (chan->channel == ADS112C14_SYS_MON_CHANNEL_SHORT) { + u8 idx; + + guard(mutex)(&data->lock); + + idx = data->sys_mon_chan_short_gain_val; + scale_avail = data->sys_mon_chan_short_scale_available[idx]; + *val = scale_avail[0]; + *val2 = scale_avail[1]; + + return IIO_VAL_DECIMAL64_PICO; + } + + *val = vref_uV / (MICRO / MILLI); + + /* + * Some SYS_MON channels (ext ref, AVDD, DVDD) need to be + * multiplied by 8 to account for internal attenuation of / 8. + */ + switch (chan->address) { + case 3 ... 5: + *val2 = fsr_bits - 3; + break; + default: + *val2 = fsr_bits; + break; + } + + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_OFFSET: + /* Only the temperature channel has an offset. */ + if (chan->type != IIO_TEMP) + return -EINVAL; + /* + * Die temperature [°C] = 25°C + (Measured voltage – TS_Offset) / TS_TC + * TS_TC (typical) = 405 uV/°C + * TS_Offset (typical) = 119.5 mV + */ + *val = div_s64((s64)(25 * 405 - 119500) * BIT(fsr_bits), vref_uV); + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int ads112c14_read_avail(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, const int **vals, + int *type, int *length, long mask) +{ + struct ads112c14_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + if (chan->channel < ADS112C14_SYS_MON_CHANNEL_BASE) { + struct ads112c14_measurement *measurement; + + guard(mutex)(&data->lock); + + measurement = &data->measurements[chan->scan_index]; + *vals = (const int *)measurement->scale_available; + *length = 2 * ARRAY_SIZE(measurement->scale_available); + *type = IIO_VAL_DECIMAL64_PICO; + return IIO_AVAIL_LIST; + } + + if (chan->channel == ADS112C14_SYS_MON_CHANNEL_SHORT) { + guard(mutex)(&data->lock); + + *vals = (const int *)data->sys_mon_chan_short_scale_available; + *length = 2 * ARRAY_SIZE(data->sys_mon_chan_short_scale_available); + *type = IIO_VAL_DECIMAL64_PICO; + return IIO_AVAIL_LIST; + } + + return -EINVAL; + default: + return -EINVAL; + } +} + +static int ads112c14_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct ads112c14_data *data = iio_priv(indio_dev); + const int (*scale_avail)[2]; + u8 *gain_val; + + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: { + guard(mutex)(&data->lock); + + if (chan->channel < ADS112C14_SYS_MON_CHANNEL_BASE) { + struct ads112c14_measurement *measurement; + + measurement = &data->measurements[chan->scan_index]; + scale_avail = measurement->scale_available; + gain_val = &measurement->gain_val; + } else if (chan->channel == ADS112C14_SYS_MON_CHANNEL_SHORT) { + scale_avail = data->sys_mon_chan_short_scale_available; + gain_val = &data->sys_mon_chan_short_gain_val; + } else { + return -EINVAL; + } + + for (u32 i = 0; i < ARRAY_SIZE(ads112c14_pga_gains_x10); i++) { + if (iio_val_s64_compose(val, val2) == + iio_val_s64_compose(scale_avail[i][0], scale_avail[i][1])) { + *gain_val = i; + return 0; + } + } + + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int ads112c14_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_DECIMAL64_PICO; + default: + return IIO_VAL_INT_PLUS_MICRO; + } +} + +static int ads112c14_debugfs_reg_access(struct iio_dev *indio_dev, + unsigned int reg, + unsigned int writeval, + unsigned int *readval) +{ + struct ads112c14_data *data = iio_priv(indio_dev); + + if (readval) + return regmap_read(data->regmap, reg, readval); + + return regmap_write(data->regmap, reg, writeval); +} + +static int ads112c14_read_label(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, char *label) +{ + struct ads112c14_data *data = iio_priv(indio_dev); + const char *label_source; + + /* measurement channels */ + if (chan->channel < ADS112C14_SYS_MON_CHANNEL_BASE) { + struct ads112c14_measurement *measurement; + + measurement = &data->measurements[chan->scan_index]; + if (!measurement->label) + return -EINVAL; + + return sysfs_emit(label, "%s\n", measurement->label); + } + + /* System monitor channels. */ + switch (chan->channel) { + case ADS112C14_SYS_MON_CHANNEL_TEMP: + label_source = "Internal temperature sensor"; + break; + case ADS112C14_SYS_MON_CHANNEL_EXT_REF: + label_source = "External reference"; + break; + case ADS112C14_SYS_MON_CHANNEL_AVDD: + label_source = "AVDD"; + break; + case ADS112C14_SYS_MON_CHANNEL_DVDD: + label_source = "DVDD"; + break; + case ADS112C14_SYS_MON_CHANNEL_SHORT: + label_source = "Internal short (internal reference source)"; + break; + default: + return -EINVAL; + } + + return sysfs_emit(label, "%s\n", label_source); +} + +static irqreturn_t ads112c14_trigger_handler(int irq, void *private) +{ + struct iio_poll_func *pf = private; + struct iio_dev *indio_dev = pf->indio_dev; + struct ads112c14_data *data = iio_priv(indio_dev); + u32 offset = 0; + u32 i; + int ret; + + iio_for_each_active_channel(indio_dev, i) { + const struct iio_chan_spec *chan = &indio_dev->channels[i]; + + ret = ads112c14_single_conversion(data, chan, + (u8 *)&data->scan[offset++], + true); + if (ret) { + dev_err_once(indio_dev->dev.parent, + "failed to read channel %d: %pe; additional errors will be suppressed\n", + chan->channel, ERR_PTR(ret)); + goto out; + } + } + + iio_push_to_buffers_with_ts(indio_dev, data->scan, + sizeof(data->scan), pf->timestamp); +out: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static const struct iio_info ads112c14_info = { + .read_raw = ads112c14_read_raw, + .read_avail = ads112c14_read_avail, + .write_raw = ads112c14_write_raw, + .write_raw_get_fmt = ads112c14_write_raw_get_fmt, + .debugfs_reg_access = ads112c14_debugfs_reg_access, + .read_label = ads112c14_read_label, +}; + +static int ads112c14_populate_idac_mag(u32 current_nA, u8 *idac_mag) +{ + u32 current_uA = current_nA / (NANO / MICRO); + + /* Convert microamps to IMAG bits */ + if (current_uA == 1) + *idac_mag = 1; + else if (in_range(current_uA, 10, 100) && current_uA % 10 == 0) + *idac_mag = current_uA / 10 + 1; + else + return dev_err_probe(NULL, -EINVAL, + "invalid excitation-current-nanoamp value\n"); + + return 0; +} + +static int ads112c14_parse_channels(struct iio_dev *indio_dev, + bool *need_avdd_ref, bool *need_ext_ref) +{ + struct ads112c14_data *data = iio_priv(indio_dev); + struct device *dev = indio_dev->dev.parent; + struct iio_chan_spec *channels; + u32 num_child_nodes, i, pair[2]; + int ret; + + *need_avdd_ref = false; + *need_ext_ref = false; + + num_child_nodes = device_get_named_child_node_count(dev, "channel"); + + data->measurements = devm_kcalloc(dev, num_child_nodes, + sizeof(*data->measurements), GFP_KERNEL); + if (!data->measurements) + return -ENOMEM; + + channels = devm_kcalloc(dev, num_child_nodes + + ARRAY_SIZE(ads112c14_sys_mon_channels) + 1, + sizeof(*channels), GFP_KERNEL); + if (!channels) + return -ENOMEM; + + i = 0; + device_for_each_named_child_node_scoped(dev, child, "channel") { + struct ads112c14_measurement *measurement = &data->measurements[i]; + struct iio_chan_spec *spec = &channels[i]; + + spec->indexed = 1; + spec->scan_index = i; + measurement->gain_val = 1; + + if (fwnode_property_present(child, "label")) { + ret = fwnode_property_read_string(child, "label", &measurement->label); + if (ret) + return dev_err_probe(dev, ret, + "failed to read label property\n"); + } + + if (fwnode_property_present(child, "single-channel")) { + ret = fwnode_property_read_u32(child, "single-channel", + &pair[0]); + if (ret) + return dev_err_probe(dev, ret, + "failed to read single-channel property\n"); + + if (pair[0] >= 8) + return dev_err_probe(dev, -EINVAL, + "single-channel value must be between 0 and 7\n"); + + spec->channel = pair[0]; + /* + * NB: channel2 is unused by iio core code in this case. + * Let's us avoid special case for negative input mux + * for single-ended channels when taking measurements. + */ + spec->channel2 = ADS112C14_MUX_CFG_AIN_GND; + } else if (fwnode_property_present(child, "diff-channels")) { + ret = fwnode_property_read_u32_array(child, "diff-channels", + pair, ARRAY_SIZE(pair)); + if (ret) + return dev_err_probe(dev, ret, + "failed to read diff-channels property\n"); + + if (pair[0] >= 8 || pair[1] >= 8) + return dev_err_probe(dev, -EINVAL, + "diff-channels values must be between 0 and 7\n"); + + spec->differential = 1; + spec->channel = pair[0]; + spec->channel2 = pair[1]; + } else { + return dev_err_probe(dev, -EINVAL, + "channel node missing channel type property\n"); + } + + if (fwnode_property_present(child, "excitation-channels")) { + ret = fwnode_property_count_u32(child, "excitation-channels"); + if (ret < 0) + return dev_err_probe(dev, ret, + "failed to read excitation-channels property\n"); + + if (ret < 1 || ret > 2) + return dev_err_probe(dev, -EINVAL, + "excitation-channels property must have 1 or 2 values\n"); + + measurement->iadc_count = ret; + pair[1] = 0; + + ret = fwnode_property_read_u32_array(child, "excitation-channels", + pair, measurement->iadc_count); + if (ret) + return dev_err_probe(dev, ret, + "failed to read excitation-channels property\n"); + + if (pair[0] >= 8 || pair[1] >= 8) + return dev_err_probe(dev, -EINVAL, + "excitation-channels values must be between 0 and 7\n"); + + measurement->idac1_mux = pair[0]; + measurement->idac2_mux = measurement->iadc_count > 1 ? pair[1] : 0; + + ret = fwnode_property_read_u32_array(child, "excitation-current-nanoamp", + pair, measurement->iadc_count); + if (ret) + return dev_err_probe(dev, ret, + "failed to read excitation-current-nanoamp property\n"); + + if (pair[0] <= 100 * (NANO / MICRO) && + (measurement->iadc_count == 1 || pair[1] <= 100 * (NANO / MICRO))) { + /* + * If both values are 100µA or less, then we can + * use IUNIT = 1µA for better precision. + */ + ret = ads112c14_populate_idac_mag(pair[0], + &measurement->idac1_mag); + if (ret) + return ret; + + if (measurement->iadc_count > 1) { + ret = ads112c14_populate_idac_mag(pair[1], + &measurement->idac2_mag); + if (ret) + return ret; + } + } else { + /* + * Otherwise, IUINT is 10µA (flag set) and so + * IxMAG is 1/10 of the actual current. + */ + measurement->iunit = 1; + + ret = ads112c14_populate_idac_mag(pair[0] / 10, + &measurement->idac1_mag); + if (ret) + return ret; + + if (measurement->iadc_count > 1) { + ret = ads112c14_populate_idac_mag(pair[1] / 10, + &measurement->idac2_mag); + if (ret) + return ret; + } + } + } + + measurement->bipolar = fwnode_property_read_bool(child, "bipolar"); + measurement->global_chop = fwnode_property_read_bool(child, + "input-chopping"); + + if (fwnode_property_present(child, "reference-sources")) { + ret = fwnode_property_match_property_string(child, + "reference-sources", ads112c14_vref_source_names, + ARRAY_SIZE(ads112c14_vref_source_names)); + if (ret < 0) + return dev_err_probe(dev, ret, + "invalid reference-sources value\n"); + + measurement->vref_source = ret; + } + + if (measurement->vref_source == ADS112C14_VREF_SOURCE_AVDD) + *need_avdd_ref = true; + if (measurement->vref_source == ADS112C14_VREF_SOURCE_EXTERNAL) + *need_ext_ref = true; + + spec->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE); + spec->info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE); + + /* + * If reference source is resistor rather than voltage supply, + * then the measurement is effectively a resistance measurement. + */ + spec->type = (measurement->vref_source == ADS112C14_VREF_SOURCE_EXTERNAL && + data->ext_ref_ohms) ? IIO_RESISTANCE : IIO_VOLTAGE; + + if (spec->type == IIO_RESISTANCE) + spec->differential = 0; + + spec->scan_type = (struct iio_scan_type){ + .format = measurement->bipolar ? + IIO_SCAN_FORMAT_SIGNED_INT : + IIO_SCAN_FORMAT_UNSIGNED_INT, + .realbits = data->chip_info->resolution_bits, + .storagebits = 32, + .shift = 32 - data->chip_info->resolution_bits, + .endianness = IIO_BE, + }; + + i++; + } + + data->num_measurements = i; + if (data->num_measurements > ADS112C14_MAX_MEASUREMENT_CHANNELS) + return dev_err_probe(dev, -EINVAL, + "too many measurement channels defined\n"); + + memcpy(channels + i, ads112c14_sys_mon_channels, sizeof(ads112c14_sys_mon_channels)); + + for (u32 j = 0; j < ARRAY_SIZE(ads112c14_sys_mon_channels); j++) { + struct iio_chan_spec *spec = &channels[i]; + + /* Update the template that was already copied with dynamic values. */ + spec->scan_index = i; + spec->scan_type = (struct iio_scan_type){ + .format = IIO_SCAN_FORMAT_SIGNED_INT, + .realbits = data->chip_info->resolution_bits, + .storagebits = 32, + .shift = 32 - data->chip_info->resolution_bits, + .endianness = IIO_BE, + }; + + i++; + } + + channels[i] = IIO_CHAN_SOFT_TIMESTAMP(i); + i++; + + indio_dev->channels = channels; + indio_dev->num_channels = i; + + return 0; +} + +static void ads112c14_populate_scale_available(int (*scale_avail)[2], + u32 full_scale, u32 fsr_bits) +{ + for (u32 i = 0; i < ARRAY_SIZE(ads112c14_pga_gains_x10); i++) { + u64 gain_x10 = ads112c14_pga_gains_x10[i]; + s64 scale; + + scale = div64_u64((u64)PICO * 10U * full_scale, + gain_x10 * BIT(fsr_bits)); + + iio_val_s64_decompose(scale, &scale_avail[i][0], + &scale_avail[i][1]); + } +} + +static void ads112c14_populate_tables(struct ads112c14_data *data) +{ + u32 full_scale, fsr_bits; + + for (u32 i = 0; i < data->num_measurements; i++) { + struct ads112c14_measurement *measurement = &data->measurements[i]; + + switch (measurement->vref_source) { + case ADS112C14_VREF_SOURCE_EXTERNAL: + if (data->ext_ref_ohms) + full_scale = data->ext_ref_ohms; + else + full_scale = data->ext_ref_uV / (MICRO / MILLI); + break; + case ADS112C14_VREF_SOURCE_AVDD: + full_scale = data->avdd_uV / (MICRO / MILLI); + break; + case ADS112C14_VREF_SOURCE_INTERNAL_1_25V: + full_scale = ADS112C14_INT_REF0_mV; + break; + default: + full_scale = ADS112C14_INT_REF1_mV; + break; + } + + fsr_bits = data->chip_info->resolution_bits - measurement->bipolar; + + ads112c14_populate_scale_available(measurement->scale_available, + full_scale, fsr_bits); + } + + /* For now, assuming all sys_mon channels are using 2.5V reference. */ + full_scale = ADS112C14_INT_REF1_mV; + fsr_bits = data->chip_info->resolution_bits - 1; + + ads112c14_populate_scale_available(data->sys_mon_chan_short_scale_available, + full_scale, fsr_bits); +} + +static int ads112c14_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + const struct ads112c14_chip_info *info; + struct iio_dev *indio_dev; + struct ads112c14_data *data; + bool need_avdd_ref, need_ext_ref; + u32 refp_uV = 0; + u32 refn_uV = 0; + u32 reg_val; + int ret; + + info = i2c_get_match_data(client); + if (!info) + return dev_err_probe(dev, -ENODEV, "missing match data\n"); + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->chip_info = info; + + ret = devm_mutex_init(dev, &data->lock); + if (ret) + return ret; + + if (device_property_present(dev, "ti,refp-refn-resistor-ohms")) { + ret = device_property_read_u32(dev, "ti,refp-refn-resistor-ohms", + &data->ext_ref_ohms); + if (ret) + return dev_err_probe(dev, ret, + "failed to read ti,refp-refn-resistor-ohms property\n"); + } + + ret = ads112c14_parse_channels(indio_dev, &need_avdd_ref, &need_ext_ref); + if (ret) + return ret; + + ret = devm_regulator_get_enable(dev, "dvdd"); + if (ret) + return dev_err_probe(dev, ret, "failed to get dvdd regulator\n"); + + if (need_avdd_ref) { + ret = devm_regulator_get_enable_read_voltage(dev, "avdd"); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to get avdd voltage\n"); + + data->avdd_uV = ret; + } else { + ret = devm_regulator_get_enable(dev, "avdd"); + if (ret) + return dev_err_probe(dev, ret, "failed to get avdd regulator\n"); + } + + if (device_property_present(dev, "refp-supply")) { + ret = devm_regulator_get_enable_read_voltage(dev, "refp"); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to get refp voltage\n"); + + refp_uV = ret; + + struct fwnode_handle *refp_fwnode __free(fwnode_handle) = + fwnode_find_reference(dev->fwnode, "refp-supply", 0); + if (IS_ERR(refp_fwnode)) + return dev_err_probe(dev, PTR_ERR(refp_fwnode), + "failed to get refp fwnode\n"); + + struct fwnode_handle *avdd_fwnode __free(fwnode_handle) = + fwnode_find_reference(dev->fwnode, "avdd-supply", 0); + if (IS_ERR(avdd_fwnode)) + return dev_err_probe(dev, PTR_ERR(avdd_fwnode), + "failed to get avdd fwnode\n"); + + /* REFP buffer should not be enabled when connected to AVDD */ + data->refp_is_avdd = refp_fwnode == avdd_fwnode; + } + + if (device_property_present(dev, "refn-supply")) { + ret = devm_regulator_get_enable_read_voltage(dev, "refn"); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to get refn voltage\n"); + + refn_uV = ret; + } else { + data->refn_is_gnd = true; + } + + data->ext_ref_uV = refp_uV - refn_uV; + + if (data->ext_ref_uV && data->ext_ref_ohms) + return dev_err_probe(dev, -EINVAL, + "ti,refp-refn-resistor-ohms property should not be present when refp-supply or refn-supply is present\n"); + + if (need_ext_ref && !data->ext_ref_uV && !data->ext_ref_ohms) + return dev_err_probe(dev, -EINVAL, + "external reference measurements require either refp-supply or ti,refp-refn-resistor-ohms property\n"); + + /* It takes some time for the internal reference to stabilize. */ + fsleep(10 * USEC_PER_MSEC); + + data->regmap = devm_regmap_init(dev, &ads112c14_regmap_bus, data, + &ads112c14_regmap_config); + if (IS_ERR(data->regmap)) + return dev_err_probe(dev, PTR_ERR(data->regmap), + "failed to init regmap\n"); + + /* + * Write magic reset value (0x16) to ensure known state. The reset may + * cause an error because of failing to get the I2C ACK at the end of + * the message. The device still gets reset so it is safe to ignore the + * return value here. If something else is wrong, later read/write will + * likely have the same error. + */ + regmap_write(data->regmap, ADS112C14_REG_CONVERSION_CTRL, + FIELD_PREP(ADS112C14_CONVERSION_CTRL_RESET, 0x16)); + + fsleep(ADS112C14_DELAY_RESET_US); + + ret = regmap_read(data->regmap, ADS112C14_REG_STATUS_MSB, ®_val); + if (ret) + return ret; + + if (FIELD_GET(ADS112C14_STATUS_MSB_RESETN, reg_val)) + return dev_err_probe(dev, -EIO, "reset failed\n"); + + /* Default gain after reset is 1. */ + data->sys_mon_chan_short_gain_val = 1; + + /* + * Clear reset bit to prepare for next probe. And clear AVDD fault since + * that happens on every reset. + */ + ret = regmap_write(data->regmap, ADS112C14_REG_STATUS_MSB, + ADS112C14_STATUS_MSB_RESETN | + ADS112C14_STATUS_MSB_AVDD_UVN); + if (ret) + return ret; + + ret = regmap_set_bits(data->regmap, ADS112C14_REG_DIGITAL_CFG, + ADS112C14_DIGITAL_CFG_I2C_CRC_EN); + if (ret) + return ret; + + data->i2c_crc_enabled = true; + + ret = regmap_read(data->regmap, ADS112C14_REG_DEVICE_ID, ®_val); + if (ret) + return ret; + + if (FIELD_GET(ADS112C14_DEVICE_ID_BITS, reg_val) != info->device_id) + dev_info(dev, "device ID mismatch, expected 0x%X, got 0x%lX\n", + info->device_id, + FIELD_GET(ADS112C14_DEVICE_ID_BITS, reg_val)); + + ret = regmap_update_bits(data->regmap, ADS112C14_REG_DEVICE_CFG, + ADS112C14_DEVICE_CFG_CONV_MODE, + FIELD_PREP(ADS112C14_DEVICE_CFG_CONV_MODE, + ADS112C14_DEVICE_CFG_CONV_MODE_SINGLE_SHOT)); + if (ret) + return ret; + + ads112c14_populate_tables(data); + + indio_dev->name = info->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &ads112c14_info; + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + ads112c14_trigger_handler, NULL); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct ads112c14_chip_info ads112c14_chip_info = { + .name = "ads112c14", + .device_id = 0xE, + .resolution_bits = 16, +}; + +static const struct ads112c14_chip_info ads122c14_chip_info = { + .name = "ads122c14", + .device_id = 0xF, + .resolution_bits = 24, +}; + +static const struct of_device_id ads112c14_of_match[] = { + { .compatible = "ti,ads112c14", .data = &ads112c14_chip_info }, + { .compatible = "ti,ads122c14", .data = &ads122c14_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, ads112c14_of_match); + +static const struct i2c_device_id ads112c14_id[] = { + { .name = "ads112c14", .driver_data = (kernel_ulong_t)&ads112c14_chip_info }, + { .name = "ads122c14", .driver_data = (kernel_ulong_t)&ads122c14_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ads112c14_id); + +static int ads112c14_i2c_add_driver(struct i2c_driver *driver) +{ + crc8_populate_msb(ads112c14_crc8_table, ADS112C14_I2C_CRC8_POLYNOMIAL); + + return i2c_add_driver(driver); +} + +static struct i2c_driver ads112c14_driver = { + .driver = { + .name = "ads112c14", + .of_match_table = ads112c14_of_match, + }, + .probe = ads112c14_probe, + .id_table = ads112c14_id, +}; +module_driver(ads112c14_driver, ads112c14_i2c_add_driver, i2c_del_driver); + +MODULE_AUTHOR("David Lechner (TI) <dlechner@baylibre.com>"); +MODULE_DESCRIPTION("TI ADS112C14 I2C ADC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/adc/ti-ads124s08.c b/drivers/iio/adc/ti-ads124s08.c index 8ea1269f74db..49fbc63508ac 100644 --- a/drivers/iio/adc/ti-ads124s08.c +++ b/drivers/iio/adc/ti-ads124s08.c @@ -8,7 +8,6 @@ #include <linux/device.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/slab.h> #include <linux/sysfs.h> @@ -321,7 +320,8 @@ static int ads124s_probe(struct spi_device *spi) ads124s_priv->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ads124s_priv->reset_gpio)) - dev_info(&spi->dev, "Reset GPIO not defined\n"); + return dev_err_probe(&spi->dev, PTR_ERR(ads124s_priv->reset_gpio), + "Failed to get reset GPIO\n"); ads124s_priv->chip_info = &ads124s_chip_info_tbl[spi_id->driver_data]; @@ -348,8 +348,8 @@ static int ads124s_probe(struct spi_device *spi) } static const struct spi_device_id ads124s_id[] = { - { "ads124s06", ADS124S06_ID }, - { "ads124s08", ADS124S08_ID }, + { .name = "ads124s06", .driver_data = ADS124S06_ID }, + { .name = "ads124s08", .driver_data = ADS124S08_ID }, { } }; MODULE_DEVICE_TABLE(spi, ads124s_id); diff --git a/drivers/iio/adc/ti-ads1298.c b/drivers/iio/adc/ti-ads1298.c index ae30b47e4514..06c6353aa1b2 100644 --- a/drivers/iio/adc/ti-ads1298.c +++ b/drivers/iio/adc/ti-ads1298.c @@ -66,7 +66,7 @@ #define ADS1298_MASK_CONFIG3_VREF_4V BIT(5) #define ADS1298_REG_LOFF 0x04 -#define ADS1298_REG_CHnSET(n) (0x05 + n) +#define ADS1298_REG_CHnSET(n) (0x05 + (n)) #define ADS1298_MASK_CH_PD BIT(7) #define ADS1298_MASK_CH_PGA GENMASK(6, 4) #define ADS1298_MASK_CH_MUX GENMASK(2, 0) @@ -210,9 +210,11 @@ static int ads1298_read_one(struct ads1298_private *priv, int chan_index) return ret; } - /* Cannot take longer than 40ms (250Hz) */ - ret = wait_for_completion_timeout(&priv->completion, msecs_to_jiffies(50)); - if (!ret) + /* + * One conversion takes at most 4ms at the lowest sample rate (250Hz). + * Use 50ms to allow for kernel scheduling latency. + */ + if (!wait_for_completion_timeout(&priv->completion, msecs_to_jiffies(50))) return -ETIMEDOUT; return 0; @@ -279,6 +281,7 @@ static const u8 ads1298_pga_settings[] = { 6, 1, 2, 3, 4, 8, 12 }; static int ads1298_get_scale(struct ads1298_private *priv, int channel, int *val, int *val2) { + unsigned int pga_idx; int ret; unsigned int regval; u8 gain; @@ -302,7 +305,11 @@ static int ads1298_get_scale(struct ads1298_private *priv, if (ret) return ret; - gain = ads1298_pga_settings[FIELD_GET(ADS1298_MASK_CH_PGA, regval)]; + pga_idx = FIELD_GET(ADS1298_MASK_CH_PGA, regval); + if (pga_idx >= ARRAY_SIZE(ads1298_pga_settings)) + return -EINVAL; + + gain = ads1298_pga_settings[pga_idx]; *val /= gain; /* Full scale is VREF / gain */ *val2 = ADS1298_BITS_PER_SAMPLE - 1; /* Signed, hence the -1 */ @@ -615,15 +622,6 @@ static int ads1298_init(struct iio_dev *indio_dev) if (!indio_dev->name) return -ENOMEM; - /* Enable internal test signal, double amplitude, double frequency */ - ret = regmap_write(priv->regmap, ADS1298_REG_CONFIG2, - ADS1298_MASK_CONFIG2_RESERVED | - ADS1298_MASK_CONFIG2_INT_TEST | - ADS1298_MASK_CONFIG2_TEST_AMP | - ADS1298_MASK_CONFIG2_TEST_FREQ_FAST); - if (ret) - return ret; - val = ADS1298_MASK_CONFIG3_RESERVED; /* Must write 1 always */ if (!priv->reg_vref) { /* Enable internal reference */ @@ -745,7 +743,7 @@ static int ads1298_probe(struct spi_device *spi) } static const struct spi_device_id ads1298_id[] = { - { "ads1298" }, + { .name = "ads1298" }, { } }; MODULE_DEVICE_TABLE(spi, ads1298_id); diff --git a/drivers/iio/adc/ti-ads131e08.c b/drivers/iio/adc/ti-ads131e08.c index a585621b0bc3..1d25f887cadb 100644 --- a/drivers/iio/adc/ti-ads131e08.c +++ b/drivers/iio/adc/ti-ads131e08.c @@ -917,9 +917,9 @@ static const struct of_device_id ads131e08_of_match[] = { MODULE_DEVICE_TABLE(of, ads131e08_of_match); static const struct spi_device_id ads131e08_ids[] = { - { "ads131e04", (kernel_ulong_t)&ads131e08_info_tbl[ads131e04] }, - { "ads131e06", (kernel_ulong_t)&ads131e08_info_tbl[ads131e06] }, - { "ads131e08", (kernel_ulong_t)&ads131e08_info_tbl[ads131e08] }, + { .name = "ads131e04", .driver_data = (kernel_ulong_t)&ads131e08_info_tbl[ads131e04] }, + { .name = "ads131e06", .driver_data = (kernel_ulong_t)&ads131e08_info_tbl[ads131e06] }, + { .name = "ads131e08", .driver_data = (kernel_ulong_t)&ads131e08_info_tbl[ads131e08] }, { } }; MODULE_DEVICE_TABLE(spi, ads131e08_ids); diff --git a/drivers/iio/adc/ti-ads131m02.c b/drivers/iio/adc/ti-ads131m02.c index 07d63bf62c5f..2f8f75c8216b 100644 --- a/drivers/iio/adc/ti-ads131m02.c +++ b/drivers/iio/adc/ti-ads131m02.c @@ -23,7 +23,6 @@ #include <linux/err.h> #include <linux/iio/iio.h> #include <linux/lockdep.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/regulator/consumer.h> @@ -944,11 +943,11 @@ static const struct of_device_id ads131m_of_match[] = { MODULE_DEVICE_TABLE(of, ads131m_of_match); static const struct spi_device_id ads131m_id[] = { - { "ads131m02", (kernel_ulong_t)&ads131m02_config }, - { "ads131m03", (kernel_ulong_t)&ads131m03_config }, - { "ads131m04", (kernel_ulong_t)&ads131m04_config }, - { "ads131m06", (kernel_ulong_t)&ads131m06_config }, - { "ads131m08", (kernel_ulong_t)&ads131m08_config }, + { .name = "ads131m02", .driver_data = (kernel_ulong_t)&ads131m02_config }, + { .name = "ads131m03", .driver_data = (kernel_ulong_t)&ads131m03_config }, + { .name = "ads131m04", .driver_data = (kernel_ulong_t)&ads131m04_config }, + { .name = "ads131m06", .driver_data = (kernel_ulong_t)&ads131m06_config }, + { .name = "ads131m08", .driver_data = (kernel_ulong_t)&ads131m08_config }, { } }; MODULE_DEVICE_TABLE(spi, ads131m_id); diff --git a/drivers/iio/adc/ti-ads7138.c b/drivers/iio/adc/ti-ads7138.c index ee5c1b8e3a8e..da82a6947b2b 100644 --- a/drivers/iio/adc/ti-ads7138.c +++ b/drivers/iio/adc/ti-ads7138.c @@ -227,6 +227,26 @@ static int ads7138_osr_to_bits(int osr) return -EINVAL; } +static int ads7138_read_statistics(const struct i2c_client *client, u8 reg, + u8 *out_values, u8 length) +{ + int ret; + + /* Disable statistics update so the value is not updated mid read */ + ret = ads7138_i2c_clear_bit(client, ADS7138_REG_GENERAL_CFG, + ADS7138_GENERAL_CFG_STATS_EN); + if (ret) + return ret; + + ret = ads7138_i2c_read_block(client, reg, out_values, length); + if (ret) + return ret; + + /* Enable statistics update after read */ + return ads7138_i2c_set_bit(client, ADS7138_REG_GENERAL_CFG, + ADS7138_GENERAL_CFG_STATS_EN); +} + static int ads7138_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -236,28 +256,32 @@ static int ads7138_read_raw(struct iio_dev *indio_dev, u8 values[2]; switch (mask) { + /* + * Reading the statistics registers reinitializes them. This is + * unfortunate but necessary to prevent data races. + */ case IIO_CHAN_INFO_RAW: - ret = ads7138_i2c_read_block(data->client, - ADS7138_REG_RECENT_LSB_CH(chan->channel), - values, ARRAY_SIZE(values)); + ret = ads7138_read_statistics(data->client, + ADS7138_REG_RECENT_LSB_CH(chan->channel), + values, ARRAY_SIZE(values)); if (ret) return ret; *val = get_unaligned_le16(values); return IIO_VAL_INT; case IIO_CHAN_INFO_PEAK: - ret = ads7138_i2c_read_block(data->client, - ADS7138_REG_MAX_LSB_CH(chan->channel), - values, ARRAY_SIZE(values)); + ret = ads7138_read_statistics(data->client, + ADS7138_REG_MAX_LSB_CH(chan->channel), + values, ARRAY_SIZE(values)); if (ret) return ret; *val = get_unaligned_le16(values); return IIO_VAL_INT; case IIO_CHAN_INFO_TROUGH: - ret = ads7138_i2c_read_block(data->client, - ADS7138_REG_MIN_LSB_CH(chan->channel), - values, ARRAY_SIZE(values)); + ret = ads7138_read_statistics(data->client, + ADS7138_REG_MIN_LSB_CH(chan->channel), + values, ARRAY_SIZE(values)); if (ret) return ret; @@ -727,8 +751,8 @@ static const struct of_device_id ads7138_of_match[] = { MODULE_DEVICE_TABLE(of, ads7138_of_match); static const struct i2c_device_id ads7138_device_ids[] = { - { "ads7128", (kernel_ulong_t)&ads7128_data }, - { "ads7138", (kernel_ulong_t)&ads7138_data }, + { .name = "ads7128", .driver_data = (kernel_ulong_t)&ads7128_data }, + { .name = "ads7138", .driver_data = (kernel_ulong_t)&ads7138_data }, { } }; MODULE_DEVICE_TABLE(i2c, ads7138_device_ids); diff --git a/drivers/iio/adc/ti-ads7924.c b/drivers/iio/adc/ti-ads7924.c index bbcc4fc22b6e..ff30a52d2850 100644 --- a/drivers/iio/adc/ti-ads7924.c +++ b/drivers/iio/adc/ti-ads7924.c @@ -12,6 +12,7 @@ */ #include <linux/bitfield.h> +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/gpio/consumer.h> #include <linux/init.h> @@ -198,6 +199,8 @@ static int ads7924_get_adc_result(struct ads7924_data *data, if (chan->channel < 0 || chan->channel >= ADS7924_CHANNELS) return -EINVAL; + guard(mutex)(&data->lock); + if (data->conv_invalid) { int conv_time; @@ -227,9 +230,7 @@ static int ads7924_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - mutex_lock(&data->lock); ret = ads7924_get_adc_result(data, chan, val); - mutex_unlock(&data->lock); if (ret < 0) return ret; @@ -441,7 +442,7 @@ static int ads7924_probe(struct i2c_client *client) } static const struct i2c_device_id ads7924_id[] = { - { "ads7924" }, + { .name = "ads7924" }, { } }; MODULE_DEVICE_TABLE(i2c, ads7924_id); diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c index bbe1ce577789..d27c1f2885fd 100644 --- a/drivers/iio/adc/ti-ads7950.c +++ b/drivers/iio/adc/ti-ads7950.c @@ -47,8 +47,6 @@ #define TI_ADS7950_MAX_CHAN 16 #define TI_ADS7950_NUM_GPIOS 4 -#define TI_ADS7950_TIMESTAMP_SIZE (sizeof(int64_t) / sizeof(__be16)) - /* val = value, dec = left shift, bits = number of bits of the mask */ #define TI_ADS7950_EXTRACT(val, dec, bits) \ (((val) >> (dec)) & ((1 << (bits)) - 1)) @@ -105,8 +103,7 @@ struct ti_ads7950_state { * DMA (thus cache coherency maintenance) may require the * transfer buffers to live in their own cache lines. */ - u16 rx_buf[TI_ADS7950_MAX_CHAN + 2 + TI_ADS7950_TIMESTAMP_SIZE] - __aligned(IIO_DMA_MINALIGN); + u16 rx_buf[TI_ADS7950_MAX_CHAN + 2] __aligned(IIO_DMA_MINALIGN); u16 tx_buf[TI_ADS7950_MAX_CHAN + 2]; u16 single_tx; u16 single_rx; @@ -118,21 +115,6 @@ struct ti_ads7950_chip_info { unsigned int num_channels; }; -enum ti_ads7950_id { - TI_ADS7950, - TI_ADS7951, - TI_ADS7952, - TI_ADS7953, - TI_ADS7954, - TI_ADS7955, - TI_ADS7956, - TI_ADS7957, - TI_ADS7958, - TI_ADS7959, - TI_ADS7960, - TI_ADS7961, -}; - #define TI_ADS7950_V_CHAN(index, bits) \ { \ .type = IIO_VOLTAGE, \ @@ -225,81 +207,65 @@ static DECLARE_TI_ADS7950_8_CHANNELS(ti_ads7959, 8); static DECLARE_TI_ADS7950_12_CHANNELS(ti_ads7960, 8); static DECLARE_TI_ADS7950_16_CHANNELS(ti_ads7961, 8); -static const struct ti_ads7950_chip_info ti_ads7950_chip_info[] = { - [TI_ADS7950] = { - .channels = ti_ads7950_channels, - .num_channels = ARRAY_SIZE(ti_ads7950_channels), - }, - [TI_ADS7951] = { - .channels = ti_ads7951_channels, - .num_channels = ARRAY_SIZE(ti_ads7951_channels), - }, - [TI_ADS7952] = { - .channels = ti_ads7952_channels, - .num_channels = ARRAY_SIZE(ti_ads7952_channels), - }, - [TI_ADS7953] = { - .channels = ti_ads7953_channels, - .num_channels = ARRAY_SIZE(ti_ads7953_channels), - }, - [TI_ADS7954] = { - .channels = ti_ads7954_channels, - .num_channels = ARRAY_SIZE(ti_ads7954_channels), - }, - [TI_ADS7955] = { - .channels = ti_ads7955_channels, - .num_channels = ARRAY_SIZE(ti_ads7955_channels), - }, - [TI_ADS7956] = { - .channels = ti_ads7956_channels, - .num_channels = ARRAY_SIZE(ti_ads7956_channels), - }, - [TI_ADS7957] = { - .channels = ti_ads7957_channels, - .num_channels = ARRAY_SIZE(ti_ads7957_channels), - }, - [TI_ADS7958] = { - .channels = ti_ads7958_channels, - .num_channels = ARRAY_SIZE(ti_ads7958_channels), - }, - [TI_ADS7959] = { - .channels = ti_ads7959_channels, - .num_channels = ARRAY_SIZE(ti_ads7959_channels), - }, - [TI_ADS7960] = { - .channels = ti_ads7960_channels, - .num_channels = ARRAY_SIZE(ti_ads7960_channels), - }, - [TI_ADS7961] = { - .channels = ti_ads7961_channels, - .num_channels = ARRAY_SIZE(ti_ads7961_channels), - }, +static const struct ti_ads7950_chip_info ti_ads7950_chip_info = { + .channels = ti_ads7950_channels, + .num_channels = ARRAY_SIZE(ti_ads7950_channels), }; -/* - * ti_ads7950_update_scan_mode() setup the spi transfer buffer for the new - * scan mask - */ -static int ti_ads7950_update_scan_mode(struct iio_dev *indio_dev, - const unsigned long *active_scan_mask) -{ - struct ti_ads7950_state *st = iio_priv(indio_dev); - int i, cmd, len; +static const struct ti_ads7950_chip_info ti_ads7951_chip_info = { + .channels = ti_ads7951_channels, + .num_channels = ARRAY_SIZE(ti_ads7951_channels), +}; - len = 0; - for_each_set_bit(i, active_scan_mask, indio_dev->num_channels) { - cmd = TI_ADS7950_MAN_CMD(TI_ADS7950_CR_CHAN(i)); - st->tx_buf[len++] = cmd; - } +static const struct ti_ads7950_chip_info ti_ads7952_chip_info = { + .channels = ti_ads7952_channels, + .num_channels = ARRAY_SIZE(ti_ads7952_channels), +}; - /* Data for the 1st channel is not returned until the 3rd transfer */ - st->tx_buf[len++] = 0; - st->tx_buf[len++] = 0; +static const struct ti_ads7950_chip_info ti_ads7953_chip_info = { + .channels = ti_ads7953_channels, + .num_channels = ARRAY_SIZE(ti_ads7953_channels), +}; - st->ring_xfer.len = len * 2; +static const struct ti_ads7950_chip_info ti_ads7954_chip_info = { + .channels = ti_ads7954_channels, + .num_channels = ARRAY_SIZE(ti_ads7954_channels), +}; - return 0; -} +static const struct ti_ads7950_chip_info ti_ads7955_chip_info = { + .channels = ti_ads7955_channels, + .num_channels = ARRAY_SIZE(ti_ads7955_channels), +}; + +static const struct ti_ads7950_chip_info ti_ads7956_chip_info = { + .channels = ti_ads7956_channels, + .num_channels = ARRAY_SIZE(ti_ads7956_channels), +}; + +static const struct ti_ads7950_chip_info ti_ads7957_chip_info = { + .channels = ti_ads7957_channels, + .num_channels = ARRAY_SIZE(ti_ads7957_channels), +}; + +static const struct ti_ads7950_chip_info ti_ads7958_chip_info = { + .channels = ti_ads7958_channels, + .num_channels = ARRAY_SIZE(ti_ads7958_channels), +}; + +static const struct ti_ads7950_chip_info ti_ads7959_chip_info = { + .channels = ti_ads7959_channels, + .num_channels = ARRAY_SIZE(ti_ads7959_channels), +}; + +static const struct ti_ads7950_chip_info ti_ads7960_chip_info = { + .channels = ti_ads7960_channels, + .num_channels = ARRAY_SIZE(ti_ads7960_channels), +}; + +static const struct ti_ads7950_chip_info ti_ads7961_chip_info = { + .channels = ti_ads7961_channels, + .num_channels = ARRAY_SIZE(ti_ads7961_channels), +}; static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p) { @@ -308,16 +274,19 @@ static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p) struct ti_ads7950_state *st = iio_priv(indio_dev); int ret; - mutex_lock(&st->slock); - ret = spi_sync(st->spi, &st->ring_msg); - if (ret < 0) - goto out; + do { + guard(mutex)(&st->slock); + + ret = spi_sync(st->spi, &st->ring_msg); + if (ret) + break; - iio_push_to_buffers_with_timestamp(indio_dev, &st->rx_buf[2], - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts_unaligned(indio_dev, &st->rx_buf[2], + sizeof(*st->rx_buf) * + TI_ADS7950_MAX_CHAN, + iio_get_time_ns(indio_dev)); + } while (0); -out: - mutex_unlock(&st->slock); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; @@ -328,35 +297,21 @@ static int ti_ads7950_scan_direct(struct iio_dev *indio_dev, unsigned int ch) struct ti_ads7950_state *st = iio_priv(indio_dev); int ret, cmd; - mutex_lock(&st->slock); + guard(mutex)(&st->slock); + cmd = TI_ADS7950_MAN_CMD(TI_ADS7950_CR_CHAN(ch)); st->single_tx = cmd; ret = spi_sync(st->spi, &st->scan_single_msg); if (ret) - goto out; - - ret = st->single_rx; - -out: - mutex_unlock(&st->slock); + return ret; - return ret; + return st->single_rx; } -static int ti_ads7950_get_range(struct ti_ads7950_state *st) +static unsigned int ti_ads7950_get_range(struct ti_ads7950_state *st) { - int vref; - - if (st->vref_mv) { - vref = st->vref_mv; - } else { - vref = regulator_get_voltage(st->reg); - if (vref < 0) - return vref; - - vref /= 1000; - } + unsigned int vref = st->vref_mv; if (st->cmd_settings_bitmask & TI_ADS7950_CR_RANGE_5V) vref *= 2; @@ -385,11 +340,7 @@ static int ti_ads7950_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - ret = ti_ads7950_get_range(st); - if (ret < 0) - return ret; - - *val = ret; + *val = ti_ads7950_get_range(st); *val2 = (1 << chan->scan_type.realbits) - 1; return IIO_VAL_FRACTIONAL; @@ -399,17 +350,50 @@ static int ti_ads7950_read_raw(struct iio_dev *indio_dev, } static const struct iio_info ti_ads7950_info = { - .read_raw = &ti_ads7950_read_raw, - .update_scan_mode = ti_ads7950_update_scan_mode, + .read_raw = &ti_ads7950_read_raw, +}; + +static int ti_ads7950_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ti_ads7950_state *st = iio_priv(indio_dev); + u32 len = 0; + u32 i; + u16 cmd; + + for_each_set_bit(i, indio_dev->active_scan_mask, indio_dev->num_channels) { + cmd = TI_ADS7950_MAN_CMD(TI_ADS7950_CR_CHAN(i)); + st->tx_buf[len++] = cmd; + } + + /* Data for the 1st channel is not returned until the 3rd transfer */ + st->tx_buf[len++] = 0; + st->tx_buf[len++] = 0; + + st->ring_xfer.len = len * 2; + + return spi_optimize_message(st->spi, &st->ring_msg); +} + +static int ti_ads7950_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ti_ads7950_state *st = iio_priv(indio_dev); + + spi_unoptimize_message(&st->ring_msg); + + return 0; +} + +static const struct iio_buffer_setup_ops ti_ads7950_buffer_setup_ops = { + .preenable = ti_ads7950_buffer_preenable, + .postdisable = ti_ads7950_buffer_postdisable, }; static int ti_ads7950_set(struct gpio_chip *chip, unsigned int offset, int value) { struct ti_ads7950_state *st = gpiochip_get_data(chip); - int ret; - mutex_lock(&st->slock); + guard(mutex)(&st->slock); if (value) st->cmd_settings_bitmask |= BIT(offset); @@ -417,24 +401,22 @@ static int ti_ads7950_set(struct gpio_chip *chip, unsigned int offset, st->cmd_settings_bitmask &= ~BIT(offset); st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st); - ret = spi_sync(st->spi, &st->scan_single_msg); - - mutex_unlock(&st->slock); - return ret; + return spi_sync(st->spi, &st->scan_single_msg); } static int ti_ads7950_get(struct gpio_chip *chip, unsigned int offset) { struct ti_ads7950_state *st = gpiochip_get_data(chip); + bool state; int ret; - mutex_lock(&st->slock); + guard(mutex)(&st->slock); /* If set as output, return the output */ if (st->gpio_cmd_settings_bitmask & BIT(offset)) { - ret = st->cmd_settings_bitmask & BIT(offset); - goto out; + state = st->cmd_settings_bitmask & BIT(offset); + return state; } /* GPIO data bit sets SDO bits 12-15 to GPIO input */ @@ -442,21 +424,18 @@ static int ti_ads7950_get(struct gpio_chip *chip, unsigned int offset) st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st); ret = spi_sync(st->spi, &st->scan_single_msg); if (ret) - goto out; + return ret; - ret = ((st->single_rx >> 12) & BIT(offset)) ? 1 : 0; + state = (st->single_rx >> 12) & BIT(offset); /* Revert back to original settings */ st->cmd_settings_bitmask &= ~TI_ADS7950_CR_GPIO_DATA; st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st); ret = spi_sync(st->spi, &st->scan_single_msg); if (ret) - goto out; - -out: - mutex_unlock(&st->slock); + return ret; - return ret; + return state; } static int ti_ads7950_get_direction(struct gpio_chip *chip, @@ -472,9 +451,8 @@ static int _ti_ads7950_set_direction(struct gpio_chip *chip, int offset, int input) { struct ti_ads7950_state *st = gpiochip_get_data(chip); - int ret = 0; - mutex_lock(&st->slock); + guard(mutex)(&st->slock); /* Only change direction if needed */ if (input && (st->gpio_cmd_settings_bitmask & BIT(offset))) @@ -482,15 +460,11 @@ static int _ti_ads7950_set_direction(struct gpio_chip *chip, int offset, else if (!input && !(st->gpio_cmd_settings_bitmask & BIT(offset))) st->gpio_cmd_settings_bitmask |= BIT(offset); else - goto out; + return 0; st->single_tx = TI_ADS7950_GPIO_CMD_SETTINGS(st); - ret = spi_sync(st->spi, &st->scan_single_msg); -out: - mutex_unlock(&st->slock); - - return ret; + return spi_sync(st->spi, &st->scan_single_msg); } static int ti_ads7950_direction_input(struct gpio_chip *chip, @@ -513,9 +487,9 @@ static int ti_ads7950_direction_output(struct gpio_chip *chip, static int ti_ads7950_init_hw(struct ti_ads7950_state *st) { - int ret = 0; + int ret; - mutex_lock(&st->slock); + guard(mutex)(&st->slock); /* Settings for Manual/Auto1/Auto2 commands */ /* Default to 5v ref */ @@ -523,17 +497,12 @@ static int ti_ads7950_init_hw(struct ti_ads7950_state *st) st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st); ret = spi_sync(st->spi, &st->scan_single_msg); if (ret) - goto out; + return ret; /* Settings for GPIO command */ st->gpio_cmd_settings_bitmask = 0x0; st->single_tx = TI_ADS7950_GPIO_CMD_SETTINGS(st); - ret = spi_sync(st->spi, &st->scan_single_msg); - -out: - mutex_unlock(&st->slock); - - return ret; + return spi_sync(st->spi, &st->scan_single_msg); } static int ti_ads7950_probe(struct spi_device *spi) @@ -546,10 +515,8 @@ static int ti_ads7950_probe(struct spi_device *spi) spi->bits_per_word = 16; spi->mode |= SPI_CS_WORD; ret = spi_setup(spi); - if (ret < 0) { - dev_err(&spi->dev, "Error in spi setup\n"); - return ret; - } + if (ret) + return dev_err_probe(&spi->dev, ret, "Error in spi setup\n"); indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (!indio_dev) @@ -557,11 +524,9 @@ static int ti_ads7950_probe(struct spi_device *spi) st = iio_priv(indio_dev); - spi_set_drvdata(spi, indio_dev); - st->spi = spi; - info = &ti_ads7950_chip_info[spi_get_device_id(spi)->driver_data]; + info = spi_get_device_match_data(spi); indio_dev->name = spi_get_device_id(spi)->name; indio_dev->modes = INDIO_DIRECT_MODE; @@ -599,43 +564,38 @@ static int ti_ads7950_probe(struct spi_device *spi) spi_message_init_with_transfers(&st->scan_single_msg, st->scan_single_xfer, 3); + ret = devm_mutex_init(&spi->dev, &st->slock); + if (ret) + return ret; + /* Use hard coded value for reference voltage in ACPI case */ - if (ACPI_COMPANION(&spi->dev)) + if (ACPI_COMPANION(&spi->dev)) { st->vref_mv = TI_ADS7950_VA_MV_ACPI_DEFAULT; + } else { + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref"); + if (ret < 0) + return dev_err_probe(&spi->dev, ret, + "Failed to get regulator \"vref\"\n"); - mutex_init(&st->slock); - - st->reg = devm_regulator_get(&spi->dev, "vref"); - if (IS_ERR(st->reg)) { - ret = dev_err_probe(&spi->dev, PTR_ERR(st->reg), - "Failed to get regulator \"vref\"\n"); - goto error_destroy_mutex; - } - - ret = regulator_enable(st->reg); - if (ret) { - dev_err(&spi->dev, "Failed to enable regulator \"vref\"\n"); - goto error_destroy_mutex; + st->vref_mv = ret / 1000; } - ret = iio_triggered_buffer_setup(indio_dev, NULL, - &ti_ads7950_trigger_handler, NULL); - if (ret) { - dev_err(&spi->dev, "Failed to setup triggered buffer\n"); - goto error_disable_reg; - } + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL, + &ti_ads7950_trigger_handler, + &ti_ads7950_buffer_setup_ops); + if (ret) + return dev_err_probe(&spi->dev, ret, + "Failed to setup triggered buffer\n"); ret = ti_ads7950_init_hw(st); - if (ret) { - dev_err(&spi->dev, "Failed to init adc chip\n"); - goto error_cleanup_ring; - } + if (ret) + return dev_err_probe(&spi->dev, ret, + "Failed to init adc chip\n"); - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(&spi->dev, "Failed to register iio device\n"); - goto error_cleanup_ring; - } + ret = devm_iio_device_register(&spi->dev, indio_dev); + if (ret) + return dev_err_probe(&spi->dev, ret, + "Failed to register iio device\n"); /* Add GPIO chip */ st->chip.label = dev_name(&st->spi->dev); @@ -650,68 +610,44 @@ static int ti_ads7950_probe(struct spi_device *spi) st->chip.get = ti_ads7950_get; st->chip.set = ti_ads7950_set; - ret = gpiochip_add_data(&st->chip, st); - if (ret) { - dev_err(&spi->dev, "Failed to init GPIOs\n"); - goto error_iio_device; - } + ret = devm_gpiochip_add_data(&spi->dev, &st->chip, st); + if (ret) + return dev_err_probe(&spi->dev, ret, + "Failed to init GPIOs\n"); return 0; - -error_iio_device: - iio_device_unregister(indio_dev); -error_cleanup_ring: - iio_triggered_buffer_cleanup(indio_dev); -error_disable_reg: - regulator_disable(st->reg); -error_destroy_mutex: - mutex_destroy(&st->slock); - - return ret; -} - -static void ti_ads7950_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct ti_ads7950_state *st = iio_priv(indio_dev); - - gpiochip_remove(&st->chip); - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - regulator_disable(st->reg); - mutex_destroy(&st->slock); } static const struct spi_device_id ti_ads7950_id[] = { - { "ads7950", TI_ADS7950 }, - { "ads7951", TI_ADS7951 }, - { "ads7952", TI_ADS7952 }, - { "ads7953", TI_ADS7953 }, - { "ads7954", TI_ADS7954 }, - { "ads7955", TI_ADS7955 }, - { "ads7956", TI_ADS7956 }, - { "ads7957", TI_ADS7957 }, - { "ads7958", TI_ADS7958 }, - { "ads7959", TI_ADS7959 }, - { "ads7960", TI_ADS7960 }, - { "ads7961", TI_ADS7961 }, + { .name = "ads7950", .driver_data = (kernel_ulong_t)&ti_ads7950_chip_info }, + { .name = "ads7951", .driver_data = (kernel_ulong_t)&ti_ads7951_chip_info }, + { .name = "ads7952", .driver_data = (kernel_ulong_t)&ti_ads7952_chip_info }, + { .name = "ads7953", .driver_data = (kernel_ulong_t)&ti_ads7953_chip_info }, + { .name = "ads7954", .driver_data = (kernel_ulong_t)&ti_ads7954_chip_info }, + { .name = "ads7955", .driver_data = (kernel_ulong_t)&ti_ads7955_chip_info }, + { .name = "ads7956", .driver_data = (kernel_ulong_t)&ti_ads7956_chip_info }, + { .name = "ads7957", .driver_data = (kernel_ulong_t)&ti_ads7957_chip_info }, + { .name = "ads7958", .driver_data = (kernel_ulong_t)&ti_ads7958_chip_info }, + { .name = "ads7959", .driver_data = (kernel_ulong_t)&ti_ads7959_chip_info }, + { .name = "ads7960", .driver_data = (kernel_ulong_t)&ti_ads7960_chip_info }, + { .name = "ads7961", .driver_data = (kernel_ulong_t)&ti_ads7961_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ti_ads7950_id); static const struct of_device_id ads7950_of_table[] = { - { .compatible = "ti,ads7950", .data = &ti_ads7950_chip_info[TI_ADS7950] }, - { .compatible = "ti,ads7951", .data = &ti_ads7950_chip_info[TI_ADS7951] }, - { .compatible = "ti,ads7952", .data = &ti_ads7950_chip_info[TI_ADS7952] }, - { .compatible = "ti,ads7953", .data = &ti_ads7950_chip_info[TI_ADS7953] }, - { .compatible = "ti,ads7954", .data = &ti_ads7950_chip_info[TI_ADS7954] }, - { .compatible = "ti,ads7955", .data = &ti_ads7950_chip_info[TI_ADS7955] }, - { .compatible = "ti,ads7956", .data = &ti_ads7950_chip_info[TI_ADS7956] }, - { .compatible = "ti,ads7957", .data = &ti_ads7950_chip_info[TI_ADS7957] }, - { .compatible = "ti,ads7958", .data = &ti_ads7950_chip_info[TI_ADS7958] }, - { .compatible = "ti,ads7959", .data = &ti_ads7950_chip_info[TI_ADS7959] }, - { .compatible = "ti,ads7960", .data = &ti_ads7950_chip_info[TI_ADS7960] }, - { .compatible = "ti,ads7961", .data = &ti_ads7950_chip_info[TI_ADS7961] }, + { .compatible = "ti,ads7950", .data = &ti_ads7950_chip_info }, + { .compatible = "ti,ads7951", .data = &ti_ads7951_chip_info }, + { .compatible = "ti,ads7952", .data = &ti_ads7952_chip_info }, + { .compatible = "ti,ads7953", .data = &ti_ads7953_chip_info }, + { .compatible = "ti,ads7954", .data = &ti_ads7954_chip_info }, + { .compatible = "ti,ads7955", .data = &ti_ads7955_chip_info }, + { .compatible = "ti,ads7956", .data = &ti_ads7956_chip_info }, + { .compatible = "ti,ads7957", .data = &ti_ads7957_chip_info }, + { .compatible = "ti,ads7958", .data = &ti_ads7958_chip_info }, + { .compatible = "ti,ads7959", .data = &ti_ads7959_chip_info }, + { .compatible = "ti,ads7960", .data = &ti_ads7960_chip_info }, + { .compatible = "ti,ads7961", .data = &ti_ads7961_chip_info }, { } }; MODULE_DEVICE_TABLE(of, ads7950_of_table); @@ -722,7 +658,6 @@ static struct spi_driver ti_ads7950_driver = { .of_match_table = ads7950_of_table, }, .probe = ti_ads7950_probe, - .remove = ti_ads7950_remove, .id_table = ti_ads7950_id, }; module_spi_driver(ti_ads7950_driver); diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c index b0bf46cae0b6..8ad070b5ec4c 100644 --- a/drivers/iio/adc/ti-ads8688.c +++ b/drivers/iio/adc/ti-ads8688.c @@ -6,18 +6,15 @@ #include <linux/device.h> #include <linux/kernel.h> #include <linux/slab.h> -#include <linux/sysfs.h> #include <linux/spi/spi.h> #include <linux/regulator/consumer.h> #include <linux/err.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> -#include <linux/iio/sysfs.h> #define ADS8688_CMD_REG(x) (x << 8) #define ADS8688_CMD_REG_NOOP 0x00 @@ -66,6 +63,7 @@ struct ads8688_state { const struct ads8688_chip_info *chip_info; struct spi_device *spi; unsigned int vref_mv; + int scale_avail[3][2]; enum ads8688_range range[8]; union { __be32 d32; @@ -114,37 +112,9 @@ static const struct ads8688_ranges ads8688_range_def[5] = { } }; -static ssize_t ads8688_show_scales(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ads8688_state *st = iio_priv(dev_to_iio_dev(dev)); - - return sprintf(buf, "0.%09u 0.%09u 0.%09u\n", - ads8688_range_def[0].scale * st->vref_mv, - ads8688_range_def[1].scale * st->vref_mv, - ads8688_range_def[2].scale * st->vref_mv); -} - -static ssize_t ads8688_show_offsets(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d %d\n", ads8688_range_def[0].offset, - ads8688_range_def[3].offset); -} - -static IIO_DEVICE_ATTR(in_voltage_scale_available, S_IRUGO, - ads8688_show_scales, NULL, 0); -static IIO_DEVICE_ATTR(in_voltage_offset_available, S_IRUGO, - ads8688_show_offsets, NULL, 0); - -static struct attribute *ads8688_attributes[] = { - &iio_dev_attr_in_voltage_scale_available.dev_attr.attr, - &iio_dev_attr_in_voltage_offset_available.dev_attr.attr, - NULL, -}; - -static const struct attribute_group ads8688_attribute_group = { - .attrs = ads8688_attributes, +static const int ads8688_offset_avail[] = { + -(1 << (ADS8688_REALBITS - 1)), + 0 }; #define ADS8688_CHAN(index) \ @@ -155,6 +125,9 @@ static const struct attribute_group ads8688_attribute_group = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \ | BIT(IIO_CHAN_INFO_SCALE) \ | BIT(IIO_CHAN_INFO_OFFSET), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_SCALE) \ + | BIT(IIO_CHAN_INFO_OFFSET), \ .scan_index = index, \ .scan_type = { \ .sign = 'u', \ @@ -369,11 +342,34 @@ static int ads8688_write_raw_get_fmt(struct iio_dev *indio_dev, return -EINVAL; } +static int ads8688_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct ads8688_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + *vals = (const int *)st->scale_avail; + *type = IIO_VAL_INT_PLUS_NANO; + *length = ARRAY_SIZE(st->scale_avail) * 2; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_OFFSET: + *vals = ads8688_offset_avail; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(ads8688_offset_avail); + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + static const struct iio_info ads8688_info = { .read_raw = &ads8688_read_raw, + .read_avail = &ads8688_read_avail, .write_raw = &ads8688_write_raw, .write_raw_get_fmt = &ads8688_write_raw_get_fmt, - .attrs = &ads8688_attribute_group, }; static irqreturn_t ads8688_trigger_handler(int irq, void *p) @@ -426,6 +422,11 @@ static int ads8688_probe(struct spi_device *spi) st->vref_mv = ret == -ENODEV ? ADS8688_VREF_MV : ret / 1000; + for (unsigned int i = 0; i < ARRAY_SIZE(st->scale_avail); i++) { + st->scale_avail[i][0] = 0; + st->scale_avail[i][1] = ads8688_range_def[i].scale * st->vref_mv; + } + st->chip_info = &ads8688_chip_info_tbl[spi_get_device_id(spi)->driver_data]; spi->mode = SPI_MODE_1; @@ -452,8 +453,8 @@ static int ads8688_probe(struct spi_device *spi) } static const struct spi_device_id ads8688_id[] = { - { "ads8684", ID_ADS8684 }, - { "ads8688", ID_ADS8688 }, + { .name = "ads8684", .driver_data = ID_ADS8684 }, + { .name = "ads8688", .driver_data = ID_ADS8688 }, { } }; MODULE_DEVICE_TABLE(spi, ads8688_id); diff --git a/drivers/iio/adc/ti-lmp92064.c b/drivers/iio/adc/ti-lmp92064.c index 7e57006a8a12..d248bbea0d31 100644 --- a/drivers/iio/adc/ti-lmp92064.c +++ b/drivers/iio/adc/ti-lmp92064.c @@ -357,7 +357,7 @@ static int lmp92064_adc_probe(struct spi_device *spi) } static const struct spi_device_id lmp92064_id_table[] = { - { "lmp92064" }, + { .name = "lmp92064" }, { } }; MODULE_DEVICE_TABLE(spi, lmp92064_id_table); diff --git a/drivers/iio/adc/ti-tlc4541.c b/drivers/iio/adc/ti-tlc4541.c index f67945c62c99..ea776f80de72 100644 --- a/drivers/iio/adc/ti-tlc4541.c +++ b/drivers/iio/adc/ti-tlc4541.c @@ -24,7 +24,6 @@ #include <linux/iio/triggered_buffer.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> #include <linux/spi/spi.h> @@ -241,8 +240,8 @@ static const struct of_device_id tlc4541_dt_ids[] = { MODULE_DEVICE_TABLE(of, tlc4541_dt_ids); static const struct spi_device_id tlc4541_id[] = { - { "tlc3541", TLC3541 }, - { "tlc4541", TLC4541 }, + { .name = "tlc3541", .driver_data = TLC3541 }, + { .name = "tlc4541", .driver_data = TLC4541 }, { } }; MODULE_DEVICE_TABLE(spi, tlc4541_id); diff --git a/drivers/iio/adc/ti-tsc2046.c b/drivers/iio/adc/ti-tsc2046.c index aba4b10a17ac..125f6d7e2d84 100644 --- a/drivers/iio/adc/ti-tsc2046.c +++ b/drivers/iio/adc/ti-tsc2046.c @@ -121,11 +121,6 @@ struct tsc2046_adc_group_layout { 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; @@ -141,7 +136,6 @@ enum tsc2046_state { struct tsc2046_adc_priv { struct spi_device *spi; - const struct tsc2046_adc_dcfg *dcfg; bool internal_vref; struct iio_trigger *trig; @@ -214,11 +208,6 @@ const struct iio_chan_spec name ## _channels[] = { \ 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. @@ -739,7 +728,6 @@ static void tsc2046_adc_parse_fwnode(struct tsc2046_adc_priv *priv) 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; @@ -752,10 +740,6 @@ static int tsc2046_adc_probe(struct spi_device *spi) return -EINVAL; } - dcfg = spi_get_device_match_data(spi); - if (!dcfg) - return -EINVAL; - spi->mode &= ~SPI_MODE_X_MASK; spi->mode |= SPI_MODE_0; ret = spi_setup(spi); @@ -767,14 +751,13 @@ static int tsc2046_adc_probe(struct spi_device *spi) return -ENOMEM; priv = iio_priv(indio_dev); - priv->dcfg = dcfg; priv->spi = spi; indio_dev->name = TI_TSC2046_NAME; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = dcfg->channels; - indio_dev->num_channels = dcfg->num_channels; + indio_dev->channels = tsc2046_adc_channels; + indio_dev->num_channels = ARRAY_SIZE(tsc2046_adc_channels); indio_dev->info = &tsc2046_adc_info; ret = devm_regulator_get_enable_read_voltage(dev, "vref"); @@ -829,13 +812,13 @@ static int tsc2046_adc_probe(struct spi_device *spi) } static const struct of_device_id ads7950_of_table[] = { - { .compatible = "ti,tsc2046e-adc", .data = &tsc2046_adc_dcfg_tsc2046e }, + { .compatible = "ti,tsc2046e-adc" }, { } }; MODULE_DEVICE_TABLE(of, ads7950_of_table); static const struct spi_device_id tsc2046_adc_spi_ids[] = { - { "tsc2046e-adc", (unsigned long)&tsc2046_adc_dcfg_tsc2046e }, + { .name = "tsc2046e-adc" }, { } }; MODULE_DEVICE_TABLE(spi, tsc2046_adc_spi_ids); diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index a1a28584de93..1516dd332f90 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -113,10 +113,10 @@ static void tiadc_step_config(struct iio_dev *indio_dev) * There are 16 configurable steps and 8 analog input * lines available which are shared between Touchscreen and ADC. * - * Steps forwards i.e. from 0 towards 16 are used by ADC - * depending on number of input lines needed. + * Steps forward, i.e. from 0 towards 16, are used by ADC + * depending on the number of input lines needed. * Channel would represent which analog input - * needs to be given to ADC to digitalize data. + * needs to be given to ADC to digitize data. */ for (i = 0; i < adc_dev->channels; i++) { int chan; diff --git a/drivers/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c index fe3b31ec976e..0ee7e16b5e24 100644 --- a/drivers/iio/adc/twl4030-madc.c +++ b/drivers/iio/adc/twl4030-madc.c @@ -19,7 +19,6 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/delay.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/property.h> @@ -252,7 +251,7 @@ static const struct s16_fract twl4030_divider_ratios[16] = { {5, 11}, /* CHANNEL 15 */ }; -/* Conversion table from -3 to 55 degrees Celcius */ +/* Conversion table from -3 to 55 degrees Celsius */ static int twl4030_therm_tbl[] = { 30800, 29500, 28300, 27100, 26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700, diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c index 3ac774ebf678..31b1c01baa27 100644 --- a/drivers/iio/adc/twl6030-gpadc.c +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -16,7 +16,6 @@ */ #include <linux/interrupt.h> #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/property.h> @@ -416,7 +415,7 @@ static u8 twl6032_channel_to_reg(int channel) { /* * for any prior chosen channel, when the conversion is ready - * the result is avalable in GPCH0_LSB, GPCH0_MSB. + * the result is available in GPCH0_LSB, GPCH0_MSB. */ return TWL6032_GPADC_GPCH0_LSB; diff --git a/drivers/iio/adc/versal-sysmon-core.c b/drivers/iio/adc/versal-sysmon-core.c new file mode 100644 index 000000000000..1b55d343982e --- /dev/null +++ b/drivers/iio/adc/versal-sysmon-core.c @@ -0,0 +1,1052 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AMD Versal SysMon core driver + * + * Copyright (C) 2019 - 2022, Xilinx, Inc. + * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc. + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/cleanup.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/limits.h> +#include <linux/minmax.h> +#include <linux/module.h> +#include <linux/overflow.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/string.h> +#include <linux/sysfs.h> +#include <linux/units.h> + +#include <linux/iio/events.h> +#include <linux/iio/iio.h> + +#include "versal-sysmon.h" + +/* + * Oversampling ratio values exposed to userspace via IIO. + * Actual number of samples averaged: 1=none, 2=2x, 4=4x, 8=8x, 16=16x. + */ +static const int sysmon_oversampling_avail[] = { 1, 2, 4, 8, 16 }; + +/* TEMP hysteresis mode bit in SYSMON_TEMP_EV_CFG */ +#define SYSMON_TEMP_HYST_MASK BIT(1) + +/* Compute alarm register offset from a channel address */ +#define SYSMON_ALARM_OFFSET(addr) \ + (SYSMON_ALARM_REG + ((addr) / SYSMON_ALARM_BITS_PER_REG) * SYSMON_REG_STRIDE) + +#define SYSMON_CHAN_TEMP(_chan, _address, _name) \ +{ \ + .type = IIO_TEMP, \ + .indexed = 1, \ + .address = _address, \ + .channel = _chan, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .datasheet_name = _name, \ +} + +enum sysmon_alarm_bit { + SYSMON_BIT_ALARM0 = 0, + SYSMON_BIT_ALARM1 = 1, + SYSMON_BIT_ALARM2 = 2, + SYSMON_BIT_ALARM3 = 3, + SYSMON_BIT_ALARM4 = 4, + SYSMON_BIT_TEMP = 9, +}; + +/* Temperature event specification: rising threshold + hysteresis only */ +static const struct iio_event_spec sysmon_temp_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_HYSTERESIS), + }, +}; + +/* Supply event specifications */ +static const struct iio_event_spec sysmon_supply_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_ENABLE), + }, +}; + +/* + * Static temperature channels (always present). + * + * These are hardware-computed aggregate registers across all active + * temperature satellites: + * temp: current max temperature across all active satellites + * min: current min temperature across all active satellites + * max_max: highest peak recorded since last hardware reset + * min_min: lowest trough recorded since last hardware reset + */ +static const struct iio_chan_spec temp_channels[] = { + SYSMON_CHAN_TEMP(0, SYSMON_TEMP_MAX, "temp"), + SYSMON_CHAN_TEMP(1, SYSMON_TEMP_MIN, "min"), + SYSMON_CHAN_TEMP(2, SYSMON_TEMP_MAX_MAX, "max_max"), + SYSMON_CHAN_TEMP(3, SYSMON_TEMP_MIN_MIN, "min_min"), +}; + +static void sysmon_q8p7_to_millicelsius(s16 raw_data, int *val) +{ + *val = (raw_data * MILLIDEGREE_PER_DEGREE) >> SYSMON_FRACTIONAL_SHIFT; +} + +static void sysmon_millicelsius_to_q8p7(u32 *raw_data, int val) +{ + *raw_data = (val << SYSMON_FRACTIONAL_SHIFT) / MILLIDEGREE_PER_DEGREE; +} + +static void sysmon_supply_rawtoprocessed(int raw_data, int *val) +{ + int mantissa, format, exponent; + + mantissa = FIELD_GET(SYSMON_MANTISSA_MASK, raw_data); + exponent = SYSMON_SUPPLY_MANTISSA_BITS - FIELD_GET(SYSMON_MODE_MASK, raw_data); + format = FIELD_GET(SYSMON_FMT_MASK, raw_data); + /* + * When format bit is set the mantissa is two's complement + * (per hardware spec); sign-extend to int for correct arithmetic. + */ + if (format) + mantissa = sign_extend32(mantissa, 15); + + *val = (mantissa * (int)MILLI) >> exponent; +} + +static void sysmon_supply_processedtoraw(int val, u32 reg_val, u32 *raw_data) +{ + int exponent = FIELD_GET(SYSMON_MODE_MASK, reg_val); + int format = FIELD_GET(SYSMON_FMT_MASK, reg_val); + int scale, tmp; + + scale = BIT(SYSMON_SUPPLY_MANTISSA_BITS - exponent); + tmp = (val * scale) / (int)MILLI; + + if (format) + tmp = clamp(tmp, S16_MIN, S16_MAX); + else + tmp = clamp(tmp, 0, U16_MAX); + + *raw_data = (u16)tmp; +} + +static int sysmon_supply_thresh_offset(unsigned long address, enum iio_event_direction dir) +{ + if (dir == IIO_EV_DIR_RISING) + return (address * SYSMON_REG_STRIDE) + SYSMON_SUPPLY_TH_UP; + if (dir == IIO_EV_DIR_FALLING) + return (address * SYSMON_REG_STRIDE) + SYSMON_SUPPLY_TH_LOW; + + return -EINVAL; +} + +static int sysmon_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct sysmon *sysmon = iio_priv(indio_dev); + unsigned int regval; + int ret; + + guard(mutex)(&sysmon->lock); + + if (mask == IIO_CHAN_INFO_OVERSAMPLING_RATIO) { + *val = (chan->type == IIO_TEMP) ? sysmon->temp_oversampling : + sysmon->supply_oversampling; + return IIO_VAL_INT; + } + + switch (chan->type) { + case IIO_TEMP: + if (mask == IIO_CHAN_INFO_SCALE) { + /* Q8.7 to millicelsius: raw * 1000 / 128 */ + *val = MILLIDEGREE_PER_DEGREE; + *val2 = BIT(SYSMON_FRACTIONAL_SHIFT); + return IIO_VAL_FRACTIONAL; + } + if (mask != IIO_CHAN_INFO_RAW) + return -EINVAL; + + ret = regmap_read(sysmon->regmap, chan->address, ®val); + if (ret) + return ret; + + *val = sign_extend32(regval, 15); + return IIO_VAL_INT; + + case IIO_VOLTAGE: + if (mask != IIO_CHAN_INFO_PROCESSED) + return -EINVAL; + + ret = regmap_read(sysmon->regmap, + chan->address * SYSMON_REG_STRIDE + + SYSMON_SUPPLY_BASE, ®val); + if (ret) + return ret; + + sysmon_supply_rawtoprocessed(regval, val); + return IIO_VAL_INT; + + default: + return -EINVAL; + } +} + +static u32 sysmon_get_event_mask(const struct iio_chan_spec *chan) +{ + if (chan->type == IIO_TEMP) + return BIT(SYSMON_BIT_TEMP); + + return BIT(chan->address / SYSMON_ALARM_BITS_PER_REG); +} + +static int sysmon_read_alarm_config(struct sysmon *sysmon, + unsigned long address) +{ + u32 shift = address % SYSMON_ALARM_BITS_PER_REG; + u32 offset = SYSMON_ALARM_OFFSET(address); + + return regmap_test_bits(sysmon->regmap, offset, BIT(shift)); +} + +static int sysmon_write_alarm_config(struct sysmon *sysmon, + unsigned long address, bool enable) +{ + u32 shift = address % SYSMON_ALARM_BITS_PER_REG; + u32 offset = SYSMON_ALARM_OFFSET(address); + + return regmap_assign_bits(sysmon->regmap, offset, BIT(shift), enable); +} + +static int sysmon_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 sysmon *sysmon = iio_priv(indio_dev); + u32 mask = sysmon_get_event_mask(chan); + unsigned int imr; + int config_value; + int ret; + + ret = regmap_read(sysmon->regmap, SYSMON_IMR, &imr); + if (ret) + return ret; + + /* IMR bits are 1=masked, invert to get 1=enabled */ + imr = ~imr; + + switch (chan->type) { + case IIO_VOLTAGE: + config_value = sysmon_read_alarm_config(sysmon, chan->address); + if (config_value < 0) + return config_value; + return config_value && (imr & mask); + + case IIO_TEMP: + /* + * Return the administrative state, not the hardware IMR. + * The IRQ handler temporarily masks the interrupt during + * the polling window; reading IMR would show it as disabled. + * temp_mask bit is set when administratively disabled. + */ + return !(sysmon->temp_mask & mask); + + default: + return -EINVAL; + } +} + +static int sysmon_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + bool state) +{ + u32 offset = SYSMON_ALARM_OFFSET(chan->address); + struct sysmon *sysmon = iio_priv(indio_dev); + u32 mask = sysmon_get_event_mask(chan); + unsigned int alarm_config; + int ret; + + guard(mutex)(&sysmon->lock); + + switch (chan->type) { + case IIO_VOLTAGE: + ret = sysmon_write_alarm_config(sysmon, chan->address, state); + if (ret) + return ret; + + ret = regmap_read(sysmon->regmap, offset, &alarm_config); + if (ret) + return ret; + + if (alarm_config) + return regmap_write(sysmon->regmap, SYSMON_IER, mask); + + return regmap_write(sysmon->regmap, SYSMON_IDR, mask); + + case IIO_TEMP: + if (state) { + ret = regmap_write(sysmon->regmap, SYSMON_IER, mask); + if (ret) + return ret; + + scoped_guard(spinlock_irq, &sysmon->irq_lock) + sysmon->temp_mask &= ~mask; + } else { + ret = regmap_write(sysmon->regmap, SYSMON_IDR, mask); + if (ret) + return ret; + + scoped_guard(spinlock_irq, &sysmon->irq_lock) + sysmon->temp_mask |= mask; + } + return 0; + + default: + return -EINVAL; + } +} + +/* + * Recompute the lower threshold register from upper threshold and + * cached hysteresis. Called when either upper threshold or hysteresis + * is written. + */ +static int sysmon_update_temp_lower(struct sysmon *sysmon) +{ + unsigned int upper_reg; + int upper_mc, lower_mc; + u32 raw_val; + int ret; + + ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_UP, &upper_reg); + if (ret) + return ret; + + sysmon_q8p7_to_millicelsius(upper_reg, &upper_mc); + lower_mc = clamp(upper_mc - sysmon->temp_hysteresis, -256000, 255992); + sysmon_millicelsius_to_q8p7(&raw_val, lower_mc); + + return regmap_write(sysmon->regmap, SYSMON_TEMP_TH_LOW, raw_val); +} + +static int sysmon_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 sysmon *sysmon = iio_priv(indio_dev); + unsigned int reg_val; + int offset; + int ret; + + guard(mutex)(&sysmon->lock); + + switch (chan->type) { + case IIO_TEMP: + switch (info) { + case IIO_EV_INFO_VALUE: + ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_UP, ®_val); + if (ret) + return ret; + + sysmon_q8p7_to_millicelsius(reg_val, val); + + return IIO_VAL_INT; + + case IIO_EV_INFO_HYSTERESIS: + *val = sysmon->temp_hysteresis; + return IIO_VAL_INT; + + default: + return -EINVAL; + } + + case IIO_VOLTAGE: + offset = sysmon_supply_thresh_offset(chan->address, dir); + if (offset < 0) + return offset; + + ret = regmap_read(sysmon->regmap, offset, ®_val); + if (ret) + return ret; + + sysmon_supply_rawtoprocessed(reg_val, val); + + return IIO_VAL_INT; + + default: + return -EINVAL; + } +} + +static int sysmon_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 sysmon *sysmon = iio_priv(indio_dev); + unsigned int reg_val; + u32 raw_val; + int offset; + int ret; + + guard(mutex)(&sysmon->lock); + + switch (chan->type) { + case IIO_TEMP: + switch (info) { + case IIO_EV_INFO_VALUE: + /* Q8.7 signed range: -256000 to +255992 mC */ + if (val < -256000 || val > 255992) + return -EINVAL; + + sysmon_millicelsius_to_q8p7(&raw_val, val); + + ret = regmap_write(sysmon->regmap, SYSMON_TEMP_TH_UP, raw_val); + if (ret) + return ret; + + /* Recompute lower = upper - hysteresis */ + return sysmon_update_temp_lower(sysmon); + + case IIO_EV_INFO_HYSTERESIS: + if (val < 0) + return -EINVAL; + + sysmon->temp_hysteresis = val; + + return sysmon_update_temp_lower(sysmon); + + default: + return -EINVAL; + } + + case IIO_VOLTAGE: + offset = sysmon_supply_thresh_offset(chan->address, dir); + if (offset < 0) + return offset; + + ret = regmap_read(sysmon->regmap, offset, ®_val); + if (ret) + return ret; + + /* Clamp to prevent overflow in processedtoraw conversion */ + if (val < -32768 || val > 32767) + return -EINVAL; + + sysmon_supply_processedtoraw(val, reg_val, &raw_val); + + /* + * The hardware threshold register returns FMT and MODE + * bits in the upper 16 bits on read, but only the lower + * 16-bit mantissa is used on write. + */ + return regmap_write(sysmon->regmap, offset, raw_val); + + default: + return -EINVAL; + } +} + +static int sysmon_set_avg_enable(struct sysmon *sysmon, + u32 base, u32 count, u32 val) +{ + struct regmap *map = sysmon->regmap; + int ret; + + for (unsigned int i = 0; i < count; i++) { + ret = regmap_write(map, base + i * SYSMON_REG_STRIDE, val); + if (ret) + return ret; + } + + return 0; +} + +static int sysmon_osr_write_temp(struct sysmon *sysmon, unsigned int val) +{ + /* + * HW register encoding is sample_count / 2: + * 0=none, 1=2x, 2=4x, 4=8x, 8=16x (not log2-based). + */ + unsigned int hw_val = val >> 1; + unsigned int readback; + int ret; + + ret = regmap_update_bits(sysmon->regmap, SYSMON_CONFIG, + SYSMON_CONFIG_TEMP_SAT_OSR, + FIELD_PREP(SYSMON_CONFIG_TEMP_SAT_OSR, hw_val)); + if (ret) + return ret; + + /* + * Readback fence: the SysMon CONFIG register resides in the + * PMC domain behind the NoC. A posted write may not reach the + * hardware before the next MMIO access. Reading the register + * back forces the interconnect to complete the write, preventing + * a bus hang on the subsequent access. + */ + regmap_read(sysmon->regmap, SYSMON_CONFIG, &readback); + + return sysmon_set_avg_enable(sysmon, SYSMON_TEMP_EN_AVG_BASE, + SYSMON_TEMP_EN_AVG_COUNT, + hw_val ? ~0 : 0); +} + +static int sysmon_osr_write_supply(struct sysmon *sysmon, unsigned int val) +{ + /* HW encoding: sample_count / 2 (see sysmon_osr_write_temp) */ + unsigned int hw_val = val >> 1; + unsigned int readback; + int ret; + + ret = regmap_update_bits(sysmon->regmap, SYSMON_CONFIG, + SYSMON_CONFIG_SUPPLY_OSR, + FIELD_PREP(SYSMON_CONFIG_SUPPLY_OSR, hw_val)); + if (ret) + return ret; + + /* Readback fence -- see sysmon_osr_write_temp for details */ + regmap_read(sysmon->regmap, SYSMON_CONFIG, &readback); + + return sysmon_set_avg_enable(sysmon, SYSMON_SUPPLY_EN_AVG_BASE, + SYSMON_SUPPLY_EN_AVG_COUNT, + hw_val ? ~0 : 0); +} + +static int sysmon_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct sysmon *sysmon = iio_priv(indio_dev); + unsigned int i; + int ret; + + if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(sysmon_oversampling_avail); i++) { + if (val == sysmon_oversampling_avail[i]) + break; + } + if (i == ARRAY_SIZE(sysmon_oversampling_avail)) + return -EINVAL; + + guard(mutex)(&sysmon->lock); + + if (chan->type == IIO_TEMP) { + ret = sysmon_osr_write_temp(sysmon, val); + if (ret) + return ret; + sysmon->temp_oversampling = val; + } else { + ret = sysmon_osr_write_supply(sysmon, val); + if (ret) + return ret; + sysmon->supply_oversampling = val; + } + + return 0; +} + +static int sysmon_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + if (mask == IIO_CHAN_INFO_OVERSAMPLING_RATIO) + return IIO_VAL_INT; + + return -EINVAL; +} + +static int sysmon_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, + int *length, long mask) +{ + if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO) + return -EINVAL; + + *vals = sysmon_oversampling_avail; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(sysmon_oversampling_avail); + + return IIO_AVAIL_LIST; +} + +static int sysmon_read_label(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + char *label) +{ + if (chan->datasheet_name) + return sysfs_emit(label, "%s\n", chan->datasheet_name); + + return -EINVAL; +} + +static const struct iio_info sysmon_iio_info = { + .read_raw = sysmon_read_raw, + .write_raw = sysmon_write_raw, + .write_raw_get_fmt = sysmon_write_raw_get_fmt, + .read_avail = sysmon_read_avail, + .read_label = sysmon_read_label, + .read_event_config = sysmon_read_event_config, + .write_event_config = sysmon_write_event_config, + .read_event_value = sysmon_read_event_value, + .write_event_value = sysmon_write_event_value, +}; + +static void sysmon_push_event(struct iio_dev *indio_dev, u32 address) +{ + const struct iio_chan_spec *chan; + enum iio_event_direction dir; + + for (unsigned int i = 0; i < indio_dev->num_channels; i++) { + if (indio_dev->channels[i].address != address) + continue; + + chan = &indio_dev->channels[i]; + /* Temp uses hysteresis mode (rising only), voltage uses window */ + dir = (chan->type == IIO_TEMP) ? IIO_EV_DIR_RISING : + IIO_EV_DIR_EITHER; + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(chan->type, + chan->channel, + IIO_EV_TYPE_THRESH, + dir), + iio_get_time_ns(indio_dev)); + } +} + +static int sysmon_handle_event(struct iio_dev *indio_dev, u32 event) +{ + u32 alarm_flag_offset = SYSMON_ALARM_FLAG + event * SYSMON_REG_STRIDE; + u32 alarm_reg_offset = SYSMON_ALARM_REG + event * SYSMON_REG_STRIDE; + struct sysmon *sysmon = iio_priv(indio_dev); + unsigned long alarm_flag_reg; + unsigned int reg_val; + u32 address, bit; + int ret; + + switch (event) { + case SYSMON_BIT_TEMP: + sysmon_push_event(indio_dev, SYSMON_TEMP_MAX); + + ret = regmap_write(sysmon->regmap, SYSMON_IDR, BIT(SYSMON_BIT_TEMP)); + if (ret) + return ret; + + sysmon->masked_temp |= BIT(SYSMON_BIT_TEMP); + return 0; + + case SYSMON_BIT_ALARM0: + case SYSMON_BIT_ALARM1: + case SYSMON_BIT_ALARM2: + case SYSMON_BIT_ALARM3: + case SYSMON_BIT_ALARM4: + ret = regmap_read(sysmon->regmap, alarm_flag_offset, ®_val); + if (ret) + return ret; + + alarm_flag_reg = reg_val; + + for_each_set_bit(bit, &alarm_flag_reg, SYSMON_ALARM_BITS_PER_REG) { + address = bit + SYSMON_ALARM_BITS_PER_REG * event; + sysmon_push_event(indio_dev, address); + ret = regmap_clear_bits(sysmon->regmap, alarm_reg_offset, BIT(bit)); + if (ret) + return ret; + } + + return regmap_write(sysmon->regmap, alarm_flag_offset, alarm_flag_reg); + + default: + return -EINVAL; + } +} + +static void sysmon_handle_events(struct iio_dev *indio_dev, + unsigned long events) +{ + unsigned int bit; + + for_each_set_bit(bit, &events, SYSMON_NO_OF_EVENTS) + sysmon_handle_event(indio_dev, bit); +} + +static void sysmon_unmask_temp(struct sysmon *sysmon, unsigned int isr) +{ + unsigned int status; + u32 ier; + + status = isr & SYSMON_TEMP_INTR_MASK; + + ier = ~status & sysmon->masked_temp; + sysmon->masked_temp &= status; + + /* Only unmask if not administratively disabled by userspace */ + ier &= ~sysmon->temp_mask; + + regmap_write(sysmon->regmap, SYSMON_IER, ier); +} + +/* + * Versal threshold interrupts are level-sensitive. Active threshold + * interrupts are masked in the handler and polled via delayed work + * until the condition clears, then unmasked. + */ +static void sysmon_unmask_worker(struct work_struct *work) +{ + struct sysmon *sysmon = + container_of(work, struct sysmon, sysmon_unmask_work.work); + unsigned int isr; + + /* + * If the ISR read fails, skip processing to avoid acting + * on undefined data. + */ + scoped_guard(spinlock_irq, &sysmon->irq_lock) { + if (regmap_read(sysmon->regmap, SYSMON_ISR, &isr)) + break; + regmap_write(sysmon->regmap, SYSMON_ISR, isr); + sysmon_unmask_temp(sysmon, isr); + } + + if (sysmon->masked_temp) + schedule_delayed_work(&sysmon->sysmon_unmask_work, + msecs_to_jiffies(SYSMON_UNMASK_WORK_DELAY_MS)); + else + regmap_write(sysmon->regmap, SYSMON_STATUS_RESET, 1); +} + +static irqreturn_t sysmon_iio_irq(int irq, void *data) +{ + struct iio_dev *indio_dev = data; + struct sysmon *sysmon = iio_priv(indio_dev); + unsigned int isr, imr; + + guard(spinlock)(&sysmon->irq_lock); + + if (regmap_read(sysmon->regmap, SYSMON_ISR, &isr) || + regmap_read(sysmon->regmap, SYSMON_IMR, &imr)) + return IRQ_NONE; + + isr &= ~imr; + if (!isr) + return IRQ_NONE; + + regmap_write(sysmon->regmap, SYSMON_ISR, isr); + + sysmon_handle_events(indio_dev, isr); + schedule_delayed_work(&sysmon->sysmon_unmask_work, + msecs_to_jiffies(SYSMON_UNMASK_WORK_DELAY_MS)); + + return IRQ_HANDLED; +} + +static void sysmon_disable_interrupts(void *data) +{ + struct sysmon *sysmon = data; + + regmap_write(sysmon->regmap, SYSMON_IDR, SYSMON_INTR_ALL_MASK); + + scoped_guard(spinlock_irq, &sysmon->irq_lock) + sysmon->masked_temp = 0; + + cancel_delayed_work_sync(&sysmon->sysmon_unmask_work); +} + +static int sysmon_init_interrupt(struct sysmon *sysmon, + struct device *dev, + struct iio_dev *indio_dev, + int irq) +{ + unsigned int imr; + int ret; + + /* Events not supported without IRQ (e.g. I2C path) */ + if (!irq) + return 0; + + INIT_DELAYED_WORK(&sysmon->sysmon_unmask_work, sysmon_unmask_worker); + + ret = regmap_read(sysmon->regmap, SYSMON_IMR, &imr); + if (ret) + return ret; + sysmon->temp_mask = imr & SYSMON_TEMP_INTR_MASK; + + ret = devm_request_irq(dev, irq, sysmon_iio_irq, 0, "sysmon-irq", indio_dev); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, sysmon_disable_interrupts, sysmon); +} + +/* + * Initialize the cached hysteresis for a temperature channel from the + * current hardware threshold registers: hysteresis = upper - lower. + */ +static int sysmon_init_hysteresis(struct sysmon *sysmon, int *hysteresis) +{ + unsigned int upper_reg, lower_reg; + int upper_mc, lower_mc; + int ret; + + ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_UP, &upper_reg); + if (ret) + return ret; + + ret = regmap_read(sysmon->regmap, SYSMON_TEMP_TH_LOW, &lower_reg); + if (ret) + return ret; + + sysmon_q8p7_to_millicelsius(upper_reg, &upper_mc); + sysmon_q8p7_to_millicelsius(lower_reg, &lower_mc); + *hysteresis = upper_mc - lower_mc; + + return 0; +} + +/** + * sysmon_parse_fw() - Parse firmware nodes and configure IIO channels. + * @indio_dev: IIO device instance + * @dev: Parent device + * @irq: IRQ number (positive enables event channels, 0 disables) + * + * Reads voltage-channels and temperature-channels container nodes from + * firmware and builds the IIO channel array. Static temperature channels + * and event channels are prepended, followed by supply and satellite + * channels from DT. + * + * Event channels and per-channel event specs are only added when the + * device has an IRQ. I2C devices have no interrupt line, and the I2C + * regmap cannot be called from atomic context, so events are not + * supported on that path. + * + * Return: 0 on success, negative errno on failure. + */ +static int sysmon_parse_fw(struct iio_dev *indio_dev, struct device *dev, int irq) +{ + unsigned int num_chan, num_static, num_supply, num_temp; + unsigned int idx, temp_chan_idx, volt_chan_idx; + struct iio_chan_spec *sysmon_channels; + const char *label; + u32 reg; + int ret; + + struct fwnode_handle *supply_node __free(fwnode_handle) = + device_get_named_child_node(dev, "voltage-channels"); + num_supply = fwnode_get_child_node_count(supply_node); + + struct fwnode_handle *temp_node __free(fwnode_handle) = + device_get_named_child_node(dev, "temperature-channels"); + num_temp = fwnode_get_child_node_count(temp_node); + + num_static = ARRAY_SIZE(temp_channels); + num_chan = size_add(num_temp, size_add(num_static, num_supply)); + sysmon_channels = devm_kcalloc(dev, num_chan, sizeof(*sysmon_channels), GFP_KERNEL); + if (!sysmon_channels) + return -ENOMEM; + + memcpy(sysmon_channels, temp_channels, sizeof(temp_channels)); + + /* Attach event spec to channel 0 when IRQ is available */ + if (irq > 0) { + sysmon_channels[0].event_spec = sysmon_temp_events; + sysmon_channels[0].num_event_specs = ARRAY_SIZE(sysmon_temp_events); + } + + idx = num_static; + + /* Supply channels from DT */ + fwnode_for_each_child_node_scoped(supply_node, child) { + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret) + return dev_err_probe(dev, ret, + "missing reg for supply channel\n"); + + if (reg > SYSMON_SUPPLY_IDX_MAX) + return dev_err_probe(dev, -EINVAL, + "supply reg %u exceeds max %u\n", + reg, SYSMON_SUPPLY_IDX_MAX); + + ret = fwnode_property_read_string(child, "label", &label); + if (ret) + return dev_err_probe(dev, ret, + "missing label for supply channel\n"); + + sysmon_channels[idx++] = (struct iio_chan_spec) { + .type = IIO_VOLTAGE, + .indexed = 1, + .address = reg, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .info_mask_shared_by_type = + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_type_available = + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .event_spec = irq > 0 ? + sysmon_supply_events : NULL, + .num_event_specs = irq > 0 ? + ARRAY_SIZE(sysmon_supply_events) : 0, + .datasheet_name = label, + }; + } + + /* Temperature satellite channels from DT */ + fwnode_for_each_child_node_scoped(temp_node, child) { + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret) + return dev_err_probe(dev, ret, + "missing reg for temp channel\n"); + + if (reg < 1 || reg > SYSMON_TEMP_SAT_MAX) + return dev_err_probe(dev, -EINVAL, + "temp reg %u out of range [1..%u]\n", + reg, SYSMON_TEMP_SAT_MAX); + + ret = fwnode_property_read_string(child, "label", &label); + if (ret) + return dev_err_probe(dev, ret, + "missing label for temp channel\n"); + + sysmon_channels[idx++] = (struct iio_chan_spec) { + .type = IIO_TEMP, + .indexed = 1, + .address = SYSMON_TEMP_SAT_BASE + + (reg - 1) * SYSMON_REG_STRIDE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_type_available = + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .datasheet_name = label, + }; + } + + indio_dev->num_channels = idx; + indio_dev->info = &sysmon_iio_info; + + /* + * Assign per-type sequential channel numbers. + * IIO sysfs uses type prefix (in_tempN, in_voltageN) + * so numbers only need to be unique within each type. + */ + temp_chan_idx = 0; + volt_chan_idx = 0; + for (unsigned int idx = 0; idx < indio_dev->num_channels; idx++) { + if (sysmon_channels[idx].type == IIO_TEMP) + sysmon_channels[idx].channel = temp_chan_idx++; + else + sysmon_channels[idx].channel = volt_chan_idx++; + } + + indio_dev->channels = sysmon_channels; + + return 0; +} + +/** + * devm_versal_sysmon_core_probe() - Initialize Versal SysMon core + * @dev: Parent device + * @regmap: Register map for hardware access + * + * Return: 0 on success, negative errno on failure. + */ +int devm_versal_sysmon_core_probe(struct device *dev, struct regmap *regmap) +{ + struct iio_dev *indio_dev; + struct sysmon *sysmon; + int irq; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*sysmon)); + if (!indio_dev) + return -ENOMEM; + + sysmon = iio_priv(indio_dev); + sysmon->regmap = regmap; + sysmon->temp_oversampling = 1; + sysmon->supply_oversampling = 1; + + ret = devm_mutex_init(dev, &sysmon->lock); + if (ret) + return ret; + spin_lock_init(&sysmon->irq_lock); + + /* Disable all interrupts and clear pending status */ + ret = regmap_write(sysmon->regmap, SYSMON_IDR, SYSMON_INTR_ALL_MASK); + if (ret) + return ret; + ret = regmap_write(sysmon->regmap, SYSMON_ISR, SYSMON_INTR_ALL_MASK); + if (ret) + return ret; + + irq = fwnode_irq_get(dev_fwnode(dev), 0); + if (irq == -EPROBE_DEFER) + return dev_err_probe(dev, irq, "failed to get IRQ\n"); + + indio_dev->name = "versal-sysmon"; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = sysmon_parse_fw(indio_dev, dev, irq); + if (ret) + return ret; + + if (irq > 0) { + /* Set hysteresis mode for temperature threshold */ + ret = regmap_set_bits(sysmon->regmap, SYSMON_TEMP_EV_CFG, + SYSMON_TEMP_HYST_MASK); + if (ret) + return ret; + + /* Initialize cached hysteresis from hardware registers */ + ret = sysmon_init_hysteresis(sysmon, &sysmon->temp_hysteresis); + if (ret) + return ret; + + ret = sysmon_init_interrupt(sysmon, dev, indio_dev, irq); + if (ret) + return ret; + } + + return devm_iio_device_register(dev, indio_dev); +} +EXPORT_SYMBOL_NS_GPL(devm_versal_sysmon_core_probe, "VERSAL_SYSMON"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("AMD Versal SysMon Core Driver"); +MODULE_AUTHOR("Salih Erim <salih.erim@amd.com>"); diff --git a/drivers/iio/adc/versal-sysmon-i2c.c b/drivers/iio/adc/versal-sysmon-i2c.c new file mode 100644 index 000000000000..e9a7629159ab --- /dev/null +++ b/drivers/iio/adc/versal-sysmon-i2c.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AMD Versal SysMon I2C driver + * + * Copyright (C) 2023 - 2026, Advanced Micro Devices, Inc. + */ + +#include <linux/bits.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/types.h> +#include <linux/unaligned.h> + +#include "versal-sysmon.h" + +#define SYSMON_I2C_INSTR_READ BIT(2) +#define SYSMON_I2C_INSTR_WRITE BIT(3) + +/* + * I2C command frame layout (8 bytes): + * [0..3] data payload (little-endian u32) + * [4..5] register offset >> 2 (little-endian u16) + * [6] instruction (read/write) + * [7] reserved + */ +#define SYSMON_I2C_DATA_OFS 0 +#define SYSMON_I2C_REG_OFS 4 +#define SYSMON_I2C_INSTR_OFS 6 + +static int sysmon_i2c_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct i2c_client *client = context; + u8 write_buf[8] = { }; + u8 read_buf[4]; + int ret; + + put_unaligned_le16(reg >> 2, &write_buf[SYSMON_I2C_REG_OFS]); + write_buf[SYSMON_I2C_INSTR_OFS] = SYSMON_I2C_INSTR_READ; + + ret = i2c_master_send(client, write_buf, sizeof(write_buf)); + if (ret < 0) + return ret; + if (ret != sizeof(write_buf)) + return -EIO; + + ret = i2c_master_recv(client, read_buf, sizeof(read_buf)); + if (ret < 0) + return ret; + if (ret != sizeof(read_buf)) + return -EIO; + + *val = get_unaligned_le32(read_buf); + + return 0; +} + +static int sysmon_i2c_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + struct i2c_client *client = context; + u8 write_buf[8] = { }; + int ret; + + put_unaligned_le32(val, &write_buf[SYSMON_I2C_DATA_OFS]); + put_unaligned_le16(reg >> 2, &write_buf[SYSMON_I2C_REG_OFS]); + write_buf[SYSMON_I2C_INSTR_OFS] = SYSMON_I2C_INSTR_WRITE; + + ret = i2c_master_send(client, write_buf, sizeof(write_buf)); + if (ret < 0) + return ret; + if (ret != sizeof(write_buf)) + return -EIO; + + return 0; +} + +/* + * Almost all registers are volatile (live ADC readings, interrupt + * status). The rest are not accessed often enough to benefit from + * caching. + */ +static const struct regmap_config sysmon_i2c_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = SYSMON_REG_STRIDE, + .max_register = SYSMON_MAX_REG, + .reg_read = sysmon_i2c_reg_read, + .reg_write = sysmon_i2c_reg_write, +}; + +static int sysmon_i2c_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct regmap *regmap; + + regmap = devm_regmap_init(dev, NULL, client, &sysmon_i2c_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + /* I2C has no IRQ connection; events are not supported */ + return devm_versal_sysmon_core_probe(dev, regmap); +} + +static const struct of_device_id sysmon_i2c_of_match_table[] = { + { .compatible = "xlnx,versal-sysmon" }, + { } +}; +MODULE_DEVICE_TABLE(of, sysmon_i2c_of_match_table); + +static const struct i2c_device_id sysmon_i2c_id_table[] = { + { .name = "versal-sysmon" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sysmon_i2c_id_table); + +static struct i2c_driver sysmon_i2c_driver = { + .probe = sysmon_i2c_probe, + .driver = { + .name = "versal-sysmon-i2c", + .of_match_table = sysmon_i2c_of_match_table, + }, + .id_table = sysmon_i2c_id_table, +}; +module_i2c_driver(sysmon_i2c_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("AMD Versal SysMon I2C Driver"); +MODULE_IMPORT_NS("VERSAL_SYSMON"); +MODULE_AUTHOR("Conall O'Griofa <conall.ogriofa@amd.com>"); +MODULE_AUTHOR("Salih Erim <salih.erim@amd.com>"); diff --git a/drivers/iio/adc/versal-sysmon.c b/drivers/iio/adc/versal-sysmon.c new file mode 100644 index 000000000000..529d0486c9f9 --- /dev/null +++ b/drivers/iio/adc/versal-sysmon.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AMD Versal SysMon MMIO platform driver + * + * Copyright (C) 2019 - 2022, Xilinx, Inc. + * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc. + */ + +#include <linux/err.h> +#include <linux/io.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/types.h> + +#include "versal-sysmon.h" + +struct sysmon_mmio { + void __iomem *base; +}; + +static int sysmon_mmio_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + struct sysmon_mmio *mmio = context; + + *val = readl(mmio->base + reg); + return 0; +} + +static int sysmon_mmio_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct sysmon_mmio *mmio = context; + + /* NPI must be unlocked before any register write except to NPI_LOCK */ + if (reg != SYSMON_NPI_LOCK) + writel(SYSMON_NPI_UNLOCK_CODE, mmio->base + SYSMON_NPI_LOCK); + writel(val, mmio->base + reg); + + return 0; +} + +static const struct regmap_config sysmon_mmio_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = SYSMON_REG_STRIDE, + .max_register = SYSMON_MAX_REG, + .reg_read = sysmon_mmio_reg_read, + .reg_write = sysmon_mmio_reg_write, + .fast_io = true, +}; + +static int sysmon_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct sysmon_mmio *mmio; + struct regmap *regmap; + + mmio = devm_kzalloc(dev, sizeof(*mmio), GFP_KERNEL); + if (!mmio) + return -ENOMEM; + + mmio->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(mmio->base)) + return PTR_ERR(mmio->base); + + regmap = devm_regmap_init(dev, NULL, mmio, &sysmon_mmio_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return devm_versal_sysmon_core_probe(dev, regmap); +} + +static const struct of_device_id sysmon_of_match_table[] = { + { .compatible = "xlnx,versal-sysmon" }, + { } +}; +MODULE_DEVICE_TABLE(of, sysmon_of_match_table); + +static struct platform_driver sysmon_platform_driver = { + .probe = sysmon_platform_probe, + .driver = { + .name = "versal-sysmon", + .of_match_table = sysmon_of_match_table, + }, +}; +module_platform_driver(sysmon_platform_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("AMD Versal SysMon Platform Driver"); +MODULE_IMPORT_NS("VERSAL_SYSMON"); +MODULE_AUTHOR("Salih Erim <salih.erim@amd.com>"); diff --git a/drivers/iio/adc/versal-sysmon.h b/drivers/iio/adc/versal-sysmon.h new file mode 100644 index 000000000000..bb9a75bf71c0 --- /dev/null +++ b/drivers/iio/adc/versal-sysmon.h @@ -0,0 +1,120 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * AMD Versal SysMon driver + * + * Copyright (C) 2019 - 2022, Xilinx, Inc. + * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc. + */ + +#ifndef _VERSAL_SYSMON_H_ +#define _VERSAL_SYSMON_H_ + +#include <linux/bits.h> +#include <linux/mutex.h> +#include <linux/spinlock_types.h> +#include <linux/workqueue.h> + +struct device; +struct regmap; + +/* Register offsets (sorted by address) */ +#define SYSMON_NPI_LOCK 0x000C +#define SYSMON_ISR 0x0044 +#define SYSMON_IMR 0x0048 +#define SYSMON_IER 0x004C +#define SYSMON_IDR 0x0050 +#define SYSMON_CONFIG 0x0100 +#define SYSMON_TEMP_MAX 0x1030 +#define SYSMON_TEMP_MIN 0x1034 +#define SYSMON_SUPPLY_BASE 0x1040 +#define SYSMON_ALARM_FLAG 0x1018 +#define SYSMON_ALARM_REG 0x1940 +#define SYSMON_SUPPLY_EN_AVG_BASE 0x1958 +#define SYSMON_TEMP_TH_LOW 0x1970 +#define SYSMON_TEMP_TH_UP 0x1974 +#define SYSMON_SUPPLY_TH_LOW 0x1980 +#define SYSMON_SUPPLY_TH_UP 0x1C80 +#define SYSMON_TEMP_EV_CFG 0x1F84 +#define SYSMON_TEMP_MIN_MIN 0x1F8C +#define SYSMON_TEMP_MAX_MAX 0x1F90 +#define SYSMON_STATUS_RESET 0x1F94 +#define SYSMON_TEMP_SAT_BASE 0x1FAC +#define SYSMON_TEMP_EN_AVG_BASE 0x24B4 +#define SYSMON_MAX_REG 0x24C0 + +/* NPI unlock value written to SYSMON_NPI_LOCK */ +#define SYSMON_NPI_UNLOCK_CODE 0xF9E8D7C6 + +/* Register stride: 4 bytes per 32-bit register */ +#define SYSMON_REG_STRIDE 4 + +#define SYSMON_SUPPLY_IDX_MAX 159 +#define SYSMON_TEMP_SAT_MAX 64 +#define SYSMON_NO_OF_EVENTS 32 +#define SYSMON_INTR_ALL_MASK GENMASK(31, 0) + +/* ISR/IMR temperature alarm mask (bit 9) */ +#define SYSMON_TEMP_INTR_MASK BIT(9) + +/* SYSMON_CONFIG: supply oversampling ratio */ +#define SYSMON_CONFIG_SUPPLY_OSR GENMASK(17, 14) + +/* SYSMON_CONFIG: temperature satellite oversampling ratio */ +#define SYSMON_CONFIG_TEMP_SAT_OSR GENMASK(27, 24) + +/* Per-channel averaging enable register counts */ +#define SYSMON_SUPPLY_EN_AVG_COUNT 5 +#define SYSMON_TEMP_EN_AVG_COUNT 2 + +/* Supply voltage conversion register fields */ +#define SYSMON_MANTISSA_MASK GENMASK(15, 0) +#define SYSMON_FMT_MASK BIT(16) +#define SYSMON_MODE_MASK GENMASK(18, 17) + +/* Q8.7 fractional shift */ +#define SYSMON_FRACTIONAL_SHIFT 7U +#define SYSMON_SUPPLY_MANTISSA_BITS 16 + +/* Bits per alarm register */ +#define SYSMON_ALARM_BITS_PER_REG 32 + +#define SYSMON_UNMASK_WORK_DELAY_MS 500 + +/** + * struct sysmon - Driver data for Versal SysMon + * @regmap: register map for hardware access + * @lock: protects read-modify-write sequences on threshold registers + * and cached state that spans multiple regmap calls + * @irq_lock: protects interrupt mask register updates (MMIO path only) + * @masked_temp: currently masked temperature alarm bits + * @temp_mask: temperature interrupt configuration mask + * @temp_hysteresis: cached DEVICE_TEMP hysteresis in millicelsius + * @sysmon_unmask_work: re-enables events after alarm condition clears + * @temp_oversampling: current temp oversampling ratio + * @supply_oversampling: current supply oversampling ratio + */ +struct sysmon { + struct regmap *regmap; + /* + * Protects read-modify-write sequences on threshold registers + * and cached state (oversampling ratios, hysteresis values) + * that spans multiple regmap calls. + */ + struct mutex lock; + /* + * Protects interrupt mask register updates. Only used on the + * MMIO path (fast_io regmap); I2C has no IRQ and never reaches + * the event code that takes this lock. + */ + spinlock_t irq_lock; + unsigned int masked_temp; + unsigned int temp_mask; + int temp_hysteresis; + struct delayed_work sysmon_unmask_work; + unsigned int temp_oversampling; + unsigned int supply_oversampling; +}; + +int devm_versal_sysmon_core_probe(struct device *dev, struct regmap *regmap); + +#endif /* _VERSAL_SYSMON_H_ */ diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index d7182ed0d2a7..bcbeb482e714 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -5,7 +5,6 @@ * Copyright 2013 Freescale Semiconductor, Inc. */ -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/property.h> diff --git a/drivers/iio/adc/viperboard_adc.c b/drivers/iio/adc/viperboard_adc.c index 9bb0b83c8f67..6efe1c618ef7 100644 --- a/drivers/iio/adc/viperboard_adc.c +++ b/drivers/iio/adc/viperboard_adc.c @@ -70,8 +70,10 @@ static int vprbrd_iio_read_raw(struct iio_dev *iio_dev, VPRBRD_USB_TYPE_OUT, 0x0000, 0x0000, admsg, sizeof(struct vprbrd_adc_msg), VPRBRD_USB_TIMEOUT_MS); if (ret != sizeof(struct vprbrd_adc_msg)) { - dev_err(&iio_dev->dev, "usb send error on adc read\n"); + mutex_unlock(&vb->lock); error = -EREMOTEIO; + dev_err(&iio_dev->dev, "usb send error on adc read\n"); + goto error; } ret = usb_control_msg(vb->usb_dev, diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c index 124470c92529..158e6133abf5 100644 --- a/drivers/iio/adc/xilinx-ams.c +++ b/drivers/iio/adc/xilinx-ams.c @@ -18,7 +18,6 @@ #include <linux/iopoll.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/overflow.h> #include <linux/platform_device.h> #include <linux/property.h> @@ -102,6 +101,7 @@ #define AMS_PS_SEQ_MASK GENMASK(21, 0) #define AMS_PL_SEQ_MASK GENMASK_ULL(59, 22) +#define AMS_ALARM_NONE 0x000 /* not a real offset */ #define AMS_ALARM_TEMP 0x140 #define AMS_ALARM_SUPPLY1 0x144 #define AMS_ALARM_SUPPLY2 0x148 @@ -720,22 +720,20 @@ static int ams_read_raw(struct iio_dev *indio_dev, int ret; switch (mask) { - case IIO_CHAN_INFO_RAW: - mutex_lock(&ams->lock); + case IIO_CHAN_INFO_RAW: { + guard(mutex)(&ams->lock); if (chan->scan_index >= AMS_CTRL_SEQ_BASE) { ret = ams_read_vcc_reg(ams, chan->address, val); if (ret) - goto unlock_mutex; + return ret; ams_enable_channel_sequence(indio_dev); } else if (chan->scan_index >= AMS_PS_SEQ_MAX) *val = readl(ams->pl_base + chan->address); else *val = readl(ams->ps_base + chan->address); - ret = IIO_VAL_INT; -unlock_mutex: - mutex_unlock(&ams->lock); - return ret; + return IIO_VAL_INT; + } case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_VOLTAGE: @@ -765,9 +763,49 @@ unlock_mutex: } } +struct ams_alarm_map { + enum ams_ps_pl_seq scan_index; + unsigned int base_offset; +}; + +/* + * Array index matches enum ams_alarm_bit. + * Entries with base_offset == AMS_ALARM_NONE are unused/invalid + * (e.g. RESERVED) and must be skipped. + */ +static const struct ams_alarm_map alarm_map[] = { + [AMS_ALARM_BIT_TEMP] = { AMS_SEQ_TEMP, AMS_ALARM_TEMP }, + [AMS_ALARM_BIT_SUPPLY1] = { AMS_SEQ_SUPPLY1, AMS_ALARM_SUPPLY1 }, + [AMS_ALARM_BIT_SUPPLY2] = { AMS_SEQ_SUPPLY2, AMS_ALARM_SUPPLY2 }, + [AMS_ALARM_BIT_SUPPLY3] = { AMS_SEQ_SUPPLY3, AMS_ALARM_SUPPLY3 }, + [AMS_ALARM_BIT_SUPPLY4] = { AMS_SEQ_SUPPLY4, AMS_ALARM_SUPPLY4 }, + [AMS_ALARM_BIT_SUPPLY5] = { AMS_SEQ_SUPPLY5, AMS_ALARM_SUPPLY5 }, + [AMS_ALARM_BIT_SUPPLY6] = { AMS_SEQ_SUPPLY6, AMS_ALARM_SUPPLY6 }, + [AMS_ALARM_BIT_RESERVED] = { 0, AMS_ALARM_NONE }, + [AMS_ALARM_BIT_SUPPLY7] = { AMS_SEQ_SUPPLY7, AMS_ALARM_SUPPLY7 }, + [AMS_ALARM_BIT_SUPPLY8] = { AMS_SEQ_SUPPLY8, AMS_ALARM_SUPPLY8 }, + [AMS_ALARM_BIT_SUPPLY9] = { AMS_SEQ_SUPPLY9, AMS_ALARM_SUPPLY9 }, + [AMS_ALARM_BIT_SUPPLY10] = { AMS_SEQ_SUPPLY10, AMS_ALARM_SUPPLY10 }, + [AMS_ALARM_BIT_VCCAMS] = { AMS_SEQ_VCCAMS, AMS_ALARM_VCCAMS }, + [AMS_ALARM_BIT_TEMP_REMOTE] = { AMS_SEQ_TEMP_REMOTE, AMS_ALARM_TEMP_REMOTE }, +}; + +static int ams_scan_index_to_event(int scan_index) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(alarm_map); i++) { + if (alarm_map[i].base_offset == AMS_ALARM_NONE) + continue; + + if (alarm_map[i].scan_index == scan_index) + return i; + } + + return -EINVAL; +} + static int ams_get_alarm_offset(int scan_index, enum iio_event_direction dir) { - int offset; + int offset, event; if (scan_index >= AMS_PS_SEQ_MAX) scan_index -= AMS_PS_SEQ_MAX; @@ -781,36 +819,11 @@ static int ams_get_alarm_offset(int scan_index, enum iio_event_direction dir) offset = 0; } - switch (scan_index) { - case AMS_SEQ_TEMP: - return AMS_ALARM_TEMP + offset; - case AMS_SEQ_SUPPLY1: - return AMS_ALARM_SUPPLY1 + offset; - case AMS_SEQ_SUPPLY2: - return AMS_ALARM_SUPPLY2 + offset; - case AMS_SEQ_SUPPLY3: - return AMS_ALARM_SUPPLY3 + offset; - case AMS_SEQ_SUPPLY4: - return AMS_ALARM_SUPPLY4 + offset; - case AMS_SEQ_SUPPLY5: - return AMS_ALARM_SUPPLY5 + offset; - case AMS_SEQ_SUPPLY6: - return AMS_ALARM_SUPPLY6 + offset; - case AMS_SEQ_SUPPLY7: - return AMS_ALARM_SUPPLY7 + offset; - case AMS_SEQ_SUPPLY8: - return AMS_ALARM_SUPPLY8 + offset; - case AMS_SEQ_SUPPLY9: - return AMS_ALARM_SUPPLY9 + offset; - case AMS_SEQ_SUPPLY10: - return AMS_ALARM_SUPPLY10 + offset; - case AMS_SEQ_VCCAMS: - return AMS_ALARM_VCCAMS + offset; - case AMS_SEQ_TEMP_REMOTE: - return AMS_ALARM_TEMP_REMOTE + offset; - default: + event = ams_scan_index_to_event(scan_index); + if (event < 0 || alarm_map[event].base_offset == AMS_ALARM_NONE) return 0; - } + + return alarm_map[event].base_offset + offset; } static const struct iio_chan_spec *ams_event_to_channel(struct iio_dev *dev, @@ -823,96 +836,38 @@ static const struct iio_chan_spec *ams_event_to_channel(struct iio_dev *dev, scan_index = AMS_PS_SEQ_MAX; } - switch (event) { - case AMS_ALARM_BIT_TEMP: - scan_index += AMS_SEQ_TEMP; - break; - case AMS_ALARM_BIT_SUPPLY1: - scan_index += AMS_SEQ_SUPPLY1; - break; - case AMS_ALARM_BIT_SUPPLY2: - scan_index += AMS_SEQ_SUPPLY2; - break; - case AMS_ALARM_BIT_SUPPLY3: - scan_index += AMS_SEQ_SUPPLY3; - break; - case AMS_ALARM_BIT_SUPPLY4: - scan_index += AMS_SEQ_SUPPLY4; - break; - case AMS_ALARM_BIT_SUPPLY5: - scan_index += AMS_SEQ_SUPPLY5; - break; - case AMS_ALARM_BIT_SUPPLY6: - scan_index += AMS_SEQ_SUPPLY6; - break; - case AMS_ALARM_BIT_SUPPLY7: - scan_index += AMS_SEQ_SUPPLY7; - break; - case AMS_ALARM_BIT_SUPPLY8: - scan_index += AMS_SEQ_SUPPLY8; - break; - case AMS_ALARM_BIT_SUPPLY9: - scan_index += AMS_SEQ_SUPPLY9; - break; - case AMS_ALARM_BIT_SUPPLY10: - scan_index += AMS_SEQ_SUPPLY10; - break; - case AMS_ALARM_BIT_VCCAMS: - scan_index += AMS_SEQ_VCCAMS; - break; - case AMS_ALARM_BIT_TEMP_REMOTE: - scan_index += AMS_SEQ_TEMP_REMOTE; - break; - default: - break; - } + if (event >= ARRAY_SIZE(alarm_map)) + return NULL; + + if (alarm_map[event].base_offset == AMS_ALARM_NONE) + return NULL; + + scan_index += alarm_map[event].scan_index; for (i = 0; i < dev->num_channels; i++) if (dev->channels[i].scan_index == scan_index) break; + if (i == dev->num_channels) + return NULL; + return &dev->channels[i]; } static int ams_get_alarm_mask(int scan_index) { - int bit = 0; + int bit = 0, event; if (scan_index >= AMS_PS_SEQ_MAX) { bit = AMS_PL_ALARM_START; scan_index -= AMS_PS_SEQ_MAX; } - switch (scan_index) { - case AMS_SEQ_TEMP: - return BIT(AMS_ALARM_BIT_TEMP + bit); - case AMS_SEQ_SUPPLY1: - return BIT(AMS_ALARM_BIT_SUPPLY1 + bit); - case AMS_SEQ_SUPPLY2: - return BIT(AMS_ALARM_BIT_SUPPLY2 + bit); - case AMS_SEQ_SUPPLY3: - return BIT(AMS_ALARM_BIT_SUPPLY3 + bit); - case AMS_SEQ_SUPPLY4: - return BIT(AMS_ALARM_BIT_SUPPLY4 + bit); - case AMS_SEQ_SUPPLY5: - return BIT(AMS_ALARM_BIT_SUPPLY5 + bit); - case AMS_SEQ_SUPPLY6: - return BIT(AMS_ALARM_BIT_SUPPLY6 + bit); - case AMS_SEQ_SUPPLY7: - return BIT(AMS_ALARM_BIT_SUPPLY7 + bit); - case AMS_SEQ_SUPPLY8: - return BIT(AMS_ALARM_BIT_SUPPLY8 + bit); - case AMS_SEQ_SUPPLY9: - return BIT(AMS_ALARM_BIT_SUPPLY9 + bit); - case AMS_SEQ_SUPPLY10: - return BIT(AMS_ALARM_BIT_SUPPLY10 + bit); - case AMS_SEQ_VCCAMS: - return BIT(AMS_ALARM_BIT_VCCAMS + bit); - case AMS_SEQ_TEMP_REMOTE: - return BIT(AMS_ALARM_BIT_TEMP_REMOTE + bit); - default: + event = ams_scan_index_to_event(scan_index); + if (event < 0) return 0; - } + + return BIT(event + bit); } static int ams_read_event_config(struct iio_dev *indio_dev, @@ -936,7 +891,7 @@ static int ams_write_event_config(struct iio_dev *indio_dev, alarm = ams_get_alarm_mask(chan->scan_index); - mutex_lock(&ams->lock); + guard(mutex)(&ams->lock); if (state) ams->alarm_mask |= alarm; @@ -945,8 +900,6 @@ static int ams_write_event_config(struct iio_dev *indio_dev, ams_update_alarm(ams, ams->alarm_mask); - mutex_unlock(&ams->lock); - return 0; } @@ -959,15 +912,13 @@ static int ams_read_event_value(struct iio_dev *indio_dev, struct ams *ams = iio_priv(indio_dev); unsigned int offset = ams_get_alarm_offset(chan->scan_index, dir); - mutex_lock(&ams->lock); + guard(mutex)(&ams->lock); if (chan->scan_index >= AMS_PS_SEQ_MAX) *val = readl(ams->pl_base + offset); else *val = readl(ams->ps_base + offset); - mutex_unlock(&ams->lock); - return IIO_VAL_INT; } @@ -980,7 +931,7 @@ static int ams_write_event_value(struct iio_dev *indio_dev, struct ams *ams = iio_priv(indio_dev); unsigned int offset; - mutex_lock(&ams->lock); + guard(mutex)(&ams->lock); /* Set temperature channel threshold to direct threshold */ if (chan->type == IIO_TEMP) { @@ -1002,8 +953,6 @@ static int ams_write_event_value(struct iio_dev *indio_dev, else writel(val, ams->ps_base + offset); - mutex_unlock(&ams->lock); - return 0; } @@ -1012,6 +961,8 @@ static void ams_handle_event(struct iio_dev *indio_dev, u32 event) const struct iio_chan_spec *chan; chan = ams_event_to_channel(indio_dev, event); + if (!chan) + return; if (chan->type == IIO_TEMP) { /* diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index e257c1b94a5f..cab66bb8cc1c 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -17,7 +17,6 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/overflow.h> #include <linux/platform_device.h> @@ -817,6 +816,7 @@ static int xadc_postdisable(struct iio_dev *indio_dev) { struct xadc *xadc = iio_priv(indio_dev); unsigned long scan_mask; + int seq_mode; int ret; int i; @@ -824,6 +824,12 @@ static int xadc_postdisable(struct iio_dev *indio_dev) for (i = 0; i < indio_dev->num_channels; i++) scan_mask |= BIT(indio_dev->channels[i].scan_index); + /* + * Use the correct sequencer mode for the idle state: simultaneous + * mode for dual external mux configurations, continuous otherwise. + */ + seq_mode = xadc_get_seq_mode(xadc, scan_mask); + /* Enable all channels and calibration */ ret = xadc_write_adc_reg(xadc, XADC_REG_SEQ(0), scan_mask & 0xffff); if (ret) @@ -834,11 +840,11 @@ static int xadc_postdisable(struct iio_dev *indio_dev) return ret; ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_SEQ_MASK, - XADC_CONF1_SEQ_CONTINUOUS); + seq_mode); if (ret) return ret; - return xadc_power_adc_b(xadc, XADC_CONF1_SEQ_CONTINUOUS); + return xadc_power_adc_b(xadc, seq_mode); } static int xadc_preenable(struct iio_dev *indio_dev) diff --git a/drivers/iio/addac/ad74115.c b/drivers/iio/addac/ad74115.c index f8b04d86b01f..9b9d7a12ce87 100644 --- a/drivers/iio/addac/ad74115.c +++ b/drivers/iio/addac/ad74115.c @@ -1835,7 +1835,10 @@ static int ad74115_probe(struct spi_device *spi) st = iio_priv(indio_dev); st->spi = spi; - mutex_init(&st->lock); + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; + init_completion(&st->adc_data_completion); indio_dev->name = AD74115_NAME; @@ -1901,7 +1904,7 @@ static int __init ad74115_register_driver(struct spi_driver *spi) } static const struct spi_device_id ad74115_spi_id[] = { - { "ad74115h" }, + { .name = "ad74115h" }, { } }; diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c index a20b4d48c5f7..2e5a58e48a89 100644 --- a/drivers/iio/addac/ad74413r.c +++ b/drivers/iio/addac/ad74413r.c @@ -18,7 +18,6 @@ #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> #include <linux/interrupt.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> @@ -839,12 +838,9 @@ static int _ad74413r_get_single_adc_result(struct ad74413r_state *st, if (ret) return ret; - ret = wait_for_completion_timeout(&st->adc_data_completion, - msecs_to_jiffies(1000)); - if (!ret) { - ret = -ETIMEDOUT; - return ret; - } + if (!wait_for_completion_timeout(&st->adc_data_completion, + msecs_to_jiffies(1000))) + return -ETIMEDOUT; ret = regmap_read(st->regmap, AD74413R_REG_ADC_RESULT_X(channel), &uval); @@ -1461,7 +1457,7 @@ static int ad74413r_probe(struct spi_device *spi) ret = devm_request_irq(st->dev, spi->irq, ad74413r_adc_data_interrupt, 0, st->chip_info->name, indio_dev); if (ret) - return dev_err_probe(st->dev, ret, "Failed to request irq\n"); + return ret; ret = devm_iio_triggered_buffer_setup(st->dev, indio_dev, &iio_pollfunc_store_time, diff --git a/drivers/iio/addac/stx104.c b/drivers/iio/addac/stx104.c index 7bdf2cb94176..6207eb2fac74 100644 --- a/drivers/iio/addac/stx104.c +++ b/drivers/iio/addac/stx104.c @@ -349,9 +349,9 @@ static const struct iio_chan_spec stx104_channels_diff[] = { STX104_IN_CHAN(6, 1), STX104_IN_CHAN(7, 1) }; -static int stx104_reg_mask_xlate(struct gpio_regmap *const gpio, const unsigned int base, - unsigned int offset, unsigned int *const reg, - unsigned int *const mask) +static int stx104_reg_mask_xlate(struct gpio_regmap *const gpio, enum gpio_regmap_operation op, + const unsigned int base, unsigned int offset, + unsigned int *const reg, unsigned int *const mask) { /* Output lines are located at same register bit offsets as input lines */ if (offset >= 4) diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c index ecaf59278c6f..3a6a09ffa526 100644 --- a/drivers/iio/afe/iio-rescale.c +++ b/drivers/iio/afe/iio-rescale.c @@ -10,7 +10,6 @@ #include <linux/err.h> #include <linux/gcd.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/property.h> @@ -609,3 +608,4 @@ module_platform_driver(rescale_driver); MODULE_DESCRIPTION("IIO rescale driver"); MODULE_AUTHOR("Peter Rosin <peda@axentia.se>"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/iio/amplifiers/Kconfig b/drivers/iio/amplifiers/Kconfig index a8a604863eed..9e24421b5e97 100644 --- a/drivers/iio/amplifiers/Kconfig +++ b/drivers/iio/amplifiers/Kconfig @@ -18,7 +18,15 @@ config AD8366 AD8366 Dual-Digital Variable Gain Amplifier (VGA) ADA4961 BiCMOS RF Digital Gain Amplifier (DGA) ADL5240 Digitally controlled variable gain amplifier (VGA) + ADRF5702: 0.125 dB LSB, 8-Bit, Silicon Digital Attenuator + ADRF5703: 0.25 dB LSB, 7-Bit, Silicon Digital Attenuator + ADRF5720: 0.5 dB LSB, 6-Bit, Silicon Digital Attenuator + ADRF5730: 0.5 dB LSB, 6-Bit, Silicon Digital Attenuator + ADRF5731: 2 dB LSB, 4-Bit, Silicon Digital Attenuator + HMC271A: 1dB LSB 5-Bit Digital Attenuator SMT HMC792A 0.25 dB LSB GaAs MMIC 6-Bit Digital Attenuator + HMC1018A: 1.0 dB LSB GaAs MMIC 5-BIT Digital Attenuator + HMC1019A: 0.5 dB LSB GaAs MMIC 5-BIT Digital Attenuator HMC1119 0.25 dB LSB, 7-Bit, Silicon Digital Attenuator To compile this driver as a module, choose M here: the diff --git a/drivers/iio/amplifiers/ad8366.c b/drivers/iio/amplifiers/ad8366.c index d06ac786501c..e12f8604f59f 100644 --- a/drivers/iio/amplifiers/ad8366.c +++ b/drivers/iio/amplifiers/ad8366.c @@ -5,46 +5,51 @@ * AD8366 Dual-Digital Variable Gain Amplifier (VGA) * ADA4961 BiCMOS RF Digital Gain Amplifier (DGA) * ADL5240 Digitally controlled variable gain amplifier (VGA) + * ADRF5702: 0.125 dB LSB, 8-Bit, Silicon Digital Attenuator, 50 MHz to 20 GHz + * ADRF5703: 0.25 dB LSB, 7-Bit, Silicon Digital Attenuator, 9 kHz to 20 GHz + * ADRF5720: 0.5 dB LSB, 6-Bit, Silicon Digital Attenuator, 9 kHz to 40 GHz + * ADRF5730: 0.5 dB LSB, 6-Bit, Silicon Digital Attenuator, 100 MHz to 40 GHz + * ADRF5731: 2 dB LSB, 4-Bit, Silicon Digital Attenuator, 100 MHz to 40 GHz + * HMC271A: 1dB LSB 5-Bit Digital Attenuator SMT, 0.7 - 3.7 GHz * HMC792A 0.25 dB LSB GaAs MMIC 6-Bit Digital Attenuator + * HMC1018A: 1.0 dB LSB GaAs MMIC 5-BIT DIGITAL ATTENUATOR, 0.1 - 30 GHz + * HMC1019A: 0.5 dB LSB GaAs MMIC 5-BIT DIGITAL ATTENUATOR, 0.1 - 30 GHz * HMC1119 0.25 dB LSB, 7-Bit, Silicon Digital Attenuator * - * Copyright 2012-2019 Analog Devices Inc. + * Copyright 2012-2026 Analog Devices Inc. */ -#include <linux/device.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/sysfs.h> -#include <linux/spi/spi.h> -#include <linux/regulator/consumer.h> -#include <linux/gpio/consumer.h> +#include <linux/bitrev.h> +#include <linux/bits.h> +#include <linux/dev_printk.h> #include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/math.h> +#include <linux/minmax.h> #include <linux/module.h> -#include <linux/bitrev.h> +#include <linux/mutex.h> +#include <linux/regulator/consumer.h> +#include <linux/reset.h> +#include <linux/spi/spi.h> +#include <linux/types.h> +#include <linux/unaligned.h> #include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> - -enum ad8366_type { - ID_AD8366, - ID_ADA4961, - ID_ADL5240, - ID_HMC792, - ID_HMC1119, -}; struct ad8366_info { + const char *name; int gain_min; int gain_max; + int gain_step; + size_t num_channels; + size_t (*pack_code)(const unsigned char *code, size_t num_channels, + unsigned char *data); }; struct ad8366_state { struct spi_device *spi; - struct regulator *reg; struct mutex lock; /* protect sensor state */ - struct gpio_desc *reset_gpio; unsigned char ch[2]; - enum ad8366_type type; const struct ad8366_info *info; /* * DMA (thus cache coherency maintenance) may require the @@ -53,60 +58,148 @@ struct ad8366_state { unsigned char data[2] __aligned(IIO_DMA_MINALIGN); }; -static const struct ad8366_info ad8366_infos[] = { - [ID_AD8366] = { - .gain_min = 4500, - .gain_max = 20500, - }, - [ID_ADA4961] = { - .gain_min = -6000, - .gain_max = 15000, - }, - [ID_ADL5240] = { - .gain_min = -11500, - .gain_max = 20000, - }, - [ID_HMC792] = { - .gain_min = -15750, - .gain_max = 0, - }, - [ID_HMC1119] = { - .gain_min = -31750, - .gain_max = 0, - }, -}; +static size_t ad8366_pack_code(const unsigned char *code, size_t num_channels, + unsigned char *data) +{ + u8 ch_a = bitrev8(code[0]) >> 2; + u8 ch_b = bitrev8(code[1]) >> 2; + + put_unaligned_be16((ch_b << 6) | ch_a, &data[0]); + return sizeof(__be16); +} -static int ad8366_write(struct iio_dev *indio_dev, - unsigned char ch_a, unsigned char ch_b) +static size_t adrf5731_pack_code(const unsigned char *code, size_t num_channels, + unsigned char *data) { - struct ad8366_state *st = iio_priv(indio_dev); - int ret; + data[0] = code[0] << 2; + return 1; +} - switch (st->type) { - case ID_AD8366: - ch_a = bitrev8(ch_a & 0x3F); - ch_b = bitrev8(ch_b & 0x3F); +static size_t hmc271_pack_code(const unsigned char *code, size_t num_channels, + unsigned char *data) +{ + data[0] = bitrev8(code[0]) >> 3; + return 1; +} - st->data[0] = ch_b >> 4; - st->data[1] = (ch_b << 4) | (ch_a >> 2); - break; - case ID_ADA4961: - st->data[0] = ch_a & 0x1F; - break; - case ID_ADL5240: - st->data[0] = (ch_a & 0x3F); - break; - case ID_HMC792: - case ID_HMC1119: - st->data[0] = ch_a; - break; - } +static const struct ad8366_info ad8366_chip_info = { + .name = "ad8366", + .gain_min = 4500, + .gain_max = 20500, + .gain_step = 253, + .num_channels = 2, + .pack_code = ad8366_pack_code, +}; - ret = spi_write(st->spi, st->data, indio_dev->num_channels); - if (ret < 0) - dev_err(&indio_dev->dev, "write failed (%d)", ret); +static const struct ad8366_info ada4961_chip_info = { + .name = "ada4961", + .gain_min = -6000, + .gain_max = 15000, + .gain_step = -1000, + .num_channels = 1, +}; - return ret; +static const struct ad8366_info adl5240_chip_info = { + .name = "adl5240", + .gain_min = -11500, + .gain_max = 20000, + .gain_step = 500, + .num_channels = 1, +}; + +static const struct ad8366_info adrf5702_chip_info = { + .name = "adrf5702", + .gain_min = -31875, + .gain_max = 0, + .gain_step = -125, + .num_channels = 1, +}; + +static const struct ad8366_info adrf5703_chip_info = { + .name = "adrf5703", + .gain_min = -31750, + .gain_max = 0, + .gain_step = -250, + .num_channels = 1, +}; + +static const struct ad8366_info adrf5720_chip_info = { + .name = "adrf5720", + .gain_min = -31500, + .gain_max = 0, + .gain_step = -500, + .num_channels = 1, +}; + +static const struct ad8366_info adrf5730_chip_info = { + .name = "adrf5730", + .gain_min = -31500, + .gain_max = 0, + .gain_step = -500, + .num_channels = 1, +}; + +static const struct ad8366_info adrf5731_chip_info = { + .name = "adrf5731", + .gain_min = -30000, + .gain_max = 0, + .gain_step = -2000, + .num_channels = 1, + .pack_code = adrf5731_pack_code, +}; + +static const struct ad8366_info hmc271_chip_info = { + .name = "hmc271a", + .gain_min = -31000, + .gain_max = 0, + .gain_step = 1000, + .num_channels = 1, + .pack_code = hmc271_pack_code, +}; + +static const struct ad8366_info hmc792_chip_info = { + .name = "hmc792a", + .gain_min = -15750, + .gain_max = 0, + .gain_step = 250, + .num_channels = 1, +}; + +static const struct ad8366_info hmc1018_chip_info = { + .name = "hmc1018a", + .gain_min = -31000, + .gain_max = 0, + .gain_step = 1000, + .num_channels = 1, +}; + +static const struct ad8366_info hmc1019_chip_info = { + .name = "hmc1019a", + .gain_min = -15500, + .gain_max = 0, + .gain_step = 500, + .num_channels = 1, +}; + +static const struct ad8366_info hmc1119_chip_info = { + .name = "hmc1119", + .gain_min = -31750, + .gain_max = 0, + .gain_step = -250, + .num_channels = 1, +}; + +static int ad8366_write_code(struct ad8366_state *st) +{ + const struct ad8366_info *inf = st->info; + size_t len = 1; + + if (inf->pack_code) + len = inf->pack_code(st->ch, inf->num_channels, st->data); + else + st->data[0] = st->ch[0]; + + return spi_write(st->spi, st->data, len); } static int ad8366_read_raw(struct iio_dev *indio_dev, @@ -116,6 +209,7 @@ static int ad8366_read_raw(struct iio_dev *indio_dev, long m) { struct ad8366_state *st = iio_priv(indio_dev); + const struct ad8366_info *inf = st->info; int ret; int code, gain = 0; @@ -123,25 +217,8 @@ static int ad8366_read_raw(struct iio_dev *indio_dev, switch (m) { case IIO_CHAN_INFO_HARDWAREGAIN: code = st->ch[chan->channel]; - - switch (st->type) { - case ID_AD8366: - gain = code * 253 + 4500; - break; - case ID_ADA4961: - gain = 15000 - code * 1000; - break; - case ID_ADL5240: - gain = 20000 - 31500 + code * 500; - break; - case ID_HMC792: - gain = -1 * code * 500; - break; - case ID_HMC1119: - gain = -1 * code * 250; - break; - } - + gain = inf->gain_step > 0 ? inf->gain_min : inf->gain_max; + gain += inf->gain_step * code; /* Values in dB */ *val = gain / 1000; *val2 = (gain % 1000) * 1000; @@ -176,29 +253,14 @@ static int ad8366_write_raw(struct iio_dev *indio_dev, if (gain > inf->gain_max || gain < inf->gain_min) return -EINVAL; - switch (st->type) { - case ID_AD8366: - code = (gain - 4500) / 253; - break; - case ID_ADA4961: - code = (15000 - gain) / 1000; - break; - case ID_ADL5240: - code = ((gain - 500 - 20000) / 500) & 0x3F; - break; - case ID_HMC792: - code = (abs(gain) / 500) & 0x3F; - break; - case ID_HMC1119: - code = (abs(gain) / 250) & 0x7F; - break; - } + gain -= inf->gain_step > 0 ? inf->gain_min : inf->gain_max; + code = DIV_ROUND_CLOSEST(gain, inf->gain_step); mutex_lock(&st->lock); switch (mask) { case IIO_CHAN_INFO_HARDWAREGAIN: st->ch[chan->channel] = code; - ret = ad8366_write(indio_dev, st->ch[0], st->ch[1]); + ret = ad8366_write_code(st); break; default: ret = -EINVAL; @@ -239,107 +301,97 @@ static const struct iio_chan_spec ad8366_channels[] = { AD8366_CHAN(1), }; -static const struct iio_chan_spec ada4961_channels[] = { - AD8366_CHAN(0), -}; - static int ad8366_probe(struct spi_device *spi) { + struct device *dev = &spi->dev; + struct gpio_desc *enable_gpio; + struct reset_control *rstc; struct iio_dev *indio_dev; struct ad8366_state *st; int ret; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; st = iio_priv(indio_dev); - st->reg = devm_regulator_get(&spi->dev, "vcc"); - if (!IS_ERR(st->reg)) { - ret = regulator_enable(st->reg); - if (ret) - return ret; - } + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; + + ret = devm_regulator_get_enable(dev, "vcc"); + if (ret) + return dev_err_probe(dev, ret, "Failed to get regulator\n"); - spi_set_drvdata(spi, indio_dev); - mutex_init(&st->lock); st->spi = spi; - st->type = spi_get_device_id(spi)->driver_data; + st->info = spi_get_device_match_data(spi); - switch (st->type) { - case ID_AD8366: - indio_dev->channels = ad8366_channels; - indio_dev->num_channels = ARRAY_SIZE(ad8366_channels); - break; - case ID_ADA4961: - case ID_ADL5240: - case ID_HMC792: - case ID_HMC1119: - st->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(st->reset_gpio)) { - ret = PTR_ERR(st->reset_gpio); - goto error_disable_reg; - } - indio_dev->channels = ada4961_channels; - indio_dev->num_channels = ARRAY_SIZE(ada4961_channels); - break; - default: - dev_err(&spi->dev, "Invalid device ID\n"); - ret = -EINVAL; - goto error_disable_reg; - } + enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); + if (IS_ERR(enable_gpio)) + return dev_err_probe(dev, PTR_ERR(enable_gpio), + "Failed to get enable GPIO\n"); + + rstc = devm_reset_control_get_optional_exclusive_deasserted(dev, NULL); + if (IS_ERR(rstc)) + return dev_err_probe(dev, PTR_ERR(rstc), + "Failed to get reset controller\n"); - st->info = &ad8366_infos[st->type]; - indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->name = st->info->name; indio_dev->info = &ad8366_info; indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = ad8366_channels; + indio_dev->num_channels = st->info->num_channels; - ret = ad8366_write(indio_dev, 0, 0); + ret = ad8366_write_code(st); if (ret < 0) - goto error_disable_reg; - - ret = iio_device_register(indio_dev); - if (ret) - goto error_disable_reg; - - return 0; + return dev_err_probe(dev, ret, "failed to write initial gain\n"); -error_disable_reg: - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); - - return ret; -} - -static void ad8366_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct ad8366_state *st = iio_priv(indio_dev); - struct regulator *reg = st->reg; - - iio_device_unregister(indio_dev); - - if (!IS_ERR(reg)) - regulator_disable(reg); + return devm_iio_device_register(dev, indio_dev); } static const struct spi_device_id ad8366_id[] = { - {"ad8366", ID_AD8366}, - {"ada4961", ID_ADA4961}, - {"adl5240", ID_ADL5240}, - {"hmc792a", ID_HMC792}, - {"hmc1119", ID_HMC1119}, + { .name = "ad8366", .driver_data = (kernel_ulong_t)&ad8366_chip_info }, + { .name = "ada4961", .driver_data = (kernel_ulong_t)&ada4961_chip_info }, + { .name = "adl5240", .driver_data = (kernel_ulong_t)&adl5240_chip_info }, + { .name = "adrf5702", .driver_data = (kernel_ulong_t)&adrf5702_chip_info }, + { .name = "adrf5703", .driver_data = (kernel_ulong_t)&adrf5703_chip_info }, + { .name = "adrf5720", .driver_data = (kernel_ulong_t)&adrf5720_chip_info }, + { .name = "adrf5730", .driver_data = (kernel_ulong_t)&adrf5730_chip_info }, + { .name = "adrf5731", .driver_data = (kernel_ulong_t)&adrf5731_chip_info }, + { .name = "hmc271a", .driver_data = (kernel_ulong_t)&hmc271_chip_info }, + { .name = "hmc792a", .driver_data = (kernel_ulong_t)&hmc792_chip_info }, + { .name = "hmc1018a", .driver_data = (kernel_ulong_t)&hmc1018_chip_info }, + { .name = "hmc1019a", .driver_data = (kernel_ulong_t)&hmc1019_chip_info }, + { .name = "hmc1119", .driver_data = (kernel_ulong_t)&hmc1119_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad8366_id); +static const struct of_device_id ad8366_of_match[] = { + { .compatible = "adi,ad8366", .data = &ad8366_chip_info }, + { .compatible = "adi,ada4961", .data = &ada4961_chip_info }, + { .compatible = "adi,adl5240", .data = &adl5240_chip_info }, + { .compatible = "adi,adrf5702", .data = &adrf5702_chip_info }, + { .compatible = "adi,adrf5703", .data = &adrf5703_chip_info }, + { .compatible = "adi,adrf5720", .data = &adrf5720_chip_info }, + { .compatible = "adi,adrf5730", .data = &adrf5730_chip_info }, + { .compatible = "adi,adrf5731", .data = &adrf5731_chip_info }, + { .compatible = "adi,hmc271a", .data = &hmc271_chip_info }, + { .compatible = "adi,hmc792a", .data = &hmc792_chip_info }, + { .compatible = "adi,hmc1018a", .data = &hmc1018_chip_info }, + { .compatible = "adi,hmc1019a", .data = &hmc1019_chip_info }, + { .compatible = "adi,hmc1119", .data = &hmc1119_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, ad8366_of_match); + static struct spi_driver ad8366_driver = { .driver = { - .name = KBUILD_MODNAME, + .name = KBUILD_MODNAME, + .of_match_table = ad8366_of_match, }, .probe = ad8366_probe, - .remove = ad8366_remove, .id_table = ad8366_id, }; diff --git a/drivers/iio/amplifiers/ada4250.c b/drivers/iio/amplifiers/ada4250.c index 40f396ea9069..9702de3a5074 100644 --- a/drivers/iio/amplifiers/ada4250.c +++ b/drivers/iio/amplifiers/ada4250.c @@ -109,7 +109,7 @@ static int ada4250_set_offset_uv(struct iio_dev *indio_dev, /* * Compute Range and Voltage per LSB for the Sensor Offset Calibration - * Example of computation for Range 1 and Range 2 (Curren Bias Set = AVDD): + * Example of computation for Range 1 and Range 2 (Current Bias Set = AVDD): * Range 1 Range 2 * Gain | Max Vos(mV) | LSB(mV) | Max Vos(mV) | LSB(mV) | * 2 | X1*127 | X1=0.126(AVDD-1) | X1*3*127 | X1*3 | @@ -358,7 +358,7 @@ static int ada4250_probe(struct spi_device *spi) } static const struct spi_device_id ada4250_id[] = { - { "ada4250", 0 }, + { .name = "ada4250" }, { } }; MODULE_DEVICE_TABLE(spi, ada4250_id); diff --git a/drivers/iio/amplifiers/adl8113.c b/drivers/iio/amplifiers/adl8113.c index b8a431b6616b..1f1cfca980b4 100644 --- a/drivers/iio/amplifiers/adl8113.c +++ b/drivers/iio/amplifiers/adl8113.c @@ -12,7 +12,6 @@ #include <linux/err.h> #include <linux/gpio/consumer.h> #include <linux/iio/iio.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/property.h> diff --git a/drivers/iio/amplifiers/hmc425a.c b/drivers/iio/amplifiers/hmc425a.c index 4dbf894c7e3b..85bfc8dcc5fb 100644 --- a/drivers/iio/amplifiers/hmc425a.c +++ b/drivers/iio/amplifiers/hmc425a.c @@ -14,7 +14,6 @@ #include <linux/iio/sysfs.h> #include <linux/kernel.h> #include <linux/math.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/property.h> diff --git a/drivers/iio/buffer/industrialio-buffer-cb.c b/drivers/iio/buffer/industrialio-buffer-cb.c index 0c266c216525..b58263bcf3cb 100644 --- a/drivers/iio/buffer/industrialio-buffer-cb.c +++ b/drivers/iio/buffer/industrialio-buffer-cb.c @@ -154,3 +154,4 @@ EXPORT_SYMBOL_GPL(iio_channel_cb_get_iio_dev); MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); MODULE_DESCRIPTION("Industrial I/O callback buffer"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index 98acce909854..1bd82d3db5ea 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -56,6 +56,23 @@ static void iio_dmaengine_buffer_block_done(void *data, iio_dma_buffer_block_done(block); } +/* + * Cyclic transfers run until abort. Cap active cyclic blocks to one until there + * is a use case for more. + */ +static bool iio_dmaengine_buffer_has_active_cyclic(struct dmaengine_buffer *dmaengine_buffer) +{ + struct iio_dma_buffer_block *block; + + guard(spinlock_irqsave)(&dmaengine_buffer->queue.list_lock); + list_for_each_entry(block, &dmaengine_buffer->active, head) { + if (block->cyclic) + return true; + } + + return false; +} + static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, struct iio_dma_buffer_block *block) { @@ -79,13 +96,20 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, else dma_dir = DMA_MEM_TO_DEV; + if (block->cyclic && iio_dmaengine_buffer_has_active_cyclic(dmaengine_buffer)) { + dev_err(queue->dev, "cyclic DMA transfer already active\n"); + return -EBUSY; + } + if (block->sg_table) { + unsigned long flags; + sgl = block->sg_table->sgl; nents = sg_nents_for_len(sgl, block->bytes_used); if (nents < 0) return nents; - vecs = kmalloc_array(nents, sizeof(*vecs), GFP_ATOMIC); + vecs = kmalloc_objs(*vecs, nents, GFP_ATOMIC); if (!vecs) return -ENOMEM; @@ -99,9 +123,19 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, sgl = sg_next(sgl); } + if (block->cyclic) + flags = DMA_PREP_REPEAT; + else + flags = DMA_PREP_INTERRUPT; + + /* + * A new transfer may need to end an already active cyclic transfer + * before it can run, so always set the EOT flag. + */ + flags |= DMA_PREP_LOAD_EOT; desc = dmaengine_prep_peripheral_dma_vec(dmaengine_buffer->chan, vecs, nents, dma_dir, - DMA_PREP_INTERRUPT); + flags); kfree(vecs); } else { max_size = min(block->size, dmaengine_buffer->max_size); @@ -122,8 +156,10 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, if (!desc) return -ENOMEM; - desc->callback_result = iio_dmaengine_buffer_block_done; - desc->callback_param = block; + if (!block->cyclic) { + desc->callback_result = iio_dmaengine_buffer_block_done; + desc->callback_param = block; + } cookie = dmaengine_submit(desc); if (dma_submit_error(cookie)) diff --git a/drivers/iio/buffer/industrialio-hw-consumer.c b/drivers/iio/buffer/industrialio-hw-consumer.c index cb771ef8eeb3..d035aa33b357 100644 --- a/drivers/iio/buffer/industrialio-hw-consumer.c +++ b/drivers/iio/buffer/industrialio-hw-consumer.c @@ -28,7 +28,6 @@ struct hw_consumer_buffer { struct list_head head; struct iio_dev *indio_dev; struct iio_buffer buffer; - long scan_mask[]; }; static struct hw_consumer_buffer *iio_buffer_to_hw_consumer_buffer( @@ -41,6 +40,8 @@ static void iio_hw_buf_release(struct iio_buffer *buffer) { struct hw_consumer_buffer *hw_buf = iio_buffer_to_hw_consumer_buffer(buffer); + + bitmap_free(buffer->scan_mask); kfree(hw_buf); } @@ -52,7 +53,6 @@ static const struct iio_buffer_access_funcs iio_hw_buf_access = { static struct hw_consumer_buffer *iio_hw_consumer_get_buffer( struct iio_hw_consumer *hwc, struct iio_dev *indio_dev) { - unsigned int mask_longs = BITS_TO_LONGS(iio_get_masklength(indio_dev)); struct hw_consumer_buffer *buf; list_for_each_entry(buf, &hwc->buffers, head) { @@ -60,13 +60,18 @@ static struct hw_consumer_buffer *iio_hw_consumer_get_buffer( return buf; } - buf = kzalloc_flex(*buf, scan_mask, mask_longs); + buf = kzalloc_obj(*buf); if (!buf) return NULL; buf->buffer.access = &iio_hw_buf_access; buf->indio_dev = indio_dev; - buf->buffer.scan_mask = buf->scan_mask; + buf->buffer.scan_mask = bitmap_zalloc(iio_get_masklength(indio_dev), + GFP_KERNEL); + if (!buf->buffer.scan_mask) { + kfree(buf); + return NULL; + } iio_buffer_init(&buf->buffer); list_add_tail(&buf->head, &hwc->buffers); @@ -82,7 +87,7 @@ static struct hw_consumer_buffer *iio_hw_consumer_get_buffer( */ struct iio_hw_consumer *iio_hw_consumer_alloc(struct device *dev) { - struct hw_consumer_buffer *buf; + struct hw_consumer_buffer *buf, *tmp; struct iio_hw_consumer *hwc; struct iio_channel *chan; int ret; @@ -113,7 +118,7 @@ struct iio_hw_consumer *iio_hw_consumer_alloc(struct device *dev) return hwc; err_put_buffers: - list_for_each_entry(buf, &hwc->buffers, head) + list_for_each_entry_safe(buf, tmp, &hwc->buffers, head) iio_buffer_put(&buf->buffer); iio_channel_release_all(hwc->channels); err_free_hwc: @@ -211,3 +216,4 @@ EXPORT_SYMBOL_GPL(iio_hw_consumer_disable); MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); MODULE_DESCRIPTION("Hardware consumer buffer the IIO framework"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/iio/buffer/kfifo_buf.c b/drivers/iio/buffer/kfifo_buf.c index a6ff9085b8a2..b67ea6468226 100644 --- a/drivers/iio/buffer/kfifo_buf.c +++ b/drivers/iio/buffer/kfifo_buf.c @@ -224,35 +224,9 @@ void iio_kfifo_free(struct iio_buffer *r) } EXPORT_SYMBOL(iio_kfifo_free); -static void devm_iio_kfifo_release(struct device *dev, void *res) +static void devm_iio_kfifo_release(void *buffer) { - iio_kfifo_free(*(struct iio_buffer **)res); -} - -/** - * devm_iio_kfifo_allocate - Resource-managed iio_kfifo_allocate() - * @dev: Device to allocate kfifo buffer for - * - * RETURNS: - * Pointer to allocated iio_buffer on success, NULL on failure. - */ -static struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev) -{ - struct iio_buffer **ptr, *r; - - ptr = devres_alloc(devm_iio_kfifo_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return NULL; - - r = iio_kfifo_allocate(); - if (r) { - *ptr = r; - devres_add(dev, ptr); - } else { - devres_free(ptr); - } - - return r; + iio_kfifo_free(buffer); } /** @@ -262,10 +236,12 @@ static struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev) * @setup_ops: The setup_ops required to configure the HW part of the buffer (optional) * @buffer_attrs: Extra sysfs buffer attributes for this IIO buffer * - * This function allocates a kfifo buffer via devm_iio_kfifo_allocate() and + * This function allocates a kfifo buffer via iio_kfifo_allocate() and * attaches it to the IIO device via iio_device_attach_buffer(). * This is meant to be a bit of a short-hand/helper function as there are a few * drivers that seem to do this. + * + * Return: 0 on success, negative error code on failure. */ int devm_iio_kfifo_buffer_setup_ext(struct device *dev, struct iio_dev *indio_dev, @@ -273,11 +249,16 @@ int devm_iio_kfifo_buffer_setup_ext(struct device *dev, const struct iio_dev_attr **buffer_attrs) { struct iio_buffer *buffer; + int ret; - buffer = devm_iio_kfifo_allocate(dev); + buffer = iio_kfifo_allocate(); if (!buffer) return -ENOMEM; + ret = devm_add_action_or_reset(dev, devm_iio_kfifo_release, buffer); + if (ret) + return ret; + indio_dev->modes |= INDIO_BUFFER_SOFTWARE; indio_dev->setup_ops = setup_ops; diff --git a/drivers/iio/cdc/ad7150.c b/drivers/iio/cdc/ad7150.c index 427d32e398b3..2f35c6d2f9ce 100644 --- a/drivers/iio/cdc/ad7150.c +++ b/drivers/iio/cdc/ad7150.c @@ -13,7 +13,6 @@ #include <linux/i2c.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> @@ -306,7 +305,7 @@ static int ad7150_write_event_config(struct iio_dev *indio_dev, dir); if (ret) goto error_ret; - /* reenable any irq's we disabled whilst changing mode */ + /* re-enable any IRQs we disabled whilst changing mode */ enable_irq(chip->interrupts[0]); enable_irq(chip->interrupts[1]); } @@ -628,9 +627,9 @@ static int ad7150_probe(struct i2c_client *client) } static const struct i2c_device_id ad7150_id[] = { - { "ad7150", AD7150 }, - { "ad7151", AD7151 }, - { "ad7156", AD7150 }, + { .name = "ad7150", .driver_data = AD7150 }, + { .name = "ad7151", .driver_data = AD7151 }, + { .name = "ad7156", .driver_data = AD7150 }, { } }; diff --git a/drivers/iio/cdc/ad7746.c b/drivers/iio/cdc/ad7746.c index 8a306d55c72a..cf68b882bc49 100644 --- a/drivers/iio/cdc/ad7746.c +++ b/drivers/iio/cdc/ad7746.c @@ -606,7 +606,7 @@ static int ad7746_read_channel(struct iio_dev *indio_dev, return ret; /* - * Offset applied internally becaue the _offset userspace interface is + * Offset applied internally because the _offset userspace interface is * needed for the CAP DACs which apply a controllable offset. */ *val = get_unaligned_be24(data) - 0x800000; @@ -789,9 +789,9 @@ static int ad7746_probe(struct i2c_client *client) } static const struct i2c_device_id ad7746_id[] = { - { "ad7745", 7745 }, - { "ad7746", 7746 }, - { "ad7747", 7747 }, + { .name = "ad7745", .driver_data = 7745 }, + { .name = "ad7746", .driver_data = 7746 }, + { .name = "ad7747", .driver_data = 7747 }, { } }; MODULE_DEVICE_TABLE(i2c, ad7746_id); diff --git a/drivers/iio/chemical/ags02ma.c b/drivers/iio/chemical/ags02ma.c index 151178d4e8f4..8b97ea4a9515 100644 --- a/drivers/iio/chemical/ags02ma.c +++ b/drivers/iio/chemical/ags02ma.c @@ -139,7 +139,7 @@ static int ags02ma_probe(struct i2c_client *client) } static const struct i2c_device_id ags02ma_id_table[] = { - { "ags02ma" }, + { .name = "ags02ma" }, { } }; MODULE_DEVICE_TABLE(i2c, ags02ma_id_table); diff --git a/drivers/iio/chemical/ams-iaq-core.c b/drivers/iio/chemical/ams-iaq-core.c index 10156d794092..7af515110b89 100644 --- a/drivers/iio/chemical/ams-iaq-core.c +++ b/drivers/iio/chemical/ams-iaq-core.c @@ -7,7 +7,6 @@ */ #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/init.h> #include <linux/i2c.h> @@ -163,7 +162,7 @@ static int ams_iaqcore_probe(struct i2c_client *client) } static const struct i2c_device_id ams_iaqcore_id[] = { - { "ams-iaq-core" }, + { .name = "ams-iaq-core" }, { } }; MODULE_DEVICE_TABLE(i2c, ams_iaqcore_id); diff --git a/drivers/iio/chemical/atlas-ezo-sensor.c b/drivers/iio/chemical/atlas-ezo-sensor.c index 59f3a4fa9e9f..298b2fe48a19 100644 --- a/drivers/iio/chemical/atlas-ezo-sensor.c +++ b/drivers/iio/chemical/atlas-ezo-sensor.c @@ -8,7 +8,6 @@ #include <linux/init.h> #include <linux/delay.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/property.h> @@ -186,9 +185,9 @@ static const struct iio_info atlas_info = { }; static const struct i2c_device_id atlas_ezo_id[] = { - { "atlas-co2-ezo", (kernel_ulong_t)&atlas_ezo_devices[ATLAS_CO2_EZO] }, - { "atlas-o2-ezo", (kernel_ulong_t)&atlas_ezo_devices[ATLAS_O2_EZO] }, - { "atlas-hum-ezo", (kernel_ulong_t)&atlas_ezo_devices[ATLAS_HUM_EZO] }, + { .name = "atlas-co2-ezo", .driver_data = (kernel_ulong_t)&atlas_ezo_devices[ATLAS_CO2_EZO] }, + { .name = "atlas-o2-ezo", .driver_data = (kernel_ulong_t)&atlas_ezo_devices[ATLAS_O2_EZO] }, + { .name = "atlas-hum-ezo", .driver_data = (kernel_ulong_t)&atlas_ezo_devices[ATLAS_HUM_EZO] }, { } }; MODULE_DEVICE_TABLE(i2c, atlas_ezo_id); diff --git a/drivers/iio/chemical/atlas-sensor.c b/drivers/iio/chemical/atlas-sensor.c index 8bbba85af699..1d4a9919df1a 100644 --- a/drivers/iio/chemical/atlas-sensor.c +++ b/drivers/iio/chemical/atlas-sensor.c @@ -13,9 +13,7 @@ #include <linux/mutex.h> #include <linux/err.h> #include <linux/irq.h> -#include <linux/irq_work.h> #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/regmap.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> @@ -88,7 +86,6 @@ struct atlas_data { struct iio_trigger *trig; const struct atlas_device *chip; struct regmap *regmap; - struct irq_work work; unsigned int interrupt_enabled; /* 96-bit data + 32-bit pad + 64-bit timestamp */ __be32 buffer[6] __aligned(8); @@ -413,7 +410,11 @@ static int atlas_buffer_postenable(struct iio_dev *indio_dev) if (ret) return ret; - return atlas_set_interrupt(data, true); + ret = atlas_set_interrupt(data, true); + if (ret) + pm_runtime_put_autosuspend(&data->client->dev); + + return ret; } static int atlas_buffer_predisable(struct iio_dev *indio_dev) @@ -437,13 +438,6 @@ static const struct iio_buffer_setup_ops atlas_buffer_setup_ops = { .predisable = atlas_buffer_predisable, }; -static void atlas_work_handler(struct irq_work *work) -{ - struct atlas_data *data = container_of(work, struct atlas_data, work); - - iio_trigger_poll(data->trig); -} - static irqreturn_t atlas_trigger_handler(int irq, void *private) { struct iio_poll_func *pf = private; @@ -470,7 +464,7 @@ static irqreturn_t atlas_interrupt_handler(int irq, void *private) struct iio_dev *indio_dev = private; struct atlas_data *data = iio_priv(indio_dev); - irq_work_queue(&data->work); + iio_trigger_poll_nested(data->trig); return IRQ_HANDLED; } @@ -586,11 +580,11 @@ static const struct iio_info atlas_info = { }; static const struct i2c_device_id atlas_id[] = { - { "atlas-ph-sm", (kernel_ulong_t)&atlas_devices[ATLAS_PH_SM] }, - { "atlas-ec-sm", (kernel_ulong_t)&atlas_devices[ATLAS_EC_SM] }, - { "atlas-orp-sm", (kernel_ulong_t)&atlas_devices[ATLAS_ORP_SM] }, - { "atlas-do-sm", (kernel_ulong_t)&atlas_devices[ATLAS_DO_SM] }, - { "atlas-rtd-sm", (kernel_ulong_t)&atlas_devices[ATLAS_RTD_SM] }, + { .name = "atlas-ph-sm", .driver_data = (kernel_ulong_t)&atlas_devices[ATLAS_PH_SM] }, + { .name = "atlas-ec-sm", .driver_data = (kernel_ulong_t)&atlas_devices[ATLAS_EC_SM] }, + { .name = "atlas-orp-sm", .driver_data = (kernel_ulong_t)&atlas_devices[ATLAS_ORP_SM] }, + { .name = "atlas-do-sm", .driver_data = (kernel_ulong_t)&atlas_devices[ATLAS_DO_SM] }, + { .name = "atlas-rtd-sm", .driver_data = (kernel_ulong_t)&atlas_devices[ATLAS_RTD_SM] }, { } }; MODULE_DEVICE_TABLE(i2c, atlas_id); @@ -666,8 +660,6 @@ static int atlas_probe(struct i2c_client *client) goto unregister_trigger; } - init_irq_work(&data->work, atlas_work_handler); - if (client->irq > 0) { /* interrupt pin toggles on new conversion */ ret = devm_request_threaded_irq(&client->dev, client->irq, diff --git a/drivers/iio/chemical/bme680_core.c b/drivers/iio/chemical/bme680_core.c index 24e0b59e2fdf..ac9a737481dc 100644 --- a/drivers/iio/chemical/bme680_core.c +++ b/drivers/iio/chemical/bme680_core.c @@ -128,7 +128,7 @@ struct bme680_data { u16 heater_temp; struct { - s32 chan[4]; + s32 chan[BME680_NUM_CHANNELS]; aligned_s64 ts; } scan; @@ -807,7 +807,7 @@ static int bme680_read_gas(struct bme680_data *data, int *comp_gas_res) adc_gas_res = FIELD_GET(BME680_ADC_GAS_RES, gas_regs_val); /* - * occurs if either the gas heating duration was insuffient + * This may occur if either the gas heating duration was insufficient * to reach the target heater temperature or the target * heater temperature was too high for the heater sink to * reach. diff --git a/drivers/iio/chemical/bme680_i2c.c b/drivers/iio/chemical/bme680_i2c.c index 5560ea708b36..c34d67bcb2a3 100644 --- a/drivers/iio/chemical/bme680_i2c.c +++ b/drivers/iio/chemical/bme680_i2c.c @@ -24,10 +24,9 @@ static int bme680_i2c_probe(struct i2c_client *client) const char *name = NULL; regmap = devm_regmap_init_i2c(client, &bme680_regmap_config); - if (IS_ERR(regmap)) { - dev_err(&client->dev, "Failed to register i2c regmap %ld\n", PTR_ERR(regmap)); - return PTR_ERR(regmap); - } + if (IS_ERR(regmap)) + return dev_err_probe(&client->dev, PTR_ERR(regmap), + "Failed to register i2c regmap\n"); if (id) name = id->name; @@ -36,7 +35,7 @@ static int bme680_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id bme680_i2c_id[] = { - { "bme680" }, + { .name = "bme680" }, { } }; MODULE_DEVICE_TABLE(i2c, bme680_i2c_id); diff --git a/drivers/iio/chemical/bme680_spi.c b/drivers/iio/chemical/bme680_spi.c index aa97645ba539..2175b9564fa1 100644 --- a/drivers/iio/chemical/bme680_spi.c +++ b/drivers/iio/chemical/bme680_spi.c @@ -4,7 +4,6 @@ * * Copyright (C) 2018 Himanshu Jha <himanshujha199640@gmail.com> */ -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> #include <linux/spi/spi.h> @@ -122,16 +121,15 @@ static int bme680_spi_probe(struct spi_device *spi) regmap = devm_regmap_init(&spi->dev, &bme680_regmap_bus, bus_context, &bme680_regmap_config); - if (IS_ERR(regmap)) { - dev_err(&spi->dev, "Failed to register spi regmap %ld\n", PTR_ERR(regmap)); - return PTR_ERR(regmap); - } + if (IS_ERR(regmap)) + return dev_err_probe(&spi->dev, PTR_ERR(regmap), + "Failed to register spi regmap\n"); return bme680_core_probe(&spi->dev, regmap, id->name); } static const struct spi_device_id bme680_spi_id[] = { - {"bme680", 0}, + { .name = "bme680" }, { } }; MODULE_DEVICE_TABLE(spi, bme680_spi_id); diff --git a/drivers/iio/chemical/ccs811.c b/drivers/iio/chemical/ccs811.c index 998c9239c4c7..d126ee12ffe5 100644 --- a/drivers/iio/chemical/ccs811.c +++ b/drivers/iio/chemical/ccs811.c @@ -484,10 +484,8 @@ static int ccs811_probe(struct i2c_client *client) IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "ccs811_irq", indio_dev); - if (ret) { - dev_err(&client->dev, "irq request error %d\n", -ret); + if (ret) goto err_poweroff; - } data->drdy_trig = devm_iio_trigger_alloc(&client->dev, "%s-dev%d", @@ -552,8 +550,8 @@ static void ccs811_remove(struct i2c_client *client) } static const struct i2c_device_id ccs811_id[] = { - { "ccs811" }, - { } + { .name = "ccs811" }, + { } }; MODULE_DEVICE_TABLE(i2c, ccs811_id); diff --git a/drivers/iio/chemical/ens160_core.c b/drivers/iio/chemical/ens160_core.c index bbc96c4c6283..7c1ffda38b99 100644 --- a/drivers/iio/chemical/ens160_core.c +++ b/drivers/iio/chemical/ens160_core.c @@ -320,7 +320,7 @@ static int ens160_setup_trigger(struct iio_dev *indio_dev, int irq) IRQF_NO_THREAD, indio_dev->name, indio_dev->trig); if (ret) - return dev_err_probe(dev, ret, "failed to request irq\n"); + return ret; return 0; } diff --git a/drivers/iio/chemical/ens160_i2c.c b/drivers/iio/chemical/ens160_i2c.c index aa0dfe639245..ab0e8dcce011 100644 --- a/drivers/iio/chemical/ens160_i2c.c +++ b/drivers/iio/chemical/ens160_i2c.c @@ -34,7 +34,7 @@ static int ens160_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id ens160_i2c_id[] = { - { "ens160" }, + { .name = "ens160" }, { } }; MODULE_DEVICE_TABLE(i2c, ens160_i2c_id); diff --git a/drivers/iio/chemical/ens160_spi.c b/drivers/iio/chemical/ens160_spi.c index a674c0e1bf4b..7c11d19291c9 100644 --- a/drivers/iio/chemical/ens160_spi.c +++ b/drivers/iio/chemical/ens160_spi.c @@ -39,7 +39,7 @@ static const struct of_device_id ens160_spi_of_match[] = { MODULE_DEVICE_TABLE(of, ens160_spi_of_match); static const struct spi_device_id ens160_spi_id[] = { - { "ens160" }, + { .name = "ens160" }, { } }; MODULE_DEVICE_TABLE(spi, ens160_spi_id); diff --git a/drivers/iio/chemical/mhz19b.c b/drivers/iio/chemical/mhz19b.c index 3c64154918b1..a793620e95b7 100644 --- a/drivers/iio/chemical/mhz19b.c +++ b/drivers/iio/chemical/mhz19b.c @@ -17,7 +17,6 @@ #include <linux/jiffies.h> #include <linux/kstrtox.h> #include <linux/minmax.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regulator/consumer.h> #include <linux/serdev.h> @@ -52,6 +51,8 @@ struct mhz19b_state { struct completion buf_ready; u8 buf_idx; + bool buf_overflow; + /* * Serdev receive buffer. * When data is received from the MH-Z19B, @@ -106,6 +107,10 @@ static int mhz19b_serdev_cmd(struct iio_dev *indio_dev, int cmd, u16 arg) cmd_buf[8] = mhz19b_get_checksum(cmd_buf); /* Write buf to uart ctrl synchronously */ + st->buf_idx = 0; + st->buf_overflow = false; + reinit_completion(&st->buf_ready); + ret = serdev_device_write(serdev, cmd_buf, MHZ19B_CMD_SIZE, 0); if (ret < 0) return ret; @@ -121,6 +126,9 @@ static int mhz19b_serdev_cmd(struct iio_dev *indio_dev, int cmd, u16 arg) if (!ret) return -ETIMEDOUT; + if (st->buf_overflow) + return -EMSGSIZE; + if (st->buf[8] != mhz19b_get_checksum(st->buf)) { dev_err(dev, "checksum err"); return -EINVAL; @@ -240,6 +248,14 @@ static size_t mhz19b_receive_buf(struct serdev_device *serdev, { struct iio_dev *indio_dev = dev_get_drvdata(&serdev->dev); struct mhz19b_state *st = iio_priv(indio_dev); + size_t remaining = MHZ19B_CMD_SIZE - st->buf_idx; + + if (len > remaining) { + st->buf_idx = 0; + st->buf_overflow = true; + complete(&st->buf_ready); + return len; + } memcpy(st->buf + st->buf_idx, data, len); st->buf_idx += len; diff --git a/drivers/iio/chemical/pms7003.c b/drivers/iio/chemical/pms7003.c index 656d4a12c58f..c50edb24af89 100644 --- a/drivers/iio/chemical/pms7003.c +++ b/drivers/iio/chemical/pms7003.c @@ -14,7 +14,6 @@ #include <linux/iio/triggered_buffer.h> #include <linux/jiffies.h> #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/serdev.h> diff --git a/drivers/iio/chemical/scd30_core.c b/drivers/iio/chemical/scd30_core.c index a665fcb78806..770571c21521 100644 --- a/drivers/iio/chemical/scd30_core.c +++ b/drivers/iio/chemical/scd30_core.c @@ -2,8 +2,10 @@ /* * Sensirion SCD30 carbon dioxide sensor core driver * - * Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com> + * Copyright (c) 2020 Tomasz Duszynski <tduszyns@gmail.com> */ + +#include <linux/bitfield.h> #include <linux/bits.h> #include <linux/cleanup.h> #include <linux/completion.h> @@ -43,6 +45,11 @@ #define SCD30_TEMP_OFFSET_MAX 655360 #define SCD30_EXTRA_TIMEOUT_PER_S 250 +/* Floating point arithmetic macros */ +#define SCD30_FLOAT_MANTISSA_MSK GENMASK(22, 0) +#define SCD30_FLOAT_EXP_MSK GENMASK(30, 23) +#define SCD30_FLOAT_SIGN_MSK BIT(31) + enum { SCD30_CONC, SCD30_TEMP, @@ -89,10 +96,14 @@ static int scd30_reset(struct scd30_state *state) /* simplified float to fixed point conversion with a scaling factor of 0.01 */ static int scd30_float_to_fp(int float32) { - int fraction, shift, - mantissa = float32 & GENMASK(22, 0), - sign = (float32 & BIT(31)) ? -1 : 1, - exp = (float32 & ~BIT(31)) >> 23; + int fraction, shift, sign; + int mantissa = FIELD_GET(SCD30_FLOAT_MANTISSA_MSK, float32); + int exp = FIELD_GET(SCD30_FLOAT_EXP_MSK, float32); + + if (float32 & SCD30_FLOAT_SIGN_MSK) + sign = -1; + else + sign = 1; /* special case 0 */ if (!exp && !mantissa) @@ -256,7 +267,7 @@ static int scd30_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const guard(mutex)(&state->lock); switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: - if (val) + if (val || !val2) return -EINVAL; val = 1000000000 / val2; @@ -368,11 +379,13 @@ static ssize_t calibration_auto_enable_show(struct device *dev, struct device_at int ret; u16 val; - mutex_lock(&state->lock); + guard(mutex)(&state->lock); + ret = scd30_command_read(state, CMD_ASC, &val); - mutex_unlock(&state->lock); + if (ret) + return ret; - return ret ?: sysfs_emit(buf, "%d\n", val); + return sysfs_emit(buf, "%d\n", val); } static ssize_t calibration_auto_enable_store(struct device *dev, struct device_attribute *attr, @@ -387,11 +400,13 @@ static ssize_t calibration_auto_enable_store(struct device *dev, struct device_a if (ret) return ret; - mutex_lock(&state->lock); + guard(mutex)(&state->lock); + ret = scd30_command_write(state, CMD_ASC, val); - mutex_unlock(&state->lock); + if (ret) + return ret; - return ret ?: len; + return len; } static ssize_t calibration_forced_value_show(struct device *dev, struct device_attribute *attr, @@ -402,11 +417,13 @@ static ssize_t calibration_forced_value_show(struct device *dev, struct device_a int ret; u16 val; - mutex_lock(&state->lock); + guard(mutex)(&state->lock); + ret = scd30_command_read(state, CMD_FRC, &val); - mutex_unlock(&state->lock); + if (ret) + return ret; - return ret ?: sysfs_emit(buf, "%d\n", val); + return sysfs_emit(buf, "%d\n", val); } static ssize_t calibration_forced_value_store(struct device *dev, struct device_attribute *attr, @@ -424,11 +441,13 @@ static ssize_t calibration_forced_value_store(struct device *dev, struct device_ if (val < SCD30_FRC_MIN_PPM || val > SCD30_FRC_MAX_PPM) return -EINVAL; - mutex_lock(&state->lock); + guard(mutex)(&state->lock); + ret = scd30_command_write(state, CMD_FRC, val); - mutex_unlock(&state->lock); + if (ret) + return ret; - return ret ?: len; + return len; } static IIO_DEVICE_ATTR_RO(sampling_frequency_available, 0); @@ -579,24 +598,34 @@ out: return IRQ_HANDLED; } +static int scd30_trigger_handler_helper(struct iio_dev *indio_dev, int *scan_data, + size_t scan_data_size) +{ + struct scd30_state *state = iio_priv(indio_dev); + int ret; + + guard(mutex)(&state->lock); + + if (!iio_trigger_using_own(indio_dev)) + ret = scd30_read_poll(state); + else + ret = scd30_read_meas(state); + memcpy(scan_data, state->meas, scan_data_size); + + return ret; +} + static irqreturn_t scd30_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; - struct scd30_state *state = iio_priv(indio_dev); struct { int data[SCD30_MEAS_COUNT]; aligned_s64 ts; } scan = { }; int ret; - mutex_lock(&state->lock); - if (!iio_trigger_using_own(indio_dev)) - ret = scd30_read_poll(state); - else - ret = scd30_read_meas(state); - memcpy(scan.data, state->meas, sizeof(state->meas)); - mutex_unlock(&state->lock); + ret = scd30_trigger_handler_helper(indio_dev, scan.data, sizeof(scan.data)); if (ret) goto out; @@ -657,7 +686,7 @@ static int scd30_setup_trigger(struct iio_dev *indio_dev) IRQF_NO_AUTOEN, indio_dev->name, indio_dev); if (ret) - return dev_err_probe(dev, ret, "failed to request irq\n"); + return ret; return 0; } @@ -682,7 +711,11 @@ int scd30_probe(struct device *dev, int irq, const char *name, void *priv, state->pressure_comp = SCD30_PRESSURE_COMP_DEFAULT; state->meas_interval = SCD30_MEAS_INTERVAL_DEFAULT; state->command = command; - mutex_init(&state->lock); + + ret = devm_mutex_init(dev, &state->lock); + if (ret) + return ret; + init_completion(&state->meas_ready); dev_set_drvdata(dev, indio_dev); @@ -741,6 +774,6 @@ int scd30_probe(struct device *dev, int irq, const char *name, void *priv, } EXPORT_SYMBOL_NS(scd30_probe, "IIO_SCD30"); -MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>"); +MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>"); MODULE_DESCRIPTION("Sensirion SCD30 carbon dioxide sensor core driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/chemical/scd30_i2c.c b/drivers/iio/chemical/scd30_i2c.c index 436df9c61a71..bcef1e473e34 100644 --- a/drivers/iio/chemical/scd30_i2c.c +++ b/drivers/iio/chemical/scd30_i2c.c @@ -2,7 +2,7 @@ /* * Sensirion SCD30 carbon dioxide sensor i2c driver * - * Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com> + * Copyright (c) 2020 Tomasz Duszynski <tduszyns@gmail.com> * * I2C slave address: 0x61 */ @@ -10,7 +10,6 @@ #include <linux/device.h> #include <linux/errno.h> #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/types.h> #include <linux/unaligned.h> @@ -20,7 +19,7 @@ #define SCD30_I2C_MAX_BUF_SIZE 18 #define SCD30_I2C_CRC8_POLYNOMIAL 0x31 -static u16 scd30_i2c_cmd_lookup_tbl[] = { +static const u16 scd30_i2c_cmd_lookup_tbl[] = { [CMD_START_MEAS] = 0x0010, [CMD_STOP_MEAS] = 0x0104, [CMD_MEAS_INTERVAL] = 0x4600, @@ -71,6 +70,9 @@ static int scd30_i2c_command(struct scd30_state *state, enum scd30_cmd cmd, u16 int i, ret; char crc; + if (!response && size != 0) + return -EINVAL; + put_unaligned_be16(scd30_i2c_cmd_lookup_tbl[cmd], buf); i = 2; @@ -134,7 +136,7 @@ static struct i2c_driver scd30_i2c_driver = { }; module_i2c_driver(scd30_i2c_driver); -MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>"); +MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>"); MODULE_DESCRIPTION("Sensirion SCD30 carbon dioxide sensor i2c driver"); MODULE_LICENSE("GPL v2"); MODULE_IMPORT_NS("IIO_SCD30"); diff --git a/drivers/iio/chemical/scd30_serial.c b/drivers/iio/chemical/scd30_serial.c index e8b453aae859..31b0fc957b08 100644 --- a/drivers/iio/chemical/scd30_serial.c +++ b/drivers/iio/chemical/scd30_serial.c @@ -2,14 +2,13 @@ /* * Sensirion SCD30 carbon dioxide sensor serial driver * - * Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com> + * Copyright (c) 2020 Tomasz Duszynski <tduszyns@gmail.com> */ #include <linux/crc16.h> #include <linux/device.h> #include <linux/errno.h> #include <linux/iio/iio.h> #include <linux/jiffies.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/property.h> #include <linux/serdev.h> @@ -258,7 +257,7 @@ static struct serdev_device_driver scd30_serdev_driver = { }; module_serdev_device_driver(scd30_serdev_driver); -MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>"); +MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>"); MODULE_DESCRIPTION("Sensirion SCD30 carbon dioxide sensor serial driver"); MODULE_LICENSE("GPL v2"); MODULE_IMPORT_NS("IIO_SCD30"); diff --git a/drivers/iio/chemical/sgp30.c b/drivers/iio/chemical/sgp30.c index 21730d62b5c8..379c1c4af8d8 100644 --- a/drivers/iio/chemical/sgp30.c +++ b/drivers/iio/chemical/sgp30.c @@ -20,7 +20,6 @@ #include <linux/delay.h> #include <linux/kthread.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/i2c.h> #include <linux/iio/iio.h> @@ -498,6 +497,7 @@ static const struct of_device_id sgp_dt_ids[] = { { .compatible = "sensirion,sgpc3", .data = &sgp_devices[SGPC3] }, { } }; +MODULE_DEVICE_TABLE(of, sgp_dt_ids); static int sgp_probe(struct i2c_client *client) { @@ -548,6 +548,9 @@ static int sgp_probe(struct i2c_client *client) data->iaq_thread = kthread_run(sgp_iaq_threadfn, data, "%s-iaq", data->client->name); + if (IS_ERR(data->iaq_thread)) + return dev_err_probe(dev, PTR_ERR(data->iaq_thread), + "failed to start IAQ thread\n"); return 0; } @@ -562,13 +565,11 @@ static void sgp_remove(struct i2c_client *client) } static const struct i2c_device_id sgp_id[] = { - { "sgp30", (kernel_ulong_t)&sgp_devices[SGP30] }, - { "sgpc3", (kernel_ulong_t)&sgp_devices[SGPC3] }, + { .name = "sgp30", .driver_data = (kernel_ulong_t)&sgp_devices[SGP30] }, + { .name = "sgpc3", .driver_data = (kernel_ulong_t)&sgp_devices[SGPC3] }, { } }; - MODULE_DEVICE_TABLE(i2c, sgp_id); -MODULE_DEVICE_TABLE(of, sgp_dt_ids); static struct i2c_driver sgp_driver = { .driver = { diff --git a/drivers/iio/chemical/sgp40.c b/drivers/iio/chemical/sgp40.c index 07d8ab830211..b2b5e32a9eb2 100644 --- a/drivers/iio/chemical/sgp40.c +++ b/drivers/iio/chemical/sgp40.c @@ -355,7 +355,7 @@ static int sgp40_probe(struct i2c_client *client) } static const struct i2c_device_id sgp40_id[] = { - { "sgp40" }, + { .name = "sgp40" }, { } }; diff --git a/drivers/iio/chemical/sps30.c b/drivers/iio/chemical/sps30.c index a934bf0298dd..8e15baa31423 100644 --- a/drivers/iio/chemical/sps30.c +++ b/drivers/iio/chemical/sps30.c @@ -5,6 +5,7 @@ * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com> */ +#include <linux/cleanup.h> #include <linux/crc8.h> #include <linux/delay.h> #include <linux/i2c.h> @@ -69,6 +70,8 @@ static int sps30_do_meas(struct sps30_state *state, s32 *data, int size) { int i, ret; + guard(mutex)(&state->lock); + if (state->state == RESET) { ret = state->ops->start_meas(state); if (ret) @@ -111,9 +114,7 @@ static irqreturn_t sps30_trigger_handler(int irq, void *p) aligned_s64 ts; } scan; - mutex_lock(&state->lock); ret = sps30_do_meas(state, scan.data, ARRAY_SIZE(scan.data)); - mutex_unlock(&state->lock); if (ret) goto err; @@ -136,7 +137,6 @@ static int sps30_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_PROCESSED: switch (chan->type) { case IIO_MASSCONCENTRATION: - mutex_lock(&state->lock); /* read up to the number of bytes actually needed */ switch (chan->channel2) { case IIO_MOD_PM1: @@ -152,7 +152,6 @@ static int sps30_read_raw(struct iio_dev *indio_dev, ret = sps30_do_meas(state, data, 4); break; } - mutex_unlock(&state->lock); if (ret) return ret; @@ -197,9 +196,9 @@ static ssize_t start_cleaning_store(struct device *dev, if (kstrtoint(buf, 0, &val) || val != 1) return -EINVAL; - mutex_lock(&state->lock); + guard(mutex)(&state->lock); + ret = state->ops->clean_fan(state); - mutex_unlock(&state->lock); if (ret) return ret; @@ -215,9 +214,9 @@ static ssize_t cleaning_period_show(struct device *dev, __be32 val; int ret; - mutex_lock(&state->lock); + guard(mutex)(&state->lock); + ret = state->ops->read_cleaning_period(state, &val); - mutex_unlock(&state->lock); if (ret) return ret; @@ -238,12 +237,11 @@ static ssize_t cleaning_period_store(struct device *dev, struct device_attribute (val > SPS30_AUTO_CLEANING_PERIOD_MAX)) return -EINVAL; - mutex_lock(&state->lock); + guard(mutex)(&state->lock); + ret = state->ops->write_cleaning_period(state, cpu_to_be32(val)); - if (ret) { - mutex_unlock(&state->lock); + if (ret) return ret; - } msleep(20); @@ -256,8 +254,6 @@ static ssize_t cleaning_period_store(struct device *dev, struct device_attribute dev_warn(dev, "period changed but reads will return the old value\n"); - mutex_unlock(&state->lock); - return len; } diff --git a/drivers/iio/chemical/sps30_i2c.c b/drivers/iio/chemical/sps30_i2c.c index c92f04990c34..2d3a876cc06e 100644 --- a/drivers/iio/chemical/sps30_i2c.c +++ b/drivers/iio/chemical/sps30_i2c.c @@ -2,7 +2,7 @@ /* * Sensirion SPS30 particulate matter sensor i2c driver * - * Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com> + * Copyright (c) 2020 Tomasz Duszynski <tduszyns@gmail.com> * * I2C slave address: 0x69 */ @@ -12,7 +12,6 @@ #include <linux/device.h> #include <linux/errno.h> #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/types.h> @@ -232,7 +231,7 @@ static int sps30_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id sps30_i2c_id[] = { - { "sps30" }, + { .name = "sps30" }, { } }; MODULE_DEVICE_TABLE(i2c, sps30_i2c_id); @@ -253,7 +252,7 @@ static struct i2c_driver sps30_i2c_driver = { }; module_i2c_driver(sps30_i2c_driver); -MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>"); +MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>"); MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor i2c driver"); MODULE_LICENSE("GPL v2"); MODULE_IMPORT_NS("IIO_SPS30"); diff --git a/drivers/iio/chemical/sps30_serial.c b/drivers/iio/chemical/sps30_serial.c index a5e6bc08d5fd..0cdba8703e93 100644 --- a/drivers/iio/chemical/sps30_serial.c +++ b/drivers/iio/chemical/sps30_serial.c @@ -2,14 +2,13 @@ /* * Sensirion SPS30 particulate matter sensor serial driver * - * Copyright (c) 2021 Tomasz Duszynski <tomasz.duszynski@octakon.com> + * Copyright (c) 2021 Tomasz Duszynski <tduszyns@gmail.com> */ #include <linux/completion.h> #include <linux/device.h> #include <linux/errno.h> #include <linux/iio/iio.h> #include <linux/minmax.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/serdev.h> #include <linux/types.h> @@ -426,7 +425,7 @@ static struct serdev_device_driver sps30_serial_driver = { }; module_serdev_device_driver(sps30_serial_driver); -MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>"); +MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>"); MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor serial driver"); MODULE_LICENSE("GPL v2"); MODULE_IMPORT_NS("IIO_SPS30"); diff --git a/drivers/iio/chemical/sunrise_co2.c b/drivers/iio/chemical/sunrise_co2.c index 158be9d798d2..dae8a7025e05 100644 --- a/drivers/iio/chemical/sunrise_co2.c +++ b/drivers/iio/chemical/sunrise_co2.c @@ -13,7 +13,6 @@ #include <linux/bitops.h> #include <linux/i2c.h> #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/regmap.h> diff --git a/drivers/iio/chemical/vz89x.c b/drivers/iio/chemical/vz89x.c index 5b358bcd311b..2e10a6b17047 100644 --- a/drivers/iio/chemical/vz89x.c +++ b/drivers/iio/chemical/vz89x.c @@ -10,7 +10,6 @@ #include <linux/mutex.h> #include <linux/init.h> #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -385,8 +384,8 @@ static int vz89x_probe(struct i2c_client *client) } static const struct i2c_device_id vz89x_id[] = { - { "vz89x", (kernel_ulong_t)&vz89x_chips[VZ89X] }, - { "vz89te", (kernel_ulong_t)&vz89x_chips[VZ89TE] }, + { .name = "vz89x", .driver_data = (kernel_ulong_t)&vz89x_chips[VZ89X] }, + { .name = "vz89te", .driver_data = (kernel_ulong_t)&vz89x_chips[VZ89TE] }, { } }; MODULE_DEVICE_TABLE(i2c, vz89x_id); diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_activity.c b/drivers/iio/common/cros_ec_sensors/cros_ec_activity.c index 6e38d115b6fe..6762685e6876 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_activity.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_activity.c @@ -279,13 +279,7 @@ static int cros_ec_sensors_probe(struct platform_device *pdev) channel++; } - /* Timestamp */ - channel->scan_index = index; - channel->type = IIO_TIMESTAMP; - channel->channel = -1; - channel->scan_type.sign = 's'; - channel->scan_type.realbits = 64; - channel->scan_type.storagebits = 64; + *channel = IIO_CHAN_SOFT_TIMESTAMP(index); indio_dev->channels = st->channels; indio_dev->num_channels = index + 1; diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c b/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c index 2d3d148b4206..8f5bf40a0596 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c @@ -20,7 +20,6 @@ #include <linux/iio/triggered_buffer.h> #include <linux/iio/trigger_consumer.h> #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_data/cros_ec_commands.h> #include <linux/platform_device.h> diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c index 82cef4a12442..b971f8b646be 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c @@ -16,7 +16,6 @@ #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_data/cros_ec_commands.h> #include <linux/platform_data/cros_ec_proto.h> @@ -106,7 +105,7 @@ static int cros_ec_sensors_read(struct iio_dev *indio_dev, switch (st->core.type) { case MOTIONSENSE_TYPE_ACCEL: /* - * EC returns data in g, iio exepects m/s^2. + * EC returns data in g, IIO expects m/s^2. * Do not use IIO_G_TO_M_S_2 to avoid precision loss. */ *val = div_s64(val64 * 980665, 10); @@ -279,13 +278,7 @@ static int cros_ec_sensors_probe(struct platform_device *pdev) } } - /* Timestamp */ - channel->type = IIO_TIMESTAMP; - channel->channel = -1; - channel->scan_index = CROS_EC_SENSOR_MAX_AXIS; - channel->scan_type.sign = 's'; - channel->scan_type.realbits = 64; - channel->scan_type.storagebits = 64; + *channel = IIO_CHAN_SOFT_TIMESTAMP(CROS_EC_SENSOR_MAX_AXIS); indio_dev->channels = state->channels; indio_dev->num_channels = CROS_EC_SENSORS_MAX_CHANNELS; diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c index a61428bfdce3..9e7c26e37880 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c @@ -72,8 +72,7 @@ static const struct { {HID_USAGE_SENSOR_HUMAN_ATTENTION, 0, 1, 0}, }; -static void simple_div(int dividend, int divisor, int *whole, - int *micro_frac) +static void simple_div(int dividend, int divisor, int *whole, int *micro_frac) { int rem; int exp = 0; @@ -111,7 +110,7 @@ for 10^-2. Negative numbers are 2's complement */ static void convert_from_vtf_format(u32 value, int size, int exp, - int *val1, int *val2) + int *val1, int *val2) { int sign = 1; @@ -176,7 +175,7 @@ s32 hid_sensor_read_poll_value(struct hid_sensor_common *st) EXPORT_SYMBOL_NS(hid_sensor_read_poll_value, "IIO_HID_ATTRIBUTES"); int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st, - int *val1, int *val2) + int *val1, int *val2) { s32 value; int ret; @@ -203,7 +202,7 @@ int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st, EXPORT_SYMBOL_NS(hid_sensor_read_samp_freq_value, "IIO_HID"); int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st, - int val1, int val2) + int val1, int val2) { s32 value; int ret; @@ -238,15 +237,15 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st, EXPORT_SYMBOL_NS(hid_sensor_write_samp_freq_value, "IIO_HID"); int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st, - int *val1, int *val2) + int *val1, int *val2) { s32 value; int ret; ret = sensor_hub_get_feature(st->hsdev, st->sensitivity.report_id, - st->sensitivity.index, sizeof(value), - &value); + st->sensitivity.index, + sizeof(value), &value); if (ret < 0 || value < 0) { *val1 = *val2 = 0; return -EINVAL; @@ -268,8 +267,8 @@ int hid_sensor_read_raw_hyst_rel_value(struct hid_sensor_common *st, int *val1, ret = sensor_hub_get_feature(st->hsdev, st->sensitivity_rel.report_id, - st->sensitivity_rel.index, sizeof(value), - &value); + st->sensitivity_rel.index, + sizeof(value), &value); if (ret < 0 || value < 0) { *val1 = *val2 = 0; return -EINVAL; @@ -282,9 +281,8 @@ int hid_sensor_read_raw_hyst_rel_value(struct hid_sensor_common *st, int *val1, } EXPORT_SYMBOL_NS(hid_sensor_read_raw_hyst_rel_value, "IIO_HID"); - int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, - int val1, int val2) + int val1, int val2) { s32 value; int ret; @@ -293,8 +291,8 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, return -EINVAL; value = convert_to_vtf_format(st->sensitivity.size, - st->sensitivity.unit_expo, - val1, val2); + st->sensitivity.unit_expo, + val1, val2); ret = sensor_hub_set_feature(st->hsdev, st->sensitivity.report_id, st->sensitivity.index, sizeof(value), &value); @@ -303,8 +301,8 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, ret = sensor_hub_get_feature(st->hsdev, st->sensitivity.report_id, - st->sensitivity.index, sizeof(value), - &value); + st->sensitivity.index, + sizeof(value), &value); if (ret < 0 || value < 0) return -EINVAL; @@ -324,8 +322,8 @@ int hid_sensor_write_raw_hyst_rel_value(struct hid_sensor_common *st, return -EINVAL; value = convert_to_vtf_format(st->sensitivity_rel.size, - st->sensitivity_rel.unit_expo, - val1, val2); + st->sensitivity_rel.unit_expo, + val1, val2); ret = sensor_hub_set_feature(st->hsdev, st->sensitivity_rel.report_id, st->sensitivity_rel.index, sizeof(value), &value); @@ -334,8 +332,8 @@ int hid_sensor_write_raw_hyst_rel_value(struct hid_sensor_common *st, ret = sensor_hub_get_feature(st->hsdev, st->sensitivity_rel.report_id, - st->sensitivity_rel.index, sizeof(value), - &value); + st->sensitivity_rel.index, + sizeof(value), &value); if (ret < 0 || value < 0) return -EINVAL; @@ -346,7 +344,7 @@ int hid_sensor_write_raw_hyst_rel_value(struct hid_sensor_common *st, EXPORT_SYMBOL_NS(hid_sensor_write_raw_hyst_rel_value, "IIO_HID"); /* - * This fuction applies the unit exponent to the scale. + * This function applies the unit exponent to the scale. * For example: * 9.806650000 ->exp:2-> val0[980]val1[665000000] * 9.000806000 ->exp:2-> val0[900]val1[80600000] @@ -356,8 +354,8 @@ EXPORT_SYMBOL_NS(hid_sensor_write_raw_hyst_rel_value, "IIO_HID"); * 1.001745329 ->exp:4-> val0[10017]val1[453290000] * 9.806650000 ->exp:-2-> val0[0]val1[98066500] */ -static void adjust_exponent_nano(int *val0, int *val1, int scale0, - int scale1, int exp) +static void adjust_exponent_nano(int *val0, int *val1, + int scale0, int scale1, int exp) { int divisor; int i; @@ -404,8 +402,8 @@ static void adjust_exponent_nano(int *val0, int *val1, int scale0, } int hid_sensor_format_scale(u32 usage_id, - struct hid_sensor_hub_attribute_info *attr_info, - int *val0, int *val1) + struct hid_sensor_hub_attribute_info *attr_info, + int *val0, int *val1) { int i; int exp; @@ -415,12 +413,11 @@ int hid_sensor_format_scale(u32 usage_id, for (i = 0; i < ARRAY_SIZE(unit_conversion); ++i) { if (unit_conversion[i].usage_id == usage_id && - unit_conversion[i].unit == attr_info->units) { - exp = hid_sensor_convert_exponent( - attr_info->unit_expo); + unit_conversion[i].unit == attr_info->units) { + exp = hid_sensor_convert_exponent(attr_info->unit_expo); adjust_exponent_nano(val0, val1, - unit_conversion[i].scale_val0, - unit_conversion[i].scale_val1, exp); + unit_conversion[i].scale_val0, + unit_conversion[i].scale_val1, exp); break; } } @@ -438,8 +435,8 @@ EXPORT_SYMBOL_NS(hid_sensor_convert_timestamp, "IIO_HID"); static int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev, - u32 usage_id, - struct hid_sensor_common *st) + u32 usage_id, + struct hid_sensor_common *st) { sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, usage_id, @@ -473,9 +470,10 @@ int hid_sensor_get_report_latency(struct hid_sensor_common *st) int ret; int value; - ret = sensor_hub_get_feature(st->hsdev, st->report_latency.report_id, - st->report_latency.index, sizeof(value), - &value); + ret = sensor_hub_get_feature(st->hsdev, + st->report_latency.report_id, + st->report_latency.index, + sizeof(value), &value); if (ret < 0) return ret; @@ -498,10 +496,10 @@ bool hid_sensor_batch_mode_supported(struct hid_sensor_common *st) EXPORT_SYMBOL_NS(hid_sensor_batch_mode_supported, "IIO_HID_ATTRIBUTES"); int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, - u32 usage_id, - struct hid_sensor_common *st, - const u32 *sensitivity_addresses, - u32 sensitivity_addresses_len) + u32 usage_id, + struct hid_sensor_common *st, + const u32 *sensitivity_addresses, + u32 sensitivity_addresses_len) { struct hid_sensor_hub_attribute_info timestamp; @@ -527,7 +525,7 @@ int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, usage_id, HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS, - &st->sensitivity); + &st->sensitivity); sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, usage_id, @@ -578,8 +576,9 @@ int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, timestamp.index, timestamp.report_id); ret = sensor_hub_get_feature(hsdev, - st->power_state.report_id, - st->power_state.index, sizeof(value), &value); + st->power_state.report_id, + st->power_state.index, + sizeof(value), &value); if (ret < 0) return ret; if (value < 0) diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index 5540e2d28f4a..60808e2430ca 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -14,6 +14,7 @@ #include <linux/iio/triggered_buffer.h> #include <linux/iio/trigger_consumer.h> #include <linux/iio/sysfs.h> +#include <linux/iio/kfifo_buf.h> #include "hid-sensor-trigger.h" static ssize_t _hid_sensor_set_report_latency(struct device *dev, @@ -202,12 +203,21 @@ static void hid_sensor_set_power_work(struct work_struct *work) _hid_sensor_power_state(attrb, true); } -static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig, - bool state) +static int buffer_postenable(struct iio_dev *indio_dev) { - return hid_sensor_power_state(iio_trigger_get_drvdata(trig), state); + return hid_sensor_power_state(iio_device_get_drvdata(indio_dev), 1); } +static int buffer_predisable(struct iio_dev *indio_dev) +{ + return hid_sensor_power_state(iio_device_get_drvdata(indio_dev), 0); +} + +static const struct iio_buffer_setup_ops hid_sensor_buffer_ops = { + .postenable = buffer_postenable, + .predisable = buffer_predisable, +}; + void hid_sensor_remove_trigger(struct iio_dev *indio_dev, struct hid_sensor_common *attrb) { @@ -219,16 +229,11 @@ void hid_sensor_remove_trigger(struct iio_dev *indio_dev, cancel_work_sync(&attrb->work); iio_trigger_unregister(attrb->trigger); iio_trigger_free(attrb->trigger); - iio_triggered_buffer_cleanup(indio_dev); } EXPORT_SYMBOL_NS(hid_sensor_remove_trigger, "IIO_HID"); -static const struct iio_trigger_ops hid_sensor_trigger_ops = { - .set_trigger_state = &hid_sensor_data_rdy_trigger_set_state, -}; - int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, - struct hid_sensor_common *attrb) + struct hid_sensor_common *attrb) { const struct iio_dev_attr **fifo_attrs; int ret; @@ -239,25 +244,34 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, else fifo_attrs = NULL; - ret = iio_triggered_buffer_setup_ext(indio_dev, - &iio_pollfunc_store_time, NULL, - IIO_BUFFER_DIRECTION_IN, - NULL, fifo_attrs); + indio_dev->modes = INDIO_DIRECT_MODE | INDIO_HARDWARE_TRIGGERED; + + ret = devm_iio_kfifo_buffer_setup_ext(&indio_dev->dev, indio_dev, + &hid_sensor_buffer_ops, + fifo_attrs); if (ret) { - dev_err(&indio_dev->dev, "Triggered Buffer Setup Failed\n"); + dev_err(&indio_dev->dev, "Kfifo Buffer Setup Failed\n"); return ret; } + /* + * The current user space in distro "iio-sensor-proxy" is not working in + * trigerless mode and it expects + * /sys/bus/iio/devices/iio:device0/trigger/current_trigger. + * The change replacing iio_triggered_buffer_setup_ext() with + * devm_iio_kfifo_buffer_setup_ext() will not create attribute without + * registering a trigger with INDIO_HARDWARE_TRIGGERED. + * So the below code fragment is still required. + */ + trig = iio_trigger_alloc(indio_dev->dev.parent, "%s-dev%d", name, iio_device_id(indio_dev)); - if (trig == NULL) { + if (!trig) { dev_err(&indio_dev->dev, "Trigger Allocate Failed\n"); - ret = -ENOMEM; - goto error_triggered_buffer_cleanup; + return -ENOMEM; } iio_trigger_set_drvdata(trig, attrb); - trig->ops = &hid_sensor_trigger_ops; ret = iio_trigger_register(trig); if (ret) { @@ -284,8 +298,6 @@ error_unreg_trigger: iio_trigger_unregister(trig); error_free_trig: iio_trigger_free(trig); -error_triggered_buffer_cleanup: - iio_triggered_buffer_cleanup(indio_dev); return ret; } EXPORT_SYMBOL_NS(hid_sensor_setup_trigger, "IIO_HID"); @@ -302,7 +314,9 @@ static int __maybe_unused hid_sensor_resume(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev); + schedule_work(&attrb->work); + return 0; } @@ -310,6 +324,7 @@ static int __maybe_unused hid_sensor_runtime_resume(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev); + return _hid_sensor_power_state(attrb, true); } diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h index f94fca4f1edf..589de858e369 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h @@ -15,7 +15,7 @@ struct iio_dev; extern const struct dev_pm_ops hid_sensor_pm_ops; int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, - struct hid_sensor_common *attrb); + struct hid_sensor_common *attrb); void hid_sensor_remove_trigger(struct iio_dev *indio_dev, struct hid_sensor_common *attrb); int hid_sensor_power_state(struct hid_sensor_common *st, bool state); diff --git a/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c b/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c index 97526ba87b93..88a82d1370c5 100644 --- a/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c +++ b/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c @@ -10,18 +10,19 @@ #include <linux/iio/common/inv_sensors_timestamp.h> -/* compute jitter, min and max following jitter in per mille */ -#define INV_SENSORS_TIMESTAMP_JITTER(_val, _jitter) \ - (div_s64((_val) * (_jitter), 1000)) +/* compute min and max following jitter in per mille */ #define INV_SENSORS_TIMESTAMP_MIN(_val, _jitter) \ (((_val) * (1000 - (_jitter))) / 1000) #define INV_SENSORS_TIMESTAMP_MAX(_val, _jitter) \ (((_val) * (1000 + (_jitter))) / 1000) +/* minimum timestamp delta between 2 interrupts for measuring period (20ms) */ +#define INV_SENSORS_MIN_IT_DELTA (20 * NSEC_PER_MSEC) + /* Add a new value inside an accumulator and update the estimate value */ -static void inv_update_acc(struct inv_sensors_timestamp_acc *acc, uint32_t val) +static void inv_update_acc(struct inv_sensors_timestamp_acc *acc, u32 val) { - uint64_t sum = 0; + u64 sum = 0; size_t i; acc->values[acc->idx++] = val; @@ -58,9 +59,9 @@ void inv_sensors_timestamp_init(struct inv_sensors_timestamp *ts, EXPORT_SYMBOL_NS_GPL(inv_sensors_timestamp_init, "IIO_INV_SENSORS_TIMESTAMP"); int inv_sensors_timestamp_update_odr(struct inv_sensors_timestamp *ts, - uint32_t period, bool fifo) + u32 period, bool fifo) { - uint32_t mult; + u32 mult; /* when FIFO is on, prevent odr change if one is already pending */ if (fifo && ts->new_mult != 0) @@ -78,9 +79,9 @@ int inv_sensors_timestamp_update_odr(struct inv_sensors_timestamp *ts, } EXPORT_SYMBOL_NS_GPL(inv_sensors_timestamp_update_odr, "IIO_INV_SENSORS_TIMESTAMP"); -static bool inv_validate_period(struct inv_sensors_timestamp *ts, uint32_t period) +static bool inv_validate_period(struct inv_sensors_timestamp *ts, u32 period) { - uint32_t period_min, period_max; + u32 period_min, period_max; /* check that period is acceptable */ period_min = ts->min_period * ts->mult; @@ -92,9 +93,9 @@ static bool inv_validate_period(struct inv_sensors_timestamp *ts, uint32_t perio } static bool inv_update_chip_period(struct inv_sensors_timestamp *ts, - uint32_t period) + u32 period) { - uint32_t new_chip_period; + u32 new_chip_period; if (!inv_validate_period(ts, period)) return false; @@ -102,78 +103,84 @@ static bool inv_update_chip_period(struct inv_sensors_timestamp *ts, /* update chip internal period estimation */ new_chip_period = period / ts->mult; inv_update_acc(&ts->chip_period, new_chip_period); - ts->period = ts->mult * ts->chip_period.val; return true; } -static void inv_align_timestamp_it(struct inv_sensors_timestamp *ts) +static u32 inv_align_timestamp_it(struct inv_sensors_timestamp *ts, + unsigned int sample_nb) { - const int64_t period_min = (int64_t)ts->min_period * ts->mult; - const int64_t period_max = (int64_t)ts->max_period * ts->mult; - int64_t add_max, sub_max; - int64_t delta, jitter; - int64_t adjust; - - /* delta time between last sample and last interrupt */ - delta = ts->it.lo - ts->timestamp; - - /* adjust timestamp while respecting jitter */ - add_max = period_max - (int64_t)ts->period; - sub_max = period_min - (int64_t)ts->period; - jitter = INV_SENSORS_TIMESTAMP_JITTER((int64_t)ts->period, ts->chip.jitter); - if (delta > jitter) - adjust = add_max; - else if (delta < -jitter) - adjust = sub_max; - else - adjust = 0; + const s64 period_min = (s64)ts->min_period * ts->mult; + const s64 period_max = (s64)ts->max_period * ts->mult; + s64 new_period; + + /* compute new period aligning last timestamp with interrupt timestamp */ + new_period = div_s64(ts->it.up - ts->timestamp, sample_nb); - ts->timestamp += adjust; + /* ensure that period never overflows the jitter */ + return clamp(new_period, period_min, period_max); } void inv_sensors_timestamp_interrupt(struct inv_sensors_timestamp *ts, - size_t sample_nb, int64_t timestamp) + size_t sample_nb, s64 timestamp) { struct inv_sensors_timestamp_interval *it; - int64_t delta, interval; - uint32_t period; + s64 delta, delta_threshold, interval; + u32 period; bool valid = false; if (sample_nb == 0) return; + /* no previous data, compute theoretical value from interrupt */ + if (ts->timestamp == 0) { + /* elapsed time: sensor period * sensor samples number */ + interval = (s64)ts->period * (s64)sample_nb; + ts->timestamp = timestamp - interval; + } + + /* update delta timestamps and estimated period */ + it = &ts->delta; + ts->delta_counter += sample_nb; + delta = timestamp - it->up; + delta_threshold = INV_SENSORS_TIMESTAMP_MIN(INV_SENSORS_MIN_IT_DELTA, ts->chip.jitter); + if (delta >= delta_threshold) { + it->lo = it->up; + it->up = timestamp; + if (it->lo != 0) { + /* compute period: delta time divided by number of samples */ + delta = it->up - it->lo; + period = div_s64(delta, ts->delta_counter); + inv_update_chip_period(ts, period); + } + ts->delta_counter = 0; + } + /* update interrupt timestamp and compute chip and sensor periods */ it = &ts->it; it->lo = it->up; it->up = timestamp; delta = it->up - it->lo; if (it->lo != 0) { - /* compute period: delta time divided by number of samples */ + /* compute period and check validity */ period = div_s64(delta, sample_nb); - valid = inv_update_chip_period(ts, period); - } - - /* no previous data, compute theoritical value from interrupt */ - if (ts->timestamp == 0) { - /* elapsed time: sensor period * sensor samples number */ - interval = (int64_t)ts->period * (int64_t)sample_nb; - ts->timestamp = it->up - interval; - return; + valid = inv_validate_period(ts, period); } /* if interrupt interval is valid, sync with interrupt timestamp */ if (valid) - inv_align_timestamp_it(ts); + ts->period = inv_align_timestamp_it(ts, sample_nb); + else + ts->period = ts->mult * ts->chip_period.val; } EXPORT_SYMBOL_NS_GPL(inv_sensors_timestamp_interrupt, "IIO_INV_SENSORS_TIMESTAMP"); void inv_sensors_timestamp_apply_odr(struct inv_sensors_timestamp *ts, - uint32_t fifo_period, size_t fifo_nb, + u32 fifo_period, size_t fifo_nb, unsigned int fifo_no) { - int64_t interval; - uint32_t fifo_mult; + s64 interval; + u32 fifo_mult; if (ts->new_mult == 0) return; @@ -185,7 +192,7 @@ void inv_sensors_timestamp_apply_odr(struct inv_sensors_timestamp *ts, /* * After ODR change the time interval with the previous sample is - * undertermined (depends when the change occures). So we compute the + * undertermined (depends when the change occurs). So we compute the * timestamp from the current interrupt using the new FIFO period, the * total number of samples and the current sample numero. */ @@ -194,7 +201,7 @@ void inv_sensors_timestamp_apply_odr(struct inv_sensors_timestamp *ts, fifo_mult = fifo_period / ts->chip.clock_period; fifo_period = fifo_mult * ts->chip_period.val; /* computes time interval between interrupt and this sample */ - interval = (int64_t)(fifo_nb - fifo_no) * (int64_t)fifo_period; + interval = (s64)(fifo_nb - fifo_no) * (s64)fifo_period; ts->timestamp = ts->it.up - interval; } } diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.c b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c index 588470863681..1960a2ce82a8 100644 --- a/drivers/iio/common/ms_sensors/ms_sensors_i2c.c +++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c @@ -96,7 +96,7 @@ EXPORT_SYMBOL_NS(ms_sensors_read_prom_word, "IIO_MEAS_SPEC_SENSORS"); * * Generic ADC conversion & read function for Measurement Specialties * devices. - * The function will issue conversion command, sleep appopriate delay, and + * The function will issue conversion command, sleep appropriate delay, and * issue command to read ADC. * * Return: 0 on success, negative errno otherwise. diff --git a/drivers/iio/common/scmi_sensors/scmi_iio.c b/drivers/iio/common/scmi_sensors/scmi_iio.c index 5136ad9ada04..442b40ef27cf 100644 --- a/drivers/iio/common/scmi_sensors/scmi_iio.c +++ b/drivers/iio/common/scmi_sensors/scmi_iio.c @@ -419,17 +419,6 @@ static const struct iio_chan_spec_ext_info scmi_iio_ext_info[] = { { } }; -static void scmi_iio_set_timestamp_channel(struct iio_chan_spec *iio_chan, - int scan_index) -{ - iio_chan->type = IIO_TIMESTAMP; - iio_chan->channel = -1; - iio_chan->scan_index = scan_index; - iio_chan->scan_type.sign = 'u'; - iio_chan->scan_type.realbits = 64; - iio_chan->scan_type.storagebits = 64; -} - static void scmi_iio_set_data_channel(struct iio_chan_spec *iio_chan, enum iio_chan_type type, enum iio_modifier mod, int scan_index) @@ -629,7 +618,7 @@ scmi_alloc_iiodev(struct scmi_device *sdev, "Error in registering sensor update notifier for sensor %s\n", sensor->sensor_info->name); - scmi_iio_set_timestamp_channel(&iio_channels[i], i); + iio_channels[i] = IIO_CHAN_SOFT_TIMESTAMP(i); iiodev->channels = iio_channels; return iiodev; } diff --git a/drivers/iio/common/ssp_sensors/ssp_dev.c b/drivers/iio/common/ssp_sensors/ssp_dev.c index da09c9f3ceb6..828fcfe1d4f1 100644 --- a/drivers/iio/common/ssp_sensors/ssp_dev.c +++ b/drivers/iio/common/ssp_sensors/ssp_dev.c @@ -7,7 +7,6 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/mfd/core.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/property.h> @@ -28,7 +27,7 @@ struct ssp_instruction { __le32 a; __le32 b; u8 c; -} __attribute__((__packed__)); +} __packed__; static const u8 ssp_magnitude_table[] = {110, 85, 171, 71, 203, 195, 0, 67, 208, 56, 175, 244, 206, 213, 0, 92, 250, 0, 55, 48, 189, 252, 171, @@ -590,6 +589,7 @@ static void ssp_remove(struct spi_device *spi) ssp_clean_pending_list(data); free_irq(data->spi->irq, data); + cancel_delayed_work_sync(&data->work_refresh); timer_delete_sync(&data->wdt_timer); cancel_work_sync(&data->work_wdt); diff --git a/drivers/iio/common/ssp_sensors/ssp_iio_sensor.h b/drivers/iio/common/ssp_sensors/ssp_iio_sensor.h index 4528ab55eb68..05fcad61c848 100644 --- a/drivers/iio/common/ssp_sensors/ssp_iio_sensor.h +++ b/drivers/iio/common/ssp_sensors/ssp_iio_sensor.h @@ -18,18 +18,6 @@ },\ } -/* It is defined here as it is a mixed timestamp */ -#define SSP_CHAN_TIMESTAMP(_si) { \ - .type = IIO_TIMESTAMP, \ - .channel = -1, \ - .scan_index = _si, \ - .scan_type = { \ - .sign = 's', \ - .realbits = 64, \ - .storagebits = 64, \ - }, \ -} - #define SSP_MS_PER_S 1000 #define SSP_INVERTED_SCALING_FACTOR 1000000U diff --git a/drivers/iio/common/ssp_sensors/ssp_spi.c b/drivers/iio/common/ssp_sensors/ssp_spi.c index 6c81c0385fb5..08ed92859be0 100644 --- a/drivers/iio/common/ssp_sensors/ssp_spi.c +++ b/drivers/iio/common/ssp_sensors/ssp_spi.c @@ -6,7 +6,7 @@ #include "ssp.h" #define SSP_DEV (&data->spi->dev) -#define SSP_GET_MESSAGE_TYPE(data) (data & (3 << SSP_RW)) +#define SSP_GET_MESSAGE_TYPE(data) ((data) & (3 << SSP_RW)) /* * SSP -> AP Instruction @@ -29,7 +29,7 @@ struct ssp_msg_header { __le16 length; __le16 options; __le32 data; -} __attribute__((__packed__)); +} __packed; struct ssp_msg { u16 length; @@ -119,9 +119,9 @@ static inline void ssp_get_buffer(struct ssp_msg *m, unsigned int offset, } #define SSP_GET_BUFFER_AT_INDEX(m, index) \ - (m->buffer[SSP_HEADER_SIZE_ALIGNED + index]) + ((m)->buffer[SSP_HEADER_SIZE_ALIGNED + (index)]) #define SSP_SET_BUFFER_AT_INDEX(m, index, val) \ - (m->buffer[SSP_HEADER_SIZE_ALIGNED + index] = val) + ((m)->buffer[SSP_HEADER_SIZE_ALIGNED + (index)] = val) static void ssp_clean_msg(struct ssp_msg *m) { diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index dac593be5695..76f91696f66a 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -498,29 +498,35 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev, u8 *outdata; struct st_sensor_data *sdata = iio_priv(indio_dev); unsigned int byte_for_channel; + u32 tmp; byte_for_channel = DIV_ROUND_UP(ch->scan_type.realbits + ch->scan_type.shift, 8); - outdata = kmalloc(byte_for_channel, GFP_DMA | GFP_KERNEL); - if (!outdata) - return -ENOMEM; + outdata = sdata->buffer_data; err = regmap_bulk_read(sdata->regmap, ch->address, outdata, byte_for_channel); if (err < 0) - goto st_sensors_free_memory; - - if (byte_for_channel == 1) - *data = (s8)*outdata; - else if (byte_for_channel == 2) - *data = (s16)get_unaligned_le16(outdata); - else if (byte_for_channel == 3) - *data = (s32)sign_extend32(get_unaligned_le24(outdata), 23); + return err; -st_sensors_free_memory: - kfree(outdata); + if (byte_for_channel == 1) { + tmp = *outdata; + } else if (byte_for_channel == 2) { + if (ch->scan_type.endianness == IIO_BE) + tmp = get_unaligned_be16(outdata); + else + tmp = get_unaligned_le16(outdata); + } else if (byte_for_channel == 3) { + if (ch->scan_type.endianness == IIO_BE) + tmp = get_unaligned_be24(outdata); + else + tmp = get_unaligned_le24(outdata); + } else { + return -EINVAL; + } + *data = sign_extend32(tmp, BYTES_TO_BITS(byte_for_channel) - 1); - return err; + return 0; } int st_sensors_read_info_raw(struct iio_dev *indio_dev, diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c index 8a8ab688d798..7b3e9732cc3e 100644 --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c @@ -211,10 +211,8 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, irq_trig, sdata->trig->name, sdata->trig); - if (err) { - dev_err(parent, "failed to request trigger IRQ.\n"); + if (err) return err; - } err = devm_iio_trigger_register(parent, sdata->trig); if (err < 0) { diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index db9f5c711b3d..3b3c77d8b3e1 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -11,8 +11,11 @@ config AD3530R depends on SPI select REGMAP_SPI help - Say yes here to build support for Analog Devices AD3530R, AD3531R - Digital to Analog Converter. + Say yes here to build support for the following Analog Devices + Digital to Analog Converters: + - AD3530/AD3530R (8-channel) + - AD3531/AD3531R (4-channel) + - AD3532/AD3532R (16-channel) To compile this driver as a module, choose M here: the module will be called ad3530r. @@ -178,6 +181,17 @@ config AD5624R_SPI Say yes here to build support for Analog Devices AD5624R, AD5644R and AD5664R converters (DAC). This driver uses the common SPI interface. +config AD5706R + tristate "Analog Devices AD5706R DAC driver" + depends on SPI + select REGMAP + help + Say yes here to build support for Analog Devices AD5706R 4-channel, + 16-bit current output DAC. + + To compile this driver as a module, choose M here: the + module will be called ad5706r. + config AD9739A tristate "Analog Devices AD9739A RF DAC spi driver" depends on SPI @@ -229,15 +243,26 @@ config LTC2688 config AD5686 tristate + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER config AD5686_SPI tristate "Analog Devices AD5686 and similar multi-channel DACs (SPI)" depends on SPI select AD5686 help - Say yes here to build support for Analog Devices AD5672R, AD5674R, - AD5676, AD5676R, AD5679R, AD5684, AD5684R, AD5684R, AD5685R, AD5686, - AD5686R Voltage Output Digital to Analog Converter. + Say yes here to build support for Analog Devices Voltage Output + Digital to Analog Converters: + - Single-channel: + AD5310R, AD5681R, AD5682R, AD5683, AD5683R + - Dual-channel: + AD5313R, AD5687, AD5687R, AD5689, AD5689R + - Quad-channel: + AD5317R, AD5684, AD5684R, AD5685R, AD5686, AD5686R + - 8-channel: + AD5672R, AD5676, AD5676R + - 16-channel: + AD5674, AD5674R, AD5679, AD5679R To compile this driver as a module, choose M here: the module will be called ad5686. @@ -247,10 +272,18 @@ config AD5696_I2C depends on I2C select AD5686 help - Say yes here to build support for Analog Devices AD5311R, AD5337, - AD5338R, AD5671R, AD5673R, AD5675R, AD5677R, AD5691R, AD5692R, AD5693, - AD5693R, AD5694, AD5694R, AD5695R, AD5696, and AD5696R Digital to - Analog converters. + Say yes here to build support for Analog Devices Voltage Output + Digital to Analog Converters: + - Single-channel: + AD5311R, AD5691R, AD5692R, AD5693, AD5693R + - Dual-channel: + AD5338R, AD5697R + - Quad-channel: + AD5316R, AD5694, AD5694R, AD5695R, AD5696, AD5696R + - 8-channel: + AD5671R, AD5675, AD5675R + - 16-channel: + AD5673R, AD5677R To compile this driver as a module, choose M here: the module will be called ad5696. @@ -408,6 +441,7 @@ config DPOT_DAC config DS4424 tristate "Maxim Integrated DS4422/DS4424 DAC driver" depends on I2C + select REGMAP_I2C help If you say yes here you get support for Maxim chips DS4422, DS4424. @@ -515,6 +549,17 @@ config MAX5821 Say yes here to build support for Maxim MAX5821 10 bits DAC. +config MCF54415_DAC + tristate "NXP MCF54415 DAC driver" + depends on M5441x || COMPILE_TEST + select REGMAP_MMIO + help + Say yes here if you want to build support for NXP ColdFire + MCF54415/6/7/8 12-bit DAC module. + + To compile this driver as a module, choose M here: the module + will be called mcf54415_dac. + config MCP4725 tristate "MCP4725/6 DAC driver" depends on I2C @@ -537,9 +582,20 @@ config MCP4728 To compile this driver as a module, choose M here: the module will be called mcp4728. +config MCP47A1 + tristate "MCP47A1 DAC driver" + depends on I2C + help + Say Y here if you want to build a driver for the Microchip + MCP47A1 digital-to-analog converter with an I2C interface. + + To compile this driver as a module, choose M here: the module + will be called mcp47a1. + config MCP47FEB02 tristate "MCP47F(E/V)B01/02/04/08/11/12/14/18/21/22/24/28 DAC driver" depends on I2C + select REGMAP_I2C help Say yes here if you want to build the driver for the Microchip: - 8-bit DAC: diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index 2a80bbf4e80a..992f8930f95c 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_AD5449) += ad5449.o obj-$(CONFIG_AD5592R_BASE) += ad5592r-base.o obj-$(CONFIG_AD5592R) += ad5592r.o obj-$(CONFIG_AD5593R) += ad5593r.o +obj-$(CONFIG_AD5706R) += ad5706r.o obj-$(CONFIG_AD5755) += ad5755.o obj-$(CONFIG_AD5758) += ad5758.o obj-$(CONFIG_AD5761) += ad5761.o @@ -51,8 +52,10 @@ obj-$(CONFIG_MAX517) += max517.o obj-$(CONFIG_MAX22007) += max22007.o obj-$(CONFIG_MAX5522) += max5522.o obj-$(CONFIG_MAX5821) += max5821.o +obj-$(CONFIG_MCF54415_DAC) += mcf54415_dac.o obj-$(CONFIG_MCP4725) += mcp4725.o obj-$(CONFIG_MCP4728) += mcp4728.o +obj-$(CONFIG_MCP47A1) += mcp47a1.o obj-$(CONFIG_MCP47FEB02) += mcp47feb02.o obj-$(CONFIG_MCP4821) += mcp4821.o obj-$(CONFIG_MCP4922) += mcp4922.o diff --git a/drivers/iio/dac/ad3530r.c b/drivers/iio/dac/ad3530r.c index b97b46090d80..06b7f280f61b 100644 --- a/drivers/iio/dac/ad3530r.c +++ b/drivers/iio/dac/ad3530r.c @@ -2,6 +2,7 @@ /* * AD3530R/AD3530 8-channel, 16-bit Voltage Output DAC Driver * AD3531R/AD3531 4-channel, 16-bit Voltage Output DAC Driver + * AD3532R/AD3532 16-channel, 16-bit Voltage Output DAC Driver * * Copyright 2025 Analog Devices Inc. */ @@ -16,7 +17,6 @@ #include <linux/gpio/consumer.h> #include <linux/iio/iio.h> #include <linux/kstrtox.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/property.h> @@ -39,6 +39,25 @@ #define AD3531R_SW_LDAC_TRIG_A 0xDD #define AD3531R_INPUT_CH 0xE3 +/* AD3532R/AD3532 bank 0 registers (channels 0-7) */ +#define AD3532R_INTERFACE_CONFIG_A_0 0x1000 +#define AD3532R_OUTPUT_OPERATING_MODE_0 0x1020 +#define AD3532R_OUTPUT_OPERATING_MODE_1 0x1021 +#define AD3532R_OUTPUT_CONTROL_0 0x102A +#define AD3532R_REFERENCE_CONTROL_0 0x103C +#define AD3532R_SW_LDAC_TRIG_0 0x10E5 +#define AD3532R_INPUT_CH_0 0x10EB + +/* AD3532R/AD3532 bank 1 registers (channels 8-15) */ +#define AD3532R_INTERFACE_CONFIG_A_1 0x3000 +#define AD3532R_OUTPUT_OPERATING_MODE_2 0x3020 +#define AD3532R_OUTPUT_OPERATING_MODE_3 0x3021 +#define AD3532R_OUTPUT_CONTROL_1 0x302A +#define AD3532R_REFERENCE_CONTROL_1 0x303C +#define AD3532R_SW_LDAC_TRIG_1 0x30E5 +#define AD3532R_INPUT_CH_1 0x30EB +#define AD3532R_MAX_REG_ADDR 0x30F9 + #define AD3530R_SLD_TRIG_A BIT(7) #define AD3530R_OUTPUT_CONTROL_RANGE BIT(2) #define AD3530R_REFERENCE_CONTROL_SEL BIT(0) @@ -50,8 +69,10 @@ #define AD3530R_LDAC_PULSE_US 100 #define AD3530R_DAC_MAX_VAL GENMASK(15, 0) -#define AD3530R_MAX_CHANNELS 8 +#define AD3530R_CH_PER_REG 4 +#define AD3530R_CH_PER_BANK 8 #define AD3531R_MAX_CHANNELS 4 +#define AD3532R_MAX_CHANNELS 16 enum ad3530r_mode { AD3530R_NORMAL_OP, @@ -68,9 +89,16 @@ struct ad3530r_chan { struct ad3530r_chip_info { const char *name; const struct iio_chan_spec *channels; + const struct regmap_config *regmap_config; int (*input_ch_reg)(unsigned int channel); + int (*sw_ldac_trig_reg)(unsigned int channel); + const unsigned int *interface_config_a; + const unsigned int *output_control; + const unsigned int *reference_control; + const unsigned int *op_mode; unsigned int num_channels; - unsigned int sw_ldac_trig_reg; + unsigned int num_banks; + unsigned int num_op_mode_regs; bool internal_ref_support; }; @@ -78,7 +106,7 @@ struct ad3530r_state { struct regmap *regmap; /* lock to protect against multiple access to the device and shared data */ struct mutex lock; - struct ad3530r_chan chan[AD3530R_MAX_CHANNELS]; + struct ad3530r_chan chan[AD3532R_MAX_CHANNELS]; const struct ad3530r_chip_info *chip_info; struct gpio_desc *ldac_gpio; int vref_mV; @@ -99,12 +127,32 @@ static int ad3531r_input_ch_reg(unsigned int channel) return 2 * channel + AD3531R_INPUT_CH; } +static int ad3532r_input_ch_reg(unsigned int channel) +{ + unsigned int bank = channel / AD3530R_CH_PER_BANK; + unsigned int local_ch = channel % AD3530R_CH_PER_BANK; + + return 2 * local_ch + (bank ? AD3532R_INPUT_CH_1 : AD3532R_INPUT_CH_0); +} + static const char * const ad3530r_powerdown_modes[] = { "1kohm_to_gnd", "7.7kohm_to_gnd", "32kohm_to_gnd", }; +static const char * const ad3531r_powerdown_modes[] = { + "500ohm_to_gnd", + "3.85kohm_to_gnd", + "16kohm_to_gnd", +}; + +static const char * const ad3532r_powerdown_modes[] = { + "1kohm_to_gnd", + "10kohm_to_gnd", + "three_state", +}; + static int ad3530r_get_powerdown_mode(struct iio_dev *indio_dev, const struct iio_chan_spec *chan) { @@ -133,6 +181,20 @@ static const struct iio_enum ad3530r_powerdown_mode_enum = { .set = ad3530r_set_powerdown_mode, }; +static const struct iio_enum ad3531r_powerdown_mode_enum = { + .items = ad3531r_powerdown_modes, + .num_items = ARRAY_SIZE(ad3531r_powerdown_modes), + .get = ad3530r_get_powerdown_mode, + .set = ad3530r_set_powerdown_mode, +}; + +static const struct iio_enum ad3532r_powerdown_mode_enum = { + .items = ad3532r_powerdown_modes, + .num_items = ARRAY_SIZE(ad3532r_powerdown_modes), + .get = ad3530r_get_powerdown_mode, + .set = ad3530r_set_powerdown_mode, +}; + static ssize_t ad3530r_get_dac_powerdown(struct iio_dev *indio_dev, uintptr_t private, const struct iio_chan_spec *chan, @@ -177,6 +239,62 @@ static ssize_t ad3530r_set_dac_powerdown(struct iio_dev *indio_dev, return len; } +static ssize_t ad3532r_set_dac_powerdown(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct ad3530r_state *st = iio_priv(indio_dev); + unsigned int bank, local_ch, reg_in_bank, ch_in_reg; + unsigned int reg, mask, val; + bool powerdown; + int ret; + + ret = kstrtobool(buf, &powerdown); + if (ret) + return ret; + + bank = chan->channel / AD3530R_CH_PER_BANK; + local_ch = chan->channel % AD3530R_CH_PER_BANK; + reg_in_bank = local_ch / AD3530R_CH_PER_REG; + ch_in_reg = local_ch % AD3530R_CH_PER_REG; + + reg = reg_in_bank + (bank ? AD3532R_OUTPUT_OPERATING_MODE_2 : + AD3532R_OUTPUT_OPERATING_MODE_0); + mask = AD3530R_OP_MODE_CHAN_MSK(ch_in_reg); + + guard(mutex)(&st->lock); + if (powerdown) { + val = field_prep(mask, st->chan[chan->channel].powerdown_mode); + ret = regmap_update_bits(st->regmap, reg, mask, val); + } else { + ret = regmap_clear_bits(st->regmap, reg, mask); + } + if (ret) + return ret; + + st->chan[chan->channel].powerdown = powerdown; + + return len; +} + +static int ad3530r_trigger_sw_ldac_reg(unsigned int channel) +{ + return AD3530R_SW_LDAC_TRIG_A; +} + +static int ad3531r_trigger_sw_ldac_reg(unsigned int channel) +{ + return AD3531R_SW_LDAC_TRIG_A; +} + +static int ad3532r_trigger_sw_ldac_reg(unsigned int channel) +{ + unsigned int bank = channel / AD3530R_CH_PER_BANK; + + return bank ? AD3532R_SW_LDAC_TRIG_1 : AD3532R_SW_LDAC_TRIG_0; +} + static int ad3530r_trigger_hw_ldac(struct gpio_desc *ldac_gpio) { gpiod_set_value_cansleep(ldac_gpio, 1); @@ -202,7 +320,7 @@ static int ad3530r_dac_write(struct ad3530r_state *st, unsigned int chan, if (st->ldac_gpio) return ad3530r_trigger_hw_ldac(st->ldac_gpio); - return regmap_set_bits(st->regmap, st->chip_info->sw_ldac_trig_reg, + return regmap_set_bits(st->regmap, st->chip_info->sw_ldac_trig_reg(chan), AD3530R_SLD_TRIG_A); } @@ -276,7 +394,33 @@ static const struct iio_chan_spec_ext_info ad3530r_ext_info[] = { { } }; -#define AD3530R_CHAN(_chan) \ +static const struct iio_chan_spec_ext_info ad3531r_ext_info[] = { + { + .name = "powerdown", + .shared = IIO_SEPARATE, + .read = ad3530r_get_dac_powerdown, + .write = ad3530r_set_dac_powerdown, + }, + IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad3531r_powerdown_mode_enum), + IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, + &ad3531r_powerdown_mode_enum), + { } +}; + +static const struct iio_chan_spec_ext_info ad3532r_ext_info[] = { + { + .name = "powerdown", + .shared = IIO_SEPARATE, + .read = ad3530r_get_dac_powerdown, + .write = ad3532r_set_dac_powerdown, + }, + IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad3532r_powerdown_mode_enum), + IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, + &ad3532r_powerdown_mode_enum), + { } +}; + +#define AD3530R_CHAN(_chan, _ext_info) \ { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ @@ -284,69 +428,236 @@ static const struct iio_chan_spec_ext_info ad3530r_ext_info[] = { .output = 1, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_SCALE), \ - .ext_info = ad3530r_ext_info, \ + .ext_info = _ext_info, \ } static const struct iio_chan_spec ad3530r_channels[] = { - AD3530R_CHAN(0), - AD3530R_CHAN(1), - AD3530R_CHAN(2), - AD3530R_CHAN(3), - AD3530R_CHAN(4), - AD3530R_CHAN(5), - AD3530R_CHAN(6), - AD3530R_CHAN(7), + AD3530R_CHAN(0, ad3530r_ext_info), + AD3530R_CHAN(1, ad3530r_ext_info), + AD3530R_CHAN(2, ad3530r_ext_info), + AD3530R_CHAN(3, ad3530r_ext_info), + AD3530R_CHAN(4, ad3530r_ext_info), + AD3530R_CHAN(5, ad3530r_ext_info), + AD3530R_CHAN(6, ad3530r_ext_info), + AD3530R_CHAN(7, ad3530r_ext_info), }; static const struct iio_chan_spec ad3531r_channels[] = { - AD3530R_CHAN(0), - AD3530R_CHAN(1), - AD3530R_CHAN(2), - AD3530R_CHAN(3), + AD3530R_CHAN(0, ad3531r_ext_info), + AD3530R_CHAN(1, ad3531r_ext_info), + AD3530R_CHAN(2, ad3531r_ext_info), + AD3530R_CHAN(3, ad3531r_ext_info), +}; + +static const struct iio_chan_spec ad3532r_channels[] = { + AD3530R_CHAN(0, ad3532r_ext_info), + AD3530R_CHAN(1, ad3532r_ext_info), + AD3530R_CHAN(2, ad3532r_ext_info), + AD3530R_CHAN(3, ad3532r_ext_info), + AD3530R_CHAN(4, ad3532r_ext_info), + AD3530R_CHAN(5, ad3532r_ext_info), + AD3530R_CHAN(6, ad3532r_ext_info), + AD3530R_CHAN(7, ad3532r_ext_info), + AD3530R_CHAN(8, ad3532r_ext_info), + AD3530R_CHAN(9, ad3532r_ext_info), + AD3530R_CHAN(10, ad3532r_ext_info), + AD3530R_CHAN(11, ad3532r_ext_info), + AD3530R_CHAN(12, ad3532r_ext_info), + AD3530R_CHAN(13, ad3532r_ext_info), + AD3530R_CHAN(14, ad3532r_ext_info), + AD3530R_CHAN(15, ad3532r_ext_info), +}; + +static const unsigned int ad3530r_if_config[] = { + AD3530R_INTERFACE_CONFIG_A, +}; + +static const unsigned int ad3530r_out_ctrl[] = { + AD3530R_OUTPUT_CONTROL_0, +}; + +static const unsigned int ad3530r_ref_ctrl[] = { + AD3530R_REFERENCE_CONTROL_0, +}; + +static const unsigned int ad3530r_op_mode[] = { + AD3530R_OUTPUT_OPERATING_MODE_0, + AD3530R_OUTPUT_OPERATING_MODE_1, +}; + +static const unsigned int ad3531r_op_mode[] = { + AD3530R_OUTPUT_OPERATING_MODE_0, +}; + +static const unsigned int ad3532r_if_config[] = { + AD3532R_INTERFACE_CONFIG_A_0, + AD3532R_INTERFACE_CONFIG_A_1, +}; + +static const unsigned int ad3532r_out_ctrl[] = { + AD3532R_OUTPUT_CONTROL_0, + AD3532R_OUTPUT_CONTROL_1, +}; + +static const unsigned int ad3532r_ref_ctrl[] = { + AD3532R_REFERENCE_CONTROL_0, + AD3532R_REFERENCE_CONTROL_1, +}; + +static const unsigned int ad3532r_op_mode[] = { + AD3532R_OUTPUT_OPERATING_MODE_0, + AD3532R_OUTPUT_OPERATING_MODE_1, + AD3532R_OUTPUT_OPERATING_MODE_2, + AD3532R_OUTPUT_OPERATING_MODE_3, +}; + +static const struct regmap_config ad3530r_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .max_register = AD3530R_MAX_REG_ADDR, +}; + +static const struct regmap_config ad3532r_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .max_register = AD3532R_MAX_REG_ADDR, }; static const struct ad3530r_chip_info ad3530_chip = { .name = "ad3530", .channels = ad3530r_channels, + .regmap_config = &ad3530r_regmap_config, .num_channels = ARRAY_SIZE(ad3530r_channels), - .sw_ldac_trig_reg = AD3530R_SW_LDAC_TRIG_A, + .sw_ldac_trig_reg = ad3530r_trigger_sw_ldac_reg, .input_ch_reg = ad3530r_input_ch_reg, + .interface_config_a = ad3530r_if_config, + .output_control = ad3530r_out_ctrl, + .reference_control = ad3530r_ref_ctrl, + .op_mode = ad3530r_op_mode, + .num_banks = ARRAY_SIZE(ad3530r_if_config), + .num_op_mode_regs = ARRAY_SIZE(ad3530r_op_mode), .internal_ref_support = false, }; static const struct ad3530r_chip_info ad3530r_chip = { .name = "ad3530r", .channels = ad3530r_channels, + .regmap_config = &ad3530r_regmap_config, .num_channels = ARRAY_SIZE(ad3530r_channels), - .sw_ldac_trig_reg = AD3530R_SW_LDAC_TRIG_A, + .sw_ldac_trig_reg = ad3530r_trigger_sw_ldac_reg, .input_ch_reg = ad3530r_input_ch_reg, + .interface_config_a = ad3530r_if_config, + .output_control = ad3530r_out_ctrl, + .reference_control = ad3530r_ref_ctrl, + .op_mode = ad3530r_op_mode, + .num_banks = ARRAY_SIZE(ad3530r_if_config), + .num_op_mode_regs = ARRAY_SIZE(ad3530r_op_mode), .internal_ref_support = true, }; static const struct ad3530r_chip_info ad3531_chip = { .name = "ad3531", .channels = ad3531r_channels, + .regmap_config = &ad3530r_regmap_config, .num_channels = ARRAY_SIZE(ad3531r_channels), - .sw_ldac_trig_reg = AD3531R_SW_LDAC_TRIG_A, + .sw_ldac_trig_reg = ad3531r_trigger_sw_ldac_reg, .input_ch_reg = ad3531r_input_ch_reg, + .interface_config_a = ad3530r_if_config, + .output_control = ad3530r_out_ctrl, + .reference_control = ad3530r_ref_ctrl, + .op_mode = ad3531r_op_mode, + .num_banks = ARRAY_SIZE(ad3530r_if_config), + .num_op_mode_regs = ARRAY_SIZE(ad3531r_op_mode), .internal_ref_support = false, }; static const struct ad3530r_chip_info ad3531r_chip = { .name = "ad3531r", .channels = ad3531r_channels, + .regmap_config = &ad3530r_regmap_config, .num_channels = ARRAY_SIZE(ad3531r_channels), - .sw_ldac_trig_reg = AD3531R_SW_LDAC_TRIG_A, + .sw_ldac_trig_reg = ad3531r_trigger_sw_ldac_reg, .input_ch_reg = ad3531r_input_ch_reg, + .interface_config_a = ad3530r_if_config, + .output_control = ad3530r_out_ctrl, + .reference_control = ad3530r_ref_ctrl, + .op_mode = ad3531r_op_mode, + .num_banks = ARRAY_SIZE(ad3530r_if_config), + .num_op_mode_regs = ARRAY_SIZE(ad3531r_op_mode), .internal_ref_support = true, }; +static const struct ad3530r_chip_info ad3532_chip = { + .name = "ad3532", + .channels = ad3532r_channels, + .regmap_config = &ad3532r_regmap_config, + .num_channels = ARRAY_SIZE(ad3532r_channels), + .sw_ldac_trig_reg = ad3532r_trigger_sw_ldac_reg, + .input_ch_reg = ad3532r_input_ch_reg, + .interface_config_a = ad3532r_if_config, + .output_control = ad3532r_out_ctrl, + .reference_control = ad3532r_ref_ctrl, + .op_mode = ad3532r_op_mode, + .num_banks = ARRAY_SIZE(ad3532r_if_config), + .num_op_mode_regs = ARRAY_SIZE(ad3532r_op_mode), + .internal_ref_support = false, +}; + +static const struct ad3530r_chip_info ad3532r_chip = { + .name = "ad3532r", + .channels = ad3532r_channels, + .regmap_config = &ad3532r_regmap_config, + .num_channels = ARRAY_SIZE(ad3532r_channels), + .sw_ldac_trig_reg = ad3532r_trigger_sw_ldac_reg, + .input_ch_reg = ad3532r_input_ch_reg, + .interface_config_a = ad3532r_if_config, + .output_control = ad3532r_out_ctrl, + .reference_control = ad3532r_ref_ctrl, + .op_mode = ad3532r_op_mode, + .num_banks = ARRAY_SIZE(ad3532r_if_config), + .num_op_mode_regs = ARRAY_SIZE(ad3532r_op_mode), + .internal_ref_support = true, +}; + +static int ad3530r_set_reg_bank_bits(const struct ad3530r_state *st, + const unsigned int *regs, + unsigned int num_regs, + unsigned int mask) +{ + int ret; + + for (unsigned int i = 0; i < num_regs; i++) { + ret = regmap_set_bits(st->regmap, regs[i], mask); + if (ret) + return ret; + } + + return 0; +} + +static int ad3530r_write_reg_banks(const struct ad3530r_state *st, + const unsigned int *regs, + unsigned int num_regs, + unsigned int val) +{ + int ret; + + for (unsigned int i = 0; i < num_regs; i++) { + ret = regmap_write(st->regmap, regs[i], val); + if (ret) + return ret; + } + + return 0; +} + static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV) { + const struct ad3530r_chip_info *chip_info = st->chip_info; struct device *dev = regmap_get_device(st->regmap); struct gpio_desc *reset_gpio; - int i, ret; u8 range_multiplier, val; + int ret; reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(reset_gpio)) @@ -359,8 +670,9 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV) gpiod_set_value_cansleep(reset_gpio, 0); } else { /* Perform software reset */ - ret = regmap_update_bits(st->regmap, AD3530R_INTERFACE_CONFIG_A, - AD3530R_SW_RESET, AD3530R_SW_RESET); + ret = ad3530r_set_reg_bank_bits(st, chip_info->interface_config_a, + chip_info->num_banks, + AD3530R_SW_RESET); if (ret) return ret; } @@ -369,8 +681,9 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV) range_multiplier = 1; if (device_property_read_bool(dev, "adi,range-double")) { - ret = regmap_set_bits(st->regmap, AD3530R_OUTPUT_CONTROL_0, - AD3530R_OUTPUT_CONTROL_RANGE); + ret = ad3530r_set_reg_bank_bits(st, chip_info->output_control, + chip_info->num_banks, + AD3530R_OUTPUT_CONTROL_RANGE); if (ret) return ret; @@ -380,8 +693,9 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV) if (external_vref_uV) { st->vref_mV = range_multiplier * external_vref_uV / MILLI; } else { - ret = regmap_set_bits(st->regmap, AD3530R_REFERENCE_CONTROL_0, - AD3530R_REFERENCE_CONTROL_SEL); + ret = ad3530r_set_reg_bank_bits(st, chip_info->reference_control, + chip_info->num_banks, + AD3530R_REFERENCE_CONTROL_SEL); if (ret) return ret; @@ -394,18 +708,12 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV) FIELD_PREP(AD3530R_OP_MODE_CHAN_MSK(2), AD3530R_NORMAL_OP) | FIELD_PREP(AD3530R_OP_MODE_CHAN_MSK(3), AD3530R_NORMAL_OP); - ret = regmap_write(st->regmap, AD3530R_OUTPUT_OPERATING_MODE_0, val); + ret = ad3530r_write_reg_banks(st, st->chip_info->op_mode, + st->chip_info->num_op_mode_regs, val); if (ret) return ret; - if (st->chip_info->num_channels > 4) { - ret = regmap_write(st->regmap, AD3530R_OUTPUT_OPERATING_MODE_1, - val); - if (ret) - return ret; - } - - for (i = 0; i < st->chip_info->num_channels; i++) + for (unsigned int i = 0; i < st->chip_info->num_channels; i++) st->chan[i].powerdown_mode = AD3530R_POWERDOWN_32K; st->ldac_gpio = devm_gpiod_get_optional(dev, "ldac", GPIOD_OUT_LOW); @@ -416,12 +724,6 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV) return 0; } -static const struct regmap_config ad3530r_regmap_config = { - .reg_bits = 16, - .val_bits = 8, - .max_register = AD3530R_MAX_REG_ADDR, -}; - static const struct iio_info ad3530r_info = { .read_raw = ad3530r_read_raw, .write_raw = ad3530r_write_raw, @@ -442,7 +744,11 @@ static int ad3530r_probe(struct spi_device *spi) st = iio_priv(indio_dev); - st->regmap = devm_regmap_init_spi(spi, &ad3530r_regmap_config); + st->chip_info = spi_get_device_match_data(spi); + if (!st->chip_info) + return -ENODEV; + + st->regmap = devm_regmap_init_spi(spi, st->chip_info->regmap_config); if (IS_ERR(st->regmap)) return dev_err_probe(dev, PTR_ERR(st->regmap), "Failed to init regmap"); @@ -451,10 +757,6 @@ static int ad3530r_probe(struct spi_device *spi) if (ret) return ret; - st->chip_info = spi_get_device_match_data(spi); - if (!st->chip_info) - return -ENODEV; - ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulators), regulators); if (ret) @@ -484,10 +786,12 @@ static int ad3530r_probe(struct spi_device *spi) } static const struct spi_device_id ad3530r_id[] = { - { "ad3530", (kernel_ulong_t)&ad3530_chip }, - { "ad3530r", (kernel_ulong_t)&ad3530r_chip }, - { "ad3531", (kernel_ulong_t)&ad3531_chip }, - { "ad3531r", (kernel_ulong_t)&ad3531r_chip }, + { .name = "ad3530", .driver_data = (kernel_ulong_t)&ad3530_chip }, + { .name = "ad3530r", .driver_data = (kernel_ulong_t)&ad3530r_chip }, + { .name = "ad3531", .driver_data = (kernel_ulong_t)&ad3531_chip }, + { .name = "ad3531r", .driver_data = (kernel_ulong_t)&ad3531r_chip }, + { .name = "ad3532", .driver_data = (kernel_ulong_t)&ad3532_chip }, + { .name = "ad3532r", .driver_data = (kernel_ulong_t)&ad3532r_chip }, { } }; MODULE_DEVICE_TABLE(spi, ad3530r_id); @@ -497,6 +801,8 @@ static const struct of_device_id ad3530r_of_match[] = { { .compatible = "adi,ad3530r", .data = &ad3530r_chip }, { .compatible = "adi,ad3531", .data = &ad3531_chip }, { .compatible = "adi,ad3531r", .data = &ad3531r_chip }, + { .compatible = "adi,ad3532", .data = &ad3532_chip }, + { .compatible = "adi,ad3532r", .data = &ad3532r_chip }, { } }; MODULE_DEVICE_TABLE(of, ad3530r_of_match); diff --git a/drivers/iio/dac/ad3552r-hs.c b/drivers/iio/dac/ad3552r-hs.c index a9578afa7015..f865843aa439 100644 --- a/drivers/iio/dac/ad3552r-hs.c +++ b/drivers/iio/dac/ad3552r-hs.c @@ -12,7 +12,6 @@ #include <linux/gpio/consumer.h> #include <linux/iio/backend.h> #include <linux/iio/buffer.h> -#include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <linux/property.h> #include <linux/units.h> @@ -549,7 +548,7 @@ static ssize_t ad3552r_hs_write_data_source(struct file *f, guard(mutex)(&st->lock); - if (count >= sizeof(buf)) + if (*ppos != 0 || count >= sizeof(buf)) return -ENOSPC; ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, userbuf, @@ -591,7 +590,7 @@ static ssize_t ad3552r_hs_show_data_source_avail(struct file *f, int i; for (i = 0; i < ARRAY_SIZE(dbgfs_attr_source); i++) { - len += scnprintf(buf + len, PAGE_SIZE - len, "%s ", + len += scnprintf(buf + len, sizeof(buf) - len, "%s ", dbgfs_attr_source[i]); } buf[len - 1] = '\n'; diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c index 93c33bc3e1be..16db94fef9d4 100644 --- a/drivers/iio/dac/ad3552r.c +++ b/drivers/iio/dac/ad3552r.c @@ -167,8 +167,7 @@ static int ad3552r_read_raw(struct iio_dev *indio_dev, mutex_unlock(&dac->lock); if (err < 0) return err; - *val = !((tmp_val & AD3552R_MASK_CH_DAC_POWERDOWN(ch)) >> - __ffs(AD3552R_MASK_CH_DAC_POWERDOWN(ch))); + *val = !field_get(AD3552R_MASK_CH_DAC_POWERDOWN(ch), tmp_val); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = dac->ch_data[ch].scale_int; @@ -629,7 +628,9 @@ static int ad3552r_probe(struct spi_device *spi) if (!dac->model_data) return -EINVAL; - mutex_init(&dac->lock); + err = devm_mutex_init(&spi->dev, &dac->lock); + if (err) + return err; err = ad3552r_init(dac); if (err) diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c index 84be5174babd..298f3a703571 100644 --- a/drivers/iio/dac/ad5064.c +++ b/drivers/iio/dac/ad5064.c @@ -920,22 +920,22 @@ static int ad5064_spi_probe(struct spi_device *spi) } static const struct spi_device_id ad5064_spi_ids[] = { - {"ad5024", ID_AD5024}, - {"ad5025", ID_AD5025}, - {"ad5044", ID_AD5044}, - {"ad5045", ID_AD5045}, - {"ad5064", ID_AD5064}, - {"ad5064-1", ID_AD5064_1}, - {"ad5065", ID_AD5065}, - {"ad5628-1", ID_AD5628_1}, - {"ad5628-2", ID_AD5628_2}, - {"ad5648-1", ID_AD5648_1}, - {"ad5648-2", ID_AD5648_2}, - {"ad5666-1", ID_AD5666_1}, - {"ad5666-2", ID_AD5666_2}, - {"ad5668-1", ID_AD5668_1}, - {"ad5668-2", ID_AD5668_2}, - {"ad5668-3", ID_AD5668_2}, /* similar enough to ad5668-2 */ + { .name = "ad5024", .driver_data = ID_AD5024 }, + { .name = "ad5025", .driver_data = ID_AD5025 }, + { .name = "ad5044", .driver_data = ID_AD5044 }, + { .name = "ad5045", .driver_data = ID_AD5045 }, + { .name = "ad5064", .driver_data = ID_AD5064 }, + { .name = "ad5064-1", .driver_data = ID_AD5064_1 }, + { .name = "ad5065", .driver_data = ID_AD5065 }, + { .name = "ad5628-1", .driver_data = ID_AD5628_1 }, + { .name = "ad5628-2", .driver_data = ID_AD5628_2 }, + { .name = "ad5648-1", .driver_data = ID_AD5648_1 }, + { .name = "ad5648-2", .driver_data = ID_AD5648_2 }, + { .name = "ad5666-1", .driver_data = ID_AD5666_1 }, + { .name = "ad5666-2", .driver_data = ID_AD5666_2 }, + { .name = "ad5668-1", .driver_data = ID_AD5668_1 }, + { .name = "ad5668-2", .driver_data = ID_AD5668_2 }, + { .name = "ad5668-3", .driver_data = ID_AD5668_2 }, /* similar enough to ad5668-2 */ { } }; MODULE_DEVICE_TABLE(spi, ad5064_spi_ids); @@ -1001,53 +1001,53 @@ static int ad5064_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id ad5064_i2c_ids[] = { - {"ad5625", ID_AD5625 }, - {"ad5625r-1v25", ID_AD5625R_1V25 }, - {"ad5625r-2v5", ID_AD5625R_2V5 }, - {"ad5627", ID_AD5627 }, - {"ad5627r-1v25", ID_AD5627R_1V25 }, - {"ad5627r-2v5", ID_AD5627R_2V5 }, - {"ad5629-1", ID_AD5629_1}, - {"ad5629-2", ID_AD5629_2}, - {"ad5629-3", ID_AD5629_2}, /* similar enough to ad5629-2 */ - {"ad5645r-1v25", ID_AD5645R_1V25 }, - {"ad5645r-2v5", ID_AD5645R_2V5 }, - {"ad5665", ID_AD5665 }, - {"ad5665r-1v25", ID_AD5665R_1V25 }, - {"ad5665r-2v5", ID_AD5665R_2V5 }, - {"ad5667", ID_AD5667 }, - {"ad5667r-1v25", ID_AD5667R_1V25 }, - {"ad5667r-2v5", ID_AD5667R_2V5 }, - {"ad5669-1", ID_AD5669_1}, - {"ad5669-2", ID_AD5669_2}, - {"ad5669-3", ID_AD5669_2}, /* similar enough to ad5669-2 */ - {"ltc2606", ID_LTC2606}, - {"ltc2607", ID_LTC2607}, - {"ltc2609", ID_LTC2609}, - {"ltc2616", ID_LTC2616}, - {"ltc2617", ID_LTC2617}, - {"ltc2619", ID_LTC2619}, - {"ltc2626", ID_LTC2626}, - {"ltc2627", ID_LTC2627}, - {"ltc2629", ID_LTC2629}, - {"ltc2631-l12", ID_LTC2631_L12}, - {"ltc2631-h12", ID_LTC2631_H12}, - {"ltc2631-l10", ID_LTC2631_L10}, - {"ltc2631-h10", ID_LTC2631_H10}, - {"ltc2631-l8", ID_LTC2631_L8}, - {"ltc2631-h8", ID_LTC2631_H8}, - {"ltc2633-l12", ID_LTC2633_L12}, - {"ltc2633-h12", ID_LTC2633_H12}, - {"ltc2633-l10", ID_LTC2633_L10}, - {"ltc2633-h10", ID_LTC2633_H10}, - {"ltc2633-l8", ID_LTC2633_L8}, - {"ltc2633-h8", ID_LTC2633_H8}, - {"ltc2635-l12", ID_LTC2635_L12}, - {"ltc2635-h12", ID_LTC2635_H12}, - {"ltc2635-l10", ID_LTC2635_L10}, - {"ltc2635-h10", ID_LTC2635_H10}, - {"ltc2635-l8", ID_LTC2635_L8}, - {"ltc2635-h8", ID_LTC2635_H8}, + { .name = "ad5625", .driver_data = ID_AD5625 }, + { .name = "ad5625r-1v25", .driver_data = ID_AD5625R_1V25 }, + { .name = "ad5625r-2v5", .driver_data = ID_AD5625R_2V5 }, + { .name = "ad5627", .driver_data = ID_AD5627 }, + { .name = "ad5627r-1v25", .driver_data = ID_AD5627R_1V25 }, + { .name = "ad5627r-2v5", .driver_data = ID_AD5627R_2V5 }, + { .name = "ad5629-1", .driver_data = ID_AD5629_1 }, + { .name = "ad5629-2", .driver_data = ID_AD5629_2 }, + { .name = "ad5629-3", .driver_data = ID_AD5629_2 }, /* similar enough to ad5629-2 */ + { .name = "ad5645r-1v25", .driver_data = ID_AD5645R_1V25 }, + { .name = "ad5645r-2v5", .driver_data = ID_AD5645R_2V5 }, + { .name = "ad5665", .driver_data = ID_AD5665 }, + { .name = "ad5665r-1v25", .driver_data = ID_AD5665R_1V25 }, + { .name = "ad5665r-2v5", .driver_data = ID_AD5665R_2V5 }, + { .name = "ad5667", .driver_data = ID_AD5667 }, + { .name = "ad5667r-1v25", .driver_data = ID_AD5667R_1V25 }, + { .name = "ad5667r-2v5", .driver_data = ID_AD5667R_2V5 }, + { .name = "ad5669-1", .driver_data = ID_AD5669_1 }, + { .name = "ad5669-2", .driver_data = ID_AD5669_2 }, + { .name = "ad5669-3", .driver_data = ID_AD5669_2 }, /* similar enough to ad5669-2 */ + { .name = "ltc2606", .driver_data = ID_LTC2606 }, + { .name = "ltc2607", .driver_data = ID_LTC2607 }, + { .name = "ltc2609", .driver_data = ID_LTC2609 }, + { .name = "ltc2616", .driver_data = ID_LTC2616 }, + { .name = "ltc2617", .driver_data = ID_LTC2617 }, + { .name = "ltc2619", .driver_data = ID_LTC2619 }, + { .name = "ltc2626", .driver_data = ID_LTC2626 }, + { .name = "ltc2627", .driver_data = ID_LTC2627 }, + { .name = "ltc2629", .driver_data = ID_LTC2629 }, + { .name = "ltc2631-l12", .driver_data = ID_LTC2631_L12 }, + { .name = "ltc2631-h12", .driver_data = ID_LTC2631_H12 }, + { .name = "ltc2631-l10", .driver_data = ID_LTC2631_L10 }, + { .name = "ltc2631-h10", .driver_data = ID_LTC2631_H10 }, + { .name = "ltc2631-l8", .driver_data = ID_LTC2631_L8 }, + { .name = "ltc2631-h8", .driver_data = ID_LTC2631_H8 }, + { .name = "ltc2633-l12", .driver_data = ID_LTC2633_L12 }, + { .name = "ltc2633-h12", .driver_data = ID_LTC2633_H12 }, + { .name = "ltc2633-l10", .driver_data = ID_LTC2633_L10 }, + { .name = "ltc2633-h10", .driver_data = ID_LTC2633_H10 }, + { .name = "ltc2633-l8", .driver_data = ID_LTC2633_L8 }, + { .name = "ltc2633-h8", .driver_data = ID_LTC2633_H8 }, + { .name = "ltc2635-l12", .driver_data = ID_LTC2635_L12 }, + { .name = "ltc2635-h12", .driver_data = ID_LTC2635_H12 }, + { .name = "ltc2635-l10", .driver_data = ID_LTC2635_L10 }, + { .name = "ltc2635-h10", .driver_data = ID_LTC2635_H10 }, + { .name = "ltc2635-l8", .driver_data = ID_LTC2635_L8 }, + { .name = "ltc2635-h8", .driver_data = ID_LTC2635_H8 }, { } }; MODULE_DEVICE_TABLE(i2c, ad5064_i2c_ids); diff --git a/drivers/iio/dac/ad5360.c b/drivers/iio/dac/ad5360.c index bd32fa57b1d7..c1553f18a26a 100644 --- a/drivers/iio/dac/ad5360.c +++ b/drivers/iio/dac/ad5360.c @@ -206,14 +206,10 @@ static int ad5360_write_unlocked(struct iio_dev *indio_dev, static int ad5360_write(struct iio_dev *indio_dev, unsigned int cmd, unsigned int addr, unsigned int val, unsigned int shift) { - int ret; struct ad5360_state *st = iio_priv(indio_dev); - mutex_lock(&st->lock); - ret = ad5360_write_unlocked(indio_dev, cmd, addr, val, shift); - mutex_unlock(&st->lock); - - return ret; + guard(mutex)(&st->lock); + return ad5360_write_unlocked(indio_dev, cmd, addr, val, shift); } static int ad5360_read(struct iio_dev *indio_dev, unsigned int type, @@ -232,7 +228,7 @@ static int ad5360_read(struct iio_dev *indio_dev, unsigned int type, }, }; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); st->data[0].d32 = cpu_to_be32(AD5360_CMD(AD5360_CMD_SPECIAL_FUNCTION) | AD5360_ADDR(AD5360_REG_SF_READBACK) | @@ -240,12 +236,10 @@ static int ad5360_read(struct iio_dev *indio_dev, unsigned int type, AD5360_READBACK_ADDR(addr)); ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); - if (ret >= 0) - ret = be32_to_cpu(st->data[1].d32) & 0xffff; - - mutex_unlock(&st->lock); + if (ret < 0) + return ret; - return ret; + return be32_to_cpu(st->data[1].d32) & 0xffff; } static ssize_t ad5360_read_dac_powerdown(struct device *dev, @@ -262,19 +256,14 @@ static int ad5360_update_ctrl(struct iio_dev *indio_dev, unsigned int set, unsigned int clr) { struct ad5360_state *st = iio_priv(indio_dev); - int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); st->ctrl |= set; st->ctrl &= ~clr; - ret = ad5360_write_unlocked(indio_dev, AD5360_CMD_SPECIAL_FUNCTION, - AD5360_REG_SF_CTRL, st->ctrl, 0); - - mutex_unlock(&st->lock); - - return ret; + return ad5360_write_unlocked(indio_dev, AD5360_CMD_SPECIAL_FUNCTION, + AD5360_REG_SF_CTRL, st->ctrl, 0); } static ssize_t ad5360_write_dac_powerdown(struct device *dev, @@ -534,14 +523,14 @@ static void ad5360_remove(struct spi_device *spi) } static const struct spi_device_id ad5360_ids[] = { - { "ad5360", ID_AD5360 }, - { "ad5361", ID_AD5361 }, - { "ad5362", ID_AD5362 }, - { "ad5363", ID_AD5363 }, - { "ad5370", ID_AD5370 }, - { "ad5371", ID_AD5371 }, - { "ad5372", ID_AD5372 }, - { "ad5373", ID_AD5373 }, + { .name = "ad5360", .driver_data = ID_AD5360 }, + { .name = "ad5361", .driver_data = ID_AD5361 }, + { .name = "ad5362", .driver_data = ID_AD5362 }, + { .name = "ad5363", .driver_data = ID_AD5363 }, + { .name = "ad5370", .driver_data = ID_AD5370 }, + { .name = "ad5371", .driver_data = ID_AD5371 }, + { .name = "ad5372", .driver_data = ID_AD5372 }, + { .name = "ad5373", .driver_data = ID_AD5373 }, { } }; MODULE_DEVICE_TABLE(spi, ad5360_ids); diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index 8b813cee7625..4a5ad419f4ea 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c @@ -446,22 +446,22 @@ static int ad5380_spi_probe(struct spi_device *spi) } static const struct spi_device_id ad5380_spi_ids[] = { - { "ad5380-3", ID_AD5380_3 }, - { "ad5380-5", ID_AD5380_5 }, - { "ad5381-3", ID_AD5381_3 }, - { "ad5381-5", ID_AD5381_5 }, - { "ad5382-3", ID_AD5382_3 }, - { "ad5382-5", ID_AD5382_5 }, - { "ad5383-3", ID_AD5383_3 }, - { "ad5383-5", ID_AD5383_5 }, - { "ad5384-3", ID_AD5380_3 }, - { "ad5384-5", ID_AD5380_5 }, - { "ad5390-3", ID_AD5390_3 }, - { "ad5390-5", ID_AD5390_5 }, - { "ad5391-3", ID_AD5391_3 }, - { "ad5391-5", ID_AD5391_5 }, - { "ad5392-3", ID_AD5392_3 }, - { "ad5392-5", ID_AD5392_5 }, + { .name = "ad5380-3", .driver_data = ID_AD5380_3 }, + { .name = "ad5380-5", .driver_data = ID_AD5380_5 }, + { .name = "ad5381-3", .driver_data = ID_AD5381_3 }, + { .name = "ad5381-5", .driver_data = ID_AD5381_5 }, + { .name = "ad5382-3", .driver_data = ID_AD5382_3 }, + { .name = "ad5382-5", .driver_data = ID_AD5382_5 }, + { .name = "ad5383-3", .driver_data = ID_AD5383_3 }, + { .name = "ad5383-5", .driver_data = ID_AD5383_5 }, + { .name = "ad5384-3", .driver_data = ID_AD5380_3 }, + { .name = "ad5384-5", .driver_data = ID_AD5380_5 }, + { .name = "ad5390-3", .driver_data = ID_AD5390_3 }, + { .name = "ad5390-5", .driver_data = ID_AD5390_5 }, + { .name = "ad5391-3", .driver_data = ID_AD5391_3 }, + { .name = "ad5391-5", .driver_data = ID_AD5391_5 }, + { .name = "ad5392-3", .driver_data = ID_AD5392_3 }, + { .name = "ad5392-5", .driver_data = ID_AD5392_5 }, { } }; MODULE_DEVICE_TABLE(spi, ad5380_spi_ids); @@ -513,22 +513,22 @@ static int ad5380_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id ad5380_i2c_ids[] = { - { "ad5380-3", ID_AD5380_3 }, - { "ad5380-5", ID_AD5380_5 }, - { "ad5381-3", ID_AD5381_3 }, - { "ad5381-5", ID_AD5381_5 }, - { "ad5382-3", ID_AD5382_3 }, - { "ad5382-5", ID_AD5382_5 }, - { "ad5383-3", ID_AD5383_3 }, - { "ad5383-5", ID_AD5383_5 }, - { "ad5384-3", ID_AD5380_3 }, - { "ad5384-5", ID_AD5380_5 }, - { "ad5390-3", ID_AD5390_3 }, - { "ad5390-5", ID_AD5390_5 }, - { "ad5391-3", ID_AD5391_3 }, - { "ad5391-5", ID_AD5391_5 }, - { "ad5392-3", ID_AD5392_3 }, - { "ad5392-5", ID_AD5392_5 }, + { .name = "ad5380-3", .driver_data = ID_AD5380_3 }, + { .name = "ad5380-5", .driver_data = ID_AD5380_5 }, + { .name = "ad5381-3", .driver_data = ID_AD5381_3 }, + { .name = "ad5381-5", .driver_data = ID_AD5381_5 }, + { .name = "ad5382-3", .driver_data = ID_AD5382_3 }, + { .name = "ad5382-5", .driver_data = ID_AD5382_5 }, + { .name = "ad5383-3", .driver_data = ID_AD5383_3 }, + { .name = "ad5383-5", .driver_data = ID_AD5383_5 }, + { .name = "ad5384-3", .driver_data = ID_AD5380_3 }, + { .name = "ad5384-5", .driver_data = ID_AD5380_5 }, + { .name = "ad5390-3", .driver_data = ID_AD5390_3 }, + { .name = "ad5390-5", .driver_data = ID_AD5390_5 }, + { .name = "ad5391-3", .driver_data = ID_AD5391_3 }, + { .name = "ad5391-5", .driver_data = ID_AD5391_5 }, + { .name = "ad5392-3", .driver_data = ID_AD5392_3 }, + { .name = "ad5392-5", .driver_data = ID_AD5392_5 }, { } }; MODULE_DEVICE_TABLE(i2c, ad5380_i2c_ids); diff --git a/drivers/iio/dac/ad5446-i2c.c b/drivers/iio/dac/ad5446-i2c.c index 40fe7e17fce4..286695e240c3 100644 --- a/drivers/iio/dac/ad5446-i2c.c +++ b/drivers/iio/dac/ad5446-i2c.c @@ -6,7 +6,6 @@ */ #include <linux/err.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <asm/byteorder.h> @@ -65,12 +64,12 @@ static const struct ad5446_chip_info ad5622_chip_info = { }; static const struct i2c_device_id ad5446_i2c_ids[] = { - {"ad5301", (kernel_ulong_t)&ad5602_chip_info}, - {"ad5311", (kernel_ulong_t)&ad5612_chip_info}, - {"ad5321", (kernel_ulong_t)&ad5622_chip_info}, - {"ad5602", (kernel_ulong_t)&ad5602_chip_info}, - {"ad5612", (kernel_ulong_t)&ad5612_chip_info}, - {"ad5622", (kernel_ulong_t)&ad5622_chip_info}, + { .name = "ad5301", .driver_data = (kernel_ulong_t)&ad5602_chip_info }, + { .name = "ad5311", .driver_data = (kernel_ulong_t)&ad5612_chip_info }, + { .name = "ad5321", .driver_data = (kernel_ulong_t)&ad5622_chip_info }, + { .name = "ad5602", .driver_data = (kernel_ulong_t)&ad5602_chip_info }, + { .name = "ad5612", .driver_data = (kernel_ulong_t)&ad5612_chip_info }, + { .name = "ad5622", .driver_data = (kernel_ulong_t)&ad5622_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, ad5446_i2c_ids); @@ -84,7 +83,7 @@ static const struct of_device_id ad5446_i2c_of_ids[] = { { .compatible = "adi,ad5622", .data = &ad5622_chip_info }, { } }; -MODULE_DEVICE_TABLE(OF, ad5446_i2c_of_ids); +MODULE_DEVICE_TABLE(of, ad5446_i2c_of_ids); static struct i2c_driver ad5446_i2c_driver = { .driver = { diff --git a/drivers/iio/dac/ad5446-spi.c b/drivers/iio/dac/ad5446-spi.c index e29d77f21482..85bb8829046a 100644 --- a/drivers/iio/dac/ad5446-spi.c +++ b/drivers/iio/dac/ad5446-spi.c @@ -6,7 +6,6 @@ */ #include <linux/err.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/spi/spi.h> #include <linux/unaligned.h> @@ -164,38 +163,38 @@ static const struct ad5446_chip_info ad5662_chip_info = { }; static const struct spi_device_id ad5446_spi_ids[] = { - {"ad5300", (kernel_ulong_t)&ad5300_chip_info}, - {"ad5310", (kernel_ulong_t)&ad5310_chip_info}, - {"ad5320", (kernel_ulong_t)&ad5320_chip_info}, - {"ad5444", (kernel_ulong_t)&ad5444_chip_info}, - {"ad5446", (kernel_ulong_t)&ad5446_chip_info}, - {"ad5450", (kernel_ulong_t)&ad5450_chip_info}, - {"ad5451", (kernel_ulong_t)&ad5451_chip_info}, - {"ad5452", (kernel_ulong_t)&ad5444_chip_info}, /* ad5452 is compatible to the ad5444 */ - {"ad5453", (kernel_ulong_t)&ad5446_chip_info}, /* ad5453 is compatible to the ad5446 */ - {"ad5512a", (kernel_ulong_t)&ad5512a_chip_info}, - {"ad5541a", (kernel_ulong_t)&ad5541a_chip_info}, - {"ad5542", (kernel_ulong_t)&ad5541a_chip_info}, /* ad5541a and ad5542 are compatible */ - {"ad5542a", (kernel_ulong_t)&ad5541a_chip_info}, /* ad5541a and ad5542a are compatible */ - {"ad5543", (kernel_ulong_t)&ad5541a_chip_info}, /* ad5541a and ad5543 are compatible */ - {"ad5553", (kernel_ulong_t)&ad5553_chip_info}, - {"ad5600", (kernel_ulong_t)&ad5541a_chip_info}, /* ad5541a and ad5600 are compatible */ - {"ad5601", (kernel_ulong_t)&ad5601_chip_info}, - {"ad5611", (kernel_ulong_t)&ad5611_chip_info}, - {"ad5621", (kernel_ulong_t)&ad5621_chip_info}, - {"ad5641", (kernel_ulong_t)&ad5641_chip_info}, - {"ad5620-2500", (kernel_ulong_t)&ad5620_2500_chip_info}, /* AD5620/40/60: */ + { .name = "ad5300", .driver_data = (kernel_ulong_t)&ad5300_chip_info }, + { .name = "ad5310", .driver_data = (kernel_ulong_t)&ad5310_chip_info }, + { .name = "ad5320", .driver_data = (kernel_ulong_t)&ad5320_chip_info }, + { .name = "ad5444", .driver_data = (kernel_ulong_t)&ad5444_chip_info }, + { .name = "ad5446", .driver_data = (kernel_ulong_t)&ad5446_chip_info }, + { .name = "ad5450", .driver_data = (kernel_ulong_t)&ad5450_chip_info }, + { .name = "ad5451", .driver_data = (kernel_ulong_t)&ad5451_chip_info }, + { .name = "ad5452", .driver_data = (kernel_ulong_t)&ad5444_chip_info }, /* ad5452 is compatible to the ad5444 */ + { .name = "ad5453", .driver_data = (kernel_ulong_t)&ad5446_chip_info }, /* ad5453 is compatible to the ad5446 */ + { .name = "ad5512a", .driver_data = (kernel_ulong_t)&ad5512a_chip_info }, + { .name = "ad5541a", .driver_data = (kernel_ulong_t)&ad5541a_chip_info }, + { .name = "ad5542", .driver_data = (kernel_ulong_t)&ad5541a_chip_info }, /* ad5541a and ad5542 are compatible */ + { .name = "ad5542a", .driver_data = (kernel_ulong_t)&ad5541a_chip_info }, /* ad5541a and ad5542a are compatible */ + { .name = "ad5543", .driver_data = (kernel_ulong_t)&ad5541a_chip_info }, /* ad5541a and ad5543 are compatible */ + { .name = "ad5553", .driver_data = (kernel_ulong_t)&ad5553_chip_info }, + { .name = "ad5600", .driver_data = (kernel_ulong_t)&ad5541a_chip_info }, /* ad5541a and ad5600 are compatible */ + { .name = "ad5601", .driver_data = (kernel_ulong_t)&ad5601_chip_info }, + { .name = "ad5611", .driver_data = (kernel_ulong_t)&ad5611_chip_info }, + { .name = "ad5621", .driver_data = (kernel_ulong_t)&ad5621_chip_info }, + { .name = "ad5641", .driver_data = (kernel_ulong_t)&ad5641_chip_info }, + { .name = "ad5620-2500", .driver_data = (kernel_ulong_t)&ad5620_2500_chip_info }, /* AD5620/40/60: */ /* part numbers may look differently */ - {"ad5620-1250", (kernel_ulong_t)&ad5620_1250_chip_info}, - {"ad5640-2500", (kernel_ulong_t)&ad5640_2500_chip_info}, - {"ad5640-1250", (kernel_ulong_t)&ad5640_1250_chip_info}, - {"ad5660-2500", (kernel_ulong_t)&ad5660_2500_chip_info}, - {"ad5660-1250", (kernel_ulong_t)&ad5660_1250_chip_info}, - {"ad5662", (kernel_ulong_t)&ad5662_chip_info}, - {"dac081s101", (kernel_ulong_t)&ad5300_chip_info}, /* compatible Texas Instruments chips */ - {"dac101s101", (kernel_ulong_t)&ad5310_chip_info}, - {"dac121s101", (kernel_ulong_t)&ad5320_chip_info}, - {"dac7512", (kernel_ulong_t)&ad5320_chip_info}, + { .name = "ad5620-1250", .driver_data = (kernel_ulong_t)&ad5620_1250_chip_info }, + { .name = "ad5640-2500", .driver_data = (kernel_ulong_t)&ad5640_2500_chip_info }, + { .name = "ad5640-1250", .driver_data = (kernel_ulong_t)&ad5640_1250_chip_info }, + { .name = "ad5660-2500", .driver_data = (kernel_ulong_t)&ad5660_2500_chip_info }, + { .name = "ad5660-1250", .driver_data = (kernel_ulong_t)&ad5660_1250_chip_info }, + { .name = "ad5662", .driver_data = (kernel_ulong_t)&ad5662_chip_info }, + { .name = "dac081s101", .driver_data = (kernel_ulong_t)&ad5300_chip_info }, /* compatible Texas Instruments chips */ + { .name = "dac101s101", .driver_data = (kernel_ulong_t)&ad5310_chip_info }, + { .name = "dac121s101", .driver_data = (kernel_ulong_t)&ad5320_chip_info }, + { .name = "dac7512", .driver_data = (kernel_ulong_t)&ad5320_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad5446_spi_ids); diff --git a/drivers/iio/dac/ad5449.c b/drivers/iio/dac/ad5449.c index d8c325260259..19e66bc69676 100644 --- a/drivers/iio/dac/ad5449.c +++ b/drivers/iio/dac/ad5449.c @@ -330,13 +330,13 @@ static void ad5449_spi_remove(struct spi_device *spi) } static const struct spi_device_id ad5449_spi_ids[] = { - { "ad5415", ID_AD5449 }, - { "ad5426", ID_AD5426 }, - { "ad5429", ID_AD5429 }, - { "ad5432", ID_AD5432 }, - { "ad5439", ID_AD5439 }, - { "ad5443", ID_AD5443 }, - { "ad5449", ID_AD5449 }, + { .name = "ad5415", .driver_data = ID_AD5449 }, + { .name = "ad5426", .driver_data = ID_AD5426 }, + { .name = "ad5429", .driver_data = ID_AD5429 }, + { .name = "ad5432", .driver_data = ID_AD5432 }, + { .name = "ad5439", .driver_data = ID_AD5439 }, + { .name = "ad5443", .driver_data = ID_AD5443 }, + { .name = "ad5449", .driver_data = ID_AD5449 }, { } }; MODULE_DEVICE_TABLE(spi, ad5449_spi_ids); diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index 355bcb6a8ba0..ad1a74678cf2 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c @@ -5,21 +5,21 @@ * Copyright 2011 Analog Devices Inc. */ -#include <linux/interrupt.h> -#include <linux/fs.h> +#include <linux/bitops.h> #include <linux/device.h> +#include <linux/fs.h> +#include <linux/interrupt.h> #include <linux/kernel.h> -#include <linux/spi/spi.h> +#include <linux/module.h> +#include <linux/regulator/consumer.h> #include <linux/slab.h> +#include <linux/spi/spi.h> #include <linux/sysfs.h> -#include <linux/regulator/consumer.h> -#include <linux/module.h> -#include <linux/bitops.h> +#include <linux/iio/dac/ad5504.h> +#include <linux/iio/events.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> -#include <linux/iio/events.h> -#include <linux/iio/dac/ad5504.h> #define AD5504_RES_MASK GENMASK(11, 0) #define AD5504_CMD_READ BIT(15) @@ -270,25 +270,26 @@ static const struct iio_chan_spec ad5504_channels[] = { static int ad5504_probe(struct spi_device *spi) { - const struct ad5504_platform_data *pdata = dev_get_platdata(&spi->dev); + struct device *dev = &spi->dev; + const struct ad5504_platform_data *pdata = dev_get_platdata(dev); struct iio_dev *indio_dev; struct ad5504_state *st; int ret; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; st = iio_priv(indio_dev); - ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vcc"); + ret = devm_regulator_get_enable_read_voltage(dev, "vcc"); if (ret < 0 && ret != -ENODEV) return ret; if (ret == -ENODEV) { if (pdata->vref_mv) st->vref_mv = pdata->vref_mv; else - dev_warn(&spi->dev, "reference voltage unspecified\n"); + dev_warn(dev, "reference voltage unspecified\n"); } else { st->vref_mv = ret / 1000; } @@ -304,22 +305,22 @@ static int ad5504_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; if (spi->irq) { - ret = devm_request_threaded_irq(&spi->dev, spi->irq, - NULL, - &ad5504_event_handler, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - spi_get_device_id(st->spi)->name, - indio_dev); + ret = devm_request_threaded_irq(dev, spi->irq, + NULL, + &ad5504_event_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + spi_get_device_id(st->spi)->name, + indio_dev); if (ret) return ret; } - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct spi_device_id ad5504_id[] = { - {"ad5504", ID_AD5504}, - {"ad5501", ID_AD5501}, + { .name = "ad5504", .driver_data = ID_AD5504 }, + { .name = "ad5501", .driver_data = ID_AD5501 }, { } }; MODULE_DEVICE_TABLE(spi, ad5504_id); diff --git a/drivers/iio/dac/ad5592r.c b/drivers/iio/dac/ad5592r.c index 92d1b629b85d..88197bc6a70b 100644 --- a/drivers/iio/dac/ad5592r.c +++ b/drivers/iio/dac/ad5592r.c @@ -10,7 +10,6 @@ #include <linux/bitops.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/spi/spi.h> #define AD5592R_GPIO_READBACK_EN BIT(10) diff --git a/drivers/iio/dac/ad5593r.c b/drivers/iio/dac/ad5593r.c index 9a8525c61173..3e4215f0ca7e 100644 --- a/drivers/iio/dac/ad5593r.c +++ b/drivers/iio/dac/ad5593r.c @@ -11,7 +11,6 @@ #include <linux/bitops.h> #include <linux/i2c.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/unaligned.h> diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c index 13aefe769bad..56aea4b1c167 100644 --- a/drivers/iio/dac/ad5624r_spi.c +++ b/drivers/iio/dac/ad5624r_spi.c @@ -260,12 +260,12 @@ static int ad5624r_probe(struct spi_device *spi) } static const struct spi_device_id ad5624r_id[] = { - {"ad5624r3", ID_AD5624R3}, - {"ad5644r3", ID_AD5644R3}, - {"ad5664r3", ID_AD5664R3}, - {"ad5624r5", ID_AD5624R5}, - {"ad5644r5", ID_AD5644R5}, - {"ad5664r5", ID_AD5664R5}, + { .name = "ad5624r3", .driver_data = ID_AD5624R3 }, + { .name = "ad5644r3", .driver_data = ID_AD5644R3 }, + { .name = "ad5664r3", .driver_data = ID_AD5664R3 }, + { .name = "ad5624r5", .driver_data = ID_AD5624R5 }, + { .name = "ad5644r5", .driver_data = ID_AD5644R5 }, + { .name = "ad5664r5", .driver_data = ID_AD5664R5 }, { } }; MODULE_DEVICE_TABLE(spi, ad5624r_id); diff --git a/drivers/iio/dac/ad5686-spi.c b/drivers/iio/dac/ad5686-spi.c index df8619e0c092..69cd9753f339 100644 --- a/drivers/iio/dac/ad5686-spi.c +++ b/drivers/iio/dac/ad5686-spi.c @@ -1,65 +1,109 @@ // SPDX-License-Identifier: GPL-2.0 /* - * AD5672R, AD5674R, AD5676, AD5676R, AD5679R, - * AD5681R, AD5682R, AD5683, AD5683R, AD5684, - * AD5684R, AD5685R, AD5686, AD5686R - * Digital to analog converters driver + * SPI driver for AD5686 and similar Digital to Analog Converters * * Copyright 2018 Analog Devices Inc. */ -#include "ad5686.h" - +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/errno.h> #include <linux/module.h> +#include <linux/overflow.h> #include <linux/spi/spi.h> +#include <asm/byteorder.h> + +#include "ad5686.h" + +/** + * struct ad5686_spi_data - SPI bus specific data + * @msg: SPI message used for transfers + * @size: number of transfers currently in the message + * @capacity: maximum number of transfers that can be added to the message + * @xfers: array of SPI transfers, allocated with the provided capacity + */ +struct ad5686_spi_data { + struct spi_message msg; + unsigned int size; + unsigned int capacity; + struct spi_transfer xfers[] __counted_by(capacity); +}; + static int ad5686_spi_write(struct ad5686_state *st, u8 cmd, u8 addr, u16 val) { - struct spi_device *spi = to_spi_device(st->dev); - u8 tx_len, *buf; - + struct ad5686_spi_data *bus_data = st->bus_data; + struct spi_transfer *xfer; + + if (bus_data->size >= bus_data->capacity) + return -E2BIG; + + /* + * This function stores spi transfers to a spi message to be sent over + * the bus when sync() op is called. If there are already transfers in + * the spi message, set the cs_change flag on the last transfer to + * ensure that the chip select is deasserted between transfers. If this + * is the first transfer, initialize the spi message. Later on, the + * current transfer is added to the message with spi_message_add_tail(). + */ + if (bus_data->size) + bus_data->xfers[bus_data->size - 1].cs_change = 1; + else + spi_message_init(&bus_data->msg); + + xfer = &bus_data->xfers[bus_data->size]; + auto buf = &st->data[bus_data->size]; switch (st->chip_info->regmap_type) { case AD5310_REGMAP: - st->data[0].d16 = cpu_to_be16(AD5310_CMD(cmd) | - val); - buf = &st->data[0].d8[0]; - tx_len = 2; + buf->d16 = cpu_to_be16(FIELD_PREP(AD5310_CMD_MSK, cmd) | + FIELD_PREP(AD5310_DATA_MSK, val)); + *xfer = (struct spi_transfer) { + .tx_buf = &buf->d16, + .len = sizeof(buf->d16), + }; break; case AD5683_REGMAP: - st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) | - AD5683_DATA(val)); - buf = &st->data[0].d8[1]; - tx_len = 3; + buf->d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, cmd) | + FIELD_PREP(AD5683_DATA_MSK, val)); + *xfer = (struct spi_transfer) { + .tx_buf = &buf->d8[1], + .len = sizeof(buf->d8) - 1, + }; break; case AD5686_REGMAP: - st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) | - AD5686_ADDR(addr) | - val); - buf = &st->data[0].d8[1]; - tx_len = 3; + buf->d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, cmd) | + FIELD_PREP(AD5686_ADDR_MSK, addr) | + FIELD_PREP(AD5686_DATA_MSK, val)); + *xfer = (struct spi_transfer) { + .tx_buf = &buf->d8[1], + .len = sizeof(buf->d8) - 1, + }; break; default: return -EINVAL; } - return spi_write(spi, buf, tx_len); + spi_message_add_tail(xfer, &bus_data->msg); + bus_data->size++; + + return 0; +} + +static int ad5686_spi_sync(struct ad5686_state *st) +{ + struct spi_device *spi = to_spi_device(st->dev); + struct ad5686_spi_data *bus_data = st->bus_data; + + bus_data->size = 0; /* always reset, even on sync failure */ + return spi_sync(spi, &bus_data->msg); } static int ad5686_spi_read(struct ad5686_state *st, u8 addr) { - struct spi_transfer t[] = { - { - .tx_buf = &st->data[0].d8[1], - .len = 3, - .cs_change = 1, - }, { - .tx_buf = &st->data[1].d8[1], - .rx_buf = &st->data[2].d8[1], - .len = 3, - }, - }; struct spi_device *spi = to_spi_device(st->dev); + struct ad5686_spi_data *bus_data = st->bus_data; + struct spi_transfer *xfer = &bus_data->xfers[0]; u8 cmd = 0; int ret; @@ -76,49 +120,120 @@ static int ad5686_spi_read(struct ad5686_state *st, u8 addr) return -EINVAL; } - st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) | - AD5686_ADDR(addr)); - st->data[1].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP)); + st->data[0].d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, cmd) | + FIELD_PREP(AD5686_ADDR_MSK, addr)); + st->data[1].d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, AD5686_CMD_NOOP)); - ret = spi_sync_transfer(spi, t, ARRAY_SIZE(t)); - if (ret < 0) + xfer[0] = (struct spi_transfer) { + .tx_buf = &st->data[0].d8[1], + .len = sizeof(st->data[0].d8) - 1, + .cs_change = 1, + }; + xfer[1] = (struct spi_transfer) { + .tx_buf = &st->data[1].d8[1], + .rx_buf = &st->data[2].d8[1], + .len = sizeof(st->data[1].d8) - 1, + }; + + spi_message_init_with_transfers(&bus_data->msg, xfer, 2); + + ret = spi_sync(spi, &bus_data->msg); + if (ret) return ret; return be32_to_cpu(st->data[2].d32); } +static const struct ad5686_bus_ops ad5686_spi_ops = { + .write = ad5686_spi_write, + .read = ad5686_spi_read, + .sync = ad5686_spi_sync, +}; + static int ad5686_spi_probe(struct spi_device *spi) { - const struct spi_device_id *id = spi_get_device_id(spi); + const struct ad5686_chip_info *info; + struct ad5686_spi_data *bus_data; + struct device *dev = &spi->dev; + unsigned int capacity; + + info = spi_get_device_match_data(spi); + if (!info) + return -ENODATA; + + /* read operation requires at least 2 transfers */ + capacity = max(info->num_channels, 2); + bus_data = devm_kzalloc(dev, struct_size(bus_data, xfers, capacity), + GFP_KERNEL); + if (!bus_data) + return -ENOMEM; + + bus_data->capacity = capacity; - return ad5686_probe(&spi->dev, id->driver_data, id->name, - ad5686_spi_write, ad5686_spi_read); + return ad5686_probe(dev, info, spi->modalias, &ad5686_spi_ops, bus_data); } static const struct spi_device_id ad5686_spi_id[] = { - {"ad5310r", ID_AD5310R}, - {"ad5672r", ID_AD5672R}, - {"ad5674r", ID_AD5674R}, - {"ad5676", ID_AD5676}, - {"ad5676r", ID_AD5676R}, - {"ad5679r", ID_AD5679R}, - {"ad5681r", ID_AD5681R}, - {"ad5682r", ID_AD5682R}, - {"ad5683", ID_AD5683}, - {"ad5683r", ID_AD5683R}, - {"ad5684", ID_AD5684}, - {"ad5684r", ID_AD5684R}, - {"ad5685", ID_AD5685R}, /* Does not exist */ - {"ad5685r", ID_AD5685R}, - {"ad5686", ID_AD5686}, - {"ad5686r", ID_AD5686R}, + { .name = "ad5310r", .driver_data = (kernel_ulong_t)&ad5310r_chip_info }, + { .name = "ad5313r", .driver_data = (kernel_ulong_t)&ad5338r_chip_info }, + { .name = "ad5317r", .driver_data = (kernel_ulong_t)&ad5317r_chip_info }, + { .name = "ad5672r", .driver_data = (kernel_ulong_t)&ad5672r_chip_info }, + { .name = "ad5674", .driver_data = (kernel_ulong_t)&ad5674_chip_info }, + { .name = "ad5674r", .driver_data = (kernel_ulong_t)&ad5674r_chip_info }, + { .name = "ad5676", .driver_data = (kernel_ulong_t)&ad5676_chip_info }, + { .name = "ad5676r", .driver_data = (kernel_ulong_t)&ad5676r_chip_info }, + { .name = "ad5679", .driver_data = (kernel_ulong_t)&ad5679_chip_info }, + { .name = "ad5679r", .driver_data = (kernel_ulong_t)&ad5679r_chip_info }, + { .name = "ad5681r", .driver_data = (kernel_ulong_t)&ad5681r_chip_info }, + { .name = "ad5682r", .driver_data = (kernel_ulong_t)&ad5682r_chip_info }, + { .name = "ad5683", .driver_data = (kernel_ulong_t)&ad5683_chip_info }, + { .name = "ad5683r", .driver_data = (kernel_ulong_t)&ad5683r_chip_info }, + { .name = "ad5684", .driver_data = (kernel_ulong_t)&ad5684_chip_info }, + { .name = "ad5684r", .driver_data = (kernel_ulong_t)&ad5684r_chip_info }, + { .name = "ad5685", .driver_data = (kernel_ulong_t)&ad5685r_chip_info }, /* nonexistent */ + { .name = "ad5685r", .driver_data = (kernel_ulong_t)&ad5685r_chip_info }, + { .name = "ad5686", .driver_data = (kernel_ulong_t)&ad5686_chip_info }, + { .name = "ad5686r", .driver_data = (kernel_ulong_t)&ad5686r_chip_info }, + { .name = "ad5687", .driver_data = (kernel_ulong_t)&ad5687_chip_info }, + { .name = "ad5687r", .driver_data = (kernel_ulong_t)&ad5687r_chip_info }, + { .name = "ad5689", .driver_data = (kernel_ulong_t)&ad5689_chip_info }, + { .name = "ad5689r", .driver_data = (kernel_ulong_t)&ad5689r_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad5686_spi_id); +static const struct of_device_id ad5686_of_match[] = { + { .compatible = "adi,ad5310r", .data = &ad5310r_chip_info }, + { .compatible = "adi,ad5313r", .data = &ad5338r_chip_info }, + { .compatible = "adi,ad5317r", .data = &ad5317r_chip_info }, + { .compatible = "adi,ad5672r", .data = &ad5672r_chip_info }, + { .compatible = "adi,ad5674", .data = &ad5674_chip_info }, + { .compatible = "adi,ad5674r", .data = &ad5674r_chip_info }, + { .compatible = "adi,ad5676", .data = &ad5676_chip_info }, + { .compatible = "adi,ad5676r", .data = &ad5676r_chip_info }, + { .compatible = "adi,ad5679", .data = &ad5679_chip_info }, + { .compatible = "adi,ad5679r", .data = &ad5679r_chip_info }, + { .compatible = "adi,ad5681r", .data = &ad5681r_chip_info }, + { .compatible = "adi,ad5682r", .data = &ad5682r_chip_info }, + { .compatible = "adi,ad5683", .data = &ad5683_chip_info }, + { .compatible = "adi,ad5683r", .data = &ad5683r_chip_info }, + { .compatible = "adi,ad5684", .data = &ad5684_chip_info }, + { .compatible = "adi,ad5684r", .data = &ad5684r_chip_info }, + { .compatible = "adi,ad5685r", .data = &ad5685r_chip_info }, + { .compatible = "adi,ad5686", .data = &ad5686_chip_info }, + { .compatible = "adi,ad5686r", .data = &ad5686r_chip_info }, + { .compatible = "adi,ad5687", .data = &ad5687_chip_info }, + { .compatible = "adi,ad5687r", .data = &ad5687r_chip_info }, + { .compatible = "adi,ad5689", .data = &ad5689_chip_info }, + { .compatible = "adi,ad5689r", .data = &ad5689r_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, ad5686_of_match); + static struct spi_driver ad5686_spi_driver = { .driver = { .name = "ad5686", + .of_match_table = ad5686_of_match, }, .probe = ad5686_spi_probe, .id_table = ad5686_spi_id, diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 4b18498aa074..0cc1c9c22a28 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -1,21 +1,34 @@ // SPDX-License-Identifier: GPL-2.0 /* - * AD5686R, AD5685R, AD5684R Digital to analog converters driver + * Core driver for AD5686 and similar Digital to Analog Converters * * Copyright 2011 Analog Devices Inc. */ -#include <linux/interrupt.h> -#include <linux/fs.h> -#include <linux/device.h> +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/cleanup.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> +#include <linux/errno.h> +#include <linux/export.h> +#include <linux/gpio/consumer.h> +#include <linux/kstrtox.h> +#include <linux/math64.h> #include <linux/module.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/sysfs.h> +#include <linux/property.h> #include <linux/regulator/consumer.h> +#include <linux/reset.h> +#include <linux/sysfs.h> +#include <linux/units.h> +#include <linux/wordpart.h> +#include <linux/iio/buffer.h> #include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> #include "ad5686.h" @@ -25,12 +38,59 @@ static const char * const ad5686_powerdown_modes[] = { "three_state" }; +static int ad5310_control_sync(struct ad5686_state *st) +{ + unsigned int pd_val = st->pwr_down_mask & st->pwr_down_mode; + + return ad5686_write(st, AD5686_CMD_CONTROL_REG, 0, + FIELD_PREP(AD5310_DATA_PD_MSK, pd_val & AD5686_PD_MSK) | + FIELD_PREP(AD5310_DATA_REF_MSK, st->use_internal_vref ? 0 : 1) | + FIELD_PREP(AD5310_DATA_GAIN_MSK, st->double_scale ? 1 : 0)); +} + +static int ad5683_control_sync(struct ad5686_state *st) +{ + unsigned int pd_val = st->pwr_down_mask & st->pwr_down_mode; + + return ad5686_write(st, AD5686_CMD_CONTROL_REG, 0, + FIELD_PREP(AD5683_DATA_PD_MSK, pd_val & AD5686_PD_MSK) | + FIELD_PREP(AD5683_DATA_REF_MSK, st->use_internal_vref ? 0 : 1) | + FIELD_PREP(AD5683_DATA_GAIN_MSK, st->double_scale ? 1 : 0)); +} + +static inline unsigned int ad5686_pd_mask_shift(const struct iio_chan_spec *chan) +{ + if (chan->channel == chan->address) + return chan->channel * 2; + + /* one-hot encoding is used in dual/quad channel devices */ + return __ffs(chan->address) * 2; +} + +static inline void ad5686_pd_field_set(const struct iio_chan_spec *chan, + unsigned int *pd, unsigned int val) +{ + unsigned int shift = ad5686_pd_mask_shift(chan); + + *pd = (*pd & ~(AD5686_PD_MSK << shift)) | ((val & AD5686_PD_MSK) << shift); +} + +static inline unsigned int ad5686_pd_field_get(const struct iio_chan_spec *chan, + unsigned int pd) +{ + unsigned int shift = ad5686_pd_mask_shift(chan); + + return (pd >> shift) & AD5686_PD_MSK; +} + static int ad5686_get_powerdown_mode(struct iio_dev *indio_dev, const struct iio_chan_spec *chan) { struct ad5686_state *st = iio_priv(indio_dev); - return ((st->pwr_down_mode >> (chan->channel * 2)) & 0x3) - 1; + guard(mutex)(&st->lock); + + return ad5686_pd_field_get(chan, st->pwr_down_mode) - 1; } static int ad5686_set_powerdown_mode(struct iio_dev *indio_dev, @@ -39,8 +99,8 @@ static int ad5686_set_powerdown_mode(struct iio_dev *indio_dev, { struct ad5686_state *st = iio_priv(indio_dev); - st->pwr_down_mode &= ~(0x3 << (chan->channel * 2)); - st->pwr_down_mode |= ((mode + 1) << (chan->channel * 2)); + guard(mutex)(&st->lock); + ad5686_pd_field_set(chan, &st->pwr_down_mode, mode + 1); return 0; } @@ -57,8 +117,10 @@ static ssize_t ad5686_read_dac_powerdown(struct iio_dev *indio_dev, { struct ad5686_state *st = iio_priv(indio_dev); - return sysfs_emit(buf, "%d\n", !!(st->pwr_down_mask & - (0x3 << (chan->channel * 2)))); + guard(mutex)(&st->lock); + + return sysfs_emit(buf, "%d\n", + !!ad5686_pd_field_get(chan, st->pwr_down_mask)); } static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev, @@ -70,50 +132,50 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev, bool readin; int ret; struct ad5686_state *st = iio_priv(indio_dev); - unsigned int val, ref_bit_msk; - u8 shift, address = 0; + unsigned int val; + u8 address; ret = kstrtobool(buf, &readin); if (ret) return ret; + guard(mutex)(&st->lock); + if (readin) - st->pwr_down_mask |= (0x3 << (chan->channel * 2)); + ad5686_pd_field_set(chan, &st->pwr_down_mask, AD5686_PD_MSK_PWR_DOWN); else - st->pwr_down_mask &= ~(0x3 << (chan->channel * 2)); + ad5686_pd_field_set(chan, &st->pwr_down_mask, AD5686_PD_MSK_PWR_UP); switch (st->chip_info->regmap_type) { case AD5310_REGMAP: - shift = 9; - ref_bit_msk = AD5310_REF_BIT_MSK; + ret = ad5310_control_sync(st); + if (ret) + return ret; break; case AD5683_REGMAP: - shift = 13; - ref_bit_msk = AD5683_REF_BIT_MSK; + ret = ad5683_control_sync(st); + if (ret) + return ret; break; case AD5686_REGMAP: - shift = 0; - ref_bit_msk = 0; /* AD5674R/AD5679R have 16 channels and 2 powerdown registers */ - if (chan->channel > 0x7) + val = st->pwr_down_mask & st->pwr_down_mode; + if (chan->channel > 0x7) { address = 0x8; - break; - case AD5693_REGMAP: - shift = 13; - ref_bit_msk = AD5693_REF_BIT_MSK; + val = upper_16_bits(val); + } else { + address = 0x0; + val = lower_16_bits(val); + } + ret = ad5686_write(st, AD5686_CMD_POWERDOWN_DAC, address, val); + if (ret) + return ret; break; default: return -EINVAL; } - val = ((st->pwr_down_mask & st->pwr_down_mode) << shift); - if (!st->use_internal_vref) - val |= ref_bit_msk; - - ret = st->write(st, AD5686_CMD_POWERDOWN_DAC, - address, val >> (address * 2)); - - return ret ? ret : len; + return len; } static int ad5686_read_raw(struct iio_dev *indio_dev, @@ -125,20 +187,25 @@ static int ad5686_read_raw(struct iio_dev *indio_dev, struct ad5686_state *st = iio_priv(indio_dev); int ret; + guard(mutex)(&st->lock); + switch (m) { case IIO_CHAN_INFO_RAW: - mutex_lock(&st->lock); - ret = st->read(st, chan->address); - mutex_unlock(&st->lock); + ret = ad5686_read(st, chan->address); if (ret < 0) return ret; *val = (ret >> chan->scan_type.shift) & GENMASK(chan->scan_type.realbits - 1, 0); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - *val = st->vref_mv; - *val2 = chan->scan_type.realbits; - return IIO_VAL_FRACTIONAL_LOG2; + if (st->double_scale) { + *val = st->scale_avail[2]; + *val2 = st->scale_avail[3]; + } else { + *val = st->scale_avail[0]; + *val2 = st->scale_avail[1]; + } + return IIO_VAL_INT_PLUS_NANO; } return -EINVAL; } @@ -150,30 +217,104 @@ static int ad5686_write_raw(struct iio_dev *indio_dev, long mask) { struct ad5686_state *st = iio_priv(indio_dev); + bool double_scale; int ret; + guard(mutex)(&st->lock); + switch (mask) { case IIO_CHAN_INFO_RAW: - if (val > (1 << chan->scan_type.realbits) || val < 0) + if (val >= (1 << chan->scan_type.realbits) || val < 0) return -EINVAL; - mutex_lock(&st->lock); - ret = st->write(st, - AD5686_CMD_WRITE_INPUT_N_UPDATE_N, - chan->address, - val << chan->scan_type.shift); - mutex_unlock(&st->lock); - break; + return ad5686_write(st, AD5686_CMD_WRITE_INPUT_N_UPDATE_N, + chan->address, val << chan->scan_type.shift); + case IIO_CHAN_INFO_SCALE: + if (val == st->scale_avail[0] && val2 == st->scale_avail[1]) + double_scale = false; + else if (val == st->scale_avail[2] && val2 == st->scale_avail[3]) + double_scale = true; + else + return -EINVAL; + + if (st->double_scale == double_scale) + return 0; /* no change */ + + if (st->chip_info->regmap_type == AD5686_REGMAP && !st->gain_gpio) + return -EINVAL; /* GAIN pin is board-strapped */ + + st->double_scale = double_scale; + switch (st->chip_info->regmap_type) { + case AD5310_REGMAP: + ret = ad5310_control_sync(st); + break; + case AD5683_REGMAP: + ret = ad5683_control_sync(st); + break; + case AD5686_REGMAP: + ret = gpiod_set_value_cansleep(st->gain_gpio, + st->double_scale ? 1 : 0); + break; + default: + ret = -EINVAL; + } + if (ret) + st->double_scale = !double_scale; /* revert on failure */ + return ret; + default: + return -EINVAL; + } +} + +static int ad5686_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_RAW: + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; default: - ret = -EINVAL; + return -EINVAL; } +} + +static int ad5686_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct ad5686_state *st = iio_priv(indio_dev); - return ret; + switch (mask) { + case IIO_CHAN_INFO_SCALE: + *type = IIO_VAL_INT_PLUS_NANO; + + if (st->chip_info->regmap_type == AD5686_REGMAP && !st->gain_gpio) { + /* + * GAIN pin is board-strapped, so only the current + * scale is available. + */ + *vals = st->double_scale ? &st->scale_avail[2] : + &st->scale_avail[0]; + *length = 2; + return IIO_AVAIL_LIST; + } + + *vals = st->scale_avail; + *length = ARRAY_SIZE(st->scale_avail); + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } } static const struct iio_info ad5686_info = { .read_raw = ad5686_read_raw, .write_raw = ad5686_write_raw, + .write_raw_get_fmt = ad5686_write_raw_get_fmt, + .read_avail = ad5686_read_avail, }; static const struct iio_chan_spec_ext_info ad5686_ext_info[] = { @@ -195,7 +336,9 @@ static const struct iio_chan_spec_ext_info ad5686_ext_info[] = { .channel = chan, \ .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),\ .address = addr, \ + .scan_index = chan, \ .scan_type = { \ .sign = 'u', \ .realbits = (bits), \ @@ -205,7 +348,7 @@ static const struct iio_chan_spec_ext_info ad5686_ext_info[] = { .ext_info = ad5686_ext_info, \ } -#define DECLARE_AD5693_CHANNELS(name, bits, _shift) \ +#define DECLARE_AD5683_CHANNELS(name, bits, _shift) \ static const struct iio_chan_spec name[] = { \ AD5868_CHANNEL(0, 0, bits, _shift), \ } @@ -256,213 +399,295 @@ static const struct iio_chan_spec name[] = { \ AD5868_CHANNEL(15, 15, bits, _shift), \ } -DECLARE_AD5693_CHANNELS(ad5310r_channels, 10, 2); -DECLARE_AD5693_CHANNELS(ad5311r_channels, 10, 6); +/* single-channel */ +DECLARE_AD5683_CHANNELS(ad5310r_channels, 10, 2); +DECLARE_AD5683_CHANNELS(ad5311r_channels, 10, 6); +DECLARE_AD5683_CHANNELS(ad5681r_channels, 12, 4); +DECLARE_AD5683_CHANNELS(ad5682r_channels, 14, 2); +DECLARE_AD5683_CHANNELS(ad5683r_channels, 16, 0); + +/* dual-channel */ DECLARE_AD5338_CHANNELS(ad5337r_channels, 8, 8); DECLARE_AD5338_CHANNELS(ad5338r_channels, 10, 6); -DECLARE_AD5676_CHANNELS(ad5672_channels, 12, 4); +DECLARE_AD5338_CHANNELS(ad5687r_channels, 12, 4); +DECLARE_AD5338_CHANNELS(ad5689r_channels, 16, 0); + +/* quad-channel */ +DECLARE_AD5686_CHANNELS(ad5317r_channels, 10, 6); +DECLARE_AD5686_CHANNELS(ad5684r_channels, 12, 4); +DECLARE_AD5686_CHANNELS(ad5685r_channels, 14, 2); +DECLARE_AD5686_CHANNELS(ad5686r_channels, 16, 0); + +/* 8-channel */ +DECLARE_AD5676_CHANNELS(ad5672r_channels, 12, 4); +DECLARE_AD5676_CHANNELS(ad5676r_channels, 16, 0); + +/* 16-channel */ DECLARE_AD5679_CHANNELS(ad5674r_channels, 12, 4); -DECLARE_AD5676_CHANNELS(ad5676_channels, 16, 0); DECLARE_AD5679_CHANNELS(ad5679r_channels, 16, 0); -DECLARE_AD5686_CHANNELS(ad5684_channels, 12, 4); -DECLARE_AD5686_CHANNELS(ad5685r_channels, 14, 2); -DECLARE_AD5686_CHANNELS(ad5686_channels, 16, 0); -DECLARE_AD5693_CHANNELS(ad5693_channels, 16, 0); -DECLARE_AD5693_CHANNELS(ad5692r_channels, 14, 2); -DECLARE_AD5693_CHANNELS(ad5691r_channels, 12, 4); - -static const struct ad5686_chip_info ad5686_chip_info_tbl[] = { - [ID_AD5310R] = { - .channels = ad5310r_channels, - .int_vref_mv = 2500, - .num_channels = 1, - .regmap_type = AD5310_REGMAP, - }, - [ID_AD5311R] = { - .channels = ad5311r_channels, - .int_vref_mv = 2500, - .num_channels = 1, - .regmap_type = AD5693_REGMAP, - }, - [ID_AD5337R] = { - .channels = ad5337r_channels, - .int_vref_mv = 2500, - .num_channels = 2, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5338R] = { - .channels = ad5338r_channels, - .int_vref_mv = 2500, - .num_channels = 2, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5671R] = { - .channels = ad5672_channels, - .int_vref_mv = 2500, - .num_channels = 8, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5672R] = { - .channels = ad5672_channels, - .int_vref_mv = 2500, - .num_channels = 8, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5673R] = { - .channels = ad5674r_channels, - .int_vref_mv = 2500, - .num_channels = 16, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5674R] = { - .channels = ad5674r_channels, - .int_vref_mv = 2500, - .num_channels = 16, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5675R] = { - .channels = ad5676_channels, - .int_vref_mv = 2500, - .num_channels = 8, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5676] = { - .channels = ad5676_channels, - .num_channels = 8, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5676R] = { - .channels = ad5676_channels, - .int_vref_mv = 2500, - .num_channels = 8, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5677R] = { - .channels = ad5679r_channels, - .int_vref_mv = 2500, - .num_channels = 16, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5679R] = { - .channels = ad5679r_channels, - .int_vref_mv = 2500, - .num_channels = 16, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5681R] = { - .channels = ad5691r_channels, - .int_vref_mv = 2500, - .num_channels = 1, - .regmap_type = AD5683_REGMAP, - }, - [ID_AD5682R] = { - .channels = ad5692r_channels, - .int_vref_mv = 2500, - .num_channels = 1, - .regmap_type = AD5683_REGMAP, - }, - [ID_AD5683] = { - .channels = ad5693_channels, - .num_channels = 1, - .regmap_type = AD5683_REGMAP, - }, - [ID_AD5683R] = { - .channels = ad5693_channels, - .int_vref_mv = 2500, - .num_channels = 1, - .regmap_type = AD5683_REGMAP, - }, - [ID_AD5684] = { - .channels = ad5684_channels, - .num_channels = 4, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5684R] = { - .channels = ad5684_channels, - .int_vref_mv = 2500, - .num_channels = 4, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5685R] = { - .channels = ad5685r_channels, - .int_vref_mv = 2500, - .num_channels = 4, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5686] = { - .channels = ad5686_channels, - .num_channels = 4, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5686R] = { - .channels = ad5686_channels, - .int_vref_mv = 2500, - .num_channels = 4, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5691R] = { - .channels = ad5691r_channels, - .int_vref_mv = 2500, - .num_channels = 1, - .regmap_type = AD5693_REGMAP, - }, - [ID_AD5692R] = { - .channels = ad5692r_channels, - .int_vref_mv = 2500, - .num_channels = 1, - .regmap_type = AD5693_REGMAP, - }, - [ID_AD5693] = { - .channels = ad5693_channels, - .num_channels = 1, - .regmap_type = AD5693_REGMAP, - }, - [ID_AD5693R] = { - .channels = ad5693_channels, - .int_vref_mv = 2500, - .num_channels = 1, - .regmap_type = AD5693_REGMAP, - }, - [ID_AD5694] = { - .channels = ad5684_channels, - .num_channels = 4, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5694R] = { - .channels = ad5684_channels, - .int_vref_mv = 2500, - .num_channels = 4, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5695R] = { - .channels = ad5685r_channels, - .int_vref_mv = 2500, - .num_channels = 4, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5696] = { - .channels = ad5686_channels, - .num_channels = 4, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5696R] = { - .channels = ad5686_channels, - .int_vref_mv = 2500, - .num_channels = 4, - .regmap_type = AD5686_REGMAP, - }, + +const struct ad5686_chip_info ad5310r_chip_info = { + .channels = ad5310r_channels, + .int_vref_mv = 2500, + .num_channels = 1, + .regmap_type = AD5310_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5310r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5311r_chip_info = { + .channels = ad5311r_channels, + .int_vref_mv = 2500, + .num_channels = 1, + .regmap_type = AD5683_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5311r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5681r_chip_info = { + .channels = ad5681r_channels, + .int_vref_mv = 2500, + .num_channels = 1, + .regmap_type = AD5683_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5681r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5682r_chip_info = { + .channels = ad5682r_channels, + .int_vref_mv = 2500, + .num_channels = 1, + .regmap_type = AD5683_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5682r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5683_chip_info = { + .channels = ad5683r_channels, + .num_channels = 1, + .regmap_type = AD5683_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5683_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5683r_chip_info = { + .channels = ad5683r_channels, + .int_vref_mv = 2500, + .num_channels = 1, + .regmap_type = AD5683_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5683r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5337r_chip_info = { + .channels = ad5337r_channels, + .int_vref_mv = 2500, + .num_channels = 2, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5337r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5338r_chip_info = { + .channels = ad5338r_channels, + .int_vref_mv = 2500, + .num_channels = 2, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5338r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5687_chip_info = { + .channels = ad5687r_channels, + .num_channels = 2, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5687_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5687r_chip_info = { + .channels = ad5687r_channels, + .int_vref_mv = 2500, + .num_channels = 2, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5687r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5689_chip_info = { + .channels = ad5689r_channels, + .num_channels = 2, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5689_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5689r_chip_info = { + .channels = ad5689r_channels, + .int_vref_mv = 2500, + .num_channels = 2, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5689r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5317r_chip_info = { + .channels = ad5317r_channels, + .int_vref_mv = 2500, + .num_channels = 4, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5317r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5684_chip_info = { + .channels = ad5684r_channels, + .num_channels = 4, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5684_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5684r_chip_info = { + .channels = ad5684r_channels, + .int_vref_mv = 2500, + .num_channels = 4, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5684r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5685r_chip_info = { + .channels = ad5685r_channels, + .int_vref_mv = 2500, + .num_channels = 4, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5685r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5686_chip_info = { + .channels = ad5686r_channels, + .num_channels = 4, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5686_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5686r_chip_info = { + .channels = ad5686r_channels, + .int_vref_mv = 2500, + .num_channels = 4, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5686r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5672r_chip_info = { + .channels = ad5672r_channels, + .int_vref_mv = 2500, + .num_channels = 8, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5672r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5676_chip_info = { + .channels = ad5676r_channels, + .num_channels = 8, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5676_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5676r_chip_info = { + .channels = ad5676r_channels, + .int_vref_mv = 2500, + .num_channels = 8, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5676r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5674_chip_info = { + .channels = ad5674r_channels, + .num_channels = 16, + .regmap_type = AD5686_REGMAP, }; +EXPORT_SYMBOL_NS_GPL(ad5674_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5674r_chip_info = { + .channels = ad5674r_channels, + .int_vref_mv = 2500, + .num_channels = 16, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5674r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5679_chip_info = { + .channels = ad5679r_channels, + .num_channels = 16, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5679_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5679r_chip_info = { + .channels = ad5679r_channels, + .int_vref_mv = 2500, + .num_channels = 16, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5679r_chip_info, "IIO_AD5686"); + +static void ad5686_init_scale_avail(struct ad5686_state *st) +{ + int realbits = st->chip_info->channels[0].scan_type.realbits; + s64 tmp = 2ULL * st->vref_mv * NANO >> realbits; + + st->scale_avail[2] = div_s64_rem(tmp, NANO, &st->scale_avail[3]); + st->scale_avail[0] = div_s64_rem(tmp >> 1, NANO, &st->scale_avail[1]); +} + +static void do_ad5686_trigger_handler(struct iio_dev *indio_dev) +{ + struct ad5686_state *st = iio_priv(indio_dev); + u16 val[AD5686_MAX_CHANNELS] = { }; + unsigned int scan_count, ch, i; + bool async_update; + u8 cmd; + + if (iio_pop_from_buffer(indio_dev->buffer, val)) + return; + + guard(mutex)(&st->lock); + + scan_count = bitmap_weight(indio_dev->active_scan_mask, + iio_get_masklength(indio_dev)); + async_update = st->ldac_gpio && scan_count > 1; + if (async_update) { + /* use LDAC to update all channels simultaneously */ + cmd = AD5686_CMD_WRITE_INPUT_N; + gpiod_set_value_cansleep(st->ldac_gpio, 0); + } else { + cmd = AD5686_CMD_WRITE_INPUT_N_UPDATE_N; + } + + i = 0; + iio_for_each_active_channel(indio_dev, ch) { + if (st->ops->write(st, cmd, indio_dev->channels[ch].address, val[i++])) + break; + } + + /* + * If sync() is available, it is called here regardless of write + * failure to allow bus implementation to reset. In that case, partial + * writes are unlikely as the write operations would just queue up + * the transfers. + */ + if (st->ops->sync) + st->ops->sync(st); + + if (async_update) + gpiod_set_value_cansleep(st->ldac_gpio, 1); +} + +static irqreturn_t ad5686_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + + do_ad5686_trigger_handler(indio_dev); + iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; +} int ad5686_probe(struct device *dev, - enum ad5686_supported_device_ids chip_type, - const char *name, ad5686_write_func write, - ad5686_read_func read) + const struct ad5686_chip_info *chip_info, + const char *name, const struct ad5686_bus_ops *ops, + void *bus_data) { + struct reset_control *rstc; struct ad5686_state *st; struct iio_dev *indio_dev; - unsigned int val, ref_bit_msk; - bool has_external_vref; - u8 cmd; int ret, i; indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); @@ -472,21 +697,69 @@ int ad5686_probe(struct device *dev, st = iio_priv(indio_dev); st->dev = dev; - st->write = write; - st->read = read; + st->ops = ops; + st->bus_data = bus_data; + st->chip_info = chip_info; + + rstc = devm_reset_control_get_optional_exclusive(dev, NULL); + if (IS_ERR(rstc)) + return dev_err_probe(dev, PTR_ERR(rstc), + "Failed to get reset control\n"); + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, "failed to enable vdd supply\n"); - st->chip_info = &ad5686_chip_info_tbl[chip_type]; + ret = devm_regulator_get_enable(dev, "vlogic"); + if (ret) + return dev_err_probe(dev, ret, "failed to enable vlogic supply\n"); - ret = devm_regulator_get_enable_read_voltage(dev, "vcc"); + ret = devm_regulator_get_enable_read_voltage(dev, "vref"); + if (ret == -ENODEV) /* vcc-supply is deprecated, but supported still */ + ret = devm_regulator_get_enable_read_voltage(dev, "vcc"); if (ret < 0 && ret != -ENODEV) - return ret; + return dev_err_probe(dev, ret, "failed to read vref voltage\n"); + + st->use_internal_vref = ret == -ENODEV; + st->vref_mv = st->use_internal_vref ? st->chip_info->int_vref_mv : ret / 1000; + if (!st->vref_mv) + return dev_err_probe(dev, -EINVAL, + "invalid or not provided vref voltage\n"); + + /* 4.5us power-up time: Datasheet Table 4: Timing Characteristics */ + fsleep(5); + + /* 1us >> 30ns reset pulse activation time: Datasheet Table 4 */ + reset_control_assert(rstc); + fsleep(1); + reset_control_deassert(rstc); - has_external_vref = ret != -ENODEV; - st->vref_mv = has_external_vref ? ret / 1000 : st->chip_info->int_vref_mv; + st->ldac_gpio = devm_gpiod_get_optional(dev, "ldac", GPIOD_OUT_HIGH); + if (IS_ERR(st->ldac_gpio)) + return dev_err_probe(dev, PTR_ERR(st->ldac_gpio), + "Failed to get LDAC GPIO\n"); + + st->double_scale = device_property_read_bool(dev, "adi,range-double"); + st->gain_gpio = devm_gpiod_get_optional(dev, "gain", + st->double_scale ? GPIOD_OUT_HIGH : + GPIOD_OUT_LOW); + if (IS_ERR(st->gain_gpio)) + return dev_err_probe(dev, PTR_ERR(st->gain_gpio), + "Failed to get GAIN GPIO\n"); + + ad5686_init_scale_avail(st); + + /* Initialize masks to all ones */ + st->pwr_down_mask = ~0; + st->pwr_down_mode = ~0; /* Set all the power down mode for all channels to 1K pulldown */ - for (i = 0; i < st->chip_info->num_channels; i++) - st->pwr_down_mode |= (0x01 << (i * 2)); + for (i = 0; i < st->chip_info->num_channels; i++) { + ad5686_pd_field_set(&st->chip_info->channels[i], + &st->pwr_down_mask, AD5686_PD_MSK_PWR_UP); + ad5686_pd_field_set(&st->chip_info->channels[i], + &st->pwr_down_mode, AD5686_PD_MODE_1K_TO_GND); + } indio_dev->name = name; indio_dev->info = &ad5686_info; @@ -494,35 +767,35 @@ int ad5686_probe(struct device *dev, indio_dev->channels = st->chip_info->channels; indio_dev->num_channels = st->chip_info->num_channels; - mutex_init(&st->lock); + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; switch (st->chip_info->regmap_type) { case AD5310_REGMAP: - cmd = AD5686_CMD_CONTROL_REG; - ref_bit_msk = AD5310_REF_BIT_MSK; - st->use_internal_vref = !has_external_vref; + ret = ad5310_control_sync(st); + if (ret) + return ret; break; case AD5683_REGMAP: - cmd = AD5686_CMD_CONTROL_REG; - ref_bit_msk = AD5683_REF_BIT_MSK; - st->use_internal_vref = !has_external_vref; + ret = ad5683_control_sync(st); + if (ret) + return ret; break; case AD5686_REGMAP: - cmd = AD5686_CMD_INTERNAL_REFER_SETUP; - ref_bit_msk = 0; - break; - case AD5693_REGMAP: - cmd = AD5686_CMD_CONTROL_REG; - ref_bit_msk = AD5693_REF_BIT_MSK; - st->use_internal_vref = !has_external_vref; + ret = ad5686_write(st, AD5686_CMD_INTERNAL_REFER_SETUP, 0, + st->use_internal_vref ? 0 : AD5686_DATA_REF_MSK); + if (ret) + return ret; break; default: return -EINVAL; } - val = (has_external_vref | ref_bit_msk); - - ret = st->write(st, cmd, 0, !!val); + ret = devm_iio_triggered_buffer_setup_ext(dev, indio_dev, NULL, + &ad5686_trigger_handler, + IIO_BUFFER_DIRECTION_OUT, + NULL, NULL); if (ret) return ret; diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h index e7d36bae3e59..482bc70515f7 100644 --- a/drivers/iio/dac/ad5686.h +++ b/drivers/iio/dac/ad5686.h @@ -8,22 +8,24 @@ #ifndef __DRIVERS_IIO_DAC_AD5686_H__ #define __DRIVERS_IIO_DAC_AD5686_H__ -#include <linux/types.h> -#include <linux/cache.h> +#include <linux/bits.h> #include <linux/mutex.h> -#include <linux/kernel.h> +#include <linux/types.h> #include <linux/iio/iio.h> -#define AD5310_CMD(x) ((x) << 12) +#define AD5310_CMD_MSK GENMASK(15, 12) +#define AD5310_DATA_MSK GENMASK(11, 0) -#define AD5683_DATA(x) ((x) << 4) +#define AD5683_DATA_MSK GENMASK(19, 4) -#define AD5686_ADDR(x) ((x) << 16) -#define AD5686_CMD(x) ((x) << 20) +#define AD5686_CMD_MSK GENMASK(23, 20) +#define AD5686_ADDR_MSK GENMASK(19, 16) +#define AD5686_DATA_MSK GENMASK(15, 0) #define AD5686_ADDR_DAC(chan) (0x1 << (chan)) #define AD5686_ADDR_ALL_DAC 0xF +#define AD5686_MAX_CHANNELS 16 #define AD5686_CMD_NOOP 0x0 #define AD5686_CMD_WRITE_INPUT_N 0x1 @@ -36,77 +38,56 @@ #define AD5686_CMD_DAISY_CHAIN_ENABLE 0x8 #define AD5686_CMD_READBACK_ENABLE 0x9 -#define AD5686_LDAC_PWRDN_NONE 0x0 -#define AD5686_LDAC_PWRDN_1K 0x1 -#define AD5686_LDAC_PWRDN_100K 0x2 -#define AD5686_LDAC_PWRDN_3STATE 0x3 - #define AD5686_CMD_CONTROL_REG 0x4 #define AD5686_CMD_READBACK_ENABLE_V2 0x5 -#define AD5310_REF_BIT_MSK BIT(8) -#define AD5683_REF_BIT_MSK BIT(12) -#define AD5693_REF_BIT_MSK BIT(12) +#define AD5310_DATA_GAIN_MSK BIT(7) +#define AD5310_DATA_REF_MSK BIT(8) +#define AD5310_DATA_PD_MSK GENMASK(10, 9) -/** - * ad5686_supported_device_ids: - */ -enum ad5686_supported_device_ids { - ID_AD5310R, - ID_AD5311R, - ID_AD5337R, - ID_AD5338R, - ID_AD5671R, - ID_AD5672R, - ID_AD5673R, - ID_AD5674R, - ID_AD5675R, - ID_AD5676, - ID_AD5676R, - ID_AD5677R, - ID_AD5679R, - ID_AD5681R, - ID_AD5682R, - ID_AD5683, - ID_AD5683R, - ID_AD5684, - ID_AD5684R, - ID_AD5685R, - ID_AD5686, - ID_AD5686R, - ID_AD5691R, - ID_AD5692R, - ID_AD5693, - ID_AD5693R, - ID_AD5694, - ID_AD5694R, - ID_AD5695R, - ID_AD5696, - ID_AD5696R, -}; +#define AD5683_DATA_GAIN_MSK BIT(11) /* DB15 */ +#define AD5683_DATA_REF_MSK BIT(12) /* DB16 */ +#define AD5683_DATA_PD_MSK GENMASK(14, 13) /* DB18:DB17 */ + +#define AD5686_DATA_REF_MSK BIT(0) + +#define AD5686_PD_MSK GENMASK(1, 0) +#define AD5686_PD_MODE_1K_TO_GND 0x1 +#define AD5686_PD_MODE_100K_TO_GND 0x2 +#define AD5686_PD_MODE_THREE_STATE 0x3 + +#define AD5686_PD_MSK_PWR_UP 0x0 +#define AD5686_PD_MSK_PWR_DOWN 0x3 enum ad5686_regmap_type { AD5310_REGMAP, AD5683_REGMAP, AD5686_REGMAP, - AD5693_REGMAP }; -struct ad5686_state; +struct gpio_desc; -typedef int (*ad5686_write_func)(struct ad5686_state *st, - u8 cmd, u8 addr, u16 val); +struct ad5686_state; -typedef int (*ad5686_read_func)(struct ad5686_state *st, u8 addr); +/** + * struct ad5686_bus_ops - bus specific read/write operations + * @read: read a register value at the given address + * @write: write a command, address and value to the device + * @sync: ensure the completion of the write operation (optional) + */ +struct ad5686_bus_ops { + int (*read)(struct ad5686_state *st, u8 addr); + int (*write)(struct ad5686_state *st, u8 cmd, u8 addr, u16 val); + int (*sync)(struct ad5686_state *st); +}; /** * struct ad5686_chip_info - chip specific information - * @int_vref_mv: AD5620/40/60: the internal reference voltage + * @int_vref_mv: the internal reference voltage * @num_channels: number of channels * @channel: channel specification * @regmap_type: register map layout variant */ - struct ad5686_chip_info { u16 int_vref_mv; unsigned int num_channels; @@ -114,28 +95,73 @@ struct ad5686_chip_info { enum ad5686_regmap_type regmap_type; }; +/* single-channel instances */ +extern const struct ad5686_chip_info ad5310r_chip_info; +extern const struct ad5686_chip_info ad5311r_chip_info; +extern const struct ad5686_chip_info ad5681r_chip_info; +extern const struct ad5686_chip_info ad5682r_chip_info; +extern const struct ad5686_chip_info ad5683_chip_info; +extern const struct ad5686_chip_info ad5683r_chip_info; + +/* dual-channel instances */ +extern const struct ad5686_chip_info ad5337r_chip_info; +extern const struct ad5686_chip_info ad5338r_chip_info; +extern const struct ad5686_chip_info ad5687_chip_info; +extern const struct ad5686_chip_info ad5687r_chip_info; +extern const struct ad5686_chip_info ad5689_chip_info; +extern const struct ad5686_chip_info ad5689r_chip_info; + +/* quad-channel instances */ +extern const struct ad5686_chip_info ad5317r_chip_info; +extern const struct ad5686_chip_info ad5684_chip_info; +extern const struct ad5686_chip_info ad5684r_chip_info; +extern const struct ad5686_chip_info ad5685r_chip_info; +extern const struct ad5686_chip_info ad5686_chip_info; +extern const struct ad5686_chip_info ad5686r_chip_info; + +/* 8-channel instances */ +extern const struct ad5686_chip_info ad5672r_chip_info; +extern const struct ad5686_chip_info ad5676_chip_info; +extern const struct ad5686_chip_info ad5676r_chip_info; + +/* 16-channel instances */ +extern const struct ad5686_chip_info ad5674_chip_info; +extern const struct ad5686_chip_info ad5674r_chip_info; +extern const struct ad5686_chip_info ad5679_chip_info; +extern const struct ad5686_chip_info ad5679r_chip_info; + /** * struct ad5686_state - driver instance specific data - * @spi: spi_device + * @dev: device instance * @chip_info: chip model specific constants, available modes etc - * @vref_mv: actual reference voltage used + * @ops: bus specific operations + * @ldac_gpio: LDAC pin GPIO descriptor + * @gain_gpio: GAIN pin GPIO descriptor * @pwr_down_mask: power down mask * @pwr_down_mode: current power down mode + * @scale_avail: pre-calculated available scale values + * @vref_mv: actual reference voltage used + * @double_scale: flag to indicate the gain multiplier is applied * @use_internal_vref: set to true if the internal reference voltage is used - * @lock lock to protect the data buffer during regmap ops - * @data: spi transfer buffers + * @lock: lock to protect access to state fields, which includes + * the data buffer during regmap ops + * @bus_data: bus specific data + * @data: transfer buffers */ - struct ad5686_state { struct device *dev; const struct ad5686_chip_info *chip_info; - unsigned short vref_mv; + const struct ad5686_bus_ops *ops; + struct gpio_desc *ldac_gpio; + struct gpio_desc *gain_gpio; unsigned int pwr_down_mask; unsigned int pwr_down_mode; - ad5686_write_func write; - ad5686_read_func read; + int scale_avail[4]; + unsigned short vref_mv; + bool double_scale; bool use_internal_vref; struct mutex lock; + void *bus_data; /* * DMA (thus cache coherency maintenance) may require the @@ -146,14 +172,29 @@ struct ad5686_state { __be32 d32; __be16 d16; u8 d8[4]; - } data[3] __aligned(IIO_DMA_MINALIGN); + } data[AD5686_MAX_CHANNELS] __aligned(IIO_DMA_MINALIGN); }; int ad5686_probe(struct device *dev, - enum ad5686_supported_device_ids chip_type, - const char *name, ad5686_write_func write, - ad5686_read_func read); + const struct ad5686_chip_info *chip_info, + const char *name, const struct ad5686_bus_ops *ops, + void *bus_data); + +static inline int ad5686_write(struct ad5686_state *st, u8 cmd, u8 addr, u16 val) +{ + int ret; + + ret = st->ops->write(st, cmd, addr, val); + if (ret) + return ret; + + return st->ops->sync ? st->ops->sync(st) : 0; +} +static inline int ad5686_read(struct ad5686_state *st, u8 addr) +{ + return st->ops->read(st, addr); +} #endif /* __DRIVERS_IIO_DAC_AD5686_H__ */ diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c index d3327bca0e07..f91abfcdbada 100644 --- a/drivers/iio/dac/ad5696-i2c.c +++ b/drivers/iio/dac/ad5696-i2c.c @@ -1,16 +1,18 @@ // SPDX-License-Identifier: GPL-2.0 /* - * AD5338R, AD5671R, AD5673R, AD5675R, AD5677R, AD5691R, AD5692R, AD5693, - * AD5693R, AD5694, AD5694R, AD5695R, AD5696, AD5696R - * Digital to analog converters driver + * I2C driver for AD5696 and similar Digital to Analog Converters * * Copyright 2018 Analog Devices Inc. */ -#include "ad5686.h" - -#include <linux/module.h> +#include <linux/bitfield.h> +#include <linux/errno.h> #include <linux/i2c.h> +#include <linux/module.h> + +#include <asm/byteorder.h> + +#include "ad5686.h" static int ad5686_i2c_read(struct ad5686_state *st, u8 addr) { @@ -31,9 +33,8 @@ static int ad5686_i2c_read(struct ad5686_state *st, u8 addr) }; int ret; - st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP) | - AD5686_ADDR(addr) | - 0x00); + st->data[0].d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, AD5686_CMD_NOOP) | + FIELD_PREP(AD5686_ADDR_MSK, addr)); ret = i2c_transfer(i2c->adapter, msg, 2); if (ret < 0) @@ -48,8 +49,9 @@ static int ad5686_i2c_write(struct ad5686_state *st, struct i2c_client *i2c = to_i2c_client(st->dev); int ret; - st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) | AD5686_ADDR(addr) - | val); + st->data[0].d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, cmd) | + FIELD_PREP(AD5686_ADDR_MSK, addr) | + FIELD_PREP(AD5686_DATA_MSK, val)); ret = i2c_master_send(i2c, &st->data[0].d8[1], 3); if (ret < 0) @@ -58,49 +60,66 @@ static int ad5686_i2c_write(struct ad5686_state *st, return (ret != 3) ? -EIO : 0; } +static const struct ad5686_bus_ops ad5686_i2c_ops = { + .write = ad5686_i2c_write, + .read = ad5686_i2c_read, +}; + static int ad5686_i2c_probe(struct i2c_client *i2c) { - const struct i2c_device_id *id = i2c_client_get_device_id(i2c); - return ad5686_probe(&i2c->dev, id->driver_data, id->name, - ad5686_i2c_write, ad5686_i2c_read); + const struct ad5686_chip_info *info; + + info = i2c_get_match_data(i2c); + if (!info) + return -ENODATA; + + return ad5686_probe(&i2c->dev, info, i2c->name, &ad5686_i2c_ops, NULL); } static const struct i2c_device_id ad5686_i2c_id[] = { - {"ad5311r", ID_AD5311R}, - {"ad5337r", ID_AD5337R}, - {"ad5338r", ID_AD5338R}, - {"ad5671r", ID_AD5671R}, - {"ad5673r", ID_AD5673R}, - {"ad5675r", ID_AD5675R}, - {"ad5677r", ID_AD5677R}, - {"ad5691r", ID_AD5691R}, - {"ad5692r", ID_AD5692R}, - {"ad5693", ID_AD5693}, - {"ad5693r", ID_AD5693R}, - {"ad5694", ID_AD5694}, - {"ad5694r", ID_AD5694R}, - {"ad5695r", ID_AD5695R}, - {"ad5696", ID_AD5696}, - {"ad5696r", ID_AD5696R}, + { .name = "ad5311r", .driver_data = (kernel_ulong_t)&ad5311r_chip_info }, + { .name = "ad5316r", .driver_data = (kernel_ulong_t)&ad5317r_chip_info }, + { .name = "ad5337r", .driver_data = (kernel_ulong_t)&ad5337r_chip_info }, + { .name = "ad5338r", .driver_data = (kernel_ulong_t)&ad5338r_chip_info }, + { .name = "ad5671r", .driver_data = (kernel_ulong_t)&ad5672r_chip_info }, + { .name = "ad5673r", .driver_data = (kernel_ulong_t)&ad5674r_chip_info }, + { .name = "ad5675", .driver_data = (kernel_ulong_t)&ad5676_chip_info }, + { .name = "ad5675r", .driver_data = (kernel_ulong_t)&ad5676r_chip_info }, + { .name = "ad5677r", .driver_data = (kernel_ulong_t)&ad5679r_chip_info }, + { .name = "ad5691r", .driver_data = (kernel_ulong_t)&ad5681r_chip_info }, + { .name = "ad5692r", .driver_data = (kernel_ulong_t)&ad5682r_chip_info }, + { .name = "ad5693", .driver_data = (kernel_ulong_t)&ad5683_chip_info }, + { .name = "ad5693r", .driver_data = (kernel_ulong_t)&ad5683r_chip_info }, + { .name = "ad5694", .driver_data = (kernel_ulong_t)&ad5684_chip_info }, + { .name = "ad5694r", .driver_data = (kernel_ulong_t)&ad5684r_chip_info }, + { .name = "ad5695r", .driver_data = (kernel_ulong_t)&ad5685r_chip_info }, + { .name = "ad5696", .driver_data = (kernel_ulong_t)&ad5686_chip_info }, + { .name = "ad5696r", .driver_data = (kernel_ulong_t)&ad5686r_chip_info }, + { .name = "ad5697r", .driver_data = (kernel_ulong_t)&ad5687r_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, ad5686_i2c_id); static const struct of_device_id ad5686_of_match[] = { - { .compatible = "adi,ad5311r" }, - { .compatible = "adi,ad5337r" }, - { .compatible = "adi,ad5338r" }, - { .compatible = "adi,ad5671r" }, - { .compatible = "adi,ad5675r" }, - { .compatible = "adi,ad5691r" }, - { .compatible = "adi,ad5692r" }, - { .compatible = "adi,ad5693" }, - { .compatible = "adi,ad5693r" }, - { .compatible = "adi,ad5694" }, - { .compatible = "adi,ad5694r" }, - { .compatible = "adi,ad5695r" }, - { .compatible = "adi,ad5696" }, - { .compatible = "adi,ad5696r" }, + { .compatible = "adi,ad5311r", .data = &ad5311r_chip_info }, + { .compatible = "adi,ad5316r", .data = &ad5317r_chip_info }, + { .compatible = "adi,ad5337r", .data = &ad5337r_chip_info }, + { .compatible = "adi,ad5338r", .data = &ad5338r_chip_info }, + { .compatible = "adi,ad5671r", .data = &ad5672r_chip_info }, + { .compatible = "adi,ad5673r", .data = &ad5674r_chip_info }, + { .compatible = "adi,ad5675", .data = &ad5676_chip_info }, + { .compatible = "adi,ad5675r", .data = &ad5676r_chip_info }, + { .compatible = "adi,ad5677r", .data = &ad5679r_chip_info }, + { .compatible = "adi,ad5691r", .data = &ad5681r_chip_info }, + { .compatible = "adi,ad5692r", .data = &ad5682r_chip_info }, + { .compatible = "adi,ad5693", .data = &ad5683_chip_info }, + { .compatible = "adi,ad5693r", .data = &ad5683r_chip_info }, + { .compatible = "adi,ad5694", .data = &ad5684_chip_info }, + { .compatible = "adi,ad5694r", .data = &ad5684r_chip_info }, + { .compatible = "adi,ad5695r", .data = &ad5685r_chip_info }, + { .compatible = "adi,ad5696", .data = &ad5686_chip_info }, + { .compatible = "adi,ad5696r", .data = &ad5686r_chip_info }, + { .compatible = "adi,ad5697r", .data = &ad5687r_chip_info }, { } }; MODULE_DEVICE_TABLE(of, ad5686_of_match); diff --git a/drivers/iio/dac/ad5706r.c b/drivers/iio/dac/ad5706r.c new file mode 100644 index 000000000000..06c4860a7eba --- /dev/null +++ b/drivers/iio/dac/ad5706r.c @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * AD5706R 16-bit Current Output Digital to Analog Converter + * + * Copyright 2026 Analog Devices Inc. + */ + +#include <linux/array_size.h> +#include <linux/bits.h> +#include <linux/dev_printk.h> +#include <linux/err.h> +#include <linux/iio/iio.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> +#include <linux/types.h> +#include <linux/unaligned.h> + +/* SPI frame layout */ +#define AD5706R_RD_MASK BIT(15) +#define AD5706R_ADDR_MASK GENMASK(11, 0) + +/* Registers */ +#define AD5706R_REG_DAC_INPUT_A_CH(x) (0x60 + ((x) * 2)) +#define AD5706R_REG_DAC_DATA_READBACK_CH(x) (0x68 + ((x) * 2)) + +#define AD5706R_DAC_RESOLUTION 16 +#define AD5706R_DAC_MAX_CODE GENMASK(15, 0) +#define AD5706R_MULTIBYTE_REG_START 0x14 +#define AD5706R_MULTIBYTE_REG_END 0x71 +#define AD5706R_MAX_REG 0x77 + +struct ad5706r_state { + struct spi_device *spi; + struct regmap *regmap; + + u8 tx_buf[4] __aligned(IIO_DMA_MINALIGN); + u8 rx_buf[4]; +}; + +static int ad5706r_reg_len(unsigned int reg) +{ + if (reg >= AD5706R_MULTIBYTE_REG_START && reg <= AD5706R_MULTIBYTE_REG_END) + return 2; + + return 1; +} + +static int ad5706r_regmap_write(void *context, const void *data, size_t count) +{ + struct ad5706r_state *st = context; + unsigned int num_bytes; + u16 reg, val; + + if (count != 4) + return -EINVAL; + + reg = get_unaligned_be16(data); + val = get_unaligned_be16(data + 2); + num_bytes = ad5706r_reg_len(reg); + + struct spi_transfer xfer = { + .tx_buf = st->tx_buf, + .len = num_bytes + 2, + }; + + put_unaligned_be16(reg, &st->tx_buf[0]); + + if (num_bytes == 1) + st->tx_buf[2] = (u8)val; + else if (num_bytes == 2) + put_unaligned_be16(val, &st->tx_buf[2]); + else + return -EINVAL; + + return spi_sync_transfer(st->spi, &xfer, 1); +} + +static int ad5706r_regmap_read(void *context, const void *reg_buf, + size_t reg_size, void *val_buf, size_t val_size) +{ + struct ad5706r_state *st = context; + unsigned int num_bytes; + u16 reg, cmd, val; + int ret; + + if (reg_size != 2 || val_size != 2) + return -EINVAL; + + reg = get_unaligned_be16(reg_buf); + num_bytes = ad5706r_reg_len(reg); + + /* Full duplex, device responds immediately after command */ + struct spi_transfer xfer = { + .tx_buf = st->tx_buf, + .rx_buf = st->rx_buf, + .len = 2 + num_bytes, + }; + + cmd = AD5706R_RD_MASK | (reg & AD5706R_ADDR_MASK); + put_unaligned_be16(cmd, &st->tx_buf[0]); + put_unaligned_be16(0, &st->tx_buf[2]); + + ret = spi_sync_transfer(st->spi, &xfer, 1); + if (ret) + return ret; + + /* Extract value from response (skip 2-byte command echo) */ + if (num_bytes == 1) + val = st->rx_buf[2]; + else if (num_bytes == 2) + val = get_unaligned_be16(&st->rx_buf[2]); + else + return -EINVAL; + + put_unaligned_be16(val, val_buf); + + return 0; +} + +static int ad5706r_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct ad5706r_state *st = iio_priv(indio_dev); + unsigned int reg, reg_val; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + reg = AD5706R_REG_DAC_DATA_READBACK_CH(chan->channel); + ret = regmap_read(st->regmap, reg, ®_val); + if (ret) + return ret; + + *val = reg_val; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 50; + *val2 = AD5706R_DAC_RESOLUTION; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } +} + +static int ad5706r_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct ad5706r_state *st = iio_priv(indio_dev); + unsigned int reg; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (val < 0 || val > AD5706R_DAC_MAX_CODE) + return -EINVAL; + + reg = AD5706R_REG_DAC_INPUT_A_CH(chan->channel); + return regmap_write(st->regmap, reg, val); + default: + return -EINVAL; + } +} + +static const struct regmap_bus ad5706r_regmap_bus = { + .write = ad5706r_regmap_write, + .read = ad5706r_regmap_read, + .reg_format_endian_default = REGMAP_ENDIAN_BIG, + .val_format_endian_default = REGMAP_ENDIAN_BIG, +}; + +static const struct regmap_config ad5706r_regmap_config = { + .reg_bits = 16, + .val_bits = 16, + .max_register = AD5706R_MAX_REG, +}; + +static const struct iio_info ad5706r_info = { + .read_raw = ad5706r_read_raw, + .write_raw = ad5706r_write_raw, +}; + +#define AD5706R_CHAN(_channel) { \ + .type = IIO_CURRENT, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .output = 1, \ + .indexed = 1, \ + .channel = _channel, \ +} + +static const struct iio_chan_spec ad5706r_channels[] = { + AD5706R_CHAN(0), + AD5706R_CHAN(1), + AD5706R_CHAN(2), + AD5706R_CHAN(3), +}; + +static int ad5706r_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct iio_dev *indio_dev; + struct ad5706r_state *st; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->spi = spi; + + st->regmap = devm_regmap_init(dev, &ad5706r_regmap_bus, + st, &ad5706r_regmap_config); + if (IS_ERR(st->regmap)) + return dev_err_probe(dev, PTR_ERR(st->regmap), + "Failed to init regmap\n"); + + indio_dev->name = "ad5706r"; + indio_dev->info = &ad5706r_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = ad5706r_channels; + indio_dev->num_channels = ARRAY_SIZE(ad5706r_channels); + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id ad5706r_of_match[] = { + { .compatible = "adi,ad5706r" }, + { } +}; +MODULE_DEVICE_TABLE(of, ad5706r_of_match); + +static const struct spi_device_id ad5706r_id[] = { + { .name = "ad5706r" }, + { } +}; +MODULE_DEVICE_TABLE(spi, ad5706r_id); + +static struct spi_driver ad5706r_driver = { + .driver = { + .name = "ad5706r", + .of_match_table = ad5706r_of_match, + }, + .probe = ad5706r_probe, + .id_table = ad5706r_id, +}; +module_spi_driver(ad5706r_driver); + +MODULE_AUTHOR("Alexis Czezar Torreno <alexisczezar.torreno@analog.com>"); +MODULE_DESCRIPTION("AD5706R 16-bit Current Output DAC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c index d0e5f35462b1..0828b9909099 100644 --- a/drivers/iio/dac/ad5755.c +++ b/drivers/iio/dac/ad5755.c @@ -827,8 +827,9 @@ static int ad5755_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->num_channels = AD5755_NUM_CHANNELS; - mutex_init(&st->lock); - + ret = devm_mutex_init(&spi->dev, &st->lock); + if (ret) + return ret; pdata = ad5755_parse_fw(&spi->dev); if (!pdata) { @@ -848,11 +849,11 @@ static int ad5755_probe(struct spi_device *spi) } static const struct spi_device_id ad5755_id[] = { - { "ad5755", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5755] }, - { "ad5755-1", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5755] }, - { "ad5757", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5757] }, - { "ad5735", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5735] }, - { "ad5737", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5737] }, + { .name = "ad5755", .driver_data = (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5755] }, + { .name = "ad5755-1", .driver_data = (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5755] }, + { .name = "ad5757", .driver_data = (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5757] }, + { .name = "ad5735", .driver_data = (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5735] }, + { .name = "ad5737", .driver_data = (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5737] }, { } }; MODULE_DEVICE_TABLE(spi, ad5755_id); diff --git a/drivers/iio/dac/ad5758.c b/drivers/iio/dac/ad5758.c index 4ed4fda76ea9..44efa373cd80 100644 --- a/drivers/iio/dac/ad5758.c +++ b/drivers/iio/dac/ad5758.c @@ -10,7 +10,6 @@ #include <linux/delay.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/spi/spi.h> #include <linux/gpio/consumer.h> @@ -851,7 +850,9 @@ static int ad5758_probe(struct spi_device *spi) st->spi = spi; - mutex_init(&st->lock); + ret = devm_mutex_init(&spi->dev, &st->lock); + if (ret) + return ret; indio_dev->name = spi_get_device_id(spi)->name; indio_dev->info = &ad5758_info; @@ -877,7 +878,7 @@ static int ad5758_probe(struct spi_device *spi) } static const struct spi_device_id ad5758_id[] = { - { "ad5758", 0 }, + { .name = "ad5758" }, { } }; MODULE_DEVICE_TABLE(spi, ad5758_id); diff --git a/drivers/iio/dac/ad5761.c b/drivers/iio/dac/ad5761.c index b5d20f04f070..c49568b943d6 100644 --- a/drivers/iio/dac/ad5761.c +++ b/drivers/iio/dac/ad5761.c @@ -342,10 +342,10 @@ static int ad5761_probe(struct spi_device *spi) } static const struct spi_device_id ad5761_id[] = { - {"ad5721", ID_AD5721}, - {"ad5721r", ID_AD5721R}, - {"ad5761", ID_AD5761}, - {"ad5761r", ID_AD5761R}, + { .name = "ad5721", .driver_data = ID_AD5721 }, + { .name = "ad5721r", .driver_data = ID_AD5721R }, + { .name = "ad5761", .driver_data = ID_AD5761 }, + { .name = "ad5761r", .driver_data = ID_AD5761R }, { } }; MODULE_DEVICE_TABLE(spi, ad5761_id); diff --git a/drivers/iio/dac/ad5764.c b/drivers/iio/dac/ad5764.c index fbbd7105a80c..2be4bee7eb01 100644 --- a/drivers/iio/dac/ad5764.c +++ b/drivers/iio/dac/ad5764.c @@ -342,10 +342,10 @@ static void ad5764_remove(struct spi_device *spi) } static const struct spi_device_id ad5764_ids[] = { - { "ad5744", ID_AD5744 }, - { "ad5744r", ID_AD5744R }, - { "ad5764", ID_AD5764 }, - { "ad5764r", ID_AD5764R }, + { .name = "ad5744", .driver_data = ID_AD5744 }, + { .name = "ad5744r", .driver_data = ID_AD5744R }, + { .name = "ad5764", .driver_data = ID_AD5764 }, + { .name = "ad5764r", .driver_data = ID_AD5764R }, { } }; MODULE_DEVICE_TABLE(spi, ad5764_ids); diff --git a/drivers/iio/dac/ad5766.c b/drivers/iio/dac/ad5766.c index f6a0a0d84fef..061b43fc0345 100644 --- a/drivers/iio/dac/ad5766.c +++ b/drivers/iio/dac/ad5766.c @@ -651,8 +651,8 @@ static const struct of_device_id ad5766_dt_match[] = { MODULE_DEVICE_TABLE(of, ad5766_dt_match); static const struct spi_device_id ad5766_spi_ids[] = { - { "ad5766", ID_AD5766 }, - { "ad5767", ID_AD5767 }, + { .name = "ad5766", .driver_data = ID_AD5766 }, + { .name = "ad5767", .driver_data = ID_AD5767 }, { } }; MODULE_DEVICE_TABLE(spi, ad5766_spi_ids); diff --git a/drivers/iio/dac/ad5770r.c b/drivers/iio/dac/ad5770r.c index cd47cb1c685c..bdc48e57013f 100644 --- a/drivers/iio/dac/ad5770r.c +++ b/drivers/iio/dac/ad5770r.c @@ -322,7 +322,7 @@ static int ad5770r_read_raw(struct iio_dev *indio_dev, chan->address, st->transf_buf, 2); if (ret) - return 0; + return ret; buf16 = get_unaligned_le16(st->transf_buf); *val = buf16 >> 2; @@ -642,7 +642,7 @@ static const struct of_device_id ad5770r_of_id[] = { MODULE_DEVICE_TABLE(of, ad5770r_of_id); static const struct spi_device_id ad5770r_id[] = { - { "ad5770r", 0 }, + { .name = "ad5770r" }, { } }; MODULE_DEVICE_TABLE(spi, ad5770r_id); diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c index ae7297f08398..a5eda135c9bd 100644 --- a/drivers/iio/dac/ad5791.c +++ b/drivers/iio/dac/ad5791.c @@ -586,11 +586,11 @@ static const struct of_device_id ad5791_of_match[] = { MODULE_DEVICE_TABLE(of, ad5791_of_match); static const struct spi_device_id ad5791_id[] = { - { "ad5760", (kernel_ulong_t)&ad5760_chip_info }, - { "ad5780", (kernel_ulong_t)&ad5780_chip_info }, - { "ad5781", (kernel_ulong_t)&ad5781_chip_info }, - { "ad5790", (kernel_ulong_t)&ad5790_chip_info }, - { "ad5791", (kernel_ulong_t)&ad5791_chip_info }, + { .name = "ad5760", .driver_data = (kernel_ulong_t)&ad5760_chip_info }, + { .name = "ad5780", .driver_data = (kernel_ulong_t)&ad5780_chip_info }, + { .name = "ad5781", .driver_data = (kernel_ulong_t)&ad5781_chip_info }, + { .name = "ad5790", .driver_data = (kernel_ulong_t)&ad5790_chip_info }, + { .name = "ad5791", .driver_data = (kernel_ulong_t)&ad5791_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad5791_id); diff --git a/drivers/iio/dac/ad7293.c b/drivers/iio/dac/ad7293.c index c3797e40cdd9..33a49813ece0 100644 --- a/drivers/iio/dac/ad7293.c +++ b/drivers/iio/dac/ad7293.c @@ -11,7 +11,6 @@ #include <linux/device.h> #include <linux/gpio/consumer.h> #include <linux/iio/iio.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> @@ -776,27 +775,27 @@ static int ad7293_reset(struct ad7293_state *st) static int ad7293_properties_parse(struct ad7293_state *st) { - struct spi_device *spi = st->spi; + struct device *dev = &st->spi->dev; int ret; - ret = devm_regulator_get_enable(&spi->dev, "avdd"); + ret = devm_regulator_get_enable(dev, "avdd"); if (ret) - return dev_err_probe(&spi->dev, ret, "failed to enable AVDD\n"); + return dev_err_probe(dev, ret, "failed to enable AVDD\n"); - ret = devm_regulator_get_enable(&spi->dev, "vdrive"); + ret = devm_regulator_get_enable(dev, "vdrive"); if (ret) - return dev_err_probe(&spi->dev, ret, "failed to enable VDRIVE\n"); + return dev_err_probe(dev, ret, "failed to enable VDRIVE\n"); - ret = devm_regulator_get_enable_optional(&spi->dev, "vrefin"); + ret = devm_regulator_get_enable_optional(dev, "vrefin"); if (ret < 0 && ret != -ENODEV) - return dev_err_probe(&spi->dev, ret, "failed to enable VREFIN\n"); + return dev_err_probe(dev, ret, "failed to enable VREFIN\n"); st->vrefin_en = ret != -ENODEV; - st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset", + st->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(st->gpio_reset)) - return dev_err_probe(&spi->dev, PTR_ERR(st->gpio_reset), + return dev_err_probe(dev, PTR_ERR(st->gpio_reset), "failed to get the reset GPIO\n"); return 0; @@ -806,7 +805,7 @@ static int ad7293_init(struct ad7293_state *st) { int ret; u16 chip_id; - struct spi_device *spi = st->spi; + struct device *dev = &st->spi->dev; ret = ad7293_properties_parse(st); if (ret) @@ -821,10 +820,8 @@ static int ad7293_init(struct ad7293_state *st) if (ret) return ret; - if (chip_id != AD7293_CHIP_ID) { - dev_err(&spi->dev, "Invalid Chip ID.\n"); - return -EINVAL; - } + if (chip_id != AD7293_CHIP_ID) + return dev_err_probe(dev, -EINVAL, "Invalid Chip ID.\n"); if (!st->vrefin_en) return __ad7293_spi_update_bits(st, AD7293_REG_GENERAL, @@ -845,9 +842,10 @@ static int ad7293_probe(struct spi_device *spi) { struct iio_dev *indio_dev; struct ad7293_state *st; + struct device *dev = &spi->dev; int ret; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; @@ -867,11 +865,11 @@ static int ad7293_probe(struct spi_device *spi) if (ret) return ret; - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct spi_device_id ad7293_id[] = { - { "ad7293", 0 }, + { .name = "ad7293" }, { } }; MODULE_DEVICE_TABLE(spi, ad7293_id); diff --git a/drivers/iio/dac/ad7303.c b/drivers/iio/dac/ad7303.c index a88cc639047d..83153e7d7fc8 100644 --- a/drivers/iio/dac/ad7303.c +++ b/drivers/iio/dac/ad7303.c @@ -7,7 +7,6 @@ #include <linux/err.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/kernel.h> #include <linux/spi/spi.h> #include <linux/slab.h> @@ -218,7 +217,9 @@ static int ad7303_probe(struct spi_device *spi) st->spi = spi; - mutex_init(&st->lock); + ret = devm_mutex_init(&spi->dev, &st->lock); + if (ret) + return ret; st->vdd_reg = devm_regulator_get(&spi->dev, "Vdd"); if (IS_ERR(st->vdd_reg)) @@ -269,7 +270,7 @@ static const struct of_device_id ad7303_spi_of_match[] = { MODULE_DEVICE_TABLE(of, ad7303_spi_of_match); static const struct spi_device_id ad7303_spi_ids[] = { - { "ad7303", 0 }, + { .name = "ad7303" }, { } }; MODULE_DEVICE_TABLE(spi, ad7303_spi_ids); diff --git a/drivers/iio/dac/ad8460.c b/drivers/iio/dac/ad8460.c index 6e45686902dd..a2292810e4cf 100644 --- a/drivers/iio/dac/ad8460.c +++ b/drivers/iio/dac/ad8460.c @@ -14,7 +14,6 @@ #include <linux/gpio/consumer.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> @@ -955,3 +954,4 @@ MODULE_AUTHOR("Mariel Tinaco <mariel.tinaco@analog.com"); MODULE_DESCRIPTION("AD8460 DAC driver"); MODULE_LICENSE("GPL"); MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/iio/dac/ad8801.c b/drivers/iio/dac/ad8801.c index 60e663af1cc1..08d7d74e999e 100644 --- a/drivers/iio/dac/ad8801.c +++ b/drivers/iio/dac/ad8801.c @@ -151,8 +151,8 @@ static int ad8801_probe(struct spi_device *spi) } static const struct spi_device_id ad8801_ids[] = { - {"ad8801", ID_AD8801}, - {"ad8803", ID_AD8803}, + { .name = "ad8801", .driver_data = ID_AD8801 }, + { .name = "ad8803", .driver_data = ID_AD8803 }, { } }; MODULE_DEVICE_TABLE(spi, ad8801_ids); diff --git a/drivers/iio/dac/ad9739a.c b/drivers/iio/dac/ad9739a.c index d77b46d83bd4..5263a0c968f5 100644 --- a/drivers/iio/dac/ad9739a.c +++ b/drivers/iio/dac/ad9739a.c @@ -14,7 +14,6 @@ #include <linux/gpio/consumer.h> #include <linux/minmax.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/regmap.h> #include <linux/spi/spi.h> @@ -447,7 +446,7 @@ static const struct of_device_id ad9739a_of_match[] = { MODULE_DEVICE_TABLE(of, ad9739a_of_match); static const struct spi_device_id ad9739a_id[] = { - {"ad9739a"}, + { .name = "ad9739a" }, { } }; MODULE_DEVICE_TABLE(spi, ad9739a_id); diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c index 9cc895bbe51a..f4f3bc67c68e 100644 --- a/drivers/iio/dac/adi-axi-dac.c +++ b/drivers/iio/dac/adi-axi-dac.c @@ -17,7 +17,6 @@ #include <linux/math.h> #include <linux/math64.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/platform_device.h> #include <linux/property.h> @@ -114,7 +113,6 @@ struct axi_dac_state { const struct axi_dac_info *info; u64 dac_clk; u32 reg_config; - bool int_tone; int dac_clk_rate; }; @@ -869,11 +867,13 @@ static const struct iio_backend_ops axi_ad3552r_ops = { static const struct iio_backend_info axi_dac_generic = { .name = "axi-dac", .ops = &axi_dac_generic_ops, + .caps = IIO_BACKEND_CAP_BUFFER | IIO_BACKEND_CAP_ENABLE, }; static const struct iio_backend_info axi_ad3552r = { .name = "axi-ad3552r", .ops = &axi_ad3552r_ops, + .caps = IIO_BACKEND_CAP_BUFFER | IIO_BACKEND_CAP_ENABLE, }; static const struct regmap_config axi_dac_regmap_config = { diff --git a/drivers/iio/dac/dpot-dac.c b/drivers/iio/dac/dpot-dac.c index d1b8441051ae..de36e2e27330 100644 --- a/drivers/iio/dac/dpot-dac.c +++ b/drivers/iio/dac/dpot-dac.c @@ -30,7 +30,6 @@ #include <linux/iio/consumer.h> #include <linux/iio/iio.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> @@ -254,3 +253,4 @@ module_platform_driver(dpot_dac_driver); MODULE_DESCRIPTION("DAC emulation driver using a digital potentiometer"); MODULE_AUTHOR("Peter Rosin <peda@axentia.se>"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/iio/dac/ds4424.c b/drivers/iio/dac/ds4424.c index c61868f2de31..b6430b832cf0 100644 --- a/drivers/iio/dac/ds4424.c +++ b/drivers/iio/dac/ds4424.c @@ -5,22 +5,31 @@ * Copyright (C) 2017 Maxim Integrated */ +#include <linux/array_size.h> +#include <linux/bits.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/i2c.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/i2c.h> +#include <linux/property.h> +#include <linux/regmap.h> #include <linux/regulator/consumer.h> -#include <linux/err.h> -#include <linux/delay.h> -#include <linux/iio/iio.h> +#include <linux/time64.h> +#include <linux/types.h> + #include <linux/iio/driver.h> +#include <linux/iio/iio.h> #include <linux/iio/machine.h> #define DS4422_MAX_DAC_CHANNELS 2 #define DS4424_MAX_DAC_CHANNELS 4 +#define DS4424_DAC_MASK GENMASK(6, 0) +#define DS4404_DAC_MASK GENMASK(4, 0) +#define DS4424_DAC_SOURCE BIT(7) + #define DS4424_DAC_ADDR(chan) ((chan) + 0xf8) -#define DS4424_SOURCE_I 1 -#define DS4424_SINK_I 0 #define DS4424_CHANNEL(chan) { \ .type = IIO_CURRENT, \ @@ -30,33 +39,61 @@ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ } -/* - * DS4424 DAC control register 8 bits - * [7] 0: to sink; 1: to source - * [6:0] steps to sink/source - * bit[7] looks like a sign bit, but the value of the register is - * not a two's complement code considering the bit[6:0] is a absolute - * distance from the zero point. - */ -union ds4424_raw_data { - struct { - u8 dx:7; - u8 source_bit:1; - }; - u8 bits; +#define DS4424_CHANNEL_WITH_SCALE(chan) { \ + .type = IIO_CURRENT, \ + .indexed = 1, \ + .output = 1, \ + .channel = chan, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ +} + +struct ds4424_chip_info { + const char *name; + int vref_mV; + int scale_denom; + u8 result_mask; + u8 num_channels; +}; + +static const struct ds4424_chip_info ds4402_info = { + .name = "ds4402", + .vref_mV = 1230, + .scale_denom = 4, + .result_mask = DS4404_DAC_MASK, + .num_channels = DS4422_MAX_DAC_CHANNELS, +}; + +static const struct ds4424_chip_info ds4404_info = { + .name = "ds4404", + .vref_mV = 1230, + .scale_denom = 4, + .result_mask = DS4404_DAC_MASK, + .num_channels = DS4424_MAX_DAC_CHANNELS, +}; + +static const struct ds4424_chip_info ds4422_info = { + .name = "ds4422", + .vref_mV = 976, + .scale_denom = 16, + .result_mask = DS4424_DAC_MASK, + .num_channels = DS4422_MAX_DAC_CHANNELS, }; -enum ds4424_device_ids { - ID_DS4422, - ID_DS4424, +static const struct ds4424_chip_info ds4424_info = { + .name = "ds4424", + .vref_mV = 976, + .scale_denom = 16, + .result_mask = DS4424_DAC_MASK, + .num_channels = DS4424_MAX_DAC_CHANNELS, }; struct ds4424_data { - struct i2c_client *client; - struct mutex lock; - uint8_t save[DS4424_MAX_DAC_CHANNELS]; + struct regmap *regmap; struct regulator *vcc_reg; - uint8_t raw[DS4424_MAX_DAC_CHANNELS]; + const struct ds4424_chip_info *chip_info; + u32 rfs_ohms[DS4424_MAX_DAC_CHANNELS]; + bool has_rfs; }; static const struct iio_chan_spec ds4424_channels[] = { @@ -66,63 +103,114 @@ static const struct iio_chan_spec ds4424_channels[] = { DS4424_CHANNEL(3), }; -static int ds4424_get_value(struct iio_dev *indio_dev, - int *val, int channel) -{ - struct ds4424_data *data = iio_priv(indio_dev); - int ret; +static const struct iio_chan_spec ds4424_channels_with_scale[] = { + DS4424_CHANNEL_WITH_SCALE(0), + DS4424_CHANNEL_WITH_SCALE(1), + DS4424_CHANNEL_WITH_SCALE(2), + DS4424_CHANNEL_WITH_SCALE(3), +}; - mutex_lock(&data->lock); - ret = i2c_smbus_read_byte_data(data->client, DS4424_DAC_ADDR(channel)); - if (ret < 0) - goto fail; +static const struct regmap_range ds44x2_ranges[] = { + regmap_reg_range(DS4424_DAC_ADDR(0), DS4424_DAC_ADDR(1)), +}; - *val = ret; +static const struct regmap_range ds44x4_ranges[] = { + regmap_reg_range(DS4424_DAC_ADDR(0), DS4424_DAC_ADDR(3)), +}; -fail: - mutex_unlock(&data->lock); - return ret; -} +static const struct regmap_access_table ds44x2_table = { + .yes_ranges = ds44x2_ranges, + .n_yes_ranges = ARRAY_SIZE(ds44x2_ranges), +}; + +static const struct regmap_access_table ds44x4_table = { + .yes_ranges = ds44x4_ranges, + .n_yes_ranges = ARRAY_SIZE(ds44x4_ranges), +}; -static int ds4424_set_value(struct iio_dev *indio_dev, - int val, struct iio_chan_spec const *chan) +static const struct regmap_config ds44x2_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_MAPLE, + .max_register = DS4424_DAC_ADDR(1), + .rd_table = &ds44x2_table, + .wr_table = &ds44x2_table, +}; + +static const struct regmap_config ds44x4_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_MAPLE, + .max_register = DS4424_DAC_ADDR(3), + .rd_table = &ds44x4_table, + .wr_table = &ds44x4_table, +}; + +static int ds4424_init_regmap(struct i2c_client *client, + struct iio_dev *indio_dev) { struct ds4424_data *data = iio_priv(indio_dev); + const struct regmap_config *regmap_config; + u8 vals[DS4424_MAX_DAC_CHANNELS]; int ret; - mutex_lock(&data->lock); - ret = i2c_smbus_write_byte_data(data->client, - DS4424_DAC_ADDR(chan->channel), val); - if (ret < 0) - goto fail; - - data->raw[chan->channel] = val; - -fail: - mutex_unlock(&data->lock); - return ret; + if (indio_dev->num_channels == DS4424_MAX_DAC_CHANNELS) + regmap_config = &ds44x4_regmap_config; + else + regmap_config = &ds44x2_regmap_config; + + data->regmap = devm_regmap_init_i2c(client, regmap_config); + if (IS_ERR(data->regmap)) + return dev_err_probe(&client->dev, PTR_ERR(data->regmap), + "Failed to init regmap.\n"); + + /* + * Prime the cache with the bootloader's configuration. + * regmap_bulk_read() will automatically populate the cache with + * the values read from the hardware. + */ + ret = regmap_bulk_read(data->regmap, DS4424_DAC_ADDR(0), vals, + indio_dev->num_channels); + if (ret) + return dev_err_probe(&client->dev, ret, + "Failed to read hardware values\n"); + + return 0; } static int ds4424_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { - union ds4424_raw_data raw; + struct ds4424_data *data = iio_priv(indio_dev); + unsigned int regval; int ret; switch (mask) { case IIO_CHAN_INFO_RAW: - ret = ds4424_get_value(indio_dev, val, chan->channel); + ret = regmap_read(data->regmap, DS4424_DAC_ADDR(chan->channel), + ®val); if (ret < 0) { - pr_err("%s : ds4424_get_value returned %d\n", - __func__, ret); + dev_err_ratelimited(indio_dev->dev.parent, + "Failed to read channel %d: %pe\n", + chan->channel, ERR_PTR(ret)); return ret; } - raw.bits = *val; - *val = raw.dx; - if (raw.source_bit == DS4424_SINK_I) + + *val = regval & data->chip_info->result_mask; + if (!(regval & DS4424_DAC_SOURCE)) *val = -*val; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + if (!data->has_rfs) + return -EINVAL; + + /* SCALE is mA/step: mV / Ohm = mA. */ + *val = data->chip_info->vref_mV; + *val2 = data->rfs_ohms[chan->channel] * + data->chip_info->scale_denom; + return IIO_VAL_FRACTIONAL; default: return -EINVAL; @@ -133,107 +221,131 @@ static int ds4424_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { - union ds4424_raw_data raw; + struct ds4424_data *data = iio_priv(indio_dev); + unsigned int abs_val; if (val2 != 0) return -EINVAL; switch (mask) { case IIO_CHAN_INFO_RAW: - if (val <= S8_MIN || val > S8_MAX) + abs_val = abs(val); + if (abs_val > data->chip_info->result_mask) return -EINVAL; - if (val > 0) { - raw.source_bit = DS4424_SOURCE_I; - raw.dx = val; - } else { - raw.source_bit = DS4424_SINK_I; - raw.dx = -val; - } + /* + * Currents exiting the IC (Source) are positive. 0 is a valid + * value for no current flow; the direction bit (Source vs Sink) + * is treated as don't-care by the hardware at 0. + */ + if (val > 0) + abs_val |= DS4424_DAC_SOURCE; - return ds4424_set_value(indio_dev, raw.bits, chan); + return regmap_write(data->regmap, DS4424_DAC_ADDR(chan->channel), + abs_val); default: return -EINVAL; } } -static int ds4424_verify_chip(struct iio_dev *indio_dev) +static int ds4424_parse_rfs(struct i2c_client *client, + struct ds4424_data *data, + struct iio_dev *indio_dev) { - int ret, val; + struct device *dev = &client->dev; + int count, ret; + + if (!device_property_present(dev, "maxim,rfs-ohms")) + return 0; + + count = device_property_count_u32(dev, "maxim,rfs-ohms"); + if (count < 0) + return dev_err_probe(dev, count, "Failed to count maxim,rfs-ohms entries\n"); + if (count != indio_dev->num_channels) + return dev_err_probe(dev, -EINVAL, "maxim,rfs-ohms must have %u entries\n", + indio_dev->num_channels); + + ret = device_property_read_u32_array(dev, "maxim,rfs-ohms", + data->rfs_ohms, + indio_dev->num_channels); + if (ret) + return dev_err_probe(dev, ret, "Failed to read maxim,rfs-ohms property\n"); + + for (unsigned int i = 0; i < indio_dev->num_channels; i++) { + if (!data->rfs_ohms[i]) + return dev_err_probe(dev, -EINVAL, "maxim,rfs-ohms entry %u is zero\n", i); + } - ret = ds4424_get_value(indio_dev, &val, 0); - if (ret < 0) - dev_err(&indio_dev->dev, - "%s failed. ret: %d\n", __func__, ret); + data->has_rfs = true; - return ret; + return 0; } static int ds4424_suspend(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ds4424_data *data = iio_priv(indio_dev); - int ret = 0; - int i; - - for (i = 0; i < indio_dev->num_channels; i++) { - data->save[i] = data->raw[i]; - ret = ds4424_set_value(indio_dev, 0, - &indio_dev->channels[i]); - if (ret < 0) - return ret; + u8 zero_buf[DS4424_MAX_DAC_CHANNELS] = { }; + int ret; + + /* Disable all outputs, bypass cache so the '0' isn't saved */ + regcache_cache_bypass(data->regmap, true); + ret = regmap_bulk_write(data->regmap, DS4424_DAC_ADDR(0), + zero_buf, indio_dev->num_channels); + regcache_cache_bypass(data->regmap, false); + if (ret) { + dev_err(dev, "Failed to zero outputs: %pe\n", ERR_PTR(ret)); + return ret; } - return ret; + + regcache_cache_only(data->regmap, true); + regcache_mark_dirty(data->regmap); + + return 0; } static int ds4424_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ds4424_data *data = iio_priv(indio_dev); - int ret = 0; - int i; - for (i = 0; i < indio_dev->num_channels; i++) { - ret = ds4424_set_value(indio_dev, data->save[i], - &indio_dev->channels[i]); - if (ret < 0) - return ret; - } - return ret; + regcache_cache_only(data->regmap, false); + return regcache_sync(data->regmap); } static DEFINE_SIMPLE_DEV_PM_OPS(ds4424_pm_ops, ds4424_suspend, ds4424_resume); -static const struct iio_info ds4424_info = { +static const struct iio_info ds4424_iio_info = { .read_raw = ds4424_read_raw, .write_raw = ds4424_write_raw, }; static int ds4424_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); + const struct ds4424_chip_info *chip_info; struct ds4424_data *data; struct iio_dev *indio_dev; int ret; + chip_info = i2c_get_match_data(client); + if (!chip_info) + return -ENODEV; + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) return -ENOMEM; data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); - data->client = client; - indio_dev->name = id->name; + indio_dev->name = chip_info->name; + data->chip_info = chip_info; data->vcc_reg = devm_regulator_get(&client->dev, "vcc"); if (IS_ERR(data->vcc_reg)) return dev_err_probe(&client->dev, PTR_ERR(data->vcc_reg), "Failed to get vcc-supply regulator.\n"); - mutex_init(&data->lock); ret = regulator_enable(data->vcc_reg); if (ret < 0) { dev_err(&client->dev, @@ -241,28 +353,29 @@ static int ds4424_probe(struct i2c_client *client) return ret; } - usleep_range(1000, 1200); - ret = ds4424_verify_chip(indio_dev); - if (ret < 0) + /* + * The datasheet does not specify a power-up to I2C ready time. + * Maintain the existing conservative 1ms delay to ensure the + * device is ready for communication. + */ + fsleep(1 * USEC_PER_MSEC); + + indio_dev->num_channels = chip_info->num_channels; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &ds4424_iio_info; + + ret = ds4424_init_regmap(client, indio_dev); + if (ret) goto fail; - switch (id->driver_data) { - case ID_DS4422: - indio_dev->num_channels = DS4422_MAX_DAC_CHANNELS; - break; - case ID_DS4424: - indio_dev->num_channels = DS4424_MAX_DAC_CHANNELS; - break; - default: - dev_err(&client->dev, - "ds4424: Invalid chip id.\n"); - ret = -ENXIO; + ret = ds4424_parse_rfs(client, data, indio_dev); + if (ret) goto fail; - } - indio_dev->channels = ds4424_channels; - indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->info = &ds4424_info; + if (data->has_rfs) + indio_dev->channels = ds4424_channels_with_scale; + else + indio_dev->channels = ds4424_channels; ret = iio_device_register(indio_dev); if (ret < 0) { @@ -288,16 +401,20 @@ static void ds4424_remove(struct i2c_client *client) } static const struct i2c_device_id ds4424_id[] = { - { "ds4422", ID_DS4422 }, - { "ds4424", ID_DS4424 }, + { .name = "ds4402", .driver_data = (kernel_ulong_t)&ds4402_info }, + { .name = "ds4404", .driver_data = (kernel_ulong_t)&ds4404_info }, + { .name = "ds4422", .driver_data = (kernel_ulong_t)&ds4422_info }, + { .name = "ds4424", .driver_data = (kernel_ulong_t)&ds4424_info }, { } }; MODULE_DEVICE_TABLE(i2c, ds4424_id); static const struct of_device_id ds4424_of_match[] = { - { .compatible = "maxim,ds4422" }, - { .compatible = "maxim,ds4424" }, + { .compatible = "maxim,ds4402", .data = &ds4402_info }, + { .compatible = "maxim,ds4404", .data = &ds4404_info }, + { .compatible = "maxim,ds4422", .data = &ds4422_info }, + { .compatible = "maxim,ds4424", .data = &ds4424_info }, { } }; diff --git a/drivers/iio/dac/lpc18xx_dac.c b/drivers/iio/dac/lpc18xx_dac.c index aa1c73f8429d..43fb9e5a2c56 100644 --- a/drivers/iio/dac/lpc18xx_dac.c +++ b/drivers/iio/dac/lpc18xx_dac.c @@ -16,7 +16,6 @@ #include <linux/io.h> #include <linux/iopoll.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> diff --git a/drivers/iio/dac/ltc1660.c b/drivers/iio/dac/ltc1660.c index 6e80b49f4665..90ffb58e7927 100644 --- a/drivers/iio/dac/ltc1660.c +++ b/drivers/iio/dac/ltc1660.c @@ -224,8 +224,8 @@ static const struct of_device_id ltc1660_dt_ids[] = { MODULE_DEVICE_TABLE(of, ltc1660_dt_ids); static const struct spi_device_id ltc1660_id[] = { - {"ltc1660", ID_LTC1660}, - {"ltc1665", ID_LTC1665}, + { .name = "ltc1660", .driver_data = ID_LTC1660 }, + { .name = "ltc1665", .driver_data = ID_LTC1665 }, { } }; MODULE_DEVICE_TABLE(spi, ltc1660_id); diff --git a/drivers/iio/dac/ltc2632.c b/drivers/iio/dac/ltc2632.c index 105f939f7e54..3800aee8dd6e 100644 --- a/drivers/iio/dac/ltc2632.c +++ b/drivers/iio/dac/ltc2632.c @@ -48,27 +48,6 @@ struct ltc2632_state { int vref_mv; }; -enum ltc2632_supported_device_ids { - ID_LTC2632L12, - ID_LTC2632L10, - ID_LTC2632L8, - ID_LTC2632H12, - ID_LTC2632H10, - ID_LTC2632H8, - ID_LTC2634L12, - ID_LTC2634L10, - ID_LTC2634L8, - ID_LTC2634H12, - ID_LTC2634H10, - ID_LTC2634H8, - ID_LTC2636L12, - ID_LTC2636L10, - ID_LTC2636L8, - ID_LTC2636H12, - ID_LTC2636H10, - ID_LTC2636H8, -}; - static int ltc2632_spi_write(struct spi_device *spi, u8 cmd, u8 addr, u16 val, u8 shift) { @@ -79,8 +58,9 @@ static int ltc2632_spi_write(struct spi_device *spi, * The input shift register is 24 bits wide. * The next four are the command bits, C3 to C0, * followed by the 4-bit DAC address, A3 to A0, and then the - * 12-, 10-, 8-bit data-word. The data-word comprises the 12-, - * 10-, 8-bit input code followed by 4, 6, or 8 don't care bits. + * 16-, 12-, 10-, 8-bit data-word. The data-word comprises the + * 16-, 12-, 10-, 8-bit input code followed by 0, 4, 6, or 8 + * don't care bits. */ data = (cmd << 20) | (addr << 16) | (val << shift); put_unaligned_be24(data, &msg[0]); @@ -206,101 +186,129 @@ static const struct iio_chan_spec_ext_info ltc2632_ext_info[] = { LTC2632_CHANNEL(7, _bits), \ } +static DECLARE_LTC2632_CHANNELS(ltc2632x16, 16); static DECLARE_LTC2632_CHANNELS(ltc2632x12, 12); static DECLARE_LTC2632_CHANNELS(ltc2632x10, 10); static DECLARE_LTC2632_CHANNELS(ltc2632x8, 8); -static const struct ltc2632_chip_info ltc2632_chip_info_tbl[] = { - [ID_LTC2632L12] = { - .channels = ltc2632x12_channels, - .num_channels = 2, - .vref_mv = 2500, - }, - [ID_LTC2632L10] = { - .channels = ltc2632x10_channels, - .num_channels = 2, - .vref_mv = 2500, - }, - [ID_LTC2632L8] = { - .channels = ltc2632x8_channels, - .num_channels = 2, - .vref_mv = 2500, - }, - [ID_LTC2632H12] = { - .channels = ltc2632x12_channels, - .num_channels = 2, - .vref_mv = 4096, - }, - [ID_LTC2632H10] = { - .channels = ltc2632x10_channels, - .num_channels = 2, - .vref_mv = 4096, - }, - [ID_LTC2632H8] = { - .channels = ltc2632x8_channels, - .num_channels = 2, - .vref_mv = 4096, - }, - [ID_LTC2634L12] = { - .channels = ltc2632x12_channels, - .num_channels = 4, - .vref_mv = 2500, - }, - [ID_LTC2634L10] = { - .channels = ltc2632x10_channels, - .num_channels = 4, - .vref_mv = 2500, - }, - [ID_LTC2634L8] = { - .channels = ltc2632x8_channels, - .num_channels = 4, - .vref_mv = 2500, - }, - [ID_LTC2634H12] = { - .channels = ltc2632x12_channels, - .num_channels = 4, - .vref_mv = 4096, - }, - [ID_LTC2634H10] = { - .channels = ltc2632x10_channels, - .num_channels = 4, - .vref_mv = 4096, - }, - [ID_LTC2634H8] = { - .channels = ltc2632x8_channels, - .num_channels = 4, - .vref_mv = 4096, - }, - [ID_LTC2636L12] = { - .channels = ltc2632x12_channels, - .num_channels = 8, - .vref_mv = 2500, - }, - [ID_LTC2636L10] = { - .channels = ltc2632x10_channels, - .num_channels = 8, - .vref_mv = 2500, - }, - [ID_LTC2636L8] = { - .channels = ltc2632x8_channels, - .num_channels = 8, - .vref_mv = 2500, - }, - [ID_LTC2636H12] = { - .channels = ltc2632x12_channels, - .num_channels = 8, - .vref_mv = 4096, - }, - [ID_LTC2636H10] = { - .channels = ltc2632x10_channels, - .num_channels = 8, - .vref_mv = 4096, - }, - [ID_LTC2636H8] = { - .channels = ltc2632x8_channels, - .num_channels = 8, - .vref_mv = 4096, - }, +static const struct ltc2632_chip_info ltc2632l12_chip_info = { + .channels = ltc2632x12_channels, + .num_channels = 2, + .vref_mv = 2500, +}; + +static const struct ltc2632_chip_info ltc2632l10_chip_info = { + .channels = ltc2632x10_channels, + .num_channels = 2, + .vref_mv = 2500, +}; + +static const struct ltc2632_chip_info ltc2632l8_chip_info = { + .channels = ltc2632x8_channels, + .num_channels = 2, + .vref_mv = 2500, +}; + +static const struct ltc2632_chip_info ltc2632h12_chip_info = { + .channels = ltc2632x12_channels, + .num_channels = 2, + .vref_mv = 4096, +}; + +static const struct ltc2632_chip_info ltc2632h10_chip_info = { + .channels = ltc2632x10_channels, + .num_channels = 2, + .vref_mv = 4096, +}; + +static const struct ltc2632_chip_info ltc2632h8_chip_info = { + .channels = ltc2632x8_channels, + .num_channels = 2, + .vref_mv = 4096, +}; + +static const struct ltc2632_chip_info ltc2634l12_chip_info = { + .channels = ltc2632x12_channels, + .num_channels = 4, + .vref_mv = 2500, +}; + +static const struct ltc2632_chip_info ltc2634l10_chip_info = { + .channels = ltc2632x10_channels, + .num_channels = 4, + .vref_mv = 2500, +}; + +static const struct ltc2632_chip_info ltc2634l8_chip_info = { + .channels = ltc2632x8_channels, + .num_channels = 4, + .vref_mv = 2500, +}; + +static const struct ltc2632_chip_info ltc2634h12_chip_info = { + .channels = ltc2632x12_channels, + .num_channels = 4, + .vref_mv = 4096, +}; + +static const struct ltc2632_chip_info ltc2634h10_chip_info = { + .channels = ltc2632x10_channels, + .num_channels = 4, + .vref_mv = 4096, +}; + +static const struct ltc2632_chip_info ltc2634h8_chip_info = { + .channels = ltc2632x8_channels, + .num_channels = 4, + .vref_mv = 4096, +}; + +static const struct ltc2632_chip_info ltc2636l12_chip_info = { + .channels = ltc2632x12_channels, + .num_channels = 8, + .vref_mv = 2500, +}; + +static const struct ltc2632_chip_info ltc2636l10_chip_info = { + .channels = ltc2632x10_channels, + .num_channels = 8, + .vref_mv = 2500, +}; + +static const struct ltc2632_chip_info ltc2636l8_chip_info = { + .channels = ltc2632x8_channels, + .num_channels = 8, + .vref_mv = 2500, +}; + +static const struct ltc2632_chip_info ltc2636h12_chip_info = { + .channels = ltc2632x12_channels, + .num_channels = 8, + .vref_mv = 4096, +}; + +static const struct ltc2632_chip_info ltc2636h10_chip_info = { + .channels = ltc2632x10_channels, + .num_channels = 8, + .vref_mv = 4096, +}; + +static const struct ltc2632_chip_info ltc2636h8_chip_info = { + .channels = ltc2632x8_channels, + .num_channels = 8, + .vref_mv = 4096, +}; + +static const struct ltc2632_chip_info ltc2654l16_chip_info = { + .channels = ltc2632x16_channels, + .num_channels = 4, + .vref_mv = 2500, +}; + +static const struct ltc2632_chip_info ltc2654h16_chip_info = { + .channels = ltc2632x16_channels, + .num_channels = 4, + .vref_mv = 4096, }; static int ltc2632_probe(struct spi_device *spi) @@ -354,84 +362,53 @@ static int ltc2632_probe(struct spi_device *spi) } static const struct spi_device_id ltc2632_id[] = { - { "ltc2632-l12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632L12] }, - { "ltc2632-l10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632L10] }, - { "ltc2632-l8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632L8] }, - { "ltc2632-h12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632H12] }, - { "ltc2632-h10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632H10] }, - { "ltc2632-h8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2632H8] }, - { "ltc2634-l12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634L12] }, - { "ltc2634-l10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634L10] }, - { "ltc2634-l8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634L8] }, - { "ltc2634-h12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634H12] }, - { "ltc2634-h10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634H10] }, - { "ltc2634-h8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2634H8] }, - { "ltc2636-l12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636L12] }, - { "ltc2636-l10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636L10] }, - { "ltc2636-l8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636L8] }, - { "ltc2636-h12", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636H12] }, - { "ltc2636-h10", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636H10] }, - { "ltc2636-h8", (kernel_ulong_t)<c2632_chip_info_tbl[ID_LTC2636H8] }, + { .name = "ltc2632-l12", .driver_data = (kernel_ulong_t)<c2632l12_chip_info }, + { .name = "ltc2632-l10", .driver_data = (kernel_ulong_t)<c2632l10_chip_info }, + { .name = "ltc2632-l8", .driver_data = (kernel_ulong_t)<c2632l8_chip_info }, + { .name = "ltc2632-h12", .driver_data = (kernel_ulong_t)<c2632h12_chip_info }, + { .name = "ltc2632-h10", .driver_data = (kernel_ulong_t)<c2632h10_chip_info }, + { .name = "ltc2632-h8", .driver_data = (kernel_ulong_t)<c2632h8_chip_info }, + { .name = "ltc2634-l12", .driver_data = (kernel_ulong_t)<c2634l12_chip_info }, + { .name = "ltc2634-l10", .driver_data = (kernel_ulong_t)<c2634l10_chip_info }, + { .name = "ltc2634-l8", .driver_data = (kernel_ulong_t)<c2634l8_chip_info }, + { .name = "ltc2634-h12", .driver_data = (kernel_ulong_t)<c2634h12_chip_info }, + { .name = "ltc2634-h10", .driver_data = (kernel_ulong_t)<c2634h10_chip_info }, + { .name = "ltc2634-h8", .driver_data = (kernel_ulong_t)<c2634h8_chip_info }, + { .name = "ltc2636-l12", .driver_data = (kernel_ulong_t)<c2636l12_chip_info }, + { .name = "ltc2636-l10", .driver_data = (kernel_ulong_t)<c2636l10_chip_info }, + { .name = "ltc2636-l8", .driver_data = (kernel_ulong_t)<c2636l8_chip_info }, + { .name = "ltc2636-h12", .driver_data = (kernel_ulong_t)<c2636h12_chip_info }, + { .name = "ltc2636-h10", .driver_data = (kernel_ulong_t)<c2636h10_chip_info }, + { .name = "ltc2636-h8", .driver_data = (kernel_ulong_t)<c2636h8_chip_info }, + { .name = "ltc2654-l16", .driver_data = (kernel_ulong_t)<c2654l16_chip_info }, + { .name = "ltc2654-l12", .driver_data = (kernel_ulong_t)<c2634l12_chip_info }, + { .name = "ltc2654-h16", .driver_data = (kernel_ulong_t)<c2654h16_chip_info }, + { .name = "ltc2654-h12", .driver_data = (kernel_ulong_t)<c2634h12_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ltc2632_id); static const struct of_device_id ltc2632_of_match[] = { - { - .compatible = "lltc,ltc2632-l12", - .data = <c2632_chip_info_tbl[ID_LTC2632L12] - }, { - .compatible = "lltc,ltc2632-l10", - .data = <c2632_chip_info_tbl[ID_LTC2632L10] - }, { - .compatible = "lltc,ltc2632-l8", - .data = <c2632_chip_info_tbl[ID_LTC2632L8] - }, { - .compatible = "lltc,ltc2632-h12", - .data = <c2632_chip_info_tbl[ID_LTC2632H12] - }, { - .compatible = "lltc,ltc2632-h10", - .data = <c2632_chip_info_tbl[ID_LTC2632H10] - }, { - .compatible = "lltc,ltc2632-h8", - .data = <c2632_chip_info_tbl[ID_LTC2632H8] - }, { - .compatible = "lltc,ltc2634-l12", - .data = <c2632_chip_info_tbl[ID_LTC2634L12] - }, { - .compatible = "lltc,ltc2634-l10", - .data = <c2632_chip_info_tbl[ID_LTC2634L10] - }, { - .compatible = "lltc,ltc2634-l8", - .data = <c2632_chip_info_tbl[ID_LTC2634L8] - }, { - .compatible = "lltc,ltc2634-h12", - .data = <c2632_chip_info_tbl[ID_LTC2634H12] - }, { - .compatible = "lltc,ltc2634-h10", - .data = <c2632_chip_info_tbl[ID_LTC2634H10] - }, { - .compatible = "lltc,ltc2634-h8", - .data = <c2632_chip_info_tbl[ID_LTC2634H8] - }, { - .compatible = "lltc,ltc2636-l12", - .data = <c2632_chip_info_tbl[ID_LTC2636L12] - }, { - .compatible = "lltc,ltc2636-l10", - .data = <c2632_chip_info_tbl[ID_LTC2636L10] - }, { - .compatible = "lltc,ltc2636-l8", - .data = <c2632_chip_info_tbl[ID_LTC2636L8] - }, { - .compatible = "lltc,ltc2636-h12", - .data = <c2632_chip_info_tbl[ID_LTC2636H12] - }, { - .compatible = "lltc,ltc2636-h10", - .data = <c2632_chip_info_tbl[ID_LTC2636H10] - }, { - .compatible = "lltc,ltc2636-h8", - .data = <c2632_chip_info_tbl[ID_LTC2636H8] - }, + { .compatible = "lltc,ltc2632-l12", .data = <c2632l12_chip_info }, + { .compatible = "lltc,ltc2632-l10", .data = <c2632l10_chip_info }, + { .compatible = "lltc,ltc2632-l8", .data = <c2632l8_chip_info }, + { .compatible = "lltc,ltc2632-h12", .data = <c2632h12_chip_info }, + { .compatible = "lltc,ltc2632-h10", .data = <c2632h10_chip_info }, + { .compatible = "lltc,ltc2632-h8", .data = <c2632h8_chip_info }, + { .compatible = "lltc,ltc2634-l12", .data = <c2634l12_chip_info }, + { .compatible = "lltc,ltc2634-l10", .data = <c2634l10_chip_info }, + { .compatible = "lltc,ltc2634-l8", .data = <c2634l8_chip_info }, + { .compatible = "lltc,ltc2634-h12", .data = <c2634h12_chip_info }, + { .compatible = "lltc,ltc2634-h10", .data = <c2634h10_chip_info }, + { .compatible = "lltc,ltc2634-h8", .data = <c2634h8_chip_info }, + { .compatible = "lltc,ltc2636-l12", .data = <c2636l12_chip_info }, + { .compatible = "lltc,ltc2636-l10", .data = <c2636l10_chip_info }, + { .compatible = "lltc,ltc2636-l8", .data = <c2636l8_chip_info }, + { .compatible = "lltc,ltc2636-h12", .data = <c2636h12_chip_info }, + { .compatible = "lltc,ltc2636-h10", .data = <c2636h10_chip_info }, + { .compatible = "lltc,ltc2636-h8", .data = <c2636h8_chip_info }, + { .compatible = "lltc,ltc2654-l16", .data = <c2654l16_chip_info }, + { .compatible = "lltc,ltc2654-h16", .data = <c2654h16_chip_info }, { } }; MODULE_DEVICE_TABLE(of, ltc2632_of_match); @@ -447,5 +424,5 @@ static struct spi_driver ltc2632_driver = { module_spi_driver(ltc2632_driver); MODULE_AUTHOR("Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com>"); -MODULE_DESCRIPTION("LTC2632 DAC SPI driver"); +MODULE_DESCRIPTION("LTC2632 and similar DAC SPI driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/dac/ltc2664.c b/drivers/iio/dac/ltc2664.c index 67f14046cf77..35bec55ebde1 100644 --- a/drivers/iio/dac/ltc2664.c +++ b/drivers/iio/dac/ltc2664.c @@ -14,7 +14,6 @@ #include <linux/kernel.h> #include <linux/math64.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/property.h> #include <linux/regmap.h> @@ -675,7 +674,9 @@ static int ltc2664_probe(struct spi_device *spi) st->chip_info = chip_info; - mutex_init(&st->lock); + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; st->regmap = devm_regmap_init_spi(spi, <c2664_regmap_config); if (IS_ERR(st->regmap)) @@ -707,8 +708,8 @@ static int ltc2664_probe(struct spi_device *spi) } static const struct spi_device_id ltc2664_id[] = { - { "ltc2664", (kernel_ulong_t)<c2664_chip }, - { "ltc2672", (kernel_ulong_t)<c2672_chip }, + { .name = "ltc2664", .driver_data = (kernel_ulong_t)<c2664_chip }, + { .name = "ltc2672", .driver_data = (kernel_ulong_t)<c2672_chip }, { } }; MODULE_DEVICE_TABLE(spi, ltc2664_id); diff --git a/drivers/iio/dac/ltc2688.c b/drivers/iio/dac/ltc2688.c index 02f408229681..0301bb7dce31 100644 --- a/drivers/iio/dac/ltc2688.c +++ b/drivers/iio/dac/ltc2688.c @@ -14,7 +14,6 @@ #include <linux/limits.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/of.h> #include <linux/property.h> @@ -992,7 +991,7 @@ static const struct of_device_id ltc2688_of_id[] = { MODULE_DEVICE_TABLE(of, ltc2688_of_id); static const struct spi_device_id ltc2688_id[] = { - { "ltc2688" }, + { .name = "ltc2688" }, { } }; MODULE_DEVICE_TABLE(spi, ltc2688_id); diff --git a/drivers/iio/dac/m62332.c b/drivers/iio/dac/m62332.c index 3497513854d7..60bb672b70e2 100644 --- a/drivers/iio/dac/m62332.c +++ b/drivers/iio/dac/m62332.c @@ -32,6 +32,7 @@ static int m62332_set_value(struct iio_dev *indio_dev, u8 val, int channel) { struct m62332_data *data = iio_priv(indio_dev); struct i2c_client *client = data->client; + bool enabling, disabling; u8 outbuf[2]; int res; @@ -43,7 +44,10 @@ static int m62332_set_value(struct iio_dev *indio_dev, u8 val, int channel) mutex_lock(&data->mutex); - if (val) { + enabling = val && !data->raw[channel]; + disabling = !val && data->raw[channel]; + + if (enabling) { res = regulator_enable(data->vcc); if (res) goto out; @@ -52,14 +56,17 @@ static int m62332_set_value(struct iio_dev *indio_dev, u8 val, int channel) res = i2c_master_send(client, outbuf, ARRAY_SIZE(outbuf)); if (res >= 0 && res != ARRAY_SIZE(outbuf)) res = -EIO; - if (res < 0) + if (res < 0) { + if (enabling) + regulator_disable(data->vcc); goto out; + } - data->raw[channel] = val; - - if (!val) + if (disabling) regulator_disable(data->vcc); + data->raw[channel] = val; + mutex_unlock(&data->mutex); return 0; @@ -228,7 +235,7 @@ static void m62332_remove(struct i2c_client *client) } static const struct i2c_device_id m62332_id[] = { - { "m62332", }, + { .name = "m62332" }, { } }; MODULE_DEVICE_TABLE(i2c, m62332_id); diff --git a/drivers/iio/dac/max22007.c b/drivers/iio/dac/max22007.c index 182ac7155a89..e2c7e2ad37ba 100644 --- a/drivers/iio/dac/max22007.c +++ b/drivers/iio/dac/max22007.c @@ -19,7 +19,6 @@ #include <linux/iio/iio.h> #include <linux/kstrtox.h> #include <linux/minmax.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/property.h> #include <linux/regmap.h> @@ -465,7 +464,7 @@ static int max22007_probe(struct spi_device *spi) } static const struct spi_device_id max22007_id[] = { - { "max22007" }, + { .name = "max22007" }, { } }; MODULE_DEVICE_TABLE(spi, max22007_id); diff --git a/drivers/iio/dac/max517.c b/drivers/iio/dac/max517.c index d334c67821ad..d2ddc72e0e50 100644 --- a/drivers/iio/dac/max517.c +++ b/drivers/iio/dac/max517.c @@ -187,11 +187,11 @@ static int max517_probe(struct i2c_client *client) } static const struct i2c_device_id max517_id[] = { - { "max517", ID_MAX517 }, - { "max518", ID_MAX518 }, - { "max519", ID_MAX519 }, - { "max520", ID_MAX520 }, - { "max521", ID_MAX521 }, + { .name = "max517", .driver_data = ID_MAX517 }, + { .name = "max518", .driver_data = ID_MAX518 }, + { .name = "max519", .driver_data = ID_MAX519 }, + { .name = "max520", .driver_data = ID_MAX520 }, + { .name = "max521", .driver_data = ID_MAX521 }, { } }; MODULE_DEVICE_TABLE(i2c, max517_id); diff --git a/drivers/iio/dac/max5522.c b/drivers/iio/dac/max5522.c index 1b8fe6b8d26e..f3415748c765 100644 --- a/drivers/iio/dac/max5522.c +++ b/drivers/iio/dac/max5522.c @@ -9,11 +9,11 @@ #include <linux/device.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> #include <linux/spi/spi.h> +#include <linux/units.h> #include <linux/iio/iio.h> @@ -24,17 +24,10 @@ #define MAX5522_REG_DATA(x) ((x) + MAX5522_CTRL_LOAD_IN_A) -struct max5522_chip_info { - const char *name; - const struct iio_chan_spec *channels; - unsigned int num_channels; -}; - struct max5522_state { struct regmap *regmap; - const struct max5522_chip_info *chip_info; unsigned short dac_cache[2]; - struct regulator *vrefin_reg; + int vref_mV; }; #define MAX5522_CHANNEL(chan) { \ @@ -57,18 +50,6 @@ static const struct iio_chan_spec max5522_channels[] = { MAX5522_CHANNEL(1), }; -enum max5522_type { - ID_MAX5522, -}; - -static const struct max5522_chip_info max5522_chip_info_tbl[] = { - [ID_MAX5522] = { - .name = "max5522", - .channels = max5522_channels, - .num_channels = 2, - }, -}; - static inline int max5522_info_to_reg(struct iio_chan_spec const *chan) { return MAX5522_REG_DATA(chan->channel); @@ -79,17 +60,13 @@ static int max5522_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long info) { struct max5522_state *state = iio_priv(indio_dev); - int ret; switch (info) { case IIO_CHAN_INFO_RAW: *val = state->dac_cache[chan->channel]; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - ret = regulator_get_voltage(state->vrefin_reg); - if (ret < 0) - return -EINVAL; - *val = ret / 1000; + *val = state->vref_mV; *val2 = 10; return IIO_VAL_FRACTIONAL_LOG2; default: @@ -143,20 +120,12 @@ static int max5522_spi_probe(struct spi_device *spi) } state = iio_priv(indio_dev); - state->chip_info = spi_get_device_match_data(spi); - if (!state->chip_info) - return -EINVAL; - state->vrefin_reg = devm_regulator_get(&spi->dev, "vrefin"); - if (IS_ERR(state->vrefin_reg)) - return dev_err_probe(&spi->dev, PTR_ERR(state->vrefin_reg), - "Vrefin regulator not specified\n"); - - ret = regulator_enable(state->vrefin_reg); - if (ret) { + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vrefin"); + if (ret < 0) return dev_err_probe(&spi->dev, ret, - "Failed to enable vref regulators\n"); - } + "Failed to get vrefin regulator\n"); + state->vref_mV = ret / (MICRO / MILLI); state->regmap = devm_regmap_init_spi(spi, &max5522_regmap_config); @@ -167,22 +136,19 @@ static int max5522_spi_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = max5522_channels; indio_dev->num_channels = ARRAY_SIZE(max5522_channels); - indio_dev->name = max5522_chip_info_tbl[ID_MAX5522].name; + indio_dev->name = "max5522"; return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id max5522_ids[] = { - { "max5522", (kernel_ulong_t)&max5522_chip_info_tbl[ID_MAX5522] }, + { .name = "max5522" }, { } }; MODULE_DEVICE_TABLE(spi, max5522_ids); static const struct of_device_id max5522_of_match[] = { - { - .compatible = "maxim,max5522", - .data = &max5522_chip_info_tbl[ID_MAX5522], - }, + { .compatible = "maxim,max5522" }, { } }; MODULE_DEVICE_TABLE(of, max5522_of_match); diff --git a/drivers/iio/dac/max5821.c b/drivers/iio/dac/max5821.c index e7e29359f8fe..45def245626b 100644 --- a/drivers/iio/dac/max5821.c +++ b/drivers/iio/dac/max5821.c @@ -26,10 +26,6 @@ #define MAX5821_EXTENDED_DAC_A 0x04 #define MAX5821_EXTENDED_DAC_B 0x08 -enum max5821_device_ids { - ID_MAX5821, -}; - struct max5821_data { struct i2c_client *client; unsigned short vref_mv; @@ -90,6 +86,7 @@ static int max5821_sync_powerdown_mode(struct max5821_data *data, const struct iio_chan_spec *chan) { u8 outbuf[2]; + int ret; outbuf[0] = MAX5821_EXTENDED_COMMAND_MODE; @@ -103,7 +100,13 @@ static int max5821_sync_powerdown_mode(struct max5821_data *data, else outbuf[1] |= MAX5821_EXTENDED_POWER_UP; - return i2c_master_send(data->client, outbuf, 2); + ret = i2c_master_send(data->client, outbuf, sizeof(outbuf)); + if (ret < 0) + return ret; + if (ret != sizeof(outbuf)) + return -EIO; + + return 0; } static ssize_t max5821_write_dac_powerdown(struct iio_dev *indio_dev, @@ -332,7 +335,7 @@ static int max5821_probe(struct i2c_client *client) } static const struct i2c_device_id max5821_id[] = { - { "max5821", ID_MAX5821 }, + { .name = "max5821" }, { } }; MODULE_DEVICE_TABLE(i2c, max5821_id); diff --git a/drivers/iio/dac/mcf54415_dac.c b/drivers/iio/dac/mcf54415_dac.c new file mode 100644 index 000000000000..e2c12241a534 --- /dev/null +++ b/drivers/iio/dac/mcf54415_dac.c @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * NXP mcf54415 DAC driver + * + * Copyright 2026 BayLibre - adureghello@baylibre.com + */ + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/types.h> + +#include <linux/iio/iio.h> + +#define MCF54415_DAC_CR 0x00 +#define MCF54415_DAC_CR_PDN BIT(0) +#define MCF54415_DAC_CR_HSLS BIT(6) +#define MCF54415_DAC_CR_WMLVL GENMASK(9, 8) +#define MCF54415_DAC_CR_FILT BIT(12) + +#define MCF54415_DAC_DATA 0x02 + +struct mcf54415_dac { + struct regmap *map; + struct clk *clk; +}; + +static const struct regmap_config mcf54415_dac_regmap_config = { + .reg_bits = 16, + .reg_stride = 2, + .val_bits = 16, + .max_register = 0x0c, /* DACX_FILTCNT, R.M. Table 30-2 */ + .val_format_endian = REGMAP_ENDIAN_BIG, + .reg_format_endian = REGMAP_ENDIAN_BIG, +}; + +static int mcf54415_dac_init(struct mcf54415_dac *info) +{ + u16 val = MCF54415_DAC_CR_FILT | FIELD_PREP(MCF54415_DAC_CR_WMLVL, 1); + int ret; + + /* Fixed defaults and enable DAC (bit 0 set to 0) */ + ret = regmap_write(info->map, MCF54415_DAC_CR, val); + if (ret) + return ret; + + /* DAC is ready after 12us, from RM table 40-3 */ + fsleep(12); + + return 0; +} + +static void mcf54415_dac_exit(void *data) +{ + struct mcf54415_dac *info = data; + + regmap_set_bits(info->map, MCF54415_DAC_CR, MCF54415_DAC_CR_PDN); +} + +static const struct iio_chan_spec mcf54415_dac_iio_channel = { + .type = IIO_VOLTAGE, + .output = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), +}; + +static int mcf54415_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct mcf54415_dac *info = iio_priv(indio_dev); + unsigned int reg; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = regmap_read(info->map, MCF54415_DAC_DATA, ®); + if (ret) + return ret; + *val = reg & GENMASK(11, 0); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + /* Reference voltage as per ColdFire datasheet is 3.3V */ + *val = 3300 /* mV */; + *val2 = 12; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } +} + +static int mcf54415_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct mcf54415_dac *info = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + /* Check based on RM 30.3.2 (DACn_DATA) reg. resolution */ + if (val < 0 || val > 4095) + return -EINVAL; + return regmap_write(info->map, MCF54415_DAC_DATA, val); + default: + return -EINVAL; + } +} + +static const struct iio_info mcf54415_dac_iio_info = { + .read_raw = &mcf54415_read_raw, + .write_raw = &mcf54415_write_raw, +}; + +static int mcf54415_dac_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct iio_dev *indio_dev; + struct mcf54415_dac *info; + void __iomem *regs; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*info)); + if (!indio_dev) + return -ENOMEM; + + info = iio_priv(indio_dev); + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) + return dev_err_probe(dev, PTR_ERR(regs), "failed to get io regs\n"); + + info->map = devm_regmap_init_mmio(dev, regs, &mcf54415_dac_regmap_config); + if (IS_ERR(info->map)) + return PTR_ERR(info->map); + + info->clk = devm_clk_get_enabled(dev, "dac"); + if (IS_ERR(info->clk)) + return dev_err_probe(dev, PTR_ERR(info->clk), "failed getting clock\n"); + + indio_dev->name = "mcf54415"; + indio_dev->info = &mcf54415_dac_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = &mcf54415_dac_iio_channel; + indio_dev->num_channels = 1; + + ret = mcf54415_dac_init(info); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, mcf54415_dac_exit, info); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct platform_device_id mcf54415_dac_ids[] = { + { .name = "mcfdac" }, + { } +}; +MODULE_DEVICE_TABLE(platform, mcf54415_dac_ids); + +static struct platform_driver mcf54415_dac_driver = { + .driver = { + .name = "mcf54415_dac", + }, + .probe = mcf54415_dac_probe, + .id_table = mcf54415_dac_ids, +}; +module_platform_driver(mcf54415_dac_driver); + +MODULE_AUTHOR("Angelo Dureghello <angelo@kernel-space.org>"); +MODULE_DESCRIPTION("NXP MCF54415 DAC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index 23b9e3a09ec8..3fa7acc69aeb 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -16,7 +16,6 @@ #include <linux/err.h> #include <linux/delay.h> #include <linux/regulator/consumer.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/iio/iio.h> @@ -523,8 +522,8 @@ static const struct mcp4725_chip_info mcp4726 = { }; static const struct i2c_device_id mcp4725_id[] = { - { "mcp4725", (kernel_ulong_t)&mcp4725 }, - { "mcp4726", (kernel_ulong_t)&mcp4726 }, + { .name = "mcp4725", .driver_data = (kernel_ulong_t)&mcp4725 }, + { .name = "mcp4726", .driver_data = (kernel_ulong_t)&mcp4726 }, { } }; MODULE_DEVICE_TABLE(i2c, mcp4725_id); diff --git a/drivers/iio/dac/mcp4728.c b/drivers/iio/dac/mcp4728.c index 4f30b99110b7..1fe184d49fc5 100644 --- a/drivers/iio/dac/mcp4728.c +++ b/drivers/iio/dac/mcp4728.c @@ -20,7 +20,6 @@ #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/regulator/consumer.h> @@ -572,7 +571,7 @@ static int mcp4728_probe(struct i2c_client *client) } static const struct i2c_device_id mcp4728_id[] = { - { "mcp4728" }, + { .name = "mcp4728" }, { } }; MODULE_DEVICE_TABLE(i2c, mcp4728_id); diff --git a/drivers/iio/dac/mcp47a1.c b/drivers/iio/dac/mcp47a1.c new file mode 100644 index 000000000000..0bf994aa0e4f --- /dev/null +++ b/drivers/iio/dac/mcp47a1.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Microchip MCP47A1 DAC driver + * + * Copyright (c) 2026 Joshua Crofts <joshua.crofts1@gmail.com> + * + * Datasheet: https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/25154A.pdf + */ + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/minmax.h> +#include <linux/module.h> +#include <linux/regulator/consumer.h> +#include <linux/types.h> +#include <linux/units.h> + +#include <linux/iio/iio.h> + +#define MCP47A1_CMD_CODE 0x00 +#define MCP47A1_MAX_STEPS 64 + +struct mcp47a1_data { + struct i2c_client *client; + int vref_mV; +}; + +static const int mcp47a1_raw_avail[] = { 0, 1, MCP47A1_MAX_STEPS - 1 }; + +static const struct iio_chan_spec mcp47a1_channel = { + .type = IIO_VOLTAGE, + .indexed = 1, + .output = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), +}; + +static int mcp47a1_write(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct mcp47a1_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (!in_range(val, 0, MCP47A1_MAX_STEPS)) + return -EINVAL; + + return i2c_smbus_write_byte_data(data->client, MCP47A1_CMD_CODE, + val); + default: + return -EINVAL; + } +} + +static int mcp47a1_read(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct mcp47a1_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = i2c_smbus_read_byte_data(data->client, MCP47A1_CMD_CODE); + if (ret < 0) + return ret; + + *val = ret; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = data->vref_mV; + *val2 = MCP47A1_MAX_STEPS; + + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } +} + +static int mcp47a1_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_RAW: + *vals = mcp47a1_raw_avail; + *type = IIO_VAL_INT; + return IIO_AVAIL_RANGE; + default: + return -EINVAL; + } +} + +static const struct iio_info mcp47a1_info = { + .write_raw = mcp47a1_write, + .read_raw = mcp47a1_read, + .read_avail = mcp47a1_read_avail, +}; + +static int mcp47a1_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct mcp47a1_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->client = client; + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable regulator\n"); + + /* Delay after device exits reset state (see AC/DC characteristics) */ + fsleep(20); + + ret = devm_regulator_get_enable_read_voltage(dev, "vref"); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to read vref\n"); + + data->vref_mV = ret / (MICRO / MILLI); + + indio_dev->name = "mcp47a1"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &mcp47a1_info; + indio_dev->channels = &mcp47a1_channel; + indio_dev->num_channels = 1; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id mcp47a1_of_match[] = { + { .compatible = "microchip,mcp47a1" }, + { } +}; +MODULE_DEVICE_TABLE(of, mcp47a1_of_match); + +static const struct i2c_device_id mcp47a1_id[] = { + { .name = "mcp47a1" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mcp47a1_id); + +static struct i2c_driver mcp47a1_driver = { + .driver = { + .name = "mcp47a1", + .of_match_table = mcp47a1_of_match, + }, + .probe = mcp47a1_probe, + .id_table = mcp47a1_id, +}; +module_i2c_driver(mcp47a1_driver); + +MODULE_AUTHOR("Joshua Crofts <joshua.crofts1@gmail.com>"); +MODULE_DESCRIPTION("Microchip MCP47A1 DAC Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/dac/mcp47feb02.c b/drivers/iio/dac/mcp47feb02.c index b218f0c3a0bd..8640b0ef4433 100644 --- a/drivers/iio/dac/mcp47feb02.c +++ b/drivers/iio/dac/mcp47feb02.c @@ -21,7 +21,6 @@ #include <linux/iio/sysfs.h> #include <linux/kstrtox.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/property.h> #include <linux/regmap.h> @@ -65,7 +64,7 @@ #define MCP47FEB02_MAX_SCALES_CH 3 #define MCP47FEB02_DAC_WIPER_UNLOCKED 0 #define MCP47FEB02_NORMAL_OPERATION 0 -#define MCP47FEB02_INTERNAL_BAND_GAP_mV 2440 +#define MCP47FEB02_INTERNAL_BAND_GAP_uV 2440000 #define NV_DAC_ADDR_OFFSET 0x10 enum mcp47feb02_vref_mode { @@ -697,44 +696,40 @@ static const struct iio_chan_spec mcp47febxx_ch_template = { }; static void mcp47feb02_init_scale(struct mcp47feb02_data *data, enum mcp47feb02_scale scale, - int vref_mV, int scale_avail[]) + int vref_uV, int scale_avail[]) { u32 value_micro, value_int; u64 tmp; - /* vref_mV should not be negative */ - tmp = (u64)vref_mV * MICRO >> data->chip_features->resolution; + /* vref_uV should not be negative */ + tmp = (u64)vref_uV * MILLI >> data->chip_features->resolution; value_int = div_u64_rem(tmp, MICRO, &value_micro); scale_avail[scale * 2] = value_int; scale_avail[scale * 2 + 1] = value_micro; } -static int mcp47feb02_init_scales_avail(struct mcp47feb02_data *data, int vdd_mV, - int vref_mV, int vref1_mV) +static int mcp47feb02_init_scales_avail(struct mcp47feb02_data *data, int vdd_uV, + int vref_uV, int vref1_uV) { - struct device *dev = regmap_get_device(data->regmap); int tmp_vref; - mcp47feb02_init_scale(data, MCP47FEB02_SCALE_VDD, vdd_mV, data->scale); + mcp47feb02_init_scale(data, MCP47FEB02_SCALE_VDD, vdd_uV, data->scale); if (data->use_vref) - tmp_vref = vref_mV; + tmp_vref = vref_uV; else - tmp_vref = MCP47FEB02_INTERNAL_BAND_GAP_mV; + tmp_vref = MCP47FEB02_INTERNAL_BAND_GAP_uV; mcp47feb02_init_scale(data, MCP47FEB02_SCALE_GAIN_X1, tmp_vref, data->scale); mcp47feb02_init_scale(data, MCP47FEB02_SCALE_GAIN_X2, tmp_vref * 2, data->scale); if (data->phys_channels >= 4) { - mcp47feb02_init_scale(data, MCP47FEB02_SCALE_VDD, vdd_mV, data->scale_1); - - if (data->use_vref1 && vref1_mV <= 0) - return dev_err_probe(dev, vref1_mV, "Invalid voltage for Vref1\n"); + mcp47feb02_init_scale(data, MCP47FEB02_SCALE_VDD, vdd_uV, data->scale_1); if (data->use_vref1) - tmp_vref = vref1_mV; + tmp_vref = vref1_uV; else - tmp_vref = MCP47FEB02_INTERNAL_BAND_GAP_mV; + tmp_vref = MCP47FEB02_INTERNAL_BAND_GAP_uV; mcp47feb02_init_scale(data, MCP47FEB02_SCALE_GAIN_X1, tmp_vref, data->scale_1); @@ -955,8 +950,6 @@ static int mcp47feb02_parse_fw(struct iio_dev *indio_dev, u32 num_channels; u8 chan_idx = 0; - guard(mutex)(&data->lock); - num_channels = device_get_child_node_count(dev); if (num_channels > chip_features->phys_channels) return dev_err_probe(dev, -EINVAL, "More channels than the chip supports\n"); @@ -1080,8 +1073,8 @@ static int mcp47feb02_init_ctrl_regs(struct mcp47feb02_data *data) return 0; } -static int mcp47feb02_init_ch_scales(struct mcp47feb02_data *data, int vdd_mV, - int vref_mV, int vref1_mV) +static int mcp47feb02_init_ch_scales(struct mcp47feb02_data *data, int vdd_uV, + int vref_uV, int vref1_uV) { unsigned int i; @@ -1089,7 +1082,7 @@ static int mcp47feb02_init_ch_scales(struct mcp47feb02_data *data, int vdd_mV, struct device *dev = regmap_get_device(data->regmap); int ret; - ret = mcp47feb02_init_scales_avail(data, vdd_mV, vref_mV, vref1_mV); + ret = mcp47feb02_init_scales_avail(data, vdd_uV, vref_uV, vref1_uV); if (ret) return dev_err_probe(dev, ret, "failed to init scales for ch %u\n", i); } @@ -1103,10 +1096,7 @@ static int mcp47feb02_probe(struct i2c_client *client) struct device *dev = &client->dev; struct mcp47feb02_data *data; struct iio_dev *indio_dev; - int vref1_mV = 0; - int vref_mV = 0; - int vdd_mV; - int ret; + int vref1_uV, vref_uV, vdd_uV, ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) @@ -1143,33 +1133,42 @@ static int mcp47feb02_probe(struct i2c_client *client) if (ret < 0) return ret; - vdd_mV = ret / MILLI; + vdd_uV = ret; + + if (device_property_present(dev, "vref-supply")) { + vref_uV = devm_regulator_get_enable_read_voltage(dev, "vref"); + if (vref_uV < 0) + return vref_uV; + + if (vref_uV == 0) + return dev_err_probe(dev, -EINVAL, "Vref is 0 uV.\n"); - ret = devm_regulator_get_enable_read_voltage(dev, "vref"); - if (ret > 0) { - vref_mV = ret / MILLI; data->use_vref = true; } else { - dev_dbg(dev, "using internal band gap as voltage reference.\n"); - dev_dbg(dev, "Vref is unavailable.\n"); + vref_uV = 0; + dev_dbg(dev, "Using internal band gap as voltage reference.\n"); } - if (chip_features->have_ext_vref1) { - ret = devm_regulator_get_enable_read_voltage(dev, "vref1"); - if (ret > 0) { - vref1_mV = ret / MILLI; - data->use_vref1 = true; - } else { - dev_dbg(dev, "using internal band gap as voltage reference 1.\n"); - dev_dbg(dev, "Vref1 is unavailable.\n"); - } + if (chip_features->have_ext_vref1 && + device_property_present(dev, "vref1-supply")) { + vref1_uV = devm_regulator_get_enable_read_voltage(dev, "vref1"); + if (vref1_uV < 0) + return vref1_uV; + + if (vref1_uV == 0) + return dev_err_probe(dev, -EINVAL, "Vref1 is 0 uV.\n"); + + data->use_vref1 = true; + } else { + vref1_uV = 0; + dev_dbg(dev, "Using internal band gap as voltage reference 1.\n"); } ret = mcp47feb02_init_ctrl_regs(data); if (ret) return dev_err_probe(dev, ret, "Error initialising vref register\n"); - ret = mcp47feb02_init_ch_scales(data, vdd_mV, vref_mV, vref1_mV); + ret = mcp47feb02_init_ch_scales(data, vdd_uV, vref_uV, vref1_uV); if (ret) return ret; @@ -1177,30 +1176,30 @@ static int mcp47feb02_probe(struct i2c_client *client) } static const struct i2c_device_id mcp47feb02_id[] = { - { "mcp47feb01", (kernel_ulong_t)&mcp47feb01_chip_features }, - { "mcp47feb02", (kernel_ulong_t)&mcp47feb02_chip_features }, - { "mcp47feb04", (kernel_ulong_t)&mcp47feb04_chip_features }, - { "mcp47feb08", (kernel_ulong_t)&mcp47feb08_chip_features }, - { "mcp47feb11", (kernel_ulong_t)&mcp47feb11_chip_features }, - { "mcp47feb12", (kernel_ulong_t)&mcp47feb12_chip_features }, - { "mcp47feb14", (kernel_ulong_t)&mcp47feb14_chip_features }, - { "mcp47feb18", (kernel_ulong_t)&mcp47feb18_chip_features }, - { "mcp47feb21", (kernel_ulong_t)&mcp47feb21_chip_features }, - { "mcp47feb22", (kernel_ulong_t)&mcp47feb22_chip_features }, - { "mcp47feb24", (kernel_ulong_t)&mcp47feb24_chip_features }, - { "mcp47feb28", (kernel_ulong_t)&mcp47feb28_chip_features }, - { "mcp47fvb01", (kernel_ulong_t)&mcp47fvb01_chip_features }, - { "mcp47fvb02", (kernel_ulong_t)&mcp47fvb02_chip_features }, - { "mcp47fvb04", (kernel_ulong_t)&mcp47fvb04_chip_features }, - { "mcp47fvb08", (kernel_ulong_t)&mcp47fvb08_chip_features }, - { "mcp47fvb11", (kernel_ulong_t)&mcp47fvb11_chip_features }, - { "mcp47fvb12", (kernel_ulong_t)&mcp47fvb12_chip_features }, - { "mcp47fvb14", (kernel_ulong_t)&mcp47fvb14_chip_features }, - { "mcp47fvb18", (kernel_ulong_t)&mcp47fvb18_chip_features }, - { "mcp47fvb21", (kernel_ulong_t)&mcp47fvb21_chip_features }, - { "mcp47fvb22", (kernel_ulong_t)&mcp47fvb22_chip_features }, - { "mcp47fvb24", (kernel_ulong_t)&mcp47fvb24_chip_features }, - { "mcp47fvb28", (kernel_ulong_t)&mcp47fvb28_chip_features }, + { .name = "mcp47feb01", .driver_data = (kernel_ulong_t)&mcp47feb01_chip_features }, + { .name = "mcp47feb02", .driver_data = (kernel_ulong_t)&mcp47feb02_chip_features }, + { .name = "mcp47feb04", .driver_data = (kernel_ulong_t)&mcp47feb04_chip_features }, + { .name = "mcp47feb08", .driver_data = (kernel_ulong_t)&mcp47feb08_chip_features }, + { .name = "mcp47feb11", .driver_data = (kernel_ulong_t)&mcp47feb11_chip_features }, + { .name = "mcp47feb12", .driver_data = (kernel_ulong_t)&mcp47feb12_chip_features }, + { .name = "mcp47feb14", .driver_data = (kernel_ulong_t)&mcp47feb14_chip_features }, + { .name = "mcp47feb18", .driver_data = (kernel_ulong_t)&mcp47feb18_chip_features }, + { .name = "mcp47feb21", .driver_data = (kernel_ulong_t)&mcp47feb21_chip_features }, + { .name = "mcp47feb22", .driver_data = (kernel_ulong_t)&mcp47feb22_chip_features }, + { .name = "mcp47feb24", .driver_data = (kernel_ulong_t)&mcp47feb24_chip_features }, + { .name = "mcp47feb28", .driver_data = (kernel_ulong_t)&mcp47feb28_chip_features }, + { .name = "mcp47fvb01", .driver_data = (kernel_ulong_t)&mcp47fvb01_chip_features }, + { .name = "mcp47fvb02", .driver_data = (kernel_ulong_t)&mcp47fvb02_chip_features }, + { .name = "mcp47fvb04", .driver_data = (kernel_ulong_t)&mcp47fvb04_chip_features }, + { .name = "mcp47fvb08", .driver_data = (kernel_ulong_t)&mcp47fvb08_chip_features }, + { .name = "mcp47fvb11", .driver_data = (kernel_ulong_t)&mcp47fvb11_chip_features }, + { .name = "mcp47fvb12", .driver_data = (kernel_ulong_t)&mcp47fvb12_chip_features }, + { .name = "mcp47fvb14", .driver_data = (kernel_ulong_t)&mcp47fvb14_chip_features }, + { .name = "mcp47fvb18", .driver_data = (kernel_ulong_t)&mcp47fvb18_chip_features }, + { .name = "mcp47fvb21", .driver_data = (kernel_ulong_t)&mcp47fvb21_chip_features }, + { .name = "mcp47fvb22", .driver_data = (kernel_ulong_t)&mcp47fvb22_chip_features }, + { .name = "mcp47fvb24", .driver_data = (kernel_ulong_t)&mcp47fvb24_chip_features }, + { .name = "mcp47fvb28", .driver_data = (kernel_ulong_t)&mcp47fvb28_chip_features }, { } }; MODULE_DEVICE_TABLE(i2c, mcp47feb02_id); diff --git a/drivers/iio/dac/mcp4821.c b/drivers/iio/dac/mcp4821.c index 748bdca9a964..8d8c00cd60e9 100644 --- a/drivers/iio/dac/mcp4821.c +++ b/drivers/iio/dac/mcp4821.c @@ -12,13 +12,12 @@ * MCP48x2: https://ww1.microchip.com/downloads/en/DeviceDoc/20002249B.pdf * * TODO: - * - Configurable gain * - Regulator control */ #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/spi/spi.h> +#include <linux/units.h> #include <linux/iio/iio.h> #include <linux/iio/types.h> @@ -26,12 +25,32 @@ #include <linux/unaligned.h> #define MCP4821_ACTIVE_MODE BIT(12) +#define MCP4821_GAIN_ENABLE BIT(13) #define MCP4802_SECOND_CHAN BIT(15) -/* DAC uses an internal Voltage reference of 4.096V at a gain of 2x */ -#define MCP4821_2X_GAIN_VREF_MV 4096 +/* DAC uses an internal Voltage reference of 2.048V */ +#define MCP4821_VREF_MV 2048 -enum mcp4821_supported_drvice_ids { +/* + * MCP48xx DAC output: + * + * Vout = (Vref * D / 2^N) * G + * + * where: + * - Vref = 2.048V (internal reference) + * - N = DAC resolution (12 bits for MCP4821) + * - G = gain selection: + * 1x when GA bit = 1 + * 2x when GA bit = 0 (default) + * + * Therefore full-scale voltage is: + * - 1x gain: 2.048V + * - 2x gain: 4.096V + * + * Scale = Vfull-scale / 2^N + */ + +enum mcp4821_supported_device_ids { ID_MCP4801, ID_MCP4802, ID_MCP4811, @@ -43,6 +62,8 @@ enum mcp4821_supported_drvice_ids { struct mcp4821_state { struct spi_device *spi; u16 dac_value[2]; + int gain; + int scale_avail[4]; }; struct mcp4821_chip_info { @@ -57,6 +78,7 @@ struct mcp4821_chip_info { .channel = (channel_id), \ .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_type = { \ .realbits = (resolution), \ .shift = 12 - (resolution), \ @@ -115,15 +137,15 @@ static int mcp4821_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { - struct mcp4821_state *state; + struct mcp4821_state *state = iio_priv(indio_dev); switch (mask) { case IIO_CHAN_INFO_RAW: - state = iio_priv(indio_dev); *val = state->dac_value[chan->channel]; return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: - *val = MCP4821_2X_GAIN_VREF_MV; + *val = MCP4821_VREF_MV * state->gain; *val2 = chan->scan_type.realbits; return IIO_VAL_FRACTIONAL_LOG2; default: @@ -131,6 +153,17 @@ static int mcp4821_read_raw(struct iio_dev *indio_dev, } } +static void mcp4821_calc_scale(int vref_mv, int resolution, + int *val, int *val2) +{ + s64 tmp; + int micro; + + tmp = (s64)vref_mv * MICRO >> resolution; + *val = div_s64_rem(tmp, MICRO, µ); + *val2 = micro; +} + static int mcp4821_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) @@ -139,35 +172,85 @@ static int mcp4821_write_raw(struct iio_dev *indio_dev, u16 write_val; __be16 write_buffer; int ret; + int v, v2; - if (val2 != 0) - return -EINVAL; + switch (mask) { + case IIO_CHAN_INFO_RAW: - if (val < 0 || val >= BIT(chan->scan_type.realbits)) - return -EINVAL; + if (val2 != 0) + return -EINVAL; - if (mask != IIO_CHAN_INFO_RAW) - return -EINVAL; + if (val < 0 || val >= BIT(chan->scan_type.realbits)) + return -EINVAL; - write_val = MCP4821_ACTIVE_MODE | val << chan->scan_type.shift; - if (chan->channel) - write_val |= MCP4802_SECOND_CHAN; + write_val = MCP4821_ACTIVE_MODE | val << chan->scan_type.shift; + if (chan->channel) + write_val |= MCP4802_SECOND_CHAN; - write_buffer = cpu_to_be16(write_val); - ret = spi_write(state->spi, &write_buffer, sizeof(write_buffer)); - if (ret) { - dev_err(&state->spi->dev, "Failed to write to device: %d", ret); - return ret; + /* GA bit = 1 -> 1x gain */ + if (state->gain == 1) + write_val |= MCP4821_GAIN_ENABLE; + + write_buffer = cpu_to_be16(write_val); + ret = spi_write(state->spi, &write_buffer, sizeof(write_buffer)); + if (ret) { + dev_err(&state->spi->dev, "Failed to write to device: %d", ret); + return ret; + } + + state->dac_value[chan->channel] = val; + return 0; + + case IIO_CHAN_INFO_SCALE: + mcp4821_calc_scale(MCP4821_VREF_MV, chan->scan_type.realbits, &v, &v2); + if (val == v && val2 == v2) { + state->gain = 1; + return 0; + } + + mcp4821_calc_scale(MCP4821_VREF_MV * 2, + chan->scan_type.realbits, &v, &v2); + if (val == v && val2 == v2) { + state->gain = 2; + return 0; + } + return -EINVAL; + default: + return -EINVAL; } +} - state->dac_value[chan->channel] = val; +static inline void mcp4821_init_avail_gain(struct mcp4821_state *state, + int resolution) +{ + state->scale_avail[0] = MCP4821_VREF_MV; + state->scale_avail[1] = resolution; + state->scale_avail[2] = MCP4821_VREF_MV * 2; + state->scale_avail[3] = resolution; +} + +static int mcp4821_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long info) +{ + struct mcp4821_state *state = iio_priv(indio_dev); - return 0; + switch (info) { + case IIO_CHAN_INFO_SCALE: + *vals = state->scale_avail; + *type = IIO_VAL_FRACTIONAL_LOG2; + *length = ARRAY_SIZE(state->scale_avail); + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } } static const struct iio_info mcp4821_info = { .read_raw = &mcp4821_read_raw, .write_raw = &mcp4821_write_raw, + .read_avail = &mcp4821_read_avail, }; static int mcp4821_probe(struct spi_device *spi) @@ -183,12 +266,15 @@ static int mcp4821_probe(struct spi_device *spi) state = iio_priv(indio_dev); state->spi = spi; + /* default gain is 2x */ + state->gain = 2; info = spi_get_device_match_data(spi); indio_dev->name = info->name; indio_dev->info = &mcp4821_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = info->channels; indio_dev->num_channels = info->num_channels; + mcp4821_init_avail_gain(state, info->channels[0].scan_type.realbits); return devm_iio_device_register(&spi->dev, indio_dev); } @@ -211,12 +297,12 @@ static const struct of_device_id mcp4821_of_table[] = { MODULE_DEVICE_TABLE(of, mcp4821_of_table); static const struct spi_device_id mcp4821_id_table[] = { - { "mcp4801", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4801]}, - { "mcp4802", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4802]}, - { "mcp4811", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4811]}, - { "mcp4812", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4812]}, - { "mcp4821", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4821]}, - { "mcp4822", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4822]}, + { .name = "mcp4801", .driver_data = (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4801] }, + { .name = "mcp4802", .driver_data = (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4802] }, + { .name = "mcp4811", .driver_data = (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4811] }, + { .name = "mcp4812", .driver_data = (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4812] }, + { .name = "mcp4821", .driver_data = (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4821] }, + { .name = "mcp4822", .driver_data = (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4822] }, { } }; MODULE_DEVICE_TABLE(spi, mcp4821_id_table); diff --git a/drivers/iio/dac/mcp4922.c b/drivers/iio/dac/mcp4922.c index 74f338afcab9..15072a9081ff 100644 --- a/drivers/iio/dac/mcp4922.c +++ b/drivers/iio/dac/mcp4922.c @@ -157,10 +157,10 @@ static int mcp4922_probe(struct spi_device *spi) static const struct spi_device_id mcp4922_id[] = { - {"mcp4902", ID_MCP4902}, - {"mcp4912", ID_MCP4912}, - {"mcp4921", ID_MCP4921}, - {"mcp4922", ID_MCP4922}, + { .name = "mcp4902", .driver_data = ID_MCP4902 }, + { .name = "mcp4912", .driver_data = ID_MCP4912 }, + { .name = "mcp4921", .driver_data = ID_MCP4921 }, + { .name = "mcp4922", .driver_data = ID_MCP4922 }, { } }; MODULE_DEVICE_TABLE(spi, mcp4922_id); diff --git a/drivers/iio/dac/rohm-bd79703.c b/drivers/iio/dac/rohm-bd79703.c index e91090e4a66d..6e2e7787f8a4 100644 --- a/drivers/iio/dac/rohm-bd79703.c +++ b/drivers/iio/dac/rohm-bd79703.c @@ -214,10 +214,10 @@ static int bd79703_probe(struct spi_device *spi) } static const struct spi_device_id bd79703_id[] = { - { "bd79700", (kernel_ulong_t)&bd79700_chip_data }, - { "bd79701", (kernel_ulong_t)&bd79701_chip_data }, - { "bd79702", (kernel_ulong_t)&bd79702_chip_data }, - { "bd79703", (kernel_ulong_t)&bd79703_chip_data }, + { .name = "bd79700", .driver_data = (kernel_ulong_t)&bd79700_chip_data }, + { .name = "bd79701", .driver_data = (kernel_ulong_t)&bd79701_chip_data }, + { .name = "bd79702", .driver_data = (kernel_ulong_t)&bd79702_chip_data }, + { .name = "bd79703", .driver_data = (kernel_ulong_t)&bd79703_chip_data }, { } }; MODULE_DEVICE_TABLE(spi, bd79703_id); diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c index 8ef702917060..b5795c14f0fe 100644 --- a/drivers/iio/dac/stm32-dac-core.c +++ b/drivers/iio/dac/stm32-dac-core.c @@ -9,7 +9,6 @@ #include <linux/clk.h> #include <linux/delay.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/of_platform.h> #include <linux/platform_device.h> diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c index b860e18d52a1..99438f6d4700 100644 --- a/drivers/iio/dac/stm32-dac.c +++ b/drivers/iio/dac/stm32-dac.c @@ -13,7 +13,6 @@ #include <linux/kernel.h> #include <linux/kstrtox.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> diff --git a/drivers/iio/dac/ti-dac082s085.c b/drivers/iio/dac/ti-dac082s085.c index 715870c8a9c4..afa7d9bad5de 100644 --- a/drivers/iio/dac/ti-dac082s085.c +++ b/drivers/iio/dac/ti-dac082s085.c @@ -14,7 +14,6 @@ #include <linux/iio/iio.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> @@ -335,12 +334,12 @@ static const struct of_device_id ti_dac_of_id[] = { MODULE_DEVICE_TABLE(of, ti_dac_of_id); static const struct spi_device_id ti_dac_spi_id[] = { - { "dac082s085", dual_8bit }, - { "dac102s085", dual_10bit }, - { "dac122s085", dual_12bit }, - { "dac084s085", quad_8bit }, - { "dac104s085", quad_10bit }, - { "dac124s085", quad_12bit }, + { .name = "dac082s085", .driver_data = dual_8bit }, + { .name = "dac102s085", .driver_data = dual_10bit }, + { .name = "dac122s085", .driver_data = dual_12bit }, + { .name = "dac084s085", .driver_data = quad_8bit }, + { .name = "dac104s085", .driver_data = quad_10bit }, + { .name = "dac124s085", .driver_data = quad_12bit }, { } }; MODULE_DEVICE_TABLE(spi, ti_dac_spi_id); diff --git a/drivers/iio/dac/ti-dac5571.c b/drivers/iio/dac/ti-dac5571.c index bdc3f94aef98..78fd5fa42db6 100644 --- a/drivers/iio/dac/ti-dac5571.c +++ b/drivers/iio/dac/ti-dac5571.c @@ -20,7 +20,6 @@ #include <linux/iio/iio.h> #include <linux/i2c.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/regulator/consumer.h> @@ -45,7 +44,6 @@ static const struct dac5571_spec dac5571_spec[] = { struct dac5571_data { struct i2c_client *client; - int id; struct mutex lock; struct regulator *vref; u16 val[4]; @@ -403,17 +401,17 @@ static const struct of_device_id dac5571_of_id[] = { MODULE_DEVICE_TABLE(of, dac5571_of_id); static const struct i2c_device_id dac5571_id[] = { - {"dac081c081", (kernel_ulong_t)&dac5571_spec[single_8bit] }, - {"dac121c081", (kernel_ulong_t)&dac5571_spec[single_12bit] }, - {"dac5571", (kernel_ulong_t)&dac5571_spec[single_8bit] }, - {"dac6571", (kernel_ulong_t)&dac5571_spec[single_10bit] }, - {"dac7571", (kernel_ulong_t)&dac5571_spec[single_12bit] }, - {"dac5574", (kernel_ulong_t)&dac5571_spec[quad_8bit] }, - {"dac6574", (kernel_ulong_t)&dac5571_spec[quad_10bit] }, - {"dac7574", (kernel_ulong_t)&dac5571_spec[quad_12bit] }, - {"dac5573", (kernel_ulong_t)&dac5571_spec[quad_8bit] }, - {"dac6573", (kernel_ulong_t)&dac5571_spec[quad_10bit] }, - {"dac7573", (kernel_ulong_t)&dac5571_spec[quad_12bit] }, + { .name = "dac081c081", .driver_data = (kernel_ulong_t)&dac5571_spec[single_8bit] }, + { .name = "dac121c081", .driver_data = (kernel_ulong_t)&dac5571_spec[single_12bit] }, + { .name = "dac5571", .driver_data = (kernel_ulong_t)&dac5571_spec[single_8bit] }, + { .name = "dac6571", .driver_data = (kernel_ulong_t)&dac5571_spec[single_10bit] }, + { .name = "dac7571", .driver_data = (kernel_ulong_t)&dac5571_spec[single_12bit] }, + { .name = "dac5574", .driver_data = (kernel_ulong_t)&dac5571_spec[quad_8bit] }, + { .name = "dac6574", .driver_data = (kernel_ulong_t)&dac5571_spec[quad_10bit] }, + { .name = "dac7574", .driver_data = (kernel_ulong_t)&dac5571_spec[quad_12bit] }, + { .name = "dac5573", .driver_data = (kernel_ulong_t)&dac5571_spec[quad_8bit] }, + { .name = "dac6573", .driver_data = (kernel_ulong_t)&dac5571_spec[quad_10bit] }, + { .name = "dac7573", .driver_data = (kernel_ulong_t)&dac5571_spec[quad_12bit] }, { } }; MODULE_DEVICE_TABLE(i2c, dac5571_id); diff --git a/drivers/iio/dac/ti-dac7311.c b/drivers/iio/dac/ti-dac7311.c index 5c1c5213962f..e5843bd35259 100644 --- a/drivers/iio/dac/ti-dac7311.c +++ b/drivers/iio/dac/ti-dac7311.c @@ -311,9 +311,9 @@ static const struct of_device_id ti_dac_of_id[] = { MODULE_DEVICE_TABLE(of, ti_dac_of_id); static const struct spi_device_id ti_dac_spi_id[] = { - { "dac5311", ID_DAC5311 }, - { "dac6311", ID_DAC6311 }, - { "dac7311", ID_DAC7311 }, + { .name = "dac5311", .driver_data = ID_DAC5311 }, + { .name = "dac6311", .driver_data = ID_DAC6311 }, + { .name = "dac7311", .driver_data = ID_DAC7311 }, { } }; MODULE_DEVICE_TABLE(spi, ti_dac_spi_id); diff --git a/drivers/iio/dac/ti-dac7612.c b/drivers/iio/dac/ti-dac7612.c index c308eca02b88..9065663cd609 100644 --- a/drivers/iio/dac/ti-dac7612.c +++ b/drivers/iio/dac/ti-dac7612.c @@ -165,7 +165,7 @@ static int dac7612_probe(struct spi_device *spi) } static const struct spi_device_id dac7612_id[] = { - {"ti-dac7612"}, + { .name = "ti-dac7612" }, { } }; MODULE_DEVICE_TABLE(spi, dac7612_id); diff --git a/drivers/iio/dac/vf610_dac.c b/drivers/iio/dac/vf610_dac.c index 93639599b2b9..3aa22fecd308 100644 --- a/drivers/iio/dac/vf610_dac.c +++ b/drivers/iio/dac/vf610_dac.c @@ -10,7 +10,6 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> diff --git a/drivers/iio/filter/admv8818.c b/drivers/iio/filter/admv8818.c index 19f823446cda..b88689e60cc8 100644 --- a/drivers/iio/filter/admv8818.c +++ b/drivers/iio/filter/admv8818.c @@ -11,7 +11,6 @@ #include <linux/device.h> #include <linux/iio/iio.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/notifier.h> #include <linux/property.h> @@ -657,56 +656,49 @@ static void admv8818_clk_disable(void *data) static int admv8818_init(struct admv8818_state *st) { int ret; - struct spi_device *spi = st->spi; + struct device *dev = &st->spi->dev; unsigned int chip_id; ret = regmap_write(st->regmap, ADMV8818_REG_SPI_CONFIG_A, ADMV8818_SOFTRESET_N_MSK | ADMV8818_SOFTRESET_MSK); - if (ret) { - dev_err(&spi->dev, "ADMV8818 Soft Reset failed.\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "ADMV8818 Soft Reset failed.\n"); ret = regmap_write(st->regmap, ADMV8818_REG_SPI_CONFIG_A, ADMV8818_SDOACTIVE_N_MSK | ADMV8818_SDOACTIVE_MSK); - if (ret) { - dev_err(&spi->dev, "ADMV8818 SDO Enable failed.\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "ADMV8818 SDO Enable failed.\n"); ret = regmap_read(st->regmap, ADMV8818_REG_CHIPTYPE, &chip_id); - if (ret) { - dev_err(&spi->dev, "ADMV8818 Chip ID read failed.\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "ADMV8818 Chip ID read failed.\n"); - if (chip_id != 0x1) { - dev_err(&spi->dev, "ADMV8818 Invalid Chip ID.\n"); - return -EINVAL; - } + if (chip_id != 0x1) + return dev_err_probe(dev, -EINVAL, + "ADMV8818 Invalid Chip ID.\n"); ret = regmap_update_bits(st->regmap, ADMV8818_REG_SPI_CONFIG_B, ADMV8818_SINGLE_INSTRUCTION_MSK, FIELD_PREP(ADMV8818_SINGLE_INSTRUCTION_MSK, 1)); - if (ret) { - dev_err(&spi->dev, "ADMV8818 Single Instruction failed.\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "ADMV8818 Single Instruction failed.\n"); if (st->clkin) return admv8818_rfin_band_select(st); - else - return 0; + + return 0; } static int admv8818_clk_setup(struct admv8818_state *st) { - struct spi_device *spi = st->spi; + struct device *dev = &st->spi->dev; int ret; - st->clkin = devm_clk_get_optional(&spi->dev, "rf_in"); + st->clkin = devm_clk_get_optional(dev, "rf_in"); if (IS_ERR(st->clkin)) - return dev_err_probe(&spi->dev, PTR_ERR(st->clkin), + return dev_err_probe(dev, PTR_ERR(st->clkin), "failed to get the input clock\n"); else if (!st->clkin) return 0; @@ -715,7 +707,7 @@ static int admv8818_clk_setup(struct admv8818_state *st) if (ret) return ret; - ret = devm_add_action_or_reset(&spi->dev, admv8818_clk_disable, st); + ret = devm_add_action_or_reset(dev, admv8818_clk_disable, st); if (ret) return ret; @@ -724,16 +716,16 @@ static int admv8818_clk_setup(struct admv8818_state *st) if (ret < 0) return ret; - return devm_add_action_or_reset(&spi->dev, admv8818_clk_notifier_unreg, st); + return devm_add_action_or_reset(dev, admv8818_clk_notifier_unreg, st); } static int admv8818_read_properties(struct admv8818_state *st) { - struct spi_device *spi = st->spi; + struct device *dev = &st->spi->dev; u32 mhz; int ret; - ret = device_property_read_u32(&spi->dev, "adi,lpf-margin-mhz", &mhz); + ret = device_property_read_u32(dev, "adi,lpf-margin-mhz", &mhz); if (ret == 0) st->lpf_margin_hz = (u64)mhz * HZ_PER_MHZ; else if (ret == -EINVAL) @@ -742,7 +734,7 @@ static int admv8818_read_properties(struct admv8818_state *st) return ret; - ret = device_property_read_u32(&spi->dev, "adi,hpf-margin-mhz", &mhz); + ret = device_property_read_u32(dev, "adi,hpf-margin-mhz", &mhz); if (ret == 0) st->hpf_margin_hz = (u64)mhz * HZ_PER_MHZ; else if (ret == -EINVAL) @@ -758,9 +750,10 @@ static int admv8818_probe(struct spi_device *spi) struct iio_dev *indio_dev; struct regmap *regmap; struct admv8818_state *st; + struct device *dev = &spi->dev; int ret; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; @@ -792,11 +785,11 @@ static int admv8818_probe(struct spi_device *spi) if (ret) return ret; - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct spi_device_id admv8818_id[] = { - { "admv8818", 0 }, + { .name = "admv8818" }, { } }; MODULE_DEVICE_TABLE(spi, admv8818_id); diff --git a/drivers/iio/flow/Kconfig b/drivers/iio/flow/Kconfig new file mode 100644 index 000000000000..e0e1a8e3654a --- /dev/null +++ b/drivers/iio/flow/Kconfig @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Liquid / gas flow sensor drivers +# +# When adding new entries keep the list in alphabetical order + +menu "Flow sensors" + +config SENSIRION_SLF3S + tristate "Sensirion SLF3S liquid flow sensor" + depends on I2C + select CRC8 + help + Say yes here to build support for the Sensirion SLF3S family of + digital liquid-flow sensors (SLF3S-0600F, SLF3S-1300F and + SLF3S-4000B). The driver reports the volumetric flow rate and the + embedded temperature reading via the standard IIO interface. + + To compile this driver as a module, choose M here: the module + will be called slf3s. + +endmenu diff --git a/drivers/iio/flow/Makefile b/drivers/iio/flow/Makefile new file mode 100644 index 000000000000..3cf4ab95c69c --- /dev/null +++ b/drivers/iio/flow/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for industrial I/O flow sensor drivers +# + +# When adding new entries keep the list in alphabetical order +obj-$(CONFIG_SENSIRION_SLF3S) += slf3s.o diff --git a/drivers/iio/flow/slf3s.c b/drivers/iio/flow/slf3s.c new file mode 100644 index 000000000000..dfa7c1409045 --- /dev/null +++ b/drivers/iio/flow/slf3s.c @@ -0,0 +1,542 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sensirion SLF3S liquid flow sensor driver. + * + * Supports the SLF3S-0600F, SLF3S-1300F and SLF3S-4000B liquid-flow + * sensors over I2C. Each measurement frame returns a 16-bit signed + * flow value, a 16-bit signed temperature value and a status word, + * each protected by a CRC-8 byte. + * + * The active calibration medium (water or isopropyl alcohol) is + * runtime-switchable via the in_volumeflow_medium sysfs attribute and + * defaults to water. + * + * Datasheet: https://sensirion.com/products/catalog/SLF3S-0600F/ + * + * Copyright (C) 2026 CMBlu Energy GmbH + * Author: Wadim Mueller <wafgo01@gmail.com> + */ + +#include <linux/array_size.h> +#include <linux/bitops.h> +#include <linux/cleanup.h> +#include <linux/crc8.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/i2c.h> +#include <linux/math.h> +#include <linux/math64.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/pm.h> +#include <linux/regulator/consumer.h> +#include <linux/types.h> +#include <linux/unaligned.h> +#include <linux/units.h> + +#include <linux/iio/iio.h> + +#define SLF3S_CRC8_POLY 0x31 +#define SLF3S_CRC8_INIT 0xff + +#define SLF3S_PRODUCT_ID_LEN 18 +#define SLF3S_PRODUCT_FAMILY_BYTE 1 +#define SLF3S_PRODUCT_SUBTYPE_BYTE 3 +#define SLF3S_PRODUCT_FAMILY_ID 0x03 + +/* Datasheet section 2.2: tPU = 25 ms max from power-on to first cmd. */ +#define SLF3S_POWER_UP_DELAY_US (25 * USEC_PER_MSEC) +/* Datasheet section 2.2: tw = 60 ms typical until first valid sample. */ +#define SLF3S_MEAS_START_DELAY_US (60 * USEC_PER_MSEC) + +static const u8 slf3s_cmd_prep_pid[] = { 0x36, 0x7c }; +static const u8 slf3s_cmd_read_pid[] = { 0xe1, 0x02 }; +static const u8 slf3s_cmd_start_water[] = { 0x36, 0x08 }; +static const u8 slf3s_cmd_start_ipa[] = { 0x36, 0x15 }; +static const u8 slf3s_cmd_stop_meas[] = { 0x3f, 0xf9 }; + +enum slf3s_medium { + SLF3S_MEDIUM_WATER, + SLF3S_MEDIUM_IPA, +}; + +static const char * const slf3s_medium_modes[] = { + [SLF3S_MEDIUM_WATER] = "water", + [SLF3S_MEDIUM_IPA] = "ipa", +}; + +enum slf3s_variant_id { + SLF3S_0600F, + SLF3S_1300F, + SLF3S_4000B, +}; + +/** + * struct slf3s_variant - per-variant calibration constants + * @sub_type: product-info sub-type byte returned by the sensor + * @name: name reported via @iio_dev.name + * @scale: flow scale in l/s per LSB + */ +struct slf3s_variant { + u8 sub_type; + const char *name; + struct s32_fract scale; +}; + +static const struct slf3s_variant slf3s_variants[] = { + [SLF3S_0600F] = { + .sub_type = 0x03, + .name = "slf3s-0600f", + .scale = { .numerator = 1, .denominator = 600 * MICRO }, + }, + [SLF3S_1300F] = { + .sub_type = 0x02, + .name = "slf3s-1300f", + .scale = { .numerator = 1, .denominator = 30 * MICRO }, + }, + [SLF3S_4000B] = { + .sub_type = 0x05, + .name = "slf3s-4000b", + .scale = { .numerator = 1, .denominator = 1920 * MILLI }, + }, +}; + +/** + * struct slf3s_data - per-device state + * @client: I2C client this instance is bound to + * @vdd: supply regulator, disabled while suspended + * @variant: pointer into @slf3s_variants for the detected device + * @medium: currently active calibration medium + * @lock: serialises the multi-step command/response exchanges + * @crc_table: pre-computed CRC-8 lookup table for SLF3S_CRC8_POLY + */ +struct slf3s_data { + struct i2c_client *client; + struct regulator *vdd; + const struct slf3s_variant *variant; + enum slf3s_medium medium; + struct mutex lock; + u8 crc_table[CRC8_TABLE_SIZE]; +}; + +static int slf3s_send_cmd(struct i2c_client *client, const u8 *cmd) +{ + int ret; + + ret = i2c_master_send(client, cmd, 2); + if (ret < 0) + return ret; + if (ret != 2) + return -EIO; + + return 0; +} + +/* Start continuous measurement and wait until the first sample is valid. */ +static int slf3s_start_meas(struct slf3s_data *sf, enum slf3s_medium medium) +{ + const u8 *cmd = (medium == SLF3S_MEDIUM_IPA) ? slf3s_cmd_start_ipa + : slf3s_cmd_start_water; + int ret; + + ret = slf3s_send_cmd(sf->client, cmd); + if (ret) + return ret; + + fsleep(SLF3S_MEAS_START_DELAY_US); + + return 0; +} + +static bool slf3s_crc_valid(const struct slf3s_data *sf, const u8 *block) +{ + return crc8(sf->crc_table, block, 2, SLF3S_CRC8_INIT) == block[2]; +} + +/* + * Read the product-info block and pick the matching variant. The + * sub-type byte returned by the sensor is the source of truth; a + * DT-supplied compatible only seeds an initial guess and is overridden + * on mismatch (with an informational message so misconfigured device + * trees are easy to spot). + * + * Bus / CRC failures are real errors and fail probe. An unknown + * sub-type byte falls back to the variant named in the device tree / + * I2C table, so a drop-in replacement part that lists one of the known + * compatibles keeps working on an older kernel that does not know its + * sub-type yet. Without any match data probe fails since no + * meaningful scale can be published. + */ +static int slf3s_detect_variant(struct slf3s_data *sf) +{ + struct i2c_client *client = sf->client; + u8 buf[SLF3S_PRODUCT_ID_LEN]; + int ret; + + ret = slf3s_send_cmd(client, slf3s_cmd_prep_pid); + if (ret) + return ret; + + ret = slf3s_send_cmd(client, slf3s_cmd_read_pid); + if (ret) + return ret; + + ret = i2c_master_recv(client, buf, sizeof(buf)); + if (ret < 0) + return ret; + if (ret != sizeof(buf)) + return -EIO; + + for (unsigned int i = 0; i < SLF3S_PRODUCT_ID_LEN; i += 3) { + if (!slf3s_crc_valid(sf, &buf[i])) + return -EIO; + } + + if (buf[SLF3S_PRODUCT_FAMILY_BYTE] != SLF3S_PRODUCT_FAMILY_ID) + dev_info(&client->dev, + "unexpected family byte 0x%02x (expected 0x%02x)\n", + buf[SLF3S_PRODUCT_FAMILY_BYTE], + SLF3S_PRODUCT_FAMILY_ID); + + for (unsigned int i = 0; i < ARRAY_SIZE(slf3s_variants); i++) { + if (buf[SLF3S_PRODUCT_SUBTYPE_BYTE] != + slf3s_variants[i].sub_type) + continue; + + if (sf->variant && sf->variant != &slf3s_variants[i]) + dev_info(&client->dev, + "DT compatible says %s but sensor reports %s; using the latter\n", + sf->variant->name, + slf3s_variants[i].name); + + sf->variant = &slf3s_variants[i]; + + return 0; + } + + if (sf->variant) { + dev_warn(&client->dev, + "unknown SLF3S sub-type 0x%02x, assuming %s\n", + buf[SLF3S_PRODUCT_SUBTYPE_BYTE], sf->variant->name); + return 0; + } + + dev_err(&client->dev, "unknown SLF3S sub-type 0x%02x\n", + buf[SLF3S_PRODUCT_SUBTYPE_BYTE]); + + return -ENODEV; +} + +static int slf3s_read_sample(struct slf3s_data *sf, int *flow, int *temp) +{ + /* + * A measurement frame is flow, temperature and a signaling-flags + * word, each followed by a CRC byte. Only flow and temperature are + * used, so the read is stopped after their two words (6 bytes). + */ + u8 buf[6]; + int ret; + + ret = i2c_master_recv(sf->client, buf, sizeof(buf)); + if (ret < 0) + return ret; + if (ret != sizeof(buf)) + return -EIO; + + for (unsigned int i = 0; i < sizeof(buf); i += 3) { + if (!slf3s_crc_valid(sf, &buf[i])) + return -EIO; + } + + *flow = sign_extend32(get_unaligned_be16(&buf[0]), 15); + *temp = sign_extend32(get_unaligned_be16(&buf[3]), 15); + + return 0; +} + +static int slf3s_get_medium(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct slf3s_data *sf = iio_priv(indio_dev); + + return sf->medium; +} + +static int slf3s_set_medium(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, unsigned int mode) +{ + struct slf3s_data *sf = iio_priv(indio_dev); + int ret; + + guard(mutex)(&sf->lock); + + ret = slf3s_send_cmd(sf->client, slf3s_cmd_stop_meas); + if (ret) + return ret; + + ret = slf3s_start_meas(sf, mode); + if (ret) { + /* + * Try to restart with the previous medium so the sensor is + * not left idle, which would fail all subsequent reads. + */ + if (slf3s_start_meas(sf, sf->medium)) + dev_warn(&sf->client->dev, + "failed to restart measurement, reads will fail until a medium is set\n"); + return ret; + } + + sf->medium = mode; + + return 0; +} + +static const struct iio_enum slf3s_medium_enum = { + .items = slf3s_medium_modes, + .num_items = ARRAY_SIZE(slf3s_medium_modes), + .get = slf3s_get_medium, + .set = slf3s_set_medium, +}; + +static const struct iio_chan_spec_ext_info slf3s_ext_info[] = { + IIO_ENUM("medium", IIO_SHARED_BY_TYPE, &slf3s_medium_enum), + IIO_ENUM_AVAILABLE("medium", IIO_SHARED_BY_TYPE, &slf3s_medium_enum), + { } +}; + +static const struct iio_chan_spec slf3s_channels[] = { + { + .type = IIO_VOLUMEFLOW, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .ext_info = slf3s_ext_info, + }, + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + }, +}; + +static int slf3s_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct slf3s_data *sf = iio_priv(indio_dev); + int flow, temp, ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + scoped_guard(mutex, &sf->lock) + ret = slf3s_read_sample(sf, &flow, &temp); + if (ret) + return ret; + + *val = (chan->type == IIO_VOLUMEFLOW) ? flow : temp; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + if (chan->type == IIO_VOLUMEFLOW) { + /* + * The variant scale is the flow per LSB in l/s, but + * IIO reports volume flow in m^3/s (1 l = 1e-3 m^3). + * These values are tiny (~1.67e-12 m^3/s for the + * SLF3S-0600F), so emit a 64-bit fixed-point value with + * femto (1e-15) resolution to preserve precision. + * Converting l/s to m^3/s (/ MILLI) and scaling to femto + * (* FEMTO) leaves a net * (FEMTO / MILLI) factor. + */ + const struct slf3s_variant *v = sf->variant; + s64 num = (s64)v->scale.numerator * (FEMTO / MILLI); + s64 scale = DIV_S64_ROUND_CLOSEST(num, + v->scale.denominator); + + iio_val_s64_decompose(scale, val, val2); + + return IIO_VAL_DECIMAL64_FEMTO; + } + /* Temperature LSB = 1/200 degC; IIO_TEMP wants milli-degC. */ + *val = MILLIDEGREE_PER_DEGREE / 200; + + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static const struct iio_info slf3s_info = { + .read_raw = slf3s_read_raw, +}; + +static void slf3s_stop_meas(void *data) +{ + struct slf3s_data *sf = data; + + slf3s_send_cmd(sf->client, slf3s_cmd_stop_meas); +} + +static void slf3s_disable_vdd(void *data) +{ + struct slf3s_data *sf = data; + + regulator_disable(sf->vdd); +} + +static int slf3s_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct iio_dev *indio_dev; + struct slf3s_data *sf; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*sf)); + if (!indio_dev) + return -ENOMEM; + + sf = iio_priv(indio_dev); + sf->client = client; + i2c_set_clientdata(client, indio_dev); + sf->variant = i2c_get_match_data(client); + sf->medium = SLF3S_MEDIUM_WATER; + crc8_populate_msb(sf->crc_table, SLF3S_CRC8_POLY); + + ret = devm_mutex_init(dev, &sf->lock); + if (ret) + return ret; + + sf->vdd = devm_regulator_get(dev, "vdd"); + if (IS_ERR(sf->vdd)) + return dev_err_probe(dev, PTR_ERR(sf->vdd), + "failed to get vdd supply\n"); + + ret = regulator_enable(sf->vdd); + if (ret) + return dev_err_probe(dev, ret, "failed to enable vdd supply\n"); + + ret = devm_add_action_or_reset(dev, slf3s_disable_vdd, sf); + if (ret) + return ret; + + fsleep(SLF3S_POWER_UP_DELAY_US); + + /* + * The sensor may still be in continuous measurement mode from a + * previous boot (warm reboot / kexec); in that case it would NACK + * the product-id command below. Stop it first and ignore the error + * if it was already idle. + */ + slf3s_send_cmd(client, slf3s_cmd_stop_meas); + + ret = slf3s_detect_variant(sf); + if (ret) + return dev_err_probe(dev, ret, "product info read failed\n"); + + ret = slf3s_start_meas(sf, sf->medium); + if (ret) + return dev_err_probe(dev, ret, + "failed to start measurement\n"); + + ret = devm_add_action_or_reset(dev, slf3s_stop_meas, sf); + if (ret) + return ret; + + indio_dev->name = sf->variant->name; + indio_dev->channels = slf3s_channels; + indio_dev->num_channels = ARRAY_SIZE(slf3s_channels); + indio_dev->info = &slf3s_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + return devm_iio_device_register(dev, indio_dev); +} + +/* + * The sensor has no low-power state of its own, so stop the measurement + * and cut the supply while suspended. Resume powers it back up, waits + * out the power-up time and restarts with the medium that was active + * before. + */ +static int slf3s_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct slf3s_data *sf = iio_priv(indio_dev); + int ret; + + guard(mutex)(&sf->lock); + + ret = slf3s_send_cmd(sf->client, slf3s_cmd_stop_meas); + if (ret) + return ret; + + return regulator_disable(sf->vdd); +} + +static int slf3s_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct slf3s_data *sf = iio_priv(indio_dev); + int ret; + + guard(mutex)(&sf->lock); + + ret = regulator_enable(sf->vdd); + if (ret) + return ret; + + fsleep(SLF3S_POWER_UP_DELAY_US); + + return slf3s_start_meas(sf, sf->medium); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(slf3s_pm_ops, slf3s_suspend, slf3s_resume); + +static const struct i2c_device_id slf3s_id[] = { + { + .name = "slf3s-0600f", + .driver_data = (kernel_ulong_t)&slf3s_variants[SLF3S_0600F], + }, + { + .name = "slf3s-1300f", + .driver_data = (kernel_ulong_t)&slf3s_variants[SLF3S_1300F], + }, + { + .name = "slf3s-4000b", + .driver_data = (kernel_ulong_t)&slf3s_variants[SLF3S_4000B], + }, + { } +}; +MODULE_DEVICE_TABLE(i2c, slf3s_id); + +static const struct of_device_id slf3s_of_match[] = { + { + .compatible = "sensirion,slf3s-0600f", + .data = &slf3s_variants[SLF3S_0600F], + }, + { + .compatible = "sensirion,slf3s-1300f", + .data = &slf3s_variants[SLF3S_1300F], + }, + { + .compatible = "sensirion,slf3s-4000b", + .data = &slf3s_variants[SLF3S_4000B], + }, + { } +}; +MODULE_DEVICE_TABLE(of, slf3s_of_match); + +static struct i2c_driver slf3s_driver = { + .driver = { + .name = "slf3s", + .of_match_table = slf3s_of_match, + .pm = pm_sleep_ptr(&slf3s_pm_ops), + }, + .probe = slf3s_probe, + .id_table = slf3s_id, +}; +module_i2c_driver(slf3s_driver); + +MODULE_AUTHOR("Wadim Mueller <wafgo01@gmail.com>"); +MODULE_DESCRIPTION("Sensirion SLF3S liquid flow sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/frequency/Kconfig b/drivers/iio/frequency/Kconfig index 583cbdf4e8cd..90c6304c4bcd 100644 --- a/drivers/iio/frequency/Kconfig +++ b/drivers/iio/frequency/Kconfig @@ -29,6 +29,16 @@ endmenu menu "Phase-Locked Loop (PLL) frequency synthesizers" +config ADF41513 + tristate "Analog Devices ADF41513 PLL Frequency Synthesizer" + depends on SPI + help + Say yes here to build support for Analog Devices ADF41513 + 26.5 GHz Integer-N/Fractional-N PLL Frequency Synthesizer. + + To compile this driver as a module, choose M here: the + module will be called adf41513. + config ADF4350 tristate "Analog Devices ADF4350/ADF4351 Wideband Synthesizers" depends on SPI diff --git a/drivers/iio/frequency/Makefile b/drivers/iio/frequency/Makefile index 70d0e0b70e80..53b4d01414d8 100644 --- a/drivers/iio/frequency/Makefile +++ b/drivers/iio/frequency/Makefile @@ -5,6 +5,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_AD9523) += ad9523.o +obj-$(CONFIG_ADF41513) += adf41513.o obj-$(CONFIG_ADF4350) += adf4350.o obj-$(CONFIG_ADF4371) += adf4371.o obj-$(CONFIG_ADF4377) += adf4377.o diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c index 63c485e9e44c..1e393f40a8c8 100644 --- a/drivers/iio/frequency/ad9523.c +++ b/drivers/iio/frequency/ad9523.c @@ -167,9 +167,9 @@ /* AD9523_CHANNEL_CLOCK_DIST */ #define AD9523_CLK_DIST_DIV_PHASE(x) (((x) & 0x3F) << 18) -#define AD9523_CLK_DIST_DIV_PHASE_REV(x) ((ret >> 18) & 0x3F) +#define AD9523_CLK_DIST_DIV_PHASE_REV(x) (((x) >> 18) & 0x3F) #define AD9523_CLK_DIST_DIV(x) ((((x) - 1) & 0x3FF) << 8) -#define AD9523_CLK_DIST_DIV_REV(x) (((ret >> 8) & 0x3FF) + 1) +#define AD9523_CLK_DIST_DIV_REV(x) ((((x) >> 8) & 0x3FF) + 1) #define AD9523_CLK_DIST_INV_DIV_OUTPUT_EN (1 << 7) #define AD9523_CLK_DIST_IGNORE_SYNC_EN (1 << 6) #define AD9523_CLK_DIST_PWR_DOWN_EN (1 << 5) @@ -558,55 +558,35 @@ static ssize_t ad9523_show(struct device *dev, return ret; } -static IIO_DEVICE_ATTR(pll1_locked, S_IRUGO, - ad9523_show, - NULL, - AD9523_STAT_PLL1_LD); - -static IIO_DEVICE_ATTR(pll2_locked, S_IRUGO, - ad9523_show, - NULL, - AD9523_STAT_PLL2_LD); - -static IIO_DEVICE_ATTR(pll1_reference_clk_a_present, S_IRUGO, - ad9523_show, - NULL, - AD9523_STAT_REFA); - -static IIO_DEVICE_ATTR(pll1_reference_clk_b_present, S_IRUGO, - ad9523_show, - NULL, - AD9523_STAT_REFB); - -static IIO_DEVICE_ATTR(pll1_reference_clk_test_present, S_IRUGO, - ad9523_show, - NULL, - AD9523_STAT_REF_TEST); - -static IIO_DEVICE_ATTR(vcxo_clk_present, S_IRUGO, - ad9523_show, - NULL, - AD9523_STAT_VCXO); - -static IIO_DEVICE_ATTR(pll2_feedback_clk_present, S_IRUGO, - ad9523_show, - NULL, - AD9523_STAT_PLL2_FB_CLK); - -static IIO_DEVICE_ATTR(pll2_reference_clk_present, S_IRUGO, - ad9523_show, - NULL, - AD9523_STAT_PLL2_REF_CLK); - -static IIO_DEVICE_ATTR(sync_dividers, S_IWUSR, - NULL, - ad9523_store, - AD9523_SYNC); - -static IIO_DEVICE_ATTR(store_eeprom, S_IWUSR, - NULL, - ad9523_store, - AD9523_EEPROM); +static IIO_DEVICE_ATTR(pll1_locked, 0444, ad9523_show, NULL, + AD9523_STAT_PLL1_LD); + +static IIO_DEVICE_ATTR(pll2_locked, 0444, ad9523_show, NULL, + AD9523_STAT_PLL2_LD); + +static IIO_DEVICE_ATTR(pll1_reference_clk_a_present, 0444, ad9523_show, NULL, + AD9523_STAT_REFA); + +static IIO_DEVICE_ATTR(pll1_reference_clk_b_present, 0444, ad9523_show, NULL, + AD9523_STAT_REFB); + +static IIO_DEVICE_ATTR(pll1_reference_clk_test_present, 0444, ad9523_show, NULL, + AD9523_STAT_REF_TEST); + +static IIO_DEVICE_ATTR(vcxo_clk_present, 0444, ad9523_show, NULL, + AD9523_STAT_VCXO); + +static IIO_DEVICE_ATTR(pll2_feedback_clk_present, 0444, ad9523_show, NULL, + AD9523_STAT_PLL2_FB_CLK); + +static IIO_DEVICE_ATTR(pll2_reference_clk_present, 0444, ad9523_show, NULL, + AD9523_STAT_PLL2_REF_CLK); + +static IIO_DEVICE_ATTR(sync_dividers, 0200, NULL, ad9523_store, + AD9523_SYNC); + +static IIO_DEVICE_ATTR(store_eeprom, 0200, NULL, ad9523_store, + AD9523_EEPROM); static struct attribute *ad9523_attributes[] = { &iio_dev_attr_sync_dividers.dev_attr.attr, @@ -797,8 +777,7 @@ static int ad9523_setup(struct iio_dev *indio_dev) return ret; ret = ad9523_write(indio_dev, AD9523_PLL1_CHARGE_PUMP_CTRL, - AD9523_PLL1_CHARGE_PUMP_CURRENT_nA(pdata-> - pll1_charge_pump_current_nA) | + AD9523_PLL1_CHARGE_PUMP_CURRENT_nA(pdata->pll1_charge_pump_current_nA) | AD9523_PLL1_CHARGE_PUMP_MODE_NORMAL | AD9523_PLL1_BACKLASH_PW_MIN); if (ret < 0) @@ -842,8 +821,7 @@ static int ad9523_setup(struct iio_dev *indio_dev) */ ret = ad9523_write(indio_dev, AD9523_PLL2_CHARGE_PUMP, - AD9523_PLL2_CHARGE_PUMP_CURRENT_nA(pdata-> - pll2_charge_pump_current_nA)); + AD9523_PLL2_CHARGE_PUMP_CURRENT_nA(pdata->pll2_charge_pump_current_nA)); if (ret < 0) return ret; @@ -970,17 +948,17 @@ static int ad9523_setup(struct iio_dev *indio_dev) static int ad9523_probe(struct spi_device *spi) { - struct ad9523_platform_data *pdata = dev_get_platdata(&spi->dev); + struct device *dev = &spi->dev; + struct ad9523_platform_data *pdata; struct iio_dev *indio_dev; struct ad9523_state *st; int ret; - if (!pdata) { - dev_err(&spi->dev, "no platform data?\n"); - return -EINVAL; - } + pdata = dev_get_platdata(dev); + if (!pdata) + return dev_err_probe(dev, -EINVAL, "no platform data?\n"); - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -988,16 +966,16 @@ static int ad9523_probe(struct spi_device *spi) mutex_init(&st->lock); - ret = devm_regulator_get_enable(&spi->dev, "vcc"); + ret = devm_regulator_get_enable(dev, "vcc"); if (ret) return ret; - st->pwrdown_gpio = devm_gpiod_get_optional(&spi->dev, "powerdown", + st->pwrdown_gpio = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH); if (IS_ERR(st->pwrdown_gpio)) return PTR_ERR(st->pwrdown_gpio); - st->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", + st->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(st->reset_gpio)) return PTR_ERR(st->reset_gpio); @@ -1007,12 +985,11 @@ static int ad9523_probe(struct spi_device *spi) gpiod_direction_output(st->reset_gpio, 1); } - st->sync_gpio = devm_gpiod_get_optional(&spi->dev, "sync", + st->sync_gpio = devm_gpiod_get_optional(dev, "sync", GPIOD_OUT_HIGH); if (IS_ERR(st->sync_gpio)) return PTR_ERR(st->sync_gpio); - spi_set_drvdata(spi, indio_dev); st->spi = spi; st->pdata = pdata; @@ -1027,11 +1004,11 @@ static int ad9523_probe(struct spi_device *spi) if (ret < 0) return ret; - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct spi_device_id ad9523_id[] = { - {"ad9523-1", 9523}, + { .name = "ad9523-1" }, { } }; MODULE_DEVICE_TABLE(spi, ad9523_id); diff --git a/drivers/iio/frequency/adf41513.c b/drivers/iio/frequency/adf41513.c new file mode 100644 index 000000000000..c497027012ba --- /dev/null +++ b/drivers/iio/frequency/adf41513.c @@ -0,0 +1,1246 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ADF41513 SPI PLL Frequency Synthesizer driver + * + * Copyright 2026 Analog Devices Inc. + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/clk.h> +#include <linux/dev_printk.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/kstrtox.h> +#include <linux/log2.h> +#include <linux/math64.h> +#include <linux/minmax.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/pm.h> +#include <linux/property.h> +#include <linux/regulator/consumer.h> +#include <linux/spi/spi.h> +#include <linux/sysfs.h> +#include <linux/time64.h> +#include <linux/types.h> +#include <linux/units.h> + +#include <linux/iio/iio.h> + +/* Registers */ +#define ADF41513_REG0 0 +#define ADF41513_REG1 1 +#define ADF41513_REG2 2 +#define ADF41513_REG3 3 +#define ADF41513_REG4 4 +#define ADF41513_REG5 5 +#define ADF41513_REG6 6 +#define ADF41513_REG7 7 +#define ADF41513_REG8 8 +#define ADF41513_REG9 9 +#define ADF41513_REG10 10 +#define ADF41513_REG11 11 +#define ADF41513_REG12 12 +#define ADF41513_REG13 13 +#define ADF41513_REG_NUM 14 + +#define ADF41513_SYNC_REG0 BIT(ADF41513_REG0) +#define ADF41513_SYNC_REG1 BIT(ADF41513_REG1) +#define ADF41513_SYNC_REG2 BIT(ADF41513_REG2) +#define ADF41513_SYNC_REG3 BIT(ADF41513_REG3) +#define ADF41513_SYNC_REG4 BIT(ADF41513_REG4) +#define ADF41513_SYNC_REG5 BIT(ADF41513_REG5) +#define ADF41513_SYNC_REG6 BIT(ADF41513_REG6) +#define ADF41513_SYNC_REG7 BIT(ADF41513_REG7) +#define ADF41513_SYNC_REG9 BIT(ADF41513_REG9) +#define ADF41513_SYNC_REG11 BIT(ADF41513_REG11) +#define ADF41513_SYNC_REG12 BIT(ADF41513_REG12) +#define ADF41513_SYNC_REG13 BIT(ADF41513_REG13) +#define ADF41513_SYNC_DIFF 0 +#define ADF41513_SYNC_ALL GENMASK(ADF41513_REG13, ADF41513_REG0) + +/* REG0 Bit Definitions */ +#define ADF41513_REG0_CTRL_BITS_MSK GENMASK(3, 0) +#define ADF41513_REG0_INT_MSK GENMASK(19, 4) +#define ADF41513_REG0_VAR_MOD_MSK BIT(28) + +/* REG1 Bit Definitions */ +#define ADF41513_REG1_FRAC1_MSK GENMASK(28, 4) +#define ADF41513_REG1_DITHER2_MSK BIT(31) + +/* REG2 Bit Definitions */ +#define ADF41513_REG2_PHASE_VAL_MSK GENMASK(15, 4) +#define ADF41513_REG2_PHASE_ADJ_MSK BIT(31) + +/* REG3 Bit Definitions */ +#define ADF41513_REG3_FRAC2_MSK GENMASK(27, 4) + +/* REG4 Bit Definitions */ +#define ADF41513_REG4_MOD2_MSK GENMASK(27, 4) + +/* REG5 Bit Definitions */ +#define ADF41513_REG5_CLK1_DIV_MSK GENMASK(15, 4) +#define ADF41513_REG5_R_CNT_MSK GENMASK(20, 16) +#define ADF41513_REG5_REF_DOUBLER_MSK BIT(21) +#define ADF41513_REG5_RDIV2_MSK BIT(22) +#define ADF41513_REG5_PRESCALER_MSK BIT(23) +#define ADF41513_REG5_LSB_P1_MSK BIT(24) +#define ADF41513_REG5_CP_CURRENT_MSK GENMASK(28, 25) +#define ADF41513_REG5_DLD_MODES_MSK GENMASK(31, 30) + +/* REG6 Bit Definitions */ +#define ADF41513_REG6_COUNTER_RESET_MSK BIT(4) +#define ADF41513_REG6_CP_TRISTATE_MSK BIT(5) +#define ADF41513_REG6_POWER_DOWN_MSK BIT(6) +#define ADF41513_REG6_PD_POLARITY_MSK BIT(7) +#define ADF41513_REG6_LDP_MSK GENMASK(9, 8) +#define ADF41513_REG6_CP_TRISTATE_PD_ON_MSK BIT(16) +#define ADF41513_REG6_SD_RESET_MSK BIT(17) +#define ADF41513_REG6_LOL_ENABLE_MSK BIT(18) +#define ADF41513_REG6_ABP_MSK BIT(19) +#define ADF41513_REG6_INT_MODE_MSK BIT(20) +#define ADF41513_REG6_BLEED_ENABLE_MSK BIT(22) +#define ADF41513_REG6_BLEED_POLARITY_MSK BIT(23) +#define ADF41513_REG6_BLEED_CURRENT_MSK GENMASK(31, 24) + +/* REG7 Bit Definitions */ +#define ADF41513_REG7_CLK2_DIV_MSK GENMASK(17, 6) +#define ADF41513_REG7_CLK_DIV_MODE_MSK GENMASK(19, 18) +#define ADF41513_REG7_PS_BIAS_MSK GENMASK(21, 20) +#define ADF41513_REG7_N_DELAY_MSK GENMASK(23, 22) +#define ADF41513_REG7_LD_CLK_SEL_MSK BIT(26) +#define ADF41513_REG7_LD_COUNT_MSK GENMASK(29, 27) + +/* REG9 Bit Definitions */ +#define ADF41513_REG9_LD_BIAS_MSK GENMASK(31, 30) + +/* REG11 Bit Definitions */ +#define ADF41513_REG11_POWER_DOWN_SEL_MSK BIT(31) + +/* REG12 Bit Definitions */ +#define ADF41513_REG12_READBACK_SEL_MSK GENMASK(19, 14) +#define ADF41513_REG12_LE_SELECT_MSK BIT(20) +#define ADF41513_REG12_MASTER_RESET_MSK BIT(22) +#define ADF41513_REG12_LOGIC_LEVEL_MSK BIT(27) +#define ADF41513_REG12_MUXOUT_MSK GENMASK(31, 28) + +/* MUXOUT Selection */ +#define ADF41513_MUXOUT_TRISTATE 0x0 +#define ADF41513_MUXOUT_DVDD 0x1 +#define ADF41513_MUXOUT_DGND 0x2 +#define ADF41513_MUXOUT_R_DIV 0x3 +#define ADF41513_MUXOUT_N_DIV 0x4 +#define ADF41513_MUXOUT_DIG_LD 0x6 +#define ADF41513_MUXOUT_SDO 0x7 +#define ADF41513_MUXOUT_READBACK 0x8 +#define ADF41513_MUXOUT_CLK1_DIV 0xA +#define ADF41513_MUXOUT_R_DIV2 0xD +#define ADF41513_MUXOUT_N_DIV2 0xE + +/* DLD Mode Selection */ +#define ADF41513_DLD_TRISTATE 0x0 +#define ADF41513_DLD_DIG_LD 0x1 +#define ADF41513_DLD_LOW 0x2 +#define ADF41513_DLD_HIGH 0x3 + +/* Prescaler Selection */ +#define ADF41513_PRESCALER_4_5 0 +#define ADF41513_PRESCALER_8_9 1 +#define ADF41513_PRESCALER_AUTO 2 + +/* CLK Divider mode */ +#define ADF41513_CLK_DIV_MODE_OFF 0 +#define ADF41513_CLK_DIV_MODE_PHASE_RESYNC 2 + +/* Specifications */ +#define ADF41510_MAX_RF_FREQ_HZ (10ULL * HZ_PER_GHZ) +#define ADF41513_MIN_RF_FREQ_HZ (1ULL * HZ_PER_GHZ) +#define ADF41513_MAX_RF_FREQ_HZ (26500ULL * HZ_PER_MHZ) + +#define ADF41513_MIN_REF_FREQ_HZ (10 * HZ_PER_MHZ) +#define ADF41513_MAX_REF_FREQ_HZ (800 * HZ_PER_MHZ) +#define ADF41513_MAX_REF_FREQ_DOUBLER_HZ (225 * HZ_PER_MHZ) + +#define ADF41513_MAX_PFD_FREQ_INT_N_UHZ (250ULL * MEGA * MICROHZ_PER_HZ) +#define ADF41513_MAX_PFD_FREQ_FRAC_N_UHZ (125ULL * MEGA * MICROHZ_PER_HZ) +#define ADF41513_MAX_FREQ_RESOLUTION_UHZ (100ULL * KILO * MICROHZ_PER_HZ) + +#define ADF41513_MIN_INT_4_5 20 +#define ADF41513_MAX_INT_4_5 511 +#define ADF41513_MIN_INT_8_9 64 +#define ADF41513_MAX_INT_8_9 1023 + +#define ADF41513_MIN_INT_FRAC_4_5 23 +#define ADF41513_MIN_INT_FRAC_8_9 75 + +#define ADF41513_MIN_R_CNT 1 +#define ADF41513_MAX_R_CNT 32 + +#define ADF41513_MIN_R_SET 1800 +#define ADF41513_DEFAULT_R_SET 2700 +#define ADF41513_MAX_R_SET 10000 + +#define ADF41513_MIN_CP_VOLTAGE_mV 810 +#define ADF41513_DEFAULT_CP_VOLTAGE_mV 6480 +#define ADF41513_MAX_CP_VOLTAGE_mV 12960 + +#define ADF41513_MIN_CP_CURRENT_uA 81 +#define ADF41513_MAX_CP_CURRENT_uA 7200 + +#define ADF41513_LD_COUNT_FAST_MIN 2 +#define ADF41513_LD_COUNT_FAST_LIMIT 64 +#define ADF41513_LD_COUNT_MIN 64 +#define ADF41513_LD_COUNT_MAX 8192 + +#define ADF41513_FIXED_MODULUS BIT(25) +#define ADF41513_MAX_MOD2 (BIT(24) - 1) +#define ADF41513_MAX_PHASE_VAL (BIT(12) - 1) +#define ADF41513_MAX_CLK_DIVIDER (BIT(12) - 1) + +#define ADF41513_HZ_DECIMAL_SCALE 6 +#define ADF41513_PS_BIAS_INIT 0x2 +#define ADF41513_MAX_PHASE_MICRORAD ((2 * 314159265UL) / 100) + +enum adf41513_pll_mode { + ADF41513_MODE_INVALID, + ADF41513_MODE_INTEGER_N, + ADF41513_MODE_FIXED_MODULUS, + ADF41513_MODE_VARIABLE_MODULUS, +}; + +struct adf41513_chip_info { + const char *name; + u64 max_rf_freq_hz; + bool has_prescaler_8_9; +}; + +struct adf41513_data { + u64 power_up_frequency_hz; + u64 freq_resolution_uhz; + u32 phase_resync_period_ns; + u32 charge_pump_voltage_mv; + u32 lock_detect_count; + + u8 ref_div_factor; + bool ref_doubler_en; + bool ref_div2_en; + bool phase_detector_polarity; + + bool logic_lvl_1v8_en; + bool le_sync_en; +}; + +struct adf41513_pll_settings { + enum adf41513_pll_mode mode; + + /* reference path parameters */ + u8 r_counter; + u8 ref_doubler; + u8 ref_div2; + u8 prescaler; + + /* frequency parameters */ + u64 target_frequency_uhz; + u64 actual_frequency_uhz; + u64 pfd_frequency_uhz; + + /* pll parameters */ + u32 frac1; + u32 frac2; + u32 mod2; + u16 int_val; +}; + +struct adf41513_state { + const struct adf41513_chip_info *chip_info; + struct spi_device *spi; + struct gpio_desc *lock_detect; + struct clk *ref_clk; + u32 ref_freq_hz; + + /* + * Lock for accessing device registers. Some operations require + * multiple consecutive R/W operations, during which the device + * shouldn't be interrupted. The buffers are also shared across + * all operations so need to be protected on stand alone reads and + * writes. + */ + struct mutex lock; + + /* Cached register values */ + u32 regs[ADF41513_REG_NUM]; + u32 regs_hw[ADF41513_REG_NUM]; + + struct adf41513_data data; + struct adf41513_pll_settings settings; + + bool powerdown; +}; + +static const u16 adf41513_ld_window_x10_ns[] = { + 9, 12, 16, 17, 21, 28, 29, 35, /* 0 - 7 */ + 43, 47, 49, 52, 70, 79, 115, /* 8 - 14 */ +}; + +static const u8 adf41513_ldp_bias[] = { + 0xC, 0xD, 0xE, 0x8, 0x9, 0x4, 0xA, 0x5, /* 0 - 7 */ + 0x0, 0x6, 0xB, 0x1, 0x2, 0x7, 0x3, /* 8 - 14 */ +}; + +static const char * const adf41513_power_supplies[] = { + "avdd1", "avdd2", "avdd3", "avdd4", "avdd5", "vp", +}; + +static int adf41513_sync_config(struct adf41513_state *st, u16 sync_mask) +{ + __be32 d32; + int ret; + + /* write registers in reverse order (R13 to R0)*/ + for (int i = ADF41513_REG13; i >= ADF41513_REG0; i--) { + if (st->regs_hw[i] == st->regs[i] && !(sync_mask & BIT(i))) + continue; + + d32 = cpu_to_be32(st->regs[i] | i); + ret = spi_write_then_read(st->spi, &d32, sizeof(d32), NULL, 0); + if (ret < 0) + return ret; + st->regs_hw[i] = st->regs[i]; + dev_dbg(&st->spi->dev, "REG%d <= 0x%08X\n", i, st->regs[i] | i); + } + + return 0; +} + +static u64 adf41513_pll_get_rate(struct adf41513_state *st) +{ + struct adf41513_pll_settings *cfg = &st->settings; + + if (cfg->mode != ADF41513_MODE_INVALID) + return cfg->actual_frequency_uhz; + + /* get pll settings from regs_hw */ + cfg->int_val = FIELD_GET(ADF41513_REG0_INT_MSK, st->regs_hw[ADF41513_REG0]); + cfg->frac1 = FIELD_GET(ADF41513_REG1_FRAC1_MSK, st->regs_hw[ADF41513_REG1]); + cfg->frac2 = FIELD_GET(ADF41513_REG3_FRAC2_MSK, st->regs_hw[ADF41513_REG3]); + cfg->mod2 = FIELD_GET(ADF41513_REG4_MOD2_MSK, st->regs_hw[ADF41513_REG4]); + cfg->r_counter = FIELD_GET(ADF41513_REG5_R_CNT_MSK, st->regs_hw[ADF41513_REG5]); + cfg->ref_doubler = FIELD_GET(ADF41513_REG5_REF_DOUBLER_MSK, st->regs_hw[ADF41513_REG5]); + cfg->ref_div2 = FIELD_GET(ADF41513_REG5_RDIV2_MSK, st->regs_hw[ADF41513_REG5]); + cfg->prescaler = FIELD_GET(ADF41513_REG5_PRESCALER_MSK, st->regs_hw[ADF41513_REG5]); + + if (!cfg->mod2) + cfg->mod2 = 1; + if (!cfg->r_counter) + cfg->r_counter = ADF41513_MAX_R_CNT; + + /* calculate pfd frequency */ + cfg->pfd_frequency_uhz = (u64)st->ref_freq_hz * MICRO; + if (cfg->ref_doubler) + cfg->pfd_frequency_uhz <<= 1; + if (cfg->ref_div2) + cfg->pfd_frequency_uhz >>= 1; + cfg->pfd_frequency_uhz = div_u64(cfg->pfd_frequency_uhz, cfg->r_counter); + cfg->actual_frequency_uhz = (u64)cfg->int_val * cfg->pfd_frequency_uhz; + + /* check if int mode is selected */ + if (FIELD_GET(ADF41513_REG6_INT_MODE_MSK, st->regs_hw[ADF41513_REG6])) { + cfg->mode = ADF41513_MODE_INTEGER_N; + } else { + cfg->actual_frequency_uhz += mul_u64_u32_div(cfg->pfd_frequency_uhz, + cfg->frac1, + ADF41513_FIXED_MODULUS); + + /* check if variable modulus is selected */ + if (FIELD_GET(ADF41513_REG0_VAR_MOD_MSK, st->regs_hw[ADF41513_REG0])) { + cfg->actual_frequency_uhz += + mul_u64_u64_div_u64(cfg->frac2, + cfg->pfd_frequency_uhz, + (u64)cfg->mod2 * ADF41513_FIXED_MODULUS); + + cfg->mode = ADF41513_MODE_VARIABLE_MODULUS; + } else { + /* LSB_P1 offset */ + if (!FIELD_GET(ADF41513_REG5_LSB_P1_MSK, st->regs_hw[ADF41513_REG5])) + cfg->actual_frequency_uhz += + div_u64(cfg->pfd_frequency_uhz, + 2 * ADF41513_FIXED_MODULUS); + cfg->mode = ADF41513_MODE_FIXED_MODULUS; + } + } + + cfg->target_frequency_uhz = cfg->actual_frequency_uhz; + + return cfg->actual_frequency_uhz; +} + +static int adf41513_calc_pfd_frequency(struct adf41513_state *st, + struct adf41513_pll_settings *result, + u64 fpfd_limit_uhz) +{ + result->ref_div2 = st->data.ref_div2_en; + result->ref_doubler = st->data.ref_doubler_en; + result->r_counter = st->data.ref_div_factor - 1; + + do { + result->r_counter++; + /* f_PFD = REF_IN × ((1 + D)/(R × (1 + T))) */ + result->pfd_frequency_uhz = (u64)st->ref_freq_hz * MICRO; + if (result->ref_doubler) + result->pfd_frequency_uhz <<= 1; + if (result->ref_div2) + result->pfd_frequency_uhz >>= 1; + result->pfd_frequency_uhz = div_u64(result->pfd_frequency_uhz, + result->r_counter); + } while (result->pfd_frequency_uhz > fpfd_limit_uhz); + + if (result->r_counter > ADF41513_MAX_R_CNT) { + dev_err(&st->spi->dev, "Cannot optimize PFD frequency\n"); + return -ERANGE; + } + + return 0; +} + +static int adf41513_calc_integer_n(struct adf41513_state *st, + struct adf41513_pll_settings *result) +{ + u32 max_int = st->chip_info->has_prescaler_8_9 ? + ADF41513_MAX_INT_8_9 : ADF41513_MAX_INT_4_5; + u64 freq_error_uhz; + u32 int_val = div64_u64_rem(result->target_frequency_uhz, result->pfd_frequency_uhz, + &freq_error_uhz); + + /* check if freq error is within a tolerance of 1/2 resolution */ + if (freq_error_uhz > (result->pfd_frequency_uhz >> 1) && int_val < max_int) { + int_val++; + freq_error_uhz = result->pfd_frequency_uhz - freq_error_uhz; + } + + if (freq_error_uhz > st->data.freq_resolution_uhz) + return -ERANGE; + + /* set prescaler */ + if (st->chip_info->has_prescaler_8_9 && int_val >= ADF41513_MIN_INT_8_9 && + int_val <= ADF41513_MAX_INT_8_9) + result->prescaler = 1; + else if (int_val >= ADF41513_MIN_INT_4_5 && int_val <= ADF41513_MAX_INT_4_5) + result->prescaler = 0; + else + return -ERANGE; + + result->actual_frequency_uhz = (u64)int_val * result->pfd_frequency_uhz; + result->mode = ADF41513_MODE_INTEGER_N; + result->int_val = int_val; + result->frac1 = 0; + result->frac2 = 0; + result->mod2 = 0; + + return 0; +} + +static int adf41513_calc_fixed_mod(struct adf41513_state *st, + struct adf41513_pll_settings *result) +{ + u64 resolution_uhz = div_u64(result->pfd_frequency_uhz, ADF41513_FIXED_MODULUS); + u64 target_frequency_uhz = result->target_frequency_uhz; + u64 freq_error_uhz; + u32 int_val, frac1; + bool lsb_p1_offset = !FIELD_GET(ADF41513_REG5_LSB_P1_MSK, st->regs[ADF41513_REG5]); + + /* LSB_P1 adds a frequency offset of f_pfd/2^26 */ + if (lsb_p1_offset) + target_frequency_uhz -= resolution_uhz >> 1; + + int_val = div64_u64_rem(target_frequency_uhz, result->pfd_frequency_uhz, + &freq_error_uhz); + + if (st->chip_info->has_prescaler_8_9 && int_val >= ADF41513_MIN_INT_FRAC_8_9 && + int_val <= ADF41513_MAX_INT_8_9) + result->prescaler = 1; + else if (int_val >= ADF41513_MIN_INT_FRAC_4_5 && int_val <= ADF41513_MAX_INT_4_5) + result->prescaler = 0; + else + return -ERANGE; + + /* compute frac1 and fixed modulus error */ + frac1 = mul_u64_u64_div_u64(freq_error_uhz, ADF41513_FIXED_MODULUS, + result->pfd_frequency_uhz); + freq_error_uhz -= mul_u64_u32_div(result->pfd_frequency_uhz, frac1, + ADF41513_FIXED_MODULUS); + + /* check if freq error is within a tolerance of 1/2 resolution */ + if (freq_error_uhz > (resolution_uhz >> 1) && frac1 < (ADF41513_FIXED_MODULUS - 1)) { + frac1++; + freq_error_uhz = freq_error_uhz < resolution_uhz ? + resolution_uhz - freq_error_uhz : 0; + } + + if (freq_error_uhz > st->data.freq_resolution_uhz) + return -ERANGE; + + /* integer part */ + result->actual_frequency_uhz = (u64)int_val * result->pfd_frequency_uhz; + /* fractional part */ + if (lsb_p1_offset) + result->actual_frequency_uhz += (resolution_uhz >> 1); + result->actual_frequency_uhz += mul_u64_u32_div(result->pfd_frequency_uhz, frac1, + ADF41513_FIXED_MODULUS); + result->mode = ADF41513_MODE_FIXED_MODULUS; + result->int_val = int_val; + result->frac1 = frac1; + result->frac2 = 0; + result->mod2 = 0; + + return 0; +} + +static int adf41513_calc_variable_mod(struct adf41513_state *st, + struct adf41513_pll_settings *result) +{ + u64 freq_error_uhz, mod2; + u32 frac1, frac2; + u32 int_val = div64_u64_rem(result->target_frequency_uhz, + result->pfd_frequency_uhz, &freq_error_uhz); + + if (st->chip_info->has_prescaler_8_9 && int_val >= ADF41513_MIN_INT_FRAC_8_9 && + int_val <= ADF41513_MAX_INT_8_9) + result->prescaler = 1; + else if (int_val >= ADF41513_MIN_INT_FRAC_4_5 && int_val <= ADF41513_MAX_INT_4_5) + result->prescaler = 0; + else + return -ERANGE; + + /* calculate required mod2 based on target resolution / 2 */ + mod2 = DIV64_U64_ROUND_CLOSEST(result->pfd_frequency_uhz << 1, + st->data.freq_resolution_uhz * ADF41513_FIXED_MODULUS); + /* ensure mod2 is at least 2 for meaningful operation */ + mod2 = clamp(mod2, 2, ADF41513_MAX_MOD2); + + /* calculate frac1 and frac2 */ + frac1 = mul_u64_u64_div_u64(freq_error_uhz, ADF41513_FIXED_MODULUS, + result->pfd_frequency_uhz); + frac2 = mul_u64_u64_div_u64(freq_error_uhz, mod2 * ADF41513_FIXED_MODULUS, + result->pfd_frequency_uhz) - mod2 * frac1; + + /* integer part */ + result->actual_frequency_uhz = (u64)int_val * result->pfd_frequency_uhz; + /* fractional part */ + result->actual_frequency_uhz += mul_u64_u64_div_u64(mod2 * frac1 + frac2, + result->pfd_frequency_uhz, + mod2 * ADF41513_FIXED_MODULUS); + result->mode = ADF41513_MODE_VARIABLE_MODULUS; + result->int_val = int_val; + result->frac1 = frac1; + result->frac2 = frac2; + result->mod2 = mod2; + + return 0; +} + +static int adf41513_calc_pll_settings(struct adf41513_state *st, + struct adf41513_pll_settings *result, + u64 rf_out_uhz) +{ + u64 max_rf_freq_uhz = st->chip_info->max_rf_freq_hz * MICRO; + u64 min_rf_freq_uhz = ADF41513_MIN_RF_FREQ_HZ * MICRO; + u64 pfd_freq_limit_uhz; + int ret; + + if (rf_out_uhz < min_rf_freq_uhz || rf_out_uhz > max_rf_freq_uhz) { + dev_err(&st->spi->dev, "RF frequency %llu uHz out of range [%llu, %llu] uHz\n", + rf_out_uhz, min_rf_freq_uhz, max_rf_freq_uhz); + return -EINVAL; + } + + result->target_frequency_uhz = rf_out_uhz; + + /* try integer-N first (best phase noise performance) */ + pfd_freq_limit_uhz = min(div_u64(rf_out_uhz, ADF41513_MIN_INT_4_5), + ADF41513_MAX_PFD_FREQ_INT_N_UHZ); + ret = adf41513_calc_pfd_frequency(st, result, pfd_freq_limit_uhz); + if (ret) + return ret; + + if (adf41513_calc_integer_n(st, result) == 0) + return 0; + + /* try fractional-N: recompute pfd frequency if necessary */ + pfd_freq_limit_uhz = min(div_u64(rf_out_uhz, ADF41513_MIN_INT_FRAC_4_5), + ADF41513_MAX_PFD_FREQ_FRAC_N_UHZ); + if (pfd_freq_limit_uhz < result->pfd_frequency_uhz) { + ret = adf41513_calc_pfd_frequency(st, result, pfd_freq_limit_uhz); + if (ret) + return ret; + } + + /* fixed-modulus attempt */ + if (adf41513_calc_fixed_mod(st, result) == 0) + return 0; + + /* variable-modulus attempt */ + ret = adf41513_calc_variable_mod(st, result); + if (ret) { + dev_err(&st->spi->dev, + "no valid PLL configuration found for %llu uHz\n", + rf_out_uhz); + return ret; + } + + return 0; +} + +static void adf41513_set_bleed_val(struct adf41513_state *st) +{ + u32 bleed_value, cp_index; + + if (!(st->regs[ADF41513_REG6] & ADF41513_REG6_BLEED_ENABLE_MSK)) + return; + + if (st->data.phase_detector_polarity) + bleed_value = 90; + else + bleed_value = 144; + + cp_index = 1 + FIELD_GET(ADF41513_REG5_CP_CURRENT_MSK, + st->regs[ADF41513_REG5]); + bleed_value = div64_u64(st->settings.pfd_frequency_uhz * cp_index * bleed_value, + 1600ULL * MEGA * MICROHZ_PER_HZ); + + FIELD_MODIFY(ADF41513_REG6_BLEED_CURRENT_MSK, &st->regs[ADF41513_REG6], + bleed_value); +} + +static void adf41513_set_ld_window(struct adf41513_state *st) +{ + /* + * The ideal lock detector window size is halfway between the max + * window, set by the phase comparison period t_PFD = (1 / f_PFD), + * and the minimum is set by (I_BLEED/I_CP) × t_PFD + */ + u16 ld_window_10x_ns = div64_u64(10ULL * NSEC_PER_SEC * MICROHZ_PER_HZ, + st->settings.pfd_frequency_uhz << 1); + u8 ld_idx, ldp, ld_bias; + + if (st->settings.mode != ADF41513_MODE_INTEGER_N) { + /* account for bleed current (deduced from eq.6 and eq.7) */ + if (st->data.phase_detector_polarity) + ld_window_10x_ns += 4; + else + ld_window_10x_ns += 6; + } + + ld_idx = find_closest(ld_window_10x_ns, adf41513_ld_window_x10_ns, + ARRAY_SIZE(adf41513_ld_window_x10_ns)); + ldp = (adf41513_ldp_bias[ld_idx] >> 2) & 0x3; + ld_bias = adf41513_ldp_bias[ld_idx] & 0x3; + + FIELD_MODIFY(ADF41513_REG6_LDP_MSK, &st->regs[ADF41513_REG6], ldp); + FIELD_MODIFY(ADF41513_REG9_LD_BIAS_MSK, &st->regs[ADF41513_REG9], ld_bias); +} + +static void adf41513_set_phase_resync(struct adf41513_state *st) +{ + u32 total_div, clk1_div, clk2_div; + + if (!st->data.phase_resync_period_ns) + return; + + /* assuming both clock dividers hold similar values */ + total_div = mul_u64_u64_div_u64(st->settings.pfd_frequency_uhz, + st->data.phase_resync_period_ns, + 1ULL * MICROHZ_PER_HZ * NSEC_PER_SEC); + clk1_div = clamp(int_sqrt(total_div), 1, + ADF41513_MAX_CLK_DIVIDER); + clk2_div = clamp(DIV_ROUND_CLOSEST(total_div, clk1_div), 1, + ADF41513_MAX_CLK_DIVIDER); + + FIELD_MODIFY(ADF41513_REG5_CLK1_DIV_MSK, &st->regs[ADF41513_REG5], + clk1_div); + FIELD_MODIFY(ADF41513_REG7_CLK2_DIV_MSK, &st->regs[ADF41513_REG7], + clk2_div); + + /* enable phase resync */ + FIELD_MODIFY(ADF41513_REG7_CLK_DIV_MODE_MSK, &st->regs[ADF41513_REG7], + ADF41513_CLK_DIV_MODE_PHASE_RESYNC); +} + +static int adf41513_set_frequency(struct adf41513_state *st, u64 freq_uhz, u16 sync_mask) +{ + struct adf41513_pll_settings result; + bool pfd_change = false; + bool mode_change = false; + int ret; + + ret = adf41513_calc_pll_settings(st, &result, freq_uhz); + if (ret < 0) + return ret; + + /* apply computed results to pll settings */ + pfd_change = st->settings.pfd_frequency_uhz != result.pfd_frequency_uhz; + mode_change = st->settings.mode != result.mode; + st->settings = result; + + dev_dbg(&st->spi->dev, + "%s mode: int=%u, frac1=%u, frac2=%u, mod2=%u, fpdf=%llu Hz, prescaler=%s\n", + (result.mode == ADF41513_MODE_INTEGER_N) ? "integer-n" : + (result.mode == ADF41513_MODE_FIXED_MODULUS) ? "fixed-modulus" : "variable-modulus", + result.int_val, result.frac1, result.frac2, result.mod2, + div64_u64(result.pfd_frequency_uhz, MICRO), + result.prescaler ? "8/9" : "4/5"); + + st->regs[ADF41513_REG0] = FIELD_PREP(ADF41513_REG0_INT_MSK, + st->settings.int_val); + if (st->settings.mode == ADF41513_MODE_VARIABLE_MODULUS) + st->regs[ADF41513_REG0] |= ADF41513_REG0_VAR_MOD_MSK; + + st->regs[ADF41513_REG1] = FIELD_PREP(ADF41513_REG1_FRAC1_MSK, + st->settings.frac1); + if (st->settings.mode != ADF41513_MODE_INTEGER_N) + st->regs[ADF41513_REG1] |= ADF41513_REG1_DITHER2_MSK; + + st->regs[ADF41513_REG3] = FIELD_PREP(ADF41513_REG3_FRAC2_MSK, + st->settings.frac2); + FIELD_MODIFY(ADF41513_REG4_MOD2_MSK, &st->regs[ADF41513_REG4], + st->settings.mod2); + FIELD_MODIFY(ADF41513_REG5_R_CNT_MSK, &st->regs[ADF41513_REG5], + st->settings.r_counter % ADF41513_MAX_R_CNT); + FIELD_MODIFY(ADF41513_REG5_REF_DOUBLER_MSK, &st->regs[ADF41513_REG5], + st->settings.ref_doubler); + FIELD_MODIFY(ADF41513_REG5_RDIV2_MSK, &st->regs[ADF41513_REG5], + st->settings.ref_div2); + FIELD_MODIFY(ADF41513_REG5_PRESCALER_MSK, &st->regs[ADF41513_REG5], + st->settings.prescaler); + + if (st->settings.mode == ADF41513_MODE_INTEGER_N) { + st->regs[ADF41513_REG6] |= ADF41513_REG6_INT_MODE_MSK; + st->regs[ADF41513_REG6] &= ~ADF41513_REG6_BLEED_ENABLE_MSK; + } else { + st->regs[ADF41513_REG6] &= ~ADF41513_REG6_INT_MODE_MSK; + st->regs[ADF41513_REG6] |= ADF41513_REG6_BLEED_ENABLE_MSK; + } + + if (pfd_change) + adf41513_set_phase_resync(st); + + if (pfd_change || mode_change) { + adf41513_set_bleed_val(st); + adf41513_set_ld_window(st); + } + + return adf41513_sync_config(st, sync_mask | ADF41513_SYNC_REG0); +} + +static int adf41513_suspend(struct adf41513_state *st) +{ + st->regs[ADF41513_REG6] |= FIELD_PREP(ADF41513_REG6_POWER_DOWN_MSK, 1); + st->regs[ADF41513_REG12] &= ~ADF41513_REG12_LE_SELECT_MSK; + return adf41513_sync_config(st, ADF41513_SYNC_DIFF); +} + +static int adf41513_resume(struct adf41513_state *st) +{ + int ret; + + st->regs[ADF41513_REG6] &= ~ADF41513_REG6_POWER_DOWN_MSK; + st->regs[ADF41513_REG12] &= ~ADF41513_REG12_LE_SELECT_MSK; + ret = adf41513_sync_config(st, ADF41513_SYNC_ALL); + if (ret) + return ret; + + if (st->data.le_sync_en) { + st->regs[ADF41513_REG12] |= ADF41513_REG12_LE_SELECT_MSK; + ret = adf41513_sync_config(st, ADF41513_SYNC_DIFF); + if (ret) + return ret; + } + + return 0; +} + +static ssize_t adf41513_read_resolution(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + struct adf41513_state *st = iio_priv(indio_dev); + int vals[2]; + + guard(mutex)(&st->lock); + + iio_val_s64_decompose(st->data.freq_resolution_uhz, &vals[0], &vals[1]); + return iio_format_value(buf, IIO_VAL_DECIMAL64_MICRO, ARRAY_SIZE(vals), vals); +} + +static ssize_t adf41513_read_powerdown(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + struct adf41513_state *st = iio_priv(indio_dev); + u32 val; + + guard(mutex)(&st->lock); + + val = FIELD_GET(ADF41513_REG6_POWER_DOWN_MSK, st->regs_hw[ADF41513_REG6]); + return sysfs_emit(buf, "%u\n", val); +} + +static ssize_t adf41513_write_resolution(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct adf41513_state *st = iio_priv(indio_dev); + u64 freq_uhz; + int ret; + + ret = kstrtoudec64(buf, ADF41513_HZ_DECIMAL_SCALE, &freq_uhz); + if (ret) + return ret; + + if (freq_uhz == 0 || freq_uhz > ADF41513_MAX_FREQ_RESOLUTION_UHZ) + return -EINVAL; + + guard(mutex)(&st->lock); + + st->data.freq_resolution_uhz = freq_uhz; + return len; +} + +static ssize_t adf41513_write_powerdown(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct adf41513_state *st = iio_priv(indio_dev); + bool val; + int ret; + + ret = kstrtobool(buf, &val); + if (ret) + return ret; + + guard(mutex)(&st->lock); + + if (val) + ret = adf41513_suspend(st); + else + ret = adf41513_resume(st); + if (ret) + return ret; + + st->powerdown = val; + return len; +} + +static const struct iio_chan_spec_ext_info adf41513_ext_info[] = { + { + .name = "frequency_resolution", + .read = adf41513_read_resolution, + .write = adf41513_write_resolution, + .shared = IIO_SEPARATE, + }, + { + .name = "powerdown", + .read = adf41513_read_powerdown, + .write = adf41513_write_powerdown, + .shared = IIO_SEPARATE, + }, + { } +}; + +static const struct iio_chan_spec adf41513_chan = { + .type = IIO_ALTVOLTAGE, + .indexed = 1, + .output = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_FREQUENCY) | + BIT(IIO_CHAN_INFO_PHASE), + .ext_info = adf41513_ext_info, +}; + +static int adf41513_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long info) +{ + struct adf41513_state *st = iio_priv(indio_dev); + u64 tmp64; + + guard(mutex)(&st->lock); + + switch (info) { + case IIO_CHAN_INFO_FREQUENCY: + if (st->lock_detect && + !gpiod_get_value_cansleep(st->lock_detect)) { + dev_dbg(&st->spi->dev, "PLL un-locked\n"); + return -EBUSY; + } + tmp64 = adf41513_pll_get_rate(st); + iio_val_s64_decompose(tmp64, val, val2); + return IIO_VAL_DECIMAL64_MICRO; + case IIO_CHAN_INFO_PHASE: + tmp64 = FIELD_GET(ADF41513_REG2_PHASE_VAL_MSK, + st->regs_hw[ADF41513_REG2]); + tmp64 = (tmp64 * ADF41513_MAX_PHASE_MICRORAD) >> 12; + iio_val_s64_decompose(tmp64, val, val2); + return IIO_VAL_DECIMAL64_MICRO; + default: + return -EINVAL; + } +} + +static int adf41513_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long info) +{ + struct adf41513_state *st = iio_priv(indio_dev); + u64 tmp64 = iio_val_s64_compose(val, val2); + u16 phase_val; + int ret; + + guard(mutex)(&st->lock); + + switch (info) { + case IIO_CHAN_INFO_FREQUENCY: + return adf41513_set_frequency(st, tmp64, ADF41513_SYNC_DIFF); + case IIO_CHAN_INFO_PHASE: + if (tmp64 >= ADF41513_MAX_PHASE_MICRORAD) + return -EINVAL; + + phase_val = DIV_U64_ROUND_CLOSEST(tmp64 << 12, + ADF41513_MAX_PHASE_MICRORAD); + phase_val = min(phase_val, ADF41513_MAX_PHASE_VAL); + st->regs[ADF41513_REG2] |= ADF41513_REG2_PHASE_ADJ_MSK; + FIELD_MODIFY(ADF41513_REG2_PHASE_VAL_MSK, + &st->regs[ADF41513_REG2], phase_val); + ret = adf41513_sync_config(st, ADF41513_SYNC_REG0); + /* clear phase adjust for the next sync */ + st->regs[ADF41513_REG2] &= ~ADF41513_REG2_PHASE_ADJ_MSK; + return ret; + default: + return -EINVAL; + } +} + +static int adf41513_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_FREQUENCY: + case IIO_CHAN_INFO_PHASE: + return IIO_VAL_DECIMAL64_MICRO; + default: + return -EINVAL; + } +} + +static int adf41513_reg_access(struct iio_dev *indio_dev, unsigned int reg, + unsigned int writeval, unsigned int *readval) +{ + struct adf41513_state *st = iio_priv(indio_dev); + + if (reg > ADF41513_REG13) + return -EINVAL; + + guard(mutex)(&st->lock); + + if (!readval) { + if (reg <= ADF41513_REG6) + st->settings.mode = ADF41513_MODE_INVALID; + st->regs[reg] = writeval & ~0xF; /* Clear control bits */ + return adf41513_sync_config(st, BIT(reg)); + } + + *readval = st->regs_hw[reg]; + return 0; +} + +static const struct iio_info adf41513_info = { + .read_raw = adf41513_read_raw, + .write_raw = adf41513_write_raw, + .write_raw_get_fmt = adf41513_write_raw_get_fmt, + .debugfs_reg_access = &adf41513_reg_access, +}; + +static int adf41513_parse_fw(struct adf41513_state *st) +{ + struct device *dev = &st->spi->dev; + u32 tmp, cp_resistance, cp_current; + int ret; + + tmp = ADF41510_MAX_RF_FREQ_HZ / MEGA; + device_property_read_u32(dev, "adi,power-up-frequency-mhz", &tmp); + st->data.power_up_frequency_hz = (u64)tmp * MEGA; + if (st->data.power_up_frequency_hz < ADF41513_MIN_RF_FREQ_HZ || + st->data.power_up_frequency_hz > st->chip_info->max_rf_freq_hz) + return dev_err_probe(dev, -ERANGE, + "power-up frequency %llu Hz out of range\n", + st->data.power_up_frequency_hz); + + tmp = ADF41513_MIN_R_CNT; + device_property_read_u32(dev, "adi,reference-div-factor", &tmp); + if (tmp < ADF41513_MIN_R_CNT || tmp > ADF41513_MAX_R_CNT) + return dev_err_probe(dev, -ERANGE, + "invalid reference div factor %u\n", tmp); + st->data.ref_div_factor = tmp; + + st->data.ref_div2_en = device_property_read_bool(dev, "adi,reference-div2-enable"); + st->data.ref_doubler_en = device_property_read_bool(dev, "adi,reference-doubler-enable"); + + if (st->data.ref_doubler_en && + st->ref_freq_hz > ADF41513_MAX_REF_FREQ_DOUBLER_HZ) { + return dev_err_probe(dev, -ERANGE, + "Ref frequency not supported with doubler enabled\n"); + } + + cp_resistance = ADF41513_DEFAULT_R_SET; + device_property_read_u32(dev, "adi,charge-pump-resistor-ohms", &cp_resistance); + if (cp_resistance < ADF41513_MIN_R_SET || cp_resistance > ADF41513_MAX_R_SET) + return dev_err_probe(dev, -ERANGE, "R_SET %u Ohms out of range\n", cp_resistance); + + st->data.charge_pump_voltage_mv = ADF41513_DEFAULT_CP_VOLTAGE_mV; + ret = device_property_read_u32(dev, "adi,charge-pump-current-microamp", &cp_current); + if (!ret) { + if (cp_current < ADF41513_MIN_CP_CURRENT_uA || + cp_current > ADF41513_MAX_CP_CURRENT_uA) + return dev_err_probe(dev, -ERANGE, + "I_CP %u uA out of range\n", cp_current); + + tmp = DIV_ROUND_CLOSEST(cp_current * cp_resistance, MILLI); + if (tmp < ADF41513_MIN_CP_VOLTAGE_mV || tmp > ADF41513_MAX_CP_VOLTAGE_mV) + return dev_err_probe(dev, -ERANGE, "I_CP %u uA (%u Ohms) out of range\n", + cp_current, cp_resistance); + st->data.charge_pump_voltage_mv = tmp; + } + + st->data.phase_detector_polarity = + device_property_read_bool(dev, "adi,phase-detector-polarity-positive-enable"); + + st->data.phase_resync_period_ns = 0; + ret = device_property_read_u32(dev, "adi,phase-resync-period-ns", &tmp); + if (!ret) + st->data.phase_resync_period_ns = tmp; + + st->data.logic_lvl_1v8_en = device_property_read_bool(dev, "adi,logic-level-1v8-enable"); + + tmp = ADF41513_LD_COUNT_MIN; + device_property_read_u32(dev, "adi,lock-detector-count", &tmp); + if (tmp < ADF41513_LD_COUNT_FAST_MIN || tmp > ADF41513_LD_COUNT_MAX || + !is_power_of_2(tmp)) + return dev_err_probe(dev, -ERANGE, + "invalid lock detect count: %u\n", tmp); + st->data.lock_detect_count = tmp; + + /* load enable sync */ + st->data.le_sync_en = device_property_read_bool(dev, "adi,le-sync-enable"); + st->data.freq_resolution_uhz = MICROHZ_PER_HZ; + + return 0; +} + +static void adf41513_chip_disable(void *data) +{ + gpiod_set_value_cansleep(data, 0); +} + +static void adf41513_close(void *data) +{ + adf41513_suspend(data); +} + +static int adf41513_setup(struct device *dev, struct adf41513_state *st) +{ + u32 tmp; + int ret; + + memset(st->regs_hw, 0xFF, sizeof(st->regs_hw)); + + /* assuming DLD pin is used for lock detection */ + st->regs[ADF41513_REG5] = FIELD_PREP(ADF41513_REG5_DLD_MODES_MSK, + ADF41513_DLD_DIG_LD); + + tmp = DIV_ROUND_CLOSEST(st->data.charge_pump_voltage_mv, ADF41513_MIN_CP_VOLTAGE_mV); + st->regs[ADF41513_REG5] |= FIELD_PREP(ADF41513_REG5_CP_CURRENT_MSK, tmp - 1); + + st->regs[ADF41513_REG6] = ADF41513_REG6_ABP_MSK | + ADF41513_REG6_LOL_ENABLE_MSK | + ADF41513_REG6_SD_RESET_MSK; + if (st->data.phase_detector_polarity) + st->regs[ADF41513_REG6] |= ADF41513_REG6_PD_POLARITY_MSK; + + st->regs[ADF41513_REG7] = FIELD_PREP(ADF41513_REG7_PS_BIAS_MSK, + ADF41513_PS_BIAS_INIT); + tmp = ilog2(st->data.lock_detect_count); + if (st->data.lock_detect_count < ADF41513_LD_COUNT_FAST_LIMIT) { + tmp -= const_ilog2(ADF41513_LD_COUNT_FAST_MIN); + st->regs[ADF41513_REG7] |= ADF41513_REG7_LD_CLK_SEL_MSK; + } else { + tmp -= const_ilog2(ADF41513_LD_COUNT_MIN); + } + st->regs[ADF41513_REG7] |= FIELD_PREP(ADF41513_REG7_LD_COUNT_MSK, tmp); + + st->regs[ADF41513_REG11] = ADF41513_REG11_POWER_DOWN_SEL_MSK; + st->regs[ADF41513_REG12] = FIELD_PREP(ADF41513_REG12_LOGIC_LEVEL_MSK, + st->data.logic_lvl_1v8_en ? 0 : 1); + + /* perform initialization sequence with power-up frequency */ + ret = adf41513_set_frequency(st, st->data.power_up_frequency_hz * MICRO, + ADF41513_SYNC_ALL); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, adf41513_close, st); + if (ret) + return ret; + + if (st->data.le_sync_en) { + st->regs[ADF41513_REG12] |= ADF41513_REG12_LE_SELECT_MSK; + ret = adf41513_sync_config(st, ADF41513_SYNC_DIFF); + if (ret) + return ret; + } + + return 0; +} + +static int adf41513_pm_suspend(struct device *dev) +{ + struct adf41513_state *st = dev_get_drvdata(dev); + + guard(mutex)(&st->lock); + return adf41513_suspend(st); +} + +static int adf41513_pm_resume(struct device *dev) +{ + struct adf41513_state *st = dev_get_drvdata(dev); + + guard(mutex)(&st->lock); + if (st->powerdown) + return 0; /* nothing to do */ + + return adf41513_resume(st); +} + +static const struct adf41513_chip_info adf41510_chip_info = { + .name = "adf41510", + .max_rf_freq_hz = ADF41510_MAX_RF_FREQ_HZ, + .has_prescaler_8_9 = false, +}; + +static const struct adf41513_chip_info adf41513_chip_info = { + .name = "adf41513", + .max_rf_freq_hz = ADF41513_MAX_RF_FREQ_HZ, + .has_prescaler_8_9 = true, +}; + +static int adf41513_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct gpio_desc *chip_enable; + struct iio_dev *indio_dev; + struct adf41513_state *st; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->spi = spi; + st->chip_info = spi_get_device_match_data(spi); + if (!st->chip_info) + return -EINVAL; + + spi_set_drvdata(spi, st); + + st->ref_clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(st->ref_clk)) + return PTR_ERR(st->ref_clk); + + st->ref_freq_hz = clk_get_rate(st->ref_clk); + if (st->ref_freq_hz < ADF41513_MIN_REF_FREQ_HZ || + st->ref_freq_hz > ADF41513_MAX_REF_FREQ_HZ) + return dev_err_probe(dev, -ERANGE, + "reference frequency %u Hz out of range\n", + st->ref_freq_hz); + + ret = adf41513_parse_fw(st); + if (ret) + return ret; + + ret = devm_regulator_bulk_get_enable(dev, + ARRAY_SIZE(adf41513_power_supplies), + adf41513_power_supplies); + if (ret) + return dev_err_probe(dev, ret, + "failed to get and enable regulators\n"); + + st->lock_detect = devm_gpiod_get_optional(dev, "lock-detect", GPIOD_IN); + if (IS_ERR(st->lock_detect)) + return dev_err_probe(dev, PTR_ERR(st->lock_detect), + "fail to request lock detect GPIO\n"); + + chip_enable = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); + if (IS_ERR(chip_enable)) + return dev_err_probe(dev, PTR_ERR(chip_enable), + "fail to request chip enable GPIO\n"); + + ret = devm_add_action_or_reset(dev, adf41513_chip_disable, chip_enable); + if (ret) + return dev_err_probe(dev, ret, "Failed to add disable action\n"); + + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; + + indio_dev->name = st->chip_info->name; + indio_dev->info = &adf41513_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = &adf41513_chan; + indio_dev->num_channels = 1; + + ret = adf41513_setup(dev, st); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to setup device\n"); + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct spi_device_id adf41513_id[] = { + { .name = "adf41510", .driver_data = (kernel_ulong_t)&adf41510_chip_info }, + { .name = "adf41513", .driver_data = (kernel_ulong_t)&adf41513_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(spi, adf41513_id); + +static const struct of_device_id adf41513_of_match[] = { + { .compatible = "adi,adf41510", .data = &adf41510_chip_info }, + { .compatible = "adi,adf41513", .data = &adf41513_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, adf41513_of_match); + +static DEFINE_SIMPLE_DEV_PM_OPS(adf41513_pm_ops, adf41513_pm_suspend, adf41513_pm_resume); + +static struct spi_driver adf41513_driver = { + .driver = { + .name = "adf41513", + .pm = pm_ptr(&adf41513_pm_ops), + .of_match_table = adf41513_of_match, + }, + .probe = adf41513_probe, + .id_table = adf41513_id, +}; +module_spi_driver(adf41513_driver); + +MODULE_AUTHOR("Rodrigo Alencar <rodrigo.alencar@analog.com>"); +MODULE_DESCRIPTION("Analog Devices ADF41513 PLL Frequency Synthesizer"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c index ed1741165f55..315317d6eec4 100644 --- a/drivers/iio/frequency/adf4350.c +++ b/drivers/iio/frequency/adf4350.c @@ -7,7 +7,6 @@ #include <linux/device.h> #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/property.h> #include <linux/slab.h> @@ -152,10 +151,10 @@ static int adf4350_set_freq(struct adf4350_state *st, unsigned long long freq) st->r4_rf_div_sel = 0; /* - * !\TODO: The below computation is making sure we get a power of 2 - * shift (st->r4_rf_div_sel) so that freq becomes higher or equal to - * ADF4350_MIN_VCO_FREQ. This might be simplified with fls()/fls_long() - * and friends. + * NOTE: This iteratively shifts freq by a power of 2 + * (st->r4_rf_div_sel) to meet or exceed ADF4350_MIN_VCO_FREQ. + * A constant-time approach using fls_long() was attempted but + * deemed more complex without meaningful benefit for init code. */ while (freq < ADF4350_MIN_VCO_FREQ) { freq <<= 1; @@ -607,7 +606,7 @@ static int adf4350_probe(struct spi_device *spi) if (dev_fwnode(&spi->dev)) { pdata = adf4350_parse_dt(&spi->dev); if (pdata == NULL) - return -EINVAL; + return -ENOMEM; } else { pdata = dev_get_platdata(&spi->dev); } @@ -692,8 +691,8 @@ static const struct of_device_id adf4350_of_match[] = { MODULE_DEVICE_TABLE(of, adf4350_of_match); static const struct spi_device_id adf4350_id[] = { - {"adf4350", 4350}, - {"adf4351", 4351}, + { .name = "adf4350", .driver_data = 4350 }, + { .name = "adf4351", .driver_data = 4351 }, { } }; MODULE_DEVICE_TABLE(spi, adf4350_id); diff --git a/drivers/iio/frequency/adf4371.c b/drivers/iio/frequency/adf4371.c index d6dc7827fb41..e20ed718d01d 100644 --- a/drivers/iio/frequency/adf4371.c +++ b/drivers/iio/frequency/adf4371.c @@ -624,8 +624,8 @@ static int adf4371_probe(struct spi_device *spi) } static const struct spi_device_id adf4371_id_table[] = { - { "adf4371", (kernel_ulong_t)&adf4371_chip_info }, - { "adf4372", (kernel_ulong_t)&adf4372_chip_info }, + { .name = "adf4371", .driver_data = (kernel_ulong_t)&adf4371_chip_info }, + { .name = "adf4372", .driver_data = (kernel_ulong_t)&adf4372_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, adf4371_id_table); diff --git a/drivers/iio/frequency/adf4377.c b/drivers/iio/frequency/adf4377.c index 8e2da218d48a..4dd19a9aa994 100644 --- a/drivers/iio/frequency/adf4377.c +++ b/drivers/iio/frequency/adf4377.c @@ -7,6 +7,7 @@ #include <linux/bitfield.h> #include <linux/bits.h> +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/clkdev.h> @@ -518,14 +519,15 @@ static int adf4377_get_freq(struct adf4377_state *st, u64 *freq) u64 clkin_freq; int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); + ret = regmap_read(st->regmap, 0x12, &ref_div_factor); if (ret) - goto exit; + return ret; ret = regmap_bulk_read(st->regmap, 0x10, st->buf, sizeof(st->buf)); if (ret) - goto exit; + return ret; clkin_freq = clk_get_rate(st->clkin); ref_div_factor = FIELD_GET(ADF4377_0012_R_DIV_MSK, ref_div_factor); @@ -533,10 +535,8 @@ static int adf4377_get_freq(struct adf4377_state *st, u64 *freq) get_unaligned_le16(&st->buf)); *freq = div_u64(clkin_freq, ref_div_factor) * n_int; -exit: - mutex_unlock(&st->lock); - return ret; + return 0; } static int adf4377_set_freq(struct adf4377_state *st, u64 freq) @@ -545,26 +545,24 @@ static int adf4377_set_freq(struct adf4377_state *st, u64 freq) u64 f_vco; int ret; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); - if (freq > ADF4377_MAX_CLKPN_FREQ || freq < ADF4377_MIN_CLKPN_FREQ) { - ret = -EINVAL; - goto exit; - } + if (freq > ADF4377_MAX_CLKPN_FREQ || freq < ADF4377_MIN_CLKPN_FREQ) + return -EINVAL; ret = regmap_update_bits(st->regmap, 0x1C, ADF4377_001C_EN_DNCLK_MSK | ADF4377_001C_EN_DRCLK_MSK, FIELD_PREP(ADF4377_001C_EN_DNCLK_MSK, 1) | FIELD_PREP(ADF4377_001C_EN_DRCLK_MSK, 1)); if (ret) - goto exit; + return ret; ret = regmap_update_bits(st->regmap, 0x11, ADF4377_0011_EN_AUTOCAL_MSK | ADF4377_0011_DCLK_DIV2_MSK, FIELD_PREP(ADF4377_0011_EN_AUTOCAL_MSK, 1) | FIELD_PREP(ADF4377_0011_DCLK_DIV2_MSK, st->dclk_div2)); if (ret) - goto exit; + return ret; ret = regmap_update_bits(st->regmap, 0x2E, ADF4377_002E_EN_ADC_CNV_MSK | ADF4377_002E_EN_ADC_MSK | @@ -574,56 +572,56 @@ static int adf4377_set_freq(struct adf4377_state *st, u64 freq) FIELD_PREP(ADF4377_002E_ADC_A_CONV_MSK, ADF4377_002E_ADC_A_CONV_VCO_CALIB)); if (ret) - goto exit; + return ret; ret = regmap_update_bits(st->regmap, 0x20, ADF4377_0020_EN_ADC_CLK_MSK, FIELD_PREP(ADF4377_0020_EN_ADC_CLK_MSK, 1)); if (ret) - goto exit; + return ret; ret = regmap_update_bits(st->regmap, 0x2F, ADF4377_002F_DCLK_DIV1_MSK, FIELD_PREP(ADF4377_002F_DCLK_DIV1_MSK, st->dclk_div1)); if (ret) - goto exit; + return ret; ret = regmap_update_bits(st->regmap, 0x24, ADF4377_0024_DCLK_MODE_MSK, FIELD_PREP(ADF4377_0024_DCLK_MODE_MSK, st->dclk_mode)); if (ret) - goto exit; + return ret; ret = regmap_write(st->regmap, 0x27, FIELD_PREP(ADF4377_0027_SYNTH_LOCK_TO_LSB_MSK, st->synth_lock_timeout)); if (ret) - goto exit; + return ret; ret = regmap_update_bits(st->regmap, 0x28, ADF4377_0028_SYNTH_LOCK_TO_MSB_MSK, FIELD_PREP(ADF4377_0028_SYNTH_LOCK_TO_MSB_MSK, st->synth_lock_timeout >> 8)); if (ret) - goto exit; + return ret; ret = regmap_write(st->regmap, 0x29, FIELD_PREP(ADF4377_0029_VCO_ALC_TO_LSB_MSK, st->vco_alc_timeout)); if (ret) - goto exit; + return ret; ret = regmap_update_bits(st->regmap, 0x2A, ADF4377_002A_VCO_ALC_TO_MSB_MSK, FIELD_PREP(ADF4377_002A_VCO_ALC_TO_MSB_MSK, st->vco_alc_timeout >> 8)); if (ret) - goto exit; + return ret; ret = regmap_write(st->regmap, 0x26, FIELD_PREP(ADF4377_0026_VCO_BAND_DIV_MSK, st->vco_band_div)); if (ret) - goto exit; + return ret; ret = regmap_write(st->regmap, 0x2D, FIELD_PREP(ADF4377_002D_ADC_CLK_DIV_MSK, st->adc_clk_div)); if (ret) - goto exit; + return ret; st->clkout_div_sel = 0; @@ -641,24 +639,24 @@ static int adf4377_set_freq(struct adf4377_state *st, u64 freq) FIELD_PREP(ADF4377_0011_EN_RDBLR_MSK, 0) | FIELD_PREP(ADF4377_0011_N_INT_MSB_MSK, st->n_int >> 8)); if (ret) - goto exit; + return ret; ret = regmap_update_bits(st->regmap, 0x12, ADF4377_0012_R_DIV_MSK | ADF4377_0012_CLKOUT_DIV_MSK, FIELD_PREP(ADF4377_0012_CLKOUT_DIV_MSK, st->clkout_div_sel) | FIELD_PREP(ADF4377_0012_R_DIV_MSK, st->ref_div_factor)); if (ret) - goto exit; + return ret; ret = regmap_write(st->regmap, 0x10, FIELD_PREP(ADF4377_0010_N_INT_LSB_MSK, st->n_int)); if (ret) - goto exit; + return ret; ret = regmap_read_poll_timeout(st->regmap, 0x49, read_val, !(read_val & (ADF4377_0049_FSM_BUSY_MSK)), 200, 200 * 100); if (ret) - goto exit; + return ret; /* Disable EN_DNCLK, EN_DRCLK */ ret = regmap_update_bits(st->regmap, 0x1C, ADF4377_001C_EN_DNCLK_MSK | @@ -666,26 +664,21 @@ static int adf4377_set_freq(struct adf4377_state *st, u64 freq) FIELD_PREP(ADF4377_001C_EN_DNCLK_MSK, 0) | FIELD_PREP(ADF4377_001C_EN_DRCLK_MSK, 0)); if (ret) - goto exit; + return ret; /* Disable EN_ADC_CLK */ ret = regmap_update_bits(st->regmap, 0x20, ADF4377_0020_EN_ADC_CLK_MSK, FIELD_PREP(ADF4377_0020_EN_ADC_CLK_MSK, 0)); if (ret) - goto exit; + return ret; /* Set output Amplitude */ - ret = regmap_update_bits(st->regmap, 0x19, ADF4377_0019_CLKOUT2_OP_MSK | - ADF4377_0019_CLKOUT1_OP_MSK, - FIELD_PREP(ADF4377_0019_CLKOUT1_OP_MSK, - ADF4377_0019_CLKOUT_420MV) | - FIELD_PREP(ADF4377_0019_CLKOUT2_OP_MSK, - ADF4377_0019_CLKOUT_420MV)); - -exit: - mutex_unlock(&st->lock); - - return ret; + return regmap_update_bits(st->regmap, 0x19, ADF4377_0019_CLKOUT2_OP_MSK | + ADF4377_0019_CLKOUT1_OP_MSK, + FIELD_PREP(ADF4377_0019_CLKOUT1_OP_MSK, + ADF4377_0019_CLKOUT_420MV) | + FIELD_PREP(ADF4377_0019_CLKOUT2_OP_MSK, + ADF4377_0019_CLKOUT_420MV)); } static void adf4377_gpio_init(struct adf4377_state *st) @@ -706,23 +699,20 @@ static void adf4377_gpio_init(struct adf4377_state *st) static int adf4377_init(struct adf4377_state *st) { - struct spi_device *spi = st->spi; + struct device *dev = &st->spi->dev; int ret; adf4377_gpio_init(st); ret = adf4377_soft_reset(st); - if (ret) { - dev_err(&spi->dev, "Failed to soft reset.\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to soft reset.\n"); ret = regmap_multi_reg_write(st->regmap, adf4377_reg_defaults, ARRAY_SIZE(adf4377_reg_defaults)); - if (ret) { - dev_err(&spi->dev, "Failed to set default registers.\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "Failed to set default registers.\n"); ret = regmap_update_bits(st->regmap, 0x00, ADF4377_0000_SDO_ACTIVE_MSK | ADF4377_0000_SDO_ACTIVE_R_MSK, @@ -730,10 +720,9 @@ static int adf4377_init(struct adf4377_state *st) ADF4377_0000_SDO_ACTIVE_SPI_4W) | FIELD_PREP(ADF4377_0000_SDO_ACTIVE_R_MSK, ADF4377_0000_SDO_ACTIVE_SPI_4W)); - if (ret) { - dev_err(&spi->dev, "Failed to set 4-Wire Operation.\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "Failed to set 4-Wire Operation.\n"); st->clkin_freq = clk_get_rate(st->clkin); @@ -747,10 +736,9 @@ static int adf4377_init(struct adf4377_state *st) FIELD_PREP(ADF4377_001A_PD_PFDCP_MSK, 0) | FIELD_PREP(ADF4377_001A_PD_CLKOUT1_MSK, 0) | FIELD_PREP(ADF4377_001A_PD_CLKOUT2_MSK, 0)); - if (ret) { - dev_err(&spi->dev, "Failed to set power down registers.\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "Failed to set power down registers.\n"); /* Set Mux Output */ ret = regmap_update_bits(st->regmap, 0x1D, @@ -882,35 +870,35 @@ static const struct iio_chan_spec adf4377_channels[] = { static int adf4377_properties_parse(struct adf4377_state *st) { - struct spi_device *spi = st->spi; + struct device *dev = &st->spi->dev; int ret; - st->clkin = devm_clk_get_enabled(&spi->dev, "ref_in"); + st->clkin = devm_clk_get_enabled(dev, "ref_in"); if (IS_ERR(st->clkin)) - return dev_err_probe(&spi->dev, PTR_ERR(st->clkin), + return dev_err_probe(dev, PTR_ERR(st->clkin), "failed to get the reference input clock\n"); - st->gpio_ce = devm_gpiod_get_optional(&st->spi->dev, "chip-enable", + st->gpio_ce = devm_gpiod_get_optional(dev, "chip-enable", GPIOD_OUT_LOW); if (IS_ERR(st->gpio_ce)) - return dev_err_probe(&spi->dev, PTR_ERR(st->gpio_ce), + return dev_err_probe(dev, PTR_ERR(st->gpio_ce), "failed to get the CE GPIO\n"); - st->gpio_enclk1 = devm_gpiod_get_optional(&st->spi->dev, "clk1-enable", + st->gpio_enclk1 = devm_gpiod_get_optional(dev, "clk1-enable", GPIOD_OUT_LOW); if (IS_ERR(st->gpio_enclk1)) - return dev_err_probe(&spi->dev, PTR_ERR(st->gpio_enclk1), + return dev_err_probe(dev, PTR_ERR(st->gpio_enclk1), "failed to get the CE GPIO\n"); if (st->chip_info->has_gpio_enclk2) { - st->gpio_enclk2 = devm_gpiod_get_optional(&st->spi->dev, "clk2-enable", + st->gpio_enclk2 = devm_gpiod_get_optional(dev, "clk2-enable", GPIOD_OUT_LOW); if (IS_ERR(st->gpio_enclk2)) - return dev_err_probe(&spi->dev, PTR_ERR(st->gpio_enclk2), + return dev_err_probe(dev, PTR_ERR(st->gpio_enclk2), "failed to get the CE GPIO\n"); } - ret = device_property_match_property_string(&spi->dev, "adi,muxout-select", + ret = device_property_match_property_string(dev, "adi,muxout-select", adf4377_muxout_modes, ARRAY_SIZE(adf4377_muxout_modes)); if (ret >= 0) @@ -924,13 +912,11 @@ static int adf4377_properties_parse(struct adf4377_state *st) static int adf4377_freq_change(struct notifier_block *nb, unsigned long action, void *data) { struct adf4377_state *st = container_of(nb, struct adf4377_state, nb); - int ret; if (action == POST_RATE_CHANGE) { - mutex_lock(&st->lock); - ret = notifier_from_errno(adf4377_init(st)); - mutex_unlock(&st->lock); - return ret; + guard(mutex)(&st->lock); + + return notifier_from_errno(adf4377_init(st)); } return NOTIFY_OK; @@ -1055,9 +1041,10 @@ static int adf4377_probe(struct spi_device *spi) struct iio_dev *indio_dev; struct regmap *regmap; struct adf4377_state *st; + struct device *dev = &spi->dev; int ret; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; @@ -1080,7 +1067,7 @@ static int adf4377_probe(struct spi_device *spi) return ret; st->nb.notifier_call = adf4377_freq_change; - ret = devm_clk_notifier_register(&spi->dev, st->clkin, &st->nb); + ret = devm_clk_notifier_register(dev, st->clkin, &st->nb); if (ret) return ret; @@ -1097,12 +1084,12 @@ static int adf4377_probe(struct spi_device *spi) indio_dev->num_channels = ARRAY_SIZE(adf4377_channels); } - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct spi_device_id adf4377_id[] = { - { "adf4377", (kernel_ulong_t)&adf4377_chip_info }, - { "adf4378", (kernel_ulong_t)&adf4378_chip_info }, + { .name = "adf4377", .driver_data = (kernel_ulong_t)&adf4377_chip_info }, + { .name = "adf4378", .driver_data = (kernel_ulong_t)&adf4378_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, adf4377_id); diff --git a/drivers/iio/frequency/admfm2000.c b/drivers/iio/frequency/admfm2000.c index b2263b9afeda..0405b53c5851 100644 --- a/drivers/iio/frequency/admfm2000.c +++ b/drivers/iio/frequency/admfm2000.c @@ -11,7 +11,6 @@ #include <linux/iio/iio.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <linux/property.h> diff --git a/drivers/iio/frequency/admv1013.c b/drivers/iio/frequency/admv1013.c index d8e8d541990f..c9baaab574e3 100644 --- a/drivers/iio/frequency/admv1013.c +++ b/drivers/iio/frequency/admv1013.c @@ -11,7 +11,6 @@ #include <linux/device.h> #include <linux/iio/iio.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/notifier.h> #include <linux/property.h> #include <linux/regulator/consumer.h> @@ -85,9 +84,9 @@ enum { }; enum { - ADMV1013_SE_MODE_POS = 6, - ADMV1013_SE_MODE_NEG = 9, - ADMV1013_SE_MODE_DIFF = 12 + ADMV1013_SE_MODE_POS, + ADMV1013_SE_MODE_NEG, + ADMV1013_SE_MODE_DIFF, }; struct admv1013_state { @@ -441,7 +440,7 @@ static int admv1013_init(struct admv1013_state *st, int vcm_uv) { int ret; unsigned int data; - struct spi_device *spi = st->spi; + struct device *dev = &st->spi->dev; /* Perform a software reset */ ret = __admv1013_spi_update_bits(st, ADMV1013_REG_SPI_CONTROL, @@ -461,19 +460,30 @@ static int admv1013_init(struct admv1013_state *st, int vcm_uv) return ret; data = FIELD_GET(ADMV1013_CHIP_ID_MSK, data); - if (data != ADMV1013_CHIP_ID) { - dev_err(&spi->dev, "Invalid Chip ID.\n"); - return -EINVAL; - } + if (data != ADMV1013_CHIP_ID) + return dev_err_probe(dev, -EINVAL, "Invalid Chip ID.\n"); ret = __admv1013_spi_write(st, ADMV1013_REG_VVA_TEMP_COMP, 0xE700); if (ret) return ret; - data = FIELD_PREP(ADMV1013_QUAD_SE_MODE_MSK, st->quad_se_mode); + switch (st->quad_se_mode) { + case ADMV1013_SE_MODE_POS: + data = 6; + break; + case ADMV1013_SE_MODE_NEG: + data = 9; + break; + case ADMV1013_SE_MODE_DIFF: + data = 12; + break; + default: + return -EINVAL; + } ret = __admv1013_spi_update_bits(st, ADMV1013_REG_QUAD, - ADMV1013_QUAD_SE_MODE_MSK, data); + ADMV1013_QUAD_SE_MODE_MSK, + FIELD_PREP(ADMV1013_QUAD_SE_MODE_MSK, data)); if (ret) return ret; @@ -514,43 +524,39 @@ static void admv1013_powerdown(void *data) admv1013_spi_update_bits(data, ADMV1013_REG_ENABLE, enable_reg_msk, enable_reg); } +static const char * const admv1013_input_modes[] = { + [ADMV1013_IQ_MODE] = "iq", + [ADMV1013_IF_MODE] = "if", +}; + +static const char * const admv1013_quad_se_modes[] = { + [ADMV1013_SE_MODE_POS] = "se-pos", + [ADMV1013_SE_MODE_NEG] = "se-neg", + [ADMV1013_SE_MODE_DIFF] = "diff", +}; + static int admv1013_properties_parse(struct admv1013_state *st) { int ret; - const char *str; - struct spi_device *spi = st->spi; + struct device *dev = &st->spi->dev; - st->det_en = device_property_read_bool(&spi->dev, "adi,detector-enable"); + st->det_en = device_property_read_bool(dev, "adi,detector-enable"); - ret = device_property_read_string(&spi->dev, "adi,input-mode", &str); - if (ret) - st->input_mode = ADMV1013_IQ_MODE; + ret = device_property_match_property_string(dev, "adi,input-mode", + admv1013_input_modes, + ARRAY_SIZE(admv1013_input_modes)); + st->input_mode = ret >= 0 ? ret : ADMV1013_IQ_MODE; - if (!strcmp(str, "iq")) - st->input_mode = ADMV1013_IQ_MODE; - else if (!strcmp(str, "if")) - st->input_mode = ADMV1013_IF_MODE; - else - return -EINVAL; + ret = device_property_match_property_string(dev, "adi,quad-se-mode", + admv1013_quad_se_modes, + ARRAY_SIZE(admv1013_quad_se_modes)); + st->quad_se_mode = ret >= 0 ? ret : ADMV1013_SE_MODE_DIFF; - ret = device_property_read_string(&spi->dev, "adi,quad-se-mode", &str); - if (ret) - st->quad_se_mode = ADMV1013_SE_MODE_DIFF; - - if (!strcmp(str, "diff")) - st->quad_se_mode = ADMV1013_SE_MODE_DIFF; - else if (!strcmp(str, "se-pos")) - st->quad_se_mode = ADMV1013_SE_MODE_POS; - else if (!strcmp(str, "se-neg")) - st->quad_se_mode = ADMV1013_SE_MODE_NEG; - else - return -EINVAL; - - ret = devm_regulator_bulk_get_enable(&st->spi->dev, + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(admv1013_vcc_regs), admv1013_vcc_regs); if (ret) { - dev_err_probe(&spi->dev, ret, + dev_err_probe(dev, ret, "Failed to request VCC regulators\n"); return ret; } @@ -562,9 +568,10 @@ static int admv1013_probe(struct spi_device *spi) { struct iio_dev *indio_dev; struct admv1013_state *st; + struct device *dev = &spi->dev; int ret, vcm_uv; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; @@ -581,40 +588,38 @@ static int admv1013_probe(struct spi_device *spi) if (ret) return ret; - ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vcm"); + ret = devm_regulator_get_enable_read_voltage(dev, "vcm"); if (ret < 0) - return dev_err_probe(&spi->dev, ret, + return dev_err_probe(dev, ret, "failed to get the common-mode voltage\n"); vcm_uv = ret; - st->clkin = devm_clk_get_enabled(&spi->dev, "lo_in"); + st->clkin = devm_clk_get_enabled(dev, "lo_in"); if (IS_ERR(st->clkin)) - return dev_err_probe(&spi->dev, PTR_ERR(st->clkin), + return dev_err_probe(dev, PTR_ERR(st->clkin), "failed to get the LO input clock\n"); st->nb.notifier_call = admv1013_freq_change; - ret = devm_clk_notifier_register(&spi->dev, st->clkin, &st->nb); + ret = devm_clk_notifier_register(dev, st->clkin, &st->nb); if (ret) return ret; mutex_init(&st->lock); ret = admv1013_init(st, vcm_uv); - if (ret) { - dev_err(&spi->dev, "admv1013 init failed\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "admv1013 init failed\n"); - ret = devm_add_action_or_reset(&spi->dev, admv1013_powerdown, st); + ret = devm_add_action_or_reset(dev, admv1013_powerdown, st); if (ret) return ret; - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct spi_device_id admv1013_id[] = { - { "admv1013", 0 }, + { .name = "admv1013" }, { } }; MODULE_DEVICE_TABLE(spi, admv1013_id); diff --git a/drivers/iio/frequency/admv1014.c b/drivers/iio/frequency/admv1014.c index 7a8f92ec80a2..d1d528975229 100644 --- a/drivers/iio/frequency/admv1014.c +++ b/drivers/iio/frequency/admv1014.c @@ -12,7 +12,6 @@ #include <linux/device.h> #include <linux/iio/iio.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/notifier.h> #include <linux/property.h> #include <linux/regulator/consumer.h> @@ -610,15 +609,14 @@ static int admv1014_init(struct admv1014_state *st) { unsigned int chip_id, enable_reg, enable_reg_msk; struct spi_device *spi = st->spi; + struct device *dev = &spi->dev; int ret; ret = regulator_bulk_enable(ADMV1014_NUM_REGULATORS, st->regulators); - if (ret) { - dev_err(&spi->dev, "Failed to enable regulators"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to enable regulators"); - ret = devm_add_action_or_reset(&spi->dev, admv1014_reg_disable, st->regulators); + ret = devm_add_action_or_reset(dev, admv1014_reg_disable, st->regulators); if (ret) return ret; @@ -626,16 +624,16 @@ static int admv1014_init(struct admv1014_state *st) if (ret) return ret; - ret = devm_add_action_or_reset(&spi->dev, admv1014_clk_disable, st->clkin); + ret = devm_add_action_or_reset(dev, admv1014_clk_disable, st->clkin); if (ret) return ret; st->nb.notifier_call = admv1014_freq_change; - ret = devm_clk_notifier_register(&spi->dev, st->clkin, &st->nb); + ret = devm_clk_notifier_register(dev, st->clkin, &st->nb); if (ret) return ret; - ret = devm_add_action_or_reset(&spi->dev, admv1014_powerdown, st); + ret = devm_add_action_or_reset(dev, admv1014_powerdown, st); if (ret) return ret; @@ -643,55 +641,47 @@ static int admv1014_init(struct admv1014_state *st) ret = __admv1014_spi_update_bits(st, ADMV1014_REG_SPI_CONTROL, ADMV1014_SPI_SOFT_RESET_MSK, FIELD_PREP(ADMV1014_SPI_SOFT_RESET_MSK, 1)); - if (ret) { - dev_err(&spi->dev, "ADMV1014 SPI software reset failed.\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "ADMV1014 SPI software reset failed.\n"); ret = __admv1014_spi_update_bits(st, ADMV1014_REG_SPI_CONTROL, ADMV1014_SPI_SOFT_RESET_MSK, FIELD_PREP(ADMV1014_SPI_SOFT_RESET_MSK, 0)); - if (ret) { - dev_err(&spi->dev, "ADMV1014 SPI software reset disable failed.\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "ADMV1014 SPI software reset disable failed.\n"); ret = __admv1014_spi_write(st, ADMV1014_REG_VVA_TEMP_COMP, 0x727C); - if (ret) { - dev_err(&spi->dev, "Writing default Temperature Compensation value failed.\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "Writing default Temperature Compensation value failed.\n"); ret = __admv1014_spi_read(st, ADMV1014_REG_SPI_CONTROL, &chip_id); if (ret) return ret; chip_id = FIELD_GET(ADMV1014_CHIP_ID_MSK, chip_id); - if (chip_id != ADMV1014_CHIP_ID) { - dev_err(&spi->dev, "Invalid Chip ID.\n"); - return -EINVAL; - } + if (chip_id != ADMV1014_CHIP_ID) + return dev_err_probe(dev, -EINVAL, "Invalid Chip ID.\n"); ret = __admv1014_spi_update_bits(st, ADMV1014_REG_QUAD, ADMV1014_QUAD_SE_MODE_MSK, FIELD_PREP(ADMV1014_QUAD_SE_MODE_MSK, st->quad_se_mode)); - if (ret) { - dev_err(&spi->dev, "Writing Quad SE Mode failed.\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "Writing Quad SE Mode failed.\n"); ret = admv1014_update_quad_filters(st); - if (ret) { - dev_err(&spi->dev, "Update Quad Filters failed.\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "Update Quad Filters failed.\n"); ret = admv1014_update_vcm_settings(st); - if (ret) { - dev_err(&spi->dev, "Update VCM Settings failed.\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "Update VCM Settings failed.\n"); enable_reg_msk = ADMV1014_P1DB_COMPENSATION_MSK | ADMV1014_IF_AMP_PD_MSK | @@ -712,13 +702,14 @@ static int admv1014_properties_parse(struct admv1014_state *st) { unsigned int i; struct spi_device *spi = st->spi; + struct device *dev = &spi->dev; int ret; - st->det_en = device_property_read_bool(&spi->dev, "adi,detector-enable"); + st->det_en = device_property_read_bool(dev, "adi,detector-enable"); - st->p1db_comp = device_property_read_bool(&spi->dev, "adi,p1db-compensation-enable"); + st->p1db_comp = device_property_read_bool(dev, "adi,p1db-compensation-enable"); - ret = device_property_match_property_string(&spi->dev, "adi,input-mode", + ret = device_property_match_property_string(dev, "adi,input-mode", input_mode_names, ARRAY_SIZE(input_mode_names)); if (ret >= 0) @@ -726,7 +717,7 @@ static int admv1014_properties_parse(struct admv1014_state *st) else st->input_mode = ADMV1014_IQ_MODE; - ret = device_property_match_property_string(&spi->dev, "adi,quad-se-mode", + ret = device_property_match_property_string(dev, "adi,quad-se-mode", quad_se_mode_names, ARRAY_SIZE(quad_se_mode_names)); if (ret >= 0) @@ -737,16 +728,14 @@ static int admv1014_properties_parse(struct admv1014_state *st) for (i = 0; i < ADMV1014_NUM_REGULATORS; ++i) st->regulators[i].supply = admv1014_reg_name[i]; - ret = devm_regulator_bulk_get(&st->spi->dev, ADMV1014_NUM_REGULATORS, + ret = devm_regulator_bulk_get(dev, ADMV1014_NUM_REGULATORS, st->regulators); - if (ret) { - dev_err(&spi->dev, "Failed to request regulators"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to request regulators"); - st->clkin = devm_clk_get(&spi->dev, "lo_in"); + st->clkin = devm_clk_get(dev, "lo_in"); if (IS_ERR(st->clkin)) - return dev_err_probe(&spi->dev, PTR_ERR(st->clkin), + return dev_err_probe(dev, PTR_ERR(st->clkin), "failed to get the LO input clock\n"); return 0; @@ -756,9 +745,10 @@ static int admv1014_probe(struct spi_device *spi) { struct iio_dev *indio_dev; struct admv1014_state *st; + struct device *dev = &spi->dev; int ret; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; @@ -787,11 +777,11 @@ static int admv1014_probe(struct spi_device *spi) if (ret) return ret; - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct spi_device_id admv1014_id[] = { - { "admv1014", 0 }, + { .name = "admv1014" }, { } }; MODULE_DEVICE_TABLE(spi, admv1014_id); diff --git a/drivers/iio/frequency/admv4420.c b/drivers/iio/frequency/admv4420.c index 3ae462b4f5c9..618511eddfb1 100644 --- a/drivers/iio/frequency/admv4420.c +++ b/drivers/iio/frequency/admv4420.c @@ -243,7 +243,7 @@ static int admv4420_calc_parameters(struct admv4420_state *st) st->n_counter.n_counter = 1; } if (!sol_found) - return -1; + return -EINVAL; st->n_counter.int_val = div_u64_rem(st->n_counter.n_counter, 10, &st->n_counter.frac_val); st->n_counter.mod_val = 10; @@ -279,10 +279,9 @@ static int admv4420_setup(struct iio_dev *indio_dev) if (ret) return ret; - if (val != ADMV4420_SCRATCH_PAD_VAL_1) { - dev_err(dev, "Failed ADMV4420 to read/write scratchpad %x ", val); - return -EIO; - } + if (val != ADMV4420_SCRATCH_PAD_VAL_1) + return dev_err_probe(dev, -EIO, + "Failed ADMV4420 to read/write scratchpad %x\n", val); ret = regmap_write(st->regmap, ADMV4420_SCRATCHPAD, @@ -294,10 +293,9 @@ static int admv4420_setup(struct iio_dev *indio_dev) if (ret) return ret; - if (val != ADMV4420_SCRATCH_PAD_VAL_2) { - dev_err(dev, "Failed to read/write scratchpad %x ", val); - return -EIO; - } + if (val != ADMV4420_SCRATCH_PAD_VAL_2) + return dev_err_probe(dev, -EIO, + "Failed to read/write scratchpad %x\n", val); st->mux_sel = ADMV4420_LOCK_DTCT; st->lo_freq_hz = ADMV4420_DEFAULT_LO_FREQ_HZ; @@ -305,10 +303,10 @@ static int admv4420_setup(struct iio_dev *indio_dev) admv4420_fw_parse(st); ret = admv4420_calc_parameters(st); - if (ret) { - dev_err(dev, "Failed calc parameters for %lld ", st->vco_freq_hz); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "Failed calc parameters for %llu\n", + st->vco_freq_hz); ret = regmap_write(st->regmap, ADMV4420_R_DIV_L, FIELD_GET(0xFF, st->ref_block.divider)); @@ -344,18 +342,19 @@ static int admv4420_setup(struct iio_dev *indio_dev) static int admv4420_probe(struct spi_device *spi) { + struct device *dev = &spi->dev; struct iio_dev *indio_dev; struct admv4420_state *st; struct regmap *regmap; int ret; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; regmap = devm_regmap_init_spi(spi, &admv4420_regmap_config); if (IS_ERR(regmap)) - return dev_err_probe(&spi->dev, PTR_ERR(regmap), + return dev_err_probe(dev, PTR_ERR(regmap), "Failed to initializing spi regmap\n"); st = iio_priv(indio_dev); @@ -368,12 +367,10 @@ static int admv4420_probe(struct spi_device *spi) indio_dev->num_channels = ARRAY_SIZE(admv4420_channels); ret = admv4420_setup(indio_dev); - if (ret) { - dev_err(&spi->dev, "Setup ADMV4420 failed (%d)\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Setup ADMV4420 failed\n"); - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct of_device_id admv4420_of_match[] = { diff --git a/drivers/iio/frequency/adrf6780.c b/drivers/iio/frequency/adrf6780.c index a7a21f929970..79a615062172 100644 --- a/drivers/iio/frequency/adrf6780.c +++ b/drivers/iio/frequency/adrf6780.c @@ -13,7 +13,6 @@ #include <linux/device.h> #include <linux/iio/iio.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/spi/spi.h> #include <linux/unaligned.h> @@ -188,8 +187,11 @@ static int adrf6780_read_adc_raw(struct adrf6780_state *st, unsigned int *read_v if (ret) goto exit; - /* Recommended delay for the ADC to be ready*/ - usleep_range(200, 250); + /* + * Per ADRF6780 datasheet (Rev. D, page 23, ADC section), + * wait approximately 200 us for the ADC to be ready. + */ + fsleep(200); ret = __adrf6780_spi_read(st, ADRF6780_REG_ADC_OUTPUT, read_val); if (ret) @@ -346,23 +348,21 @@ static const struct iio_chan_spec adrf6780_channels[] = { static int adrf6780_reset(struct adrf6780_state *st) { int ret; - struct spi_device *spi = st->spi; + struct device *dev = &st->spi->dev; ret = __adrf6780_spi_update_bits(st, ADRF6780_REG_CONTROL, ADRF6780_SOFT_RESET_MSK, FIELD_PREP(ADRF6780_SOFT_RESET_MSK, 1)); - if (ret) { - dev_err(&spi->dev, "ADRF6780 SPI software reset failed.\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "ADRF6780 SPI software reset failed.\n"); ret = __adrf6780_spi_update_bits(st, ADRF6780_REG_CONTROL, ADRF6780_SOFT_RESET_MSK, FIELD_PREP(ADRF6780_SOFT_RESET_MSK, 0)); - if (ret) { - dev_err(&spi->dev, "ADRF6780 SPI software reset disable failed.\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "ADRF6780 SPI software reset disable failed.\n"); return 0; } @@ -371,7 +371,7 @@ static int adrf6780_init(struct adrf6780_state *st) { int ret; unsigned int chip_id, enable_reg, enable_reg_msk; - struct spi_device *spi = st->spi; + struct device *dev = &st->spi->dev; /* Perform a software reset */ ret = adrf6780_reset(st); @@ -383,10 +383,9 @@ static int adrf6780_init(struct adrf6780_state *st) return ret; chip_id = FIELD_GET(ADRF6780_CHIP_ID_MSK, chip_id); - if (chip_id != ADRF6780_CHIP_ID) { - dev_err(&spi->dev, "ADRF6780 Invalid Chip ID.\n"); - return -EINVAL; - } + if (chip_id != ADRF6780_CHIP_ID) + return dev_err_probe(dev, -EINVAL, + "ADRF6780 Invalid Chip ID.\n"); enable_reg_msk = ADRF6780_VGA_BUFFER_EN_MSK | ADRF6780_DETECTOR_EN_MSK | @@ -426,18 +425,18 @@ static int adrf6780_init(struct adrf6780_state *st) static void adrf6780_properties_parse(struct adrf6780_state *st) { - struct spi_device *spi = st->spi; - - st->vga_buff_en = device_property_read_bool(&spi->dev, "adi,vga-buff-en"); - st->lo_buff_en = device_property_read_bool(&spi->dev, "adi,lo-buff-en"); - st->if_mode_en = device_property_read_bool(&spi->dev, "adi,if-mode-en"); - st->iq_mode_en = device_property_read_bool(&spi->dev, "adi,iq-mode-en"); - st->lo_x2_en = device_property_read_bool(&spi->dev, "adi,lo-x2-en"); - st->lo_ppf_en = device_property_read_bool(&spi->dev, "adi,lo-ppf-en"); - st->lo_en = device_property_read_bool(&spi->dev, "adi,lo-en"); - st->uc_bias_en = device_property_read_bool(&spi->dev, "adi,uc-bias-en"); - st->lo_sideband = device_property_read_bool(&spi->dev, "adi,lo-sideband"); - st->vdet_out_en = device_property_read_bool(&spi->dev, "adi,vdet-out-en"); + struct device *dev = &st->spi->dev; + + st->vga_buff_en = device_property_read_bool(dev, "adi,vga-buff-en"); + st->lo_buff_en = device_property_read_bool(dev, "adi,lo-buff-en"); + st->if_mode_en = device_property_read_bool(dev, "adi,if-mode-en"); + st->iq_mode_en = device_property_read_bool(dev, "adi,iq-mode-en"); + st->lo_x2_en = device_property_read_bool(dev, "adi,lo-x2-en"); + st->lo_ppf_en = device_property_read_bool(dev, "adi,lo-ppf-en"); + st->lo_en = device_property_read_bool(dev, "adi,lo-en"); + st->uc_bias_en = device_property_read_bool(dev, "adi,uc-bias-en"); + st->lo_sideband = device_property_read_bool(dev, "adi,lo-sideband"); + st->vdet_out_en = device_property_read_bool(dev, "adi,vdet-out-en"); } static void adrf6780_powerdown(void *data) @@ -450,9 +449,10 @@ static int adrf6780_probe(struct spi_device *spi) { struct iio_dev *indio_dev; struct adrf6780_state *st; + struct device *dev = &spi->dev; int ret; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; @@ -467,9 +467,9 @@ static int adrf6780_probe(struct spi_device *spi) adrf6780_properties_parse(st); - st->clkin = devm_clk_get_enabled(&spi->dev, "lo_in"); + st->clkin = devm_clk_get_enabled(dev, "lo_in"); if (IS_ERR(st->clkin)) - return dev_err_probe(&spi->dev, PTR_ERR(st->clkin), + return dev_err_probe(dev, PTR_ERR(st->clkin), "failed to get the LO input clock\n"); mutex_init(&st->lock); @@ -478,15 +478,15 @@ static int adrf6780_probe(struct spi_device *spi) if (ret) return ret; - ret = devm_add_action_or_reset(&spi->dev, adrf6780_powerdown, st); + ret = devm_add_action_or_reset(dev, adrf6780_powerdown, st); if (ret) return ret; - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct spi_device_id adrf6780_id[] = { - { "adrf6780", 0 }, + { .name = "adrf6780" }, { } }; MODULE_DEVICE_TABLE(spi, adrf6780_id); diff --git a/drivers/iio/gyro/adis16080.c b/drivers/iio/gyro/adis16080.c index 178bba95a709..0c8bc1e569fe 100644 --- a/drivers/iio/gyro/adis16080.c +++ b/drivers/iio/gyro/adis16080.c @@ -212,8 +212,8 @@ static int adis16080_probe(struct spi_device *spi) } static const struct spi_device_id adis16080_ids[] = { - { "adis16080", ID_ADIS16080 }, - { "adis16100", ID_ADIS16100 }, + { .name = "adis16080", .driver_data = ID_ADIS16080 }, + { .name = "adis16100", .driver_data = ID_ADIS16100 }, { } }; MODULE_DEVICE_TABLE(spi, adis16080_ids); diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c index 369c7428e1ef..ff335f81e9ae 100644 --- a/drivers/iio/gyro/adis16136.c +++ b/drivers/iio/gyro/adis16136.c @@ -563,10 +563,10 @@ static int adis16136_probe(struct spi_device *spi) } static const struct spi_device_id adis16136_ids[] = { - { "adis16133", ID_ADIS16133 }, - { "adis16135", ID_ADIS16135 }, - { "adis16136", ID_ADIS16136 }, - { "adis16137", ID_ADIS16137 }, + { .name = "adis16133", .driver_data = ID_ADIS16133 }, + { .name = "adis16135", .driver_data = ID_ADIS16135 }, + { .name = "adis16136", .driver_data = ID_ADIS16136 }, + { .name = "adis16137", .driver_data = ID_ADIS16137 }, { } }; MODULE_DEVICE_TABLE(spi, adis16136_ids); diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c index 586e6cfa14a9..a79a8edf4c98 100644 --- a/drivers/iio/gyro/adis16260.c +++ b/drivers/iio/gyro/adis16260.c @@ -287,6 +287,9 @@ 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: + if (val <= 0) + return -EINVAL; + if (spi_get_device_id(adis->spi)->driver_data) t = 256 / val; else @@ -408,12 +411,12 @@ static int adis16260_probe(struct spi_device *spi) * support for the on chip filtering. */ static const struct spi_device_id adis16260_id[] = { - {"adis16260", ADIS16260}, - {"adis16265", ADIS16260}, - {"adis16266", ADIS16266}, - {"adis16250", ADIS16260}, - {"adis16255", ADIS16260}, - {"adis16251", ADIS16251}, + { .name = "adis16260", .driver_data = ADIS16260 }, + { .name = "adis16265", .driver_data = ADIS16260 }, + { .name = "adis16266", .driver_data = ADIS16266 }, + { .name = "adis16250", .driver_data = ADIS16260 }, + { .name = "adis16255", .driver_data = ADIS16260 }, + { .name = "adis16251", .driver_data = ADIS16251 }, { } }; MODULE_DEVICE_TABLE(spi, adis16260_id); diff --git a/drivers/iio/gyro/adxrs290.c b/drivers/iio/gyro/adxrs290.c index 3efe385ebedc..563de2724396 100644 --- a/drivers/iio/gyro/adxrs290.c +++ b/drivers/iio/gyro/adxrs290.c @@ -8,6 +8,7 @@ #include <linux/bitfield.h> #include <linux/bitops.h> +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/kernel.h> @@ -115,65 +116,53 @@ static const int adxrs290_hpf_3db_freq_hz_table[][2] = { static int adxrs290_get_rate_data(struct iio_dev *indio_dev, const u8 cmd, int *val) { struct adxrs290_state *st = iio_priv(indio_dev); - int ret = 0; int temp; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); + temp = spi_w8r16(st->spi, cmd); - if (temp < 0) { - ret = temp; - goto err_unlock; - } + if (temp < 0) + return temp; *val = sign_extend32(temp, 15); -err_unlock: - mutex_unlock(&st->lock); - return ret; + return 0; } static int adxrs290_get_temp_data(struct iio_dev *indio_dev, int *val) { const u8 cmd = ADXRS290_READ_REG(ADXRS290_REG_TEMP0); struct adxrs290_state *st = iio_priv(indio_dev); - int ret = 0; int temp; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); + temp = spi_w8r16(st->spi, cmd); - if (temp < 0) { - ret = temp; - goto err_unlock; - } + if (temp < 0) + return temp; /* extract lower 12 bits temperature reading */ *val = sign_extend32(temp, 11); -err_unlock: - mutex_unlock(&st->lock); - return ret; + return 0; } static int adxrs290_get_3db_freq(struct iio_dev *indio_dev, u8 *val, u8 *val2) { const u8 cmd = ADXRS290_READ_REG(ADXRS290_REG_FILTER); struct adxrs290_state *st = iio_priv(indio_dev); - int ret = 0; short temp; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); + temp = spi_w8r8(st->spi, cmd); - if (temp < 0) { - ret = temp; - goto err_unlock; - } + if (temp < 0) + return temp; *val = FIELD_GET(ADXRS290_LPF_MASK, temp); *val2 = FIELD_GET(ADXRS290_HPF_MASK, temp); -err_unlock: - mutex_unlock(&st->lock); - return ret; + return 0; } static int adxrs290_spi_write_reg(struct spi_device *spi, const u8 reg, @@ -220,11 +209,11 @@ static int adxrs290_set_mode(struct iio_dev *indio_dev, enum adxrs290_mode mode) if (st->mode == mode) return 0; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); ret = spi_w8r8(st->spi, ADXRS290_READ_REG(ADXRS290_REG_POWER_CTL)); if (ret < 0) - goto out_unlock; + return ret; val = ret; @@ -236,21 +225,18 @@ static int adxrs290_set_mode(struct iio_dev *indio_dev, enum adxrs290_mode mode) val |= ADXRS290_MEASUREMENT; break; default: - ret = -EINVAL; - goto out_unlock; + return -EINVAL; } ret = adxrs290_spi_write_reg(st->spi, ADXRS290_REG_POWER_CTL, val); if (ret < 0) { dev_err(&st->spi->dev, "unable to set mode: %d\n", ret); - goto out_unlock; + return ret; } /* update cached mode */ st->mode = mode; -out_unlock: - mutex_unlock(&st->lock); return ret; } @@ -506,19 +492,20 @@ static irqreturn_t adxrs290_trigger_handler(int irq, void *p) u8 tx = ADXRS290_READ_REG(ADXRS290_REG_DATAX0); int ret; - mutex_lock(&st->lock); + do { + guard(mutex)(&st->lock); - /* exercise a bulk data capture starting from reg DATAX0... */ - ret = spi_write_then_read(st->spi, &tx, sizeof(tx), st->buffer.channels, - sizeof(st->buffer.channels)); - if (ret < 0) - goto out_unlock_notify; + /* exercise a bulk data capture starting from reg DATAX0... */ + ret = spi_write_then_read(st->spi, &tx, sizeof(tx), + st->buffer.channels, + sizeof(st->buffer.channels)); + if (ret < 0) + break; - iio_push_to_buffers_with_timestamp(indio_dev, &st->buffer, - pf->timestamp); + iio_push_to_buffers_with_timestamp(indio_dev, &st->buffer, + pf->timestamp); + } while (0); -out_unlock_notify: - mutex_unlock(&st->lock); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; @@ -598,9 +585,8 @@ static int adxrs290_probe_trigger(struct iio_dev *indio_dev) ret = devm_request_irq(&st->spi->dev, st->spi->irq, &iio_trigger_generic_data_rdy_poll, IRQF_NO_THREAD, "adxrs290_irq", st->dready_trig); - if (ret < 0) - return dev_err_probe(&st->spi->dev, ret, - "request irq %d failed\n", st->spi->irq); + if (ret) + return ret; ret = devm_iio_trigger_register(&st->spi->dev, st->dready_trig); if (ret) { diff --git a/drivers/iio/gyro/adxrs450.c b/drivers/iio/gyro/adxrs450.c index a1d8d3cb301b..030d042cab8b 100644 --- a/drivers/iio/gyro/adxrs450.c +++ b/drivers/iio/gyro/adxrs450.c @@ -439,8 +439,8 @@ static int adxrs450_probe(struct spi_device *spi) } static const struct spi_device_id adxrs450_id[] = { - {"adxrs450", ID_ADXRS450}, - {"adxrs453", ID_ADXRS453}, + { .name = "adxrs450", .driver_data = ID_ADXRS450 }, + { .name = "adxrs453", .driver_data = ID_ADXRS453 }, { } }; MODULE_DEVICE_TABLE(spi, adxrs450_id); diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c index 38394b5f3275..d611341a0e2a 100644 --- a/drivers/iio/gyro/bmg160_core.c +++ b/drivers/iio/gyro/bmg160_core.c @@ -201,6 +201,9 @@ static int bmg160_get_filter(struct bmg160_data *data, int *val) break; } + if (i == ARRAY_SIZE(bmg160_samp_freq_table)) + return -EINVAL; + *val = bmg160_samp_freq_table[i].filter; return ret ? ret : IIO_VAL_INT; @@ -218,6 +221,9 @@ static int bmg160_set_filter(struct bmg160_data *data, int val) break; } + if (i == ARRAY_SIZE(bmg160_samp_freq_table)) + return -EINVAL; + ret = regmap_write(data->regmap, BMG160_REG_PMU_BW, bmg160_samp_freq_table[i].bw_bits); if (ret < 0) { @@ -258,8 +264,14 @@ static int bmg160_chip_init(struct bmg160_data *data) if (ret < 0) return ret; - /* Wait upto 500 ms to be ready after changing mode */ - usleep_range(500, 1000); + /* + * Wait for the chip to be ready after switching to normal mode. + * The BMG160 datasheet (BST-BMG160-DS000-07 Rev. 1.0, May 2013) + * specifies a start-up / wake-up time (tsu, twusm) of 30 ms; use + * BMG160_MAX_STARTUP_TIME_MS (80 ms) as a safety margin, matching + * what bmg160_runtime_resume() already does. + */ + msleep(BMG160_MAX_STARTUP_TIME_MS); /* Set Bandwidth */ ret = bmg160_set_bw(data, BMG160_DEF_BW); diff --git a/drivers/iio/gyro/bmg160_i2c.c b/drivers/iio/gyro/bmg160_i2c.c index 1fb8a7969c25..be3cfbd286aa 100644 --- a/drivers/iio/gyro/bmg160_i2c.c +++ b/drivers/iio/gyro/bmg160_i2c.c @@ -3,7 +3,6 @@ #include <linux/regmap.h> #include <linux/iio/iio.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include "bmg160.h" @@ -47,9 +46,9 @@ static const struct acpi_device_id bmg160_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, bmg160_acpi_match); static const struct i2c_device_id bmg160_i2c_id[] = { - { "bmg160" }, - { "bmi055_gyro" }, - { "bmi088_gyro" }, + { .name = "bmg160" }, + { .name = "bmi055_gyro" }, + { .name = "bmi088_gyro" }, { } }; diff --git a/drivers/iio/gyro/bmg160_spi.c b/drivers/iio/gyro/bmg160_spi.c index 6aecc5eb8347..14ae1d03be3d 100644 --- a/drivers/iio/gyro/bmg160_spi.c +++ b/drivers/iio/gyro/bmg160_spi.c @@ -33,12 +33,11 @@ static void bmg160_spi_remove(struct spi_device *spi) } static const struct spi_device_id bmg160_spi_id[] = { - {"bmg160", 0}, - {"bmi055_gyro", 0}, - {"bmi088_gyro", 0}, + { .name = "bmg160" }, + { .name = "bmi055_gyro" }, + { .name = "bmi088_gyro" }, { } }; - MODULE_DEVICE_TABLE(spi, bmg160_spi_id); static const struct of_device_id bmg160_of_match[] = { diff --git a/drivers/iio/gyro/fxas21002c_i2c.c b/drivers/iio/gyro/fxas21002c_i2c.c index 43c6b3079487..634f9019aa96 100644 --- a/drivers/iio/gyro/fxas21002c_i2c.c +++ b/drivers/iio/gyro/fxas21002c_i2c.c @@ -7,7 +7,6 @@ #include <linux/err.h> #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> @@ -39,7 +38,7 @@ static void fxas21002c_i2c_remove(struct i2c_client *i2c) } static const struct i2c_device_id fxas21002c_i2c_id[] = { - { "fxas21002c" }, + { .name = "fxas21002c" }, { } }; MODULE_DEVICE_TABLE(i2c, fxas21002c_i2c_id); diff --git a/drivers/iio/gyro/fxas21002c_spi.c b/drivers/iio/gyro/fxas21002c_spi.c index d62efe50b697..40b1e02b2a5c 100644 --- a/drivers/iio/gyro/fxas21002c_spi.c +++ b/drivers/iio/gyro/fxas21002c_spi.c @@ -6,7 +6,6 @@ */ #include <linux/err.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> #include <linux/spi/spi.h> @@ -40,7 +39,7 @@ static void fxas21002c_spi_remove(struct spi_device *spi) } static const struct spi_device_id fxas21002c_spi_id[] = { - { "fxas21002c", 0 }, + { .name = "fxas21002c" }, { } }; MODULE_DEVICE_TABLE(spi, fxas21002c_spi_id); diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index c43990c518f7..58250a972567 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -3,10 +3,10 @@ * HID Sensors Driver * Copyright (c) 2012, Intel Corporation. */ +#include <linux/bitops.h> #include <linux/device.h> #include <linux/platform_device.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/slab.h> #include <linux/hid-sensor-hub.h> #include <linux/iio/iio.h> @@ -42,7 +42,7 @@ static const u32 gyro_3d_addresses[GYRO_3D_CHANNEL_MAX] = { HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS }; -static const u32 gryo_3d_sensitivity_addresses[] = { +static const u32 gyro_3d_sensitivity_addresses[] = { HID_USAGE_SENSOR_DATA_ANGL_VELOCITY, }; @@ -82,22 +82,10 @@ static const struct iio_chan_spec gyro_3d_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP) }; -/* Adjust channel real bits based on report descriptor */ -static void gyro_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels, - int channel, int size) -{ - channels[channel].scan_type.sign = 's'; - /* Real storage bits will change based on the report desc. */ - channels[channel].scan_type.realbits = size * 8; - /* Maximum size of a sample to capture is u32 */ - channels[channel].scan_type.storagebits = sizeof(u32) * 8; -} - /* Channel read_raw handler */ static int gyro_3d_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, - long mask) + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { struct gyro_3d_state *gyro_state = iio_priv(indio_dev); int report_id = -1; @@ -122,8 +110,7 @@ static int gyro_3d_read_raw(struct iio_dev *indio_dev, min < 0); else { *val = 0; - hid_sensor_power_state(&gyro_state->common_attributes, - false); + hid_sensor_power_state(&gyro_state->common_attributes, false); return -EINVAL; } hid_sensor_power_state(&gyro_state->common_attributes, false); @@ -156,10 +143,8 @@ static int gyro_3d_read_raw(struct iio_dev *indio_dev, /* Channel write_raw handler */ static int gyro_3d_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct gyro_3d_state *gyro_state = iio_priv(indio_dev); int ret = 0; @@ -187,8 +172,7 @@ static const struct iio_info gyro_3d_info = { /* Callback handler to send event after all samples are received and captured */ static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - void *priv) + u32 usage_id, void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct gyro_3d_state *gyro_state = iio_priv(indio_dev); @@ -209,9 +193,9 @@ static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int gyro_3d_capture_sample(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - size_t raw_len, char *raw_data, - void *priv) + u32 usage_id, + size_t raw_len, char *raw_data, + void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct gyro_3d_state *gyro_state = iio_priv(indio_dev); @@ -244,29 +228,30 @@ static int gyro_3d_capture_sample(struct hid_sensor_hub_device *hsdev, static int gyro_3d_parse_report(struct platform_device *pdev, struct hid_sensor_hub_device *hsdev, struct iio_chan_spec *channels, - unsigned usage_id, + u32 usage_id, struct gyro_3d_state *st) { int ret; - int i; - for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) { + for (unsigned int ch = CHANNEL_SCAN_INDEX_X; ch <= CHANNEL_SCAN_INDEX_Z; ch++) { ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT, usage_id, - HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS + i, - &st->gyro[CHANNEL_SCAN_INDEX_X + i]); + HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS + ch, + &st->gyro[ch]); if (ret < 0) break; - gyro_3d_adjust_channel_bit_mask(channels, - CHANNEL_SCAN_INDEX_X + i, - st->gyro[CHANNEL_SCAN_INDEX_X + i].size); + channels[ch].scan_type = (struct iio_scan_type) { + .format = 's', + .realbits = BYTES_TO_BITS(st->gyro[ch].size), + .storagebits = BITS_PER_TYPE(u32), + }; } dev_dbg(&pdev->dev, "gyro_3d %x:%x, %x:%x, %x:%x\n", - st->gyro[0].index, - st->gyro[0].report_id, - st->gyro[1].index, st->gyro[1].report_id, - st->gyro[2].index, st->gyro[2].report_id); + st->gyro[0].index, + st->gyro[0].report_id, + st->gyro[1].index, st->gyro[1].report_id, + st->gyro[2].index, st->gyro[2].report_id); st->scale_precision = hid_sensor_format_scale( HID_USAGE_SENSOR_GYRO_3D, @@ -297,8 +282,8 @@ static int hid_gyro_3d_probe(struct platform_device *pdev) ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_GYRO_3D, &gyro_state->common_attributes, - gryo_3d_sensitivity_addresses, - ARRAY_SIZE(gryo_3d_sensitivity_addresses)); + gyro_3d_sensitivity_addresses, + ARRAY_SIZE(gyro_3d_sensitivity_addresses)); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); return ret; @@ -327,32 +312,32 @@ static int hid_gyro_3d_probe(struct platform_device *pdev) atomic_set(&gyro_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, - &gyro_state->common_attributes); + &gyro_state->common_attributes); if (ret < 0) { dev_err(&pdev->dev, "trigger setup failed\n"); return ret; } - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(&pdev->dev, "device register failed\n"); - goto error_remove_trigger; - } - gyro_state->callbacks.send_event = gyro_3d_proc_event; gyro_state->callbacks.capture_sample = gyro_3d_capture_sample; gyro_state->callbacks.pdev = pdev; ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D, - &gyro_state->callbacks); + &gyro_state->callbacks); if (ret < 0) { dev_err(&pdev->dev, "callback reg failed\n"); - goto error_iio_unreg; + goto error_remove_trigger; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "device register failed\n"); + goto error_remove_callback; } return ret; -error_iio_unreg: - iio_device_unregister(indio_dev); +error_remove_callback: + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D); error_remove_trigger: hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes); return ret; @@ -365,8 +350,8 @@ static void hid_gyro_3d_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct gyro_3d_state *gyro_state = iio_priv(indio_dev); - sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D); iio_device_unregister(indio_dev); + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D); hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes); } diff --git a/drivers/iio/gyro/itg3200_buffer.c b/drivers/iio/gyro/itg3200_buffer.c index cf97adfa9727..87efa2c74ca4 100644 --- a/drivers/iio/gyro/itg3200_buffer.c +++ b/drivers/iio/gyro/itg3200_buffer.c @@ -34,7 +34,7 @@ static int itg3200_read_all_channels(struct i2c_client *i2c, __be16 *buf) .addr = i2c->addr, .flags = i2c->flags | I2C_M_RD, .len = ITG3200_SCAN_ELEMENTS * sizeof(s16), - .buf = (char *)&buf, + .buf = (char *)buf, }, }; diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c index bfe95ec1abda..6b13d54d9b01 100644 --- a/drivers/iio/gyro/itg3200_core.c +++ b/drivers/iio/gyro/itg3200_core.c @@ -389,7 +389,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(itg3200_pm_ops, itg3200_suspend, itg3200_resume); static const struct i2c_device_id itg3200_id[] = { - { "itg3200" }, + { .name = "itg3200" }, { } }; MODULE_DEVICE_TABLE(i2c, itg3200_id); diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c index 317e7b217ec6..07c0f9011c63 100644 --- a/drivers/iio/gyro/mpu3050-core.c +++ b/drivers/iio/gyro/mpu3050-core.c @@ -356,7 +356,7 @@ static int mpu3050_read_raw(struct iio_dev *indio_dev, goto out_read_raw_unlock; } - *val = be16_to_cpu(raw_val); + *val = (s16)be16_to_cpu(raw_val); ret = IIO_VAL_INT; goto out_read_raw_unlock; @@ -1129,11 +1129,16 @@ static int mpu3050_trigger_probe(struct iio_dev *indio_dev, int irq) ret = iio_trigger_register(mpu3050->trig); if (ret) - return ret; + goto err_iio_trigger; indio_dev->trig = iio_trigger_get(mpu3050->trig); return 0; + +err_iio_trigger: + free_irq(mpu3050->irq, mpu3050->trig); + + return ret; } int mpu3050_common_probe(struct device *dev, @@ -1221,12 +1226,6 @@ int mpu3050_common_probe(struct device *dev, goto err_power_down; } - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(dev, "device register failed\n"); - goto err_cleanup_buffer; - } - dev_set_drvdata(dev, indio_dev); /* Check if we have an assigned IRQ to use as trigger */ @@ -1249,9 +1248,20 @@ int mpu3050_common_probe(struct device *dev, pm_runtime_use_autosuspend(dev); pm_runtime_put(dev); + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(dev, "device register failed\n"); + goto err_iio_device_register; + } + return 0; -err_cleanup_buffer: +err_iio_device_register: + pm_runtime_get_sync(dev); + pm_runtime_put_noidle(dev); + pm_runtime_disable(dev); + if (irq) + free_irq(mpu3050->irq, mpu3050->trig); iio_triggered_buffer_cleanup(indio_dev); err_power_down: mpu3050_power_down(mpu3050); @@ -1264,13 +1274,13 @@ void mpu3050_common_remove(struct device *dev) struct iio_dev *indio_dev = dev_get_drvdata(dev); struct mpu3050 *mpu3050 = iio_priv(indio_dev); + iio_device_unregister(indio_dev); pm_runtime_get_sync(dev); pm_runtime_put_noidle(dev); pm_runtime_disable(dev); - iio_triggered_buffer_cleanup(indio_dev); if (mpu3050->irq) - free_irq(mpu3050->irq, mpu3050); - iio_device_unregister(indio_dev); + free_irq(mpu3050->irq, mpu3050->trig); + iio_triggered_buffer_cleanup(indio_dev); mpu3050_power_down(mpu3050); } diff --git a/drivers/iio/gyro/mpu3050-i2c.c b/drivers/iio/gyro/mpu3050-i2c.c index 6549b22e643d..2a5bcec7272c 100644 --- a/drivers/iio/gyro/mpu3050-i2c.c +++ b/drivers/iio/gyro/mpu3050-i2c.c @@ -92,7 +92,7 @@ static void mpu3050_i2c_remove(struct i2c_client *client) * supported by this driver */ static const struct i2c_device_id mpu3050_i2c_id[] = { - { "mpu3050" }, + { .name = "mpu3050" }, { } }; MODULE_DEVICE_TABLE(i2c, mpu3050_i2c_id); diff --git a/drivers/iio/gyro/ssp_gyro_sensor.c b/drivers/iio/gyro/ssp_gyro_sensor.c index d9b41cf8d799..1acbbc1eeec3 100644 --- a/drivers/iio/gyro/ssp_gyro_sensor.c +++ b/drivers/iio/gyro/ssp_gyro_sensor.c @@ -76,7 +76,7 @@ static const struct iio_chan_spec ssp_gyro_channels[] = { SSP_CHANNEL_AG(IIO_ANGL_VEL, IIO_MOD_X, SSP_CHANNEL_SCAN_INDEX_X), SSP_CHANNEL_AG(IIO_ANGL_VEL, IIO_MOD_Y, SSP_CHANNEL_SCAN_INDEX_Y), SSP_CHANNEL_AG(IIO_ANGL_VEL, IIO_MOD_Z, SSP_CHANNEL_SCAN_INDEX_Z), - SSP_CHAN_TIMESTAMP(SSP_CHANNEL_SCAN_INDEX_TIME), + IIO_CHAN_SOFT_TIMESTAMP(SSP_CHANNEL_SCAN_INDEX_TIME), }; static int ssp_process_gyro_data(struct iio_dev *indio_dev, void *buf, diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c index aef5ec8f9dee..a587e9023ceb 100644 --- a/drivers/iio/gyro/st_gyro_i2c.c +++ b/drivers/iio/gyro/st_gyro_i2c.c @@ -9,7 +9,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/iio/iio.h> @@ -93,15 +92,15 @@ static int st_gyro_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id st_gyro_id_table[] = { - { L3G4200D_GYRO_DEV_NAME }, - { LSM330D_GYRO_DEV_NAME }, - { LSM330DL_GYRO_DEV_NAME }, - { LSM330DLC_GYRO_DEV_NAME }, - { L3GD20_GYRO_DEV_NAME }, - { L3GD20H_GYRO_DEV_NAME }, - { L3G4IS_GYRO_DEV_NAME }, - { LSM330_GYRO_DEV_NAME }, - { LSM9DS0_GYRO_DEV_NAME }, + { .name = L3G4200D_GYRO_DEV_NAME }, + { .name = LSM330D_GYRO_DEV_NAME }, + { .name = LSM330DL_GYRO_DEV_NAME }, + { .name = LSM330DLC_GYRO_DEV_NAME }, + { .name = L3GD20_GYRO_DEV_NAME }, + { .name = L3GD20H_GYRO_DEV_NAME }, + { .name = L3G4IS_GYRO_DEV_NAME }, + { .name = LSM330_GYRO_DEV_NAME }, + { .name = LSM9DS0_GYRO_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, st_gyro_id_table); diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c index f645da157372..c56331755b5c 100644 --- a/drivers/iio/gyro/st_gyro_spi.c +++ b/drivers/iio/gyro/st_gyro_spi.c @@ -9,7 +9,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/spi/spi.h> #include <linux/iio/iio.h> @@ -98,15 +97,15 @@ static int st_gyro_spi_probe(struct spi_device *spi) } static const struct spi_device_id st_gyro_id_table[] = { - { L3G4200D_GYRO_DEV_NAME }, - { LSM330D_GYRO_DEV_NAME }, - { LSM330DL_GYRO_DEV_NAME }, - { LSM330DLC_GYRO_DEV_NAME }, - { L3GD20_GYRO_DEV_NAME }, - { L3GD20H_GYRO_DEV_NAME }, - { L3G4IS_GYRO_DEV_NAME }, - { LSM330_GYRO_DEV_NAME }, - { LSM9DS0_GYRO_DEV_NAME }, + { .name = L3G4200D_GYRO_DEV_NAME }, + { .name = LSM330D_GYRO_DEV_NAME }, + { .name = LSM330DL_GYRO_DEV_NAME }, + { .name = LSM330DLC_GYRO_DEV_NAME }, + { .name = L3GD20_GYRO_DEV_NAME }, + { .name = L3GD20H_GYRO_DEV_NAME }, + { .name = L3G4IS_GYRO_DEV_NAME }, + { .name = LSM330_GYRO_DEV_NAME }, + { .name = LSM9DS0_GYRO_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(spi, st_gyro_id_table); diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c index d358f4d5e5da..2a648532242a 100644 --- a/drivers/iio/health/afe4403.c +++ b/drivers/iio/health/afe4403.c @@ -544,10 +544,8 @@ static int afe4403_probe(struct spi_device *spi) iio_trigger_generic_data_rdy_poll, IRQF_NO_THREAD, AFE4403_DRIVER_NAME, afe->trig); - if (ret) { - dev_err(dev, "Unable to request IRQ\n"); + if (ret) return ret; - } } ret = devm_iio_triggered_buffer_setup(dev, indio_dev, @@ -568,7 +566,7 @@ static int afe4403_probe(struct spi_device *spi) } static const struct spi_device_id afe4403_ids[] = { - { "afe4403", 0 }, + { .name = "afe4403" }, { } }; MODULE_DEVICE_TABLE(spi, afe4403_ids); diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index 032da52a96d0..22cd46eca217 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -551,10 +551,8 @@ static int afe4404_probe(struct i2c_client *client) iio_trigger_generic_data_rdy_poll, IRQF_NO_THREAD, AFE4404_DRIVER_NAME, afe->trig); - if (ret) { - dev_err(dev, "Unable to request IRQ\n"); + if (ret) return ret; - } } ret = devm_iio_triggered_buffer_setup(dev, indio_dev, @@ -575,7 +573,7 @@ static int afe4404_probe(struct i2c_client *client) } static const struct i2c_device_id afe4404_ids[] = { - { "afe4404" }, + { .name = "afe4404" }, { } }; MODULE_DEVICE_TABLE(i2c, afe4404_ids); diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c index 7dfdb5eb305e..191540e10c20 100644 --- a/drivers/iio/health/max30100.c +++ b/drivers/iio/health/max30100.c @@ -489,10 +489,8 @@ static int max30100_probe(struct i2c_client *client) NULL, max30100_interrupt_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "max30100_irq", indio_dev); - if (ret) { - dev_err(&client->dev, "request irq (%d) failed\n", client->irq); + if (ret) return ret; - } return iio_device_register(indio_dev); } @@ -507,7 +505,7 @@ static void max30100_remove(struct i2c_client *client) } static const struct i2c_device_id max30100_id[] = { - { "max30100" }, + { .name = "max30100" }, { } }; MODULE_DEVICE_TABLE(i2c, max30100_id); diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c index 47da44efd68b..c37316c86f14 100644 --- a/drivers/iio/health/max30102.c +++ b/drivers/iio/health/max30102.c @@ -19,7 +19,6 @@ #include <linux/irq.h> #include <linux/i2c.h> #include <linux/mutex.h> -#include <linux/mod_devicetable.h> #include <linux/regmap.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> @@ -578,10 +577,8 @@ static int max30102_probe(struct i2c_client *client) NULL, max30102_interrupt_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "max30102_irq", indio_dev); - if (ret) { - dev_err(&client->dev, "request irq (%d) failed\n", client->irq); + if (ret) return ret; - } return iio_device_register(indio_dev); } @@ -596,9 +593,9 @@ static void max30102_remove(struct i2c_client *client) } static const struct i2c_device_id max30102_id[] = { - { "max30101", max30105 }, - { "max30102", max30102 }, - { "max30105", max30105 }, + { .name = "max30101", .driver_data = max30105 }, + { .name = "max30102", .driver_data = max30102 }, + { .name = "max30105", .driver_data = max30105 }, { } }; MODULE_DEVICE_TABLE(i2c, max30102_id); diff --git a/drivers/iio/humidity/am2315.c b/drivers/iio/humidity/am2315.c index 02ca23eb8991..f29baa251f9f 100644 --- a/drivers/iio/humidity/am2315.c +++ b/drivers/iio/humidity/am2315.c @@ -250,7 +250,7 @@ static int am2315_probe(struct i2c_client *client) } static const struct i2c_device_id am2315_i2c_id[] = { - { "am2315" }, + { .name = "am2315" }, { } }; MODULE_DEVICE_TABLE(i2c, am2315_i2c_id); diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c index 980cb946bbf7..7690df97fd6c 100644 --- a/drivers/iio/humidity/dht11.c +++ b/drivers/iio/humidity/dht11.c @@ -14,7 +14,6 @@ #include <linux/string_choices.h> #include <linux/sysfs.h> #include <linux/io.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/wait.h> diff --git a/drivers/iio/humidity/ens210.c b/drivers/iio/humidity/ens210.c index 77418d97f30d..81276195152b 100644 --- a/drivers/iio/humidity/ens210.c +++ b/drivers/iio/humidity/ens210.c @@ -18,7 +18,6 @@ #include <linux/delay.h> #include <linux/i2c.h> #include <linux/iio/iio.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/types.h> @@ -149,15 +148,16 @@ static int ens210_read_raw(struct iio_dev *indio_dev, int ret; switch (mask) { - case IIO_CHAN_INFO_RAW: - scoped_guard(mutex, &data->lock) { - ret = ens210_get_measurement( - indio_dev, channel->type == IIO_TEMP, val); - if (ret) - return ret; - return IIO_VAL_INT; - } - return -EINVAL; /* compiler warning workaround */ + case IIO_CHAN_INFO_RAW: { + guard(mutex)(&data->lock); + + ret = ens210_get_measurement(indio_dev, channel->type == IIO_TEMP, + val); + if (ret) + return ret; + + return IIO_VAL_INT; + } case IIO_CHAN_INFO_SCALE: if (channel->type == IIO_TEMP) { *val = 15; @@ -314,12 +314,12 @@ static const struct of_device_id ens210_of_match[] = { MODULE_DEVICE_TABLE(of, ens210_of_match); static const struct i2c_device_id ens210_id_table[] = { - { "ens210", (kernel_ulong_t)&ens210_chip_info_data }, - { "ens210a", (kernel_ulong_t)&ens210a_chip_info_data }, - { "ens211", (kernel_ulong_t)&ens211_chip_info_data }, - { "ens212", (kernel_ulong_t)&ens212_chip_info_data }, - { "ens213a", (kernel_ulong_t)&ens213a_chip_info_data }, - { "ens215", (kernel_ulong_t)&ens215_chip_info_data }, + { .name = "ens210", .driver_data = (kernel_ulong_t)&ens210_chip_info_data }, + { .name = "ens210a", .driver_data = (kernel_ulong_t)&ens210a_chip_info_data }, + { .name = "ens211", .driver_data = (kernel_ulong_t)&ens211_chip_info_data }, + { .name = "ens212", .driver_data = (kernel_ulong_t)&ens212_chip_info_data }, + { .name = "ens213a", .driver_data = (kernel_ulong_t)&ens213a_chip_info_data }, + { .name = "ens215", .driver_data = (kernel_ulong_t)&ens215_chip_info_data }, { } }; MODULE_DEVICE_TABLE(i2c, ens210_id_table); diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c index c2b36e682e06..bc452cc8fbcf 100644 --- a/drivers/iio/humidity/hdc100x.c +++ b/drivers/iio/humidity/hdc100x.c @@ -16,7 +16,6 @@ #include <linux/cleanup.h> #include <linux/delay.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/init.h> #include <linux/i2c.h> @@ -380,12 +379,12 @@ static int hdc100x_probe(struct i2c_client *client) } static const struct i2c_device_id hdc100x_id[] = { - { "hdc100x" }, - { "hdc1000" }, - { "hdc1008" }, - { "hdc1010" }, - { "hdc1050" }, - { "hdc1080" }, + { .name = "hdc100x" }, + { .name = "hdc1000" }, + { .name = "hdc1008" }, + { .name = "hdc1010" }, + { .name = "hdc1050" }, + { .name = "hdc1080" }, { } }; MODULE_DEVICE_TABLE(i2c, hdc100x_id); diff --git a/drivers/iio/humidity/hdc2010.c b/drivers/iio/humidity/hdc2010.c index 894a8b4ab193..82d68987556d 100644 --- a/drivers/iio/humidity/hdc2010.c +++ b/drivers/iio/humidity/hdc2010.c @@ -44,7 +44,6 @@ struct hdc2010_data { struct i2c_client *client; struct mutex lock; u8 measurement_config; - u8 interrupt_config; u8 drdy_config; }; @@ -318,8 +317,8 @@ static void hdc2010_remove(struct i2c_client *client) } static const struct i2c_device_id hdc2010_id[] = { - { "hdc2010" }, - { "hdc2080" }, + { .name = "hdc2010" }, + { .name = "hdc2080" }, { } }; MODULE_DEVICE_TABLE(i2c, hdc2010_id); diff --git a/drivers/iio/humidity/hdc3020.c b/drivers/iio/humidity/hdc3020.c index 78b2c171c8da..75971c19624a 100644 --- a/drivers/iio/humidity/hdc3020.c +++ b/drivers/iio/humidity/hdc3020.c @@ -843,8 +843,7 @@ static int hdc3020_probe(struct i2c_client *client) IRQF_ONESHOT, "hdc3020", indio_dev); if (ret) - return dev_err_probe(&client->dev, ret, - "Failed to request IRQ\n"); + return ret; } ret = devm_iio_device_register(&data->client->dev, indio_dev); @@ -873,9 +872,9 @@ static int hdc3020_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(hdc3020_pm_ops, hdc3020_suspend, hdc3020_resume); static const struct i2c_device_id hdc3020_id[] = { - { "hdc3020" }, - { "hdc3021" }, - { "hdc3022" }, + { .name = "hdc3020" }, + { .name = "hdc3021" }, + { .name = "hdc3022" }, { } }; MODULE_DEVICE_TABLE(i2c, hdc3020_id); diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c index be2338d5f407..7cec81ff5685 100644 --- a/drivers/iio/humidity/hid-sensor-humidity.c +++ b/drivers/iio/humidity/hid-sensor-humidity.c @@ -8,7 +8,6 @@ #include <linux/iio/buffer.h> #include <linux/iio/iio.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include "hid-sensor-trigger.h" @@ -45,7 +44,7 @@ static const struct iio_chan_spec humidity_channels[] = { /* Adjust channel real bits based on report descriptor */ static void humidity_adjust_channel_bit_mask(struct iio_chan_spec *channels, - int channel, int size) + int channel, int size) { channels[channel].scan_type.sign = 's'; /* Real storage bits will change based on the report desc. */ @@ -55,8 +54,8 @@ static void humidity_adjust_channel_bit_mask(struct iio_chan_spec *channels, } static int humidity_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, long mask) + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { struct hid_humidity_state *humid_st = iio_priv(indio_dev); @@ -101,8 +100,8 @@ static int humidity_read_raw(struct iio_dev *indio_dev, } static int humidity_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct hid_humidity_state *humid_st = iio_priv(indio_dev); @@ -127,7 +126,7 @@ static const struct iio_info humidity_info = { /* Callback handler to send event after all samples are received and captured */ static int humidity_proc_event(struct hid_sensor_hub_device *hsdev, - unsigned int usage_id, void *pdev) + u32 usage_id, void *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct hid_humidity_state *humid_st = iio_priv(indio_dev); @@ -141,8 +140,9 @@ static int humidity_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int humidity_capture_sample(struct hid_sensor_hub_device *hsdev, - unsigned int usage_id, size_t raw_len, - char *raw_data, void *pdev) + u32 usage_id, + size_t raw_len, char *raw_data, + void *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct hid_humidity_state *humid_st = iio_priv(indio_dev); @@ -159,10 +159,10 @@ static int humidity_capture_sample(struct hid_sensor_hub_device *hsdev, /* Parse report which is specific to an usage id */ static int humidity_parse_report(struct platform_device *pdev, - struct hid_sensor_hub_device *hsdev, - struct iio_chan_spec *channels, - unsigned int usage_id, - struct hid_humidity_state *st) + struct hid_sensor_hub_device *hsdev, + struct iio_chan_spec *channels, + u32 usage_id, + struct hid_humidity_state *st) { int ret; @@ -215,13 +215,13 @@ static int hid_humidity_probe(struct platform_device *pdev) if (ret) return ret; - humid_chans = devm_kmemdup(&indio_dev->dev, humidity_channels, - sizeof(humidity_channels), GFP_KERNEL); + humid_chans = devm_kmemdup(&pdev->dev, humidity_channels, + sizeof(humidity_channels), GFP_KERNEL); if (!humid_chans) return -ENOMEM; ret = humidity_parse_report(pdev, hsdev, humid_chans, - HID_USAGE_SENSOR_HUMIDITY, humid_st); + HID_USAGE_SENSOR_HUMIDITY, humid_st); if (ret) return ret; @@ -234,7 +234,7 @@ static int hid_humidity_probe(struct platform_device *pdev) atomic_set(&humid_st->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, - &humid_st->common_attributes); + &humid_st->common_attributes); if (ret) return ret; @@ -242,7 +242,7 @@ static int hid_humidity_probe(struct platform_device *pdev) humidity_callbacks.pdev = pdev; ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY, - &humidity_callbacks); + &humidity_callbacks); if (ret) goto error_remove_trigger; diff --git a/drivers/iio/humidity/hts221_buffer.c b/drivers/iio/humidity/hts221_buffer.c index 4d03db19063e..df12c7a25b2e 100644 --- a/drivers/iio/humidity/hts221_buffer.c +++ b/drivers/iio/humidity/hts221_buffer.c @@ -122,11 +122,8 @@ int hts221_allocate_trigger(struct iio_dev *iio_dev) hts221_trigger_handler_thread, irq_type | IRQF_ONESHOT, hw->name, hw); - if (err) { - dev_err(hw->dev, "failed to request trigger irq %d\n", - hw->irq); + if (err) return err; - } hw->trig = devm_iio_trigger_alloc(hw->dev, "%s-trigger", iio_dev->name); diff --git a/drivers/iio/humidity/hts221_i2c.c b/drivers/iio/humidity/hts221_i2c.c index cbaa7d1af6c4..40276abc5d2e 100644 --- a/drivers/iio/humidity/hts221_i2c.c +++ b/drivers/iio/humidity/hts221_i2c.c @@ -9,7 +9,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/slab.h> #include <linux/regmap.h> @@ -53,7 +52,7 @@ static const struct of_device_id hts221_i2c_of_match[] = { MODULE_DEVICE_TABLE(of, hts221_i2c_of_match); static const struct i2c_device_id hts221_i2c_id_table[] = { - { HTS221_DEV_NAME }, + { .name = HTS221_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, hts221_i2c_id_table); diff --git a/drivers/iio/humidity/hts221_spi.c b/drivers/iio/humidity/hts221_spi.c index e6fef2acd523..f962842cc71d 100644 --- a/drivers/iio/humidity/hts221_spi.c +++ b/drivers/iio/humidity/hts221_spi.c @@ -47,7 +47,7 @@ static const struct of_device_id hts221_spi_of_match[] = { MODULE_DEVICE_TABLE(of, hts221_spi_of_match); static const struct spi_device_id hts221_spi_id_table[] = { - { HTS221_DEV_NAME }, + { .name = HTS221_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(spi, hts221_spi_id_table); diff --git a/drivers/iio/humidity/htu21.c b/drivers/iio/humidity/htu21.c index 7f1775bd26fd..a9dbf08b4f1a 100644 --- a/drivers/iio/humidity/htu21.c +++ b/drivers/iio/humidity/htu21.c @@ -19,7 +19,6 @@ #include <linux/kernel.h> #include <linux/stat.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -230,8 +229,8 @@ static int htu21_probe(struct i2c_client *client) } static const struct i2c_device_id htu21_id[] = { - {"htu21", HTU21}, - {"ms8607-humidity", MS8607}, + { .name = "htu21", .driver_data = HTU21 }, + { .name = "ms8607-humidity", .driver_data = MS8607 }, { } }; MODULE_DEVICE_TABLE(i2c, htu21_id); diff --git a/drivers/iio/humidity/si7005.c b/drivers/iio/humidity/si7005.c index 0797ece1fcba..0c11d0d3afe0 100644 --- a/drivers/iio/humidity/si7005.c +++ b/drivers/iio/humidity/si7005.c @@ -163,8 +163,8 @@ static int si7005_probe(struct i2c_client *client) } static const struct i2c_device_id si7005_id[] = { - { "si7005" }, - { "th02" }, + { .name = "si7005" }, + { .name = "th02" }, { } }; MODULE_DEVICE_TABLE(i2c, si7005_id); diff --git a/drivers/iio/humidity/si7020.c b/drivers/iio/humidity/si7020.c index ff2dba50c0a5..e51dd7151e4a 100644 --- a/drivers/iio/humidity/si7020.c +++ b/drivers/iio/humidity/si7020.c @@ -20,7 +20,6 @@ #include <linux/delay.h> #include <linux/i2c.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/slab.h> #include <linux/sysfs.h> #include <linux/stat.h> @@ -267,8 +266,8 @@ static int si7020_probe(struct i2c_client *client) } static const struct i2c_device_id si7020_id[] = { - { "si7020" }, - { "th06" }, + { .name = "si7020" }, + { .name = "th06" }, { } }; MODULE_DEVICE_TABLE(i2c, si7020_id); diff --git a/drivers/iio/iio_core_trigger.h b/drivers/iio/iio_core_trigger.h index e1a56824e07f..4698a857739f 100644 --- a/drivers/iio/iio_core_trigger.h +++ b/drivers/iio/iio_core_trigger.h @@ -56,4 +56,4 @@ static inline int iio_trigger_detach_poll_func(struct iio_trigger *trig, return 0; } -#endif /* CONFIG_TRIGGER_CONSUMER */ +#endif /* CONFIG_IIO_TRIGGER */ diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index 7e0181c27bb6..8bab4616be20 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -109,6 +109,7 @@ config KMX61 be called kmx61. source "drivers/iio/imu/inv_icm42600/Kconfig" +source "drivers/iio/imu/inv_icm42607/Kconfig" source "drivers/iio/imu/inv_icm45600/Kconfig" source "drivers/iio/imu/inv_mpu6050/Kconfig" diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index 13fb7846e9c9..3268dc2371ae 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o obj-y += inv_icm42600/ +obj-y += inv_icm42607/ obj-y += inv_icm45600/ obj-y += inv_mpu6050/ diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c index 36323ad149e0..4842346f9f0c 100644 --- a/drivers/iio/imu/adis16400.c +++ b/drivers/iio/imu/adis16400.c @@ -1189,21 +1189,21 @@ static int adis16400_probe(struct spi_device *spi) } static const struct spi_device_id adis16400_id[] = { - { "adis16300", (kernel_ulong_t)&adis16300_chip_info }, - { "adis16305", (kernel_ulong_t)&adis16300_chip_info }, - { "adis16334", (kernel_ulong_t)&adis16334_chip_info }, - { "adis16350", (kernel_ulong_t)&adis16350_chip_info }, - { "adis16354", (kernel_ulong_t)&adis16350_chip_info }, - { "adis16355", (kernel_ulong_t)&adis16350_chip_info }, - { "adis16360", (kernel_ulong_t)&adis16360_chip_info }, - { "adis16362", (kernel_ulong_t)&adis16362_chip_info }, - { "adis16364", (kernel_ulong_t)&adis16364_chip_info }, - { "adis16365", (kernel_ulong_t)&adis16360_chip_info }, - { "adis16367", (kernel_ulong_t)&adis16367_chip_info }, - { "adis16400", (kernel_ulong_t)&adis16400_chip_info }, - { "adis16405", (kernel_ulong_t)&adis16400_chip_info }, - { "adis16445", (kernel_ulong_t)&adis16445_chip_info }, - { "adis16448", (kernel_ulong_t)&adis16448_chip_info }, + { .name = "adis16300", .driver_data = (kernel_ulong_t)&adis16300_chip_info }, + { .name = "adis16305", .driver_data = (kernel_ulong_t)&adis16300_chip_info }, + { .name = "adis16334", .driver_data = (kernel_ulong_t)&adis16334_chip_info }, + { .name = "adis16350", .driver_data = (kernel_ulong_t)&adis16350_chip_info }, + { .name = "adis16354", .driver_data = (kernel_ulong_t)&adis16350_chip_info }, + { .name = "adis16355", .driver_data = (kernel_ulong_t)&adis16350_chip_info }, + { .name = "adis16360", .driver_data = (kernel_ulong_t)&adis16360_chip_info }, + { .name = "adis16362", .driver_data = (kernel_ulong_t)&adis16362_chip_info }, + { .name = "adis16364", .driver_data = (kernel_ulong_t)&adis16364_chip_info }, + { .name = "adis16365", .driver_data = (kernel_ulong_t)&adis16360_chip_info }, + { .name = "adis16367", .driver_data = (kernel_ulong_t)&adis16367_chip_info }, + { .name = "adis16400", .driver_data = (kernel_ulong_t)&adis16400_chip_info }, + { .name = "adis16405", .driver_data = (kernel_ulong_t)&adis16400_chip_info }, + { .name = "adis16445", .driver_data = (kernel_ulong_t)&adis16445_chip_info }, + { .name = "adis16448", .driver_data = (kernel_ulong_t)&adis16448_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, adis16400_id); diff --git a/drivers/iio/imu/adis16460.c b/drivers/iio/imu/adis16460.c index ba1887d36577..cadf21c05bbf 100644 --- a/drivers/iio/imu/adis16460.c +++ b/drivers/iio/imu/adis16460.c @@ -394,7 +394,7 @@ static int adis16460_probe(struct spi_device *spi) } static const struct spi_device_id adis16460_ids[] = { - { "adis16460", 0 }, + { .name = "adis16460" }, { } }; MODULE_DEVICE_TABLE(spi, adis16460_ids); diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index ab39bea1e729..5f21dceda8f7 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -20,7 +20,6 @@ #include <linux/lcm.h> #include <linux/math.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/spi/spi.h> @@ -2062,33 +2061,33 @@ static const struct of_device_id adis16475_of_match[] = { MODULE_DEVICE_TABLE(of, adis16475_of_match); static const struct spi_device_id adis16475_ids[] = { - { "adis16470", (kernel_ulong_t)&adis16475_chip_info[ADIS16470] }, - { "adis16475-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16475_1] }, - { "adis16475-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16475_2] }, - { "adis16475-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16475_3] }, - { "adis16477-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16477_1] }, - { "adis16477-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16477_2] }, - { "adis16477-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16477_3] }, - { "adis16465-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16465_1] }, - { "adis16465-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16465_2] }, - { "adis16465-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16465_3] }, - { "adis16467-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16467_1] }, - { "adis16467-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16467_2] }, - { "adis16467-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16467_3] }, - { "adis16500", (kernel_ulong_t)&adis16475_chip_info[ADIS16500] }, - { "adis16501", (kernel_ulong_t)&adis16475_chip_info[ADIS16501] }, - { "adis16505-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16505_1] }, - { "adis16505-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16505_2] }, - { "adis16505-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16505_3] }, - { "adis16507-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16507_1] }, - { "adis16507-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16507_2] }, - { "adis16507-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16507_3] }, - { "adis16575-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16575_2] }, - { "adis16575-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16575_3] }, - { "adis16576-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16576_2] }, - { "adis16576-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16576_3] }, - { "adis16577-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16577_2] }, - { "adis16577-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16577_3] }, + { .name = "adis16470", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16470] }, + { .name = "adis16475-1", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16475_1] }, + { .name = "adis16475-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16475_2] }, + { .name = "adis16475-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16475_3] }, + { .name = "adis16477-1", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16477_1] }, + { .name = "adis16477-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16477_2] }, + { .name = "adis16477-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16477_3] }, + { .name = "adis16465-1", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16465_1] }, + { .name = "adis16465-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16465_2] }, + { .name = "adis16465-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16465_3] }, + { .name = "adis16467-1", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16467_1] }, + { .name = "adis16467-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16467_2] }, + { .name = "adis16467-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16467_3] }, + { .name = "adis16500", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16500] }, + { .name = "adis16501", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16501] }, + { .name = "adis16505-1", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16505_1] }, + { .name = "adis16505-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16505_2] }, + { .name = "adis16505-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16505_3] }, + { .name = "adis16507-1", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16507_1] }, + { .name = "adis16507-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16507_2] }, + { .name = "adis16507-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16507_3] }, + { .name = "adis16575-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16575_2] }, + { .name = "adis16575-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16575_3] }, + { .name = "adis16576-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16576_2] }, + { .name = "adis16576-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16576_3] }, + { .name = "adis16577-2", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16577_2] }, + { .name = "adis16577-3", .driver_data = (kernel_ulong_t)&adis16475_chip_info[ADIS16577_3] }, { } }; MODULE_DEVICE_TABLE(spi, adis16475_ids); diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index 543d5c4bfb11..5187566c1876 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -13,7 +13,6 @@ #include <linux/device.h> #include <linux/kernel.h> #include <linux/spi/spi.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/lcm.h> #include <linux/property.h> @@ -111,7 +110,7 @@ #define ADIS16480_REG_SERIAL_NUM ADIS16480_REG(0x04, 0x20) -/* Each filter coefficent bank spans two pages */ +/* Each filter coefficient bank spans two pages */ #define ADIS16480_FIR_COEF(page) (x < 60 ? ADIS16480_REG(page, (x) + 8) : \ ADIS16480_REG((page) + 1, (x) - 60 + 8)) #define ADIS16480_FIR_COEF_A(x) ADIS16480_FIR_COEF(0x05, (x)) @@ -1468,7 +1467,7 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p) * We need to perform the padding to have the buffer * elements naturally aligned in case there are any * 32-bit storage size channels enabled which are added - * in the buffer after the temprature data. In case + * in the buffer after the temperature data. In case * there is no data being added after the temperature * data, the padding is harmless. */ @@ -1807,26 +1806,26 @@ static int adis16480_probe(struct spi_device *spi) } static const struct spi_device_id adis16480_ids[] = { - { "adis16375", ADIS16375 }, - { "adis16480", ADIS16480 }, - { "adis16485", ADIS16485 }, - { "adis16486", ADIS16486 }, - { "adis16487", ADIS16487 }, - { "adis16488", ADIS16488 }, - { "adis16489", ADIS16489 }, - { "adis16490", ADIS16490 }, - { "adis16495-1", ADIS16495_1 }, - { "adis16495-2", ADIS16495_2 }, - { "adis16495-3", ADIS16495_3 }, - { "adis16497-1", ADIS16497_1 }, - { "adis16497-2", ADIS16497_2 }, - { "adis16497-3", ADIS16497_3 }, - { "adis16545-1", ADIS16545_1 }, - { "adis16545-2", ADIS16545_2 }, - { "adis16545-3", ADIS16545_3 }, - { "adis16547-1", ADIS16547_1 }, - { "adis16547-2", ADIS16547_2 }, - { "adis16547-3", ADIS16547_3 }, + { .name = "adis16375", .driver_data = ADIS16375 }, + { .name = "adis16480", .driver_data = ADIS16480 }, + { .name = "adis16485", .driver_data = ADIS16485 }, + { .name = "adis16486", .driver_data = ADIS16486 }, + { .name = "adis16487", .driver_data = ADIS16487 }, + { .name = "adis16488", .driver_data = ADIS16488 }, + { .name = "adis16489", .driver_data = ADIS16489 }, + { .name = "adis16490", .driver_data = ADIS16490 }, + { .name = "adis16495-1", .driver_data = ADIS16495_1 }, + { .name = "adis16495-2", .driver_data = ADIS16495_2 }, + { .name = "adis16495-3", .driver_data = ADIS16495_3 }, + { .name = "adis16497-1", .driver_data = ADIS16497_1 }, + { .name = "adis16497-2", .driver_data = ADIS16497_2 }, + { .name = "adis16497-3", .driver_data = ADIS16497_3 }, + { .name = "adis16545-1", .driver_data = ADIS16545_1 }, + { .name = "adis16545-2", .driver_data = ADIS16545_2 }, + { .name = "adis16545-3", .driver_data = ADIS16545_3 }, + { .name = "adis16547-1", .driver_data = ADIS16547_1 }, + { .name = "adis16547-2", .driver_data = ADIS16547_2 }, + { .name = "adis16547-3", .driver_data = ADIS16547_3 }, { } }; MODULE_DEVICE_TABLE(spi, adis16480_ids); diff --git a/drivers/iio/imu/adis16550.c b/drivers/iio/imu/adis16550.c index 28f0dbd0226c..096a612865c4 100644 --- a/drivers/iio/imu/adis16550.c +++ b/drivers/iio/imu/adis16550.c @@ -18,7 +18,6 @@ #include <linux/lcm.h> #include <linux/math.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> #include <linux/swab.h> @@ -89,25 +88,7 @@ struct adis16550_sync { u16 max_rate; }; -struct adis16550_chip_info { - const struct iio_chan_spec *channels; - const struct adis16550_sync *sync_mode; - char *name; - u32 num_channels; - u32 gyro_max_val; - u32 gyro_max_scale; - u32 accel_max_val; - u32 accel_max_scale; - u32 temp_scale; - u32 deltang_max_val; - u32 deltvel_max_val; - u32 int_clk; - u16 max_dec; - u16 num_sync; -}; - struct adis16550 { - const struct adis16550_chip_info *info; struct adis adis; unsigned long clk_freq_hz; u32 sync_mode; @@ -450,8 +431,8 @@ static int adis16550_set_freq_hz(struct adis16550 *st, u32 freq_hz) * The optimal sample rate for the supported IMUs is between * int_clk - 1000 and int_clk + 500. */ - u32 max_sample_rate = st->info->int_clk * 1000 + 500000; - u32 min_sample_rate = st->info->int_clk * 1000 - 1000000; + u32 max_sample_rate = 4000 * 1000 + 500000; + u32 min_sample_rate = 4000 * 1000 - 1000000; if (!freq_hz) return -EINVAL; @@ -484,7 +465,7 @@ static int adis16550_set_freq_hz(struct adis16550 *st, u32 freq_hz) if (dec) dec--; - dec = min(dec, st->info->max_dec); + dec = min(dec, 4095); return __adis_write_reg_16(&st->adis, ADIS16550_REG_DEC_RATE, dec); } @@ -592,30 +573,30 @@ static int adis16550_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_ANGL_VEL: - *val = st->info->gyro_max_val; - *val2 = st->info->gyro_max_scale; + *val = 1; + *val2 = IIO_RAD_TO_DEGREE(80 << 16); return IIO_VAL_FRACTIONAL; case IIO_ACCEL: - *val = st->info->accel_max_val; - *val2 = st->info->accel_max_scale; + *val = 1; + *val2 = IIO_M_S_2_TO_G(102400000); return IIO_VAL_FRACTIONAL; case IIO_TEMP: - *val = st->info->temp_scale; + *val = 4; return IIO_VAL_INT; case IIO_DELTA_ANGL: - *val = st->info->deltang_max_val; + *val = IIO_DEGREE_TO_RAD(720); *val2 = 31; return IIO_VAL_FRACTIONAL_LOG2; case IIO_DELTA_VELOCITY: - *val = st->info->deltvel_max_val; + *val = 125; *val2 = 31; return IIO_VAL_FRACTIONAL_LOG2; default: return -EINVAL; } case IIO_CHAN_INFO_OFFSET: - /* temperature centered at 25°C */ - *val = DIV_ROUND_CLOSEST(25000, st->info->temp_scale); + /* temperature centered at 25°C divided by temp scale */ + *val = 25000 / 4; return IIO_VAL_INT; case IIO_CHAN_INFO_CALIBBIAS: ret = adis_read_reg_32(&st->adis, @@ -643,12 +624,12 @@ static int adis16550_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: switch (chan->type) { case IIO_ANGL_VEL: - ret = adis16550_get_accl_filter_freq(st, val); + ret = adis16550_get_gyro_filter_freq(st, val); if (ret) return ret; return IIO_VAL_INT; case IIO_ACCEL: - ret = adis16550_get_gyro_filter_freq(st, val); + ret = adis16550_get_accl_filter_freq(st, val); if (ret) return ret; return IIO_VAL_INT; @@ -681,9 +662,9 @@ static int adis16550_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: switch (chan->type) { case IIO_ANGL_VEL: - return adis16550_set_accl_filter_freq(st, val); - case IIO_ACCEL: return adis16550_set_gyro_filter_freq(st, val); + case IIO_ACCEL: + return adis16550_set_accl_filter_freq(st, val); default: return -EINVAL; } @@ -793,23 +774,6 @@ static const struct adis16550_sync adis16550_sync_modes[] = { { ADIS16550_SYNC_MODE_SCALED, 1, 128 }, }; -static const struct adis16550_chip_info adis16550_chip_info = { - .num_channels = ARRAY_SIZE(adis16550_channels), - .channels = adis16550_channels, - .name = "adis16550", - .gyro_max_val = 1, - .gyro_max_scale = IIO_RAD_TO_DEGREE(80 << 16), - .accel_max_val = 1, - .accel_max_scale = IIO_M_S_2_TO_G(102400000), - .temp_scale = 4, - .deltang_max_val = IIO_DEGREE_TO_RAD(720), - .deltvel_max_val = 125, - .int_clk = 4000, - .max_dec = 4095, - .sync_mode = adis16550_sync_modes, - .num_sync = ARRAY_SIZE(adis16550_sync_modes), -}; - static u32 adis16550_validate_crc(__be32 *buffer, const u8 n_elem) { int i; @@ -836,7 +800,7 @@ static irqreturn_t adis16550_trigger_handler(int irq, void *p) u16 dummy; bool valid; struct iio_poll_func *pf = p; - __be32 data[ADIS16550_MAX_SCAN_DATA] __aligned(8); + __be32 data[ADIS16550_MAX_SCAN_DATA] __aligned(8) = { }; struct iio_dev *indio_dev = pf->indio_dev; struct adis16550 *st = iio_priv(indio_dev); struct adis *adis = iio_device_get_drvdata(indio_dev); @@ -918,21 +882,21 @@ static int adis16550_config_sync(struct adis16550 *st) if (IS_ERR(clk)) return PTR_ERR(clk); if (!clk) { - st->clk_freq_hz = st->info->int_clk * 1000; + st->clk_freq_hz = 4000000; return 0; } st->clk_freq_hz = clk_get_rate(clk); - for (i = 0; i < st->info->num_sync; i++) { - if (st->clk_freq_hz >= st->info->sync_mode[i].min_rate && - st->clk_freq_hz <= st->info->sync_mode[i].max_rate) { - sync_mode_data = &st->info->sync_mode[i]; + for (i = 0; i < ARRAY_SIZE(adis16550_sync_modes); i++) { + if (st->clk_freq_hz >= adis16550_sync_modes[i].min_rate && + st->clk_freq_hz <= adis16550_sync_modes[i].max_rate) { + sync_mode_data = &adis16550_sync_modes[i]; break; } } - if (i == st->info->num_sync) + if (i == ARRAY_SIZE(adis16550_sync_modes)) return dev_err_probe(dev, -EINVAL, "Clk rate: %lu not in a valid range", st->clk_freq_hz); @@ -943,7 +907,7 @@ static int adis16550_config_sync(struct adis16550 *st) * of [3000 4500]. */ - sync_scale = DIV_ROUND_CLOSEST(st->info->int_clk, st->clk_freq_hz); + sync_scale = DIV_ROUND_CLOSEST(4000, st->clk_freq_hz); if (3000 > sync_scale || 4500 < sync_scale) return dev_err_probe(dev, -EINVAL, @@ -955,7 +919,7 @@ static int adis16550_config_sync(struct adis16550 *st) if (ret) return ret; - st->clk_freq_hz = st->info->int_clk; + st->clk_freq_hz = 4000; } st->clk_freq_hz *= 1000; @@ -1064,13 +1028,11 @@ static int adis16550_probe(struct spi_device *spi) return -ENOMEM; st = iio_priv(indio_dev); - st->info = spi_get_device_match_data(spi); - if (!st->info) - return -EINVAL; + adis = &st->adis; - indio_dev->name = st->info->name; - indio_dev->channels = st->info->channels; - indio_dev->num_channels = st->info->num_channels; + indio_dev->name = "adis16550"; + indio_dev->channels = adis16550_channels; + indio_dev->num_channels = ARRAY_SIZE(adis16550_channels); indio_dev->available_scan_masks = adis16550_channel_masks; indio_dev->info = &adis16550_info; indio_dev->modes = INDIO_DIRECT_MODE; @@ -1117,13 +1079,13 @@ static int adis16550_probe(struct spi_device *spi) } static const struct spi_device_id adis16550_id[] = { - { "adis16550", (kernel_ulong_t)&adis16550_chip_info}, + { .name = "adis16550" }, { } }; MODULE_DEVICE_TABLE(spi, adis16550_id); static const struct of_device_id adis16550_of_match[] = { - { .compatible = "adi,adis16550", .data = &adis16550_chip_info }, + { .compatible = "adi,adis16550" }, { } }; MODULE_DEVICE_TABLE(of, adis16550_of_match); diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c index d76e13cbac68..3e6a7af6ab01 100644 --- a/drivers/iio/imu/adis_trigger.c +++ b/drivers/iio/imu/adis_trigger.c @@ -94,7 +94,7 @@ int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) else ret = devm_request_irq(&adis->spi->dev, adis->spi->irq, &iio_trigger_generic_data_rdy_poll, - adis->irq_flag, + adis->irq_flag | IRQF_NO_THREAD, indio_dev->name, adis->trig); if (ret) diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c index 5f47708b4c5d..1e73a7f1f017 100644 --- a/drivers/iio/imu/bmi160/bmi160_core.c +++ b/drivers/iio/imu/bmi160/bmi160_core.c @@ -5,7 +5,7 @@ * Copyright (c) 2016, Intel Corporation. * Copyright (c) 2019, Martin Kelly. * - * IIO core driver for BMI160, with support for I2C/SPI busses + * IIO core driver for BMI160, with support for I2C/SPI buses * * TODO: magnetometer, hardware FIFO */ @@ -573,12 +573,16 @@ static int bmi160_config_pin(struct regmap *regmap, enum bmi160_int_pin pin, int_out_ctrl_shift = BMI160_INT1_OUT_CTRL_SHIFT; int_latch_mask = BMI160_INT1_LATCH_MASK; int_map_mask = BMI160_INT1_MAP_DRDY_EN; + pin_name = "INT1"; break; case BMI160_PIN_INT2: int_out_ctrl_shift = BMI160_INT2_OUT_CTRL_SHIFT; int_latch_mask = BMI160_INT2_LATCH_MASK; int_map_mask = BMI160_INT2_MAP_DRDY_EN; + pin_name = "INT2"; break; + default: + return -EINVAL; } int_out_ctrl_mask = BMI160_INT_OUT_CTRL_MASK << int_out_ctrl_shift; @@ -612,17 +616,8 @@ static int bmi160_config_pin(struct regmap *regmap, enum bmi160_int_pin pin, ret = bmi160_write_conf_reg(regmap, BMI160_REG_INT_MAP, int_map_mask, int_map_mask, write_usleep); - if (ret) { - switch (pin) { - case BMI160_PIN_INT1: - pin_name = "INT1"; - break; - case BMI160_PIN_INT2: - pin_name = "INT2"; - break; - } + if (ret) dev_err(dev, "Failed to configure %s IRQ pin", pin_name); - } return ret; } @@ -793,7 +788,8 @@ int bmi160_probe_trigger(struct iio_dev *indio_dev, int irq, u32 irq_type) ret = devm_request_irq(&indio_dev->dev, irq, &iio_trigger_generic_data_rdy_poll, - irq_type, "bmi160", data->trig); + irq_type | IRQF_NO_THREAD, + "bmi160", data->trig); if (ret) return ret; diff --git a/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c index 3e2758f4e0d3..3f3ee044a9cf 100644 --- a/drivers/iio/imu/bmi160/bmi160_i2c.c +++ b/drivers/iio/imu/bmi160/bmi160_i2c.c @@ -9,7 +9,6 @@ * - 0x69 if SDO is pulled to VDDIO */ #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/pm.h> #include <linux/regmap.h> @@ -38,8 +37,8 @@ static int bmi160_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id bmi160_i2c_id[] = { - { "bmi120" }, - { "bmi160" }, + { .name = "bmi120" }, + { .name = "bmi160" }, { } }; MODULE_DEVICE_TABLE(i2c, bmi160_i2c_id); diff --git a/drivers/iio/imu/bmi160/bmi160_spi.c b/drivers/iio/imu/bmi160/bmi160_spi.c index 3581bd788483..107eb3374922 100644 --- a/drivers/iio/imu/bmi160/bmi160_spi.c +++ b/drivers/iio/imu/bmi160/bmi160_spi.c @@ -5,7 +5,6 @@ * Copyright (c) 2016, Intel Corporation. * */ -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/pm.h> #include <linux/regmap.h> @@ -35,8 +34,8 @@ static int bmi160_spi_probe(struct spi_device *spi) } static const struct spi_device_id bmi160_spi_id[] = { - {"bmi120", 0}, - {"bmi160", 0}, + { .name = "bmi120" }, + { .name = "bmi160" }, { } }; MODULE_DEVICE_TABLE(spi, bmi160_spi_id); diff --git a/drivers/iio/imu/bmi270/bmi270_core.c b/drivers/iio/imu/bmi270/bmi270_core.c index 2ad230788532..fbcf6bb87acc 100644 --- a/drivers/iio/imu/bmi270/bmi270_core.c +++ b/drivers/iio/imu/bmi270/bmi270_core.c @@ -1434,7 +1434,7 @@ static int bmi270_trigger_probe(struct bmi270_data *data, bmi270_irq_thread_handler, IRQF_ONESHOT, "bmi270-int", indio_dev); if (ret) - return dev_err_probe(data->dev, ret, "Failed to request IRQ\n"); + return ret; ret = devm_iio_trigger_register(data->dev, data->trig); if (ret) diff --git a/drivers/iio/imu/bmi270/bmi270_i2c.c b/drivers/iio/imu/bmi270/bmi270_i2c.c index b92da4e0776f..7c035e82e6e9 100644 --- a/drivers/iio/imu/bmi270/bmi270_i2c.c +++ b/drivers/iio/imu/bmi270/bmi270_i2c.c @@ -3,7 +3,6 @@ #include <linux/i2c.h> #include <linux/iio/iio.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/pm.h> #include <linux/regmap.h> @@ -33,8 +32,8 @@ static int bmi270_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id bmi270_i2c_id[] = { - { "bmi260", (kernel_ulong_t)&bmi260_chip_info }, - { "bmi270", (kernel_ulong_t)&bmi270_chip_info }, + { .name = "bmi260", .driver_data = (kernel_ulong_t)&bmi260_chip_info }, + { .name = "bmi270", .driver_data = (kernel_ulong_t)&bmi270_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, bmi270_i2c_id); diff --git a/drivers/iio/imu/bmi270/bmi270_spi.c b/drivers/iio/imu/bmi270/bmi270_spi.c index 80c9fa1d685a..759b56b59e54 100644 --- a/drivers/iio/imu/bmi270/bmi270_spi.c +++ b/drivers/iio/imu/bmi270/bmi270_spi.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) #include <linux/iio/iio.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/pm.h> #include <linux/regmap.h> @@ -66,8 +65,8 @@ static int bmi270_spi_probe(struct spi_device *spi) } static const struct spi_device_id bmi270_spi_id[] = { - { "bmi260", (kernel_ulong_t)&bmi260_chip_info }, - { "bmi270", (kernel_ulong_t)&bmi270_chip_info }, + { .name = "bmi260", .driver_data = (kernel_ulong_t)&bmi260_chip_info }, + { .name = "bmi270", .driver_data = (kernel_ulong_t)&bmi270_chip_info }, { } }; @@ -76,6 +75,7 @@ static const struct of_device_id bmi270_of_match[] = { { .compatible = "bosch,bmi270", .data = &bmi270_chip_info }, { } }; +MODULE_DEVICE_TABLE(of, bmi270_of_match); static struct spi_driver bmi270_spi_driver = { .driver = { diff --git a/drivers/iio/imu/bmi323/bmi323_core.c b/drivers/iio/imu/bmi323/bmi323_core.c index 6bcb9a436581..ebeb1b10c38c 100644 --- a/drivers/iio/imu/bmi323/bmi323_core.c +++ b/drivers/iio/imu/bmi323/bmi323_core.c @@ -156,7 +156,6 @@ struct bmi323_data { struct iio_mount_matrix orientation; enum bmi323_irq_pin irq_pin; struct iio_trigger *trig; - bool drdy_trigger_enabled; enum bmi323_state state; s64 fifo_tstamp, old_fifo_tstamp; u32 odrns[BMI323_SENSORS_CNT]; @@ -1129,7 +1128,7 @@ static int bmi323_set_watermark(struct iio_dev *indio_dev, unsigned int val) { struct bmi323_data *data = iio_priv(indio_dev); - val = min(val, (u32)BMI323_FIFO_FULL_IN_FRAMES); + val = min(val, BMI323_FIFO_FULL_IN_FRAMES); guard(mutex)(&data->mutex); data->watermark = val; @@ -1947,7 +1946,7 @@ static int bmi323_trigger_probe(struct bmi323_data *data, bmi323_irq_thread_handler, IRQF_ONESHOT, "bmi323-int", indio_dev); if (ret) - return dev_err_probe(data->dev, ret, "Failed to request IRQ\n"); + return ret; ret = devm_iio_trigger_register(data->dev, data->trig); if (ret) diff --git a/drivers/iio/imu/bmi323/bmi323_i2c.c b/drivers/iio/imu/bmi323/bmi323_i2c.c index 8457fe304db8..e835b91ea6b4 100644 --- a/drivers/iio/imu/bmi323/bmi323_i2c.c +++ b/drivers/iio/imu/bmi323/bmi323_i2c.c @@ -6,7 +6,6 @@ */ #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> @@ -114,7 +113,7 @@ static const struct acpi_device_id bmi323_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, bmi323_acpi_match); static const struct i2c_device_id bmi323_i2c_ids[] = { - { "bmi323" }, + { .name = "bmi323" }, { } }; MODULE_DEVICE_TABLE(i2c, bmi323_i2c_ids); diff --git a/drivers/iio/imu/bmi323/bmi323_spi.c b/drivers/iio/imu/bmi323/bmi323_spi.c index fd56ab620750..ed0235cc40da 100644 --- a/drivers/iio/imu/bmi323/bmi323_spi.c +++ b/drivers/iio/imu/bmi323/bmi323_spi.c @@ -5,7 +5,6 @@ * Copyright (C) 2023, Jagath Jog J <jagathjog1996@gmail.com> */ -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> #include <linux/spi/spi.h> @@ -65,7 +64,7 @@ static int bmi323_spi_probe(struct spi_device *spi) } static const struct spi_device_id bmi323_spi_ids[] = { - { "bmi323" }, + { .name = "bmi323" }, { } }; MODULE_DEVICE_TABLE(spi, bmi323_spi_ids); diff --git a/drivers/iio/imu/bno055/bno055.c b/drivers/iio/imu/bno055/bno055.c index 303bc308f80a..d0101607a9b3 100644 --- a/drivers/iio/imu/bno055/bno055.c +++ b/drivers/iio/imu/bno055/bno055.c @@ -64,7 +64,7 @@ #define BNO055_GRAVITY_DATA_X_LSB_REG 0x2E #define BNO055_GRAVITY_DATA_Y_LSB_REG 0x30 #define BNO055_GRAVITY_DATA_Z_LSB_REG 0x32 -#define BNO055_SCAN_CH_COUNT ((BNO055_GRAVITY_DATA_Z_LSB_REG - BNO055_ACC_DATA_X_LSB_REG) / 2) +#define BNO055_SCAN_CH_COUNT ((BNO055_GRAVITY_DATA_Z_LSB_REG - BNO055_ACC_DATA_X_LSB_REG) / 2 + 1) #define BNO055_TEMP_REG 0x34 #define BNO055_CALIB_STAT_REG 0x35 #define BNO055_CALIB_STAT_MAGN_SHIFT 0 @@ -210,9 +210,30 @@ struct bno055_priv { u8 uid[BNO055_UID_LEN]; struct gpio_desc *reset_gpio; bool sw_reset; - struct { - __le16 chans[BNO055_SCAN_CH_COUNT]; - aligned_s64 timestamp; + union { + IIO_DECLARE_BUFFER_WITH_TS(__le16, chans, BNO055_SCAN_CH_COUNT); + /* + * This struct is not used, but it is here to ensure proper size + * and alignment of the scan buffer above (because of the extra + * requirements of the quaternion field). Technically it is not + * needed in this case, because other fields just happen to make + * things correctly aligned already. But it is better to be + * explicit about the requirements anyway. The actual contents + * of the scan buffer will vary depending on which channels are + * enabled. + */ + struct { + __le16 acc[3]; + __le16 magn[3]; + __le16 gyr[3]; + __le16 yaw; + __le16 pitch; + __le16 roll; + IIO_DECLARE_QUATERNION(__le16, quaternion); + __le16 lia[3]; + __le16 gravity[3]; + aligned_s64 timestamp; + }; } buf; struct dentry *debugfs; }; diff --git a/drivers/iio/imu/bno055/bno055_i2c.c b/drivers/iio/imu/bno055/bno055_i2c.c index f49d0905ee33..7117ec682365 100644 --- a/drivers/iio/imu/bno055/bno055_i2c.c +++ b/drivers/iio/imu/bno055/bno055_i2c.c @@ -8,7 +8,6 @@ */ #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> @@ -30,7 +29,7 @@ static int bno055_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id bno055_i2c_id[] = { - { "bno055" }, + { .name = "bno055" }, { } }; MODULE_DEVICE_TABLE(i2c, bno055_i2c_id); diff --git a/drivers/iio/imu/bno055/bno055_ser_core.c b/drivers/iio/imu/bno055/bno055_ser_core.c index 48669dabb37b..01f05feaae0a 100644 --- a/drivers/iio/imu/bno055/bno055_ser_core.c +++ b/drivers/iio/imu/bno055/bno055_ser_core.c @@ -19,7 +19,6 @@ #include <linux/errno.h> #include <linux/jiffies.h> #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/regmap.h> @@ -288,7 +287,7 @@ static int bno055_ser_write_reg(void *context, const void *_data, size_t count) struct bno055_ser_priv *priv = context; if (count < 2) { - dev_err(&priv->serdev->dev, "Invalid write count %zu", count); + dev_err(&priv->serdev->dev, "Invalid write count %zu\n", count); return -EINVAL; } @@ -306,7 +305,7 @@ static int bno055_ser_read_reg(void *context, struct bno055_ser_priv *priv = context; if (val_size > 128) { - dev_err(&priv->serdev->dev, "Invalid read valsize %zu", val_size); + dev_err(&priv->serdev->dev, "Invalid read valsize %zu\n", val_size); return -EINVAL; } diff --git a/drivers/iio/imu/fxos8700_core.c b/drivers/iio/imu/fxos8700_core.c index 281ebfd9c15a..9d2eb6fbab4a 100644 --- a/drivers/iio/imu/fxos8700_core.c +++ b/drivers/iio/imu/fxos8700_core.c @@ -2,7 +2,7 @@ /* * FXOS8700 - NXP IMU (accelerometer plus magnetometer) * - * IIO core driver for FXOS8700, with support for I2C/SPI busses + * IIO core driver for FXOS8700, with support for I2C/SPI buses * * TODO: Buffer, trigger, and IRQ support */ diff --git a/drivers/iio/imu/fxos8700_i2c.c b/drivers/iio/imu/fxos8700_i2c.c index 2cc4a27a4527..ba47e9260928 100644 --- a/drivers/iio/imu/fxos8700_i2c.c +++ b/drivers/iio/imu/fxos8700_i2c.c @@ -12,7 +12,6 @@ */ #include <linux/i2c.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/regmap.h> #include "fxos8700.h" @@ -36,7 +35,7 @@ static int fxos8700_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id fxos8700_i2c_id[] = { - { "fxos8700" }, + { .name = "fxos8700" }, { } }; MODULE_DEVICE_TABLE(i2c, fxos8700_i2c_id); diff --git a/drivers/iio/imu/fxos8700_spi.c b/drivers/iio/imu/fxos8700_spi.c index 6b0dc7a776b9..56ad0c5914d9 100644 --- a/drivers/iio/imu/fxos8700_spi.c +++ b/drivers/iio/imu/fxos8700_spi.c @@ -3,7 +3,6 @@ * FXOS8700 - NXP IMU, SPI bits */ #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/regmap.h> #include <linux/spi/spi.h> @@ -24,7 +23,7 @@ static int fxos8700_spi_probe(struct spi_device *spi) } static const struct spi_device_id fxos8700_spi_id[] = { - {"fxos8700", 0}, + { .name = "fxos8700" }, { } }; MODULE_DEVICE_TABLE(spi, fxos8700_spi_id); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index c8b48a5c5ed0..b55d993f0264 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -6,13 +6,15 @@ #ifndef INV_ICM42600_H_ #define INV_ICM42600_H_ -#include <linux/bits.h> #include <linux/bitfield.h> -#include <linux/regmap.h> +#include <linux/bits.h> #include <linux/mutex.h> -#include <linux/regulator/consumer.h> #include <linux/pm.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> + #include <linux/iio/iio.h> + #include <linux/iio/common/inv_sensors_timestamp.h> #include "inv_icm42600_buffer.h" @@ -354,6 +356,8 @@ struct inv_icm42600_sensor_state { cpu_to_le16((_wm) & GENMASK(11, 0)) /* FIFO is 2048 bytes, let 12 samples for reading latency */ #define INV_ICM42600_FIFO_WATERMARK_MAX (2048 - 12 * 16) +/* INV_ICM42600_FIFO_WATERMARK_MAX / 8 = 232 */ +#define INV_ICM42600_FIFO_WATERMARK_MAX_SAMPLES 232 #define INV_ICM42600_REG_INT_CONFIG1 0x0064 #define INV_ICM42600_INT_CONFIG1_TPULSE_DURATION BIT(6) diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index 0ab6eddf0543..4b0e3cd8a506 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -3,25 +3,26 @@ * Copyright (C) 2020 Invensense, Inc. */ -#include <linux/kernel.h> +#include <linux/delay.h> #include <linux/device.h> +#include <linux/kernel.h> +#include <linux/math64.h> +#include <linux/minmax.h> #include <linux/mutex.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> -#include <linux/delay.h> -#include <linux/math64.h> -#include <linux/minmax.h> #include <linux/units.h> #include <linux/iio/buffer.h> -#include <linux/iio/common/inv_sensors_timestamp.h> #include <linux/iio/events.h> #include <linux/iio/iio.h> #include <linux/iio/kfifo_buf.h> +#include <linux/iio/common/inv_sensors_timestamp.h> + #include "inv_icm42600.h" -#include "inv_icm42600_temp.h" #include "inv_icm42600_buffer.h" +#include "inv_icm42600_temp.h" #define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \ { \ @@ -1170,10 +1171,10 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st) accel_st->filter = INV_ICM42600_FILTER_AVG_16X; /* - * clock period is 32kHz (31250ns) + * clock period is 8kHz (125000ns) * jitter is +/- 2% (20 per mille) */ - ts_chip.clock_period = 31250; + ts_chip.clock_period = 125000; ts_chip.jitter = 20; ts_chip.init_period = inv_icm42600_odr_to_period(st->conf.accel.odr); inv_sensors_timestamp_init(&accel_st->ts, &ts_chip); @@ -1186,8 +1187,9 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st) indio_dev->num_channels = ARRAY_SIZE(inv_icm42600_accel_channels); indio_dev->available_scan_masks = inv_icm42600_accel_scan_masks; - ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, - &inv_icm42600_buffer_ops); + ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev, + &inv_icm42600_buffer_ops, + inv_icm42600_buffer_attrs); if (ret) return ERR_PTR(ret); @@ -1211,7 +1213,7 @@ int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev) ssize_t i, size; unsigned int no; const void *accel, *gyro, *timestamp; - const int8_t *temp; + const s8 *temp; unsigned int odr; int64_t ts_val; /* buffer is copied to userspace, zeroing it to avoid any data leak */ diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c index 68a395758031..998d312f7bde 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c @@ -3,17 +3,20 @@ * Copyright (C) 2020 Invensense, Inc. */ -#include <linux/kernel.h> +#include <linux/delay.h> #include <linux/device.h> +#include <linux/kernel.h> #include <linux/minmax.h> #include <linux/mutex.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> -#include <linux/delay.h> +#include <linux/stringify.h> #include <linux/iio/buffer.h> -#include <linux/iio/common/inv_sensors_timestamp.h> #include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> + +#include <linux/iio/common/inv_sensors_timestamp.h> #include "inv_icm42600.h" #include "inv_icm42600_buffer.h" @@ -186,7 +189,7 @@ static unsigned int inv_icm42600_wm_truncate(unsigned int watermark, * smallest latency but this is not as simple as choosing the smallest watermark * value. Latency depends on watermark and ODR. It requires several steps: * 1) compute gyro and accel latencies and choose the smallest value. - * 2) adapt the choosen latency so that it is a multiple of both gyro and accel + * 2) adapt the chosen latency so that it is a multiple of both gyro and accel * ones. Otherwise it is possible that you don't meet a requirement. (for * example with gyro @100Hz wm 4 and accel @100Hz with wm 6, choosing the * value of 4 will not meet accel latency requirement because 6 is not a @@ -248,6 +251,7 @@ int inv_icm42600_buffer_update_watermark(struct inv_icm42600_state *st) /* compute watermark value in bytes */ wm_size = watermark * packet_size; + st->fifo.watermark.value = watermark; /* changing FIFO watermark requires to turn off watermark interrupt */ ret = regmap_update_bits_check(st->map, INV_ICM42600_REG_INT_SOURCE0, @@ -437,6 +441,40 @@ const struct iio_buffer_setup_ops inv_icm42600_buffer_ops = { .postdisable = inv_icm42600_buffer_postdisable, }; +static ssize_t hwfifo_watermark_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); + unsigned int wm; + + guard(mutex)(&st->lock); + + if (indio_dev == st->indio_accel) + wm = st->fifo.watermark.eff_accel; + else if (indio_dev == st->indio_gyro) + wm = st->fifo.watermark.eff_gyro; + else + return -EINVAL; + + return sysfs_emit(buf, "%u\n", wm); +} + +IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_min, "1"); +IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_watermark_max, + __stringify(INV_ICM42600_FIFO_WATERMARK_MAX_SAMPLES)); +static IIO_DEVICE_ATTR_RO(hwfifo_watermark, 0); +IIO_STATIC_CONST_DEVICE_ATTR(hwfifo_enabled, "1"); + +const struct iio_dev_attr *inv_icm42600_buffer_attrs[] = { + &iio_dev_attr_hwfifo_watermark_min, + &iio_dev_attr_hwfifo_watermark_max, + &iio_dev_attr_hwfifo_watermark, + &iio_dev_attr_hwfifo_enabled, + NULL +}; + int inv_icm42600_buffer_fifo_read(struct inv_icm42600_state *st, unsigned int max) { @@ -454,11 +492,10 @@ int inv_icm42600_buffer_fifo_read(struct inv_icm42600_state *st, st->fifo.nb.accel = 0; st->fifo.nb.total = 0; - /* compute maximum FIFO read size */ + /* compute maximum FIFO read size (watermark for max = 0 interrupt case) */ if (max == 0) - max_count = sizeof(st->fifo.data); - else - max_count = max * inv_icm42600_get_packet_size(st->fifo.en); + max = st->fifo.watermark.value; + max_count = max * inv_icm42600_get_packet_size(st->fifo.en); /* read FIFO count value */ raw_fifo_count = (__be16 *)st->buffer; @@ -574,6 +611,7 @@ int inv_icm42600_buffer_init(struct inv_icm42600_state *st) st->fifo.watermark.eff_gyro = 1; st->fifo.watermark.eff_accel = 1; + st->fifo.watermark.value = 1; /* * Default FIFO configuration (bits 7 to 5) diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h index ffca4da1e249..e37ee3416337 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h @@ -6,8 +6,8 @@ #ifndef INV_ICM42600_BUFFER_H_ #define INV_ICM42600_BUFFER_H_ -#include <linux/kernel.h> #include <linux/bits.h> +#include <linux/kernel.h> struct inv_icm42600_state; @@ -34,6 +34,7 @@ struct inv_icm42600_fifo { unsigned int accel; unsigned int eff_gyro; unsigned int eff_accel; + unsigned int value; } watermark; size_t count; struct { @@ -79,6 +80,7 @@ ssize_t inv_icm42600_fifo_decode_packet(const void *packet, const void **accel, const void **timestamp, unsigned int *odr); extern const struct iio_buffer_setup_ops inv_icm42600_buffer_ops; +extern const struct iio_dev_attr *inv_icm42600_buffer_attrs[]; int inv_icm42600_buffer_init(struct inv_icm42600_state *st); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c index 76eb22488e5f..dc97d8a274e3 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c @@ -3,18 +3,18 @@ * Copyright (C) 2020 Invensense, Inc. */ -#include <linux/kernel.h> -#include <linux/device.h> -#include <linux/module.h> -#include <linux/slab.h> #include <linux/delay.h> -#include <linux/mutex.h> +#include <linux/device.h> #include <linux/interrupt.h> #include <linux/irq.h> -#include <linux/regulator/consumer.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> #include <linux/pm_runtime.h> #include <linux/property.h> #include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> #include <linux/iio/iio.h> diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c index 11339ddf1da3..253bf571439d 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c @@ -3,22 +3,23 @@ * Copyright (C) 2020 Invensense, Inc. */ -#include <linux/kernel.h> +#include <linux/delay.h> #include <linux/device.h> +#include <linux/kernel.h> +#include <linux/math64.h> #include <linux/mutex.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> -#include <linux/delay.h> -#include <linux/math64.h> #include <linux/iio/buffer.h> -#include <linux/iio/common/inv_sensors_timestamp.h> #include <linux/iio/iio.h> #include <linux/iio/kfifo_buf.h> +#include <linux/iio/common/inv_sensors_timestamp.h> + #include "inv_icm42600.h" -#include "inv_icm42600_temp.h" #include "inv_icm42600_buffer.h" +#include "inv_icm42600_temp.h" #define INV_ICM42600_GYRO_CHAN(_modifier, _index, _ext_info) \ { \ @@ -755,10 +756,10 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st) } /* - * clock period is 32kHz (31250ns) + * clock period is 8kHz (125000ns) * jitter is +/- 2% (20 per mille) */ - ts_chip.clock_period = 31250; + ts_chip.clock_period = 125000; ts_chip.jitter = 20; ts_chip.init_period = inv_icm42600_odr_to_period(st->conf.accel.odr); inv_sensors_timestamp_init(&gyro_st->ts, &ts_chip); @@ -772,8 +773,9 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st) indio_dev->available_scan_masks = inv_icm42600_gyro_scan_masks; indio_dev->setup_ops = &inv_icm42600_buffer_ops; - ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, - &inv_icm42600_buffer_ops); + ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev, + &inv_icm42600_buffer_ops, + inv_icm42600_buffer_attrs); if (ret) return ERR_PTR(ret); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c index 7e4d3ea68721..28552d2db91d 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c @@ -3,13 +3,12 @@ * Copyright (C) 2020 InvenSense, Inc. */ -#include <linux/kernel.h> #include <linux/device.h> -#include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/i2c.h> -#include <linux/regmap.h> +#include <linux/kernel.h> +#include <linux/module.h> #include <linux/property.h> +#include <linux/regmap.h> #include "inv_icm42600.h" @@ -75,13 +74,13 @@ static int inv_icm42600_probe(struct i2c_client *client) * supported by this driver */ static const struct i2c_device_id inv_icm42600_id[] = { - { "icm42600", INV_CHIP_ICM42600 }, - { "icm42602", INV_CHIP_ICM42602 }, - { "icm42605", INV_CHIP_ICM42605 }, - { "icm42686", INV_CHIP_ICM42686 }, - { "icm42622", INV_CHIP_ICM42622 }, - { "icm42688", INV_CHIP_ICM42688 }, - { "icm42631", INV_CHIP_ICM42631 }, + { .name = "icm42600", .driver_data = INV_CHIP_ICM42600 }, + { .name = "icm42602", .driver_data = INV_CHIP_ICM42602 }, + { .name = "icm42605", .driver_data = INV_CHIP_ICM42605 }, + { .name = "icm42686", .driver_data = INV_CHIP_ICM42686 }, + { .name = "icm42622", .driver_data = INV_CHIP_ICM42622 }, + { .name = "icm42688", .driver_data = INV_CHIP_ICM42688 }, + { .name = "icm42631", .driver_data = INV_CHIP_ICM42631 }, { } }; MODULE_DEVICE_TABLE(i2c, inv_icm42600_id); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c index 13e2e7d38638..faf743bc6444 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c @@ -3,13 +3,12 @@ * Copyright (C) 2020 InvenSense, Inc. */ -#include <linux/kernel.h> #include <linux/device.h> +#include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> -#include <linux/spi/spi.h> -#include <linux/regmap.h> #include <linux/property.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> #include "inv_icm42600.h" @@ -72,13 +71,13 @@ static int inv_icm42600_probe(struct spi_device *spi) * supported by this driver */ static const struct spi_device_id inv_icm42600_id[] = { - { "icm42600", INV_CHIP_ICM42600 }, - { "icm42602", INV_CHIP_ICM42602 }, - { "icm42605", INV_CHIP_ICM42605 }, - { "icm42686", INV_CHIP_ICM42686 }, - { "icm42622", INV_CHIP_ICM42622 }, - { "icm42688", INV_CHIP_ICM42688 }, - { "icm42631", INV_CHIP_ICM42631 }, + { .name = "icm42600", .driver_data = INV_CHIP_ICM42600 }, + { .name = "icm42602", .driver_data = INV_CHIP_ICM42602 }, + { .name = "icm42605", .driver_data = INV_CHIP_ICM42605 }, + { .name = "icm42686", .driver_data = INV_CHIP_ICM42686 }, + { .name = "icm42622", .driver_data = INV_CHIP_ICM42622 }, + { .name = "icm42688", .driver_data = INV_CHIP_ICM42688 }, + { .name = "icm42631", .driver_data = INV_CHIP_ICM42631 }, { } }; MODULE_DEVICE_TABLE(spi, inv_icm42600_id); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c index 727b03d541a5..7f80bda471c3 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c @@ -3,11 +3,12 @@ * Copyright (C) 2020 Invensense, Inc. */ -#include <linux/kernel.h> #include <linux/device.h> +#include <linux/kernel.h> #include <linux/mutex.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> + #include <linux/iio/iio.h> #include "inv_icm42600.h" diff --git a/drivers/iio/imu/inv_icm42607/Kconfig b/drivers/iio/imu/inv_icm42607/Kconfig new file mode 100644 index 000000000000..23f461f57afc --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/Kconfig @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +config INV_ICM42607 + tristate + select IIO_BUFFER + select IIO_INV_SENSORS_TIMESTAMP + +config INV_ICM42607_I2C + tristate "InvenSense ICM-42607 I2C driver" + depends on I2C + select INV_ICM42607 + select REGMAP_I2C + help + This driver supports the InvenSense ICM-42607 motion tracking + device over I2C. + + This driver can be built as a module. The module will be called + inv-icm42607-i2c. + +config INV_ICM42607_SPI + tristate "InvenSense ICM-42607 SPI driver" + depends on SPI_MASTER + select INV_ICM42607 + select REGMAP_SPI + help + This driver supports the InvenSense ICM-42607 motion tracking + device over SPI. + + This driver can be built as a module. The module will be called + inv-icm42607-spi. diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile new file mode 100644 index 000000000000..7b907e019601 --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o +inv-icm42607-y += inv_icm42607_core.o +inv-icm42607-y += inv_icm42607_gyro.o +inv-icm42607-y += inv_icm42607_accel.o +inv-icm42607-y += inv_icm42607_temp.o + +obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o +inv-icm42607-i2c-y += inv_icm42607_i2c.o + +obj-$(CONFIG_INV_ICM42607_SPI) += inv-icm42607-spi.o +inv-icm42607-spi-y += inv_icm42607_spi.o diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h new file mode 100644 index 000000000000..4d51b0da1aa1 --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h @@ -0,0 +1,421 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2026 InvenSense, Inc. + */ + +#ifndef INV_ICM42607_H_ +#define INV_ICM42607_H_ + +#include <linux/bits.h> +#include <linux/iio/iio.h> +#include <linux/mutex.h> +#include <linux/pm.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/time.h> +#include <linux/types.h> + +#include <asm/byteorder.h> + +/* + * Serial bus slew rates. Rates are expressed as range between the two + * values with the midpoint as the typical rate. For the final value of + * 2ns, 2ns is considered the max value with no expressed minimum or + * typical value. + */ +enum inv_icm42607_slew_rate { + INV_ICM42607_SLEW_RATE_20_60NS = 0, + INV_ICM42607_SLEW_RATE_12_36NS = 1, + INV_ICM42607_SLEW_RATE_6_19NS = 2, + INV_ICM42607_SLEW_RATE_4_14NS = 3, + INV_ICM42607_SLEW_RATE_2_6NS = 4, + INV_ICM42607_SLEW_RATE_2NS = 5, + INV_ICM42607_SLEW_RATE_NB +}; + +enum inv_icm42607_sensor_mode { + INV_ICM42607_SENSOR_MODE_OFF = 0, + INV_ICM42607_SENSOR_MODE_STANDBY = 1, + INV_ICM42607_SENSOR_MODE_LOW_POWER = 2, + INV_ICM42607_SENSOR_MODE_LOW_NOISE = 3, + INV_ICM42607_SENSOR_MODE_NB +}; + +/* gyroscope fullscale values */ +enum inv_icm42607_gyro_fs { + INV_ICM42607_GYRO_FS_2000DPS = 0, + INV_ICM42607_GYRO_FS_1000DPS = 1, + INV_ICM42607_GYRO_FS_500DPS = 2, + INV_ICM42607_GYRO_FS_250DPS = 3, + INV_ICM42607_GYRO_FS_NB +}; + +/* accelerometer fullscale values */ +enum inv_icm42607_accel_fs { + INV_ICM42607_ACCEL_FS_16G = 0, + INV_ICM42607_ACCEL_FS_8G = 1, + INV_ICM42607_ACCEL_FS_4G = 2, + INV_ICM42607_ACCEL_FS_2G = 3, + INV_ICM42607_ACCEL_FS_NB +}; + +/* ODR values - Note Gyro does not support ODR less than 12.5Hz */ +enum inv_icm42607_odr { + INV_ICM42607_ODR_1600HZ = 5, + INV_ICM42607_ODR_800HZ = 6, + INV_ICM42607_ODR_400HZ = 7, + INV_ICM42607_ODR_200HZ = 8, + INV_ICM42607_ODR_100HZ = 9, + INV_ICM42607_ODR_50HZ = 10, + INV_ICM42607_ODR_25HZ = 11, + INV_ICM42607_ODR_12_5HZ = 12, + INV_ICM42607_ODR_6_25HZ_LP = 13, + INV_ICM42607_ODR_3_125HZ_LP = 14, + INV_ICM42607_ODR_1_5625HZ_LP = 15, + INV_ICM42607_ODR_NB +}; + +/* Low-Noise mode sensor data filter (bandwidth) */ +enum inv_icm42607_filter_bw { + INV_ICM42607_FILTER_BYPASS = 0, + INV_ICM42607_FILTER_BW_180HZ = 1, + INV_ICM42607_FILTER_BW_121HZ = 2, + INV_ICM42607_FILTER_BW_73HZ = 3, + INV_ICM42607_FILTER_BW_53HZ = 4, + INV_ICM42607_FILTER_BW_34HZ = 5, + INV_ICM42607_FILTER_BW_25HZ = 6, + INV_ICM42607_FILTER_BW_16HZ = 7, + INV_ICM42607_FILTER_BW_NB +}; + +/* Low-Power mode sensor data filter (averaging) */ +enum inv_icm42607_filter_avg { + INV_ICM42607_FILTER_AVG_2X = 0, + INV_ICM42607_FILTER_AVG_4X = 1, + INV_ICM42607_FILTER_AVG_8X = 2, + INV_ICM42607_FILTER_AVG_16X = 3, + INV_ICM42607_FILTER_AVG_32X = 4, + INV_ICM42607_FILTER_AVG_64X = 5, + /* values 6 and 7 also correspond to 64x. */ +}; + +/* Temperature sensor data filter (bandwidth) */ +enum inv_icm42607_temp_filter_bw { + INV_ICM42607_TEMP_FILTER_BYPASS = 0, + INV_ICM42607_TEMP_FILTER_BW_180HZ = 1, + INV_ICM42607_TEMP_FILTER_BW_72HZ = 2, + INV_ICM42607_TEMP_FILTER_BW_34HZ = 3, + INV_ICM42607_TEMP_FILTER_BW_16HZ = 4, + INV_ICM42607_TEMP_FILTER_BW_8HZ = 5, + INV_ICM42607_TEMP_FILTER_BW_4HZ = 6, + /* value 7 also corresponds to 4Hz */ +}; + +/* Signed so that negative values can signify an invalid condition. */ +struct inv_icm42607_sensor_conf { + int mode; + int fs; + int odr; + int filter; +}; +#define INV_ICM42607_SENSOR_CONF_INIT { -1, -1, -1, -1 } + +struct inv_icm42607_conf { + struct inv_icm42607_sensor_conf gyro; + struct inv_icm42607_sensor_conf accel; + ktime_t gyro_stop; /* earliest time to stop the gyro */ +}; + +struct inv_icm42607_hw { + const char *name; + const struct inv_icm42607_conf *conf; + u8 whoami; +}; + +/** + * struct inv_icm42607_state - driver state variables + * @hw: Hardware specific data. + * @lock: lock for serializing multiple registers access. + * @map: regmap pointer. + * @indio_accel: accelerometer IIO device. + * @indio_gyro: gyroscope IIO device. + * @vddio_supply: I/O voltage regulator for the chip. + * @vddio_en: I/O voltage status for runtime PM. + * @conf: chip sensors configurations. + * @orientation: sensor chip orientation relative to main hardware. + */ +struct inv_icm42607_state { + const struct inv_icm42607_hw *hw; + struct mutex lock; + struct regmap *map; + struct iio_dev *indio_accel; + struct iio_dev *indio_gyro; + struct regulator *vddio_supply; + bool vddio_en; + struct inv_icm42607_conf conf; + struct iio_mount_matrix orientation; +}; + +/** + * struct inv_icm42607_sensor_state - sensor state variables + * @power_mode: sensor requested power mode (for common frequencies) + * @filter: sensor filter. + */ +struct inv_icm42607_sensor_state { + enum inv_icm42607_sensor_mode power_mode; + int filter; +}; + +/* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */ + +/* Register Map for User Bank 0 */ +#define INV_ICM42607_REG_MCLK_RDY 0x00 + +#define INV_ICM42607_REG_DEVICE_CONFIG 0x01 +#define INV_ICM42607_DEVICE_CONFIG_SPI_AP_4WIRE BIT(2) +#define INV_ICM42607_DEVICE_CONFIG_SPI_MODE BIT(0) + +#define INV_ICM42607_REG_SIGNAL_PATH_RESET 0x02 +#define INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET BIT(4) +#define INV_ICM42607_SIGNAL_PATH_RESET_FIFO_FLUSH BIT(2) + +#define INV_ICM42607_REG_DRIVE_CONFIG1 0x03 +#define INV_ICM42607_DRIVE_CONFIG1_I3C_DDR_MASK GENMASK(5, 3) +#define INV_ICM42607_DRIVE_CONFIG1_I3C_SDR_MASK GENMASK(2, 0) + +#define INV_ICM42607_REG_DRIVE_CONFIG2 0x04 +#define INV_ICM42607_DRIVE_CONFIG2_I2C_MASK GENMASK(5, 3) +#define INV_ICM42607_DRIVE_CONFIG2_ALL_MASK GENMASK(2, 0) + +#define INV_ICM42607_REG_DRIVE_CONFIG3 0x05 +#define INV_ICM42607_DRIVE_CONFIG3_SPI_MASK GENMASK(2, 0) + +#define INV_ICM42607_REG_INT_CONFIG 0x06 +#define INV_ICM42607_INT_CONFIG_INT2_LATCHED BIT(5) +#define INV_ICM42607_INT_CONFIG_INT2_PUSH_PULL BIT(4) +#define INV_ICM42607_INT_CONFIG_INT2_ACTIVE_HIGH BIT(3) +#define INV_ICM42607_INT_CONFIG_INT2_ACTIVE_LOW 0x00 +#define INV_ICM42607_INT_CONFIG_INT1_LATCHED BIT(2) +#define INV_ICM42607_INT_CONFIG_INT1_PUSH_PULL BIT(1) +#define INV_ICM42607_INT_CONFIG_INT1_ACTIVE_HIGH BIT(0) +#define INV_ICM42607_INT_CONFIG_INT1_ACTIVE_LOW 0x00 + +/* all sensor data are 16 bits (2 registers wide) in big-endian */ +#define INV_ICM42607_REG_TEMP_DATA1 0x09 +#define INV_ICM42607_REG_TEMP_DATA0 0x0A +#define INV_ICM42607_REG_ACCEL_DATA_X1 0x0B +#define INV_ICM42607_REG_ACCEL_DATA_X0 0x0C +#define INV_ICM42607_REG_ACCEL_DATA_Y1 0x0D +#define INV_ICM42607_REG_ACCEL_DATA_Y0 0x0E +#define INV_ICM42607_REG_ACCEL_DATA_Z1 0x0F +#define INV_ICM42607_REG_ACCEL_DATA_Z0 0x10 +#define INV_ICM42607_REG_GYRO_DATA_X1 0x11 +#define INV_ICM42607_REG_GYRO_DATA_X0 0x12 +#define INV_ICM42607_REG_GYRO_DATA_Y1 0x13 +#define INV_ICM42607_REG_GYRO_DATA_Y0 0x14 +#define INV_ICM42607_REG_GYRO_DATA_Z1 0x15 +#define INV_ICM42607_REG_GYRO_DATA_Z0 0x16 +#define INV_ICM42607_DATA_INVALID -32768 + +#define INV_ICM42607_REG_TMST_FSYNCH 0x17 +#define INV_ICM42607_REG_TMST_FSYNCL 0x18 + +/* APEX Data Registers */ +#define INV_ICM42607_REG_APEX_DATA0 0x31 +#define INV_ICM42607_REG_APEX_DATA1 0x32 +#define INV_ICM42607_REG_APEX_DATA2 0x33 +#define INV_ICM42607_REG_APEX_DATA3 0x34 +#define INV_ICM42607_REG_APEX_DATA4 0x1D +#define INV_ICM42607_REG_APEX_DATA5 0x1E + +#define INV_ICM42607_REG_PWR_MGMT0 0x1F +#define INV_ICM42607_PWR_MGMT0_ACCEL_LP_CLK_SEL BIT(7) +#define INV_ICM42607_PWR_MGMT0_IDLE BIT(4) +#define INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK GENMASK(3, 2) +#define INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK GENMASK(1, 0) + +#define INV_ICM42607_REG_GYRO_CONFIG0 0x20 +#define INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK GENMASK(6, 5) +#define INV_ICM42607_GYRO_CONFIG0_ODR_MASK GENMASK(3, 0) + +#define INV_ICM42607_REG_ACCEL_CONFIG0 0x21 +#define INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK GENMASK(6, 5) +#define INV_ICM42607_ACCEL_CONFIG0_ODR_MASK GENMASK(3, 0) + +#define INV_ICM42607_REG_TEMP_CONFIG0 0x22 +#define INV_ICM42607_TEMP_CONFIG0_FILTER_MASK GENMASK(6, 4) + +#define INV_ICM42607_REG_GYRO_CONFIG1 0x23 +#define INV_ICM42607_GYRO_CONFIG1_FILTER_MASK GENMASK(2, 0) + +#define INV_ICM42607_REG_ACCEL_CONFIG1 0x24 +#define INV_ICM42607_ACCEL_CONFIG1_AVG_MASK GENMASK(6, 4) +#define INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK GENMASK(2, 0) + +#define INV_ICM42607_REG_APEX_CONFIG0 0x25 +#define INV_ICM42607_APEX_CONFIG0_DMP_POWER_SAVE_EN BIT(3) +#define INV_ICM42607_APEX_CONFIG0_DMP_INIT_EN BIT(2) +#define INV_ICM42607_APEX_CONFIG0_DMP_MEM_RESET_EN BIT(0) + +#define INV_ICM42607_REG_APEX_CONFIG1 0x26 +#define INV_ICM42607_APEX_CONFIG1_SMD_ENABLE BIT(6) +#define INV_ICM42607_APEX_CONFIG1_FF_ENABLE BIT(5) +#define INV_ICM42607_APEX_CONFIG1_TILT_ENABLE BIT(4) +#define INV_ICM42607_APEX_CONFIG1_PED_ENABLE BIT(3) +#define INV_ICM42607_APEX_CONFIG1_DMP_ODR_MASK GENMASK(1, 0) + +#define INV_ICM42607_REG_WOM_CONFIG 0x27 +#define INV_ICM42607_WOM_CONFIG_INT_DUR_MASK GENMASK(4, 3) +#define INV_ICM42607_WOM_CONFIG_INT_MODE BIT(2) +#define INV_ICM42607_WOM_CONFIG_MODE BIT(1) +#define INV_ICM42607_WOM_CONFIG_EN BIT(0) + +#define INV_ICM42607_REG_FIFO_CONFIG1 0x28 +#define INV_ICM42607_FIFO_CONFIG1_MODE BIT(1) +#define INV_ICM42607_FIFO_CONFIG1_BYPASS BIT(0) + +#define INV_ICM42607_REG_FIFO_CONFIG2 0x29 +#define INV_ICM42607_REG_FIFO_CONFIG3 0x2A +#define INV_ICM42607_FIFO_WATERMARK_VAL(_wm) \ + cpu_to_le16((_wm) & GENMASK(11, 0)) +/* FIFO is 2048 bytes, let 12 samples for reading latency */ +#define INV_ICM42607_FIFO_WATERMARK_MAX (2048 - 12 * 16) +#define INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE 8 +#define INV_ICM42607_FIFO_2SENSORS_PACKET_SIZE 16 + +#define INV_ICM42607_REG_INT_SOURCE0 0x2B +#define INV_ICM42607_INT_SOURCE0_ST_INT1_EN BIT(7) +#define INV_ICM42607_INT_SOURCE0_FSYNC_INT1_EN BIT(6) +#define INV_ICM42607_INT_SOURCE0_PLL_RDY_INT1_EN BIT(5) +#define INV_ICM42607_INT_SOURCE0_RESET_DONE_INT1_EN BIT(4) +#define INV_ICM42607_INT_SOURCE0_DRDY_INT1_EN BIT(3) +#define INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN BIT(2) +#define INV_ICM42607_INT_SOURCE0_FIFO_FULL_INT1_EN BIT(1) +#define INV_ICM42607_INT_SOURCE0_AGC_RDY_INT1_EN BIT(0) + +#define INV_ICM42607_REG_INT_SOURCE1 0x2C +#define INV_ICM42607_INT_SOURCE1_I3C_ERROR_INT1_EN BIT(6) +#define INV_ICM42607_INT_SOURCE1_SMD_INT1_EN BIT(3) +#define INV_ICM42607_INT_SOURCE1_WOM_INT1_EN GENMASK(2, 0) + +#define INV_ICM42607_REG_INT_SOURCE3 0x2D +#define INV_ICM42607_INT_SOURCE3_ST_INT2_EN BIT(7) +#define INV_ICM42607_INT_SOURCE3_FSYNC_INT2_EN BIT(6) +#define INV_ICM42607_INT_SOURCE3_PLL_RDY_INT2_EN BIT(5) +#define INV_ICM42607_INT_SOURCE3_RESET_DONE_INT2_EN BIT(4) +#define INV_ICM42607_INT_SOURCE3_DRDY_INT2_EN BIT(3) +#define INV_ICM42607_INT_SOURCE3_FIFO_THS_INT2_EN BIT(2) +#define INV_ICM42607_INT_SOURCE3_FIFO_FULL_INT2_EN BIT(1) +#define INV_ICM42607_INT_SOURCE3_AGC_RDY_INT2_EN BIT(0) + +#define INV_ICM42607_REG_INT_SOURCE4 0x2E +#define INV_ICM42607_INT_SOURCE4_I3C_ERROR_INT2_EN BIT(6) +#define INV_ICM42607_INT_SOURCE4_SMD_INT2_EN BIT(3) +#define INV_ICM42607_INT_SOURCE4_WOM_Z_INT2_EN BIT(2) +#define INV_ICM42607_INT_SOURCE4_WOM_Y_INT2_EN BIT(1) +#define INV_ICM42607_INT_SOURCE4_WOM_X_INT2_EN BIT(0) + +#define INV_ICM42607_REG_FIFO_LOST_PKT0 0x2F +#define INV_ICM42607_REG_FIFO_LOST_PKT1 0x30 + +#define INV_ICM42607_REG_INTF_CONFIG0 0x35 +#define INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_FORMAT BIT(6) +#define INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_ENDIAN BIT(5) +#define INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN BIT(4) +#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK GENMASK(1, 0) +#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS 2 +#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS 3 + +#define INV_ICM42607_REG_INTF_CONFIG1 0x36 +#define INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN BIT(3) +#define INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN BIT(2) +#define INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK GENMASK(1, 0) +#define INV_ICM42607_INTF_CONFIG1_CLKSEL_INT 0 +#define INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL 1 +#define INV_ICM42607_INTF_CONFIG1_CLKSEL_OFF 2 + +#define INV_ICM42607_REG_INT_STATUS_DRDY 0x39 +#define INV_ICM42607_INT_STATUS_DRDY_DATA_RDY BIT(0) + +#define INV_ICM42607_REG_INT_STATUS 0x3A +#define INV_ICM42607_INT_STATUS_ST BIT(7) +#define INV_ICM42607_INT_STATUS_FSYNC BIT(6) +#define INV_ICM42607_INT_STATUS_PLL_RDY BIT(5) +#define INV_ICM42607_INT_STATUS_RESET_DONE BIT(4) +#define INV_ICM42607_INT_STATUS_FIFO_THS BIT(2) +#define INV_ICM42607_INT_STATUS_FIFO_FULL BIT(1) +#define INV_ICM42607_INT_STATUS_AGC_RDY BIT(0) + +#define INV_ICM42607_REG_INT_STATUS2 0x3B +#define INV_ICM42607_INT_STATUS2_SMD BIT(3) +#define INV_ICM42607_INT_STATUS2_WOM_INT GENMASK(2, 0) + +#define INV_ICM42607_REG_INT_STATUS3 0x3C +#define INV_ICM42607_INT_STATUS3_STEP_DET BIT(5) +#define INV_ICM42607_INT_STATUS3_STEP_CNT_OVF BIT(4) +#define INV_ICM42607_INT_STATUS3_TILT_DET BIT(3) +#define INV_ICM42607_INT_STATUS3_FF_DET BIT(2) + +/* + * FIFO access registers + * FIFO count is 16 bits (2 registers) big-endian + * FIFO data is a continuous read register to read FIFO content + */ +#define INV_ICM42607_REG_FIFO_COUNTH 0x3D +#define INV_ICM42607_REG_FIFO_COUNTL 0x3E +#define INV_ICM42607_REG_FIFO_DATA 0x3F + +#define INV_ICM42607_REG_WHOAMI 0x75 +#define INV_ICM42607P_WHOAMI 0x60 +#define INV_ICM42607_WHOAMI 0x67 + +/* + * Timings as listed in section 3 of datasheet, all values listed in datasheet + * in ms except temp startup time... setting all values in us and using + * USEC_PER_MSEC to convert from values displayed in datasheet. + */ +#define INV_ICM42607_POWER_UP_TIME_US (100 * USEC_PER_MSEC) +#define INV_ICM42607_RESET_TIME_US (1 * USEC_PER_MSEC) +#define INV_ICM42607_ACCEL_STARTUP_TIME_US (10 * USEC_PER_MSEC) +#define INV_ICM42607_GYRO_STARTUP_TIME_US (30 * USEC_PER_MSEC) +#define INV_ICM42607_GYRO_STOP_TIME_US (45 * USEC_PER_MSEC) +#define INV_ICM42607_TEMP_STARTUP_TIME_US 77 + +/* + * Suspend delay assumed from other icm42600 series device, not + * documented in datasheet. + */ +#define INV_ICM42607_SUSPEND_DELAY_MS (2 * MSEC_PER_SEC) + +typedef int (*inv_icm42607_bus_setup)(struct inv_icm42607_state *); + +extern const struct regmap_config inv_icm42607_regmap_config; +extern const struct inv_icm42607_hw inv_icm42607_hw_data; +extern const struct inv_icm42607_hw inv_icm42607p_hw_data; +extern const struct dev_pm_ops inv_icm42607_pm_ops; + +const struct iio_mount_matrix * +inv_icm42607_get_mount_matrix(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan); + +int inv_icm42607_get_pwr_mgmt0(struct inv_icm42607_state *st, + enum inv_icm42607_sensor_mode *gyro, + enum inv_icm42607_sensor_mode *accel); + +int inv_icm42607_set_sensor_conf(struct inv_icm42607_state *st, + struct inv_icm42607_sensor_conf *conf, + enum iio_chan_type chan_type); + +int inv_icm42607_read_sensor(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + s16 *val); + +int inv_icm42607_core_probe(struct regmap *regmap, + const struct inv_icm42607_hw *hw, + inv_icm42607_bus_setup bus_setup); + +struct iio_dev *inv_icm42607_gyro_init(struct inv_icm42607_state *st); + +struct iio_dev *inv_icm42607_accel_init(struct inv_icm42607_state *st); + +#endif diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c new file mode 100644 index 000000000000..0b3f035c2da0 --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 InvenSense, Inc. + */ + +#include <linux/array_size.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/device/devres.h> +#include <linux/err.h> +#include <linux/iio/iio.h> +#include <linux/mutex.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/types.h> + +#include "inv_icm42607.h" +#include "inv_icm42607_temp.h" + +#define INV_ICM42607_ACCEL_CHAN(_modifier, _index, _ext_info) \ +{ \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = _modifier, \ + .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_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = _index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ + .ext_info = _ext_info, \ +} + +enum inv_icm42607_accel_scan { + INV_ICM42607_ACCEL_SCAN_X, + INV_ICM42607_ACCEL_SCAN_Y, + INV_ICM42607_ACCEL_SCAN_Z, + INV_ICM42607_ACCEL_SCAN_TEMP, +}; + +static const struct iio_chan_spec_ext_info inv_icm42607_accel_ext_infos[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42607_get_mount_matrix), + { } +}; + +static const struct iio_chan_spec inv_icm42607_accel_channels[] = { + INV_ICM42607_ACCEL_CHAN(IIO_MOD_X, INV_ICM42607_ACCEL_SCAN_X, + inv_icm42607_accel_ext_infos), + INV_ICM42607_ACCEL_CHAN(IIO_MOD_Y, INV_ICM42607_ACCEL_SCAN_Y, + inv_icm42607_accel_ext_infos), + INV_ICM42607_ACCEL_CHAN(IIO_MOD_Z, INV_ICM42607_ACCEL_SCAN_Z, + inv_icm42607_accel_ext_infos), + INV_ICM42607_TEMP_CHAN(INV_ICM42607_ACCEL_SCAN_TEMP), +}; + +static const int inv_icm42607_accel_scale_nano[][2] = { + [INV_ICM42607_ACCEL_FS_16G] = { 0, 4788403 }, + [INV_ICM42607_ACCEL_FS_8G] = { 0, 2394202 }, + [INV_ICM42607_ACCEL_FS_4G] = { 0, 1197101 }, + [INV_ICM42607_ACCEL_FS_2G] = { 0, 598550 }, +}; + +static int inv_icm42607_accel_read_scale(struct iio_dev *indio_dev, + int *val, int *val2) +{ + struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev); + unsigned int idx; + + guard(mutex)(&st->lock); + + idx = st->conf.accel.fs; + + *val = inv_icm42607_accel_scale_nano[idx][0]; + *val2 = inv_icm42607_accel_scale_nano[idx][1]; + return IIO_VAL_INT_PLUS_NANO; +} + +static int inv_icm42607_accel_write_scale(struct iio_dev *indio_dev, + int val, int val2) +{ + struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT; + struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev); + size_t scales_len = ARRAY_SIZE(inv_icm42607_accel_scale_nano); + struct device *dev = regmap_get_device(st->map); + unsigned int idx; + int ret; + + for (idx = 0; idx < scales_len; idx++) { + if (val == inv_icm42607_accel_scale_nano[idx][0] && + val2 == inv_icm42607_accel_scale_nano[idx][1]) + break; + } + if (idx == scales_len) + return -EINVAL; + + conf.fs = idx; + + PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + guard(mutex)(&st->lock); + + return inv_icm42607_set_sensor_conf(st, &conf, IIO_ACCEL); +} + +/* IIO format int + micro , values 0-4 reserved. */ +static const int inv_icm42607_accel_odr[][2] = { + [INV_ICM42607_ODR_1600HZ] = { 1600, 0 }, + [INV_ICM42607_ODR_800HZ] = { 800, 0 }, + [INV_ICM42607_ODR_400HZ] = { 400, 0 }, + [INV_ICM42607_ODR_200HZ] = { 200, 0 }, + [INV_ICM42607_ODR_100HZ] = { 100, 0 }, + [INV_ICM42607_ODR_50HZ] = { 50, 0 }, + [INV_ICM42607_ODR_25HZ] = { 25, 0 }, + [INV_ICM42607_ODR_12_5HZ] = { 12, 500000 }, + [INV_ICM42607_ODR_6_25HZ_LP] = { 6, 250000 }, + [INV_ICM42607_ODR_3_125HZ_LP] = { 3, 125000 }, + [INV_ICM42607_ODR_1_5625HZ_LP] = { 1, 562500 }, +}; + +static int inv_icm42607_accel_read_odr(struct inv_icm42607_state *st, + int *val, int *val2) +{ + unsigned int odr; + unsigned int i; + + guard(mutex)(&st->lock); + + odr = st->conf.accel.odr; + + for (i = INV_ICM42607_ODR_1600HZ; i < ARRAY_SIZE(inv_icm42607_accel_odr); i++) { + if (i == odr) + break; + } + if (i == ARRAY_SIZE(inv_icm42607_accel_odr)) + return -EINVAL; + + *val = inv_icm42607_accel_odr[i][0]; + *val2 = inv_icm42607_accel_odr[i][1]; + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int inv_icm42607_accel_write_odr(struct iio_dev *indio_dev, + int val, int val2) +{ + struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT; + struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev); + struct device *dev = regmap_get_device(st->map); + unsigned int idx; + int ret; + + for (idx = INV_ICM42607_ODR_1600HZ; + idx < ARRAY_SIZE(inv_icm42607_accel_odr); idx++) { + if (val == inv_icm42607_accel_odr[idx][0] && + val2 == inv_icm42607_accel_odr[idx][1]) + break; + } + if (idx == ARRAY_SIZE(inv_icm42607_accel_odr)) + return -EINVAL; + + conf.odr = idx; + + PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + guard(mutex)(&st->lock); + + return inv_icm42607_set_sensor_conf(st, &conf, IIO_ACCEL); +} + +static int inv_icm42607_accel_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev); + s16 data; + int ret; + + switch (chan->type) { + case IIO_ACCEL: + break; + case IIO_TEMP: + if (mask != IIO_CHAN_INFO_SAMP_FREQ) + return inv_icm42607_temp_read_raw(indio_dev, chan, + val, val2, mask); + break; + default: + return -EINVAL; + } + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = inv_icm42607_read_sensor(indio_dev, chan, &data); + if (ret) + return ret; + *val = data; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + return inv_icm42607_accel_read_scale(indio_dev, val, val2); + case IIO_CHAN_INFO_SAMP_FREQ: + return inv_icm42607_accel_read_odr(st, val, val2); + default: + return -EINVAL; + } +} + +static int inv_icm42607_accel_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: + if (chan->type != IIO_ACCEL) + return -EINVAL; + *vals = (const int *)inv_icm42607_accel_scale_nano; + *type = IIO_VAL_INT_PLUS_NANO; + *length = ARRAY_SIZE(inv_icm42607_accel_scale_nano) * 2; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SAMP_FREQ: + *vals = (const int *)inv_icm42607_accel_odr[INV_ICM42607_ODR_1600HZ]; + *type = IIO_VAL_INT_PLUS_MICRO; + *length = (ARRAY_SIZE(inv_icm42607_accel_odr) - + INV_ICM42607_ODR_1600HZ) * 2; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int inv_icm42607_accel_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + if (chan->type != IIO_ACCEL) + return -EINVAL; + ret = inv_icm42607_accel_write_scale(indio_dev, val, val2); + return ret; + case IIO_CHAN_INFO_SAMP_FREQ: + return inv_icm42607_accel_write_odr(indio_dev, val, val2); + default: + return -EINVAL; + } +} + +static int inv_icm42607_accel_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + if (chan->type != IIO_ACCEL) + return -EINVAL; + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_SAMP_FREQ: + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static const struct iio_info inv_icm42607_accel_info = { + .read_raw = inv_icm42607_accel_read_raw, + .read_avail = inv_icm42607_accel_read_avail, + .write_raw = inv_icm42607_accel_write_raw, + .write_raw_get_fmt = inv_icm42607_accel_write_raw_get_fmt, +}; + +struct iio_dev *inv_icm42607_accel_init(struct inv_icm42607_state *st) +{ + struct device *dev = regmap_get_device(st->map); + struct inv_icm42607_sensor_state *accel_st; + struct iio_dev *indio_dev; + const char *name; + int ret; + + name = devm_kasprintf(dev, GFP_KERNEL, "%s-accel", st->hw->name); + if (!name) + return ERR_PTR(-ENOMEM); + + indio_dev = devm_iio_device_alloc(dev, sizeof(*accel_st)); + if (!indio_dev) + return ERR_PTR(-ENOMEM); + + accel_st = iio_priv(indio_dev); + accel_st->power_mode = INV_ICM42607_SENSOR_MODE_LOW_NOISE; + accel_st->filter = INV_ICM42607_FILTER_BW_73HZ; + + indio_dev->name = name; + indio_dev->info = &inv_icm42607_accel_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = inv_icm42607_accel_channels; + indio_dev->num_channels = ARRAY_SIZE(inv_icm42607_accel_channels); + iio_device_set_drvdata(indio_dev, st); + + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + return ERR_PTR(ret); + + return indio_dev; +} diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file mode 100644 index 000000000000..190e998f7b8e --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c @@ -0,0 +1,702 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 InvenSense, Inc. + */ + +#include <linux/bitfield.h> +#include <linux/cleanup.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/iio/iio.h> +#include <linux/ktime.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/time.h> +#include <linux/timekeeping.h> +#include <linux/types.h> + +#include <asm/byteorder.h> + +#include "inv_icm42607.h" + +static bool inv_icm42607_is_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case INV_ICM42607_REG_MCLK_RDY ... INV_ICM42607_REG_INT_CONFIG: + case INV_ICM42607_REG_TEMP_DATA1 ... INV_ICM42607_REG_TMST_FSYNCL: + case INV_ICM42607_REG_APEX_DATA4 ... INV_ICM42607_REG_INTF_CONFIG1: + case INV_ICM42607_REG_INT_STATUS_DRDY ... INV_ICM42607_REG_FIFO_DATA: + case INV_ICM42607_REG_WHOAMI: + return true; + } + + return false; +} + +static bool inv_icm42607_is_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case INV_ICM42607_REG_DEVICE_CONFIG ... INV_ICM42607_REG_INT_CONFIG: + case INV_ICM42607_REG_PWR_MGMT0 ... INV_ICM42607_REG_INT_SOURCE4: + case INV_ICM42607_REG_INTF_CONFIG0 ... INV_ICM42607_REG_INTF_CONFIG1: + return true; + } + + return false; +} + +static bool inv_icm42607_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case INV_ICM42607_REG_MCLK_RDY: + case INV_ICM42607_REG_SIGNAL_PATH_RESET: + case INV_ICM42607_REG_TEMP_DATA1 ... INV_ICM42607_REG_APEX_DATA5: + case INV_ICM42607_REG_APEX_CONFIG0: + case INV_ICM42607_REG_FIFO_LOST_PKT0 ... INV_ICM42607_REG_APEX_DATA3: + case INV_ICM42607_REG_INT_STATUS_DRDY: + case INV_ICM42607_REG_INT_STATUS ... INV_ICM42607_REG_FIFO_DATA: + return true; + } + + return false; +} + +const struct regmap_config inv_icm42607_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .writeable_reg = inv_icm42607_is_writeable_reg, + .readable_reg = inv_icm42607_is_readable_reg, + .volatile_reg = inv_icm42607_is_volatile_reg, + .max_register = INV_ICM42607_REG_WHOAMI, + .cache_type = REGCACHE_MAPLE, +}; +EXPORT_SYMBOL_NS_GPL(inv_icm42607_regmap_config, "IIO_ICM42607"); + +/* chip initial default configuration */ +static const struct inv_icm42607_conf inv_icm42607_default_conf = { + .gyro = { + .mode = INV_ICM42607_SENSOR_MODE_OFF, + .fs = INV_ICM42607_GYRO_FS_1000DPS, + .odr = INV_ICM42607_ODR_100HZ, + .filter = INV_ICM42607_FILTER_BW_25HZ, + }, + .accel = { + .mode = INV_ICM42607_SENSOR_MODE_OFF, + .fs = INV_ICM42607_ACCEL_FS_4G, + .odr = INV_ICM42607_ODR_100HZ, + .filter = INV_ICM42607_FILTER_BW_25HZ, + }, +}; + +const struct inv_icm42607_hw inv_icm42607_hw_data = { + .whoami = INV_ICM42607_WHOAMI, + .name = "icm42607", + .conf = &inv_icm42607_default_conf, +}; +EXPORT_SYMBOL_NS_GPL(inv_icm42607_hw_data, "IIO_ICM42607"); + +const struct inv_icm42607_hw inv_icm42607p_hw_data = { + .whoami = INV_ICM42607P_WHOAMI, + .name = "icm42607p", + .conf = &inv_icm42607_default_conf, +}; +EXPORT_SYMBOL_NS_GPL(inv_icm42607p_hw_data, "IIO_ICM42607"); + +const struct iio_mount_matrix * +inv_icm42607_get_mount_matrix(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + const struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev); + + return &st->orientation; +} + +static u32 inv_icm42607_odr_to_period_us(enum inv_icm42607_odr odr) +{ + static const u32 odr_periods[INV_ICM42607_ODR_NB] = { + /* Reserved values */ + 0, 0, 0, 0, 0, + /* 1600Hz */ + 625, + /* 800Hz */ + 1250, + /* 400Hz */ + 2500, + /* 200Hz */ + 5000, + /* 100 Hz */ + 10000, + /* 50Hz */ + 20000, + /* 25Hz */ + 40000, + /* 12.5Hz */ + 80000, + /* 6.25Hz */ + 160000, + /* 3.125Hz */ + 320000, + /* 1.5625Hz */ + 640000, + }; + + odr = clamp(odr, INV_ICM42607_ODR_1600HZ, INV_ICM42607_ODR_1_5625HZ_LP); + + return odr_periods[odr]; +} + +int inv_icm42607_get_pwr_mgmt0(struct inv_icm42607_state *st, + enum inv_icm42607_sensor_mode *gyro, + enum inv_icm42607_sensor_mode *accel) +{ + unsigned int val; + int ret; + + ret = regmap_read(st->map, INV_ICM42607_REG_PWR_MGMT0, &val); + if (ret) + return ret; + + *gyro = FIELD_GET(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, val); + *accel = FIELD_GET(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, val); + + return 0; +} + +static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st, + enum inv_icm42607_sensor_mode gyro, + enum inv_icm42607_sensor_mode accel) +{ + enum inv_icm42607_sensor_mode oldaccel, oldgyro; + unsigned int sleepval_us, odr_us; + unsigned int val; + s64 disable_wait; + int ret; + + ret = inv_icm42607_get_pwr_mgmt0(st, &oldgyro, &oldaccel); + if (ret) + return ret; + + if (gyro == oldgyro && accel == oldaccel) + return 0; + + /* + * Datasheet on page 14.26 says we need to ensure the gyro sensor is on + * for a minimum of 45ms. So if we transition from an on state to an + * off state make sure at least 45ms have passed before power off and + * wait if it hasn't. In case some platforms don't respond well to a + * sleep of 0, make sure the fsleep duration is > 0. + */ + if (!gyro && oldgyro) { + disable_wait = clamp(ktime_us_delta(st->conf.gyro_stop, ktime_get()), + 0, INV_ICM42607_GYRO_STOP_TIME_US); + + if (disable_wait > 0) + fsleep(disable_wait); + } + + val = FIELD_PREP(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, gyro) | + FIELD_PREP(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, accel); + ret = regmap_write(st->map, INV_ICM42607_REG_PWR_MGMT0, val); + if (ret) + return ret; + + /* + * If a state change occurs from off to on, sleep for the startup time + * of the sensor. Since more than one sensor can be transitioned from + * off to on, select the maximum time from each of the sensors changing + * from off to on. Also account for the time it takes for the first + * sample to be ready by looking up the odr value and adding it to the + * sleep time. The startup time for the temp sensor is considerably + * smaller than the startup time for the other sensors and one or more + * are required to be on for the temp sensor to function, so any start + * delay should be enough. + */ + sleepval_us = 0; + odr_us = 0; + if (accel && !oldaccel) { + sleepval_us = max(sleepval_us, INV_ICM42607_ACCEL_STARTUP_TIME_US); + odr_us = max(odr_us, inv_icm42607_odr_to_period_us(st->conf.accel.odr)); + } + + if (gyro && !oldgyro) { + sleepval_us = max(sleepval_us, INV_ICM42607_GYRO_STARTUP_TIME_US); + odr_us = max(odr_us, inv_icm42607_odr_to_period_us(st->conf.gyro.odr)); + /* Track the earliest we can turn off the gyroscope. */ + st->conf.gyro_stop = ktime_add_us(ktime_get(), + INV_ICM42607_GYRO_STOP_TIME_US); + } + + sleepval_us += odr_us; + + /* + * Only sleep if sleepval_us is greater than 0 in case some platforms + * have issues with a 0 delay. The 0 delay can happen if one or both + * sensors is shut down. + */ + if (sleepval_us > 0) + fsleep(sleepval_us); + + return 0; +} + +/* + * Sanity test between old and new config values, and note if we need + * to update register config0 or config1. + */ +static void inv_icm42607_update_config(struct inv_icm42607_sensor_conf *conf, + struct inv_icm42607_sensor_conf *oldconf, + bool *config0, bool *config1) +{ + if (conf->mode < 0) + conf->mode = oldconf->mode; + if (conf->fs < 0) + conf->fs = oldconf->fs; + if (conf->odr < 0) + conf->odr = oldconf->odr; + if (conf->filter < 0) + conf->filter = oldconf->filter; + + *config0 = (conf->fs != oldconf->fs) || (conf->odr != oldconf->odr); + + *config1 = (conf->filter != oldconf->filter); +} + +int inv_icm42607_set_sensor_conf(struct inv_icm42607_state *st, + struct inv_icm42607_sensor_conf *conf, + enum iio_chan_type chan_type) +{ + enum inv_icm42607_sensor_mode accel_mode, gyro_mode; + struct inv_icm42607_sensor_conf *oldconf; + bool config0, config1; + unsigned int val; + int ret; + + switch (chan_type) { + case IIO_ACCEL: + oldconf = &st->conf.accel; + break; + case IIO_ANGL_VEL: + oldconf = &st->conf.gyro; + break; + default: + return -EINVAL; + } + + /* + * Since we are only making one-shot calls today, we can avoid needless + * on/off cycles if we rely on the runtime power management to handle + * shutting off the sensors when not in use. The downside is if we + * enable both sensors then only read from one, we have to wait for + * runtime PM to turn it off. So just keep the mode of the sensor we + * are not actively using to whatever it's already set as. + */ + ret = inv_icm42607_get_pwr_mgmt0(st, &gyro_mode, &accel_mode); + if (ret) + return ret; + + inv_icm42607_update_config(conf, oldconf, &config0, &config1); + + if (config0) { + if (chan_type == IIO_ANGL_VEL) { + val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK, conf->fs); + val |= FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_ODR_MASK, conf->odr); + ret = regmap_write(st->map, INV_ICM42607_REG_GYRO_CONFIG0, val); + } else { + val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK, conf->fs); + val |= FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_ODR_MASK, conf->odr); + ret = regmap_write(st->map, INV_ICM42607_REG_ACCEL_CONFIG0, val); + } + if (ret) + return ret; + + oldconf->fs = conf->fs; + oldconf->odr = conf->odr; + } + + if (config1) { + if (chan_type == IIO_ANGL_VEL) { + val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, + conf->filter); + ret = regmap_update_bits(st->map, INV_ICM42607_REG_GYRO_CONFIG1, + INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, val); + } else { + val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, + conf->filter); + ret = regmap_update_bits(st->map, INV_ICM42607_REG_ACCEL_CONFIG1, + INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, val); + } + if (ret) + return ret; + + oldconf->filter = conf->filter; + } + + oldconf->mode = conf->mode; + + switch (chan_type) { + case IIO_ACCEL: + return inv_icm42607_set_pwr_mgmt0(st, gyro_mode, conf->mode); + case IIO_ANGL_VEL: + return inv_icm42607_set_pwr_mgmt0(st, conf->mode, accel_mode); + default: + return -EINVAL; + } +} + +int inv_icm42607_read_sensor(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + s16 *val) +{ + struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT; + struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev); + struct inv_icm42607_sensor_state *sensor_st = iio_priv(indio_dev); + struct device *dev = regmap_get_device(st->map); + unsigned int reg; + __be16 data; + int ret; + + if ((chan->type != IIO_ANGL_VEL) && (chan->type != IIO_ACCEL)) + return -EINVAL; + + switch (chan->channel2) { + case IIO_MOD_X: + if (chan->type == IIO_ANGL_VEL) + reg = INV_ICM42607_REG_GYRO_DATA_X1; + else + reg = INV_ICM42607_REG_ACCEL_DATA_X1; + break; + case IIO_MOD_Y: + if (chan->type == IIO_ANGL_VEL) + reg = INV_ICM42607_REG_GYRO_DATA_Y1; + else + reg = INV_ICM42607_REG_ACCEL_DATA_Y1; + break; + case IIO_MOD_Z: + if (chan->type == IIO_ANGL_VEL) + reg = INV_ICM42607_REG_GYRO_DATA_Z1; + else + reg = INV_ICM42607_REG_ACCEL_DATA_Z1; + break; + default: + return -EINVAL; + } + + PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + guard(mutex)(&st->lock); + + /* enable sensor */ + conf.mode = sensor_st->power_mode; + conf.filter = sensor_st->filter; + ret = inv_icm42607_set_sensor_conf(st, &conf, chan->type); + if (ret) + return ret; + + /* read sensor register data */ + ret = regmap_bulk_read(st->map, reg, &data, sizeof(data)); + if (ret) + return ret; + + *val = be16_to_cpu(data); + if (*val == INV_ICM42607_DATA_INVALID) + return -EINVAL; + + return 0; +} + +static int inv_icm42607_set_init_conf(struct inv_icm42607_state *st, + const struct inv_icm42607_conf *conf) +{ + unsigned int val; + int ret; + + val = FIELD_PREP(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, conf->gyro.mode); + val |= FIELD_PREP(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, conf->accel.mode); + ret = regmap_write(st->map, INV_ICM42607_REG_PWR_MGMT0, val); + if (ret) + return ret; + + val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK, conf->gyro.fs); + val |= FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_ODR_MASK, conf->gyro.odr); + ret = regmap_write(st->map, INV_ICM42607_REG_GYRO_CONFIG0, val); + if (ret) + return ret; + + val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK, conf->accel.fs); + val |= FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_ODR_MASK, conf->accel.odr); + ret = regmap_write(st->map, INV_ICM42607_REG_ACCEL_CONFIG0, val); + if (ret) + return ret; + + val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, conf->gyro.filter); + ret = regmap_update_bits(st->map, INV_ICM42607_REG_GYRO_CONFIG1, + INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, val); + if (ret) + return ret; + + val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, conf->accel.filter); + ret = regmap_update_bits(st->map, INV_ICM42607_REG_ACCEL_CONFIG1, + INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, val); + if (ret) + return ret; + + val = FIELD_PREP(INV_ICM42607_TEMP_CONFIG0_FILTER_MASK, + INV_ICM42607_TEMP_FILTER_BW_34HZ); + ret = regmap_update_bits(st->map, INV_ICM42607_REG_TEMP_CONFIG0, + INV_ICM42607_TEMP_CONFIG0_FILTER_MASK, val); + if (ret) + return ret; + + st->conf = *conf; + + return 0; +} + +static int inv_icm42607_setup(struct inv_icm42607_state *st, + inv_icm42607_bus_setup inv_icm42607_bus_setup) +{ + const struct device *dev = regmap_get_device(st->map); + unsigned int val; + int ret; + + ret = regmap_read(st->map, INV_ICM42607_REG_WHOAMI, &val); + if (ret) + return ret; + + /* Warn, but don't fail. */ + if (val != st->hw->whoami) + dev_warn(dev, "Unknown whoami %#02x expected %#02x (%s)\n", + val, st->hw->whoami, st->hw->name); + + ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET, + INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET); + if (ret) + return ret; + + fsleep(1 * USEC_PER_MSEC); + + /* + * No polling interval specified in datasheet, so use reset time as + * polling interval and 10x reset time as timeout period. + */ + ret = regmap_read_poll_timeout(st->map, INV_ICM42607_REG_INT_STATUS, + val, val & INV_ICM42607_INT_STATUS_RESET_DONE, + 1 * USEC_PER_MSEC, 10 * USEC_PER_MSEC); + if (ret) + return dev_err_probe(dev, ret, + "reset error, reset done bit not set\n"); + + /* Sync the regcache again after a reset. */ + regcache_mark_dirty(st->map); + ret = regcache_sync(st->map); + if (ret) + return ret; + + ret = inv_icm42607_bus_setup(st); + if (ret) + return ret; + + ret = regmap_set_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0, + INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN); + if (ret) + return ret; + + val = FIELD_PREP(INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK, + INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL); + ret = regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1, + INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK, + val); + if (ret) + return ret; + + return inv_icm42607_set_init_conf(st, st->hw->conf); +} + +static int inv_icm42607_enable_vddio_reg(struct inv_icm42607_state *st) +{ + int ret; + + if (st->vddio_en) + return 0; + + ret = regulator_enable(st->vddio_supply); + if (ret) + return ret; + + fsleep(INV_ICM42607_POWER_UP_TIME_US); + + st->vddio_en = true; + + return 0; +} + +static void inv_icm42607_sensors_off(void *_data) +{ + struct inv_icm42607_state *st = _data; + const struct device *dev = regmap_get_device(st->map); + int ret; + + guard(mutex)(&st->lock); + + st->conf.gyro.mode = INV_ICM42607_SENSOR_MODE_OFF; + st->conf.accel.mode = INV_ICM42607_SENSOR_MODE_OFF; + + ret = inv_icm42607_set_pwr_mgmt0(st, st->conf.gyro.mode, + st->conf.accel.mode); + if (ret) + dev_err(dev, "Unable to turn off sensors\n"); +} + +static void inv_icm42607_disable_vddio_reg(void *_data) +{ + struct inv_icm42607_state *st = _data; + + if (!st->vddio_en) + return; + + regulator_disable(st->vddio_supply); + + st->vddio_en = false; +} + +int inv_icm42607_core_probe(struct regmap *regmap, + const struct inv_icm42607_hw *hw, + inv_icm42607_bus_setup inv_icm42607_bus_setup) +{ + struct device *dev = regmap_get_device(regmap); + struct inv_icm42607_state *st; + int ret; + + st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL); + if (!st) + return -ENOMEM; + + dev_set_drvdata(dev, st); + + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; + + st->hw = hw; + st->map = regmap; + + ret = iio_read_mount_matrix(dev, &st->orientation); + if (ret) + return dev_err_probe(dev, ret, + "failed to retrieve mounting matrix\n"); + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, + "Failed to get vdd regulator\n"); + + st->vddio_supply = devm_regulator_get(dev, "vddio"); + if (IS_ERR(st->vddio_supply)) + return dev_err_probe(dev, PTR_ERR(st->vddio_supply), + "Failed to get vddio regulator\n"); + + ret = inv_icm42607_enable_vddio_reg(st); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, inv_icm42607_disable_vddio_reg, st); + if (ret) + return ret; + + /* Setup chip registers (includes WHOAMI check, reset check, bus setup) */ + ret = inv_icm42607_setup(st, inv_icm42607_bus_setup); + if (ret) + return ret; + + /* + * Ensure if sensors get turned on at some point, they're turned off + * as part of teardown. + */ + ret = devm_add_action_or_reset(dev, inv_icm42607_sensors_off, st); + if (ret) + return ret; + + ret = devm_pm_runtime_set_active_enabled(dev); + if (ret) + return ret; + + pm_runtime_set_autosuspend_delay(dev, INV_ICM42607_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(dev); + + /* Initialize IIO device for Accel */ + st->indio_accel = inv_icm42607_accel_init(st); + if (IS_ERR(st->indio_accel)) + return PTR_ERR(st->indio_accel); + + /* Initialize IIO device for Gyro */ + st->indio_gyro = inv_icm42607_gyro_init(st); + if (IS_ERR(st->indio_gyro)) + return PTR_ERR(st->indio_gyro); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(inv_icm42607_core_probe, "IIO_ICM42607"); + +static int inv_icm42607_suspend(struct device *dev) +{ + struct inv_icm42607_state *st = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_suspend(dev); + if (ret) + return ret; + + inv_icm42607_disable_vddio_reg(st); + + return 0; +} + +static int inv_icm42607_resume(struct device *dev) +{ + struct inv_icm42607_state *st = dev_get_drvdata(dev); + int ret; + + ret = inv_icm42607_enable_vddio_reg(st); + if (ret) + return ret; + + /* Sync the regcache again after regulator shutdown. */ + regcache_mark_dirty(st->map); + ret = regcache_sync(st->map); + if (ret) + return ret; + + return pm_runtime_force_resume(dev); +} + +static int inv_icm42607_runtime_suspend(struct device *dev) +{ + struct inv_icm42607_state *st = dev_get_drvdata(dev); + + /* + * Set sensors state to off. Since we only support one-shot + * today we can use runtime PM to turn sensors off when not + * in use, and then when needed the reads/writes will + * re-enable the sensors as needed. This reduces complexity, + * however the tradeoff is that an unused sensor won't be + * turned off until the entire chip is no longer in use. + */ + inv_icm42607_sensors_off(st); + return 0; +} + +EXPORT_NS_GPL_DEV_PM_OPS(inv_icm42607_pm_ops, IIO_ICM42607) = { + SYSTEM_SLEEP_PM_OPS(inv_icm42607_suspend, inv_icm42607_resume) + RUNTIME_PM_OPS(inv_icm42607_runtime_suspend, NULL, NULL) +}; + +MODULE_AUTHOR("InvenSense, Inc."); +MODULE_DESCRIPTION("InvenSense ICM-42607 device driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file mode 100644 index 000000000000..5b4683c2dd1e --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 InvenSense, Inc. + */ + +#include <linux/array_size.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/device/devres.h> +#include <linux/err.h> +#include <linux/iio/iio.h> +#include <linux/mutex.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/types.h> + +#include "inv_icm42607.h" +#include "inv_icm42607_temp.h" + +#define INV_ICM42607_GYRO_CHAN(_modifier, _index, _ext_info) \ +{ \ + .type = IIO_ANGL_VEL, \ + .modified = 1, \ + .channel2 = _modifier, \ + .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_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = _index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ + .ext_info = _ext_info, \ +} + +enum inv_icm42607_gyro_scan { + INV_ICM42607_GYRO_SCAN_X, + INV_ICM42607_GYRO_SCAN_Y, + INV_ICM42607_GYRO_SCAN_Z, + INV_ICM42607_GYRO_SCAN_TEMP, +}; + +static const struct iio_chan_spec_ext_info inv_icm42607_gyro_ext_infos[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42607_get_mount_matrix), + { } +}; + +static const struct iio_chan_spec inv_icm42607_gyro_channels[] = { + INV_ICM42607_GYRO_CHAN(IIO_MOD_X, INV_ICM42607_GYRO_SCAN_X, + inv_icm42607_gyro_ext_infos), + INV_ICM42607_GYRO_CHAN(IIO_MOD_Y, INV_ICM42607_GYRO_SCAN_Y, + inv_icm42607_gyro_ext_infos), + INV_ICM42607_GYRO_CHAN(IIO_MOD_Z, INV_ICM42607_GYRO_SCAN_Z, + inv_icm42607_gyro_ext_infos), + INV_ICM42607_TEMP_CHAN(INV_ICM42607_GYRO_SCAN_TEMP), +}; + +static const int inv_icm42607_gyro_scale_nano[][2] = { + [INV_ICM42607_GYRO_FS_2000DPS] = { 0, 1065264 }, + [INV_ICM42607_GYRO_FS_1000DPS] = { 0, 532632 }, + [INV_ICM42607_GYRO_FS_500DPS] = { 0, 266316 }, + [INV_ICM42607_GYRO_FS_250DPS] = { 0, 133158 }, +}; + +static int inv_icm42607_gyro_read_scale(struct iio_dev *indio_dev, + int *val, int *val2) +{ + struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev); + unsigned int idx; + + guard(mutex)(&st->lock); + + idx = st->conf.gyro.fs; + + *val = inv_icm42607_gyro_scale_nano[idx][0]; + *val2 = inv_icm42607_gyro_scale_nano[idx][1]; + return IIO_VAL_INT_PLUS_NANO; +} + +static int inv_icm42607_gyro_write_scale(struct iio_dev *indio_dev, + int val, int val2) +{ + struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev); + struct device *dev = regmap_get_device(st->map); + unsigned int idx; + struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT; + size_t scales_len = ARRAY_SIZE(inv_icm42607_gyro_scale_nano); + int ret; + + for (idx = 0; idx < scales_len; idx++) { + if (val == inv_icm42607_gyro_scale_nano[idx][0] && + val2 == inv_icm42607_gyro_scale_nano[idx][1]) + break; + } + if (idx == scales_len) + return -EINVAL; + + conf.fs = idx; + + PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + guard(mutex)(&st->lock); + + return inv_icm42607_set_sensor_conf(st, &conf, IIO_ANGL_VEL); +} + +/* IIO format int + micro , values 0-4 reserved. */ +static const int inv_icm42607_gyro_odr[][2] = { + [INV_ICM42607_ODR_1600HZ] = { 1600, 0 }, + [INV_ICM42607_ODR_800HZ] = { 800, 0 }, + [INV_ICM42607_ODR_400HZ] = { 400, 0 }, + [INV_ICM42607_ODR_200HZ] = { 200, 0 }, + [INV_ICM42607_ODR_100HZ] = { 100, 0 }, + [INV_ICM42607_ODR_50HZ] = { 50, 0 }, + [INV_ICM42607_ODR_25HZ] = { 25, 0 }, + [INV_ICM42607_ODR_12_5HZ] = { 12, 500000 }, +}; + +static int inv_icm42607_gyro_read_odr(struct inv_icm42607_state *st, + int *val, int *val2) +{ + unsigned int odr; + unsigned int i; + + guard(mutex)(&st->lock); + + odr = st->conf.gyro.odr; + + for (i = INV_ICM42607_ODR_1600HZ; i < ARRAY_SIZE(inv_icm42607_gyro_odr); i++) { + if (i == odr) + break; + } + if (i == ARRAY_SIZE(inv_icm42607_gyro_odr)) + return -EINVAL; + + *val = inv_icm42607_gyro_odr[i][0]; + *val2 = inv_icm42607_gyro_odr[i][1]; + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int inv_icm42607_gyro_write_odr(struct iio_dev *indio_dev, + int val, int val2) +{ + struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev); + struct device *dev = regmap_get_device(st->map); + unsigned int idx; + struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT; + int ret; + + for (idx = INV_ICM42607_ODR_1600HZ; + idx < ARRAY_SIZE(inv_icm42607_gyro_odr); idx++) { + if (val == inv_icm42607_gyro_odr[idx][0] && + val2 == inv_icm42607_gyro_odr[idx][1]) + break; + } + if (idx == ARRAY_SIZE(inv_icm42607_gyro_odr)) + return -EINVAL; + + conf.odr = idx; + + PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + guard(mutex)(&st->lock); + + return inv_icm42607_set_sensor_conf(st, &conf, IIO_ANGL_VEL); +} + +static int inv_icm42607_gyro_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev); + s16 data; + int ret; + + switch (chan->type) { + case IIO_ANGL_VEL: + break; + case IIO_TEMP: + if (mask != IIO_CHAN_INFO_SAMP_FREQ) + return inv_icm42607_temp_read_raw(indio_dev, chan, + val, val2, mask); + break; + default: + return -EINVAL; + } + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = inv_icm42607_read_sensor(indio_dev, chan, &data); + if (ret) + return ret; + *val = data; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + return inv_icm42607_gyro_read_scale(indio_dev, val, val2); + case IIO_CHAN_INFO_SAMP_FREQ: + return inv_icm42607_gyro_read_odr(st, val, val2); + default: + return -EINVAL; + } +} + +static int inv_icm42607_gyro_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: + if (chan->type != IIO_ANGL_VEL) + return -EINVAL; + *vals = (const int *)inv_icm42607_gyro_scale_nano; + *type = IIO_VAL_INT_PLUS_NANO; + *length = ARRAY_SIZE(inv_icm42607_gyro_scale_nano) * 2; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SAMP_FREQ: + *vals = (const int *)inv_icm42607_gyro_odr[INV_ICM42607_ODR_1600HZ]; + *type = IIO_VAL_INT_PLUS_MICRO; + *length = (ARRAY_SIZE(inv_icm42607_gyro_odr) - + INV_ICM42607_ODR_1600HZ) * 2; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int inv_icm42607_gyro_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + if (chan->type != IIO_ANGL_VEL) + return -EINVAL; + ret = inv_icm42607_gyro_write_scale(indio_dev, val, val2); + return ret; + case IIO_CHAN_INFO_SAMP_FREQ: + return inv_icm42607_gyro_write_odr(indio_dev, val, val2); + default: + return -EINVAL; + } +} + +static int inv_icm42607_gyro_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + if (chan->type != IIO_ANGL_VEL) + return -EINVAL; + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_SAMP_FREQ: + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static const struct iio_info inv_icm42607_gyro_info = { + .read_raw = inv_icm42607_gyro_read_raw, + .read_avail = inv_icm42607_gyro_read_avail, + .write_raw = inv_icm42607_gyro_write_raw, + .write_raw_get_fmt = inv_icm42607_gyro_write_raw_get_fmt, +}; + +struct iio_dev *inv_icm42607_gyro_init(struct inv_icm42607_state *st) +{ + struct device *dev = regmap_get_device(st->map); + const char *name; + struct inv_icm42607_sensor_state *gyro_st; + struct iio_dev *indio_dev; + int ret; + + name = devm_kasprintf(dev, GFP_KERNEL, "%s-gyro", st->hw->name); + if (!name) + return ERR_PTR(-ENOMEM); + + indio_dev = devm_iio_device_alloc(dev, sizeof(*gyro_st)); + if (!indio_dev) + return ERR_PTR(-ENOMEM); + + gyro_st = iio_priv(indio_dev); + gyro_st->power_mode = INV_ICM42607_SENSOR_MODE_LOW_NOISE; + gyro_st->filter = INV_ICM42607_FILTER_BW_73HZ; + + indio_dev->name = name; + indio_dev->info = &inv_icm42607_gyro_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = inv_icm42607_gyro_channels; + indio_dev->num_channels = ARRAY_SIZE(inv_icm42607_gyro_channels); + iio_device_set_drvdata(indio_dev, st); + + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + return ERR_PTR(ret); + + return indio_dev; +} diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c new file mode 100644 index 000000000000..e903106af84a --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 InvenSense, Inc. + */ + +#include <linux/bitfield.h> +#include <linux/dev_printk.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/regmap.h> + +#include "inv_icm42607.h" + +static int inv_icm42607_i2c_bus_setup(struct inv_icm42607_state *st) +{ + unsigned int val; + int ret; + + ret = regmap_clear_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1, + INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN | + INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN); + if (ret) + return ret; + + val = FIELD_PREP(INV_ICM42607_DRIVE_CONFIG2_I2C_MASK, + INV_ICM42607_SLEW_RATE_12_36NS); + ret = regmap_update_bits(st->map, INV_ICM42607_REG_DRIVE_CONFIG2, + INV_ICM42607_DRIVE_CONFIG2_I2C_MASK, val); + if (ret) + return ret; + + val = FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK, + INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS); + + return regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0, + INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK, + val); +} + +static int inv_icm42607_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + const struct inv_icm42607_hw *hw; + struct regmap *regmap; + + hw = i2c_get_match_data(client); + if (!hw) + return dev_err_probe(dev, -ENODEV, "Failed to get i2c data\n"); + + regmap = devm_regmap_init_i2c(client, &inv_icm42607_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Failed to register i2c regmap\n"); + + return inv_icm42607_core_probe(regmap, hw, inv_icm42607_i2c_bus_setup); +} + +static const struct i2c_device_id inv_icm42607_id[] = { + { + .name = "icm42607", + .driver_data = (kernel_ulong_t)&inv_icm42607_hw_data, + }, { + .name = "icm42607p", + .driver_data = (kernel_ulong_t)&inv_icm42607p_hw_data, + }, + { } +}; +MODULE_DEVICE_TABLE(i2c, inv_icm42607_id); + +static const struct of_device_id inv_icm42607_of_matches[] = { + { + .compatible = "invensense,icm42607", + .data = &inv_icm42607_hw_data, + }, { + .compatible = "invensense,icm42607p", + .data = &inv_icm42607p_hw_data, + }, + { } +}; +MODULE_DEVICE_TABLE(of, inv_icm42607_of_matches); + +static struct i2c_driver inv_icm42607_driver = { + .driver = { + .name = "inv-icm42607-i2c", + .of_match_table = inv_icm42607_of_matches, + .pm = pm_ptr(&inv_icm42607_pm_ops), + }, + .id_table = inv_icm42607_id, + .probe = inv_icm42607_probe, +}; +module_i2c_driver(inv_icm42607_driver); + +MODULE_AUTHOR("InvenSense, Inc."); +MODULE_DESCRIPTION("InvenSense ICM-42607 I2C driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_ICM42607"); diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c new file mode 100644 index 000000000000..cd739375f6b2 --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 InvenSense, Inc. + */ + +#include <linux/bitfield.h> +#include <linux/dev_printk.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> + +#include "inv_icm42607.h" + +static int inv_icm42607_spi_bus_setup(struct inv_icm42607_state *st) +{ + unsigned int val; + int ret; + + /* Only support 4-wire mode for now. */ + ret = regmap_set_bits(st->map, INV_ICM42607_REG_DEVICE_CONFIG, + INV_ICM42607_DEVICE_CONFIG_SPI_AP_4WIRE); + if (ret) + return ret; + + ret = regmap_clear_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1, + INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN | + INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN); + if (ret) + return ret; + + val = FIELD_PREP(INV_ICM42607_DRIVE_CONFIG3_SPI_MASK, + INV_ICM42607_SLEW_RATE_2NS); + ret = regmap_update_bits(st->map, INV_ICM42607_REG_DRIVE_CONFIG3, + INV_ICM42607_DRIVE_CONFIG3_SPI_MASK, val); + if (ret) + return ret; + + val = FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK, + INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS); + + return regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0, + INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK, + val); +} + +static int inv_icm42607_probe(struct spi_device *spi) +{ + const struct inv_icm42607_hw *hw; + struct device *dev = &spi->dev; + struct regmap *regmap; + + hw = spi_get_device_match_data(spi); + if (!hw) + return dev_err_probe(dev, -ENODATA, "Failed to get SPI data\n"); + + if (spi->mode & SPI_3WIRE) + return dev_err_probe(dev, -ENODEV, "SPI 3-wire mode not supported\n"); + + regmap = devm_regmap_init_spi(spi, &inv_icm42607_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Failed to register spi regmap\n"); + + return inv_icm42607_core_probe(regmap, hw, inv_icm42607_spi_bus_setup); +} + +static const struct spi_device_id inv_icm42607_spi_id_table[] = { + { + .name = "icm42607", + .driver_data = (kernel_ulong_t)&inv_icm42607_hw_data, + }, { + .name = "icm42607p", + .driver_data = (kernel_ulong_t)&inv_icm42607p_hw_data, + }, + { } +}; +MODULE_DEVICE_TABLE(spi, inv_icm42607_spi_id_table); + +static const struct of_device_id inv_icm42607_of_matches[] = { + { + .compatible = "invensense,icm42607", + .data = &inv_icm42607_hw_data, + }, + { + .compatible = "invensense,icm42607p", + .data = &inv_icm42607p_hw_data, + }, + { } +}; +MODULE_DEVICE_TABLE(of, inv_icm42607_of_matches); + +static struct spi_driver inv_icm42607_driver = { + .driver = { + .name = "inv-icm42607-spi", + .of_match_table = inv_icm42607_of_matches, + .pm = pm_ptr(&inv_icm42607_pm_ops), + }, + .id_table = inv_icm42607_spi_id_table, + .probe = inv_icm42607_probe, +}; +module_spi_driver(inv_icm42607_driver); + +MODULE_AUTHOR("InvenSense, Inc."); +MODULE_DESCRIPTION("InvenSense ICM-42607 SPI driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_ICM42607"); diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c new file mode 100644 index 000000000000..53f0484c0845 --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 InvenSense, Inc. + */ + +#include <linux/bitfield.h> +#include <linux/cleanup.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/iio/iio.h> +#include <linux/mutex.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/types.h> +#include <linux/unaligned.h> + +#include "inv_icm42607.h" +#include "inv_icm42607_temp.h" + +static int inv_icm42607_temp_read(struct inv_icm42607_state *st, s16 *temp) +{ + struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT; + struct device *dev = regmap_get_device(st->map); + int ret, gyro_mode, accel_mode; + unsigned int val; + u8 raw[2]; + + PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + guard(mutex)(&st->lock); + + /* + * Check if both the gyro and accel are off and if so, enable one + * of them. The temp sensor cannot be read if both the gyro and + * accel sensor are off. Prefer to enable the accel over the gyro + * as the datasheet says the gyro uses 5x more power and it has + * a minimum run time of 45ms. + */ + ret = regmap_read(st->map, INV_ICM42607_REG_PWR_MGMT0, &val); + if (ret) + return ret; + + accel_mode = FIELD_GET(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, val); + gyro_mode = FIELD_GET(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, val); + if (!gyro_mode && !accel_mode) { + /* enable accel sensor */ + conf.mode = INV_ICM42607_SENSOR_MODE_LOW_NOISE; + ret = inv_icm42607_set_sensor_conf(st, &conf, IIO_ACCEL); + if (ret) + return ret; + } + + ret = regmap_bulk_read(st->map, INV_ICM42607_REG_TEMP_DATA1, + raw, sizeof(raw)); + if (ret) + return ret; + + *temp = get_unaligned_be16(raw); + if (*temp == INV_ICM42607_DATA_INVALID) + return -EINVAL; + + return 0; +} + +int inv_icm42607_temp_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev); + s16 temp; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = inv_icm42607_temp_read(st, &temp); + if (ret) + return ret; + *val = temp; + return IIO_VAL_INT; + /* + * T°C = (temp / 128) + 25 + * Tm°C = 1000 * ((temp * 100 / 12800) + 25) + * scale: 100000 / 12800 ~= 7.8125 + * offset: 3200 + */ + case IIO_CHAN_INFO_SCALE: + *val = 7; + *val2 = 812500000; + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_OFFSET: + *val = 3200; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h new file mode 100644 index 000000000000..18499b4d0b94 --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2026 InvenSense, Inc. + */ + +#ifndef INV_ICM42607_TEMP_H_ +#define INV_ICM42607_TEMP_H_ + +#include <linux/bitops.h> + +struct iio_dev; +struct iio_chan_spec; + +#define INV_ICM42607_TEMP_CHAN(_index) \ +{ \ + .type = IIO_TEMP, \ + .info_mask_separate = \ + BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_OFFSET) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = _index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ +} + +int inv_icm42607_temp_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask); + +#endif diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600.h b/drivers/iio/imu/inv_icm45600/inv_icm45600.h index 1c796d4b2a40..95fa934a42b4 100644 --- a/drivers/iio/imu/inv_icm45600/inv_icm45600.h +++ b/drivers/iio/imu/inv_icm45600/inv_icm45600.h @@ -190,7 +190,7 @@ struct inv_icm45600_sensor_state { #define INV_ICM45600_REG_IREG_ADDR 0x7C #define INV_ICM45600_REG_IREG_DATA 0x7E -/* Direct acces registers */ +/* Direct access registers */ #define INV_ICM45600_REG_MISC2 0x007F #define INV_ICM45600_MISC2_SOFT_RESET BIT(1) diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600_buffer.c b/drivers/iio/imu/inv_icm45600/inv_icm45600_buffer.c index 2b9ea317385c..42111c543d3c 100644 --- a/drivers/iio/imu/inv_icm45600/inv_icm45600_buffer.c +++ b/drivers/iio/imu/inv_icm45600/inv_icm45600_buffer.c @@ -422,8 +422,11 @@ int inv_icm45600_buffer_fifo_read(struct inv_icm45600_state *st, if (max > 0 && fifo_nb > max) fifo_nb = max; - /* Try to read all FIFO data in internal buffer. */ - st->fifo.count = fifo_nb * packet_size; + /* + * Read all FIFO data into the internal buffer, clamping the + * device-reported count to the buffer capacity. + */ + st->fifo.count = min(fifo_nb * packet_size, INV_ICM45600_FIFO_SIZE_MAX); ret = regmap_noinc_read(st->map, INV_ICM45600_REG_FIFO_DATA, st->fifo.data, st->fifo.count); if (ret == -ENOTSUPP || ret == -EFBIG) { diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600_core.c b/drivers/iio/imu/inv_icm45600/inv_icm45600_core.c index d49053161a65..c1d7aa7e950d 100644 --- a/drivers/iio/imu/inv_icm45600/inv_icm45600_core.c +++ b/drivers/iio/imu/inv_icm45600/inv_icm45600_core.c @@ -716,7 +716,7 @@ int inv_icm45600_core_probe(struct regmap *regmap, const struct inv_icm45600_chi dev_set_drvdata(dev, st); - st->fifo.data = devm_kzalloc(dev, 8192, GFP_KERNEL); + st->fifo.data = devm_kzalloc(dev, INV_ICM45600_FIFO_SIZE_MAX, GFP_KERNEL); if (!st->fifo.data) return -ENOMEM; diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c b/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c index 5ebc18121a11..69acf9bac2db 100644 --- a/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c +++ b/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c @@ -5,7 +5,6 @@ #include <linux/err.h> #include <linux/i2c.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/regmap.h> #include "inv_icm45600.h" @@ -23,7 +22,7 @@ static int inv_icm45600_probe(struct i2c_client *client) if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) return -ENODEV; - chip_info = device_get_match_data(&client->dev); + chip_info = i2c_get_match_data(client); if (!chip_info) return -ENODEV; @@ -39,14 +38,14 @@ static int inv_icm45600_probe(struct i2c_client *client) * supported by this driver. */ static const struct i2c_device_id inv_icm45600_id[] = { - { "icm45605", (kernel_ulong_t)&inv_icm45605_chip_info }, - { "icm45606", (kernel_ulong_t)&inv_icm45606_chip_info }, - { "icm45608", (kernel_ulong_t)&inv_icm45608_chip_info }, - { "icm45634", (kernel_ulong_t)&inv_icm45634_chip_info }, - { "icm45686", (kernel_ulong_t)&inv_icm45686_chip_info }, - { "icm45687", (kernel_ulong_t)&inv_icm45687_chip_info }, - { "icm45688p", (kernel_ulong_t)&inv_icm45688p_chip_info }, - { "icm45689", (kernel_ulong_t)&inv_icm45689_chip_info }, + { .name = "icm45605", .driver_data = (kernel_ulong_t)&inv_icm45605_chip_info }, + { .name = "icm45606", .driver_data = (kernel_ulong_t)&inv_icm45606_chip_info }, + { .name = "icm45608", .driver_data = (kernel_ulong_t)&inv_icm45608_chip_info }, + { .name = "icm45634", .driver_data = (kernel_ulong_t)&inv_icm45634_chip_info }, + { .name = "icm45686", .driver_data = (kernel_ulong_t)&inv_icm45686_chip_info }, + { .name = "icm45687", .driver_data = (kernel_ulong_t)&inv_icm45687_chip_info }, + { .name = "icm45688p", .driver_data = (kernel_ulong_t)&inv_icm45688p_chip_info }, + { .name = "icm45689", .driver_data = (kernel_ulong_t)&inv_icm45689_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, inv_icm45600_id); diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600_i3c.c b/drivers/iio/imu/inv_icm45600/inv_icm45600_i3c.c index 9247eae9b3e2..8fb2e519bfc8 100644 --- a/drivers/iio/imu/inv_icm45600/inv_icm45600_i3c.c +++ b/drivers/iio/imu/inv_icm45600/inv_icm45600_i3c.c @@ -2,7 +2,6 @@ /* Copyright (C) 2025 InvenSense, Inc. */ #include <linux/err.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600_spi.c b/drivers/iio/imu/inv_icm45600/inv_icm45600_spi.c index 6288113a6d7c..087e590e04c2 100644 --- a/drivers/iio/imu/inv_icm45600/inv_icm45600_spi.c +++ b/drivers/iio/imu/inv_icm45600/inv_icm45600_spi.c @@ -5,7 +5,6 @@ #include <linux/device.h> #include <linux/err.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/regmap.h> #include <linux/spi/spi.h> @@ -49,14 +48,14 @@ static int inv_icm45600_probe(struct spi_device *spi) * supported by this driver. */ static const struct spi_device_id inv_icm45600_id[] = { - { "icm45605", (kernel_ulong_t)&inv_icm45605_chip_info }, - { "icm45606", (kernel_ulong_t)&inv_icm45606_chip_info }, - { "icm45608", (kernel_ulong_t)&inv_icm45608_chip_info }, - { "icm45634", (kernel_ulong_t)&inv_icm45634_chip_info }, - { "icm45686", (kernel_ulong_t)&inv_icm45686_chip_info }, - { "icm45687", (kernel_ulong_t)&inv_icm45687_chip_info }, - { "icm45688p", (kernel_ulong_t)&inv_icm45688p_chip_info }, - { "icm45689", (kernel_ulong_t)&inv_icm45689_chip_info }, + { .name = "icm45605", .driver_data = (kernel_ulong_t)&inv_icm45605_chip_info }, + { .name = "icm45606", .driver_data = (kernel_ulong_t)&inv_icm45606_chip_info }, + { .name = "icm45608", .driver_data = (kernel_ulong_t)&inv_icm45608_chip_info }, + { .name = "icm45634", .driver_data = (kernel_ulong_t)&inv_icm45634_chip_info }, + { .name = "icm45686", .driver_data = (kernel_ulong_t)&inv_icm45686_chip_info }, + { .name = "icm45687", .driver_data = (kernel_ulong_t)&inv_icm45687_chip_info }, + { .name = "icm45688p", .driver_data = (kernel_ulong_t)&inv_icm45688p_chip_info }, + { .name = "icm45689", .driver_data = (kernel_ulong_t)&inv_icm45689_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, inv_icm45600_id); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c index 8dc61812a8fc..9ef6ab74af8b 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c @@ -7,7 +7,6 @@ #include <linux/err.h> #include <linux/i2c.h> #include <linux/iio/iio.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/property.h> @@ -174,24 +173,24 @@ static void inv_mpu_remove(struct i2c_client *client) * supported by this driver */ static const struct i2c_device_id inv_mpu_id[] = { - {"mpu6050", INV_MPU6050}, - {"mpu6500", INV_MPU6500}, - {"mpu6515", INV_MPU6515}, - {"mpu6880", INV_MPU6880}, - {"mpu9150", INV_MPU9150}, - {"mpu9250", INV_MPU9250}, - {"mpu9255", INV_MPU9255}, - {"icm20608", INV_ICM20608}, - {"icm20608d", INV_ICM20608D}, - {"icm20609", INV_ICM20609}, - {"icm20689", INV_ICM20689}, - {"icm20600", INV_ICM20600}, - {"icm20602", INV_ICM20602}, - {"icm20690", INV_ICM20690}, - {"iam20380", INV_IAM20380}, - {"iam20680", INV_IAM20680}, - {"iam20680hp", INV_IAM20680HP}, - {"iam20680ht", INV_IAM20680HT}, + { .name = "mpu6050", .driver_data = INV_MPU6050 }, + { .name = "mpu6500", .driver_data = INV_MPU6500 }, + { .name = "mpu6515", .driver_data = INV_MPU6515 }, + { .name = "mpu6880", .driver_data = INV_MPU6880 }, + { .name = "mpu9150", .driver_data = INV_MPU9150 }, + { .name = "mpu9250", .driver_data = INV_MPU9250 }, + { .name = "mpu9255", .driver_data = INV_MPU9255 }, + { .name = "icm20608", .driver_data = INV_ICM20608 }, + { .name = "icm20608d", .driver_data = INV_ICM20608D }, + { .name = "icm20609", .driver_data = INV_ICM20609 }, + { .name = "icm20689", .driver_data = INV_ICM20689 }, + { .name = "icm20600", .driver_data = INV_ICM20600 }, + { .name = "icm20602", .driver_data = INV_ICM20602 }, + { .name = "icm20690", .driver_data = INV_ICM20690 }, + { .name = "iam20380", .driver_data = INV_IAM20380 }, + { .name = "iam20680", .driver_data = INV_IAM20680 }, + { .name = "iam20680hp", .driver_data = INV_IAM20680HP }, + { .name = "iam20680ht", .driver_data = INV_IAM20680HT }, { } }; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c index 6aee6c989485..6b858fdfd1c6 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c @@ -106,9 +106,9 @@ static int inv_magn_init(struct inv_mpu6050_state *st) return ret; /* - * Sensor sentivity + * Sensor sensitivity * 1 uT = 0.01 G and value is in micron (1e6) - * sensitvity = x uT * 0.01 * 1e6 + * sensitivity = x uT * 0.01 * 1e6 */ switch (st->chip_type) { case INV_MPU9150: @@ -125,7 +125,7 @@ static int inv_magn_init(struct inv_mpu6050_state *st) } /* - * Sensitivity adjustement and scale to Gauss + * Sensitivity adjustment and scale to Gauss * * Hadj = H * (((ASA - 128) * 0.5 / 128) + 1) * Factor simplification: diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c index 1f4c62142b60..71e90ddc19dd 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c @@ -2,7 +2,6 @@ /* * Copyright (C) 2015 Intel Corporation Inc. */ -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/property.h> #include <linux/spi/spi.h> @@ -66,23 +65,23 @@ static int inv_mpu_probe(struct spi_device *spi) * supported by this driver */ static const struct spi_device_id inv_mpu_id[] = { - {"mpu6000", INV_MPU6000}, - {"mpu6500", INV_MPU6500}, - {"mpu6515", INV_MPU6515}, - {"mpu6880", INV_MPU6880}, - {"mpu9250", INV_MPU9250}, - {"mpu9255", INV_MPU9255}, - {"icm20608", INV_ICM20608}, - {"icm20608d", INV_ICM20608D}, - {"icm20609", INV_ICM20609}, - {"icm20689", INV_ICM20689}, - {"icm20600", INV_ICM20600}, - {"icm20602", INV_ICM20602}, - {"icm20690", INV_ICM20690}, - {"iam20380", INV_IAM20380}, - {"iam20680", INV_IAM20680}, - {"iam20680hp", INV_IAM20680HP}, - {"iam20680ht", INV_IAM20680HT}, + { .name = "mpu6000", .driver_data = INV_MPU6000 }, + { .name = "mpu6500", .driver_data = INV_MPU6500 }, + { .name = "mpu6515", .driver_data = INV_MPU6515 }, + { .name = "mpu6880", .driver_data = INV_MPU6880 }, + { .name = "mpu9250", .driver_data = INV_MPU9250 }, + { .name = "mpu9255", .driver_data = INV_MPU9255 }, + { .name = "icm20608", .driver_data = INV_ICM20608 }, + { .name = "icm20608d", .driver_data = INV_ICM20608D }, + { .name = "icm20609", .driver_data = INV_ICM20609 }, + { .name = "icm20689", .driver_data = INV_ICM20689 }, + { .name = "icm20600", .driver_data = INV_ICM20600 }, + { .name = "icm20602", .driver_data = INV_ICM20602 }, + { .name = "icm20690", .driver_data = INV_ICM20690 }, + { .name = "iam20380", .driver_data = INV_IAM20380 }, + { .name = "iam20680", .driver_data = INV_IAM20680 }, + { .name = "iam20680hp", .driver_data = INV_IAM20680HP }, + { .name = "iam20680ht", .driver_data = INV_IAM20680HT }, { } }; diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index 3cd91d8a89ee..c288437d53ea 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -7,9 +7,9 @@ * IIO driver for KMX61 (7-bit I2C slave address 0x0E or 0x0F). */ +#include <linux/cleanup.h> #include <linux/i2c.h> #include <linux/interrupt.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/pm.h> #include <linux/pm_runtime.h> @@ -783,7 +783,7 @@ static int kmx61_read_raw(struct iio_dev *indio_dev, struct kmx61_data *data = kmx61_get_data(indio_dev); switch (mask) { - case IIO_CHAN_INFO_RAW: + case IIO_CHAN_INFO_RAW: { switch (chan->type) { case IIO_ACCEL: base_reg = KMX61_ACC_XOUT_L; @@ -794,28 +794,24 @@ static int kmx61_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } - mutex_lock(&data->lock); + guard(mutex)(&data->lock); ret = kmx61_set_power_state(data, true, chan->address); - if (ret) { - mutex_unlock(&data->lock); + if (ret) return ret; - } ret = kmx61_read_measurement(data, base_reg, chan->scan_index); if (ret < 0) { kmx61_set_power_state(data, false, chan->address); - mutex_unlock(&data->lock); return ret; } *val = sign_extend32(ret >> chan->scan_type.shift, chan->scan_type.realbits - 1); ret = kmx61_set_power_state(data, false, chan->address); - - mutex_unlock(&data->lock); if (ret) return ret; return IIO_VAL_INT; + } case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_ACCEL: @@ -830,45 +826,46 @@ static int kmx61_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } - case IIO_CHAN_INFO_SAMP_FREQ: + case IIO_CHAN_INFO_SAMP_FREQ: { if (chan->type != IIO_ACCEL && chan->type != IIO_MAGN) return -EINVAL; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); + ret = kmx61_get_odr(data, val, val2, chan->address); - mutex_unlock(&data->lock); if (ret) return -EINVAL; return IIO_VAL_INT_PLUS_MICRO; } - return -EINVAL; + default: + return -EINVAL; + } } static int kmx61_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { - int ret; struct kmx61_data *data = kmx61_get_data(indio_dev); switch (mask) { - case IIO_CHAN_INFO_SAMP_FREQ: + case IIO_CHAN_INFO_SAMP_FREQ: { if (chan->type != IIO_ACCEL && chan->type != IIO_MAGN) return -EINVAL; - mutex_lock(&data->lock); - ret = kmx61_set_odr(data, val, val2, chan->address); - mutex_unlock(&data->lock); - return ret; + guard(mutex)(&data->lock); + + return kmx61_set_odr(data, val, val2, chan->address); + } case IIO_CHAN_INFO_SCALE: switch (chan->type) { - case IIO_ACCEL: + case IIO_ACCEL: { if (val != 0) return -EINVAL; - mutex_lock(&data->lock); - ret = kmx61_set_scale(data, val2); - mutex_unlock(&data->lock); - return ret; + guard(mutex)(&data->lock); + + return kmx61_set_scale(data, val2); + } default: return -EINVAL; } @@ -945,29 +942,26 @@ static int kmx61_write_event_config(struct iio_dev *indio_dev, if (state && data->ev_enable_state) return 0; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); if (!state && data->motion_trig_on) { data->ev_enable_state = false; - goto err_unlock; + return ret; } ret = kmx61_set_power_state(data, state, KMX61_ACC); if (ret < 0) - goto err_unlock; + return ret; ret = kmx61_setup_any_motion_interrupt(data, state); if (ret < 0) { kmx61_set_power_state(data, false, KMX61_ACC); - goto err_unlock; + return ret; } data->ev_enable_state = state; -err_unlock: - mutex_unlock(&data->lock); - - return ret; + return 0; } static int kmx61_acc_validate_trigger(struct iio_dev *indio_dev, @@ -1020,11 +1014,11 @@ static int kmx61_data_rdy_trigger_set_state(struct iio_trigger *trig, struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); struct kmx61_data *data = kmx61_get_data(indio_dev); - mutex_lock(&data->lock); + guard(mutex)(&data->lock); if (!state && data->ev_enable_state && data->motion_trig_on) { data->motion_trig_on = false; - goto err_unlock; + return ret; } if (data->acc_dready_trig == trig || data->motion_trig == trig) @@ -1034,7 +1028,7 @@ static int kmx61_data_rdy_trigger_set_state(struct iio_trigger *trig, ret = kmx61_set_power_state(data, state, device); if (ret < 0) - goto err_unlock; + return ret; if (data->acc_dready_trig == trig || data->mag_dready_trig == trig) ret = kmx61_setup_new_data_interrupt(data, state, device); @@ -1042,7 +1036,7 @@ static int kmx61_data_rdy_trigger_set_state(struct iio_trigger *trig, ret = kmx61_setup_any_motion_interrupt(data, state); if (ret < 0) { kmx61_set_power_state(data, false, device); - goto err_unlock; + return ret; } if (data->acc_dready_trig == trig) @@ -1051,10 +1045,8 @@ static int kmx61_data_rdy_trigger_set_state(struct iio_trigger *trig, data->mag_dready_trig_on = state; else data->motion_trig_on = state; -err_unlock: - mutex_unlock(&data->lock); - return ret; + return 0; } static void kmx61_trig_reenable(struct iio_trigger *trig) @@ -1181,30 +1173,49 @@ static irqreturn_t kmx61_data_rdy_trig_poll(int irq, void *private) return IRQ_HANDLED; } -static irqreturn_t kmx61_trigger_handler(int irq, void *p) +/** + * kmx61_read_for_each_active_channel() - Read each active channel into a buffer + * + * @indio_dev: IIO Device struct to read from + * @buffer: Destination buffer to write to, the array must be of at least size 8 + * + * Return: + * 0 on success, negative errno on failure. + */ +static int kmx61_read_for_each_active_channel(struct iio_dev *indio_dev, s16 *buffer) { - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; struct kmx61_data *data = kmx61_get_data(indio_dev); - int bit, ret, i = 0; u8 base; - s16 buffer[8] = { }; + int ret, bit; + int i = 0; if (indio_dev == data->acc_indio_dev) base = KMX61_ACC_XOUT_L; else base = KMX61_MAG_XOUT_L; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); + iio_for_each_active_channel(indio_dev, bit) { ret = kmx61_read_measurement(data, base, bit); - if (ret < 0) { - mutex_unlock(&data->lock); - goto err; - } + if (ret < 0) + return ret; buffer[i++] = ret; } - mutex_unlock(&data->lock); + + return 0; +} + +static irqreturn_t kmx61_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + int ret; + s16 buffer[8] = { }; + + ret = kmx61_read_for_each_active_channel(indio_dev, buffer); + if (ret < 0) + goto err; iio_push_to_buffers(indio_dev, buffer); err: @@ -1419,22 +1430,18 @@ static void kmx61_remove(struct i2c_client *client) iio_trigger_unregister(data->motion_trig); } - mutex_lock(&data->lock); + guard(mutex)(&data->lock); + kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true); - mutex_unlock(&data->lock); } static int kmx61_suspend(struct device *dev) { - int ret; struct kmx61_data *data = i2c_get_clientdata(to_i2c_client(dev)); - mutex_lock(&data->lock); - ret = kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, - false); - mutex_unlock(&data->lock); + guard(mutex)(&data->lock); - return ret; + return kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, false); } static int kmx61_resume(struct device *dev) @@ -1453,13 +1460,10 @@ static int kmx61_resume(struct device *dev) static int kmx61_runtime_suspend(struct device *dev) { struct kmx61_data *data = i2c_get_clientdata(to_i2c_client(dev)); - int ret; - mutex_lock(&data->lock); - ret = kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true); - mutex_unlock(&data->lock); + guard(mutex)(&data->lock); - return ret; + return kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true); } static int kmx61_runtime_resume(struct device *dev) @@ -1481,7 +1485,7 @@ static const struct dev_pm_ops kmx61_pm_ops = { }; static const struct i2c_device_id kmx61_id[] = { - { "kmx611021" }, + { .name = "kmx611021" }, { } }; diff --git a/drivers/iio/imu/smi240.c b/drivers/iio/imu/smi240.c index d159ee59acdd..f419296bba88 100644 --- a/drivers/iio/imu/smi240.c +++ b/drivers/iio/imu/smi240.c @@ -593,7 +593,7 @@ static int smi240_probe(struct spi_device *spi) } static const struct spi_device_id smi240_spi_id[] = { - { "smi240" }, + { .name = "smi240" }, { } }; MODULE_DEVICE_TABLE(spi, smi240_spi_id); diff --git a/drivers/iio/imu/smi330/smi330_i2c.c b/drivers/iio/imu/smi330/smi330_i2c.c index e5f1825beb71..eb9413e22e14 100644 --- a/drivers/iio/imu/smi330/smi330_i2c.c +++ b/drivers/iio/imu/smi330/smi330_i2c.c @@ -3,7 +3,6 @@ * Copyright (c) 2025 Robert Bosch GmbH. */ #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> diff --git a/drivers/iio/imu/smi330/smi330_spi.c b/drivers/iio/imu/smi330/smi330_spi.c index a6044e02b451..78c2bfb15cce 100644 --- a/drivers/iio/imu/smi330/smi330_spi.c +++ b/drivers/iio/imu/smi330/smi330_spi.c @@ -2,7 +2,6 @@ /* * Copyright (c) 2025 Robert Bosch GmbH. */ -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regmap.h> #include <linux/spi/spi.h> diff --git a/drivers/iio/imu/st_lsm6dsx/Makefile b/drivers/iio/imu/st_lsm6dsx/Makefile index 57cbcd67d64f..19a488254de3 100644 --- a/drivers/iio/imu/st_lsm6dsx/Makefile +++ b/drivers/iio/imu/st_lsm6dsx/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o \ - st_lsm6dsx_shub.o + st_lsm6dsx_shub.o st_lsm6dsx_fusion.o obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 07b1773c87bd..767aadfe7061 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -294,6 +294,7 @@ enum st_lsm6dsx_sensor_id { ST_LSM6DSX_ID_EXT0, ST_LSM6DSX_ID_EXT1, ST_LSM6DSX_ID_EXT2, + ST_LSM6DSX_ID_FUSION, ST_LSM6DSX_ID_MAX }; @@ -301,6 +302,17 @@ enum st_lsm6dsx_ext_sensor_id { ST_LSM6DSX_ID_MAGN, }; +struct st_lsm6dsx_fusion_settings { + const struct iio_chan_spec *chan; + int chan_len; + struct st_lsm6dsx_reg odr_reg; + int odr_hz[ST_LSM6DSX_ODR_LIST_SIZE]; + int odr_len; + struct st_lsm6dsx_reg fifo_enable; + struct st_lsm6dsx_reg page_mux; + struct st_lsm6dsx_reg enable; +}; + /** * struct st_lsm6dsx_ext_dev_settings - i2c controller slave settings * @i2c_addr: I2c slave address list. @@ -388,6 +400,7 @@ struct st_lsm6dsx_settings { struct st_lsm6dsx_hw_ts_settings ts_settings; struct st_lsm6dsx_shub_settings shub_settings; struct st_lsm6dsx_event_settings event_settings; + struct st_lsm6dsx_fusion_settings fusion_settings; }; enum st_lsm6dsx_fifo_mode { @@ -510,6 +523,9 @@ int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u32 odr, u8 *val); int st_lsm6dsx_shub_probe(struct st_lsm6dsx_hw *hw, const char *name); int st_lsm6dsx_shub_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable); int st_lsm6dsx_shub_read_output(struct st_lsm6dsx_hw *hw, u8 *data, int len); +int st_lsm6dsx_fusion_probe(struct st_lsm6dsx_hw *hw, const char *name); +int st_lsm6dsx_fusion_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable); +int st_lsm6dsx_fusion_set_odr(struct st_lsm6dsx_sensor *sensor, bool enable); int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable); static inline int @@ -564,12 +580,14 @@ st_lsm6dsx_get_mount_matrix(const struct iio_dev *iio_dev, static inline int st_lsm6dsx_device_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable) { - if (sensor->id == ST_LSM6DSX_ID_EXT0 || - sensor->id == ST_LSM6DSX_ID_EXT1 || - sensor->id == ST_LSM6DSX_ID_EXT2) + switch (sensor->id) { + case ST_LSM6DSX_ID_EXT0 ... ST_LSM6DSX_ID_EXT2: return st_lsm6dsx_shub_set_enable(sensor, enable); - - return st_lsm6dsx_sensor_set_enable(sensor, enable); + case ST_LSM6DSX_ID_FUSION: + return st_lsm6dsx_fusion_set_enable(sensor, enable); + default: + return st_lsm6dsx_sensor_set_enable(sensor, enable); + } } static const diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index 55d877745575..777d479f10c0 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -88,6 +88,7 @@ enum st_lsm6dsx_fifo_tag { ST_LSM6DSX_EXT0_TAG = 0x0f, ST_LSM6DSX_EXT1_TAG = 0x10, ST_LSM6DSX_EXT2_TAG = 0x11, + ST_LSM6DSX_ROT_TAG = 0x13, }; static const @@ -225,6 +226,13 @@ static int st_lsm6dsx_set_fifo_odr(struct st_lsm6dsx_sensor *sensor, const struct st_lsm6dsx_reg *batch_reg; u8 data; + /* Only internal sensors have a FIFO ODR configuration register. */ + if (sensor->id >= ARRAY_SIZE(hw->settings->batch)) { + if (sensor->id == ST_LSM6DSX_ID_FUSION) + return st_lsm6dsx_fusion_set_odr(sensor, enable); + return 0; + } + batch_reg = &hw->settings->batch[sensor->id]; if (batch_reg->addr) { int val; @@ -361,8 +369,6 @@ static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 addr, return 0; } -#define ST_LSM6DSX_IIO_BUFF_SIZE (ALIGN(ST_LSM6DSX_SAMPLE_SIZE, \ - sizeof(s64)) + sizeof(s64)) /** * st_lsm6dsx_read_fifo() - hw FIFO read routine * @hw: Pointer to instance of struct st_lsm6dsx_hw. @@ -533,16 +539,23 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) } #define ST_LSM6DSX_INVALID_SAMPLE 0x7ffd -static int -st_lsm6dsx_push_tagged_data(struct st_lsm6dsx_hw *hw, u8 tag, - u8 *data, s64 ts) +static bool st_lsm6dsx_check_data(u8 tag, __le16 *data) +{ + if ((tag == ST_LSM6DSX_GYRO_TAG || tag == ST_LSM6DSX_ACC_TAG) && + (s16)le16_to_cpup(data) >= ST_LSM6DSX_INVALID_SAMPLE) + return false; + + return true; +} + +static int st_lsm6dsx_push_tagged_data(struct st_lsm6dsx_hw *hw, u8 tag, + __le16 *data, s64 ts) { - s16 val = le16_to_cpu(*(__le16 *)data); struct st_lsm6dsx_sensor *sensor; struct iio_dev *iio_dev; /* invalid sample during bootstrap phase */ - if (val >= ST_LSM6DSX_INVALID_SAMPLE) + if (!st_lsm6dsx_check_data(tag, data)) return -EINVAL; /* @@ -576,6 +589,9 @@ st_lsm6dsx_push_tagged_data(struct st_lsm6dsx_hw *hw, u8 tag, case ST_LSM6DSX_EXT2_TAG: iio_dev = hw->iio_devs[ST_LSM6DSX_ID_EXT2]; break; + case ST_LSM6DSX_ROT_TAG: + iio_dev = hw->iio_devs[ST_LSM6DSX_ID_FUSION]; + break; default: return -EINVAL; } @@ -605,7 +621,13 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw) * must be passed a buffer that is aligned to 8 bytes so * as to allow insertion of a naturally aligned timestamp. */ - u8 iio_buff[ST_LSM6DSX_IIO_BUFF_SIZE] __aligned(8); + struct { + union { + __le16 data[3]; + __le32 fifo_ts; + }; + aligned_s64 timestamp; + } iio_buff = { }; u8 tag; bool reset_ts = false; int i, err, read_len; @@ -644,7 +666,7 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw) for (i = 0; i < pattern_len; i += ST_LSM6DSX_TAGGED_SAMPLE_SIZE) { - memcpy(iio_buff, &hw->buff[i + ST_LSM6DSX_TAG_SIZE], + memcpy(&iio_buff, &hw->buff[i + ST_LSM6DSX_TAG_SIZE], ST_LSM6DSX_SAMPLE_SIZE); tag = hw->buff[i] >> 3; @@ -655,7 +677,7 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw) * B0 = ts[7:0], B1 = ts[15:8], B2 = ts[23:16], * B3 = ts[31:24] */ - ts = le32_to_cpu(*((__le32 *)iio_buff)); + ts = le32_to_cpu(iio_buff.fifo_ts); /* * check if hw timestamp engine is going to * reset (the sensor generates an interrupt @@ -666,7 +688,8 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw) reset_ts = true; ts *= hw->ts_gain; } else { - st_lsm6dsx_push_tagged_data(hw, tag, iio_buff, + st_lsm6dsx_push_tagged_data(hw, tag, + iio_buff.data, ts); } } @@ -858,12 +881,21 @@ int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw) int i, ret; for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { + const struct iio_dev_attr **attrs; + if (!hw->iio_devs[i]) continue; + /* + * For the accelerometer, allow setting FIFO sampling frequency + * values different from the sensor sampling frequency, which + * may be needed to keep FIFO data rate low while sampling + * acceleration data at high rates for accurate event detection. + */ + attrs = i == ST_LSM6DSX_ID_ACC ? st_lsm6dsx_buffer_attrs : NULL; ret = devm_iio_kfifo_buffer_setup_ext(hw->dev, hw->iio_devs[i], &st_lsm6dsx_buffer_ops, - st_lsm6dsx_buffer_attrs); + attrs); if (ret) return ret; } diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 450cb5b47346..360f1365f892 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -94,6 +94,26 @@ #define ST_LSM6DSX_REG_WHOAMI_ADDR 0x0f +/* Raw values from the IMU are 16-bit half-precision floating-point numbers. */ +#define ST_LSM6DSX_CHANNEL_ROT \ +{ \ + .type = IIO_ROT, \ + .modified = 1, \ + .channel2 = IIO_MOD_QUATERNION_AXIS, \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = 0, \ + .scan_type = { \ + .format = IIO_SCAN_FORMAT_FLOAT, \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_LE, \ + .repeat = 3, \ + }, \ + .ext_info = st_lsm6dsx_ext_info, \ +} + static const struct iio_event_spec st_lsm6dsx_ev_motion[] = { { .type = IIO_EV_TYPE_THRESH, @@ -153,6 +173,11 @@ static const struct iio_chan_spec st_lsm6ds0_gyro_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(3), }; +static const struct iio_chan_spec st_lsm6dsx_fusion_channels[] = { + ST_LSM6DSX_CHANNEL_ROT, + IIO_CHAN_SOFT_TIMESTAMP(1), +}; + static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { { .reset = { @@ -1492,6 +1517,33 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, }, }, + .fusion_settings = { + .chan = st_lsm6dsx_fusion_channels, + .chan_len = ARRAY_SIZE(st_lsm6dsx_fusion_channels), + .odr_reg = { + .addr = 0x5e, + .mask = GENMASK(5, 3), + }, + .odr_hz[0] = 15, + .odr_hz[1] = 30, + .odr_hz[2] = 60, + .odr_hz[3] = 120, + .odr_hz[4] = 240, + .odr_hz[5] = 480, + .odr_len = 6, + .fifo_enable = { + .addr = 0x44, + .mask = BIT(1), + }, + .page_mux = { + .addr = 0x01, + .mask = BIT(7), + }, + .enable = { + .addr = 0x04, + .mask = BIT(1), + }, + }, }, { .reset = { @@ -1660,6 +1712,26 @@ static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id, return -ENODEV; } + hw->settings = &st_lsm6dsx_sensor_settings[i]; + + if (hw->settings->shub_settings.page_mux.addr) { + /* + * If the IMU has the shub page selected on init, for example + * after a CPU watchdog reset while the page is selected, the + * regular register space is shadowed. While the regular + * register space is shadowed, the registers needed for + * initializing the IMU are not available. + * + * Unconditionally clear the shub page selection to ensure + * normal register access. + */ + err = st_lsm6dsx_set_page(hw, false); + if (err < 0) { + dev_err(hw->dev, "failed to clear shub page\n"); + return err; + } + } + err = regmap_read(hw->regmap, ST_LSM6DSX_REG_WHOAMI_ADDR, &data); if (err < 0) { dev_err(hw->dev, "failed to read whoami register\n"); @@ -1672,7 +1744,6 @@ static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id, } *name = st_lsm6dsx_sensor_settings[i].id[j].name; - hw->settings = &st_lsm6dsx_sensor_settings[i]; return 0; } @@ -2781,11 +2852,8 @@ static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw) st_lsm6dsx_handler_thread, irq_type | IRQF_ONESHOT, "lsm6dsx", hw); - if (err) { - dev_err(hw->dev, "failed to request trigger irq %d\n", - hw->irq); + if (err) return err; - } return 0; } @@ -2899,6 +2967,12 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, return err; } + if (hw->settings->fusion_settings.chan) { + err = st_lsm6dsx_fusion_probe(hw, name); + if (err) + return err; + } + if (hw->irq > 0) { err = st_lsm6dsx_irq_setup(hw); if (err < 0) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_fusion.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_fusion.c new file mode 100644 index 000000000000..5321033daebc --- /dev/null +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_fusion.c @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * STMicroelectronics st_lsm6dsx IMU sensor fusion + * + * Copyright 2026 BayLibre, SAS + */ + +#include <linux/cleanup.h> +#include <linux/errno.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/mutex.h> +#include <linux/regmap.h> +#include <linux/sprintf.h> +#include <linux/types.h> +#include <linux/units.h> + +#include "st_lsm6dsx.h" + +static int +st_lsm6dsx_fusion_get_odr_val(const struct st_lsm6dsx_fusion_settings *settings, + u32 odr_mHz, u8 *val) +{ + int odr_hz = odr_mHz / MILLI; + int i; + + for (i = 0; i < settings->odr_len; i++) { + if (settings->odr_hz[i] == odr_hz) + break; + } + if (i == settings->odr_len) + return -EINVAL; + + *val = i; + return 0; +} + +/** + * st_lsm6dsx_fusion_page_enable - Enable access to sensor fusion configuration + * registers. + * @hw: Sensor hardware instance. + * + * Return: 0 on success, negative value on error. + */ +static int st_lsm6dsx_fusion_page_enable(struct st_lsm6dsx_hw *hw) +{ + const struct st_lsm6dsx_reg *mux; + + mux = &hw->settings->fusion_settings.page_mux; + + return regmap_set_bits(hw->regmap, mux->addr, mux->mask); +} + +/** + * st_lsm6dsx_fusion_page_disable - Disable access to sensor fusion + * configuration registers. + * @hw: Sensor hardware instance. + * + * Return: 0 on success, negative value on error. + */ +static int st_lsm6dsx_fusion_page_disable(struct st_lsm6dsx_hw *hw) +{ + const struct st_lsm6dsx_reg *mux; + + mux = &hw->settings->fusion_settings.page_mux; + + return regmap_clear_bits(hw->regmap, mux->addr, mux->mask); +} + +static int st_lsm6dsx_fusion_set_odr_locked(struct st_lsm6dsx_sensor *sensor, + bool enable) +{ + const struct st_lsm6dsx_fusion_settings *settings; + struct st_lsm6dsx_hw *hw = sensor->hw; + int err; + + settings = &hw->settings->fusion_settings; + if (enable) { + const struct st_lsm6dsx_reg *reg = &settings->odr_reg; + u8 odr_val; + u8 data; + + st_lsm6dsx_fusion_get_odr_val(settings, sensor->hwfifo_odr_mHz, + &odr_val); + data = ST_LSM6DSX_SHIFT_VAL(odr_val, reg->mask); + err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, + data); + if (err) + return err; + } + + return regmap_assign_bits(hw->regmap, settings->fifo_enable.addr, + settings->fifo_enable.mask, enable); +} + +int st_lsm6dsx_fusion_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable) +{ + struct st_lsm6dsx_hw *hw = sensor->hw; + const struct st_lsm6dsx_reg *en_reg; + int err; + + guard(mutex)(&hw->page_lock); + + en_reg = &hw->settings->fusion_settings.enable; + err = st_lsm6dsx_fusion_page_enable(hw); + if (err) + return err; + + err = regmap_assign_bits(hw->regmap, en_reg->addr, en_reg->mask, enable); + if (err) { + st_lsm6dsx_fusion_page_disable(hw); + return err; + } + + if (enable) + hw->enable_mask |= BIT(ST_LSM6DSX_ID_FUSION); + else + hw->enable_mask &= ~BIT(ST_LSM6DSX_ID_FUSION); + + return st_lsm6dsx_fusion_page_disable(hw); +} + +int st_lsm6dsx_fusion_set_odr(struct st_lsm6dsx_sensor *sensor, bool enable) +{ + struct st_lsm6dsx_hw *hw = sensor->hw; + int err; + + guard(mutex)(&hw->page_lock); + + err = st_lsm6dsx_fusion_page_enable(hw); + if (err) + return err; + + err = st_lsm6dsx_fusion_set_odr_locked(sensor, enable); + if (err) { + st_lsm6dsx_fusion_page_disable(hw); + return err; + } + + return st_lsm6dsx_fusion_page_disable(hw); +} + +static int st_lsm6dsx_fusion_read_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *ch, + int *val, int *val2, long mask) +{ + struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *val = sensor->hwfifo_odr_mHz / MILLI; + *val2 = (sensor->hwfifo_odr_mHz % MILLI) * (MICRO / MILLI); + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int st_lsm6dsx_fusion_write_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); + const struct st_lsm6dsx_fusion_settings *settings; + int err; + + settings = &sensor->hw->settings->fusion_settings; + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: { + u32 odr_mHz = val * MILLI + val2 * (MILLI / MICRO); + u8 odr_val; + + /* check that the requested frequency is supported */ + err = st_lsm6dsx_fusion_get_odr_val(settings, odr_mHz, &odr_val); + if (err) + return err; + + sensor->hwfifo_odr_mHz = odr_mHz; + return 0; + } + default: + return -EINVAL; + } +} + +static int st_lsm6dsx_fusion_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, + int *length, long mask) +{ + struct st_lsm6dsx_sensor *sensor = iio_priv(indio_dev); + const struct st_lsm6dsx_fusion_settings *settings; + + settings = &sensor->hw->settings->fusion_settings; + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *vals = settings->odr_hz; + *type = IIO_VAL_INT; + *length = settings->odr_len; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static const struct iio_info st_lsm6dsx_fusion_info = { + .read_raw = st_lsm6dsx_fusion_read_raw, + .read_avail = st_lsm6dsx_fusion_read_avail, + .write_raw = st_lsm6dsx_fusion_write_raw, + .hwfifo_set_watermark = st_lsm6dsx_set_watermark, +}; + +int st_lsm6dsx_fusion_probe(struct st_lsm6dsx_hw *hw, const char *name) +{ + const struct st_lsm6dsx_fusion_settings *settings; + struct st_lsm6dsx_sensor *sensor; + struct iio_dev *iio_dev; + int ret; + + iio_dev = devm_iio_device_alloc(hw->dev, sizeof(*sensor)); + if (!iio_dev) + return -ENOMEM; + + settings = &hw->settings->fusion_settings; + sensor = iio_priv(iio_dev); + sensor->id = ST_LSM6DSX_ID_FUSION; + sensor->hw = hw; + sensor->hwfifo_odr_mHz = settings->odr_hz[0] * MILLI; + sensor->watermark = 1; + iio_dev->modes = INDIO_DIRECT_MODE; + iio_dev->info = &st_lsm6dsx_fusion_info; + iio_dev->channels = settings->chan; + iio_dev->num_channels = settings->chan_len; + ret = snprintf(sensor->name, sizeof(sensor->name), "%s_fusion", name); + if (ret >= sizeof(sensor->name)) + return -E2BIG; + iio_dev->name = sensor->name; + + /* + * Put the IIO device pointer in the iio_devs array so that the caller + * can set up a buffer and register this IIO device. + */ + hw->iio_devs[ST_LSM6DSX_ID_FUSION] = iio_dev; + + return 0; +} diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c index 7c933218036b..edec898cb11f 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c @@ -144,35 +144,36 @@ MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match); static const struct acpi_device_id st_lsm6dsx_i2c_acpi_match[] = { { "SMO8B30", ST_LSM6DS3TRC_ID, }, + { "SMOCF00", ST_LSM6DSO_ID, }, { } }; MODULE_DEVICE_TABLE(acpi, st_lsm6dsx_i2c_acpi_match); static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = { - { ST_LSM6DS3_DEV_NAME, ST_LSM6DS3_ID }, - { ST_LSM6DS3H_DEV_NAME, ST_LSM6DS3H_ID }, - { ST_LSM6DSL_DEV_NAME, ST_LSM6DSL_ID }, - { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID }, - { ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID }, - { ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID }, - { ST_ASM330LHH_DEV_NAME, ST_ASM330LHH_ID }, - { ST_LSM6DSOX_DEV_NAME, ST_LSM6DSOX_ID }, - { ST_LSM6DSR_DEV_NAME, ST_LSM6DSR_ID }, - { ST_LSM6DS3TRC_DEV_NAME, ST_LSM6DS3TRC_ID }, - { ST_ISM330DHCX_DEV_NAME, ST_ISM330DHCX_ID }, - { ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID }, - { ST_LSM6DS0_DEV_NAME, ST_LSM6DS0_ID }, - { ST_LSM6DSRX_DEV_NAME, ST_LSM6DSRX_ID }, - { ST_LSM6DST_DEV_NAME, ST_LSM6DST_ID }, - { ST_LSM6DSOP_DEV_NAME, ST_LSM6DSOP_ID }, - { ST_ASM330LHHX_DEV_NAME, ST_ASM330LHHX_ID }, - { ST_LSM6DSTX_DEV_NAME, ST_LSM6DSTX_ID }, - { ST_LSM6DSV_DEV_NAME, ST_LSM6DSV_ID }, - { ST_LSM6DSV16X_DEV_NAME, ST_LSM6DSV16X_ID }, - { ST_LSM6DSO16IS_DEV_NAME, ST_LSM6DSO16IS_ID }, - { ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID }, - { ST_ASM330LHB_DEV_NAME, ST_ASM330LHB_ID }, - { ST_ASM330LHHXG1_DEV_NAME, ST_ASM330LHHXG1_ID }, + { .name = ST_LSM6DS3_DEV_NAME, .driver_data = ST_LSM6DS3_ID }, + { .name = ST_LSM6DS3H_DEV_NAME, .driver_data = ST_LSM6DS3H_ID }, + { .name = ST_LSM6DSL_DEV_NAME, .driver_data = ST_LSM6DSL_ID }, + { .name = ST_LSM6DSM_DEV_NAME, .driver_data = ST_LSM6DSM_ID }, + { .name = ST_ISM330DLC_DEV_NAME, .driver_data = ST_ISM330DLC_ID }, + { .name = ST_LSM6DSO_DEV_NAME, .driver_data = ST_LSM6DSO_ID }, + { .name = ST_ASM330LHH_DEV_NAME, .driver_data = ST_ASM330LHH_ID }, + { .name = ST_LSM6DSOX_DEV_NAME, .driver_data = ST_LSM6DSOX_ID }, + { .name = ST_LSM6DSR_DEV_NAME, .driver_data = ST_LSM6DSR_ID }, + { .name = ST_LSM6DS3TRC_DEV_NAME, .driver_data = ST_LSM6DS3TRC_ID }, + { .name = ST_ISM330DHCX_DEV_NAME, .driver_data = ST_ISM330DHCX_ID }, + { .name = ST_LSM9DS1_DEV_NAME, .driver_data = ST_LSM9DS1_ID }, + { .name = ST_LSM6DS0_DEV_NAME, .driver_data = ST_LSM6DS0_ID }, + { .name = ST_LSM6DSRX_DEV_NAME, .driver_data = ST_LSM6DSRX_ID }, + { .name = ST_LSM6DST_DEV_NAME, .driver_data = ST_LSM6DST_ID }, + { .name = ST_LSM6DSOP_DEV_NAME, .driver_data = ST_LSM6DSOP_ID }, + { .name = ST_ASM330LHHX_DEV_NAME, .driver_data = ST_ASM330LHHX_ID }, + { .name = ST_LSM6DSTX_DEV_NAME, .driver_data = ST_LSM6DSTX_ID }, + { .name = ST_LSM6DSV_DEV_NAME, .driver_data = ST_LSM6DSV_ID }, + { .name = ST_LSM6DSV16X_DEV_NAME, .driver_data = ST_LSM6DSV16X_ID }, + { .name = ST_LSM6DSO16IS_DEV_NAME, .driver_data = ST_LSM6DSO16IS_ID }, + { .name = ST_ISM330IS_DEV_NAME, .driver_data = ST_ISM330IS_ID }, + { .name = ST_ASM330LHB_DEV_NAME, .driver_data = ST_ASM330LHB_ID }, + { .name = ST_ASM330LHHXG1_DEV_NAME, .driver_data = ST_ASM330LHHXG1_ID }, { } }; MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c index cb5c5d7e1f3d..cd59edcf6d71 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c @@ -6,7 +6,6 @@ */ #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/i3c/device.h> #include <linux/slab.h> diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c index 3389b15df0bc..ed47d5a6f11c 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c @@ -138,30 +138,30 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = { MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match); static const struct spi_device_id st_lsm6dsx_spi_id_table[] = { - { ST_LSM6DS3_DEV_NAME, ST_LSM6DS3_ID }, - { ST_LSM6DS3H_DEV_NAME, ST_LSM6DS3H_ID }, - { ST_LSM6DSL_DEV_NAME, ST_LSM6DSL_ID }, - { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID }, - { ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID }, - { ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID }, - { ST_ASM330LHH_DEV_NAME, ST_ASM330LHH_ID }, - { ST_LSM6DSOX_DEV_NAME, ST_LSM6DSOX_ID }, - { ST_LSM6DSR_DEV_NAME, ST_LSM6DSR_ID }, - { ST_LSM6DS3TRC_DEV_NAME, ST_LSM6DS3TRC_ID }, - { ST_ISM330DHCX_DEV_NAME, ST_ISM330DHCX_ID }, - { ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID }, - { ST_LSM6DS0_DEV_NAME, ST_LSM6DS0_ID }, - { ST_LSM6DSRX_DEV_NAME, ST_LSM6DSRX_ID }, - { ST_LSM6DST_DEV_NAME, ST_LSM6DST_ID }, - { ST_LSM6DSOP_DEV_NAME, ST_LSM6DSOP_ID }, - { ST_ASM330LHHX_DEV_NAME, ST_ASM330LHHX_ID }, - { ST_LSM6DSTX_DEV_NAME, ST_LSM6DSTX_ID }, - { ST_LSM6DSV_DEV_NAME, ST_LSM6DSV_ID }, - { ST_LSM6DSV16X_DEV_NAME, ST_LSM6DSV16X_ID }, - { ST_LSM6DSO16IS_DEV_NAME, ST_LSM6DSO16IS_ID }, - { ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID }, - { ST_ASM330LHB_DEV_NAME, ST_ASM330LHB_ID }, - { ST_ASM330LHHXG1_DEV_NAME, ST_ASM330LHHXG1_ID }, + { .name = ST_LSM6DS3_DEV_NAME, .driver_data = ST_LSM6DS3_ID }, + { .name = ST_LSM6DS3H_DEV_NAME, .driver_data = ST_LSM6DS3H_ID }, + { .name = ST_LSM6DSL_DEV_NAME, .driver_data = ST_LSM6DSL_ID }, + { .name = ST_LSM6DSM_DEV_NAME, .driver_data = ST_LSM6DSM_ID }, + { .name = ST_ISM330DLC_DEV_NAME, .driver_data = ST_ISM330DLC_ID }, + { .name = ST_LSM6DSO_DEV_NAME, .driver_data = ST_LSM6DSO_ID }, + { .name = ST_ASM330LHH_DEV_NAME, .driver_data = ST_ASM330LHH_ID }, + { .name = ST_LSM6DSOX_DEV_NAME, .driver_data = ST_LSM6DSOX_ID }, + { .name = ST_LSM6DSR_DEV_NAME, .driver_data = ST_LSM6DSR_ID }, + { .name = ST_LSM6DS3TRC_DEV_NAME, .driver_data = ST_LSM6DS3TRC_ID }, + { .name = ST_ISM330DHCX_DEV_NAME, .driver_data = ST_ISM330DHCX_ID }, + { .name = ST_LSM9DS1_DEV_NAME, .driver_data = ST_LSM9DS1_ID }, + { .name = ST_LSM6DS0_DEV_NAME, .driver_data = ST_LSM6DS0_ID }, + { .name = ST_LSM6DSRX_DEV_NAME, .driver_data = ST_LSM6DSRX_ID }, + { .name = ST_LSM6DST_DEV_NAME, .driver_data = ST_LSM6DST_ID }, + { .name = ST_LSM6DSOP_DEV_NAME, .driver_data = ST_LSM6DSOP_ID }, + { .name = ST_ASM330LHHX_DEV_NAME, .driver_data = ST_ASM330LHHX_ID }, + { .name = ST_LSM6DSTX_DEV_NAME, .driver_data = ST_LSM6DSTX_ID }, + { .name = ST_LSM6DSV_DEV_NAME, .driver_data = ST_LSM6DSV_ID }, + { .name = ST_LSM6DSV16X_DEV_NAME, .driver_data = ST_LSM6DSV16X_ID }, + { .name = ST_LSM6DSO16IS_DEV_NAME, .driver_data = ST_LSM6DSO16IS_ID }, + { .name = ST_ISM330IS_DEV_NAME, .driver_data = ST_ISM330IS_ID }, + { .name = ST_ASM330LHB_DEV_NAME, .driver_data = ST_ASM330LHB_ID }, + { .name = ST_ASM330LHHXG1_DEV_NAME, .driver_data = ST_ASM330LHHXG1_ID }, { } }; MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table); diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c index 4232a9d800fc..6581d14e2bcf 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c @@ -12,7 +12,6 @@ #include <linux/gfp_types.h> #include <linux/i2c.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/regmap.h> #include <linux/iio/common/st_sensors_i2c.h> @@ -33,8 +32,8 @@ static const struct of_device_id st_lsm9ds0_of_match[] = { MODULE_DEVICE_TABLE(of, st_lsm9ds0_of_match); static const struct i2c_device_id st_lsm9ds0_id_table[] = { - { LSM303D_IMU_DEV_NAME }, - { LSM9DS0_IMU_DEV_NAME }, + { .name = LSM303D_IMU_DEV_NAME }, + { .name = LSM9DS0_IMU_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, st_lsm9ds0_id_table); diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c index acea8a0757d7..e67f09e1f093 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c @@ -11,7 +11,6 @@ #include <linux/err.h> #include <linux/gfp_types.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/regmap.h> #include <linux/spi/spi.h> @@ -33,8 +32,8 @@ static const struct of_device_id st_lsm9ds0_of_match[] = { MODULE_DEVICE_TABLE(of, st_lsm9ds0_of_match); static const struct spi_device_id st_lsm9ds0_id_table[] = { - { LSM303D_IMU_DEV_NAME }, - { LSM9DS0_IMU_DEV_NAME }, + { .name = LSM303D_IMU_DEV_NAME }, + { .name = LSM9DS0_IMU_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(spi, st_lsm9ds0_id_table); diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c index 447b694d6d5f..f7a4be8ec320 100644 --- a/drivers/iio/industrialio-backend.c +++ b/drivers/iio/industrialio-backend.c @@ -56,6 +56,7 @@ struct iio_backend { void *priv; const char *name; unsigned int cached_reg_addr; + u32 caps; /* * This index is relative to the frontend. Meaning that for * frontends with multiple backends, this will be the index of this @@ -155,7 +156,7 @@ static ssize_t iio_backend_debugfs_write_reg(struct file *file, ssize_t rc; int ret; - if (count >= sizeof(buf)) + if (*ppos != 0 || count >= sizeof(buf)) return -ENOSPC; rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, userbuf, count); @@ -648,7 +649,7 @@ EXPORT_SYMBOL_NS_GPL(iio_backend_ext_info_get, "IIO_BACKEND"); * @len: Buffer length * * This helper is intended to be used by backends that extend an IIO channel - * (trough iio_backend_extend_chan_spec()) with extended info. In that case, + * (through iio_backend_extend_chan_spec()) with extended info. In that case, * backends are not supposed to give their own callbacks (as they would not have * a way to get the backend from indio_dev). This is the setter. * @@ -774,6 +775,20 @@ int iio_backend_extend_chan_spec(struct iio_backend *back, } EXPORT_SYMBOL_NS_GPL(iio_backend_extend_chan_spec, "IIO_BACKEND"); +/** + * iio_backend_has_caps - Check if backend has specific capabilities + * @back: Backend device + * @caps: Capabilities to check + * + * RETURNS: + * True if backend has all the requested capabilities, false otherwise. + */ +bool iio_backend_has_caps(struct iio_backend *back, u32 caps) +{ + return (back->caps & caps) == caps; +} +EXPORT_SYMBOL_NS_GPL(iio_backend_has_caps, "IIO_BACKEND"); + static void iio_backend_release(void *arg) { struct iio_backend *back = arg; @@ -836,7 +851,7 @@ EXPORT_SYMBOL_NS_GPL(iio_backend_filter_type_set, "IIO_BACKEND"); * @back: Backend device * @timeout_us: Timeout value in us. * - * When activated, it initates a proccess that aligns the sample's most + * When activated, it initiates a process that aligns the sample's most * significant bit (MSB) based solely on the captured data, without * considering any other external signals. * @@ -949,25 +964,15 @@ int iio_backend_data_transfer_addr(struct iio_backend *back, u32 address) } EXPORT_SYMBOL_NS_GPL(iio_backend_data_transfer_addr, "IIO_BACKEND"); -static struct iio_backend *__devm_iio_backend_fwnode_get(struct device *dev, const char *name, - struct fwnode_handle *fwnode) +static struct iio_backend *__devm_iio_backend_fwnode_get_by_index(struct device *dev, + struct fwnode_handle *fwnode, + unsigned int index) { - struct fwnode_handle *fwnode_back; struct iio_backend *back; - unsigned int index; int ret; - if (name) { - ret = device_property_match_string(dev, "io-backend-names", - name); - if (ret < 0) - return ERR_PTR(ret); - index = ret; - } else { - index = 0; - } - - fwnode_back = fwnode_find_reference(fwnode, "io-backends", index); + struct fwnode_handle *fwnode_back __free(fwnode_handle) = + fwnode_find_reference(fwnode, "io-backends", index); if (IS_ERR(fwnode_back)) return dev_err_cast_probe(dev, fwnode_back, "Cannot get Firmware reference\n"); @@ -977,27 +982,42 @@ static struct iio_backend *__devm_iio_backend_fwnode_get(struct device *dev, con if (!device_match_fwnode(back->dev, fwnode_back)) continue; - fwnode_handle_put(fwnode_back); ret = __devm_iio_backend_get(dev, back); if (ret) return ERR_PTR(ret); - if (name) - back->idx = index; + back->idx = index; return back; } - fwnode_handle_put(fwnode_back); return ERR_PTR(-EPROBE_DEFER); } +static struct iio_backend *__devm_iio_backend_fwnode_get(struct device *dev, const char *name, + struct fwnode_handle *fwnode) +{ + unsigned int index; + int ret; + + if (name) { + ret = device_property_match_string(dev, "io-backend-names", name); + if (ret < 0) + return ERR_PTR(ret); + index = ret; + } else { + index = 0; + } + + return __devm_iio_backend_fwnode_get_by_index(dev, fwnode, index); +} + /** * devm_iio_backend_get - Device managed backend device get * @dev: Consumer device for the backend * @name: Backend name * - * Get's the backend associated with @dev. + * Gets the backend associated with @dev. * * RETURNS: * A backend pointer, negative error pointer otherwise. @@ -1009,12 +1029,28 @@ struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name) EXPORT_SYMBOL_NS_GPL(devm_iio_backend_get, "IIO_BACKEND"); /** + * devm_iio_backend_get_by_index - Device managed backend device get by index + * @dev: Consumer device for the backend + * @index: Index of the backend in the io-backends property + * + * Gets the backend at @index associated with @dev. + * + * RETURNS: + * A backend pointer, negative error pointer otherwise. + */ +struct iio_backend *devm_iio_backend_get_by_index(struct device *dev, unsigned int index) +{ + return __devm_iio_backend_fwnode_get_by_index(dev, dev_fwnode(dev), index); +} +EXPORT_SYMBOL_NS_GPL(devm_iio_backend_get_by_index, "IIO_BACKEND"); + +/** * devm_iio_backend_fwnode_get - Device managed backend firmware node get * @dev: Consumer device for the backend * @name: Backend name * @fwnode: Firmware node of the backend consumer * - * Get's the backend associated with a firmware node. + * Gets the backend associated with a firmware node. * * RETURNS: * A backend pointer, negative error pointer otherwise. @@ -1114,6 +1150,7 @@ int devm_iio_backend_register(struct device *dev, back->ops = info->ops; back->name = info->name; + back->caps = info->caps; back->owner = dev->driver->owner; back->dev = dev; back->priv = priv; diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 46f36a6ed271..2c9ec93dff47 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -47,9 +47,6 @@ struct iio_dmabuf_priv { u64 context; - /* Spinlock used for locking the dma_fence */ - spinlock_t lock; - struct dma_buf_attachment *attach; struct sg_table *sgt; enum dma_data_direction dir; @@ -57,7 +54,12 @@ struct iio_dmabuf_priv { }; struct iio_dma_fence { + /* + * Must remain the first member so the default release callback can pass + * the fence directly to dma_fence_free(). + */ struct dma_fence base; + spinlock_t lock; /* protects base */ struct iio_dmabuf_priv *priv; struct work_struct work; }; @@ -750,7 +752,7 @@ static int iio_storage_bytes_for_si(struct iio_dev *indio_dev, bytes = scan_type->storagebits / 8; if (scan_type->repeat > 1) - bytes *= scan_type->repeat; + bytes *= roundup_pow_of_two(scan_type->repeat); return bytes; } @@ -764,7 +766,9 @@ static int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev) } static int iio_compute_scan_bytes(struct iio_dev *indio_dev, - const unsigned long *mask, bool timestamp) + const unsigned long *mask, bool timestamp, + unsigned int *scan_bytes, + unsigned int *timestamp_offset) { unsigned int bytes = 0; int length, i, largest = 0; @@ -786,12 +790,17 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, return length; bytes = ALIGN(bytes, length); + + if (timestamp_offset) + *timestamp_offset = bytes; + bytes += length; largest = max(largest, length); } - bytes = ALIGN(bytes, largest); - return bytes; + *scan_bytes = ALIGN(bytes, largest); + + return 0; } static void iio_buffer_activate(struct iio_dev *indio_dev, @@ -836,18 +845,23 @@ static int iio_buffer_disable(struct iio_buffer *buffer, return buffer->access->disable(buffer, indio_dev); } -static void iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev, - struct iio_buffer *buffer) +static int iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev, + struct iio_buffer *buffer) { unsigned int bytes; + int ret; if (!buffer->access->set_bytes_per_datum) - return; + return 0; - bytes = iio_compute_scan_bytes(indio_dev, buffer->scan_mask, - buffer->scan_timestamp); + ret = iio_compute_scan_bytes(indio_dev, buffer->scan_mask, + buffer->scan_timestamp, &bytes, NULL); + if (ret) + return ret; buffer->access->set_bytes_per_datum(buffer, bytes); + + return 0; } static int iio_buffer_request_update(struct iio_dev *indio_dev, @@ -855,7 +869,10 @@ static int iio_buffer_request_update(struct iio_dev *indio_dev, { int ret; - iio_buffer_update_bytes_per_datum(indio_dev, buffer); + ret = iio_buffer_update_bytes_per_datum(indio_dev, buffer); + if (ret) + return ret; + if (buffer->access->request_update) { ret = buffer->access->request_update(buffer); if (ret) { @@ -882,6 +899,7 @@ struct iio_device_config { unsigned int watermark; const unsigned long *scan_mask; unsigned int scan_bytes; + unsigned int scan_timestamp_offset; bool scan_timestamp; }; @@ -898,6 +916,7 @@ static int iio_verify_update(struct iio_dev *indio_dev, struct iio_buffer *buffer; bool scan_timestamp; unsigned int modes; + int ret; if (insert_buffer && bitmap_empty(insert_buffer->scan_mask, masklength)) { @@ -985,8 +1004,12 @@ static int iio_verify_update(struct iio_dev *indio_dev, scan_mask = compound_mask; } - config->scan_bytes = iio_compute_scan_bytes(indio_dev, - scan_mask, scan_timestamp); + ret = iio_compute_scan_bytes(indio_dev, scan_mask, scan_timestamp, + &config->scan_bytes, + &config->scan_timestamp_offset); + if (ret) + return ret; + config->scan_mask = scan_mask; config->scan_timestamp = scan_timestamp; @@ -1141,6 +1164,7 @@ static int iio_enable_buffers(struct iio_dev *indio_dev, indio_dev->active_scan_mask = config->scan_mask; ACCESS_PRIVATE(indio_dev, scan_timestamp) = config->scan_timestamp; indio_dev->scan_bytes = config->scan_bytes; + ACCESS_PRIVATE(indio_dev, scan_timestamp_offset) = config->scan_timestamp_offset; iio_dev_opaque->currentmode = config->mode; iio_update_demux(indio_dev); @@ -1597,12 +1621,16 @@ static int iio_buffer_chrdev_release(struct inode *inode, struct file *filep) wake_up(&buffer->pollq); - guard(mutex)(&buffer->dmabufs_mutex); - - /* Close all attached DMABUFs */ - list_for_each_entry_safe(priv, tmp, &buffer->dmabufs, entry) { - list_del_init(&priv->entry); - iio_buffer_dmabuf_put(priv->attach); + /* + * The mutex must be unlocked before iio_device_put(), which might drop the + * last reference and free the buffer. + */ + scoped_guard(mutex, &buffer->dmabufs_mutex) { + /* Close all attached DMABUFs */ + list_for_each_entry_safe(priv, tmp, &buffer->dmabufs, entry) { + list_del_init(&priv->entry); + iio_buffer_dmabuf_put(priv->attach); + } } kfree(ib); @@ -1680,7 +1708,6 @@ static int iio_buffer_attach_dmabuf(struct iio_dev_buffer_pair *ib, if (!priv) return -ENOMEM; - spin_lock_init(&priv->lock); priv->context = dma_fence_context_alloc(1); dmabuf = dma_buf_get(fd); @@ -1805,18 +1832,9 @@ iio_buffer_dma_fence_get_driver_name(struct dma_fence *fence) return "iio"; } -static void iio_buffer_dma_fence_release(struct dma_fence *fence) -{ - struct iio_dma_fence *iio_fence = - container_of(fence, struct iio_dma_fence, base); - - kfree(iio_fence); -} - static const struct dma_fence_ops iio_buffer_dma_fence_ops = { .get_driver_name = iio_buffer_dma_fence_get_driver_name, .get_timeline_name = iio_buffer_dma_fence_get_driver_name, - .release = iio_buffer_dma_fence_release, }; static int iio_buffer_enqueue_dmabuf(struct iio_dev_buffer_pair *ib, @@ -1870,6 +1888,8 @@ static int iio_buffer_enqueue_dmabuf(struct iio_dev_buffer_pair *ib, goto err_attachment_put; } + spin_lock_init(&fence->lock); + fence->priv = priv; seqno = atomic_add_return(1, &priv->seqno); @@ -1880,7 +1900,7 @@ static int iio_buffer_enqueue_dmabuf(struct iio_dev_buffer_pair *ib, * the dma_fence. */ dma_fence_init(&fence->base, &iio_buffer_dma_fence_ops, - &priv->lock, priv->context, seqno); + &fence->lock, priv->context, seqno); ret = iio_dma_resv_lock(dmabuf, nonblock); if (ret) @@ -1909,6 +1929,7 @@ static int iio_buffer_enqueue_dmabuf(struct iio_dev_buffer_pair *ib, dma_resv_add_fence(dmabuf->resv, &fence->base, dma_to_ram ? DMA_RESV_USAGE_WRITE : DMA_RESV_USAGE_READ); + dma_fence_put(&fence->base); dma_resv_unlock(dmabuf->resv); cookie = dma_fence_begin_signalling(); @@ -2422,7 +2443,7 @@ EXPORT_SYMBOL_GPL(iio_push_to_buffers); int iio_push_to_buffers_with_ts_unaligned(struct iio_dev *indio_dev, const void *data, size_t data_sz, - int64_t timestamp) + s64 timestamp) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 22eefd048ba9..767a7794624a 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -19,6 +19,7 @@ #include <linux/idr.h> #include <linux/kdev_t.h> #include <linux/kernel.h> +#include <linux/math64.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/poll.h> @@ -26,7 +27,6 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/wait.h> -#include <linux/wordpart.h> #include <linux/iio/buffer.h> #include <linux/iio/buffer_impl.h> @@ -98,6 +98,8 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_CHROMATICITY] = "chromaticity", [IIO_ATTENTION] = "attention", [IIO_ALTCURRENT] = "altcurrent", + [IIO_COVERAGE] = "coverage", + [IIO_VOLUMEFLOW] = "volumeflow", }; static const char * const iio_modifier_names[] = { @@ -157,6 +159,7 @@ static const char * const iio_modifier_names[] = { [IIO_MOD_ACTIVE] = "active", [IIO_MOD_REACTIVE] = "reactive", [IIO_MOD_APPARENT] = "apparent", + [IIO_MOD_QUATERNION_AXIS] = "quaternionaxis", }; /* relies on pairs of these shared then separate */ @@ -418,7 +421,7 @@ static ssize_t iio_debugfs_write_reg(struct file *file, char buf[80]; int ret; - if (count >= sizeof(buf)) + if (*ppos != 0 || count >= sizeof(buf)) return -EINVAL; ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, userbuf, @@ -654,6 +657,7 @@ static ssize_t __iio_format_value(char *buf, size_t offset, unsigned int type, int size, const int *vals) { int tmp0, tmp1; + int l = 0; s64 tmp2; bool scale_db = false; @@ -697,7 +701,6 @@ static ssize_t __iio_format_value(char *buf, size_t offset, unsigned int type, case IIO_VAL_INT_MULTIPLE: { int i; - int l = 0; for (i = 0; i < size; ++i) l += sysfs_emit_at(buf, offset + l, "%d ", vals[i]); @@ -706,8 +709,26 @@ static ssize_t __iio_format_value(char *buf, size_t offset, unsigned int type, case IIO_VAL_CHAR: return sysfs_emit_at(buf, offset, "%c", (char)vals[0]); case IIO_VAL_INT_64: - tmp2 = (s64)((((u64)vals[1]) << 32) | (u32)vals[0]); - return sysfs_emit_at(buf, offset, "%lld", tmp2); + return sysfs_emit_at(buf, offset, "%lld", + iio_val_s64_compose(vals[0], vals[1])); + case IIO_VAL_DECIMAL64_MILLI: + case IIO_VAL_DECIMAL64_MICRO: + case IIO_VAL_DECIMAL64_NANO: + case IIO_VAL_DECIMAL64_PICO: + case IIO_VAL_DECIMAL64_FEMTO: + { + int scale = type - IIO_VAL_DECIMAL64_BASE; + s64 frac; + + tmp2 = div64_s64_rem(iio_val_s64_compose(vals[0], vals[1]), + int_pow(10, scale), &frac); + if (tmp2 == 0 && frac < 0) + l += sysfs_emit_at(buf, offset, "-"); + + l += sysfs_emit_at(buf, offset + l, "%lld.%0*lld", tmp2, scale, + abs(frac)); + return l; + } default: return 0; } @@ -977,6 +998,7 @@ static ssize_t iio_write_channel_info(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret, fract_mult = 100000; + int type, dec_scale = 0; int integer, fract = 0; long long integer64; bool is_char = false; @@ -987,9 +1009,11 @@ static ssize_t iio_write_channel_info(struct device *dev, if (!indio_dev->info->write_raw) return -EINVAL; - if (indio_dev->info->write_raw_get_fmt) - switch (indio_dev->info->write_raw_get_fmt(indio_dev, - this_attr->c, this_attr->address)) { + if (indio_dev->info->write_raw_get_fmt) { + type = indio_dev->info->write_raw_get_fmt(indio_dev, + this_attr->c, + this_attr->address); + switch (type) { case IIO_VAL_INT: fract_mult = 0; break; @@ -1005,12 +1029,20 @@ static ssize_t iio_write_channel_info(struct device *dev, case IIO_VAL_CHAR: is_char = true; break; + case IIO_VAL_DECIMAL64_MILLI: + case IIO_VAL_DECIMAL64_MICRO: + case IIO_VAL_DECIMAL64_NANO: + case IIO_VAL_DECIMAL64_PICO: + case IIO_VAL_DECIMAL64_FEMTO: + dec_scale = type - IIO_VAL_DECIMAL64_BASE; + fallthrough; case IIO_VAL_INT_64: is_64bit = true; break; default: return -EINVAL; } + } if (is_char) { char ch; @@ -1019,12 +1051,14 @@ static ssize_t iio_write_channel_info(struct device *dev, return -EINVAL; integer = ch; } else if (is_64bit) { - ret = kstrtoll(buf, 0, &integer64); + if (dec_scale) + ret = kstrtodec64(buf, dec_scale, &integer64); + else + ret = kstrtoll(buf, 0, &integer64); if (ret) return ret; - fract = upper_32_bits(integer64); - integer = lower_32_bits(integer64); + iio_val_s64_decompose(integer64, &integer, &fract); } else { ret = __iio_str_to_fixpoint(buf, fract_mult, &integer, &fract, scale_db); diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index 4149efcd5539..e6730f52262a 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -207,6 +207,8 @@ static int iio_event_getfd(struct iio_dev *indio_dev) goto unlock; } + kfifo_reset_out(&ev_int->det_events); + iio_device_get(indio_dev); fd = anon_inode_getfd("iio:event", &iio_event_chrdev_fileops, @@ -214,10 +216,7 @@ static int iio_event_getfd(struct iio_dev *indio_dev) if (fd < 0) { clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags); iio_device_put(indio_dev); - } else { - kfifo_reset_out(&ev_int->det_events); } - unlock: mutex_unlock(&iio_dev_opaque->mlock); return fd; @@ -256,6 +255,7 @@ static const char * const iio_ev_info_text[] = { [IIO_EV_INFO_TAP2_MIN_DELAY] = "tap2_min_delay", [IIO_EV_INFO_RUNNING_PERIOD] = "runningperiod", [IIO_EV_INFO_RUNNING_COUNT] = "runningcount", + [IIO_EV_INFO_SCALE] = "scale", }; static enum iio_event_direction iio_ev_attr_dir(struct iio_dev_attr *attr) diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index 7f34fe7bad07..17781c12bc85 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -561,10 +561,6 @@ struct iio_trigger *viio_trigger_alloc(struct device *parent, if (!trig) return NULL; - trig->dev.parent = parent; - trig->dev.type = &iio_trig_type; - trig->dev.bus = &iio_bus_type; - device_initialize(&trig->dev); INIT_WORK(&trig->reenable_work, iio_reenable_work_fn); mutex_init(&trig->pool_lock); @@ -592,6 +588,11 @@ struct iio_trigger *viio_trigger_alloc(struct device *parent, IRQ_NOREQUEST | IRQ_NOAUTOEN, IRQ_NOPROBE); } + trig->dev.parent = parent; + trig->dev.type = &iio_trig_type; + trig->dev.bus = &iio_bus_type; + device_initialize(&trig->dev); + return trig; free_descs: @@ -634,9 +635,9 @@ void iio_trigger_free(struct iio_trigger *trig) } EXPORT_SYMBOL(iio_trigger_free); -static void devm_iio_trigger_release(struct device *dev, void *res) +static void devm_iio_trigger_release(void *trig) { - iio_trigger_free(*(struct iio_trigger **)res); + iio_trigger_free(trig); } /** @@ -658,24 +659,20 @@ struct iio_trigger *__devm_iio_trigger_alloc(struct device *parent, struct module *this_mod, const char *fmt, ...) { - struct iio_trigger **ptr, *trig; + struct iio_trigger *trig; va_list vargs; - - ptr = devres_alloc(devm_iio_trigger_release, sizeof(*ptr), - GFP_KERNEL); - if (!ptr) - return NULL; + int ret; /* use raw alloc_dr for kmalloc caller tracing */ va_start(vargs, fmt); trig = viio_trigger_alloc(parent, this_mod, fmt, vargs); va_end(vargs); - if (trig) { - *ptr = trig; - devres_add(parent, ptr); - } else { - devres_free(ptr); - } + if (!trig) + return NULL; + + ret = devm_add_action_or_reset(parent, devm_iio_trigger_release, trig); + if (ret) + return NULL; return trig; } diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 0df0ab3de270..1f22275de55c 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -281,7 +281,7 @@ struct iio_channel *fwnode_iio_channel_get_by_name(struct fwnode_handle *fwnode, return ERR_PTR(-ENODEV); } -EXPORT_SYMBOL_GPL(fwnode_iio_channel_get_by_name); +EXPORT_SYMBOL_NS_GPL(fwnode_iio_channel_get_by_name, "IIO_CONSUMER"); static struct iio_channel *fwnode_iio_channel_get_all(struct device *dev) { @@ -345,7 +345,7 @@ static struct iio_channel *iio_channel_get_sys(const char *name, return ERR_PTR(-ENODEV); struct iio_channel *channel __free(kfree) = - kzalloc(sizeof(*channel), GFP_KERNEL); + kzalloc_obj(*channel); if (!channel) { err = -ENOMEM; goto error_no_mem; @@ -386,7 +386,7 @@ struct iio_channel *iio_channel_get(struct device *dev, return iio_channel_get_sys(name, channel_name); } -EXPORT_SYMBOL_GPL(iio_channel_get); +EXPORT_SYMBOL_NS_GPL(iio_channel_get, "IIO_CONSUMER"); void iio_channel_release(struct iio_channel *channel) { @@ -395,7 +395,7 @@ void iio_channel_release(struct iio_channel *channel) iio_device_put(channel->indio_dev); kfree(channel); } -EXPORT_SYMBOL_GPL(iio_channel_release); +EXPORT_SYMBOL_NS_GPL(iio_channel_release, "IIO_CONSUMER"); static void devm_iio_channel_free(void *iio_channel) { @@ -418,7 +418,7 @@ struct iio_channel *devm_iio_channel_get(struct device *dev, return channel; } -EXPORT_SYMBOL_GPL(devm_iio_channel_get); +EXPORT_SYMBOL_NS_GPL(devm_iio_channel_get, "IIO_CONSUMER"); struct iio_channel *devm_fwnode_iio_channel_get_by_name(struct device *dev, struct fwnode_handle *fwnode, @@ -437,7 +437,7 @@ struct iio_channel *devm_fwnode_iio_channel_get_by_name(struct device *dev, return channel; } -EXPORT_SYMBOL_GPL(devm_fwnode_iio_channel_get_by_name); +EXPORT_SYMBOL_NS_GPL(devm_fwnode_iio_channel_get_by_name, "IIO_CONSUMER"); struct iio_channel *iio_channel_get_all(struct device *dev) { @@ -506,7 +506,7 @@ error_free_chans: iio_device_put(chans[i].indio_dev); return ERR_PTR(ret); } -EXPORT_SYMBOL_GPL(iio_channel_get_all); +EXPORT_SYMBOL_NS_GPL(iio_channel_get_all, "IIO_CONSUMER"); void iio_channel_release_all(struct iio_channel *channels) { @@ -518,7 +518,7 @@ void iio_channel_release_all(struct iio_channel *channels) } kfree(channels); } -EXPORT_SYMBOL_GPL(iio_channel_release_all); +EXPORT_SYMBOL_NS_GPL(iio_channel_release_all, "IIO_CONSUMER"); static void devm_iio_channel_free_all(void *iio_channels) { @@ -541,7 +541,7 @@ struct iio_channel *devm_iio_channel_get_all(struct device *dev) return channels; } -EXPORT_SYMBOL_GPL(devm_iio_channel_get_all); +EXPORT_SYMBOL_NS_GPL(devm_iio_channel_get_all, "IIO_CONSUMER"); static int iio_channel_read(struct iio_channel *chan, int *val, int *val2, enum iio_chan_info_enum info) @@ -585,7 +585,7 @@ int iio_read_channel_raw(struct iio_channel *chan, int *val) return iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW); } -EXPORT_SYMBOL_GPL(iio_read_channel_raw); +EXPORT_SYMBOL_NS_GPL(iio_read_channel_raw, "IIO_CONSUMER"); int iio_read_channel_average_raw(struct iio_channel *chan, int *val) { @@ -597,7 +597,7 @@ int iio_read_channel_average_raw(struct iio_channel *chan, int *val) return iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_AVERAGE_RAW); } -EXPORT_SYMBOL_GPL(iio_read_channel_average_raw); +EXPORT_SYMBOL_NS_GPL(iio_read_channel_average_raw, "IIO_CONSUMER"); int iio_multiply_value(int *result, s64 multiplier, unsigned int type, int val, int val2) @@ -701,7 +701,7 @@ int iio_convert_raw_to_processed(struct iio_channel *chan, int raw, return iio_convert_raw_to_processed_unlocked(chan, raw, processed, scale); } -EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed); +EXPORT_SYMBOL_NS_GPL(iio_convert_raw_to_processed, "IIO_CONSUMER"); int iio_read_channel_attribute(struct iio_channel *chan, int *val, int *val2, enum iio_chan_info_enum attribute) @@ -714,13 +714,13 @@ int iio_read_channel_attribute(struct iio_channel *chan, int *val, int *val2, return iio_channel_read(chan, val, val2, attribute); } -EXPORT_SYMBOL_GPL(iio_read_channel_attribute); +EXPORT_SYMBOL_NS_GPL(iio_read_channel_attribute, "IIO_CONSUMER"); int iio_read_channel_offset(struct iio_channel *chan, int *val, int *val2) { return iio_read_channel_attribute(chan, val, val2, IIO_CHAN_INFO_OFFSET); } -EXPORT_SYMBOL_GPL(iio_read_channel_offset); +EXPORT_SYMBOL_NS_GPL(iio_read_channel_offset, "IIO_CONSUMER"); int iio_read_channel_processed_scale(struct iio_channel *chan, int *val, unsigned int scale) @@ -738,7 +738,11 @@ int iio_read_channel_processed_scale(struct iio_channel *chan, int *val, if (ret < 0) return ret; - return iio_multiply_value(val, scale, ret, pval, pval2); + ret = iio_multiply_value(val, scale, ret, pval, pval2); + if (ret < 0) + return ret; + + return 0; } else { ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW); if (ret < 0) @@ -748,20 +752,20 @@ int iio_read_channel_processed_scale(struct iio_channel *chan, int *val, scale); } } -EXPORT_SYMBOL_GPL(iio_read_channel_processed_scale); +EXPORT_SYMBOL_NS_GPL(iio_read_channel_processed_scale, "IIO_CONSUMER"); int iio_read_channel_processed(struct iio_channel *chan, int *val) { /* This is just a special case with scale factor 1 */ return iio_read_channel_processed_scale(chan, val, 1); } -EXPORT_SYMBOL_GPL(iio_read_channel_processed); +EXPORT_SYMBOL_NS_GPL(iio_read_channel_processed, "IIO_CONSUMER"); int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2) { return iio_read_channel_attribute(chan, val, val2, IIO_CHAN_INFO_SCALE); } -EXPORT_SYMBOL_GPL(iio_read_channel_scale); +EXPORT_SYMBOL_NS_GPL(iio_read_channel_scale, "IIO_CONSUMER"); static int iio_channel_read_avail(struct iio_channel *chan, const int **vals, int *type, int *length, @@ -790,7 +794,7 @@ int iio_read_avail_channel_attribute(struct iio_channel *chan, return iio_channel_read_avail(chan, vals, type, length, attribute); } -EXPORT_SYMBOL_GPL(iio_read_avail_channel_attribute); +EXPORT_SYMBOL_NS_GPL(iio_read_avail_channel_attribute, "IIO_CONSUMER"); int iio_read_avail_channel_raw(struct iio_channel *chan, const int **vals, int *length) @@ -807,7 +811,7 @@ int iio_read_avail_channel_raw(struct iio_channel *chan, return ret; } -EXPORT_SYMBOL_GPL(iio_read_avail_channel_raw); +EXPORT_SYMBOL_NS_GPL(iio_read_avail_channel_raw, "IIO_CONSUMER"); static int iio_channel_read_max(struct iio_channel *chan, int *val, int *val2, int *type, @@ -863,7 +867,7 @@ int iio_read_max_channel_raw(struct iio_channel *chan, int *val) return iio_channel_read_max(chan, val, NULL, &type, IIO_CHAN_INFO_RAW); } -EXPORT_SYMBOL_GPL(iio_read_max_channel_raw); +EXPORT_SYMBOL_NS_GPL(iio_read_max_channel_raw, "IIO_CONSUMER"); static int iio_channel_read_min(struct iio_channel *chan, int *val, int *val2, int *type, @@ -919,7 +923,7 @@ int iio_read_min_channel_raw(struct iio_channel *chan, int *val) return iio_channel_read_min(chan, val, NULL, &type, IIO_CHAN_INFO_RAW); } -EXPORT_SYMBOL_GPL(iio_read_min_channel_raw); +EXPORT_SYMBOL_NS_GPL(iio_read_min_channel_raw, "IIO_CONSUMER"); int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type) { @@ -933,7 +937,7 @@ int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type) return 0; } -EXPORT_SYMBOL_GPL(iio_get_channel_type); +EXPORT_SYMBOL_NS_GPL(iio_get_channel_type, "IIO_CONSUMER"); static int iio_channel_write(struct iio_channel *chan, int val, int val2, enum iio_chan_info_enum info) @@ -957,13 +961,13 @@ int iio_write_channel_attribute(struct iio_channel *chan, int val, int val2, return iio_channel_write(chan, val, val2, attribute); } -EXPORT_SYMBOL_GPL(iio_write_channel_attribute); +EXPORT_SYMBOL_NS_GPL(iio_write_channel_attribute, "IIO_CONSUMER"); int iio_write_channel_raw(struct iio_channel *chan, int val) { return iio_write_channel_attribute(chan, val, 0, IIO_CHAN_INFO_RAW); } -EXPORT_SYMBOL_GPL(iio_write_channel_raw); +EXPORT_SYMBOL_NS_GPL(iio_write_channel_raw, "IIO_CONSUMER"); unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan) { @@ -978,7 +982,7 @@ unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan) return i; } -EXPORT_SYMBOL_GPL(iio_get_channel_ext_info_count); +EXPORT_SYMBOL_NS_GPL(iio_get_channel_ext_info_count, "IIO_CONSUMER"); static const struct iio_chan_spec_ext_info * iio_lookup_ext_info(const struct iio_channel *chan, const char *attr) @@ -1013,7 +1017,7 @@ ssize_t iio_read_channel_ext_info(struct iio_channel *chan, return ext_info->read(chan->indio_dev, ext_info->private, chan->channel, buf); } -EXPORT_SYMBOL_GPL(iio_read_channel_ext_info); +EXPORT_SYMBOL_NS_GPL(iio_read_channel_ext_info, "IIO_CONSUMER"); ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr, const char *buf, size_t len) @@ -1027,7 +1031,7 @@ ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr, return ext_info->write(chan->indio_dev, ext_info->private, chan->channel, buf, len); } -EXPORT_SYMBOL_GPL(iio_write_channel_ext_info); +EXPORT_SYMBOL_NS_GPL(iio_write_channel_ext_info, "IIO_CONSUMER"); ssize_t iio_read_channel_label(struct iio_channel *chan, char *buf) { @@ -1038,4 +1042,4 @@ ssize_t iio_read_channel_label(struct iio_channel *chan, char *buf) return do_iio_read_channel_label(chan->indio_dev, chan->channel, buf); } -EXPORT_SYMBOL_GPL(iio_read_channel_label); +EXPORT_SYMBOL_NS_GPL(iio_read_channel_label, "IIO_CONSUMER"); diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index ac1408d374c9..f23bbce12c72 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -45,6 +45,7 @@ config ADUX1020 config AL3000A tristate "AL3000a ambient light sensor" + select REGMAP_I2C depends on I2C help Say Y here if you want to build a driver for the Dyna Image AL3000a @@ -55,6 +56,7 @@ config AL3000A config AL3010 tristate "AL3010 ambient light sensor" + select REGMAP_I2C depends on I2C help Say Y here if you want to build a driver for the Dyna Image AL3010 @@ -65,6 +67,7 @@ config AL3010 config AL3320A tristate "AL3320A ambient light sensor" + select REGMAP_I2C depends on I2C help Say Y here if you want to build a driver for the Dyna Image AL3320A @@ -119,6 +122,20 @@ config APDS9960 To compile this driver as a module, choose M here: the module will be called apds9960 +config APDS9999 + tristate "Broadcom APDS9999 ALS, RGB and proximity sensor" + depends on I2C + help + Say Y here if you want to build support for the Broadcom APDS9999 + ALS, RGB and proximity sensor with I2C interface. + + This driver provides ambient light sensing (ALS/Lux), raw + intensity data for red, green, blue and IR channels, plus + proximity detection support. + + To compile this driver as a module, choose M here: the + module will be called apds9999. + config AS73211 tristate "AMS AS73211 XYZ color sensor and AMS AS7331 UV sensor" depends on I2C @@ -359,7 +376,7 @@ config ROHM_BU27034 select IIO_KFIFO_BUF help Enable support for the ROHM BU27034 ambient light sensor. ROHM BU27034 - is an ambient light sesnor with 3 channels and 3 photo diodes capable + is an ambient light sensor with 3 channels and 3 photo diodes capable of detecting a very wide range of illuminance. Typical application is adjusting LCD and backlight power of TVs and mobile phones. @@ -699,6 +716,17 @@ config VEML3235 To compile this driver as a module, choose M here: the module will be called veml3235. +config VEML3328 + tristate "VEML3328 RGBCIR light sensor" + select REGMAP_I2C + depends on I2C + help + Say Y here if you want to build a driver for the Vishay VEML3328 + RGB IR light sensor. + + To compile this driver as a module, choose M here: the + module will be called veml3328 + config VEML6030 tristate "VEML6030 and VEML6035 ambient light sensors" select REGMAP_I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index c0048e0d5ca8..64e354c49ed8 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_APDS9160) += apds9160.o obj-$(CONFIG_APDS9300) += apds9300.o obj-$(CONFIG_APDS9306) += apds9306.o obj-$(CONFIG_APDS9960) += apds9960.o +obj-$(CONFIG_APDS9999) += apds9999.o obj-$(CONFIG_AS73211) += as73211.o obj-$(CONFIG_BH1745) += bh1745.o obj-$(CONFIG_BH1750) += bh1750.o @@ -65,6 +66,7 @@ obj-$(CONFIG_US5182D) += us5182d.o obj-$(CONFIG_VCNL4000) += vcnl4000.o obj-$(CONFIG_VCNL4035) += vcnl4035.o obj-$(CONFIG_VEML3235) += veml3235.o +obj-$(CONFIG_VEML3328) += veml3328.o obj-$(CONFIG_VEML6030) += veml6030.o obj-$(CONFIG_VEML6040) += veml6040.o obj-$(CONFIG_VEML6046X00) += veml6046x00.o diff --git a/drivers/iio/light/acpi-als.c b/drivers/iio/light/acpi-als.c index d5d1a8b9c035..1983a7f17aa9 100644 --- a/drivers/iio/light/acpi-als.c +++ b/drivers/iio/light/acpi-als.c @@ -18,6 +18,7 @@ #include <linux/err.h> #include <linux/irq.h> #include <linux/mutex.h> +#include <linux/platform_device.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> @@ -90,9 +91,9 @@ static int acpi_als_read_value(struct acpi_als *als, char *prop, s32 *val) return 0; } -static void acpi_als_notify(struct acpi_device *device, u32 event) +static void acpi_als_notify(acpi_handle handle, u32 event, void *data) { - struct iio_dev *indio_dev = acpi_driver_data(device); + struct iio_dev *indio_dev = data; struct acpi_als *als = iio_priv(indio_dev); if (iio_buffer_enabled(indio_dev) && iio_trigger_using_own(indio_dev)) { @@ -102,7 +103,7 @@ static void acpi_als_notify(struct acpi_device *device, u32 event) break; default: /* Unhandled event */ - dev_dbg(&device->dev, + dev_dbg(&als->device->dev, "Unhandled ACPI ALS event (%08x)!\n", event); } @@ -175,20 +176,24 @@ out: return IRQ_HANDLED; } -static int acpi_als_add(struct acpi_device *device) +static int acpi_als_probe(struct platform_device *pdev) { - struct device *dev = &device->dev; + struct device *dev = &pdev->dev; + struct acpi_device *device; struct iio_dev *indio_dev; struct acpi_als *als; int ret; + device = ACPI_COMPANION(dev); + if (!device) + return -ENODEV; + indio_dev = devm_iio_device_alloc(dev, sizeof(*als)); if (!indio_dev) return -ENOMEM; als = iio_priv(indio_dev); - device->driver_data = indio_dev; als->device = device; mutex_init(&als->lock); @@ -218,7 +223,18 @@ static int acpi_als_add(struct acpi_device *device) if (ret) return ret; - return devm_iio_device_register(dev, indio_dev); + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + return ret; + + return acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, + acpi_als_notify, indio_dev); +} + +static void acpi_als_remove(struct platform_device *pdev) +{ + acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev), + ACPI_DEVICE_NOTIFY, acpi_als_notify); } static const struct acpi_device_id acpi_als_device_ids[] = { @@ -228,17 +244,15 @@ static const struct acpi_device_id acpi_als_device_ids[] = { MODULE_DEVICE_TABLE(acpi, acpi_als_device_ids); -static struct acpi_driver acpi_als_driver = { - .name = "acpi_als", - .class = ACPI_ALS_CLASS, - .ids = acpi_als_device_ids, - .ops = { - .add = acpi_als_add, - .notify = acpi_als_notify, +static struct platform_driver acpi_als_driver = { + .probe = acpi_als_probe, + .remove = acpi_als_remove, + .driver = { + .name = "acpi_als", + .acpi_match_table = acpi_als_device_ids, }, }; - -module_acpi_driver(acpi_als_driver); +module_platform_driver(acpi_als_driver); MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>"); MODULE_AUTHOR("Martin Liska <marxin.liska@gmail.com>"); diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c index edb3d9dc8bed..088b9431d10a 100644 --- a/drivers/iio/light/adjd_s311.c +++ b/drivers/iio/light/adjd_s311.c @@ -260,7 +260,7 @@ static int adjd_s311_probe(struct i2c_client *client) } static const struct i2c_device_id adjd_s311_id[] = { - { "adjd_s311" }, + { .name = "adjd_s311" }, { } }; MODULE_DEVICE_TABLE(i2c, adjd_s311_id); diff --git a/drivers/iio/light/adux1020.c b/drivers/iio/light/adux1020.c index 66ff9c5fb66a..0ea282ecc99a 100644 --- a/drivers/iio/light/adux1020.c +++ b/drivers/iio/light/adux1020.c @@ -808,17 +808,15 @@ static int adux1020_probe(struct i2c_client *client) NULL, adux1020_interrupt_handler, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, ADUX1020_DRV_NAME, indio_dev); - if (ret) { - dev_err(&client->dev, "irq request error %d\n", -ret); + if (ret) return ret; - } } return devm_iio_device_register(&client->dev, indio_dev); } static const struct i2c_device_id adux1020_id[] = { - { "adux1020" }, + { .name = "adux1020" }, { } }; MODULE_DEVICE_TABLE(i2c, adux1020_id); diff --git a/drivers/iio/light/al3000a.c b/drivers/iio/light/al3000a.c index 9871096cbab3..957ec42333ef 100644 --- a/drivers/iio/light/al3000a.c +++ b/drivers/iio/light/al3000a.c @@ -4,7 +4,6 @@ #include <linux/device.h> #include <linux/err.h> #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/pm.h> #include <linux/regmap.h> @@ -183,7 +182,7 @@ static int al3000a_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(al3000a_pm_ops, al3000a_suspend, al3000a_resume); static const struct i2c_device_id al3000a_id[] = { - { "al3000a" }, + { .name = "al3000a" }, { } }; MODULE_DEVICE_TABLE(i2c, al3000a_id); diff --git a/drivers/iio/light/al3010.c b/drivers/iio/light/al3010.c index 0932fa2b49fa..49f6d8336dbe 100644 --- a/drivers/iio/light/al3010.c +++ b/drivers/iio/light/al3010.c @@ -18,7 +18,6 @@ #include <linux/i2c.h> #include <linux/module.h> #include <linux/regmap.h> -#include <linux/mod_devicetable.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -42,7 +41,7 @@ enum al3xxxx_range { }; static const int al3010_scales[][2] = { - {0, 1187200}, {0, 296800}, {0, 74200}, {0, 18600} + { 1, 187200 }, { 0, 296800 }, { 0, 74200 }, { 0, 18600 }, }; static const struct regmap_config al3010_regmap_config = { @@ -111,7 +110,8 @@ static int al3010_read_raw(struct iio_dev *indio_dev, int *val2, long mask) { struct al3010_data *data = iio_priv(indio_dev); - int ret, gain, raw; + int ret, gain; + __le16 raw; switch (mask) { case IIO_CHAN_INFO_RAW: @@ -120,11 +120,12 @@ static int al3010_read_raw(struct iio_dev *indio_dev, * - low byte of output is stored at AL3010_REG_DATA_LOW * - high byte of output is stored at AL3010_REG_DATA_LOW + 1 */ - ret = regmap_read(data->regmap, AL3010_REG_DATA_LOW, &raw); + ret = regmap_bulk_read(data->regmap, AL3010_REG_DATA_LOW, + &raw, sizeof(raw)); if (ret) return ret; - *val = raw; + *val = le16_to_cpu(raw); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: @@ -218,7 +219,7 @@ static int al3010_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(al3010_pm_ops, al3010_suspend, al3010_resume); static const struct i2c_device_id al3010_id[] = { - {"al3010", }, + { .name = "al3010" }, { } }; MODULE_DEVICE_TABLE(i2c, al3010_id); diff --git a/drivers/iio/light/al3320a.c b/drivers/iio/light/al3320a.c index 63f5a85912fc..8bb7f7e878c2 100644 --- a/drivers/iio/light/al3320a.c +++ b/drivers/iio/light/al3320a.c @@ -16,7 +16,6 @@ #include <linux/i2c.h> #include <linux/module.h> #include <linux/regmap.h> -#include <linux/mod_devicetable.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -135,7 +134,8 @@ static int al3320a_read_raw(struct iio_dev *indio_dev, int *val2, long mask) { struct al3320a_data *data = iio_priv(indio_dev); - int ret, gain, raw; + int ret, gain; + __le16 raw; switch (mask) { case IIO_CHAN_INFO_RAW: @@ -144,11 +144,12 @@ static int al3320a_read_raw(struct iio_dev *indio_dev, * - low byte of output is stored at AL3320A_REG_DATA_LOW * - high byte of output is stored at AL3320A_REG_DATA_LOW + 1 */ - ret = regmap_read(data->regmap, AL3320A_REG_DATA_LOW, &raw); + ret = regmap_bulk_read(data->regmap, AL3320A_REG_DATA_LOW, + &raw, sizeof(raw)); if (ret) return ret; - *val = raw; + *val = le16_to_cpu(raw); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: @@ -246,7 +247,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(al3320a_pm_ops, al3320a_suspend, al3320a_resume); static const struct i2c_device_id al3320a_id[] = { - { "al3320a" }, + { .name = "al3320a" }, { } }; MODULE_DEVICE_TABLE(i2c, al3320a_id); diff --git a/drivers/iio/light/apds9160.c b/drivers/iio/light/apds9160.c index 9b8af11b7b67..d7e0924b8106 100644 --- a/drivers/iio/light/apds9160.c +++ b/drivers/iio/light/apds9160.c @@ -620,7 +620,7 @@ static int apds9160_set_ps_gain(struct apds9160_chip *data, int val) /* * The PS intelligent cancellation level register allows - * for an on-chip substraction of the ADC count caused by + * for an on-chip subtraction of the ADC count caused by * unwanted reflected light from PS ADC output. */ static int apds9160_set_ps_cancellation_level(struct apds9160_chip *data, @@ -1545,11 +1545,8 @@ static int apds9160_probe(struct i2c_client *client) apds9160_irq_handler, IRQF_ONESHOT, "apds9160_event", indio_dev); - if (ret) { - return dev_err_probe(dev, ret, - "request irq (%d) failed\n", - client->irq); - } + if (ret) + return ret; } else { indio_dev->info = &apds9160_info_no_events; indio_dev->channels = apds9160_channels_without_events; @@ -1572,7 +1569,7 @@ static const struct of_device_id apds9160_of_match[] = { MODULE_DEVICE_TABLE(of, apds9160_of_match); static const struct i2c_device_id apds9160_id[] = { - { "apds9160", 0 }, + { .name = "apds9160" }, { } }; MODULE_DEVICE_TABLE(i2c, apds9160_id); diff --git a/drivers/iio/light/apds9300.c b/drivers/iio/light/apds9300.c index 05ba21675063..f0abbc4a862a 100644 --- a/drivers/iio/light/apds9300.c +++ b/drivers/iio/light/apds9300.c @@ -432,10 +432,8 @@ static int apds9300_probe(struct i2c_client *client) NULL, apds9300_interrupt_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "apds9300_event", indio_dev); - if (ret) { - dev_err(&client->dev, "irq request error %d\n", -ret); + if (ret) goto err; - } } ret = iio_device_register(indio_dev); @@ -492,7 +490,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(apds9300_pm_ops, apds9300_suspend, apds9300_resume); static const struct i2c_device_id apds9300_id[] = { - { APDS9300_DRV_NAME }, + { .name = APDS9300_DRV_NAME }, { } }; diff --git a/drivers/iio/light/apds9306.c b/drivers/iio/light/apds9306.c index 7e68cca0edfa..f681b02e4922 100644 --- a/drivers/iio/light/apds9306.c +++ b/drivers/iio/light/apds9306.c @@ -168,7 +168,6 @@ struct apds9306_regfields { * respectively. * @regmap: Regmap structure pointer * @rf: Regmap register fields structure - * @nlux_per_count: Nano lux per ADC count for a particular model * @read_data_available: Flag set by IRQ handler for ADC data available */ struct apds9306_data { @@ -180,7 +179,6 @@ struct apds9306_data { struct regmap *regmap; struct apds9306_regfields rf; - int nlux_per_count; int read_data_available; }; @@ -471,9 +469,9 @@ static int apds9306_read_data(struct apds9306_data *data, int *val, int reg) int status = 0; u8 buff[3]; - ret = pm_runtime_resume_and_get(data->dev); - if (ret) - return ret; + PM_RUNTIME_ACQUIRE_AUTOSUSPEND(data->dev, pm); + if (PM_RUNTIME_ACQUIRE_ERR(&pm)) + return PM_RUNTIME_ACQUIRE_ERR(&pm); ret = regmap_field_read(rf->intg_time, &intg_time_idx); if (ret) @@ -537,8 +535,6 @@ static int apds9306_read_data(struct apds9306_data *data, int *val, int reg) *val = get_unaligned_le24(&buff); - pm_runtime_put_autosuspend(data->dev); - return 0; } @@ -1176,7 +1172,7 @@ static int apds9306_init_iio_gts(struct apds9306_data *data) static void apds9306_powerdown(void *ptr) { - struct apds9306_data *data = (struct apds9306_data *)ptr; + struct apds9306_data *data = ptr; struct apds9306_regfields *rf = &data->rf; int ret; @@ -1288,8 +1284,7 @@ static int apds9306_probe(struct i2c_client *client) apds9306_irq_handler, IRQF_ONESHOT, "apds9306_event", indio_dev); if (ret) - return dev_err_probe(dev, ret, - "failed to assign interrupt.\n"); + return ret; } else { indio_dev->info = &apds9306_info_no_events; indio_dev->channels = apds9306_channels_without_events; diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c index 785c5dbe2d08..afe520de60e2 100644 --- a/drivers/iio/light/apds9960.c +++ b/drivers/iio/light/apds9960.c @@ -1098,10 +1098,8 @@ static int apds9960_probe(struct i2c_client *client) IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "apds9960_event", indio_dev); - if (ret) { - dev_err(&client->dev, "request irq (%d) failed\n", client->irq); + if (ret) goto error_power_down; - } ret = iio_device_register(indio_dev); if (ret) @@ -1154,7 +1152,7 @@ static const struct dev_pm_ops apds9960_pm_ops = { }; static const struct i2c_device_id apds9960_id[] = { - { "apds9960" }, + { .name = "apds9960" }, { } }; MODULE_DEVICE_TABLE(i2c, apds9960_id); diff --git a/drivers/iio/light/apds9999.c b/drivers/iio/light/apds9999.c new file mode 100644 index 000000000000..43fa9992c9c2 --- /dev/null +++ b/drivers/iio/light/apds9999.c @@ -0,0 +1,332 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * IIO driver for Broadcom APDS9999 Lux Light Sensor + * + * Copyright (C) 2026 + * Author: Jose A. Perez de Azpillaga <azpijr@gmail.com> + * + * TODO: proximity sensor + */ + +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/cleanup.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/math64.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/unaligned.h> +#include <linux/units.h> + +#define APDS9999_REG_MAIN_CTRL 0x00 +#define APDS9999_MAIN_CTRL_LS_EN BIT(1) +#define APDS9999_REG_LS_MEAS_RATE 0x04 +#define APDS9999_LS_RES_MASK GENMASK(6, 4) +#define APDS9999_LS_RATE_MASK GENMASK(2, 0) +#define APDS9999_REG_LS_GAIN 0x05 +#define APDS9999_REG_PART_ID 0x06 +#define APDS9999_REG_MAIN_STATUS 0x07 +#define APDS9999_MAIN_STATUS_LS_DATA BIT(3) +#define APDS9999_REG_LS_DATA_IR_0 0x0A +#define APDS9999_REG_LS_DATA_GREEN_0 0x0D +#define APDS9999_REG_LS_DATA_BLUE_0 0x10 +#define APDS9999_REG_LS_DATA_RED_0 0x13 + +#define APDS9999_PART_ID 0xC2 + +#define APDS9999_GAIN_1X 0 +#define APDS9999_GAIN_3X 1 +#define APDS9999_GAIN_6X 2 +#define APDS9999_GAIN_9X 3 +#define APDS9999_GAIN_18X 4 + +static const int apds9999_gains[] = { + [APDS9999_GAIN_1X] = 1, + [APDS9999_GAIN_3X] = 3, + [APDS9999_GAIN_6X] = 6, + [APDS9999_GAIN_9X] = 9, + [APDS9999_GAIN_18X] = 18, +}; + +#define APDS9999_RES_20BIT 0 +#define APDS9999_RES_19BIT 1 +#define APDS9999_RES_18BIT 2 +#define APDS9999_RES_17BIT 3 +#define APDS9999_RES_16BIT 4 +#define APDS9999_RES_13BIT 5 + +static const int apds9999_itimes_us[] = { + [APDS9999_RES_20BIT] = 400 * USEC_PER_MSEC, + [APDS9999_RES_19BIT] = 200 * USEC_PER_MSEC, + [APDS9999_RES_18BIT] = 100 * USEC_PER_MSEC, + [APDS9999_RES_17BIT] = 50 * USEC_PER_MSEC, + [APDS9999_RES_16BIT] = 25 * USEC_PER_MSEC, + [APDS9999_RES_13BIT] = 3125, +}; + +#define APDS9999_RATE_25_MS 0 +#define APDS9999_RATE_50_MS 1 +#define APDS9999_RATE_100_MS 2 +#define APDS9999_RATE_200_MS 3 +#define APDS9999_RATE_500_MS 4 +#define APDS9999_RATE_1000_MS 5 +#define APDS9999_RATE_2000_MS 6 + +struct apds9999_data { + struct i2c_client *client; + /* lock: serializes access to device registers and cached values */ + struct mutex lock; + int als_gain_idx; + int als_res; + int als_rate; +}; + +static void apds9999_standby(void *client) +{ + i2c_smbus_write_byte_data(client, APDS9999_REG_MAIN_CTRL, 0); +} + +/* + * Apply power-on defaults: 18-bit / 100 ms resolution and rate, + * 3x gain. These match the datasheet reset values. + */ +static int apds9999_init(struct apds9999_data *data) +{ + struct device *dev = &data->client->dev; + struct i2c_client *client = data->client; + u8 regval; + int ret; + + ret = devm_add_action_or_reset(dev, apds9999_standby, client); + if (ret) + return ret; + + guard(mutex)(&data->lock); + + regval = FIELD_PREP(APDS9999_LS_RES_MASK, APDS9999_RES_18BIT) | + FIELD_PREP(APDS9999_LS_RATE_MASK, APDS9999_RATE_100_MS); + ret = i2c_smbus_write_byte_data(client, APDS9999_REG_LS_MEAS_RATE, + regval); + if (ret) + return ret; + data->als_res = APDS9999_RES_18BIT; + data->als_rate = APDS9999_RATE_100_MS; + + ret = i2c_smbus_write_byte_data(client, APDS9999_REG_LS_GAIN, + APDS9999_GAIN_3X); + if (ret) + return ret; + data->als_gain_idx = APDS9999_GAIN_3X; + + return i2c_smbus_write_byte_data(client, APDS9999_REG_MAIN_CTRL, + APDS9999_MAIN_CTRL_LS_EN); +} + +static int apds9999_read_channel(struct apds9999_data *data, u8 reg, + u32 *counts) +{ + struct i2c_client *client = data->client; + u8 buf[3]; + int ret, tries; + + guard(mutex)(&data->lock); + + /* + * Poll MAIN_STATUS for new data. Timeout: ~2 integration periods + * plus margin. Each try sleeps 20 ms. + */ + tries = max(2, (apds9999_itimes_us[data->als_res] * 2) / 20000); + + while (tries--) { + ret = i2c_smbus_read_byte_data(client, + APDS9999_REG_MAIN_STATUS); + if (ret < 0) + return ret; + if (ret & APDS9999_MAIN_STATUS_LS_DATA) + break; + fsleep(20000); + } + + if (tries < 0) + return -ETIMEDOUT; + + ret = i2c_smbus_read_i2c_block_data(client, reg, sizeof(buf), buf); + if (ret < 0) + return ret; + if (ret != sizeof(buf)) + return -EIO; + + *counts = get_unaligned_le24(buf) & GENMASK(19, 0); + return 0; +} + +static int apds9999_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct apds9999_data *data = iio_priv(indio_dev); + int gain, itime_us; + u64 scale_nano; + u32 counts; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = apds9999_read_channel(data, chan->address, &counts); + if (ret) + return ret; + *val = (int)counts; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: { + u32 remainder; + + /* + * Scale (lux per count) = 54 / (gain * integration_time_ms) + * + * The constant 54 is derived from the datasheet table: + * at gain = 3x, itime = 100 ms -> 0.180 lux/count + * -> C = 0.180 * 3 * 100 = 54 + * + * Expressed as IIO_VAL_INT_PLUS_NANO. + */ + gain = apds9999_gains[data->als_gain_idx]; + itime_us = apds9999_itimes_us[data->als_res]; + + /* scale_nano = 54 * 1e12 / (gain * itime_us) nano-lux/count */ + scale_nano = div_u64(54ULL * NSEC_PER_SEC * USEC_PER_MSEC, (u32)(gain * itime_us)); + *val = (int)div_u64_rem(scale_nano, NSEC_PER_SEC, &remainder); + *val2 = (int)remainder; + return IIO_VAL_INT_PLUS_NANO; + } + case IIO_CHAN_INFO_INT_TIME: + *val = 0; + *val2 = apds9999_itimes_us[data->als_res]; + return IIO_VAL_INT_PLUS_MICRO; + + default: + return -EINVAL; + } +} + +static const struct iio_info apds9999_info = { + .read_raw = apds9999_read_raw, +}; + +/* + * The green channel uses optical coating to approximate the human eye + * spectral response. IIO_INTENSITY channels provide raw ADC data for + * red, green, blue, and IR so userspace can compute weighted lux. + */ +static const struct iio_chan_spec apds9999_channels[] = { + { + .type = IIO_LIGHT, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), + .address = APDS9999_REG_LS_DATA_GREEN_0, + }, + { + .type = IIO_INTENSITY, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_RED, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), + .address = APDS9999_REG_LS_DATA_RED_0, + }, + { + .type = IIO_INTENSITY, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_GREEN, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), + .address = APDS9999_REG_LS_DATA_GREEN_0, + }, + { + .type = IIO_INTENSITY, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_BLUE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), + .address = APDS9999_REG_LS_DATA_BLUE_0, + }, + { + .type = IIO_INTENSITY, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_IR, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), + .address = APDS9999_REG_LS_DATA_IR_0, + }, +}; + +static int apds9999_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct apds9999_data *data; + struct iio_dev *indio_dev; + int ret, part_id; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->client = client; + + ret = devm_mutex_init(dev, &data->lock); + if (ret) + return ret; + + part_id = i2c_smbus_read_byte_data(client, APDS9999_REG_PART_ID); + if (part_id < 0) + return dev_err_probe(dev, part_id, "failed to read PART_ID\n"); + if (part_id != APDS9999_PART_ID) + dev_info(dev, "unexpected PART_ID 0x%02x (expected 0x%02x)\n", + part_id, APDS9999_PART_ID); + + ret = apds9999_init(data); + if (ret) + return dev_err_probe(dev, ret, "failed to initialize device\n"); + + indio_dev->name = "apds9999"; + indio_dev->info = &apds9999_info; + indio_dev->channels = apds9999_channels; + indio_dev->num_channels = ARRAY_SIZE(apds9999_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + return dev_err_probe(dev, ret, "failed to register IIO device\n"); + + return 0; +} + +static const struct i2c_device_id apds9999_id[] = { + { .name = "apds9999" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, apds9999_id); + +static const struct of_device_id apds9999_of_match[] = { + { .compatible = "brcm,apds9999" }, + { } +}; +MODULE_DEVICE_TABLE(of, apds9999_of_match); + +static struct i2c_driver apds9999_driver = { + .driver = { + .name = "apds9999", + .of_match_table = apds9999_of_match, + }, + .probe = apds9999_probe, + .id_table = apds9999_id, +}; +module_i2c_driver(apds9999_driver); + +MODULE_AUTHOR("Jose A. Perez de Azpillaga <azpijr@gmail.com>"); +MODULE_DESCRIPTION("APDS-9999 Lux Light Sensor IIO Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/light/as73211.c b/drivers/iio/light/as73211.c index 32719f584c47..67f33bbe1c13 100644 --- a/drivers/iio/light/as73211.c +++ b/drivers/iio/light/as73211.c @@ -677,9 +677,6 @@ static irqreturn_t as73211_trigger_handler(int irq __always_unused, void *p) (char *)&scan.chan[0], 3 * sizeof(scan.chan[0])); if (ret < 0) goto done; - - /* Avoid pushing uninitialized data */ - scan.chan[3] = 0; } if (data_result) { @@ -878,8 +875,8 @@ static const struct of_device_id as73211_of_match[] = { MODULE_DEVICE_TABLE(of, as73211_of_match); static const struct i2c_device_id as73211_id[] = { - { "as73211", (kernel_ulong_t)&as73211_spec }, - { "as7331", (kernel_ulong_t)&as7331_spec }, + { .name = "as73211", .driver_data = (kernel_ulong_t)&as73211_spec }, + { .name = "as7331", .driver_data = (kernel_ulong_t)&as7331_spec }, { } }; MODULE_DEVICE_TABLE(i2c, as73211_id); diff --git a/drivers/iio/light/bh1745.c b/drivers/iio/light/bh1745.c index 10b00344bbed..2b8ff36071b8 100644 --- a/drivers/iio/light/bh1745.c +++ b/drivers/iio/light/bh1745.c @@ -784,8 +784,7 @@ static int bh1745_setup_triggered_buffer(struct iio_dev *indio_dev, IRQF_ONESHOT, "bh1745_interrupt", indio_dev); if (ret) - return dev_err_probe(dev, ret, - "Request for IRQ failed\n"); + return ret; } return 0; @@ -874,7 +873,7 @@ static int bh1745_probe(struct i2c_client *client) } static const struct i2c_device_id bh1745_idtable[] = { - { "bh1745" }, + { .name = "bh1745" }, { } }; MODULE_DEVICE_TABLE(i2c, bh1745_idtable); diff --git a/drivers/iio/light/bh1750.c b/drivers/iio/light/bh1750.c index 764f88826fcb..a51ac98c83c8 100644 --- a/drivers/iio/light/bh1750.c +++ b/drivers/iio/light/bh1750.c @@ -319,11 +319,11 @@ static int bh1750_suspend(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(bh1750_pm_ops, bh1750_suspend, NULL); static const struct i2c_device_id bh1750_id[] = { - { "bh1710", BH1710 }, - { "bh1715", BH1750 }, - { "bh1721", BH1721 }, - { "bh1750", BH1750 }, - { "bh1751", BH1750 }, + { .name = "bh1710", .driver_data = BH1710 }, + { .name = "bh1715", .driver_data = BH1750 }, + { .name = "bh1721", .driver_data = BH1721 }, + { .name = "bh1750", .driver_data = BH1750 }, + { .name = "bh1751", .driver_data = BH1750 }, { } }; MODULE_DEVICE_TABLE(i2c, bh1750_id); diff --git a/drivers/iio/light/bh1780.c b/drivers/iio/light/bh1780.c index a740d1f992a8..5447b990ffb7 100644 --- a/drivers/iio/light/bh1780.c +++ b/drivers/iio/light/bh1780.c @@ -13,7 +13,6 @@ #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/pm_runtime.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -255,7 +254,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(bh1780_dev_pm_ops, bh1780_runtime_suspend, bh1780_runtime_resume, NULL); static const struct i2c_device_id bh1780_id[] = { - { "bh1780" }, + { .name = "bh1780" }, { } }; diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c index bb90f738312a..b32a94028f09 100644 --- a/drivers/iio/light/cm32181.c +++ b/drivers/iio/light/cm32181.c @@ -10,7 +10,6 @@ #include <linux/i2c.h> #include <linux/mutex.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/interrupt.h> #include <linux/regulator/consumer.h> #include <linux/iio/iio.h> @@ -369,7 +368,7 @@ static int cm32181_write_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_CALIBSCALE: cm32181->calibscale = val; - return val; + return 0; case IIO_CHAN_INFO_INT_TIME: ret = cm32181_write_als_it(cm32181, val2); return ret; diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c index 3a3ad6b4c468..5f25452633f2 100644 --- a/drivers/iio/light/cm3232.c +++ b/drivers/iio/light/cm3232.c @@ -10,7 +10,6 @@ #include <linux/i2c.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/init.h> @@ -366,9 +365,10 @@ static void cm3232_remove(struct i2c_client *client) } static const struct i2c_device_id cm3232_id[] = { - { "cm3232" }, + { .name = "cm3232" }, { } }; +MODULE_DEVICE_TABLE(i2c, cm3232_id); static int cm3232_suspend(struct device *dev) { @@ -400,8 +400,6 @@ static int cm3232_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(cm3232_pm_ops, cm3232_suspend, cm3232_resume); -MODULE_DEVICE_TABLE(i2c, cm3232_id); - static const struct of_device_id cm3232_of_match[] = { {.compatible = "capella,cm3232"}, { } diff --git a/drivers/iio/light/cm3323.c b/drivers/iio/light/cm3323.c index 79ad6e2209ca..506c91f44f43 100644 --- a/drivers/iio/light/cm3323.c +++ b/drivers/iio/light/cm3323.c @@ -80,24 +80,20 @@ static int cm3323_init(struct iio_dev *indio_dev) { int ret; struct cm3323_data *data = iio_priv(indio_dev); + struct device *dev = &data->client->dev; ret = i2c_smbus_read_word_data(data->client, CM3323_CMD_CONF); - if (ret < 0) { - dev_err(&data->client->dev, "Error reading reg_conf\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Error reading reg_conf\n"); /* enable sensor and set auto force mode */ ret &= ~(CM3323_CONF_SD_BIT | CM3323_CONF_AF_BIT); - - ret = i2c_smbus_write_word_data(data->client, CM3323_CMD_CONF, ret); - if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_conf\n"); - return ret; - } - data->reg_conf = ret; + ret = i2c_smbus_write_word_data(data->client, CM3323_CMD_CONF, data->reg_conf); + if (ret < 0) + return dev_err_probe(dev, ret, "Error writing reg_conf\n"); + return 0; } @@ -237,10 +233,8 @@ static int cm3323_probe(struct i2c_client *client) indio_dev->modes = INDIO_DIRECT_MODE; ret = cm3323_init(indio_dev); - if (ret < 0) { - dev_err(&client->dev, "cm3323 chip init failed\n"); + if (ret < 0) return ret; - } ret = devm_add_action_or_reset(&client->dev, cm3323_disable, indio_dev); if (ret < 0) @@ -250,7 +244,7 @@ static int cm3323_probe(struct i2c_client *client) } static const struct i2c_device_id cm3323_id[] = { - { "cm3323" }, + { .name = "cm3323" }, { } }; MODULE_DEVICE_TABLE(i2c, cm3323_id); diff --git a/drivers/iio/light/cm3605.c b/drivers/iio/light/cm3605.c index 0c17378e27d1..34c127593947 100644 --- a/drivers/iio/light/cm3605.c +++ b/drivers/iio/light/cm3605.c @@ -10,7 +10,6 @@ */ #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/iio/events.h> @@ -233,10 +232,8 @@ static int cm3605_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(dev, irq, cm3605_prox_irq, NULL, 0, "cm3605", indio_dev); - if (ret) { - dev_err(dev, "unable to request IRQ\n"); + if (ret) goto out_disable_aset; - } /* Just name the trigger the same as the driver */ led_trigger_register_simple("cm3605", &cm3605->led); @@ -325,3 +322,4 @@ module_platform_driver(cm3605_driver); MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); MODULE_DESCRIPTION("CM3605 ambient light and proximity sensor driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c index 446dd54d5037..6ebd8ce4ca12 100644 --- a/drivers/iio/light/cm36651.c +++ b/drivers/iio/light/cm36651.c @@ -713,7 +713,7 @@ static void cm36651_remove(struct i2c_client *client) } static const struct i2c_device_id cm36651_id[] = { - { "cm36651" }, + { .name = "cm36651" }, { } }; diff --git a/drivers/iio/light/cros_ec_light_prox.c b/drivers/iio/light/cros_ec_light_prox.c index 815806ceb5c8..7ab565b1fb9f 100644 --- a/drivers/iio/light/cros_ec_light_prox.c +++ b/drivers/iio/light/cros_ec_light_prox.c @@ -14,7 +14,6 @@ #include <linux/iio/triggered_buffer.h> #include <linux/iio/trigger_consumer.h> #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_data/cros_ec_commands.h> #include <linux/platform_data/cros_ec_proto.h> @@ -223,14 +222,8 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev) return -EINVAL; } - /* Timestamp */ channel++; - channel->type = IIO_TIMESTAMP; - channel->channel = -1; - channel->scan_index = 1; - channel->scan_type.sign = 's'; - channel->scan_type.realbits = 64; - channel->scan_type.storagebits = 64; + *channel = IIO_CHAN_SOFT_TIMESTAMP(1); indio_dev->channels = state->channels; diff --git a/drivers/iio/light/gp2ap002.c b/drivers/iio/light/gp2ap002.c index a0d8a58f2704..1fd40d60182e 100644 --- a/drivers/iio/light/gp2ap002.c +++ b/drivers/iio/light/gp2ap002.c @@ -258,7 +258,7 @@ static int gp2ap002_read_raw(struct iio_dev *indio_dev, case IIO_LIGHT: ret = gp2ap002_get_lux(gp2ap002); if (ret < 0) - return ret; + goto out; *val = ret; ret = IIO_VAL_INT; goto out; @@ -342,6 +342,10 @@ static int gp2ap002_write_event_config(struct iio_dev *indio_dev, bool state) { struct gp2ap002 *gp2ap002 = iio_priv(indio_dev); + int ret; + + if (state == gp2ap002->enabled) + return 0; if (state) { /* @@ -349,13 +353,16 @@ static int gp2ap002_write_event_config(struct iio_dev *indio_dev, * already) and reintialize the sensor by using runtime_pm * callbacks. */ - pm_runtime_get_sync(gp2ap002->dev); - gp2ap002->enabled = true; + ret = pm_runtime_resume_and_get(gp2ap002->dev); + if (ret) + return ret; + } else { pm_runtime_put_autosuspend(gp2ap002->dev); - gp2ap002->enabled = false; } + gp2ap002->enabled = state; + return 0; } @@ -573,10 +580,8 @@ static int gp2ap002_probe(struct i2c_client *client) ret = devm_request_threaded_irq(dev, client->irq, NULL, gp2ap002_prox_irq, IRQF_ONESHOT, "gp2ap002", indio_dev); - if (ret) { - dev_err(dev, "unable to request IRQ\n"); + if (ret) goto out_put_pm; - } gp2ap002->irq = client->irq; /* @@ -642,6 +647,7 @@ static int gp2ap002_runtime_suspend(struct device *dev) /* Disable chip and IRQ, everything off */ ret = regmap_write(gp2ap002->map, GP2AP002_OPMOD, 0x00); if (ret) { + enable_irq(gp2ap002->irq); dev_err(gp2ap002->dev, "error setting up operation mode\n"); return ret; } @@ -669,7 +675,7 @@ static int gp2ap002_runtime_resume(struct device *dev) ret = regulator_enable(gp2ap002->vio); if (ret) { dev_err(dev, "failed to enable VIO regulator in resume path\n"); - return ret; + goto out_disable_vdd; } msleep(20); @@ -677,20 +683,26 @@ static int gp2ap002_runtime_resume(struct device *dev) ret = gp2ap002_init(gp2ap002); if (ret) { dev_err(dev, "re-initialization failed\n"); - return ret; + goto out_disable_vio; } /* Re-activate the IRQ */ enable_irq(gp2ap002->irq); return 0; + +out_disable_vio: + regulator_disable(gp2ap002->vio); +out_disable_vdd: + regulator_disable(gp2ap002->vdd); + return ret; } static DEFINE_RUNTIME_DEV_PM_OPS(gp2ap002_dev_pm_ops, gp2ap002_runtime_suspend, gp2ap002_runtime_resume, NULL); static const struct i2c_device_id gp2ap002_id_table[] = { - { "gp2ap002" }, + { .name = "gp2ap002" }, { } }; MODULE_DEVICE_TABLE(i2c, gp2ap002_id_table); @@ -717,3 +729,4 @@ module_i2c_driver(gp2ap002_driver); MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); MODULE_DESCRIPTION("GP2AP002 ambient light and proximity sensor driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index c7df4b258e2c..63591b7ecb89 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -31,19 +31,21 @@ * the other one. */ +#include <linux/cleanup.h> #include <linux/debugfs.h> #include <linux/delay.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/irq_work.h> +#include <linux/minmax.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> #include <linux/unaligned.h> + #include <linux/iio/buffer.h> #include <linux/iio/events.h> #include <linux/iio/iio.h> @@ -52,8 +54,6 @@ #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> -#define GP2A_I2C_NAME "gp2ap020a00f" - /* Registers */ #define GP2AP020A00F_OP_REG 0x00 /* Basic operations */ #define GP2AP020A00F_ALS_REG 0x01 /* ALS related settings */ @@ -174,10 +174,8 @@ #define GP2AP020A00F_CHAN_TIMESTAMP 3 #define GP2AP020A00F_DATA_READY_TIMEOUT msecs_to_jiffies(1000) -#define GP2AP020A00F_DATA_REG(chan) (GP2AP020A00F_D0_L_REG + \ - (chan) * 2) -#define GP2AP020A00F_THRESH_REG(th_val_id) (GP2AP020A00F_TL_L_REG + \ - (th_val_id) * 2) +#define GP2AP020A00F_DATA_REG(chan) (GP2AP020A00F_D0_L_REG + (chan) * 2) +#define GP2AP020A00F_THRESH_REG(th_val_id) (GP2AP020A00F_TL_L_REG + (th_val_id) * 2) #define GP2AP020A00F_THRESH_VAL_ID(reg_addr) ((reg_addr - 4) / 2) #define GP2AP020A00F_SUBTRACT_MODE 0 @@ -194,7 +192,7 @@ enum gp2ap020a00f_opmode { GP2AP020A00F_OPMODE_ALS_AND_PS, GP2AP020A00F_OPMODE_PROX_DETECT, GP2AP020A00F_OPMODE_SHUTDOWN, - GP2AP020A00F_NUM_OPMODES, + GP2AP020A00F_NUM_OPMODES }; enum gp2ap020a00f_cmd { @@ -246,7 +244,6 @@ struct gp2ap020a00f_data { struct iio_trigger *trig; struct regmap *regmap; unsigned int thresh_val[4]; - u8 debug_reg_addr; struct irq_work work; wait_queue_head_t data_ready_queue; }; @@ -389,20 +386,17 @@ static int gp2ap020a00f_set_operation_mode(struct gp2ap020a00f_data *data, } err = regmap_update_bits(data->regmap, GP2AP020A00F_ALS_REG, - GP2AP020A00F_PRST_MASK, opmode_regs_settings[op] - .als_reg); + GP2AP020A00F_PRST_MASK, opmode_regs_settings[op].als_reg); if (err < 0) return err; err = regmap_update_bits(data->regmap, GP2AP020A00F_PS_REG, - GP2AP020A00F_INTTYPE_MASK, opmode_regs_settings[op] - .ps_reg); + GP2AP020A00F_INTTYPE_MASK, opmode_regs_settings[op].ps_reg); if (err < 0) return err; err = regmap_update_bits(data->regmap, GP2AP020A00F_LED_REG, - GP2AP020A00F_PIN_MASK, opmode_regs_settings[op] - .led_reg); + GP2AP020A00F_PIN_MASK, opmode_regs_settings[op].led_reg); if (err < 0) return err; } @@ -453,15 +447,13 @@ static int gp2ap020a00f_write_event_threshold(struct gp2ap020a00f_data *data, */ thresh_reg_val = data->thresh_val[th_val_id] / 16; else - thresh_reg_val = data->thresh_val[th_val_id] > 16000 ? - 16000 : - data->thresh_val[th_val_id]; + thresh_reg_val = min(data->thresh_val[th_val_id], 16000U); thresh_buf = cpu_to_le16(thresh_reg_val); return regmap_bulk_write(data->regmap, GP2AP020A00F_THRESH_REG(th_val_id), - (u8 *)&thresh_buf, 2); + &thresh_buf, sizeof(thresh_buf)); } static int gp2ap020a00f_alter_opmode(struct gp2ap020a00f_data *data, @@ -493,27 +485,24 @@ static int gp2ap020a00f_alter_opmode(struct gp2ap020a00f_data *data, static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data, enum gp2ap020a00f_cmd cmd) { - int err = 0; + int err; switch (cmd) { case GP2AP020A00F_CMD_READ_RAW_CLEAR: if (data->cur_opmode != GP2AP020A00F_OPMODE_SHUTDOWN) return -EBUSY; - err = gp2ap020a00f_set_operation_mode(data, + return gp2ap020a00f_set_operation_mode(data, GP2AP020A00F_OPMODE_READ_RAW_CLEAR); - break; case GP2AP020A00F_CMD_READ_RAW_IR: if (data->cur_opmode != GP2AP020A00F_OPMODE_SHUTDOWN) return -EBUSY; - err = gp2ap020a00f_set_operation_mode(data, + return gp2ap020a00f_set_operation_mode(data, GP2AP020A00F_OPMODE_READ_RAW_IR); - break; case GP2AP020A00F_CMD_READ_RAW_PROXIMITY: if (data->cur_opmode != GP2AP020A00F_OPMODE_SHUTDOWN) return -EBUSY; - err = gp2ap020a00f_set_operation_mode(data, + return gp2ap020a00f_set_operation_mode(data, GP2AP020A00F_OPMODE_READ_RAW_PROXIMITY); - break; case GP2AP020A00F_CMD_TRIGGER_CLEAR_EN: if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT) return -EBUSY; @@ -521,16 +510,17 @@ static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data, err = gp2ap020a00f_alter_opmode(data, GP2AP020A00F_OPMODE_ALS, GP2AP020A00F_ADD_MODE); + else + err = 0; set_bit(GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER, &data->flags); - break; + return err; case GP2AP020A00F_CMD_TRIGGER_CLEAR_DIS: clear_bit(GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER, &data->flags); if (gp2ap020a00f_als_enabled(data)) break; - err = gp2ap020a00f_alter_opmode(data, + return gp2ap020a00f_alter_opmode(data, GP2AP020A00F_OPMODE_ALS, GP2AP020A00F_SUBTRACT_MODE); - break; case GP2AP020A00F_CMD_TRIGGER_IR_EN: if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT) return -EBUSY; @@ -538,16 +528,17 @@ static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data, err = gp2ap020a00f_alter_opmode(data, GP2AP020A00F_OPMODE_ALS, GP2AP020A00F_ADD_MODE); + else + err = 0; set_bit(GP2AP020A00F_FLAG_ALS_IR_TRIGGER, &data->flags); - break; + return err; case GP2AP020A00F_CMD_TRIGGER_IR_DIS: clear_bit(GP2AP020A00F_FLAG_ALS_IR_TRIGGER, &data->flags); if (gp2ap020a00f_als_enabled(data)) break; - err = gp2ap020a00f_alter_opmode(data, + return gp2ap020a00f_alter_opmode(data, GP2AP020A00F_OPMODE_ALS, GP2AP020A00F_SUBTRACT_MODE); - break; case GP2AP020A00F_CMD_TRIGGER_PROX_EN: if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT) return -EBUSY; @@ -555,13 +546,12 @@ static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data, GP2AP020A00F_OPMODE_PS, GP2AP020A00F_ADD_MODE); set_bit(GP2AP020A00F_FLAG_PROX_TRIGGER, &data->flags); - break; + return err; case GP2AP020A00F_CMD_TRIGGER_PROX_DIS: clear_bit(GP2AP020A00F_FLAG_PROX_TRIGGER, &data->flags); - err = gp2ap020a00f_alter_opmode(data, + return gp2ap020a00f_alter_opmode(data, GP2AP020A00F_OPMODE_PS, GP2AP020A00F_SUBTRACT_MODE); - break; case GP2AP020A00F_CMD_ALS_HIGH_EV_EN: if (test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags)) return 0; @@ -575,9 +565,8 @@ static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data, return err; } set_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags); - err = gp2ap020a00f_write_event_threshold(data, + return gp2ap020a00f_write_event_threshold(data, GP2AP020A00F_THRESH_TH, true); - break; case GP2AP020A00F_CMD_ALS_HIGH_EV_DIS: if (!test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags)) return 0; @@ -589,9 +578,8 @@ static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data, if (err < 0) return err; } - err = gp2ap020a00f_write_event_threshold(data, + return gp2ap020a00f_write_event_threshold(data, GP2AP020A00F_THRESH_TH, false); - break; case GP2AP020A00F_CMD_ALS_LOW_EV_EN: if (test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags)) return 0; @@ -605,9 +593,8 @@ static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data, return err; } set_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags); - err = gp2ap020a00f_write_event_threshold(data, + return gp2ap020a00f_write_event_threshold(data, GP2AP020A00F_THRESH_TL, true); - break; case GP2AP020A00F_CMD_ALS_LOW_EV_DIS: if (!test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags)) return 0; @@ -619,9 +606,8 @@ static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data, if (err < 0) return err; } - err = gp2ap020a00f_write_event_threshold(data, + return gp2ap020a00f_write_event_threshold(data, GP2AP020A00F_THRESH_TL, false); - break; case GP2AP020A00F_CMD_PROX_HIGH_EV_EN: if (test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags)) return 0; @@ -635,9 +621,8 @@ static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data, return err; } set_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags); - err = gp2ap020a00f_write_event_threshold(data, + return gp2ap020a00f_write_event_threshold(data, GP2AP020A00F_THRESH_PH, true); - break; case GP2AP020A00F_CMD_PROX_HIGH_EV_DIS: if (!test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags)) return 0; @@ -646,9 +631,8 @@ static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data, GP2AP020A00F_OPMODE_SHUTDOWN); if (err < 0) return err; - err = gp2ap020a00f_write_event_threshold(data, + return gp2ap020a00f_write_event_threshold(data, GP2AP020A00F_THRESH_PH, false); - break; case GP2AP020A00F_CMD_PROX_LOW_EV_EN: if (test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags)) return 0; @@ -662,9 +646,8 @@ static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data, return err; } set_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags); - err = gp2ap020a00f_write_event_threshold(data, + return gp2ap020a00f_write_event_threshold(data, GP2AP020A00F_THRESH_PL, true); - break; case GP2AP020A00F_CMD_PROX_LOW_EV_DIS: if (!test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags)) return 0; @@ -673,12 +656,11 @@ static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data, GP2AP020A00F_OPMODE_SHUTDOWN); if (err < 0) return err; - err = gp2ap020a00f_write_event_threshold(data, + return gp2ap020a00f_write_event_threshold(data, GP2AP020A00F_THRESH_PL, false); - break; } - return err; + return 0; } static int wait_conversion_complete_irq(struct gp2ap020a00f_data *data) @@ -697,18 +679,18 @@ static int wait_conversion_complete_irq(struct gp2ap020a00f_data *data) static int gp2ap020a00f_read_output(struct gp2ap020a00f_data *data, unsigned int output_reg, int *val) { - u8 reg_buf[2]; + __le16 reg_buf; int err; err = wait_conversion_complete_irq(data); if (err < 0) dev_dbg(&data->client->dev, "data ready timeout\n"); - err = regmap_bulk_read(data->regmap, output_reg, reg_buf, 2); + err = regmap_bulk_read(data->regmap, output_reg, ®_buf, sizeof(reg_buf)); if (err < 0) return err; - *val = le16_to_cpup((__le16 *)reg_buf); + *val = le16_to_cpu(reg_buf); return err; } @@ -866,13 +848,13 @@ static irqreturn_t gp2ap020a00f_thresh_event_handler(int irq, void *data) { struct iio_dev *indio_dev = data; struct gp2ap020a00f_data *priv = iio_priv(indio_dev); - u8 op_reg_flags, d0_reg_buf[2]; unsigned int output_val, op_reg_val; + __le16 d0_reg_buf; + u8 op_reg_flags; int thresh_val_id, ret; /* Read interrupt flags */ - ret = regmap_read(priv->regmap, GP2AP020A00F_OP_REG, - &op_reg_val); + ret = regmap_read(priv->regmap, GP2AP020A00F_OP_REG, &op_reg_val); if (ret < 0) goto done; @@ -884,8 +866,7 @@ static irqreturn_t gp2ap020a00f_thresh_event_handler(int irq, void *data) /* Clear interrupt flags (if not in INTTYPE_PULSE mode) */ if (priv->cur_opmode != GP2AP020A00F_OPMODE_PROX_DETECT) { - ret = regmap_write(priv->regmap, GP2AP020A00F_OP_REG, - op_reg_val); + ret = regmap_write(priv->regmap, GP2AP020A00F_OP_REG, op_reg_val); if (ret < 0) goto done; } @@ -895,11 +876,11 @@ static irqreturn_t gp2ap020a00f_thresh_event_handler(int irq, void *data) * transition is required. */ ret = regmap_bulk_read(priv->regmap, GP2AP020A00F_D0_L_REG, - d0_reg_buf, 2); + &d0_reg_buf, sizeof(d0_reg_buf)); if (ret < 0) goto done; - output_val = le16_to_cpup((__le16 *)d0_reg_buf); + output_val = le16_to_cpu(d0_reg_buf); if (gp2ap020a00f_adjust_lux_mode(priv, output_val)) goto done; @@ -966,17 +947,15 @@ static irqreturn_t gp2ap020a00f_trigger_handler(int irq, void *data) int i, out_val, ret; iio_for_each_active_channel(indio_dev, i) { - ret = regmap_bulk_read(priv->regmap, - GP2AP020A00F_DATA_REG(i), - &priv->buffer[d_size], 2); + ret = regmap_bulk_read(priv->regmap, GP2AP020A00F_DATA_REG(i), + &priv->buffer[d_size], 2); if (ret < 0) goto done; if (i == GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR || i == GP2AP020A00F_SCAN_MODE_LIGHT_IR) { - out_val = le16_to_cpup((__le16 *)&priv->buffer[d_size]); + out_val = get_unaligned_le16(&priv->buffer[d_size]); gp2ap020a00f_output_to_lux(priv, &out_val); - put_unaligned_le32(out_val, &priv->buffer[d_size]); d_size += 4; } else { @@ -984,16 +963,15 @@ static irqreturn_t gp2ap020a00f_trigger_handler(int irq, void *data) } } - iio_push_to_buffers_with_timestamp(indio_dev, priv->buffer, - pf->timestamp); + iio_push_to_buffers_with_timestamp(indio_dev, priv->buffer, pf->timestamp); done: iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; } -static u8 gp2ap020a00f_get_thresh_reg(const struct iio_chan_spec *chan, - enum iio_event_direction event_dir) +static int gp2ap020a00f_get_thresh_reg(const struct iio_chan_spec *chan, + enum iio_event_direction event_dir) { switch (chan->type) { case IIO_PROXIMITY: @@ -1007,10 +985,8 @@ static u8 gp2ap020a00f_get_thresh_reg(const struct iio_chan_spec *chan, else return GP2AP020A00F_TL_L_REG; default: - break; + return -EINVAL; } - - return -EINVAL; } static int gp2ap020a00f_write_event_val(struct iio_dev *indio_dev, @@ -1023,53 +999,41 @@ static int gp2ap020a00f_write_event_val(struct iio_dev *indio_dev, struct gp2ap020a00f_data *data = iio_priv(indio_dev); bool event_en = false; u8 thresh_val_id; - u8 thresh_reg_l; - int err = 0; + int thresh_reg_l; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); thresh_reg_l = gp2ap020a00f_get_thresh_reg(chan, dir); - thresh_val_id = GP2AP020A00F_THRESH_VAL_ID(thresh_reg_l); + if (thresh_reg_l < 0) + return thresh_reg_l; - if (thresh_val_id > GP2AP020A00F_THRESH_PH) { - err = -EINVAL; - goto error_unlock; - } + thresh_val_id = GP2AP020A00F_THRESH_VAL_ID(thresh_reg_l); + if (thresh_val_id > GP2AP020A00F_THRESH_PH) + return -EINVAL; switch (thresh_reg_l) { case GP2AP020A00F_TH_L_REG: - event_en = test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, - &data->flags); + event_en = test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags); break; case GP2AP020A00F_TL_L_REG: - event_en = test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, - &data->flags); + event_en = test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags); break; case GP2AP020A00F_PH_L_REG: - if (val == 0) { - err = -EINVAL; - goto error_unlock; - } - event_en = test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, - &data->flags); + if (val == 0) + return -EINVAL; + + event_en = test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags); break; case GP2AP020A00F_PL_L_REG: - if (val == 0) { - err = -EINVAL; - goto error_unlock; - } - event_en = test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, - &data->flags); + if (val == 0) + return -EINVAL; + + event_en = test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags); break; } data->thresh_val[thresh_val_id] = val; - err = gp2ap020a00f_write_event_threshold(data, thresh_val_id, - event_en); -error_unlock: - mutex_unlock(&data->lock); - - return err; + return gp2ap020a00f_write_event_threshold(data, thresh_val_id, event_en); } static int gp2ap020a00f_read_event_val(struct iio_dev *indio_dev, @@ -1080,24 +1044,19 @@ static int gp2ap020a00f_read_event_val(struct iio_dev *indio_dev, int *val, int *val2) { struct gp2ap020a00f_data *data = iio_priv(indio_dev); - u8 thresh_reg_l; - int err = IIO_VAL_INT; + int thresh_reg_l; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); thresh_reg_l = gp2ap020a00f_get_thresh_reg(chan, dir); - - if (thresh_reg_l > GP2AP020A00F_PH_L_REG) { - err = -EINVAL; - goto error_unlock; - } + if (thresh_reg_l < 0) + return thresh_reg_l; + if (thresh_reg_l > GP2AP020A00F_PH_L_REG) + return -EINVAL; *val = data->thresh_val[GP2AP020A00F_THRESH_VAL_ID(thresh_reg_l)]; -error_unlock: - mutex_unlock(&data->lock); - - return err; + return IIO_VAL_INT; } static int gp2ap020a00f_write_prox_event_config(struct iio_dev *indio_dev, @@ -1163,32 +1122,25 @@ static int gp2ap020a00f_write_event_config(struct iio_dev *indio_dev, { struct gp2ap020a00f_data *data = iio_priv(indio_dev); enum gp2ap020a00f_cmd cmd; - int err; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); switch (chan->type) { case IIO_PROXIMITY: - err = gp2ap020a00f_write_prox_event_config(indio_dev, state); - break; + return gp2ap020a00f_write_prox_event_config(indio_dev, state); case IIO_LIGHT: if (dir == IIO_EV_DIR_RISING) { cmd = state ? GP2AP020A00F_CMD_ALS_HIGH_EV_EN : GP2AP020A00F_CMD_ALS_HIGH_EV_DIS; - err = gp2ap020a00f_exec_cmd(data, cmd); + return gp2ap020a00f_exec_cmd(data, cmd); } else { cmd = state ? GP2AP020A00F_CMD_ALS_LOW_EV_EN : GP2AP020A00F_CMD_ALS_LOW_EV_DIS; - err = gp2ap020a00f_exec_cmd(data, cmd); + return gp2ap020a00f_exec_cmd(data, cmd); } - break; default: - err = -EINVAL; + return -EINVAL; } - - mutex_unlock(&data->lock); - - return err; } static int gp2ap020a00f_read_event_config(struct iio_dev *indio_dev, @@ -1197,40 +1149,29 @@ static int gp2ap020a00f_read_event_config(struct iio_dev *indio_dev, enum iio_event_direction dir) { struct gp2ap020a00f_data *data = iio_priv(indio_dev); - int event_en = 0; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); switch (chan->type) { case IIO_PROXIMITY: if (dir == IIO_EV_DIR_RISING) - event_en = test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, - &data->flags); + return test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags); else - event_en = test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, - &data->flags); - break; + return test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags); case IIO_LIGHT: if (dir == IIO_EV_DIR_RISING) - event_en = test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, - &data->flags); + return test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags); else - event_en = test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, - &data->flags); - break; + return test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags); default: - event_en = -EINVAL; - break; + return -EINVAL; } - - mutex_unlock(&data->lock); - - return event_en; } static int gp2ap020a00f_read_channel(struct gp2ap020a00f_data *data, struct iio_chan_spec const *chan, int *val) { + struct device *dev = &data->client->dev; enum gp2ap020a00f_cmd cmd; int err; @@ -1250,27 +1191,23 @@ static int gp2ap020a00f_read_channel(struct gp2ap020a00f_data *data, err = gp2ap020a00f_exec_cmd(data, cmd); if (err < 0) { - dev_err(&data->client->dev, - "gp2ap020a00f_exec_cmd failed\n"); - goto error_ret; + dev_err(dev, "gp2ap020a00f_exec_cmd failed\n"); + return err; } err = gp2ap020a00f_read_output(data, chan->address, val); if (err < 0) - dev_err(&data->client->dev, - "gp2ap020a00f_read_output failed\n"); + dev_err(dev, "gp2ap020a00f_read_output failed\n"); err = gp2ap020a00f_set_operation_mode(data, GP2AP020A00F_OPMODE_SHUTDOWN); if (err < 0) - dev_err(&data->client->dev, - "Failed to shut down the device.\n"); + dev_err(dev, "Failed to shut down the device.\n"); if (cmd == GP2AP020A00F_CMD_READ_RAW_CLEAR || cmd == GP2AP020A00F_CMD_READ_RAW_IR) gp2ap020a00f_output_to_lux(data, val); -error_ret: return err; } @@ -1383,9 +1320,9 @@ static const struct iio_info gp2ap020a00f_info = { static int gp2ap020a00f_buffer_postenable(struct iio_dev *indio_dev) { struct gp2ap020a00f_data *data = iio_priv(indio_dev); - int i, err = 0; + int i, err; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); /* * Enable triggers according to the scan_mask. Enabling either @@ -1409,28 +1346,27 @@ static int gp2ap020a00f_buffer_postenable(struct iio_dev *indio_dev) err = gp2ap020a00f_exec_cmd(data, GP2AP020A00F_CMD_TRIGGER_PROX_EN); break; + default: + err = -EINVAL; + break; } + if (err) + return err; } - if (err < 0) - goto error_unlock; - data->buffer = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); if (!data->buffer) - err = -ENOMEM; - -error_unlock: - mutex_unlock(&data->lock); + return -ENOMEM; - return err; + return 0; } static int gp2ap020a00f_buffer_predisable(struct iio_dev *indio_dev) { struct gp2ap020a00f_data *data = iio_priv(indio_dev); - int i, err = 0; + int i, err; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); iio_for_each_active_channel(indio_dev, i) { switch (i) { @@ -1446,15 +1382,16 @@ static int gp2ap020a00f_buffer_predisable(struct iio_dev *indio_dev) err = gp2ap020a00f_exec_cmd(data, GP2AP020A00F_CMD_TRIGGER_PROX_DIS); break; + default: + err = -EINVAL; + break; } + if (err) + return err; } - if (err == 0) - kfree(data->buffer); - - mutex_unlock(&data->lock); - - return err; + kfree(data->buffer); + return 0; } static const struct iio_buffer_setup_ops gp2ap020a00f_buffer_setup_ops = { @@ -1465,18 +1402,19 @@ static const struct iio_buffer_setup_ops gp2ap020a00f_buffer_setup_ops = { static int gp2ap020a00f_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); + struct device *dev = &client->dev; struct gp2ap020a00f_data *data; struct iio_dev *indio_dev; struct regmap *regmap; int err; - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) return -ENOMEM; data = iio_priv(indio_dev); - data->vled_reg = devm_regulator_get(&client->dev, "vled"); + data->vled_reg = devm_regulator_get(dev, "vled"); if (IS_ERR(data->vled_reg)) return PTR_ERR(data->vled_reg); @@ -1486,7 +1424,7 @@ static int gp2ap020a00f_probe(struct i2c_client *client) regmap = devm_regmap_init_i2c(client, &gp2ap020a00f_regmap_config); if (IS_ERR(regmap)) { - dev_err(&client->dev, "Regmap initialization failed.\n"); + dev_err(dev, "Regmap initialization failed.\n"); err = PTR_ERR(regmap); goto error_regulator_disable; } @@ -1497,7 +1435,7 @@ static int gp2ap020a00f_probe(struct i2c_client *client) ARRAY_SIZE(gp2ap020a00f_reg_init_tab)); if (err < 0) { - dev_err(&client->dev, "Device initialization failed.\n"); + dev_err(dev, "Device initialization failed.\n"); goto error_regulator_disable; } @@ -1522,11 +1460,10 @@ static int gp2ap020a00f_probe(struct i2c_client *client) goto error_regulator_disable; /* Allocate trigger */ - data->trig = devm_iio_trigger_alloc(&client->dev, "%s-trigger", - indio_dev->name); + data->trig = devm_iio_trigger_alloc(dev, "%s-trigger", indio_dev->name); if (data->trig == NULL) { err = -ENOMEM; - dev_err(&indio_dev->dev, "Failed to allocate iio trigger.\n"); + dev_err(dev, "Failed to allocate iio trigger.\n"); goto error_uninit_buffer; } @@ -1538,7 +1475,7 @@ static int gp2ap020a00f_probe(struct i2c_client *client) "gp2ap020a00f_als_event", indio_dev); if (err < 0) { - dev_err(&client->dev, "Irq request failed.\n"); + dev_err(dev, "Irq request failed.\n"); goto error_uninit_buffer; } @@ -1546,7 +1483,7 @@ static int gp2ap020a00f_probe(struct i2c_client *client) err = iio_trigger_register(data->trig); if (err < 0) { - dev_err(&client->dev, "Failed to register iio trigger.\n"); + dev_err(dev, "Failed to register iio trigger.\n"); goto error_free_irq; } @@ -1572,12 +1509,12 @@ static void gp2ap020a00f_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); struct gp2ap020a00f_data *data = iio_priv(indio_dev); + struct device *dev = &client->dev; int err; - err = gp2ap020a00f_set_operation_mode(data, - GP2AP020A00F_OPMODE_SHUTDOWN); + err = gp2ap020a00f_set_operation_mode(data, GP2AP020A00F_OPMODE_SHUTDOWN); if (err < 0) - dev_err(&indio_dev->dev, "Failed to power off the device.\n"); + dev_err(dev, "Failed to power off the device.\n"); iio_device_unregister(indio_dev); iio_trigger_unregister(data->trig); @@ -1587,10 +1524,9 @@ static void gp2ap020a00f_remove(struct i2c_client *client) } static const struct i2c_device_id gp2ap020a00f_id[] = { - { GP2A_I2C_NAME }, + { .name = "gp2ap020a00f" }, { } }; - MODULE_DEVICE_TABLE(i2c, gp2ap020a00f_id); static const struct of_device_id gp2ap020a00f_of_match[] = { @@ -1601,14 +1537,13 @@ MODULE_DEVICE_TABLE(of, gp2ap020a00f_of_match); static struct i2c_driver gp2ap020a00f_driver = { .driver = { - .name = GP2A_I2C_NAME, + .name = "gp2ap020a00f", .of_match_table = gp2ap020a00f_of_match, }, .probe = gp2ap020a00f_probe, .remove = gp2ap020a00f_remove, .id_table = gp2ap020a00f_id, }; - module_i2c_driver(gp2ap020a00f_driver); MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>"); diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index 384572844162..929343e42d83 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -3,10 +3,10 @@ * HID Sensors Driver * Copyright (c) 2012, Intel Corporation. */ +#include <linux/bitops.h> #include <linux/device.h> #include <linux/platform_device.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/slab.h> #include <linux/hid-sensor-hub.h> #include <linux/iio/iio.h> @@ -33,9 +33,9 @@ struct als_state { u32 illum[CHANNEL_SCAN_INDEX_MAX]; aligned_s64 timestamp; } scan; - int scale_pre_decml; - int scale_post_decml; - int scale_precision; + int scale_pre_decml[CHANNEL_SCAN_INDEX_MAX]; + int scale_post_decml[CHANNEL_SCAN_INDEX_MAX]; + int scale_precision[CHANNEL_SCAN_INDEX_MAX]; int value_offset; int num_channels; s64 timestamp; @@ -117,22 +117,10 @@ static const struct iio_chan_spec als_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP) }; -/* Adjust channel real bits based on report descriptor */ -static void als_adjust_channel_bit_mask(struct iio_chan_spec *channels, - int channel, int size) -{ - channels[channel].scan_type.sign = 's'; - /* Real storage bits will change based on the report desc. */ - channels[channel].scan_type.realbits = size * 8; - /* Maximum size of a sample to capture is u32 */ - channels[channel].scan_type.storagebits = sizeof(u32) * 8; -} - /* Channel read_raw handler */ static int als_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, - long mask) + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { struct als_state *als_state = iio_priv(indio_dev); struct hid_sensor_hub_device *hsdev = als_state->common_attributes.hsdev; @@ -173,12 +161,12 @@ static int als_read_raw(struct iio_dev *indio_dev, } if (report_id >= 0) { hid_sensor_power_state(&als_state->common_attributes, - true); + true); *val = sensor_hub_input_attr_get_raw_value( hsdev, hsdev->usage, address, report_id, SENSOR_HUB_SYNC, min < 0); hid_sensor_power_state(&als_state->common_attributes, - false); + false); } else { *val = 0; return -EINVAL; @@ -186,9 +174,11 @@ static int als_read_raw(struct iio_dev *indio_dev, ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SCALE: - *val = als_state->scale_pre_decml; - *val2 = als_state->scale_post_decml; - ret_type = als_state->scale_precision; + if (chan->scan_index >= CHANNEL_SCAN_INDEX_MAX) + return -EINVAL; + *val = als_state->scale_pre_decml[chan->scan_index]; + *val2 = als_state->scale_post_decml[chan->scan_index]; + ret_type = als_state->scale_precision[chan->scan_index]; break; case IIO_CHAN_INFO_OFFSET: *val = als_state->value_offset; @@ -216,10 +206,8 @@ static int als_read_raw(struct iio_dev *indio_dev, /* Channel write_raw handler */ static int als_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct als_state *als_state = iio_priv(indio_dev); int ret = 0; @@ -251,8 +239,7 @@ static const struct iio_info als_info = { /* Callback handler to send event after all samples are received and captured */ static int als_proc_event(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - void *priv) + u32 usage_id, void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct als_state *als_state = iio_priv(indio_dev); @@ -273,9 +260,9 @@ static int als_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int als_capture_sample(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - size_t raw_len, char *raw_data, - void *priv) + u32 usage_id, + size_t raw_len, char *raw_data, + void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct als_state *als_state = iio_priv(indio_dev); @@ -314,9 +301,9 @@ static int als_capture_sample(struct hid_sensor_hub_device *hsdev, /* Parse report which is specific to an usage id*/ static int als_parse_report(struct platform_device *pdev, - struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - struct als_state *st) + struct hid_sensor_hub_device *hsdev, + u32 usage_id, + struct als_state *st) { struct iio_chan_spec *channels; int ret, index = 0; @@ -335,9 +322,17 @@ static int als_parse_report(struct platform_device *pdev, channels[index] = als_channels[i]; st->als_scan_mask[0] |= BIT(i); - als_adjust_channel_bit_mask(channels, index, st->als[i].size); + channels[index].scan_type = (struct iio_scan_type) { + .format = 's', + .realbits = BYTES_TO_BITS(st->als[i].size), + .storagebits = BITS_PER_TYPE(u32), + }; ++index; + st->scale_precision[i] = hid_sensor_format_scale(usage_id, + &st->als[i], &st->scale_pre_decml[i], + &st->scale_post_decml[i]); + dev_dbg(&pdev->dev, "als %x:%x\n", st->als[i].index, st->als[i].report_id); } @@ -347,10 +342,6 @@ static int als_parse_report(struct platform_device *pdev, if (index) ret = 0; - st->scale_precision = hid_sensor_format_scale(usage_id, - &st->als[CHANNEL_SCAN_INDEX_INTENSITY], - &st->scale_pre_decml, &st->scale_post_decml); - return ret; } @@ -406,31 +397,31 @@ static int hid_als_probe(struct platform_device *pdev) atomic_set(&als_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, - &als_state->common_attributes); + &als_state->common_attributes); if (ret < 0) { dev_err(&pdev->dev, "trigger setup failed\n"); return ret; } - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(&pdev->dev, "device register failed\n"); - goto error_remove_trigger; - } - als_state->callbacks.send_event = als_proc_event; als_state->callbacks.capture_sample = als_capture_sample; als_state->callbacks.pdev = pdev; ret = sensor_hub_register_callback(hsdev, hsdev->usage, &als_state->callbacks); if (ret < 0) { dev_err(&pdev->dev, "callback reg failed\n"); - goto error_iio_unreg; + goto error_remove_trigger; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "device register failed\n"); + goto error_remove_callback; } return ret; -error_iio_unreg: - iio_device_unregister(indio_dev); +error_remove_callback: + sensor_hub_remove_callback(hsdev, hsdev->usage); error_remove_trigger: hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes); return ret; @@ -443,8 +434,8 @@ static void hid_als_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct als_state *als_state = iio_priv(indio_dev); - sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); + sensor_hub_remove_callback(hsdev, hsdev->usage); hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes); } diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c index efa904a70d0e..63fd3eff171c 100644 --- a/drivers/iio/light/hid-sensor-prox.c +++ b/drivers/iio/light/hid-sensor-prox.c @@ -3,10 +3,10 @@ * HID Sensors Driver * Copyright (c) 2014, Intel Corporation. */ +#include <linux/bitops.h> #include <linux/device.h> #include <linux/platform_device.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/slab.h> #include <linux/hid-sensor-hub.h> #include <linux/iio/iio.h> @@ -67,22 +67,10 @@ static const struct iio_chan_spec prox_channels[] = { PROX_CHANNEL(false, 0), }; -/* Adjust channel real bits based on report descriptor */ -static void prox_adjust_channel_bit_mask(struct iio_chan_spec *channels, - int channel, int size) -{ - channels[channel].scan_type.sign = 's'; - /* Real storage bits will change based on the report desc. */ - channels[channel].scan_type.realbits = size * 8; - /* Maximum size of a sample to capture is u32 */ - channels[channel].scan_type.storagebits = sizeof(u32) * 8; -} - /* Channel read_raw handler */ static int prox_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, - long mask) + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { struct prox_state *prox_state = iio_priv(indio_dev); struct hid_sensor_hub_device *hsdev; @@ -145,10 +133,8 @@ static int prox_read_raw(struct iio_dev *indio_dev, /* Channel write_raw handler */ static int prox_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct prox_state *prox_state = iio_priv(indio_dev); int ret = 0; @@ -176,8 +162,7 @@ static const struct iio_info prox_info = { /* Callback handler to send event after all samples are received and captured */ static int prox_proc_event(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - void *priv) + u32 usage_id, void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct prox_state *prox_state = iio_priv(indio_dev); @@ -193,9 +178,9 @@ static int prox_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int prox_capture_sample(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - size_t raw_len, char *raw_data, - void *priv) + u32 usage_id, + size_t raw_len, char *raw_data, + void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct prox_state *prox_state = iio_priv(indio_dev); @@ -228,8 +213,8 @@ static int prox_capture_sample(struct hid_sensor_hub_device *hsdev, /* Parse report which is specific to an usage id*/ static int prox_parse_report(struct platform_device *pdev, - struct hid_sensor_hub_device *hsdev, - struct prox_state *st) + struct hid_sensor_hub_device *hsdev, + struct prox_state *st) { struct iio_chan_spec *channels = st->channels; int index = 0; @@ -250,8 +235,11 @@ static int prox_parse_report(struct platform_device *pdev, st->scan_mask[0] |= BIT(index); channels[index] = prox_channels[i]; channels[index].scan_index = index; - prox_adjust_channel_bit_mask(channels, index, - st->prox_attr[index].size); + channels[index].scan_type = (struct iio_scan_type) { + .format = 's', + .realbits = BYTES_TO_BITS(st->prox_attr[index].size), + .storagebits = BITS_PER_TYPE(u32), + }; dev_dbg(&pdev->dev, "prox %x:%x\n", st->prox_attr[index].index, st->prox_attr[index].report_id); st->scale_precision[index] = @@ -278,8 +266,7 @@ static int hid_prox_probe(struct platform_device *pdev) struct iio_dev *indio_dev; struct prox_state *prox_state; - indio_dev = devm_iio_device_alloc(&pdev->dev, - sizeof(struct prox_state)); + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct prox_state)); if (!indio_dev) return -ENOMEM; platform_set_drvdata(pdev, indio_dev); @@ -313,18 +300,12 @@ static int hid_prox_probe(struct platform_device *pdev) atomic_set(&prox_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, - &prox_state->common_attributes); + &prox_state->common_attributes); if (ret) { dev_err(&pdev->dev, "trigger setup failed\n"); return ret; } - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(&pdev->dev, "device register failed\n"); - goto error_remove_trigger; - } - prox_state->callbacks.send_event = prox_proc_event; prox_state->callbacks.capture_sample = prox_capture_sample; prox_state->callbacks.pdev = pdev; @@ -332,13 +313,19 @@ static int hid_prox_probe(struct platform_device *pdev) &prox_state->callbacks); if (ret < 0) { dev_err(&pdev->dev, "callback reg failed\n"); - goto error_iio_unreg; + goto error_remove_trigger; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "device register failed\n"); + goto error_remove_callback; } return ret; -error_iio_unreg: - iio_device_unregister(indio_dev); +error_remove_callback: + sensor_hub_remove_callback(hsdev, hsdev->usage); error_remove_trigger: hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes); return ret; @@ -351,8 +338,8 @@ static void hid_prox_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct prox_state *prox_state = iio_priv(indio_dev); - sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); + sensor_hub_remove_callback(hsdev, hsdev->usage); hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes); } diff --git a/drivers/iio/light/iqs621-als.c b/drivers/iio/light/iqs621-als.c index b9f230210f07..cd5843e3e2c3 100644 --- a/drivers/iio/light/iqs621-als.c +++ b/drivers/iio/light/iqs621-als.c @@ -5,6 +5,7 @@ * Copyright (C) 2019 Jeff LaBundy <jeff@labundy.com> */ +#include <linux/cleanup.h> #include <linux/device.h> #include <linux/iio/events.h> #include <linux/iio/iio.h> @@ -107,26 +108,20 @@ static int iqs621_als_notifier(struct notifier_block *notifier, indio_dev = iqs621_als->indio_dev; timestamp = iio_get_time_ns(indio_dev); - mutex_lock(&iqs621_als->lock); + guard(mutex)(&iqs621_als->lock); if (event_flags & BIT(IQS62X_EVENT_SYS_RESET)) { ret = iqs621_als_init(iqs621_als); if (ret) { dev_err(indio_dev->dev.parent, "Failed to re-initialize device: %d\n", ret); - ret = NOTIFY_BAD; - } else { - ret = NOTIFY_OK; + return NOTIFY_BAD; } - - goto err_mutex; + return NOTIFY_OK; } - if (!iqs621_als->light_en && !iqs621_als->range_en && - !iqs621_als->prox_en) { - ret = NOTIFY_DONE; - goto err_mutex; - } + if (!iqs621_als->light_en && !iqs621_als->range_en && !iqs621_als->prox_en) + return NOTIFY_DONE; /* IQS621 only */ light_new = event_data->als_flags & IQS621_ALS_FLAGS_LIGHT; @@ -181,12 +176,7 @@ static int iqs621_als_notifier(struct notifier_block *notifier, iqs621_als->als_flags = event_data->als_flags; iqs621_als->ir_flags = event_data->ir_flags; - ret = NOTIFY_OK; - -err_mutex: - mutex_unlock(&iqs621_als->lock); - - return ret; + return NOTIFY_OK; } static void iqs621_als_notifier_unregister(void *context) @@ -241,30 +231,22 @@ static int iqs621_als_read_event_config(struct iio_dev *indio_dev, enum iio_event_direction dir) { struct iqs621_als_private *iqs621_als = iio_priv(indio_dev); - int ret; - mutex_lock(&iqs621_als->lock); + guard(mutex)(&iqs621_als->lock); switch (chan->type) { case IIO_LIGHT: - ret = iqs621_als->light_en; - break; + return iqs621_als->light_en; case IIO_INTENSITY: - ret = iqs621_als->range_en; - break; + return iqs621_als->range_en; case IIO_PROXIMITY: - ret = iqs621_als->prox_en; - break; + return iqs621_als->prox_en; default: - ret = -EINVAL; + return -EINVAL; } - - mutex_unlock(&iqs621_als->lock); - - return ret; } static int iqs621_als_write_event_config(struct iio_dev *indio_dev, @@ -278,11 +260,11 @@ static int iqs621_als_write_event_config(struct iio_dev *indio_dev, unsigned int val; int ret; - mutex_lock(&iqs621_als->lock); + guard(mutex)(&iqs621_als->lock); ret = regmap_read(iqs62x->regmap, iqs62x->dev_desc->als_flags, &val); if (ret) - goto err_mutex; + return ret; iqs621_als->als_flags = val; switch (chan->type) { @@ -291,40 +273,41 @@ static int iqs621_als_write_event_config(struct iio_dev *indio_dev, iqs62x->dev_desc->als_mask, iqs621_als->range_en || state ? 0 : 0xFF); - if (!ret) - iqs621_als->light_en = state; - break; + if (ret) + return ret; + iqs621_als->light_en = state; + + return 0; case IIO_INTENSITY: ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK, iqs62x->dev_desc->als_mask, iqs621_als->light_en || state ? 0 : 0xFF); - if (!ret) - iqs621_als->range_en = state; - break; + if (ret) + return ret; + iqs621_als->range_en = state; + + return 0; case IIO_PROXIMITY: ret = regmap_read(iqs62x->regmap, IQS622_IR_FLAGS, &val); if (ret) - goto err_mutex; + return ret; iqs621_als->ir_flags = val; ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK, iqs62x->dev_desc->ir_mask, state ? 0 : 0xFF); - if (!ret) - iqs621_als->prox_en = state; - break; + if (ret) + return ret; + iqs621_als->prox_en = state; + + return 0; default: - ret = -EINVAL; + return -EINVAL; } - -err_mutex: - mutex_unlock(&iqs621_als->lock); - - return ret; } static int iqs621_als_read_event_value(struct iio_dev *indio_dev, @@ -335,33 +318,28 @@ static int iqs621_als_read_event_value(struct iio_dev *indio_dev, int *val, int *val2) { struct iqs621_als_private *iqs621_als = iio_priv(indio_dev); - int ret = IIO_VAL_INT; - mutex_lock(&iqs621_als->lock); + guard(mutex)(&iqs621_als->lock); switch (dir) { case IIO_EV_DIR_RISING: *val = iqs621_als->thresh_light * 16; - break; + return IIO_VAL_INT; case IIO_EV_DIR_FALLING: *val = iqs621_als->thresh_dark * 4; - break; + return IIO_VAL_INT; case IIO_EV_DIR_EITHER: if (iqs621_als->ir_flags_mask == IQS622_IR_FLAGS_TOUCH) *val = iqs621_als->thresh_prox * 4; else *val = iqs621_als->thresh_prox; - break; + return IIO_VAL_INT; default: - ret = -EINVAL; + return -EINVAL; } - - mutex_unlock(&iqs621_als->lock); - - return ret; } static int iqs621_als_write_event_value(struct iio_dev *indio_dev, @@ -375,9 +353,9 @@ static int iqs621_als_write_event_value(struct iio_dev *indio_dev, struct iqs62x_core *iqs62x = iqs621_als->iqs62x; unsigned int thresh_reg, thresh_val; u8 ir_flags_mask, *thresh_cache; - int ret = -EINVAL; + int ret; - mutex_lock(&iqs621_als->lock); + guard(mutex)(&iqs621_als->lock); switch (dir) { case IIO_EV_DIR_RISING: @@ -426,30 +404,27 @@ static int iqs621_als_write_event_value(struct iio_dev *indio_dev, break; default: - goto err_mutex; + return -EINVAL; } thresh_cache = &iqs621_als->thresh_prox; break; default: - goto err_mutex; + return -EINVAL; } if (thresh_val > 0xFF) - goto err_mutex; + return -EINVAL; ret = regmap_write(iqs62x->regmap, thresh_reg, thresh_val); if (ret) - goto err_mutex; + return ret; *thresh_cache = thresh_val; iqs621_als->ir_flags_mask = ir_flags_mask; -err_mutex: - mutex_unlock(&iqs621_als->lock); - - return ret; + return 0; } static const struct iio_info iqs621_als_info = { diff --git a/drivers/iio/light/isl29018.c b/drivers/iio/light/isl29018.c index b6ab726d1dae..759cb71ed1c5 100644 --- a/drivers/iio/light/isl29018.c +++ b/drivers/iio/light/isl29018.c @@ -10,7 +10,6 @@ #include <linux/i2c.h> #include <linux/err.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/delay.h> @@ -829,9 +828,9 @@ static const struct acpi_device_id isl29018_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, isl29018_acpi_match); static const struct i2c_device_id isl29018_id[] = { - {"isl29018", isl29018}, - {"isl29023", isl29023}, - {"isl29035", isl29035}, + { .name = "isl29018", .driver_data = isl29018 }, + { .name = "isl29023", .driver_data = isl29023 }, + { .name = "isl29035", .driver_data = isl29035 }, { } }; MODULE_DEVICE_TABLE(i2c, isl29018_id); diff --git a/drivers/iio/light/isl29028.c b/drivers/iio/light/isl29028.c index 374bccad9119..33deb1726689 100644 --- a/drivers/iio/light/isl29028.c +++ b/drivers/iio/light/isl29028.c @@ -333,16 +333,6 @@ static int isl29028_ir_get(struct isl29028_chip *chip, int *ir_data) return isl29028_read_als_ir(chip, ir_data); } -static int isl29028_set_pm_runtime_busy(struct isl29028_chip *chip, bool on) -{ - struct device *dev = regmap_get_device(chip->regmap); - - if (on) - return pm_runtime_resume_and_get(dev); - - return pm_runtime_put_autosuspend(dev); -} - /* Channel IO */ static int isl29028_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, @@ -352,7 +342,7 @@ static int isl29028_write_raw(struct iio_dev *indio_dev, struct device *dev = regmap_get_device(chip->regmap); int ret; - ret = isl29028_set_pm_runtime_busy(chip, true); + ret = pm_runtime_resume_and_get(dev); if (ret < 0) return ret; @@ -405,11 +395,11 @@ static int isl29028_write_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; - ret = isl29028_set_pm_runtime_busy(chip, false); + ret = pm_runtime_put_autosuspend(dev); if (ret < 0) return ret; - return ret; + return 0; } static int isl29028_read_raw(struct iio_dev *indio_dev, @@ -420,7 +410,7 @@ static int isl29028_read_raw(struct iio_dev *indio_dev, struct device *dev = regmap_get_device(chip->regmap); int ret, pm_ret; - ret = isl29028_set_pm_runtime_busy(chip, true); + ret = pm_runtime_resume_and_get(dev); if (ret < 0) return ret; @@ -476,10 +466,10 @@ static int isl29028_read_raw(struct iio_dev *indio_dev, /** * Preserve the ret variable if the call to - * isl29028_set_pm_runtime_busy() is successful so the reading + * pm_runtime_put_autosuspend() is successful so the reading * (if applicable) is returned to user space. */ - pm_ret = isl29028_set_pm_runtime_busy(chip, false); + pm_ret = pm_runtime_put_autosuspend(dev); if (pm_ret < 0) return pm_ret; @@ -673,8 +663,8 @@ static DEFINE_RUNTIME_DEV_PM_OPS(isl29028_pm_ops, isl29028_suspend, isl29028_resume, NULL); static const struct i2c_device_id isl29028_id[] = { - { "isl29028" }, - { "isl29030" }, + { .name = "isl29028" }, + { .name = "isl29030" }, { } }; MODULE_DEVICE_TABLE(i2c, isl29028_id); diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c index 3acb8a4f1d12..9e0b7e6a3ecf 100644 --- a/drivers/iio/light/isl29125.c +++ b/drivers/iio/light/isl29125.c @@ -325,7 +325,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(isl29125_pm_ops, isl29125_suspend, isl29125_resume); static const struct i2c_device_id isl29125_id[] = { - { "isl29125" }, + { .name = "isl29125" }, { } }; MODULE_DEVICE_TABLE(i2c, isl29125_id); diff --git a/drivers/iio/light/isl76682.c b/drivers/iio/light/isl76682.c index b6f2fc9978f6..9b9052d08e41 100644 --- a/drivers/iio/light/isl76682.c +++ b/drivers/iio/light/isl76682.c @@ -319,7 +319,7 @@ static int isl76682_probe(struct i2c_client *client) } static const struct i2c_device_id isl76682_id[] = { - { "isl76682" }, + { .name = "isl76682" }, { } }; MODULE_DEVICE_TABLE(i2c, isl76682_id); diff --git a/drivers/iio/light/jsa1212.c b/drivers/iio/light/jsa1212.c index 6978d02a4df5..038ee49723ae 100644 --- a/drivers/iio/light/jsa1212.c +++ b/drivers/iio/light/jsa1212.c @@ -12,7 +12,6 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/delay.h> #include <linux/i2c.h> #include <linux/mutex.h> @@ -428,7 +427,7 @@ static const struct acpi_device_id jsa1212_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, jsa1212_acpi_match); static const struct i2c_device_id jsa1212_id[] = { - { JSA1212_DRIVER_NAME }, + { .name = JSA1212_DRIVER_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, jsa1212_id); diff --git a/drivers/iio/light/ltr390.c b/drivers/iio/light/ltr390.c index fc387426fa87..bc031f2c3141 100644 --- a/drivers/iio/light/ltr390.c +++ b/drivers/iio/light/ltr390.c @@ -101,7 +101,7 @@ enum ltr390_meas_rate { struct ltr390_data { struct regmap *regmap; struct i2c_client *client; - /* Protects device from simulataneous reads */ + /* Protects device from simultaneous reads */ struct mutex lock; enum ltr390_mode mode; int gain; @@ -838,8 +838,7 @@ static int ltr390_probe(struct i2c_client *client) "ltr390_thresh_event", indio_dev); if (ret) - return dev_err_probe(dev, ret, - "request irq (%d) failed\n", client->irq); + return ret; } ret = ltr390_pm_init(data); @@ -889,7 +888,7 @@ static const struct dev_pm_ops ltr390_pm_ops = { }; static const struct i2c_device_id ltr390_id[] = { - { "ltr390" }, + { .name = "ltr390" }, { } }; MODULE_DEVICE_TABLE(i2c, ltr390_id); diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c index 022e0693983b..fa0d16890c8b 100644 --- a/drivers/iio/light/ltr501.c +++ b/drivers/iio/light/ltr501.c @@ -10,7 +10,6 @@ */ #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/err.h> #include <linux/delay.h> @@ -754,7 +753,7 @@ static int ltr501_get_gain_index(const struct ltr501_gain *gain, int size, if (val == gain[i].scale && val2 == gain[i].uscale) return i; - return -1; + return -EINVAL; } static int __ltr501_write_raw(struct iio_dev *indio_dev, @@ -773,7 +772,7 @@ static int __ltr501_write_raw(struct iio_dev *indio_dev, info->als_gain_tbl_size, val, val2); if (i < 0) - return -EINVAL; + return i; data->als_contr &= ~info->als_gain_mask; data->als_contr |= i << info->als_gain_shift; @@ -785,7 +784,7 @@ static int __ltr501_write_raw(struct iio_dev *indio_dev, info->ps_gain_tbl_size, val, val2); if (i < 0) - return -EINVAL; + return i; data->ps_contr &= ~LTR501_CONTR_PS_GAIN_MASK; data->ps_contr |= i << LTR501_CONTR_PS_GAIN_SHIFT; @@ -1538,11 +1537,8 @@ static int ltr501_probe(struct i2c_client *client) IRQF_ONESHOT, "ltr501_thresh_event", indio_dev); - if (ret) { - dev_err(&client->dev, "request irq (%d) failed\n", - client->irq); + if (ret) return ret; - } } else { indio_dev->info = data->chip_info->info_no_irq; } @@ -1601,10 +1597,10 @@ static const struct acpi_device_id ltr_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, ltr_acpi_match); static const struct i2c_device_id ltr501_id[] = { - { "ltr501", ltr501 }, - { "ltr559", ltr559 }, - { "ltr301", ltr301 }, - { "ltr303", ltr303 }, + { .name = "ltr501", .driver_data = ltr501 }, + { .name = "ltr559", .driver_data = ltr559 }, + { .name = "ltr301", .driver_data = ltr301 }, + { .name = "ltr303", .driver_data = ltr303 }, { } }; MODULE_DEVICE_TABLE(i2c, ltr501_id); diff --git a/drivers/iio/light/ltrf216a.c b/drivers/iio/light/ltrf216a.c index 5f27f754fe1c..0a8851342039 100644 --- a/drivers/iio/light/ltrf216a.c +++ b/drivers/iio/light/ltrf216a.c @@ -17,7 +17,6 @@ #include <linux/i2c.h> #include <linux/init.h> #include <linux/iopoll.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/pm.h> @@ -248,11 +247,10 @@ static int ltrf216a_get_lux(struct ltrf216a_data *data) return ret; greendata = ltrf216a_read_data(data, LTRF216A_ALS_DATA_0); + ltrf216a_set_power_state(data, false); if (greendata < 0) return greendata; - ltrf216a_set_power_state(data, false); - lux = greendata * data->info->lux_multiplier * LTRF216A_WIN_FAC; return lux; @@ -551,8 +549,8 @@ static const struct ltr_chip_info ltrf216a_chip_info = { }; static const struct i2c_device_id ltrf216a_id[] = { - { "ltr308", .driver_data = (kernel_ulong_t)<r308_chip_info }, - { "ltrf216a", .driver_data = (kernel_ulong_t)<rf216a_chip_info }, + { .name = "ltr308", .driver_data = (kernel_ulong_t)<r308_chip_info }, + { .name = "ltrf216a", .driver_data = (kernel_ulong_t)<rf216a_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, ltrf216a_id); diff --git a/drivers/iio/light/lv0104cs.c b/drivers/iio/light/lv0104cs.c index 916109ec3217..eba82c334d70 100644 --- a/drivers/iio/light/lv0104cs.c +++ b/drivers/iio/light/lv0104cs.c @@ -510,7 +510,7 @@ static int lv0104cs_probe(struct i2c_client *client) } static const struct i2c_device_id lv0104cs_id[] = { - { "lv0104cs" }, + { .name = "lv0104cs" }, { } }; MODULE_DEVICE_TABLE(i2c, lv0104cs_id); diff --git a/drivers/iio/light/max44000.c b/drivers/iio/light/max44000.c index 039d45af3a7f..8c344f1b3fe2 100644 --- a/drivers/iio/light/max44000.c +++ b/drivers/iio/light/max44000.c @@ -10,7 +10,6 @@ */ #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/init.h> #include <linux/i2c.h> #include <linux/regmap.h> @@ -598,7 +597,7 @@ static int max44000_probe(struct i2c_client *client) } static const struct i2c_device_id max44000_id[] = { - { "max44000" }, + { .name = "max44000" }, { } }; MODULE_DEVICE_TABLE(i2c, max44000_id); diff --git a/drivers/iio/light/max44009.c b/drivers/iio/light/max44009.c index 8cd7f5664e5b..82b8a806c5fa 100644 --- a/drivers/iio/light/max44009.c +++ b/drivers/iio/light/max44009.c @@ -534,7 +534,7 @@ static const struct of_device_id max44009_of_match[] = { MODULE_DEVICE_TABLE(of, max44009_of_match); static const struct i2c_device_id max44009_id[] = { - { "max44009" }, + { .name = "max44009" }, { } }; MODULE_DEVICE_TABLE(i2c, max44009_id); diff --git a/drivers/iio/light/noa1305.c b/drivers/iio/light/noa1305.c index 25f63da70297..6731f1d9ec1c 100644 --- a/drivers/iio/light/noa1305.c +++ b/drivers/iio/light/noa1305.c @@ -315,7 +315,7 @@ static const struct of_device_id noa1305_of_match[] = { MODULE_DEVICE_TABLE(of, noa1305_of_match); static const struct i2c_device_id noa1305_ids[] = { - { "noa1305" }, + { .name = "noa1305" }, { } }; MODULE_DEVICE_TABLE(i2c, noa1305_ids); diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c index 393a3d2fbe1d..a948353014ac 100644 --- a/drivers/iio/light/opt3001.c +++ b/drivers/iio/light/opt3001.c @@ -8,18 +8,19 @@ * Based on previous work from: Felipe Balbi <balbi@ti.com> */ -#include <linux/bitops.h> +#include <linux/array_size.h> +#include <linux/bits.h> +#include <linux/cleanup.h> #include <linux/delay.h> -#include <linux/device.h> +#include <linux/dev_printk.h> +#include <linux/errno.h> #include <linux/i2c.h> #include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/kernel.h> +#include <linux/jiffies.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/mutex.h> -#include <linux/slab.h> #include <linux/types.h> +#include <linux/wait.h> #include <linux/iio/events.h> #include <linux/iio/iio.h> @@ -32,17 +33,16 @@ #define OPT3001_MANUFACTURER_ID 0x7e #define OPT3001_DEVICE_ID 0x7f -#define OPT3001_CONFIGURATION_RN_MASK (0xf << 12) +#define OPT3001_CONFIGURATION_RN_MASK GENMASK(15, 12) #define OPT3001_CONFIGURATION_RN_AUTO (0xc << 12) #define OPT3001_CONFIGURATION_CT BIT(11) -#define OPT3001_CONFIGURATION_M_MASK (3 << 9) +#define OPT3001_CONFIGURATION_M_MASK GENMASK(10, 9) #define OPT3001_CONFIGURATION_M_SHUTDOWN (0 << 9) #define OPT3001_CONFIGURATION_M_SINGLE (1 << 9) #define OPT3001_CONFIGURATION_M_CONTINUOUS (2 << 9) /* also 3 << 9 */ -#define OPT3001_CONFIGURATION_OVF BIT(8) #define OPT3001_CONFIGURATION_CRF BIT(7) #define OPT3001_CONFIGURATION_FH BIT(6) #define OPT3001_CONFIGURATION_FL BIT(5) @@ -50,7 +50,7 @@ #define OPT3001_CONFIGURATION_POL BIT(3) #define OPT3001_CONFIGURATION_ME BIT(2) -#define OPT3001_CONFIGURATION_FC_MASK (3 << 0) +#define OPT3001_CONFIGURATION_FC_MASK GENMASK(1, 0) /* The end-of-conversion enable is located in the low-limit register */ #define OPT3001_LOW_LIMIT_EOC_ENABLE 0xc000 @@ -91,7 +91,7 @@ struct opt3001_chip_info { */ int factor_integer; /* - * Factor used to align decimal part of proccessed value to six decimal + * Factor used to align decimal part of processed value to six decimal * places. */ int factor_decimal; @@ -101,9 +101,14 @@ struct opt3001_chip_info { struct opt3001 { struct i2c_client *client; - struct device *dev; + /* + * Ensure data capture and read-modify-write sequences are + * not interrupted. + */ struct mutex lock; + + /* Allows for IRQs to bypass locking mechanism */ bool ok_to_ignore_lock; bool result_ready; wait_queue_head_t result_ready_queue; @@ -224,11 +229,10 @@ static const struct opt3001_scale opt3002_scales[] = { }, }; -static int opt3001_find_scale(const struct opt3001 *opt, int val, - int val2, u8 *exponent) +static int opt3001_find_scale(const struct opt3001 *opt, int val, int val2, + u8 *exponent) { - int i; - for (i = 0; i < ARRAY_SIZE(*opt->chip_info->scales); i++) { + for (unsigned int i = 0; i < ARRAY_SIZE(*opt->chip_info->scales); i++) { const struct opt3001_scale *scale = &(*opt->chip_info->scales)[i]; /* * Compare the integer and micro parts to determine value scale. @@ -243,8 +247,8 @@ static int opt3001_find_scale(const struct opt3001 *opt, int val, return -EINVAL; } -static void opt3001_to_iio_ret(struct opt3001 *opt, u8 exponent, - u16 mantissa, int *val, int *val2) +static void opt3001_to_iio_ret(struct opt3001 *opt, u8 exponent, u16 mantissa, + int *val, int *val2) { int ret; int whole = opt->chip_info->factor_whole; @@ -311,121 +315,143 @@ static const struct iio_chan_spec opt3002_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(1), }; -static int opt3001_get_processed(struct opt3001 *opt, int *val, int *val2) +static int opt3001_start_conversion(struct opt3001 *opt) { - int ret; - u16 mantissa; + struct i2c_client *client = opt->client; + struct device *dev = &client->dev; u16 reg; - u8 exponent; - u16 value; - long timeout; - - if (opt->use_irq) { - /* - * Enable the end-of-conversion interrupt mechanism. Note that - * doing so will overwrite the low-level limit value however we - * will restore this value later on. - */ - ret = i2c_smbus_write_word_swapped(opt->client, - OPT3001_LOW_LIMIT, - OPT3001_LOW_LIMIT_EOC_ENABLE); - if (ret < 0) { - dev_err(opt->dev, "failed to write register %02x\n", - OPT3001_LOW_LIMIT); - return ret; - } - - /* Allow IRQ to access the device despite lock being set */ - opt->ok_to_ignore_lock = true; - } + int ret; /* Reset data-ready indicator flag */ opt->result_ready = false; /* Configure for single-conversion mode and start a new conversion */ - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION); if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_CONFIGURATION); - goto err; + dev_err(dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + return ret; } reg = ret; opt3001_set_mode(opt, ®, OPT3001_CONFIGURATION_M_SINGLE); - ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, - reg); + ret = i2c_smbus_write_word_swapped(client, OPT3001_CONFIGURATION, reg); + if (ret) + dev_err(dev, "failed to write register %02x\n", + OPT3001_CONFIGURATION); + + return ret; +} + +static int opt3001_get_processed_irq(struct opt3001 *opt) +{ + struct i2c_client *client = opt->client; + struct device *dev = &client->dev; + u16 value; + int ret; + + /* + * Enable the end-of-conversion interrupt mechanism. Note that doing so + * will overwrite the low-level limit value however we will restore this + * value later on. + */ + ret = i2c_smbus_write_word_swapped(client, + OPT3001_LOW_LIMIT, + OPT3001_LOW_LIMIT_EOC_ENABLE); if (ret < 0) { - dev_err(opt->dev, "failed to write register %02x\n", - OPT3001_CONFIGURATION); - goto err; + dev_err(dev, "failed to write register %02x\n", + OPT3001_LOW_LIMIT); + return ret; } - if (opt->use_irq) { - /* Wait for the IRQ to indicate the conversion is complete */ - ret = wait_event_timeout(opt->result_ready_queue, - opt->result_ready, - msecs_to_jiffies(OPT3001_RESULT_READY_LONG)); - if (ret == 0) - return -ETIMEDOUT; - } else { - /* Sleep for result ready time */ - timeout = (opt->int_time == OPT3001_INT_TIME_SHORT) ? - OPT3001_RESULT_READY_SHORT : OPT3001_RESULT_READY_LONG; - msleep(timeout); - - /* Check result ready flag */ - ret = i2c_smbus_read_word_swapped(opt->client, - OPT3001_CONFIGURATION); - if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_CONFIGURATION); - goto err; - } + /* Allow IRQ to access the device despite lock being set */ + opt->ok_to_ignore_lock = true; - if (!(ret & OPT3001_CONFIGURATION_CRF)) { - ret = -ETIMEDOUT; - goto err; - } + ret = opt3001_start_conversion(opt); + if (ret) + goto err; - /* Obtain value */ - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_RESULT); - if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_RESULT); - goto err; - } - opt->result = ret; - opt->result_ready = true; - } + if (wait_event_timeout(opt->result_ready_queue, opt->result_ready, + msecs_to_jiffies(OPT3001_RESULT_READY_LONG))) + ret = 0; + else + ret = -ETIMEDOUT; err: - if (opt->use_irq) - /* Disallow IRQ to access the device while lock is active */ - opt->ok_to_ignore_lock = false; + opt->ok_to_ignore_lock = false; if (ret < 0) return ret; - if (opt->use_irq) { - /* - * Disable the end-of-conversion interrupt mechanism by - * restoring the low-level limit value (clearing - * OPT3001_LOW_LIMIT_EOC_ENABLE). Note that selectively clearing - * those enable bits would affect the actual limit value due to - * bit-overlap and therefore can't be done. - */ - value = (opt->low_thresh_exp << 12) | opt->low_thresh_mantissa; - ret = i2c_smbus_write_word_swapped(opt->client, - OPT3001_LOW_LIMIT, - value); - if (ret < 0) { - dev_err(opt->dev, "failed to write register %02x\n", - OPT3001_LOW_LIMIT); - return ret; - } + /* + * Disable the end-of-conversion interrupt mechanism by restoring the + * low-level limit value (clearing OPT3001_LOW_LIMIT_EOC_ENABLE). Note + * that selectively clearing those enable bits would affect the actual + * limit value due to bit-overlap and therefore can't be done. + */ + value = (opt->low_thresh_exp << 12) | opt->low_thresh_mantissa; + ret = i2c_smbus_write_word_swapped(client, OPT3001_LOW_LIMIT, value); + if (ret) + dev_err(dev, "failed to write register %02x\n", + OPT3001_LOW_LIMIT); + + return ret; +} + +static int opt3001_get_processed_noirq(struct opt3001 *opt) +{ + struct i2c_client *client = opt->client; + struct device *dev = &client->dev; + int ret; + + ret = opt3001_start_conversion(opt); + if (ret) + return ret; + + if (opt->int_time == OPT3001_INT_TIME_SHORT) + msleep(OPT3001_RESULT_READY_SHORT); + else + msleep(OPT3001_RESULT_READY_LONG); + + /* Check result ready flag */ + ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION); + if (ret < 0) { + dev_err(dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + return ret; } + if (!(ret & OPT3001_CONFIGURATION_CRF)) + return -ETIMEDOUT; + + /* Obtain value */ + ret = i2c_smbus_read_word_swapped(client, OPT3001_RESULT); + if (ret < 0) { + dev_err(dev, "failed to read register %02x\n", + OPT3001_RESULT); + return ret; + } + + opt->result = ret; + opt->result_ready = true; + + return 0; +} + +static int opt3001_get_processed(struct opt3001 *opt, int *val, int *val2) +{ + u16 mantissa; + u8 exponent; + int ret; + + if (opt->use_irq) + ret = opt3001_get_processed_irq(opt); + else + ret = opt3001_get_processed_noirq(opt); + if (ret) + return ret; + exponent = OPT3001_REG_EXPONENT(opt->result); mantissa = OPT3001_REG_MANTISSA(opt->result); @@ -444,13 +470,15 @@ static int opt3001_get_int_time(struct opt3001 *opt, int *val, int *val2) static int opt3001_set_int_time(struct opt3001 *opt, int time) { + struct i2c_client *client = opt->client; + struct device *dev = &client->dev; int ret; u16 reg; - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION); if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_CONFIGURATION); + dev_err(dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); return ret; } @@ -469,16 +497,14 @@ static int opt3001_set_int_time(struct opt3001 *opt, int time) return -EINVAL; } - return i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, - reg); + return i2c_smbus_write_word_swapped(client, OPT3001_CONFIGURATION, reg); } static int opt3001_read_raw(struct iio_dev *iio, - struct iio_chan_spec const *chan, int *val, int *val2, - long mask) + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { struct opt3001 *opt = iio_priv(iio); - int ret; if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS) return -EBUSY; @@ -486,31 +512,24 @@ static int opt3001_read_raw(struct iio_dev *iio, if (chan->type != opt->chip_info->chan_type) return -EINVAL; - mutex_lock(&opt->lock); + guard(mutex)(&opt->lock); switch (mask) { case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_PROCESSED: - ret = opt3001_get_processed(opt, val, val2); - break; + return opt3001_get_processed(opt, val, val2); case IIO_CHAN_INFO_INT_TIME: - ret = opt3001_get_int_time(opt, val, val2); - break; + return opt3001_get_int_time(opt, val, val2); default: - ret = -EINVAL; + return -EINVAL; } - - mutex_unlock(&opt->lock); - - return ret; } static int opt3001_write_raw(struct iio_dev *iio, - struct iio_chan_spec const *chan, int val, int val2, - long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct opt3001 *opt = iio_priv(iio); - int ret; if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS) return -EBUSY; @@ -524,47 +543,46 @@ static int opt3001_write_raw(struct iio_dev *iio, if (val != 0) return -EINVAL; - mutex_lock(&opt->lock); - ret = opt3001_set_int_time(opt, val2); - mutex_unlock(&opt->lock); + guard(mutex)(&opt->lock); - return ret; + return opt3001_set_int_time(opt, val2); } static int opt3001_read_event_value(struct iio_dev *iio, - const struct iio_chan_spec *chan, enum iio_event_type type, - enum iio_event_direction dir, enum iio_event_info info, - int *val, int *val2) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) { struct opt3001 *opt = iio_priv(iio); - int ret = IIO_VAL_INT_PLUS_MICRO; - mutex_lock(&opt->lock); + guard(mutex)(&opt->lock); switch (dir) { case IIO_EV_DIR_RISING: opt3001_to_iio_ret(opt, opt->high_thresh_exp, - opt->high_thresh_mantissa, val, val2); - break; + opt->high_thresh_mantissa, val, val2); + return IIO_VAL_INT_PLUS_MICRO; case IIO_EV_DIR_FALLING: opt3001_to_iio_ret(opt, opt->low_thresh_exp, - opt->low_thresh_mantissa, val, val2); - break; + opt->low_thresh_mantissa, val, val2); + return IIO_VAL_INT_PLUS_MICRO; default: - ret = -EINVAL; + return -EINVAL; } - - mutex_unlock(&opt->lock); - - return ret; } static int opt3001_write_event_value(struct iio_dev *iio, - const struct iio_chan_spec *chan, enum iio_event_type type, - enum iio_event_direction dir, enum iio_event_info info, - int val, int val2) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) { struct opt3001 *opt = iio_priv(iio); + struct i2c_client *client = opt->client; + struct device *dev = &client->dev; int ret; int whole; int integer; @@ -579,12 +597,12 @@ static int opt3001_write_event_value(struct iio_dev *iio, if (val < 0) return -EINVAL; - mutex_lock(&opt->lock); + guard(mutex)(&opt->lock); ret = opt3001_find_scale(opt, val, val2, &exponent); if (ret < 0) { - dev_err(opt->dev, "can't find scale for %d.%06u\n", val, val2); - goto err; + dev_err(dev, "can't find scale for %d.%06u\n", val, val2); + return ret; } whole = opt->chip_info->factor_whole; @@ -607,25 +625,22 @@ static int opt3001_write_event_value(struct iio_dev *iio, opt->low_thresh_exp = exponent; break; default: - ret = -EINVAL; - goto err; + return -EINVAL; } - ret = i2c_smbus_write_word_swapped(opt->client, reg, value); + ret = i2c_smbus_write_word_swapped(client, reg, value); if (ret < 0) { - dev_err(opt->dev, "failed to write register %02x\n", reg); - goto err; + dev_err(dev, "failed to write register %02x\n", reg); + return ret; } -err: - mutex_unlock(&opt->lock); - - return ret; + return 0; } static int opt3001_read_event_config(struct iio_dev *iio, - const struct iio_chan_spec *chan, enum iio_event_type type, - enum iio_event_direction dir) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) { struct opt3001 *opt = iio_priv(iio); @@ -633,10 +648,14 @@ static int opt3001_read_event_config(struct iio_dev *iio, } static int opt3001_write_event_config(struct iio_dev *iio, - const struct iio_chan_spec *chan, enum iio_event_type type, - enum iio_event_direction dir, bool state) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + bool state) { struct opt3001 *opt = iio_priv(iio); + struct i2c_client *client = opt->client; + struct device *dev = &client->dev; int ret; u16 mode; u16 reg; @@ -647,33 +666,29 @@ static int opt3001_write_event_config(struct iio_dev *iio, if (!state && opt->mode == OPT3001_CONFIGURATION_M_SHUTDOWN) return 0; - mutex_lock(&opt->lock); + guard(mutex)(&opt->lock); mode = state ? OPT3001_CONFIGURATION_M_CONTINUOUS : OPT3001_CONFIGURATION_M_SHUTDOWN; - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION); if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_CONFIGURATION); - goto err; + dev_err(dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + return ret; } reg = ret; opt3001_set_mode(opt, ®, mode); - ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, - reg); + ret = i2c_smbus_write_word_swapped(client, OPT3001_CONFIGURATION, reg); if (ret < 0) { - dev_err(opt->dev, "failed to write register %02x\n", - OPT3001_CONFIGURATION); - goto err; + dev_err(dev, "failed to write register %02x\n", + OPT3001_CONFIGURATION); + return ret; } -err: - mutex_unlock(&opt->lock); - - return ret; + return 0; } static const struct iio_info opt3001_info = { @@ -688,47 +703,69 @@ static const struct iio_info opt3001_info = { static int opt3001_read_id(struct opt3001 *opt) { + struct i2c_client *client = opt->client; + struct device *dev = &client->dev; char manufacturer[2]; u16 device_id; int ret; - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_MANUFACTURER_ID); - if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_MANUFACTURER_ID); - return ret; - } + ret = i2c_smbus_read_word_swapped(client, OPT3001_MANUFACTURER_ID); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to read register %02x\n", + OPT3001_MANUFACTURER_ID); manufacturer[0] = ret >> 8; manufacturer[1] = ret & 0xff; - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_DEVICE_ID); - if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_DEVICE_ID); - return ret; - } + ret = i2c_smbus_read_word_swapped(client, OPT3001_DEVICE_ID); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to read register %02x\n", + OPT3001_DEVICE_ID); device_id = ret; - dev_info(opt->dev, "Found %c%c OPT%04x\n", manufacturer[0], - manufacturer[1], device_id); + dev_info(dev, "Found %c%c OPT%04x\n", manufacturer[0], manufacturer[1], + device_id); return 0; } -static int opt3001_configure(struct opt3001 *opt) +static void opt3001_power_off(void *data) { + struct opt3001 *opt = data; + struct i2c_client *client = opt->client; + struct device *dev = &client->dev; + u16 reg_val; int ret; - u16 reg; - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION); if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_CONFIGURATION); - return ret; + dev_err(dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + return; } + reg_val = ret; + opt3001_set_mode(opt, ®_val, OPT3001_CONFIGURATION_M_SHUTDOWN); + + ret = i2c_smbus_write_word_swapped(client, OPT3001_CONFIGURATION, reg_val); + if (ret < 0) + dev_err(dev, "failed to write to register %02x\n", + OPT3001_CONFIGURATION); +} + +static int opt3001_configure(struct opt3001 *opt) +{ + struct i2c_client *client = opt->client; + struct device *dev = &client->dev; + int ret; + u16 reg; + + ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + reg = ret; /* Enable automatic full-scale setting mode */ @@ -750,30 +787,28 @@ static int opt3001_configure(struct opt3001 *opt) reg &= ~OPT3001_CONFIGURATION_ME; reg &= ~OPT3001_CONFIGURATION_FC_MASK; - ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, - reg); - if (ret < 0) { - dev_err(opt->dev, "failed to write register %02x\n", - OPT3001_CONFIGURATION); - return ret; - } + ret = i2c_smbus_write_word_swapped(client, OPT3001_CONFIGURATION, reg); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to write register %02x\n", + OPT3001_CONFIGURATION); - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_LOW_LIMIT); - if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_LOW_LIMIT); - return ret; - } + ret = devm_add_action_or_reset(dev, opt3001_power_off, opt); + if (ret) + return dev_err_probe(dev, ret, + "failed to register power off function\n"); + + ret = i2c_smbus_read_word_swapped(client, OPT3001_LOW_LIMIT); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to read register %02x\n", + OPT3001_LOW_LIMIT); opt->low_thresh_mantissa = OPT3001_REG_MANTISSA(ret); opt->low_thresh_exp = OPT3001_REG_EXPONENT(ret); - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_HIGH_LIMIT); - if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_HIGH_LIMIT); - return ret; - } + ret = i2c_smbus_read_word_swapped(client, OPT3001_HIGH_LIMIT); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to read register %02x\n", + OPT3001_HIGH_LIMIT); opt->high_thresh_mantissa = OPT3001_REG_MANTISSA(ret); opt->high_thresh_exp = OPT3001_REG_EXPONENT(ret); @@ -785,6 +820,8 @@ static irqreturn_t opt3001_irq(int irq, void *_iio) { struct iio_dev *iio = _iio; struct opt3001 *opt = iio_priv(iio); + struct i2c_client *client = opt->client; + struct device *dev = &client->dev; int ret; bool wake_result_ready_queue = false; enum iio_chan_type chan_type = opt->chip_info->chan_type; @@ -793,10 +830,10 @@ static irqreturn_t opt3001_irq(int irq, void *_iio) if (!ok_to_ignore_lock) mutex_lock(&opt->lock); - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + ret = i2c_smbus_read_word_swapped(client, OPT3001_CONFIGURATION); if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_CONFIGURATION); + dev_err(dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); goto out; } @@ -804,21 +841,21 @@ static irqreturn_t opt3001_irq(int irq, void *_iio) OPT3001_CONFIGURATION_M_CONTINUOUS) { if (ret & OPT3001_CONFIGURATION_FH) iio_push_event(iio, - IIO_UNMOD_EVENT_CODE(chan_type, 0, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_RISING), - iio_get_time_ns(iio)); + IIO_UNMOD_EVENT_CODE(chan_type, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + iio_get_time_ns(iio)); if (ret & OPT3001_CONFIGURATION_FL) iio_push_event(iio, - IIO_UNMOD_EVENT_CODE(chan_type, 0, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_FALLING), - iio_get_time_ns(iio)); + IIO_UNMOD_EVENT_CODE(chan_type, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + iio_get_time_ns(iio)); } else if (ret & OPT3001_CONFIGURATION_CRF) { - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_RESULT); + ret = i2c_smbus_read_word_swapped(client, OPT3001_RESULT); if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_RESULT); + dev_err(dev, "failed to read register %02x\n", + OPT3001_RESULT); goto out; } opt->result = ret; @@ -851,12 +888,13 @@ static int opt3001_probe(struct i2c_client *client) opt = iio_priv(iio); opt->client = client; - opt->dev = dev; opt->chip_info = i2c_get_match_data(client); - mutex_init(&opt->lock); + ret = devm_mutex_init(dev, &opt->lock); + if (ret) + return ret; + init_waitqueue_head(&opt->result_ready_queue); - i2c_set_clientdata(client, iio); if (opt->chip_info->has_id) { ret = opt3001_read_id(opt); @@ -874,55 +912,20 @@ static int opt3001_probe(struct i2c_client *client) iio->modes = INDIO_DIRECT_MODE; iio->info = &opt3001_info; - ret = devm_iio_device_register(dev, iio); - if (ret) { - dev_err(dev, "failed to register IIO device\n"); - return ret; - } - /* Make use of INT pin only if valid IRQ no. is given */ if (irq > 0) { - ret = request_threaded_irq(irq, NULL, opt3001_irq, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - "opt3001", iio); - if (ret) { - dev_err(dev, "failed to request IRQ #%d\n", irq); + ret = devm_request_threaded_irq(dev, irq, NULL, opt3001_irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "opt3001", iio); + if (ret) return ret; - } + opt->use_irq = true; } else { - dev_dbg(opt->dev, "enabling interrupt-less operation\n"); - } - - return 0; -} - -static void opt3001_remove(struct i2c_client *client) -{ - struct iio_dev *iio = i2c_get_clientdata(client); - struct opt3001 *opt = iio_priv(iio); - int ret; - u16 reg; - - if (opt->use_irq) - free_irq(client->irq, iio); - - ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); - if (ret < 0) { - dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_CONFIGURATION); - return; + dev_dbg(dev, "enabling interrupt-less operation\n"); } - reg = ret; - opt3001_set_mode(opt, ®, OPT3001_CONFIGURATION_M_SHUTDOWN); - - ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, - reg); - if (ret < 0) { - dev_err(opt->dev, "failed to write register %02x\n", - OPT3001_CONFIGURATION); - } + return devm_iio_device_register(dev, iio); } static const struct opt3001_chip_info opt3001_chip_information = { @@ -948,8 +951,8 @@ static const struct opt3001_chip_info opt3002_chip_information = { }; static const struct i2c_device_id opt3001_id[] = { - { "opt3001", (kernel_ulong_t)&opt3001_chip_information }, - { "opt3002", (kernel_ulong_t)&opt3002_chip_information }, + { .name = "opt3001", .driver_data = (kernel_ulong_t)&opt3001_chip_information }, + { .name = "opt3002", .driver_data = (kernel_ulong_t)&opt3002_chip_information }, { } /* Terminating Entry */ }; MODULE_DEVICE_TABLE(i2c, opt3001_id); @@ -963,7 +966,6 @@ MODULE_DEVICE_TABLE(of, opt3001_of_match); static struct i2c_driver opt3001_driver = { .probe = opt3001_probe, - .remove = opt3001_remove, .id_table = opt3001_id, .driver = { diff --git a/drivers/iio/light/opt4001.c b/drivers/iio/light/opt4001.c index 95167273bb90..aa3d87995b7c 100644 --- a/drivers/iio/light/opt4001.c +++ b/drivers/iio/light/opt4001.c @@ -39,7 +39,7 @@ #define OPT4001_CTRL_OPER_MODE_MASK GENMASK(5, 4) #define OPT4001_CTRL_LATCH_MASK GENMASK(3, 3) #define OPT4001_CTRL_INT_POL_MASK GENMASK(2, 2) -#define OPT4001_CTRL_FAULT_COUNT GENMASK(0, 1) +#define OPT4001_CTRL_FAULT_COUNT_MASK GENMASK(1, 0) /* OPT4001 constants */ #define OPT4001_DEVICE_ID_VAL 0x121 @@ -173,6 +173,7 @@ static int opt4001_read_lux_value(struct iio_dev *indio_dev, u8 crc; u8 calc_crc; u64 lux_raw; + u32 rem; int ret; ret = regmap_read(chip->regmap, OPT4001_LIGHT1_MSB, &light1); @@ -199,8 +200,8 @@ static int opt4001_read_lux_value(struct iio_dev *indio_dev, lux_raw = lux_raw << exp; lux_raw = lux_raw * chip->chip_info->mul; - *val = div_u64_rem(lux_raw, chip->chip_info->div, val2); - *val2 = *val2 * 100; + *val = div_u64_rem(lux_raw, chip->chip_info->div, &rem); + *val2 = rem * 100; return IIO_VAL_INT_PLUS_NANO; } @@ -222,33 +223,14 @@ static int opt4001_set_conf(struct opt4001_chip *chip) return ret; } -static int opt4001_power_down(struct opt4001_chip *chip) -{ - struct device *dev = &chip->client->dev; - int ret; - unsigned int reg; - - ret = regmap_read(chip->regmap, OPT4001_DEVICE_ID, ®); - if (ret) { - dev_err(dev, "Failed to read configuration\n"); - return ret; - } - - /* MODE_OFF is 0x0 so just set bits to 0 */ - reg &= ~OPT4001_CTRL_OPER_MODE_MASK; - - ret = regmap_write(chip->regmap, OPT4001_CTRL, reg); - if (ret) - dev_err(dev, "Failed to set configuration to power down\n"); - - return ret; -} - static void opt4001_chip_off_action(void *data) { struct opt4001_chip *chip = data; + int ret; - opt4001_power_down(chip); + ret = regmap_clear_bits(chip->regmap, OPT4001_CTRL, OPT4001_CTRL_OPER_MODE_MASK); + if (ret) + dev_err(&chip->client->dev, "Failed to power down\n"); } static const struct iio_chan_spec opt4001_channels[] = { @@ -287,6 +269,9 @@ static int opt4001_write_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_INT_TIME: + if (val) + return -EINVAL; + int_time = opt4001_als_time_to_index(val2); if (int_time < 0) return int_time; @@ -438,8 +423,8 @@ static int opt4001_probe(struct i2c_client *client) * opt4001 packaging */ static const struct i2c_device_id opt4001_id[] = { - { "opt4001-sot-5x3", (kernel_ulong_t)&opt4001_sot_5x3_info }, - { "opt4001-picostar", (kernel_ulong_t)&opt4001_picostar_info }, + { .name = "opt4001-sot-5x3", .driver_data = (kernel_ulong_t)&opt4001_sot_5x3_info }, + { .name = "opt4001-picostar", .driver_data = (kernel_ulong_t)&opt4001_picostar_info }, { } }; MODULE_DEVICE_TABLE(i2c, opt4001_id); diff --git a/drivers/iio/light/opt4060.c b/drivers/iio/light/opt4060.c index d6e915ab355d..8253a6a8bee4 100644 --- a/drivers/iio/light/opt4060.c +++ b/drivers/iio/light/opt4060.c @@ -632,6 +632,9 @@ static int opt4060_write_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_INT_TIME: + if (val) + return -EINVAL; + int_time = opt4060_als_time_to_index(val2); if (int_time < 0) return int_time; @@ -710,6 +713,7 @@ static ssize_t opt4060_read_ev_period(struct opt4060_chip *chip, int *val, { int ret, pers, fault_count, int_time; u64 uval; + u32 rem; int_time = opt4060_int_time_reg[chip->int_time][0]; @@ -735,7 +739,8 @@ static ssize_t opt4060_read_ev_period(struct opt4060_chip *chip, int *val, } uval = mul_u32_u32(int_time, pers); - *val = div_u64_rem(uval, MICRO, val2); + *val = div_u64_rem(uval, MICRO, &rem); + *val2 = rem; return IIO_VAL_INT_PLUS_MICRO; } @@ -805,7 +810,7 @@ static int opt4060_get_thresholds(struct opt4060_chip *chip, u32 *th_lo, u32 *th ret = regmap_read(chip->regmap, OPT4060_THRESHOLD_HIGH, ®val); if (ret) { - dev_err(chip->dev, "Failed to read THRESHOLD_LOW.\n"); + dev_err(chip->dev, "Failed to read THRESHOLD_HIGH.\n"); return ret; } *th_hi = opt4060_calc_val_from_th_reg(regval); @@ -1200,7 +1205,7 @@ static int opt4060_setup_trigger(struct opt4060_chip *chip, struct iio_dev *idev IRQF_TRIGGER_FALLING | IRQF_ONESHOT, name, idev); if (ret) - return dev_err_probe(chip->dev, ret, "Could not request IRQ\n"); + return ret; init_completion(&chip->completion); @@ -1297,7 +1302,7 @@ static int opt4060_probe(struct i2c_client *client) } static const struct i2c_device_id opt4060_id[] = { - { "opt4060", }, + { .name = "opt4060" }, { } }; MODULE_DEVICE_TABLE(i2c, opt4060_id); diff --git a/drivers/iio/light/pa12203001.c b/drivers/iio/light/pa12203001.c index 98a1f1624c75..c0f4db8d95f7 100644 --- a/drivers/iio/light/pa12203001.c +++ b/drivers/iio/light/pa12203001.c @@ -457,7 +457,7 @@ static const struct acpi_device_id pa12203001_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, pa12203001_acpi_match); static const struct i2c_device_id pa12203001_id[] = { - { "txcpa122" }, + { .name = "txcpa122" }, { } }; diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index 9341c1d58cbe..7d82efc31f3a 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -10,7 +10,6 @@ */ #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/cleanup.h> #include <linux/init.h> #include <linux/i2c.h> @@ -988,11 +987,8 @@ static int rpr0521_probe(struct i2c_client *client) rpr0521_drdy_irq_handler, rpr0521_drdy_irq_thread, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "rpr0521_event", indio_dev); - if (ret < 0) { - dev_err(&client->dev, "request irq %d for trigger0 failed\n", - client->irq); + if (ret) goto err_pm_disable; - } ret = devm_iio_trigger_register(indio_dev->dev.parent, data->drdy_trigger0); @@ -1072,7 +1068,10 @@ static int rpr0521_runtime_resume(struct device *dev) struct rpr0521_data *data = iio_priv(indio_dev); int ret; - regcache_sync(data->regmap); + ret = regcache_sync(data->regmap); + if (ret < 0) + return ret; + if (data->als_ps_need_en) { ret = rpr0521_als_enable(data, RPR0521_MODE_ALS_ENABLE); if (ret < 0) @@ -1102,7 +1101,7 @@ static const struct acpi_device_id rpr0521_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rpr0521_acpi_match); static const struct i2c_device_id rpr0521_id[] = { - { "rpr0521" }, + { .name = "rpr0521" }, { } }; diff --git a/drivers/iio/light/si1133.c b/drivers/iio/light/si1133.c index 44fa152dbd24..22073ded8081 100644 --- a/drivers/iio/light/si1133.c +++ b/drivers/iio/light/si1133.c @@ -6,19 +6,27 @@ * Copyright 2018 Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com> */ +#include <linux/array_size.h> +#include <linux/bitops.h> +#include <linux/cleanup.h> +#include <linux/completion.h> #include <linux/delay.h> +#include <linux/dev_printk.h> +#include <linux/err.h> #include <linux/i2c.h> #include <linux/interrupt.h> +#include <linux/jiffies.h> +#include <linux/math.h> #include <linux/module.h> +#include <linux/mutex.h> #include <linux/regmap.h> +#include <linux/types.h> +#include <linux/unaligned.h> +#include <linux/util_macros.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> -#include <linux/util_macros.h> - -#include <linux/unaligned.h> - #define SI1133_REG_PART_ID 0x00 #define SI1133_REG_REV_ID 0x01 #define SI1133_REG_MFR_ID 0x02 @@ -50,23 +58,23 @@ #define SI1133_MAX_CMD_CTR 0xF #define SI1133_PARAM_REG_CHAN_LIST 0x01 -#define SI1133_PARAM_REG_ADCCONFIG(x) ((x) * 4) + 2 -#define SI1133_PARAM_REG_ADCSENS(x) ((x) * 4) + 3 -#define SI1133_PARAM_REG_ADCPOST(x) ((x) * 4) + 4 +#define SI1133_PARAM_REG_ADCCONFIG(x) (((x) * 4) + 2) +#define SI1133_PARAM_REG_ADCSENS(x) (((x) * 4) + 3) +#define SI1133_PARAM_REG_ADCPOST(x) (((x) * 4) + 4) #define SI1133_ADCMUX_MASK 0x1F -#define SI1133_ADCCONFIG_DECIM_RATE(x) (x) << 5 +#define SI1133_ADCCONFIG_DECIM_RATE(x) ((x) << 5) #define SI1133_ADCSENS_SCALE_MASK 0x70 #define SI1133_ADCSENS_SCALE_SHIFT 4 #define SI1133_ADCSENS_HSIG_MASK BIT(7) #define SI1133_ADCSENS_HSIG_SHIFT 7 #define SI1133_ADCSENS_HW_GAIN_MASK 0xF -#define SI1133_ADCSENS_NB_MEAS(x) fls(x) << SI1133_ADCSENS_SCALE_SHIFT +#define SI1133_ADCSENS_NB_MEAS(x) (fls(x) << SI1133_ADCSENS_SCALE_SHIFT) #define SI1133_ADCPOST_24BIT_EN BIT(6) -#define SI1133_ADCPOST_POSTSHIFT_BITQTY(x) (x & GENMASK(2, 0)) << 3 +#define SI1133_ADCPOST_POSTSHIFT_BITQTY(x) (((x) & GENMASK(2, 0)) << 3) #define SI1133_PARAM_ADCMUX_SMALL_IR 0x0 #define SI1133_PARAM_ADCMUX_MED_IR 0x1 @@ -86,16 +94,12 @@ #define SI1133_CMD_MINSLEEP_US_LOW 5000 #define SI1133_CMD_MINSLEEP_US_HIGH 7500 #define SI1133_CMD_TIMEOUT_MS 25 -#define SI1133_CMD_LUX_TIMEOUT_MS 5000 -#define SI1133_CMD_TIMEOUT_US SI1133_CMD_TIMEOUT_MS * 1000 -#define SI1133_REG_HOSTOUT(x) (x) + 0x13 - -#define SI1133_MEASUREMENT_FREQUENCY 1250 +#define SI1133_REG_HOSTOUT(x) ((x) + 0x13) #define SI1133_X_ORDER_MASK 0x0070 #define SI1133_Y_ORDER_MASK 0x0007 -#define si1133_get_x_order(m) ((m) & SI1133_X_ORDER_MASK) >> 4 +#define si1133_get_x_order(m) (((m) & SI1133_X_ORDER_MASK) >> 4) #define si1133_get_y_order(m) ((m) & SI1133_Y_ORDER_MASK) #define SI1133_LUX_ADC_MASK 0xE @@ -386,35 +390,42 @@ static int si1133_cmd_reset_counter(struct si1133_data *data) static int si1133_command(struct si1133_data *data, u8 cmd) { + unsigned long timeout; struct device *dev = &data->client->dev; u32 resp; int err; int expected_seq; - mutex_lock(&data->mutex); + guard(mutex)(&data->mutex); expected_seq = (data->rsp_seq + 1) & SI1133_MAX_CMD_CTR; - if (cmd == SI1133_CMD_FORCE) + if (cmd == SI1133_CMD_FORCE) { + /* Flush pending IRQs from a previous timeout. */ + regmap_read(data->regmap, SI1133_REG_IRQ_STATUS, &resp); + regmap_write(data->regmap, SI1133_REG_IRQ_ENABLE, + SI1133_IRQ_CHANNEL_ENABLE); + reinit_completion(&data->completion); + } err = regmap_write(data->regmap, SI1133_REG_COMMAND, cmd); if (err) { dev_warn(dev, "Failed to write command 0x%02x, ret=%d\n", cmd, err); - goto out; + return err; } if (cmd == SI1133_CMD_FORCE) { /* wait for irq */ - if (!wait_for_completion_timeout(&data->completion, - msecs_to_jiffies(SI1133_COMPLETION_TIMEOUT_MS))) { - err = -ETIMEDOUT; - goto out; + timeout = msecs_to_jiffies(SI1133_COMPLETION_TIMEOUT_MS); + if (!wait_for_completion_timeout(&data->completion, timeout)) { + regmap_write(data->regmap, SI1133_REG_IRQ_ENABLE, 0); + return -ETIMEDOUT; } err = regmap_read(data->regmap, SI1133_REG_RESPONSE0, &resp); if (err) - goto out; + return err; } else { err = regmap_read_poll_timeout(data->regmap, SI1133_REG_RESPONSE0, resp, @@ -427,7 +438,12 @@ static int si1133_command(struct si1133_data *data, u8 cmd) dev_warn(dev, "Failed to read command 0x%02x, ret=%d\n", cmd, err); - goto out; + /* + * Reset counter on err to prevent software and hardware + * counters being out of sync. + */ + si1133_cmd_reset_counter(data); + return err; } } @@ -438,9 +454,6 @@ static int si1133_command(struct si1133_data *data, u8 cmd) data->rsp_seq = expected_seq; } -out: - mutex_unlock(&data->mutex); - return err; } @@ -1055,7 +1068,7 @@ static int si1133_probe(struct i2c_client *client) } static const struct i2c_device_id si1133_ids[] = { - { "si1133" }, + { .name = "si1133" }, { } }; MODULE_DEVICE_TABLE(i2c, si1133_ids); diff --git a/drivers/iio/light/si1145.c b/drivers/iio/light/si1145.c index ef0abc4499b7..bb7c99041819 100644 --- a/drivers/iio/light/si1145.c +++ b/drivers/iio/light/si1145.c @@ -1251,10 +1251,8 @@ static int si1145_probe_trigger(struct iio_dev *indio_dev) IRQF_TRIGGER_FALLING | IRQF_NO_THREAD, "si1145_irq", trig); - if (ret < 0) { - dev_err(&client->dev, "irq request failed\n"); + if (ret) return ret; - } ret = devm_iio_trigger_register(&client->dev, trig); if (ret) @@ -1334,13 +1332,13 @@ static int si1145_probe(struct i2c_client *client) } static const struct i2c_device_id si1145_ids[] = { - { "si1132", SI1132 }, - { "si1141", SI1141 }, - { "si1142", SI1142 }, - { "si1143", SI1143 }, - { "si1145", SI1145 }, - { "si1146", SI1146 }, - { "si1147", SI1147 }, + { .name = "si1132", .driver_data = SI1132 }, + { .name = "si1141", .driver_data = SI1141 }, + { .name = "si1142", .driver_data = SI1142 }, + { .name = "si1143", .driver_data = SI1143 }, + { .name = "si1145", .driver_data = SI1145 }, + { .name = "si1146", .driver_data = SI1146 }, + { .name = "si1147", .driver_data = SI1147 }, { } }; MODULE_DEVICE_TABLE(i2c, si1145_ids); diff --git a/drivers/iio/light/st_uvis25_core.c b/drivers/iio/light/st_uvis25_core.c index bcd729a9924e..94d5261b2663 100644 --- a/drivers/iio/light/st_uvis25_core.c +++ b/drivers/iio/light/st_uvis25_core.c @@ -196,11 +196,8 @@ static int st_uvis25_allocate_trigger(struct iio_dev *iio_dev) st_uvis25_trigger_handler_thread, irq_type | IRQF_ONESHOT, iio_dev->name, hw); - if (err) { - dev_err(dev, "failed to request trigger irq %d\n", - hw->irq); + if (err) return err; - } hw->trig = devm_iio_trigger_alloc(dev, "%s-trigger", iio_dev->name); diff --git a/drivers/iio/light/st_uvis25_i2c.c b/drivers/iio/light/st_uvis25_i2c.c index 5d9bb4d9be63..d6b5ba139dd4 100644 --- a/drivers/iio/light/st_uvis25_i2c.c +++ b/drivers/iio/light/st_uvis25_i2c.c @@ -9,7 +9,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/slab.h> #include <linux/regmap.h> @@ -46,7 +45,7 @@ static const struct of_device_id st_uvis25_i2c_of_match[] = { MODULE_DEVICE_TABLE(of, st_uvis25_i2c_of_match); static const struct i2c_device_id st_uvis25_i2c_id_table[] = { - { ST_UVIS25_DEV_NAME }, + { .name = ST_UVIS25_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, st_uvis25_i2c_id_table); diff --git a/drivers/iio/light/st_uvis25_spi.c b/drivers/iio/light/st_uvis25_spi.c index a5aad74ce73e..0f78a0abfafb 100644 --- a/drivers/iio/light/st_uvis25_spi.c +++ b/drivers/iio/light/st_uvis25_spi.c @@ -9,7 +9,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/spi/spi.h> #include <linux/slab.h> #include <linux/regmap.h> @@ -47,7 +46,7 @@ static const struct of_device_id st_uvis25_spi_of_match[] = { MODULE_DEVICE_TABLE(of, st_uvis25_spi_of_match); static const struct spi_device_id st_uvis25_spi_id_table[] = { - { ST_UVIS25_DEV_NAME }, + { .name = ST_UVIS25_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(spi, st_uvis25_spi_id_table); diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index a75a83594a7e..7c8a1d2b2ed0 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -7,15 +7,27 @@ * IIO driver for STK3310/STK3311. 7-bit I2C address: 0x48. */ +#include <linux/array_size.h> +#include <linux/bits.h> +#include <linux/dev_printk.h> +#include <linux/err.h> #include <linux/i2c.h> #include <linux/interrupt.h> -#include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> +#include <linux/mutex.h> +#include <linux/pm.h> +#include <linux/property.h> #include <linux/regmap.h> +#include <linux/sprintf.h> +#include <linux/sysfs.h> +#include <linux/types.h> + #include <linux/iio/events.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> +#include <linux/iio/types.h> + +#include <asm/byteorder.h> #define STK3310_REG_STATE 0x00 #define STK3310_REG_PSCTRL 0x01 @@ -115,9 +127,6 @@ static const int stk3310_it_table[][2] = { struct stk3310_data { struct i2c_client *client; struct mutex lock; - bool als_enabled; - bool ps_enabled; - uint32_t ps_near_level; u64 timestamp; struct regmap *regmap; struct regmap_field *reg_state; @@ -128,6 +137,12 @@ struct stk3310_data { struct regmap_field *reg_int_ps; struct regmap_field *reg_flag_psint; struct regmap_field *reg_flag_nf; + u32 ps_thdl; + u32 ps_thdh; + u32 ps_near_level; + bool als_enabled; + bool ps_enabled; + bool ps_int_enabled; }; static const struct iio_event_spec stk3310_events[] = { @@ -255,7 +270,7 @@ static int stk3310_read_event(struct iio_dev *indio_dev, return -EINVAL; mutex_lock(&data->lock); - ret = regmap_bulk_read(data->regmap, reg, &buf, 2); + ret = regmap_bulk_read(data->regmap, reg, &buf, sizeof(buf)); mutex_unlock(&data->lock); if (ret < 0) { dev_err(&data->client->dev, "register read failed\n"); @@ -295,11 +310,18 @@ static int stk3310_write_event(struct iio_dev *indio_dev, return -EINVAL; buf = cpu_to_be16(val); - ret = regmap_bulk_write(data->regmap, reg, &buf, 2); - if (ret < 0) + ret = regmap_bulk_write(data->regmap, reg, &buf, sizeof(buf)); + if (ret < 0) { dev_err(&client->dev, "failed to set PS threshold!\n"); + return ret; + } - return ret; + if (reg == STK3310_REG_THDH_PS) + data->ps_thdh = val; + else + data->ps_thdl = val; + + return 0; } static int stk3310_read_event_config(struct iio_dev *indio_dev, @@ -331,11 +353,17 @@ static int stk3310_write_event_config(struct iio_dev *indio_dev, /* Set INT_PS value */ mutex_lock(&data->lock); ret = regmap_field_write(data->reg_int_ps, state); - if (ret < 0) + if (ret < 0) { dev_err(&client->dev, "failed to set interrupt mode\n"); + mutex_unlock(&data->lock); + return ret; + } + + data->ps_int_enabled = state; + mutex_unlock(&data->lock); - return ret; + return 0; } static int stk3310_read_raw(struct iio_dev *indio_dev, @@ -360,7 +388,7 @@ static int stk3310_read_raw(struct iio_dev *indio_dev, reg = STK3310_REG_PS_DATA_MSB; mutex_lock(&data->lock); - ret = regmap_bulk_read(data->regmap, reg, &buf, 2); + ret = regmap_bulk_read(data->regmap, reg, &buf, sizeof(buf)); if (ret < 0) { dev_err(&client->dev, "register read failed\n"); mutex_unlock(&data->lock); @@ -504,10 +532,15 @@ static int stk3310_init(struct iio_dev *indio_dev) /* Enable PS interrupts */ ret = regmap_field_write(data->reg_int_ps, STK3310_PSINT_EN); - if (ret < 0) + if (ret < 0) { dev_err(&client->dev, "failed to enable interrupts!\n"); + return ret; + } - return ret; + data->ps_int_enabled = true; + data->ps_thdh = STK3310_PS_MAX_VAL; + + return 0; } static bool stk3310_is_volatile_reg(struct device *dev, unsigned int reg) @@ -640,11 +673,8 @@ static int stk3310_probe(struct i2c_client *client) IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "stk3310_event", indio_dev); - if (ret < 0) { - dev_err(&client->dev, "request irq %d failed\n", - client->irq); + if (ret) goto err_standby; - } } ret = iio_device_register(indio_dev); @@ -671,9 +701,18 @@ static void stk3310_remove(struct i2c_client *client) static int stk3310_suspend(struct device *dev) { struct stk3310_data *data; + int ret; data = iio_priv(i2c_get_clientdata(to_i2c_client(dev))); + if (data->ps_int_enabled) { + ret = regmap_field_write(data->reg_int_ps, 0x0); + if (ret < 0) { + dev_err(dev, "failed to disable ps int at suspend.\n"); + return ret; + } + } + return stk3310_set_state(data, STK3310_STATE_STANDBY); } @@ -681,6 +720,8 @@ static int stk3310_resume(struct device *dev) { u8 state = 0; struct stk3310_data *data; + __be16 buf; + int ret; data = iio_priv(i2c_get_clientdata(to_i2c_client(dev))); if (data->ps_enabled) @@ -688,17 +729,47 @@ static int stk3310_resume(struct device *dev) if (data->als_enabled) state |= STK3310_STATE_EN_ALS; - return stk3310_set_state(data, state); + ret = stk3310_set_state(data, state); + if (ret < 0) + return ret; + + if (data->ps_thdl != 0x0) { + buf = cpu_to_be16(data->ps_thdl); + ret = regmap_bulk_write(data->regmap, STK3310_REG_THDL_PS, &buf, sizeof(buf)); + if (ret < 0) { + dev_err(dev, "failed to set reg THDL_PS at resume.\n"); + return ret; + } + } + + if (data->ps_thdh != STK3310_PS_MAX_VAL) { + buf = cpu_to_be16(data->ps_thdh); + ret = regmap_bulk_write(data->regmap, STK3310_REG_THDH_PS, &buf, sizeof(buf)); + if (ret < 0) { + dev_err(dev, "failed to set reg THDH_PS at resume.\n"); + return ret; + } + } + + if (data->ps_int_enabled) { + ret = regmap_field_write(data->reg_int_ps, STK3310_PSINT_EN); + if (ret < 0) { + dev_err(dev, "failed to enable ps int at resume.\n"); + return ret; + } + } + + return 0; } static DEFINE_SIMPLE_DEV_PM_OPS(stk3310_pm_ops, stk3310_suspend, stk3310_resume); static const struct i2c_device_id stk3310_i2c_id[] = { - { "STK3013" }, - { "STK3310" }, - { "STK3311" }, - { "STK3335" }, + { .name = "STK3013" }, + { .name = "STK3310" }, + { .name = "STK3311" }, + { .name = "STK3335" }, { } }; MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id); diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c index 5be461e6dbdb..458178fb629f 100644 --- a/drivers/iio/light/tcs3414.c +++ b/drivers/iio/light/tcs3414.c @@ -362,7 +362,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tcs3414_pm_ops, tcs3414_suspend, tcs3414_resume); static const struct i2c_device_id tcs3414_id[] = { - { "tcs3414" }, + { .name = "tcs3414" }, { } }; MODULE_DEVICE_TABLE(i2c, tcs3414_id); diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index 12429a3261b3..b392943e51c8 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -9,20 +9,21 @@ * TCS34727) * * Datasheet: http://ams.com/eng/content/download/319364/1117183/file/TCS3472_Datasheet_EN_v2.pdf - * - * TODO: wait time */ -#include <linux/module.h> -#include <linux/i2c.h> +#include <linux/cleanup.h> #include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/mutex.h> #include <linux/pm.h> +#include <linux/units.h> +#include <linux/iio/buffer.h> +#include <linux/iio/events.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> -#include <linux/iio/events.h> #include <linux/iio/trigger_consumer.h> -#include <linux/iio/buffer.h> #include <linux/iio/triggered_buffer.h> #define TCS3472_DRV_NAME "tcs3472" @@ -51,19 +52,30 @@ #define TCS3472_STATUS_AINT BIT(4) #define TCS3472_STATUS_AVALID BIT(0) #define TCS3472_ENABLE_AIEN BIT(4) +#define TCS3472_ENABLE_WEN BIT(3) #define TCS3472_ENABLE_AEN BIT(1) #define TCS3472_ENABLE_PON BIT(0) +#define TCS3472_ENABLE_RUN \ + (TCS3472_ENABLE_AEN | TCS3472_ENABLE_PON | TCS3472_ENABLE_WEN) #define TCS3472_CONTROL_AGAIN_MASK (BIT(0) | BIT(1)) +#define TCS3472_CONFIG_WLONG BIT(1) + +#define TCS3472_ATIME_TO_US(atime) (((256) - (atime)) * 2400) struct tcs3472_data { struct i2c_client *client; struct mutex lock; + int target_freq_hz; + int target_freq_uhz; u16 low_thresh; u16 high_thresh; u8 enable; + u8 enable_pre_suspend; u8 control; u8 atime; u8 apers; + u8 wtime; + bool wlong; }; static const struct iio_event_spec tcs3472_events[] = { @@ -89,6 +101,7 @@ static const struct iio_event_spec tcs3472_events[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBSCALE) | \ BIT(IIO_CHAN_INFO_INT_TIME), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .channel2 = IIO_MOD_LIGHT_##_color, \ .address = _addr, \ .scan_index = _si, \ @@ -112,9 +125,65 @@ static const struct iio_chan_spec tcs3472_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(4), }; +/* + * The chip's cycle time is the sum of three components: + * - ATIME: the programmable RGBC integration time. + * - The fixed RGBC initialization time (2400 us). + * - WTIME: the wait time, used only if WEN is set. If WLONG is active, + * the wait step is multiplied by 12 (2400 us -> 28800 us). + */ +static unsigned int tcs3472_cycle_time_us(struct tcs3472_data *data) +{ + unsigned int atime_us = TCS3472_ATIME_TO_US(data->atime); + unsigned int init_us = 2400; + unsigned int wtime_us; + + if (!(data->enable & TCS3472_ENABLE_WEN)) + wtime_us = 0; + else if (data->wlong) + wtime_us = (256 - data->wtime) * 28800; + else + wtime_us = (256 - data->wtime) * 2400; + + return atime_us + init_us + wtime_us; +} + +/* + * Convert a cycle time in microseconds to a frequency in Hz and microhertz. + * + * Given cycle_us = T (the cycle period in microseconds), the corresponding + * frequency is: + * f = 1e6 / T [Hz] + * + * The result is split into the IIO_VAL_INT_PLUS_MICRO format: + * val = floor(1e6 / T) [Hz] + * val2 = (1e6 mod T) * 1e6 / T [microhertz] + */ +static void tcs3472_cycle_to_freq(unsigned int cycle_us, int *val, int *val2) +{ + *val = USEC_PER_SEC / cycle_us; + *val2 = div_u64((u64)(USEC_PER_SEC % cycle_us) * USEC_PER_SEC, + cycle_us); +} + static int tcs3472_req_data(struct tcs3472_data *data) { - int tries = 50; + /* + * The worst-case cycle time is reached with ATIME=0x00, WTIME=0x00 + * and WLONG=1. So: + * 614 ms (Max Integration Time) + * + 2.4 ms (RGBC Init) + * + 7.37 s (Max Wait Time) + * = ~ 8 s (Total Max cycle time). + * Use that as a polling upper bound; in normal operation the loop + * exits as soon as AVALID is set. So the total number of tries in 8 + * seconds considering a polling period of 20 ms is 400. + * Considering a 20% margin due to oscillator tolerance, the total + * duration becomes approximately 9.8 seconds, which corresponds to + * about 480 steps. Therefore, setting it to 500 appears to be a + * reasonable and safe trade-off. + */ + int tries = 500; int ret; while (tries--) { @@ -162,10 +231,157 @@ static int tcs3472_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_INT_TIME: *val = 0; - *val2 = (256 - data->atime) * 2400; + *val2 = TCS3472_ATIME_TO_US(data->atime); return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SAMP_FREQ: { + unsigned int cycle_us; + + guard(mutex)(&data->lock); + cycle_us = tcs3472_cycle_time_us(data); + tcs3472_cycle_to_freq(cycle_us, val, val2); + return IIO_VAL_INT_PLUS_MICRO; + } + default: + return -EINVAL; } - return -EINVAL; +} + +/* + * __tcs3472_set_sampling_freq() - implementation of sampling frequency + * configuration. The caller must hold data->lock. + */ +static int __tcs3472_set_sampling_freq(struct tcs3472_data *data, + int val, int val2) +{ + unsigned int atime_us; + unsigned int init_us = 2400; + u64 cycle_us; + s64 wait_us; + int wtime; + bool wlong = false; + u8 config; + int ret; + + if (val < 0 || val2 < 0 || (val == 0 && val2 == 0)) + return -EINVAL; + + atime_us = TCS3472_ATIME_TO_US(data->atime); + + /* + * cycle_us = 1 / freq, expressed in microseconds. + * Numerator: 1 [s] = PSEC_PER_SEC [ps] + * Denominator: freq [Hz] * MICROHZ_PER_HZ + val2 [uHz] = freq in [uHz] + * Result: ps / uHz = us + */ + cycle_us = div64_u64(PSEC_PER_SEC, (u64)val * MICROHZ_PER_HZ + val2); + + /* + * wait_us can be negative when the requested frequency is too high + * to be reached, or very large when the requested frequency is + * close to zero. Use s64 to cover the full range: + * + * cycle_us = PSEC_PER_SEC / (val * MICROHZ_PER_HZ + val2) + * + * The divisor of the formula above reaches its maximum when + * val = val2 = INT_MAX: + * INT_MAX * MICROHZ_PER_HZ + INT_MAX = ~2.15e18 + * so cycle_us_min = floor(1e12 / 2.15e18) = 0. + * + * The divisor reaches its minimum (1) when val = 0 and val2 = 1, + * so cycle_us_max = 1e12 / 1 = 1e12. + * + * Therefore: + * wait_us_min = 0 - 2400 - 612000 = -616800 + * wait_us_max = 1e12 - 2400 - 2400 = 999999995200 + * + * Both fit comfortably in s64. + */ + wait_us = (s64)cycle_us - init_us - atime_us; + if (wait_us < 2400) { + if (data->enable & TCS3472_ENABLE_WEN) { + u8 enable = data->enable & ~TCS3472_ENABLE_WEN; + + ret = i2c_smbus_write_byte_data(data->client, + TCS3472_ENABLE, enable); + if (ret) + return ret; + + data->enable = enable; + } + + data->target_freq_hz = val; + data->target_freq_uhz = val2; + return 0; + } + + /* + * Wait state is needed: make sure WEN is active before programming + * WTIME (and possibly WLONG). + */ + if (!(data->enable & TCS3472_ENABLE_WEN)) { + u8 enable = data->enable | TCS3472_ENABLE_WEN; + + ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, + enable); + if (ret) + return ret; + + data->enable = enable; + } + + wtime = 256 - DIV_ROUND_CLOSEST_ULL(wait_us, 2400); + if (wtime < 0) { + /* + * If wait_us is too high (so the requested frequency is too + * low), the resulting wait exceeds what WTIME can represent + * (max 614 ms without WLONG). Enable WLONG, whose step is 12x + * longer (28.8 ms instead of 2.4 ms), and recompute. + */ + wlong = true; + wtime = 256 - DIV_ROUND_CLOSEST_ULL(wait_us, 28800); + } + + if (wlong != data->wlong) { + ret = i2c_smbus_read_byte_data(data->client, TCS3472_CONFIG); + if (ret < 0) + return ret; + + config = ret; + if (wlong) + config |= TCS3472_CONFIG_WLONG; + else + config &= ~TCS3472_CONFIG_WLONG; + + ret = i2c_smbus_write_byte_data(data->client, TCS3472_CONFIG, + config); + if (ret) + return ret; + + data->wlong = wlong; + } + + /* + * If the requested wait is so long that even WLONG cannot + * cover it, wtime may still be negative. Saturate to 0, + * which is the largest possible wait (256 * 28.8 ms = 7.37 s). + */ + wtime = clamp(wtime, 0, 255); + ret = i2c_smbus_write_byte_data(data->client, TCS3472_WTIME, wtime); + if (ret) + return ret; + + data->wtime = wtime; + data->target_freq_hz = val; + data->target_freq_uhz = val2; + + return 0; +} + +static int tcs3472_set_sampling_freq(struct tcs3472_data *data, + int val, int val2) +{ + guard(mutex)(&data->lock); + return __tcs3472_set_sampling_freq(data, val, val2); } static int tcs3472_write_raw(struct iio_dev *indio_dev, @@ -173,6 +389,7 @@ static int tcs3472_write_raw(struct iio_dev *indio_dev, int val, int val2, long mask) { struct tcs3472_data *data = iio_priv(indio_dev); + int ret; int i; switch (mask) { @@ -193,17 +410,34 @@ static int tcs3472_write_raw(struct iio_dev *indio_dev, if (val != 0) return -EINVAL; for (i = 0; i < 256; i++) { - if (val2 == (256 - i) * 2400) { - data->atime = i; - return i2c_smbus_write_byte_data( - data->client, TCS3472_ATIME, - data->atime); - } - + if (val2 != (256 - i) * 2400) + continue; + + guard(mutex)(&data->lock); + + ret = i2c_smbus_write_byte_data(data->client, + TCS3472_ATIME, i); + if (ret) + return ret; + + data->atime = i; + + /* + * ATIME just changed, so the cycle time changed too. + * Re-run the sampling frequency logic to recompute + * WTIME and preserve the user's last requested + * frequency. Lock is already held. + */ + return __tcs3472_set_sampling_freq(data, + data->target_freq_hz, + data->target_freq_uhz); } return -EINVAL; + case IIO_CHAN_INFO_SAMP_FREQ: + return tcs3472_set_sampling_freq(data, val, val2); + default: + return -EINVAL; } - return -EINVAL; } /* @@ -220,32 +454,24 @@ static int tcs3472_read_event(struct iio_dev *indio_dev, int *val2) { struct tcs3472_data *data = iio_priv(indio_dev); - int ret; unsigned int period; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); switch (info) { case IIO_EV_INFO_VALUE: *val = (dir == IIO_EV_DIR_RISING) ? data->high_thresh : data->low_thresh; - ret = IIO_VAL_INT; - break; + return IIO_VAL_INT; case IIO_EV_INFO_PERIOD: - period = (256 - data->atime) * 2400 * + period = tcs3472_cycle_time_us(data) * tcs3472_intr_pers[data->apers]; *val = period / USEC_PER_SEC; *val2 = period % USEC_PER_SEC; - ret = IIO_VAL_INT_PLUS_MICRO; - break; + return IIO_VAL_INT_PLUS_MICRO; default: - ret = -EINVAL; - break; + return -EINVAL; } - - mutex_unlock(&data->lock); - - return ret; } static int tcs3472_write_event(struct iio_dev *indio_dev, @@ -259,7 +485,8 @@ static int tcs3472_write_event(struct iio_dev *indio_dev, int period; int i; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); + switch (info) { case IIO_EV_INFO_VALUE: switch (dir) { @@ -270,39 +497,38 @@ static int tcs3472_write_event(struct iio_dev *indio_dev, command = TCS3472_AILT; break; default: - ret = -EINVAL; - goto error; + return -EINVAL; } ret = i2c_smbus_write_word_data(data->client, command, val); if (ret) - goto error; + return ret; if (dir == IIO_EV_DIR_RISING) data->high_thresh = val; else data->low_thresh = val; - break; - case IIO_EV_INFO_PERIOD: + + return 0; + case IIO_EV_INFO_PERIOD:{ + unsigned int cycle_us; + period = val * USEC_PER_SEC + val2; + cycle_us = tcs3472_cycle_time_us(data); for (i = 1; i < ARRAY_SIZE(tcs3472_intr_pers) - 1; i++) { - if (period <= (256 - data->atime) * 2400 * - tcs3472_intr_pers[i]) + if (period <= cycle_us * tcs3472_intr_pers[i]) break; } ret = i2c_smbus_write_byte_data(data->client, TCS3472_PERS, i); if (ret) - goto error; + return ret; data->apers = i; - break; + + return 0; + } default: - ret = -EINVAL; - break; + return -EINVAL; } -error: - mutex_unlock(&data->lock); - - return ret; } static int tcs3472_read_event_config(struct iio_dev *indio_dev, @@ -310,13 +536,10 @@ static int tcs3472_read_event_config(struct iio_dev *indio_dev, enum iio_event_direction dir) { struct tcs3472_data *data = iio_priv(indio_dev); - int ret; - mutex_lock(&data->lock); - ret = !!(data->enable & TCS3472_ENABLE_AIEN); - mutex_unlock(&data->lock); + guard(mutex)(&data->lock); - return ret; + return (data->enable & TCS3472_ENABLE_AIEN) ? 1 : 0; } static int tcs3472_write_event_config(struct iio_dev *indio_dev, @@ -327,7 +550,7 @@ static int tcs3472_write_event_config(struct iio_dev *indio_dev, int ret = 0; u8 enable_old; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); enable_old = data->enable; @@ -339,12 +562,13 @@ static int tcs3472_write_event_config(struct iio_dev *indio_dev, if (enable_old != data->enable) { ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, data->enable); - if (ret) + if (ret) { data->enable = enable_old; + return ret; + } } - mutex_unlock(&data->lock); - return ret; + return 0; } static irqreturn_t tcs3472_event_handler(int irq, void *priv) @@ -440,20 +664,46 @@ static const struct iio_info tcs3472_info = { .attrs = &tcs3472_attribute_group, }; +static int tcs3472_powerdown(struct tcs3472_data *data) +{ + int ret; + + guard(mutex)(&data->lock); + + data->enable_pre_suspend = data->enable; + + ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, + data->enable & ~TCS3472_ENABLE_RUN); + if (ret) + return ret; + + return 0; +} + +static void tcs3472_powerdown_action(void *data) +{ + tcs3472_powerdown(data); +} + static int tcs3472_probe(struct i2c_client *client) { + struct device *dev = &client->dev; struct tcs3472_data *data; struct iio_dev *indio_dev; + unsigned int cycle_us; int ret; + u8 enable; - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); - if (indio_dev == NULL) + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) return -ENOMEM; data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); data->client = client; - mutex_init(&data->lock); + ret = devm_mutex_init(dev, &data->lock); + if (ret) + return ret; indio_dev->info = &tcs3472_info; indio_dev->name = TCS3472_DRV_NAME; @@ -466,9 +716,9 @@ static int tcs3472_probe(struct i2c_client *client) return ret; if (ret == 0x44) - dev_info(&client->dev, "TCS34721/34725 found\n"); + dev_info(dev, "TCS34721/34725 found\n"); else if (ret == 0x4d) - dev_info(&client->dev, "TCS34723/34727 found\n"); + dev_info(dev, "TCS34723/34727 found\n"); else return -ENODEV; @@ -482,6 +732,16 @@ static int tcs3472_probe(struct i2c_client *client) return ret; data->atime = ret; + ret = i2c_smbus_read_byte_data(data->client, TCS3472_WTIME); + if (ret < 0) + return ret; + data->wtime = ret; + + ret = i2c_smbus_read_byte_data(data->client, TCS3472_CONFIG); + if (ret < 0) + return ret; + data->wlong = (ret & TCS3472_CONFIG_WLONG) ? 1 : 0; + ret = i2c_smbus_read_word_data(data->client, TCS3472_AILT); if (ret < 0) return ret; @@ -502,69 +762,51 @@ static int tcs3472_probe(struct i2c_client *client) if (ret < 0) return ret; - /* enable device */ - data->enable = ret | TCS3472_ENABLE_PON | TCS3472_ENABLE_AEN; - data->enable &= ~TCS3472_ENABLE_AIEN; - ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, - data->enable); + /* + * Enable the chip in its full running state, including WEN. The + * actual wait time is controlled by the WTIME and WLONG registers, + * which retain their power-on defaults until userspace writes to + * sampling_frequency. + */ + enable = (ret | TCS3472_ENABLE_RUN) & ~TCS3472_ENABLE_AIEN; + + ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, enable); if (ret < 0) return ret; - ret = iio_triggered_buffer_setup(indio_dev, NULL, - tcs3472_trigger_handler, NULL); + data->enable = enable; + + /* + * Initialize target frequency from the chip's current state so that + * subsequent integration_time changes via IIO_CHAN_INFO_INT_TIME can + * preserve a meaningful sampling rate, even before userspace writes + * sampling_frequency for the first time. + */ + cycle_us = tcs3472_cycle_time_us(data); + tcs3472_cycle_to_freq(cycle_us, &data->target_freq_hz, + &data->target_freq_uhz); + + ret = devm_add_action_or_reset(dev, tcs3472_powerdown_action, data); + if (ret) + return ret; + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, + tcs3472_trigger_handler, NULL); if (ret < 0) return ret; if (client->irq) { - ret = request_threaded_irq(client->irq, NULL, - tcs3472_event_handler, - IRQF_TRIGGER_FALLING | IRQF_SHARED | - IRQF_ONESHOT, - client->name, indio_dev); + ret = devm_request_threaded_irq(dev, client->irq, NULL, + tcs3472_event_handler, + IRQF_TRIGGER_FALLING | + IRQF_SHARED | + IRQF_ONESHOT, + client->name, indio_dev); if (ret) - goto buffer_cleanup; + return ret; } - ret = iio_device_register(indio_dev); - if (ret < 0) - goto free_irq; - - return 0; - -free_irq: - if (client->irq) - free_irq(client->irq, indio_dev); -buffer_cleanup: - iio_triggered_buffer_cleanup(indio_dev); - return ret; -} - -static int tcs3472_powerdown(struct tcs3472_data *data) -{ - int ret; - u8 enable_mask = TCS3472_ENABLE_AEN | TCS3472_ENABLE_PON; - - mutex_lock(&data->lock); - - ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, - data->enable & ~enable_mask); - if (!ret) - data->enable &= ~enable_mask; - - mutex_unlock(&data->lock); - - return ret; -} - -static void tcs3472_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - - iio_device_unregister(indio_dev); - if (client->irq) - free_irq(client->irq, indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - tcs3472_powerdown(iio_priv(indio_dev)); + return devm_iio_device_register(dev, indio_dev); } static int tcs3472_suspend(struct device *dev) @@ -579,25 +821,30 @@ static int tcs3472_resume(struct device *dev) struct tcs3472_data *data = iio_priv(i2c_get_clientdata( to_i2c_client(dev))); int ret; - u8 enable_mask = TCS3472_ENABLE_AEN | TCS3472_ENABLE_PON; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); + /* + * Restore the full ENABLE register from the snapshot taken in + * tcs3472_powerdown(). This preserves the user's last + * sampling_frequency configuration (in particular the WEN bit) + * across suspend/resume. + */ ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, - data->enable | enable_mask); - if (!ret) - data->enable |= enable_mask; + data->enable_pre_suspend); + if (ret) + return ret; - mutex_unlock(&data->lock); + data->enable = data->enable_pre_suspend; - return ret; + return 0; } static DEFINE_SIMPLE_DEV_PM_OPS(tcs3472_pm_ops, tcs3472_suspend, tcs3472_resume); static const struct i2c_device_id tcs3472_id[] = { - { "tcs3472" }, + { .name = "tcs3472" }, { } }; MODULE_DEVICE_TABLE(i2c, tcs3472_id); @@ -608,7 +855,6 @@ static struct i2c_driver tcs3472_driver = { .pm = pm_sleep_ptr(&tcs3472_pm_ops), }, .probe = tcs3472_probe, - .remove = tcs3472_remove, .id_table = tcs3472_id, }; module_i2c_driver(tcs3472_driver); diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c index f2af1cd7c2d1..7bef0c3118c2 100644 --- a/drivers/iio/light/tsl2563.c +++ b/drivers/iio/light/tsl2563.c @@ -18,7 +18,6 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/math.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/pm.h> @@ -755,7 +754,7 @@ static int tsl2563_probe(struct i2c_client *client) "tsl2563_event", indio_dev); if (err) - return dev_err_probe(dev, err, "irq request error\n"); + return err; } err = tsl2563_configure(chip); @@ -839,10 +838,10 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tsl2563_pm_ops, tsl2563_suspend, tsl2563_resume); static const struct i2c_device_id tsl2563_id[] = { - { "tsl2560", 0 }, - { "tsl2561", 1 }, - { "tsl2562", 2 }, - { "tsl2563", 3 }, + { .name = "tsl2560" }, + { .name = "tsl2561" }, + { .name = "tsl2562" }, + { .name = "tsl2563" }, { } }; MODULE_DEVICE_TABLE(i2c, tsl2563_id); diff --git a/drivers/iio/light/tsl2583.c b/drivers/iio/light/tsl2583.c index 8801a491de77..53fd423aa7ae 100644 --- a/drivers/iio/light/tsl2583.c +++ b/drivers/iio/light/tsl2583.c @@ -456,12 +456,8 @@ static int tsl2583_chip_init_and_power_on(struct iio_dev *indio_dev) usleep_range(3000, 3500); - ret = tsl2583_set_power_state(chip, TSL2583_CNTL_PWR_ON | - TSL2583_CNTL_ADC_ENBL); - if (ret < 0) - return ret; - - return ret; + return tsl2583_set_power_state(chip, + TSL2583_CNTL_PWR_ON | TSL2583_CNTL_ADC_ENBL); } /* Sysfs Interface Functions */ @@ -475,7 +471,7 @@ static ssize_t in_illuminance_input_target_show(struct device *dev, int ret; mutex_lock(&chip->als_mutex); - ret = sprintf(buf, "%d\n", chip->als_settings.als_cal_target); + ret = sysfs_emit(buf, "%d\n", chip->als_settings.als_cal_target); mutex_unlock(&chip->als_mutex); return ret; @@ -533,10 +529,10 @@ static ssize_t in_illuminance_lux_table_show(struct device *dev, int offset = 0; for (i = 0; i < ARRAY_SIZE(chip->als_settings.als_device_lux); i++) { - offset += sprintf(buf + offset, "%u,%u,%u,", - chip->als_settings.als_device_lux[i].ratio, - chip->als_settings.als_device_lux[i].ch0, - chip->als_settings.als_device_lux[i].ch1); + offset += sysfs_emit_at(buf, offset, "%u,%u,%u,", + chip->als_settings.als_device_lux[i].ratio, + chip->als_settings.als_device_lux[i].ch0, + chip->als_settings.als_device_lux[i].ch1); if (chip->als_settings.als_device_lux[i].ratio == 0) { /* * We just printed the first "0" entry. @@ -547,7 +543,7 @@ static ssize_t in_illuminance_lux_table_show(struct device *dev, } } - offset += sprintf(buf + offset, "\n"); + offset += sysfs_emit_at(buf, offset, "\n"); return offset; } @@ -639,14 +635,6 @@ static const struct iio_chan_spec tsl2583_channels[] = { }, }; -static int tsl2583_set_pm_runtime_busy(struct tsl2583_chip *chip, bool on) -{ - if (on) - return pm_runtime_resume_and_get(&chip->client->dev); - - return pm_runtime_put_autosuspend(&chip->client->dev); -} - static int tsl2583_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -654,7 +642,7 @@ static int tsl2583_read_raw(struct iio_dev *indio_dev, struct tsl2583_chip *chip = iio_priv(indio_dev); int ret, pm_ret; - ret = tsl2583_set_pm_runtime_busy(chip, true); + ret = pm_runtime_resume_and_get(&chip->client->dev); if (ret < 0) return ret; @@ -722,16 +710,16 @@ read_done: mutex_unlock(&chip->als_mutex); if (ret < 0) { - tsl2583_set_pm_runtime_busy(chip, false); + pm_runtime_put_autosuspend(&chip->client->dev); return ret; } /* * Preserve the ret variable if the call to - * tsl2583_set_pm_runtime_busy() is successful so the reading + * pm_runtime_put_autosuspend() is successful so the reading * (if applicable) is returned to user space. */ - pm_ret = tsl2583_set_pm_runtime_busy(chip, false); + pm_ret = pm_runtime_put_autosuspend(&chip->client->dev); if (pm_ret < 0) return pm_ret; @@ -745,7 +733,7 @@ static int tsl2583_write_raw(struct iio_dev *indio_dev, struct tsl2583_chip *chip = iio_priv(indio_dev); int ret; - ret = tsl2583_set_pm_runtime_busy(chip, true); + ret = pm_runtime_resume_and_get(&chip->client->dev); if (ret < 0) return ret; @@ -786,15 +774,15 @@ static int tsl2583_write_raw(struct iio_dev *indio_dev, mutex_unlock(&chip->als_mutex); if (ret < 0) { - tsl2583_set_pm_runtime_busy(chip, false); + pm_runtime_put_autosuspend(&chip->client->dev); return ret; } - ret = tsl2583_set_pm_runtime_busy(chip, false); + ret = pm_runtime_put_autosuspend(&chip->client->dev); if (ret < 0) return ret; - return ret; + return 0; } static const struct iio_info tsl2583_info = { @@ -913,9 +901,9 @@ static DEFINE_RUNTIME_DEV_PM_OPS(tsl2583_pm_ops, tsl2583_suspend, tsl2583_resume, NULL); static const struct i2c_device_id tsl2583_idtable[] = { - { "tsl2580", 0 }, - { "tsl2581", 1 }, - { "tsl2583", 2 }, + { .name = "tsl2580" }, + { .name = "tsl2581" }, + { .name = "tsl2583" }, { } }; MODULE_DEVICE_TABLE(i2c, tsl2583_idtable); diff --git a/drivers/iio/light/tsl2591.c b/drivers/iio/light/tsl2591.c index c5557867ea43..ef3ed9635a1e 100644 --- a/drivers/iio/light/tsl2591.c +++ b/drivers/iio/light/tsl2591.c @@ -192,6 +192,24 @@ static const int tsl2591_calibscale_available[] = { 1, 25, 428, 9876, }; +static const u8 tsl2591_persist_table[] = { + [TSL2591_PRST_ALS_INT_CYCLE_ANY] = 1, + [TSL2591_PRST_ALS_INT_CYCLE_2] = 2, + [TSL2591_PRST_ALS_INT_CYCLE_3] = 3, + [TSL2591_PRST_ALS_INT_CYCLE_5] = 5, + [TSL2591_PRST_ALS_INT_CYCLE_10] = 10, + [TSL2591_PRST_ALS_INT_CYCLE_15] = 15, + [TSL2591_PRST_ALS_INT_CYCLE_20] = 20, + [TSL2591_PRST_ALS_INT_CYCLE_25] = 25, + [TSL2591_PRST_ALS_INT_CYCLE_30] = 30, + [TSL2591_PRST_ALS_INT_CYCLE_35] = 35, + [TSL2591_PRST_ALS_INT_CYCLE_40] = 40, + [TSL2591_PRST_ALS_INT_CYCLE_45] = 45, + [TSL2591_PRST_ALS_INT_CYCLE_50] = 50, + [TSL2591_PRST_ALS_INT_CYCLE_55] = 55, + [TSL2591_PRST_ALS_INT_CYCLE_60] = 60, +}; + 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, @@ -231,78 +249,22 @@ static int tsl2591_multiplier_to_gain(const u32 multiplier) 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: + if (als_persist >= ARRAY_SIZE(tsl2591_persist_table) || + !tsl2591_persist_table[als_persist]) return -EINVAL; - } + + return tsl2591_persist_table[als_persist]; } 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; + for (unsigned int i = TSL2591_PRST_ALS_INT_CYCLE_ANY; + i < ARRAY_SIZE(tsl2591_persist_table); i++) { + if (als_persist == tsl2591_persist_table[i]) + return i; } + + return -EINVAL; } static int tsl2591_compatible_int_time(struct tsl2591_chip *chip, @@ -346,31 +308,6 @@ static int tsl2591_compatible_gain(struct tsl2591_chip *chip, const u8 als_gain) } } -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; @@ -952,10 +889,6 @@ static int tsl2591_write_event_value(struct iio_dev *indio_dev, 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; @@ -1137,10 +1070,8 @@ static int tsl2591_probe(struct i2c_client *client) 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; - } + if (ret) + return ret; indio_dev->info = &tsl2591_info; } else { indio_dev->info = &tsl2591_info_no_irq; diff --git a/drivers/iio/light/tsl2772.c b/drivers/iio/light/tsl2772.c index 0b171106441a..4486a1d9d84d 100644 --- a/drivers/iio/light/tsl2772.c +++ b/drivers/iio/light/tsl2772.c @@ -127,6 +127,7 @@ enum { tmd2672, tsl2772, tmd2772, + apds9900, apds9930, }; @@ -190,7 +191,7 @@ struct tsl2772_chip { }; /* - * Different devices require different coefficents, and these numbers were + * Different devices require different coefficients, and these numbers were * derived from the 'Lux Equation' section of the various device datasheets. * All of these coefficients assume a Glass Attenuation (GA) factor of 1. * The coefficients are multiplied by 1000 to avoid floating point operations. @@ -221,6 +222,12 @@ static const struct tsl2772_lux tmd2x72_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = { { 0, 0 }, }; +static const struct tsl2772_lux apds9900_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = { + { 52000, 115960 }, + { 36400, 73840 }, + { 0, 0 }, +}; + static const struct tsl2772_lux apds9930_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = { { 52000, 96824 }, { 38792, 67132 }, @@ -238,6 +245,7 @@ static const struct tsl2772_lux *tsl2772_default_lux_table_group[] = { [tmd2672] = tmd2x72_lux_table, [tsl2772] = tsl2x72_lux_table, [tmd2772] = tmd2x72_lux_table, + [apds9900] = apds9900_lux_table, [apds9930] = apds9930_lux_table, }; @@ -289,6 +297,7 @@ static const int tsl2772_int_time_avail[][6] = { [tmd2672] = { 0, 2730, 0, 2730, 0, 699000 }, [tsl2772] = { 0, 2730, 0, 2730, 0, 699000 }, [tmd2772] = { 0, 2730, 0, 2730, 0, 699000 }, + [apds9900] = { 0, 2720, 0, 2720, 0, 696000 }, [apds9930] = { 0, 2730, 0, 2730, 0, 699000 }, }; @@ -316,6 +325,7 @@ static const u8 device_channel_config[] = { [tmd2672] = PRX2, [tsl2772] = ALSPRX2, [tmd2772] = ALSPRX2, + [apds9900] = ALSPRX, [apds9930] = ALSPRX2, }; @@ -530,6 +540,7 @@ static int tsl2772_get_prox(struct iio_dev *indio_dev) case tmd2672: case tsl2772: case tmd2772: + case apds9900: case apds9930: if (!(ret & TSL2772_STA_PRX_VALID)) { ret = -EINVAL; @@ -1263,7 +1274,7 @@ static int tsl2772_read_raw(struct iio_dev *indio_dev, } break; case IIO_CHAN_INFO_CALIBSCALE: - if (chan->type == IIO_LIGHT) + if (chan->type == IIO_INTENSITY) *val = tsl2772_als_gain[chip->settings.als_gain]; else *val = tsl2772_prox_gain[chip->settings.prox_gain]; @@ -1367,6 +1378,7 @@ static int tsl2772_device_id_verif(int id, int target) return (id & 0xf0) == TRITON_ID; case tmd2671: case tmd2771: + case apds9900: return (id & 0xf0) == HALIBUT_ID; case tsl2572: case tsl2672: @@ -1837,11 +1849,8 @@ static int tsl2772_probe(struct i2c_client *clientp) IRQF_ONESHOT, "TSL2772_event", indio_dev); - if (ret) { - dev_err(&clientp->dev, - "%s: irq request failed\n", __func__); + if (ret) return ret; - } } else { indio_dev->channels = chip->chip_info->channel_without_events; } @@ -1888,17 +1897,19 @@ static int tsl2772_resume(struct device *dev) } static const struct i2c_device_id tsl2772_idtable[] = { - { "tsl2571", tsl2571 }, - { "tsl2671", tsl2671 }, - { "tmd2671", tmd2671 }, - { "tsl2771", tsl2771 }, - { "tmd2771", tmd2771 }, - { "tsl2572", tsl2572 }, - { "tsl2672", tsl2672 }, - { "tmd2672", tmd2672 }, - { "tsl2772", tsl2772 }, - { "tmd2772", tmd2772 }, - { "apds9930", apds9930 }, + { .name = "tsl2571", .driver_data = tsl2571 }, + { .name = "tsl2671", .driver_data = tsl2671 }, + { .name = "tmd2671", .driver_data = tmd2671 }, + { .name = "tsl2771", .driver_data = tsl2771 }, + { .name = "tmd2771", .driver_data = tmd2771 }, + { .name = "tsl2572", .driver_data = tsl2572 }, + { .name = "tsl2672", .driver_data = tsl2672 }, + { .name = "tmd2672", .driver_data = tmd2672 }, + { .name = "tsl2772", .driver_data = tsl2772 }, + { .name = "tmd2772", .driver_data = tmd2772 }, + { .name = "apds9900", .driver_data = apds9900 }, + { .name = "apds9901", .driver_data = apds9900 }, + { .name = "apds9930", .driver_data = apds9930 }, { } }; @@ -1915,6 +1926,8 @@ static const struct of_device_id tsl2772_of_match[] = { { .compatible = "amstaos,tmd2672" }, { .compatible = "amstaos,tsl2772" }, { .compatible = "amstaos,tmd2772" }, + { .compatible = "avago,apds9900" }, + { .compatible = "avago,apds9901" }, { .compatible = "avago,apds9930" }, { } }; diff --git a/drivers/iio/light/tsl4531.c b/drivers/iio/light/tsl4531.c index a5788c09ad02..2f91ed8a9876 100644 --- a/drivers/iio/light/tsl4531.c +++ b/drivers/iio/light/tsl4531.c @@ -227,7 +227,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tsl4531_pm_ops, tsl4531_suspend, tsl4531_resume); static const struct i2c_device_id tsl4531_id[] = { - { "tsl4531" }, + { .name = "tsl4531" }, { } }; MODULE_DEVICE_TABLE(i2c, tsl4531_id); diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c index d2f5a44892a8..ab518311fd79 100644 --- a/drivers/iio/light/us5182d.c +++ b/drivers/iio/light/us5182d.c @@ -9,7 +9,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/delay.h> #include <linux/i2c.h> #include <linux/iio/events.h> @@ -949,7 +948,7 @@ static const struct acpi_device_id us5182d_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, us5182d_acpi_match); static const struct i2c_device_id us5182d_id[] = { - { "usd5182" }, + { .name = "usd5182" }, { } }; diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index a36c23813679..336468d59ea7 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -18,12 +18,14 @@ */ #include <linux/bitfield.h> -#include <linux/module.h> -#include <linux/i2c.h> -#include <linux/err.h> +#include <linux/cleanup.h> #include <linux/delay.h> -#include <linux/pm_runtime.h> +#include <linux/err.h> +#include <linux/i2c.h> #include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> #include <linux/units.h> #include <linux/iio/buffer.h> @@ -184,13 +186,6 @@ static const int vcnl4040_ps_oversampling_ratio[] = {1, 2, 4, 8}; #define VCNL4000_SLEEP_DELAY_MS 2000 /* before we enter pm_runtime_suspend */ -enum vcnl4000_device_ids { - VCNL4000, - VCNL4010, - VCNL4040, - VCNL4200, -}; - struct vcnl4200_channel { u8 reg; ktime_t last_measurement; @@ -200,7 +195,6 @@ struct vcnl4200_channel { struct vcnl4000_data { struct i2c_client *client; - enum vcnl4000_device_ids id; int rev; int al_scale; int ps_scale; @@ -232,18 +226,9 @@ struct vcnl4000_chip_spec { const int(*als_it_times)[][2]; const int num_als_it_times; const unsigned int ulux_step; + const int prod_id; }; -static const struct i2c_device_id vcnl4000_id[] = { - { "vcnl4000", VCNL4000 }, - { "vcnl4010", VCNL4010 }, - { "vcnl4020", VCNL4010 }, - { "vcnl4040", VCNL4040 }, - { "vcnl4200", VCNL4200 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, vcnl4000_id); - static int vcnl4000_set_power_state(struct vcnl4000_data *data, bool on) { /* no suspend op */ @@ -261,12 +246,12 @@ static int vcnl4000_init(struct vcnl4000_data *data) prod_id = ret >> 4; switch (prod_id) { case VCNL4000_PROD_ID: - if (data->id != VCNL4000) + if (data->chip_spec->prod_id != VCNL4000_PROD_ID) dev_warn(&data->client->dev, "wrong device id, use vcnl4000"); break; case VCNL4010_PROD_ID: - if (data->id != VCNL4010) + if (data->chip_spec->prod_id != VCNL4010_PROD_ID) dev_warn(&data->client->dev, "wrong device id, use vcnl4010/4020"); break; @@ -277,53 +262,43 @@ static int vcnl4000_init(struct vcnl4000_data *data) data->rev = ret & 0xf; data->al_scale = 250000; - return data->chip_spec->set_power_state(data, true); + return 0; }; static ssize_t vcnl4000_write_als_enable(struct vcnl4000_data *data, bool en) { int ret; - mutex_lock(&data->vcnl4000_lock); + guard(mutex)(&data->vcnl4000_lock); ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF); if (ret < 0) - goto out; + return ret; if (en) ret &= ~VCNL4040_ALS_CONF_ALS_SHUTDOWN; else ret |= VCNL4040_ALS_CONF_ALS_SHUTDOWN; - ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, ret); - -out: - mutex_unlock(&data->vcnl4000_lock); - - return ret; + return i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, ret); } static ssize_t vcnl4000_write_ps_enable(struct vcnl4000_data *data, bool en) { int ret; - mutex_lock(&data->vcnl4000_lock); + guard(mutex)(&data->vcnl4000_lock); ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1); if (ret < 0) - goto out; + return ret; if (en) ret &= ~VCNL4040_PS_CONF1_PS_SHUTDOWN; else ret |= VCNL4040_PS_CONF1_PS_SHUTDOWN; - ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, ret); - -out: - mutex_unlock(&data->vcnl4000_lock); - - return ret; + return i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, ret); } static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool on) @@ -353,17 +328,19 @@ static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool on) static int vcnl4200_init(struct vcnl4000_data *data) { + struct i2c_client *client = data->client; + struct device *dev = &client->dev; int ret, id; u16 regval; - ret = i2c_smbus_read_word_data(data->client, VCNL4200_DEV_ID); + ret = i2c_smbus_read_word_data(client, VCNL4200_DEV_ID); if (ret < 0) return ret; id = ret & 0xff; if (id != VCNL4200_PROD_ID) { - ret = i2c_smbus_read_word_data(data->client, VCNL4040_DEV_ID); + ret = i2c_smbus_read_word_data(client, VCNL4040_DEV_ID); if (ret < 0) return ret; @@ -373,7 +350,7 @@ static int vcnl4200_init(struct vcnl4000_data *data) return -ENODEV; } - dev_dbg(&data->client->dev, "device id 0x%x", id); + dev_dbg(dev, "device id 0x%x", id); data->rev = (ret >> 8) & 0xf; data->ps_int = 0; @@ -397,32 +374,32 @@ static int vcnl4200_init(struct vcnl4000_data *data) } data->al_scale = data->chip_spec->ulux_step; data->ps_scale = 16; - mutex_init(&data->vcnl4200_al.lock); - mutex_init(&data->vcnl4200_ps.lock); + + ret = devm_mutex_init(dev, &data->vcnl4200_al.lock); + if (ret) + return ret; + + ret = devm_mutex_init(dev, &data->vcnl4200_ps.lock); + if (ret) + return ret; /* Use 16 bits proximity sensor readings */ - ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1); + ret = i2c_smbus_read_word_data(client, VCNL4200_PS_CONF1); if (ret < 0) return ret; regval = ret | VCNL4040_PS_CONF2_PS_HD; - ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, - regval); + ret = i2c_smbus_write_word_data(client, VCNL4200_PS_CONF1, regval); if (ret < 0) return ret; /* Align proximity sensor sample rate to 16 bits data width */ - ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3); + ret = i2c_smbus_read_word_data(client, VCNL4200_PS_CONF3); if (ret < 0) return ret; regval = ret | VCNL4040_CONF3_PS_SAMPLE_16BITS; - ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3, - regval); - if (ret < 0) - return ret; - - ret = data->chip_spec->set_power_state(data, true); + ret = i2c_smbus_write_word_data(client, VCNL4200_PS_CONF3, regval); if (ret < 0) return ret; @@ -456,18 +433,18 @@ static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask, int tries = 20; int ret; - mutex_lock(&data->vcnl4000_lock); + guard(mutex)(&data->vcnl4000_lock); ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, req_mask); if (ret < 0) - goto fail; + return ret; /* wait for data to become ready */ while (tries--) { ret = i2c_smbus_read_byte_data(data->client, VCNL4000_COMMAND); if (ret < 0) - goto fail; + return ret; if (ret & rdy_mask) break; msleep(20); /* measurement takes up to 100 ms */ @@ -476,21 +453,10 @@ static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask, if (tries < 0) { dev_err(&data->client->dev, "vcnl4000_measure() failed, data not ready\n"); - ret = -EIO; - goto fail; + return -EIO; } - ret = vcnl4000_read_data(data, data_reg, val); - if (ret < 0) - goto fail; - - mutex_unlock(&data->vcnl4000_lock); - - return 0; - -fail: - mutex_unlock(&data->vcnl4000_lock); - return ret; + return vcnl4000_read_data(data, data_reg, val); } static int vcnl4200_measure(struct vcnl4000_data *data, @@ -500,16 +466,14 @@ static int vcnl4200_measure(struct vcnl4000_data *data, s64 delta; ktime_t next_measurement; - mutex_lock(&chan->lock); - - next_measurement = ktime_add(chan->last_measurement, - chan->sampling_rate); - delta = ktime_us_delta(next_measurement, ktime_get()); - if (delta > 0) - usleep_range(delta, delta + 500); - chan->last_measurement = ktime_get(); - - mutex_unlock(&chan->lock); + scoped_guard(mutex, &chan->lock) { + next_measurement = ktime_add(chan->last_measurement, + chan->sampling_rate); + delta = ktime_us_delta(next_measurement, ktime_get()); + if (delta > 0) + usleep_range(delta, delta + 500); + chan->last_measurement = ktime_get(); + } ret = i2c_smbus_read_word_data(data->client, chan->reg); if (ret < 0) @@ -573,16 +537,6 @@ static bool vcnl4010_is_in_periodic_mode(struct vcnl4000_data *data) return !!(ret & VCNL4000_SELF_TIMED_EN); } -static int vcnl4000_set_pm_runtime_state(struct vcnl4000_data *data, bool on) -{ - struct device *dev = &data->client->dev; - - if (on) - return pm_runtime_resume_and_get(dev); - - return pm_runtime_put_autosuspend(dev); -} - static int vcnl4040_read_als_it(struct vcnl4000_data *data, int *val, int *val2) { int ret; @@ -620,21 +574,15 @@ static ssize_t vcnl4040_write_als_it(struct vcnl4000_data *data, int val) (*data->chip_spec->als_it_times)[0][1]), val); - mutex_lock(&data->vcnl4000_lock); + guard(mutex)(&data->vcnl4000_lock); ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF); if (ret < 0) - goto out_unlock; + return ret; regval = FIELD_PREP(VCNL4040_ALS_CONF_IT, i); regval |= (ret & ~VCNL4040_ALS_CONF_IT); - ret = i2c_smbus_write_word_data(data->client, - VCNL4200_AL_CONF, - regval); - -out_unlock: - mutex_unlock(&data->vcnl4000_lock); - return ret; + return i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, regval); } static int vcnl4040_read_ps_it(struct vcnl4000_data *data, int *val, int *val2) @@ -674,20 +622,15 @@ static ssize_t vcnl4040_write_ps_it(struct vcnl4000_data *data, int val) data->vcnl4200_ps.sampling_rate = ktime_set(0, val * 60 * NSEC_PER_USEC); - mutex_lock(&data->vcnl4000_lock); + guard(mutex)(&data->vcnl4000_lock); ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1); if (ret < 0) - goto out; + return ret; regval = (ret & ~VCNL4040_PS_CONF2_PS_IT) | FIELD_PREP(VCNL4040_PS_CONF2_PS_IT, index); - ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, - regval); - -out: - mutex_unlock(&data->vcnl4000_lock); - return ret; + return i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, regval); } static ssize_t vcnl4040_read_als_period(struct vcnl4000_data *data, int *val, int *val2) @@ -735,20 +678,15 @@ static ssize_t vcnl4040_write_als_period(struct vcnl4000_data *data, int val, in break; } - mutex_lock(&data->vcnl4000_lock); + guard(mutex)(&data->vcnl4000_lock); ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF); if (ret < 0) - goto out_unlock; + return ret; regval = FIELD_PREP(VCNL4040_ALS_CONF_PERS, i); regval |= (ret & ~VCNL4040_ALS_CONF_PERS); - ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, - regval); - -out_unlock: - mutex_unlock(&data->vcnl4000_lock); - return ret; + return i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, regval); } static ssize_t vcnl4040_read_ps_period(struct vcnl4000_data *data, int *val, int *val2) @@ -797,20 +735,15 @@ static ssize_t vcnl4040_write_ps_period(struct vcnl4000_data *data, int val, int } } - mutex_lock(&data->vcnl4000_lock); + guard(mutex)(&data->vcnl4000_lock); ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1); if (ret < 0) - goto out_unlock; + return ret; regval = FIELD_PREP(VCNL4040_CONF1_PS_PERS, i); regval |= (ret & ~VCNL4040_CONF1_PS_PERS); - ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, - regval); - -out_unlock: - mutex_unlock(&data->vcnl4000_lock); - return ret; + return i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, regval); } static ssize_t vcnl4040_read_ps_oversampling_ratio(struct vcnl4000_data *data, int *val) @@ -844,20 +777,15 @@ static ssize_t vcnl4040_write_ps_oversampling_ratio(struct vcnl4000_data *data, if (i >= ARRAY_SIZE(vcnl4040_ps_oversampling_ratio)) return -EINVAL; - mutex_lock(&data->vcnl4000_lock); + guard(mutex)(&data->vcnl4000_lock); ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3); if (ret < 0) - goto out_unlock; + return ret; regval = FIELD_PREP(VCNL4040_PS_CONF3_MPS, i); regval |= (ret & ~VCNL4040_PS_CONF3_MPS); - ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3, - regval); - -out_unlock: - mutex_unlock(&data->vcnl4000_lock); - return ret; + return i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3, regval); } static ssize_t vcnl4040_read_ps_calibbias(struct vcnl4000_data *data, int *val, int *val2) @@ -892,20 +820,15 @@ static ssize_t vcnl4040_write_ps_calibbias(struct vcnl4000_data *data, int val) if (i >= ARRAY_SIZE(vcnl4040_ps_calibbias_ua)) return -EINVAL; - mutex_lock(&data->vcnl4000_lock); + guard(mutex)(&data->vcnl4000_lock); ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3); if (ret < 0) - goto out_unlock; + return ret; regval = (ret & ~VCNL4040_PS_MS_LED_I); regval |= FIELD_PREP(VCNL4040_PS_MS_LED_I, i); - ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3, - regval); - -out_unlock: - mutex_unlock(&data->vcnl4000_lock); - return ret; + return i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3, regval); } static int vcnl4000_read_raw(struct iio_dev *indio_dev, @@ -917,7 +840,7 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = vcnl4000_set_pm_runtime_state(data, true); + ret = pm_runtime_resume_and_get(&data->client->dev); if (ret < 0) return ret; @@ -936,7 +859,7 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev, default: ret = -EINVAL; } - vcnl4000_set_pm_runtime_state(data, false); + pm_runtime_put_autosuspend(&data->client->dev); return ret; case IIO_CHAN_INFO_SCALE: if (chan->type != IIO_LIGHT) @@ -1490,17 +1413,17 @@ static int vcnl4040_write_event_config(struct iio_dev *indio_dev, enum iio_event_direction dir, bool state) { - int ret = -EINVAL; + int ret; u16 val, mask; struct vcnl4000_data *data = iio_priv(indio_dev); - mutex_lock(&data->vcnl4000_lock); + guard(mutex)(&data->vcnl4000_lock); switch (chan->type) { case IIO_LIGHT: ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF); if (ret < 0) - goto out; + return ret; mask = VCNL4040_ALS_CONF_INT_EN; if (state) @@ -1509,13 +1432,11 @@ static int vcnl4040_write_event_config(struct iio_dev *indio_dev, val = (ret & ~mask); data->als_int = FIELD_GET(VCNL4040_ALS_CONF_INT_EN, val); - ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, - val); - break; + return i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, val); case IIO_PROXIMITY: ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1); if (ret < 0) - goto out; + return ret; if (dir == IIO_EV_DIR_RISING) mask = VCNL4040_PS_IF_AWAY; @@ -1525,17 +1446,10 @@ static int vcnl4040_write_event_config(struct iio_dev *indio_dev, val = state ? (ret | mask) : (ret & ~mask); data->ps_int = FIELD_GET(VCNL4040_PS_CONF2_PS_INT, val); - ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, - val); - break; + return i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, val); default: - break; + return -EINVAL; } - -out: - mutex_unlock(&data->vcnl4000_lock); - - return ret; } static irqreturn_t vcnl4040_irq_thread(int irq, void *p) @@ -1842,6 +1756,22 @@ static const struct iio_chan_spec vcnl4040_channels[] = { } }; +static const struct iio_chan_spec cm36672p_channels[] = { + { + .type = IIO_PROXIMITY, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) | + BIT(IIO_CHAN_INFO_CALIBBIAS), + .info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) | + BIT(IIO_CHAN_INFO_CALIBBIAS), + .ext_info = vcnl4000_ext_info, + .event_spec = vcnl4040_event_spec, + .num_event_specs = ARRAY_SIZE(vcnl4040_event_spec), + }, +}; + static const struct iio_info vcnl4000_info = { .read_raw = vcnl4000_read_raw, }; @@ -1866,64 +1796,84 @@ static const struct iio_info vcnl4040_info = { .read_avail = vcnl4040_read_avail, }; -static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = { - [VCNL4000] = { - .prod = "VCNL4000", - .init = vcnl4000_init, - .measure_light = vcnl4000_measure_light, - .measure_proximity = vcnl4000_measure_proximity, - .set_power_state = vcnl4000_set_power_state, - .channels = vcnl4000_channels, - .num_channels = ARRAY_SIZE(vcnl4000_channels), - .info = &vcnl4000_info, - }, - [VCNL4010] = { - .prod = "VCNL4010/4020", - .init = vcnl4000_init, - .measure_light = vcnl4000_measure_light, - .measure_proximity = vcnl4000_measure_proximity, - .set_power_state = vcnl4000_set_power_state, - .channels = vcnl4010_channels, - .num_channels = ARRAY_SIZE(vcnl4010_channels), - .info = &vcnl4010_info, - .irq_thread = vcnl4010_irq_thread, - .trig_buffer_func = vcnl4010_trigger_handler, - .buffer_setup_ops = &vcnl4010_buffer_ops, - }, - [VCNL4040] = { - .prod = "VCNL4040", - .init = vcnl4200_init, - .measure_light = vcnl4200_measure_light, - .measure_proximity = vcnl4200_measure_proximity, - .set_power_state = vcnl4200_set_power_state, - .channels = vcnl4040_channels, - .num_channels = ARRAY_SIZE(vcnl4040_channels), - .info = &vcnl4040_info, - .irq_thread = vcnl4040_irq_thread, - .int_reg = VCNL4040_INT_FLAGS, - .ps_it_times = &vcnl4040_ps_it_times, - .num_ps_it_times = ARRAY_SIZE(vcnl4040_ps_it_times), - .als_it_times = &vcnl4040_als_it_times, - .num_als_it_times = ARRAY_SIZE(vcnl4040_als_it_times), - .ulux_step = 100000, - }, - [VCNL4200] = { - .prod = "VCNL4200", - .init = vcnl4200_init, - .measure_light = vcnl4200_measure_light, - .measure_proximity = vcnl4200_measure_proximity, - .set_power_state = vcnl4200_set_power_state, - .channels = vcnl4040_channels, - .num_channels = ARRAY_SIZE(vcnl4000_channels), - .info = &vcnl4040_info, - .irq_thread = vcnl4040_irq_thread, - .int_reg = VCNL4200_INT_FLAGS, - .ps_it_times = &vcnl4200_ps_it_times, - .num_ps_it_times = ARRAY_SIZE(vcnl4200_ps_it_times), - .als_it_times = &vcnl4200_als_it_times, - .num_als_it_times = ARRAY_SIZE(vcnl4200_als_it_times), - .ulux_step = 24000, - }, +static const struct vcnl4000_chip_spec cm36672p_spec = { + .prod = "CM36672P", + .init = vcnl4200_init, + .measure_proximity = vcnl4200_measure_proximity, + .set_power_state = vcnl4200_set_power_state, + .channels = cm36672p_channels, + .num_channels = ARRAY_SIZE(cm36672p_channels), + .info = &vcnl4040_info, + .irq_thread = vcnl4040_irq_thread, + .int_reg = VCNL4040_INT_FLAGS, + .ps_it_times = &vcnl4040_ps_it_times, + .num_ps_it_times = ARRAY_SIZE(vcnl4040_ps_it_times), + .prod_id = VCNL4040_PROD_ID, +}; + +static const struct vcnl4000_chip_spec vcnl4000_spec = { + .prod = "VCNL4000", + .init = vcnl4000_init, + .measure_light = vcnl4000_measure_light, + .measure_proximity = vcnl4000_measure_proximity, + .set_power_state = vcnl4000_set_power_state, + .channels = vcnl4000_channels, + .num_channels = ARRAY_SIZE(vcnl4000_channels), + .info = &vcnl4000_info, + .prod_id = VCNL4000_PROD_ID, +}; + +static const struct vcnl4000_chip_spec vcnl4010_spec = { + .prod = "VCNL4010/4020", + .init = vcnl4000_init, + .measure_light = vcnl4000_measure_light, + .measure_proximity = vcnl4000_measure_proximity, + .set_power_state = vcnl4000_set_power_state, + .channels = vcnl4010_channels, + .num_channels = ARRAY_SIZE(vcnl4010_channels), + .info = &vcnl4010_info, + .irq_thread = vcnl4010_irq_thread, + .trig_buffer_func = vcnl4010_trigger_handler, + .buffer_setup_ops = &vcnl4010_buffer_ops, + .prod_id = VCNL4010_PROD_ID, +}; + +static const struct vcnl4000_chip_spec vcnl4040_spec = { + .prod = "VCNL4040", + .init = vcnl4200_init, + .measure_light = vcnl4200_measure_light, + .measure_proximity = vcnl4200_measure_proximity, + .set_power_state = vcnl4200_set_power_state, + .channels = vcnl4040_channels, + .num_channels = ARRAY_SIZE(vcnl4040_channels), + .info = &vcnl4040_info, + .irq_thread = vcnl4040_irq_thread, + .int_reg = VCNL4040_INT_FLAGS, + .ps_it_times = &vcnl4040_ps_it_times, + .num_ps_it_times = ARRAY_SIZE(vcnl4040_ps_it_times), + .als_it_times = &vcnl4040_als_it_times, + .num_als_it_times = ARRAY_SIZE(vcnl4040_als_it_times), + .ulux_step = 100000, + .prod_id = VCNL4040_PROD_ID, +}; + +static const struct vcnl4000_chip_spec vcnl4200_spec = { + .prod = "VCNL4200", + .init = vcnl4200_init, + .measure_light = vcnl4200_measure_light, + .measure_proximity = vcnl4200_measure_proximity, + .set_power_state = vcnl4200_set_power_state, + .channels = vcnl4040_channels, + .num_channels = ARRAY_SIZE(vcnl4000_channels), + .info = &vcnl4040_info, + .irq_thread = vcnl4040_irq_thread, + .int_reg = VCNL4200_INT_FLAGS, + .ps_it_times = &vcnl4200_ps_it_times, + .num_ps_it_times = ARRAY_SIZE(vcnl4200_ps_it_times), + .als_it_times = &vcnl4200_als_it_times, + .num_als_it_times = ARRAY_SIZE(vcnl4200_als_it_times), + .ulux_step = 24000, + .prod_id = VCNL4200_PROD_ID, }; static const struct iio_trigger_ops vcnl4010_trigger_ops = { @@ -1948,35 +1898,60 @@ static int vcnl4010_probe_trigger(struct iio_dev *indio_dev) return devm_iio_trigger_register(&client->dev, trigger); } +static void vcnl4000_cleanup(void *data) +{ + struct iio_dev *indio_dev = data; + struct vcnl4000_data *chip = iio_priv(indio_dev); + struct device *dev = &chip->client->dev; + int ret; + + ret = chip->chip_spec->set_power_state(chip, false); + if (ret) + dev_warn(dev, "Failed to power down (%pe)", ERR_PTR(ret)); +} + static int vcnl4000_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); + static const char * const regulator_names[] = { "vdd", "vio", "vled" }; + struct device *dev = &client->dev; struct vcnl4000_data *data; struct iio_dev *indio_dev; int ret; - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) return -ENOMEM; data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); data->client = client; - data->id = id->driver_data; - data->chip_spec = &vcnl4000_chip_spec_cfg[data->id]; + data->chip_spec = i2c_get_match_data(client); + + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names), + regulator_names); + if (ret) + return ret; - mutex_init(&data->vcnl4000_lock); + ret = devm_mutex_init(dev, &data->vcnl4000_lock); + if (ret) + return ret; ret = data->chip_spec->init(data); if (ret < 0) return ret; - dev_dbg(&client->dev, "%s Ambient light/proximity sensor, Rev: %02x\n", + ret = data->chip_spec->set_power_state(data, true); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, vcnl4000_cleanup, indio_dev); + if (ret) + return ret; + + dev_dbg(dev, "%s Ambient light/proximity sensor, Rev: %02x\n", data->chip_spec->prod, data->rev); - if (device_property_read_u32(&client->dev, "proximity-near-level", - &data->near_level)) - data->near_level = 0; + device_property_read_u32(dev, "proximity-near-level", &data->near_level); indio_dev->info = data->chip_spec->info; indio_dev->channels = data->chip_spec->channels; @@ -1986,94 +1961,55 @@ static int vcnl4000_probe(struct i2c_client *client) if (data->chip_spec->trig_buffer_func && data->chip_spec->buffer_setup_ops) { - ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, - NULL, + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, data->chip_spec->trig_buffer_func, data->chip_spec->buffer_setup_ops); - if (ret < 0) { - dev_err(&client->dev, - "unable to setup iio triggered buffer\n"); + if (ret < 0) return ret; - } } if (client->irq && data->chip_spec->irq_thread) { - ret = devm_request_threaded_irq(&client->dev, client->irq, - NULL, data->chip_spec->irq_thread, + ret = devm_request_threaded_irq(dev, client->irq, NULL, + data->chip_spec->irq_thread, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "vcnl4000_irq", indio_dev); - if (ret < 0) { - dev_err(&client->dev, "irq request failed\n"); + if (ret < 0) return ret; - } ret = vcnl4010_probe_trigger(indio_dev); if (ret < 0) return ret; } - ret = pm_runtime_set_active(&client->dev); - if (ret < 0) - goto fail_poweroff; + ret = devm_pm_runtime_set_active_enabled(dev); + if (ret) + return ret; - ret = iio_device_register(indio_dev); - if (ret < 0) - goto fail_poweroff; + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + return ret; - pm_runtime_enable(&client->dev); - pm_runtime_set_autosuspend_delay(&client->dev, VCNL4000_SLEEP_DELAY_MS); - pm_runtime_use_autosuspend(&client->dev); + pm_runtime_set_autosuspend_delay(dev, VCNL4000_SLEEP_DELAY_MS); + pm_runtime_use_autosuspend(dev); return 0; -fail_poweroff: - data->chip_spec->set_power_state(data, false); - return ret; } static const struct of_device_id vcnl_4000_of_match[] = { - { - .compatible = "vishay,vcnl4000", - .data = (void *)VCNL4000, - }, - { - .compatible = "vishay,vcnl4010", - .data = (void *)VCNL4010, - }, - { - .compatible = "vishay,vcnl4020", - .data = (void *)VCNL4010, - }, - { - .compatible = "vishay,vcnl4040", - .data = (void *)VCNL4040, - }, - { - .compatible = "vishay,vcnl4200", - .data = (void *)VCNL4200, - }, + { .compatible = "capella,cm36672p", .data = &cm36672p_spec }, + /* Capella CM36686 is fully compatible with Vishay VCNL4040 */ + { .compatible = "capella,cm36686", .data = &vcnl4040_spec }, + { .compatible = "vishay,vcnl4000", .data = &vcnl4000_spec }, + { .compatible = "vishay,vcnl4010", .data = &vcnl4010_spec }, + { .compatible = "vishay,vcnl4020", .data = &vcnl4010_spec }, + { .compatible = "vishay,vcnl4040", .data = &vcnl4040_spec }, + { .compatible = "vishay,vcnl4200", .data = &vcnl4200_spec }, { } }; MODULE_DEVICE_TABLE(of, vcnl_4000_of_match); -static void vcnl4000_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct vcnl4000_data *data = iio_priv(indio_dev); - int ret; - - pm_runtime_dont_use_autosuspend(&client->dev); - pm_runtime_disable(&client->dev); - iio_device_unregister(indio_dev); - pm_runtime_set_suspended(&client->dev); - - ret = data->chip_spec->set_power_state(data, false); - if (ret) - dev_warn(&client->dev, "Failed to power down (%pe)\n", - ERR_PTR(ret)); -} - static int vcnl4000_runtime_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); @@ -2093,6 +2029,18 @@ static int vcnl4000_runtime_resume(struct device *dev) static DEFINE_RUNTIME_DEV_PM_OPS(vcnl4000_pm_ops, vcnl4000_runtime_suspend, vcnl4000_runtime_resume, NULL); +static const struct i2c_device_id vcnl4000_id[] = { + { .name = "cm36672p", .driver_data = (kernel_ulong_t)&cm36672p_spec }, + { .name = "cm36686", .driver_data = (kernel_ulong_t)&vcnl4040_spec }, + { .name = "vcnl4000", .driver_data = (kernel_ulong_t)&vcnl4000_spec }, + { .name = "vcnl4010", .driver_data = (kernel_ulong_t)&vcnl4010_spec }, + { .name = "vcnl4020", .driver_data = (kernel_ulong_t)&vcnl4010_spec }, + { .name = "vcnl4040", .driver_data = (kernel_ulong_t)&vcnl4040_spec }, + { .name = "vcnl4200", .driver_data = (kernel_ulong_t)&vcnl4200_spec }, + { } +}; +MODULE_DEVICE_TABLE(i2c, vcnl4000_id); + static struct i2c_driver vcnl4000_driver = { .driver = { .name = VCNL4000_DRV_NAME, @@ -2101,7 +2049,6 @@ static struct i2c_driver vcnl4000_driver = { }, .probe = vcnl4000_probe, .id_table = vcnl4000_id, - .remove = vcnl4000_remove, }; module_i2c_driver(vcnl4000_driver); diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c index 963747927425..ce1bd42b0c7c 100644 --- a/drivers/iio/light/vcnl4035.c +++ b/drivers/iio/light/vcnl4035.c @@ -103,17 +103,23 @@ static irqreturn_t vcnl4035_trigger_consumer_handler(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct vcnl4035_data *data = iio_priv(indio_dev); /* Ensure naturally aligned timestamp */ - u8 buffer[ALIGN(sizeof(u16), sizeof(s64)) + sizeof(s64)] __aligned(8) = { }; + struct { + u16 als_data; + aligned_s64 timestamp; + } buffer = { }; + unsigned int val; int ret; - ret = regmap_read(data->regmap, VCNL4035_ALS_DATA, (int *)buffer); + ret = regmap_read(data->regmap, VCNL4035_ALS_DATA, &val); if (ret < 0) { dev_err(&data->client->dev, "Trigger consumer can't read from sensor.\n"); goto fail_read; } - iio_push_to_buffers_with_timestamp(indio_dev, buffer, - iio_get_time_ns(indio_dev)); + + buffer.als_data = val; + iio_push_to_buffers_with_timestamp(indio_dev, &buffer, + iio_get_time_ns(indio_dev)); fail_read: iio_trigger_notify_done(indio_dev->trig); @@ -139,16 +145,6 @@ static const struct iio_trigger_ops vcnl4035_trigger_ops = { .set_trigger_state = vcnl4035_als_drdy_set_state, }; -static int vcnl4035_set_pm_runtime_state(struct vcnl4035_data *data, bool on) -{ - struct device *dev = &data->client->dev; - - if (on) - return pm_runtime_resume_and_get(dev); - - return pm_runtime_put_autosuspend(dev); -} - static int vcnl4035_read_info_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val) { @@ -196,11 +192,11 @@ static int vcnl4035_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = vcnl4035_set_pm_runtime_state(data, true); + ret = pm_runtime_resume_and_get(&data->client->dev); if (ret < 0) return ret; ret = vcnl4035_read_info_raw(indio_dev, chan, val); - vcnl4035_set_pm_runtime_state(data, false); + pm_runtime_put_autosuspend(&data->client->dev); return ret; case IIO_CHAN_INFO_INT_TIME: *val = 50; @@ -231,7 +227,7 @@ static int vcnl4035_write_raw(struct iio_dev *indio_dev, if (val <= 0 || val > 800) return -EINVAL; - ret = vcnl4035_set_pm_runtime_state(data, true); + ret = pm_runtime_resume_and_get(&data->client->dev); if (ret < 0) return ret; @@ -241,7 +237,7 @@ static int vcnl4035_write_raw(struct iio_dev *indio_dev, if (!ret) data->als_it_val = val / 100; - vcnl4035_set_pm_runtime_state(data, false); + pm_runtime_put_autosuspend(&data->client->dev); return ret; default: return -EINVAL; @@ -381,7 +377,7 @@ static const struct iio_chan_spec vcnl4035_channels[] = { .sign = 'u', .realbits = 16, .storagebits = 16, - .endianness = IIO_LE, + .endianness = IIO_CPU, }, }, { @@ -395,7 +391,7 @@ static const struct iio_chan_spec vcnl4035_channels[] = { .sign = 'u', .realbits = 16, .storagebits = 16, - .endianness = IIO_LE, + .endianness = IIO_CPU, }, }, }; @@ -641,7 +637,10 @@ static int vcnl4035_runtime_resume(struct device *dev) struct vcnl4035_data *data = iio_priv(indio_dev); int ret; - regcache_sync(data->regmap); + ret = regcache_sync(data->regmap); + if (ret < 0) + return ret; + ret = vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_ENABLE); if (ret < 0) return ret; @@ -656,7 +655,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(vcnl4035_pm_ops, vcnl4035_runtime_suspend, vcnl4035_runtime_resume, NULL); static const struct i2c_device_id vcnl4035_id[] = { - { "vcnl4035" }, + { .name = "vcnl4035" }, { } }; MODULE_DEVICE_TABLE(i2c, vcnl4035_id); diff --git a/drivers/iio/light/veml3235.c b/drivers/iio/light/veml3235.c index 9309ad83ca9e..d8a39223009b 100644 --- a/drivers/iio/light/veml3235.c +++ b/drivers/iio/light/veml3235.c @@ -525,7 +525,7 @@ static const struct of_device_id veml3235_of_match[] = { MODULE_DEVICE_TABLE(of, veml3235_of_match); static const struct i2c_device_id veml3235_id[] = { - { "veml3235" }, + { .name = "veml3235" }, { } }; MODULE_DEVICE_TABLE(i2c, veml3235_id); diff --git a/drivers/iio/light/veml3328.c b/drivers/iio/light/veml3328.c new file mode 100644 index 000000000000..7ff1753925c4 --- /dev/null +++ b/drivers/iio/light/veml3328.c @@ -0,0 +1,422 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Vishay VEML3328 RGBCIR light sensor driver + * + * Copyright (c) 2026 Joshua Crofts <joshua.crofts1@gmail.com> + * + * Datasheet: https://www.vishay.com/docs/84968/veml3328.pdf + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/time.h> +#include <linux/types.h> + +#include <linux/iio/iio.h> + +#define VEML3328_REG_CONF 0x00 +#define VEML3328_REG_ID 0x0c +#define VEML3328_REG_DATA_C 0x04 +#define VEML3328_REG_DATA_R 0x05 +#define VEML3328_REG_DATA_G 0x06 +#define VEML3328_REG_DATA_B 0x07 +#define VEML3328_REG_DATA_IR 0x08 + +#define VEML3328_CONF_IT_MASK GENMASK(5, 4) +#define VEML3328_CONF_GAIN_MASK GENMASK(11, 10) + +#define VEML3328_MAX_IT_TIME (400 * USEC_PER_MSEC) + +#define VEML3328_ID_VAL 0x28 + +#define VEML3328_SHUTDOWN (BIT(0) | BIT(15)) + +struct veml3328_data { + struct regmap *regmap; + /* Ensure read-modify-write sequences are not interrupted. */ + struct mutex lock; +}; + +static const struct regmap_config veml3328_regmap_config = { + .name = "veml3328", + .reg_bits = 8, + .val_bits = 16, + .max_register = VEML3328_REG_ID, + .val_format_endian = REGMAP_ENDIAN_LITTLE, +}; + +#define VEML3328_CHAN_SPEC(_color, _addr) { \ + .type = IIO_INTENSITY, \ + .modified = 1, \ + .channel2 = IIO_MOD_LIGHT_##_color, \ + .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_all = BIT(IIO_CHAN_INFO_INT_TIME), \ + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME), \ + .address = _addr, \ +} + +static const struct iio_chan_spec veml3328_channels[] = { + { + .type = IIO_LIGHT, + + .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_all = BIT(IIO_CHAN_INFO_INT_TIME), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME), + .address = VEML3328_REG_DATA_G, + }, + VEML3328_CHAN_SPEC(CLEAR, VEML3328_REG_DATA_C), + VEML3328_CHAN_SPEC(RED, VEML3328_REG_DATA_R), + VEML3328_CHAN_SPEC(GREEN, VEML3328_REG_DATA_G), + VEML3328_CHAN_SPEC(BLUE, VEML3328_REG_DATA_B), + VEML3328_CHAN_SPEC(IR, VEML3328_REG_DATA_IR), +}; + +/* + * Precomputed scale values (micro units). + * Formula for calculation: 0.384 * (50000 / IT_us) * (1 / Gain) + * Gain indexes: 0 (x0.5), 1 (x1), 2 (x2), 3 (x4) + * IT indexes: 0 (50ms), 1 (100ms), 2 (200ms), 3 (400ms) + */ +static const int veml3328_scale_vals[4][8] = { + { 0, 768000, 0, 384000, 0, 192000, 0, 96000 }, + { 0, 384000, 0, 192000, 0, 96000, 0, 48000 }, + { 0, 192000, 0, 96000, 0, 48000, 0, 24000 }, + { 0, 96000, 0, 48000, 0, 24000, 0, 12000 }, +}; + +/* integration times in microseconds */ +static const int veml3328_it_times[][2] = { + { 0, 50 * USEC_PER_MSEC }, + { 0, 100 * USEC_PER_MSEC }, + { 0, 200 * USEC_PER_MSEC }, + { 0, 400 * USEC_PER_MSEC }, +}; + +static int veml3328_power_down(struct veml3328_data *data) +{ + return regmap_set_bits(data->regmap, VEML3328_REG_CONF, + VEML3328_SHUTDOWN); +} + +static int veml3328_power_up(struct veml3328_data *data) +{ + int ret; + + ret = regmap_clear_bits(data->regmap, VEML3328_REG_CONF, + VEML3328_SHUTDOWN); + if (ret) + return ret; + + /* + * Sleep for maximum integration time to ensure sensor is powered on + * correctly. + */ + fsleep(VEML3328_MAX_IT_TIME); + + return 0; +} + +static void veml3328_power_down_action(void *data) +{ + veml3328_power_down(data); +} + +static int veml3328_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct veml3328_data *data = iio_priv(indio_dev); + struct regmap *regmap = data->regmap; + struct device *dev = regmap_get_device(regmap); + unsigned int reg_val; + int it_inx, gain_inx; + int ret; + + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = regmap_read(regmap, chan->address, ®_val); + if (ret) + return ret; + + *val = reg_val; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_INT_TIME: + ret = regmap_read(regmap, VEML3328_REG_CONF, ®_val); + if (ret) + return ret; + + it_inx = FIELD_GET(VEML3328_CONF_IT_MASK, reg_val); + if (it_inx >= ARRAY_SIZE(veml3328_it_times)) + return -EINVAL; + + *val = veml3328_it_times[it_inx][0]; + *val2 = veml3328_it_times[it_inx][1]; + return IIO_VAL_INT_PLUS_MICRO; + + case IIO_CHAN_INFO_SCALE: + ret = regmap_read(regmap, VEML3328_REG_CONF, ®_val); + if (ret) + return ret; + + it_inx = FIELD_GET(VEML3328_CONF_IT_MASK, reg_val); + gain_inx = FIELD_GET(VEML3328_CONF_GAIN_MASK, reg_val); + + if (it_inx >= ARRAY_SIZE(veml3328_it_times) || gain_inx >= 4) + return -EINVAL; + + /* Stride by 2 through the flattened array to match (val, val2) */ + *val = veml3328_scale_vals[it_inx][gain_inx * 2]; + *val2 = veml3328_scale_vals[it_inx][gain_inx * 2 + 1]; + + return IIO_VAL_INT_PLUS_MICRO; + + default: + return -EINVAL; + } +} + +static int veml3328_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct veml3328_data *data = iio_priv(indio_dev); + struct regmap *regmap = data->regmap; + struct device *dev = regmap_get_device(data->regmap); + unsigned int reg_val; + int ret, it_inx; + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + *length = ARRAY_SIZE(veml3328_it_times) * 2; + *vals = (const int *)veml3328_it_times; + *type = IIO_VAL_INT_PLUS_MICRO; + return IIO_AVAIL_LIST; + + case IIO_CHAN_INFO_SCALE: { + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + ret = regmap_read(regmap, VEML3328_REG_CONF, ®_val); + if (ret) + return ret; + + it_inx = FIELD_GET(VEML3328_CONF_IT_MASK, reg_val); + if (it_inx >= ARRAY_SIZE(veml3328_it_times)) + return -EINVAL; + + *length = 8; + *vals = (const int *)veml3328_scale_vals[it_inx]; + *type = IIO_VAL_INT_PLUS_MICRO; + return IIO_AVAIL_LIST; + } + default: + return -EINVAL; + } +} + +static int veml3328_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct veml3328_data *data = iio_priv(indio_dev); + struct regmap *regmap = data->regmap; + struct device *dev = regmap_get_device(regmap); + unsigned int reg_val; + int i, it_inx; + int ret; + + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + guard(mutex)(&data->lock); + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + if (val != 0) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(veml3328_it_times); i++) { + if (veml3328_it_times[i][1] == val2) + break; + } + + if (i == ARRAY_SIZE(veml3328_it_times)) + return -EINVAL; + + return regmap_update_bits(regmap, VEML3328_REG_CONF, + VEML3328_CONF_IT_MASK, + FIELD_PREP(VEML3328_CONF_IT_MASK, i)); + + case IIO_CHAN_INFO_SCALE: + ret = regmap_read(regmap, VEML3328_REG_CONF, ®_val); + if (ret) + return ret; + + it_inx = FIELD_GET(VEML3328_CONF_IT_MASK, reg_val); + if (it_inx >= ARRAY_SIZE(veml3328_it_times)) + return -EINVAL; + + for (i = 0; i < 4; i++) { + if (val == veml3328_scale_vals[it_inx][i * 2] && + val2 == veml3328_scale_vals[it_inx][i * 2 + 1]) + break; + } + + if (i == 4) + return -EINVAL; + + return regmap_update_bits(regmap, VEML3328_REG_CONF, + VEML3328_CONF_GAIN_MASK, + FIELD_PREP(VEML3328_CONF_GAIN_MASK, i)); + + default: + return -EINVAL; + } +} + +static const struct iio_info veml3328_info = { + .read_raw = veml3328_read_raw, + .write_raw = veml3328_write_raw, + .read_avail = veml3328_read_avail, +}; + +static int veml3328_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct veml3328_data *data; + struct iio_dev *indio_dev; + unsigned int reg_val; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + + data->regmap = devm_regmap_init_i2c(client, &veml3328_regmap_config); + if (IS_ERR(data->regmap)) + return dev_err_probe(dev, PTR_ERR(data->regmap), + "Failed to initialize regmap\n"); + + ret = devm_mutex_init(dev, &data->lock); + if (ret) + return ret; + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable regulator\n"); + + ret = regmap_read(data->regmap, VEML3328_REG_ID, ®_val); + if (ret) + return dev_err_probe(dev, ret, "Failed to read ID register\n"); + + if ((reg_val & 0xff) != VEML3328_ID_VAL) + dev_warn(dev, "Unknown device ID: 0x%02x\n", reg_val & 0xff); + + ret = veml3328_power_up(data); + if (ret) + return dev_err_probe(dev, ret, "Failed to power on sensor\n"); + + ret = devm_add_action_or_reset(dev, veml3328_power_down_action, data); + if (ret) + return dev_err_probe(dev, ret, "Failed to register teardown\n"); + + indio_dev->name = "veml3328"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &veml3328_info; + indio_dev->channels = veml3328_channels; + indio_dev->num_channels = ARRAY_SIZE(veml3328_channels); + + pm_runtime_set_active(dev); + pm_runtime_set_autosuspend_delay(dev, 2000); + pm_runtime_use_autosuspend(dev); + + ret = devm_pm_runtime_enable(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable runtime PM\n"); + + return devm_iio_device_register(dev, indio_dev); +} + +static int veml3328_runtime_suspend(struct device *dev) +{ + struct veml3328_data *data = iio_priv(dev_get_drvdata(dev)); + int ret; + + ret = veml3328_power_down(data); + if (ret) + dev_err(dev, "Failed to suspend: %d\n", ret); + + return ret; +} + +static int veml3328_runtime_resume(struct device *dev) +{ + struct veml3328_data *data = iio_priv(dev_get_drvdata(dev)); + int ret; + + ret = veml3328_power_up(data); + if (ret) + dev_err(dev, "Failed to resume: %d\n", ret); + + return ret; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(veml3328_pm_ops, + veml3328_runtime_suspend, + veml3328_runtime_resume, + NULL); + +static const struct of_device_id veml3328_of_match[] = { + { .compatible = "vishay,veml3328" }, + { } +}; +MODULE_DEVICE_TABLE(of, veml3328_of_match); + +static const struct i2c_device_id veml3328_id[] = { + { .name = "veml3328" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, veml3328_id); + +static struct i2c_driver veml3328_driver = { + .driver = { + .name = "veml3328", + .of_match_table = veml3328_of_match, + .pm = pm_ptr(&veml3328_pm_ops), + }, + .probe = veml3328_probe, + .id_table = veml3328_id, +}; +module_i2c_driver(veml3328_driver); + +MODULE_AUTHOR("Joshua Crofts <joshua.crofts1@gmail.com>"); +MODULE_DESCRIPTION("VEML3328 RGBCIR Light Sensor"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/light/veml6030.c b/drivers/iio/light/veml6030.c index 6bcacae3863c..ec9c127e7d8a 100644 --- a/drivers/iio/light/veml6030.c +++ b/drivers/iio/light/veml6030.c @@ -521,13 +521,9 @@ static int veml6030_write_persistence(struct iio_dev *indio_dev, static int veml6030_set_scale(struct iio_dev *indio_dev, int val, int val2) { - int ret, gain_sel, it_idx, it_sel; + int ret, gain_sel, it_sel; struct veml6030_data *data = iio_priv(indio_dev); - ret = regmap_field_read(data->rf.it, &it_idx); - if (ret) - return ret; - ret = iio_gts_find_gain_time_sel_for_scale(&data->gts, val, val2, &gain_sel, &it_sel); if (ret) @@ -875,9 +871,11 @@ static irqreturn_t veml6030_event_handler(int irq, void *private) else evtdir = IIO_EV_DIR_FALLING; - iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, - 0, IIO_EV_TYPE_THRESH, evtdir), - iio_get_time_ns(indio_dev)); + iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_LIGHT, + 0, + IIO_EV_TYPE_THRESH, + evtdir), + iio_get_time_ns(indio_dev)); return IRQ_HANDLED; } @@ -923,9 +921,7 @@ static int veml6030_set_info(struct iio_dev *indio_dev) IRQF_TRIGGER_LOW | IRQF_ONESHOT, indio_dev->name, indio_dev); if (ret < 0) - return dev_err_probe(&client->dev, ret, - "irq %d request failed\n", - client->irq); + return ret; indio_dev->info = &veml6030_info; } else { @@ -1218,9 +1214,9 @@ static const struct of_device_id veml6030_of_match[] = { MODULE_DEVICE_TABLE(of, veml6030_of_match); static const struct i2c_device_id veml6030_id[] = { - { "veml6030", (kernel_ulong_t)&veml6030_chip}, - { "veml6035", (kernel_ulong_t)&veml6035_chip}, - { "veml7700", (kernel_ulong_t)&veml7700_chip}, + { .name = "veml6030", .driver_data = (kernel_ulong_t)&veml6030_chip }, + { .name = "veml6035", .driver_data = (kernel_ulong_t)&veml6035_chip }, + { .name = "veml7700", .driver_data = (kernel_ulong_t)&veml7700_chip }, { } }; MODULE_DEVICE_TABLE(i2c, veml6030_id); diff --git a/drivers/iio/light/veml6040.c b/drivers/iio/light/veml6040.c index f563f9f0ee67..0960784b8866 100644 --- a/drivers/iio/light/veml6040.c +++ b/drivers/iio/light/veml6040.c @@ -254,7 +254,7 @@ static int veml6040_probe(struct i2c_client *client) } static const struct i2c_device_id veml6040_id_table[] = { - {"veml6040"}, + { .name = "veml6040" }, { } }; MODULE_DEVICE_TABLE(i2c, veml6040_id_table); diff --git a/drivers/iio/light/veml6046x00.c b/drivers/iio/light/veml6046x00.c index e60f24d46e7b..b40b70679640 100644 --- a/drivers/iio/light/veml6046x00.c +++ b/drivers/iio/light/veml6046x00.c @@ -13,7 +13,6 @@ #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/time.h> @@ -1009,7 +1008,7 @@ static const struct of_device_id veml6046x00_of_match[] = { MODULE_DEVICE_TABLE(of, veml6046x00_of_match); static const struct i2c_device_id veml6046x00_id[] = { - { "veml6046x00" }, + { .name = "veml6046x00" }, { } }; MODULE_DEVICE_TABLE(i2c, veml6046x00_id); diff --git a/drivers/iio/light/veml6070.c b/drivers/iio/light/veml6070.c index 6d4483c85f30..c99336bd919f 100644 --- a/drivers/iio/light/veml6070.c +++ b/drivers/iio/light/veml6070.c @@ -134,9 +134,7 @@ static int veml6070_read(struct veml6070_data *data) if (ret < 0) return ret; - ret = (msb << 8) | lsb; - - return 0; + return (msb << 8) | lsb; } static const struct iio_chan_spec veml6070_channels[] = { @@ -247,13 +245,6 @@ static const struct iio_info veml6070_info = { .write_raw = veml6070_write_raw, }; -static void veml6070_i2c_unreg(void *p) -{ - struct veml6070_data *data = p; - - i2c_unregister_device(data->client2); -} - static int veml6070_probe(struct i2c_client *client) { struct veml6070_data *data; @@ -283,7 +274,8 @@ static int veml6070_probe(struct i2c_client *client) if (ret < 0) return ret; - data->client2 = i2c_new_dummy_device(client->adapter, VEML6070_ADDR_DATA_LSB); + data->client2 = devm_i2c_new_dummy_device(&client->dev, client->adapter, + VEML6070_ADDR_DATA_LSB); if (IS_ERR(data->client2)) return dev_err_probe(&client->dev, PTR_ERR(data->client2), "i2c device for second chip address failed\n"); @@ -294,15 +286,11 @@ static int veml6070_probe(struct i2c_client *client) if (ret < 0) return ret; - ret = devm_add_action_or_reset(&client->dev, veml6070_i2c_unreg, data); - if (ret < 0) - return ret; - return devm_iio_device_register(&client->dev, indio_dev); } static const struct i2c_device_id veml6070_id[] = { - { "veml6070" }, + { .name = "veml6070" }, { } }; MODULE_DEVICE_TABLE(i2c, veml6070_id); diff --git a/drivers/iio/light/veml6075.c b/drivers/iio/light/veml6075.c index edbb43407054..59187244aba0 100644 --- a/drivers/iio/light/veml6075.c +++ b/drivers/iio/light/veml6075.c @@ -100,7 +100,7 @@ static const struct iio_chan_spec veml6075_channels[] = { static int veml6075_request_measurement(struct veml6075_data *data) { - int ret, conf, int_time; + int ret, conf, int_time, int_index; ret = regmap_read(data->regmap, VEML6075_CMD_CONF, &conf); if (ret < 0) @@ -117,7 +117,11 @@ static int veml6075_request_measurement(struct veml6075_data *data) * time for all possible configurations. Using a 1.50 factor simplifies * operations and ensures reliability under all circumstances. */ - int_time = veml6075_it_ms[FIELD_GET(VEML6075_CONF_IT, conf)]; + int_index = FIELD_GET(VEML6075_CONF_IT, conf); + if (int_index >= ARRAY_SIZE(veml6075_it_ms)) + return -EINVAL; + + int_time = veml6075_it_ms[int_index]; msleep(int_time + (int_time / 2)); /* shutdown again, data registers are still accessible */ @@ -451,7 +455,7 @@ static int veml6075_probe(struct i2c_client *client) } static const struct i2c_device_id veml6075_id[] = { - { "veml6075" }, + { .name = "veml6075" }, { } }; MODULE_DEVICE_TABLE(i2c, veml6075_id); diff --git a/drivers/iio/light/vl6180.c b/drivers/iio/light/vl6180.c index c1314b144367..aef8a5333442 100644 --- a/drivers/iio/light/vl6180.c +++ b/drivers/iio/light/vl6180.c @@ -16,7 +16,6 @@ */ #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/mutex.h> #include <linux/err.h> @@ -722,7 +721,7 @@ static int vl6180_probe(struct i2c_client *client) IRQF_ONESHOT, indio_dev->name, indio_dev); if (ret) - return dev_err_probe(&client->dev, ret, "devm_request_irq error\n"); + return ret; init_completion(&data->completion); @@ -750,7 +749,7 @@ static const struct of_device_id vl6180_of_match[] = { MODULE_DEVICE_TABLE(of, vl6180_of_match); static const struct i2c_device_id vl6180_id[] = { - { "vl6180" }, + { .name = "vl6180" }, { } }; MODULE_DEVICE_TABLE(i2c, vl6180_id); diff --git a/drivers/iio/light/zopt2201.c b/drivers/iio/light/zopt2201.c index 1dba1b949cc3..b53be5f7354e 100644 --- a/drivers/iio/light/zopt2201.c +++ b/drivers/iio/light/zopt2201.c @@ -10,17 +10,17 @@ * TODO: interrupt support, ALS/UVB raw mode */ -#include <linux/module.h> +#include <linux/cleanup.h> +#include <linux/delay.h> +#include <linux/err.h> #include <linux/i2c.h> +#include <linux/module.h> #include <linux/mutex.h> -#include <linux/err.h> -#include <linux/delay.h> +#include <linux/unaligned.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> -#include <linux/unaligned.h> - #define ZOPT2201_DRV_NAME "zopt2201" /* Registers */ @@ -186,10 +186,10 @@ static int zopt2201_read(struct zopt2201_data *data, u8 reg) u8 buf[3]; int ret; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); ret = zopt2201_enable_mode(data, reg == ZOPT2201_UVB_DATA); if (ret < 0) - goto fail; + return ret; while (tries--) { unsigned long t = zopt2201_resolution[data->res].us; @@ -200,30 +200,25 @@ static int zopt2201_read(struct zopt2201_data *data, u8 reg) msleep(t / 1000); ret = i2c_smbus_read_byte_data(client, ZOPT2201_MAIN_STATUS); if (ret < 0) - goto fail; + return ret; if (ret & ZOPT2201_MAIN_STATUS_DRDY) break; } if (tries < 0) { ret = -ETIMEDOUT; - goto fail; + return ret; } ret = i2c_smbus_read_i2c_block_data(client, reg, sizeof(buf), buf); if (ret < 0) - goto fail; + return ret; ret = i2c_smbus_write_byte_data(client, ZOPT2201_MAIN_CTRL, 0x00); if (ret < 0) - goto fail; - mutex_unlock(&data->lock); + return ret; return get_unaligned_le24(&buf[0]); - -fail: - mutex_unlock(&data->lock); - return ret; } static const struct iio_chan_spec zopt2201_channels[] = { @@ -317,17 +312,15 @@ static int zopt2201_set_resolution(struct zopt2201_data *data, u8 res) static int zopt2201_write_resolution(struct zopt2201_data *data, int val, int val2) { - int i, ret; + int i; if (val != 0) return -EINVAL; for (i = 0; i < ARRAY_SIZE(zopt2201_resolution); i++) if (val2 == zopt2201_resolution[i].us) { - mutex_lock(&data->lock); - ret = zopt2201_set_resolution(data, i); - mutex_unlock(&data->lock); - return ret; + guard(mutex)(&data->lock); + return zopt2201_set_resolution(data, i); } return -EINVAL; @@ -351,16 +344,12 @@ static int zopt2201_write_scale_by_idx(struct zopt2201_data *data, int idx, { int ret; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); ret = zopt2201_set_resolution(data, zopt2201_scale_array[idx].res); if (ret < 0) - goto unlock; - - ret = zopt2201_set_gain(data, zopt2201_scale_array[idx].gain); + return ret; -unlock: - mutex_unlock(&data->lock); - return ret; + return zopt2201_set_gain(data, zopt2201_scale_array[idx].gain); } static int zopt2201_write_scale_als(struct zopt2201_data *data, @@ -527,7 +516,7 @@ static int zopt2201_probe(struct i2c_client *client) } static const struct i2c_device_id zopt2201_id[] = { - { "zopt2201" }, + { .name = "zopt2201" }, { } }; MODULE_DEVICE_TABLE(i2c, zopt2201_id); diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index fb313e591e85..d359003b248e 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig @@ -151,6 +151,17 @@ config MMC5633 To compile this driver as a module, choose M here: the module will be called mmc5633 +config MMC5983 + tristate "MEMSIC MMC5983 3-axis magnetic sensor" + depends on I2C + select REGMAP_I2C + help + Say yes here to build support for the MEMSIC MMC5983 3-axis + magnetic sensor. + + To compile this driver as a module, choose M here: the module + will be called mmc5983 + config IIO_ST_MAGN_3AXIS tristate "STMicroelectronics magnetometers 3-Axis Driver" depends on (I2C || SPI_MASTER) && SYSFS @@ -198,6 +209,28 @@ config INFINEON_TLV493D To compile this driver as a module, choose M here: the module will be called tlv493d. +config QMC5883L + tristate "QST QMC5883L 3-Axis Magnetic Sensor" + depends on I2C + select REGMAP_I2C + help + Say Y here to add support driver for QST QMC5883L 3-Axis + Magnetic Sensor. + + To compile this driver as a module, choose M here: the + module will be called qmc5883l. + +config QMC6308 + tristate "QST QMC6308 3-Axis Magnetic Sensor" + depends on I2C + select REGMAP_I2C + help + Say Y here to add support for the QST QMC6308 3-Axis + Magnetic Sensor. + + To compile this driver as a module, choose M here: the + module will be called qmc6308. + config SENSORS_HMC5843 tristate select IIO_BUFFER diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile index 5bd227f8c120..8f2205975c1b 100644 --- a/drivers/iio/magnetometer/Makefile +++ b/drivers/iio/magnetometer/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_MAG3110) += mag3110.o obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o obj-$(CONFIG_MMC35240) += mmc35240.o obj-$(CONFIG_MMC5633) += mmc5633.o +obj-$(CONFIG_MMC5983) += mmc5983.o obj-$(CONFIG_IIO_ST_MAGN_3AXIS) += st_magn.o st_magn-y := st_magn_core.o @@ -26,6 +27,9 @@ obj-$(CONFIG_IIO_ST_MAGN_SPI_3AXIS) += st_magn_spi.o obj-$(CONFIG_INFINEON_TLV493D) += tlv493d.o +obj-$(CONFIG_QMC5883L) += qmc5883l.o +obj-$(CONFIG_QMC6308) += qmc6308.o + obj-$(CONFIG_SENSORS_HMC5843) += hmc5843_core.o obj-$(CONFIG_SENSORS_HMC5843_I2C) += hmc5843_i2c.o obj-$(CONFIG_SENSORS_HMC5843_SPI) += hmc5843_spi.o diff --git a/drivers/iio/magnetometer/af8133j.c b/drivers/iio/magnetometer/af8133j.c index b1768c3aa8f3..352f53edad9a 100644 --- a/drivers/iio/magnetometer/af8133j.c +++ b/drivers/iio/magnetometer/af8133j.c @@ -504,7 +504,7 @@ static const struct of_device_id af8133j_of_match[] = { MODULE_DEVICE_TABLE(of, af8133j_of_match); static const struct i2c_device_id af8133j_id[] = { - { "af8133j" }, + { .name = "af8133j" }, { } }; MODULE_DEVICE_TABLE(i2c, af8133j_id); diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c index 68ece700c7ce..375023db2758 100644 --- a/drivers/iio/magnetometer/ak8974.c +++ b/drivers/iio/magnetometer/ak8974.c @@ -12,7 +12,6 @@ * Author: Linus Walleij <linus.walleij@linaro.org> */ #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/kernel.h> #include <linux/i2c.h> #include <linux/interrupt.h> @@ -380,11 +379,7 @@ static int ak8974_getresult(struct ak8974 *ak8974, __le16 *result) return -ERANGE; } - ret = regmap_bulk_read(ak8974->map, AK8974_DATA_X, result, 6); - if (ret) - return ret; - - return ret; + return regmap_bulk_read(ak8974->map, AK8974_DATA_X, result, 6); } static irqreturn_t ak8974_drdy_irq(int irq, void *d) @@ -577,7 +572,7 @@ static int ak8974_measure_channel(struct ak8974 *ak8974, unsigned long address, /* * This explicit cast to (s16) is necessary as the measurement * is done in 2's complement with positive and negative values. - * The follwing assignment to *val will then convert the signed + * The following assignment to *val will then convert the signed * s16 value to a signed int value. */ *val = (s16)le16_to_cpu(hw_values[address]); @@ -927,11 +922,8 @@ static int ak8974_probe(struct i2c_client *i2c) irq_trig, ak8974->name, ak8974); - if (ret) { - dev_err(&i2c->dev, "unable to request DRDY IRQ " - "- proceeding without IRQ\n"); + if (ret) goto no_irq; - } ak8974->drdy_irq = true; } @@ -1017,10 +1009,10 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ak8974_dev_pm_ops, ak8974_runtime_suspend, ak8974_runtime_resume, NULL); static const struct i2c_device_id ak8974_id[] = { - { "ami305" }, - { "ami306" }, - { "ak8974" }, - { "hscdtd008a" }, + { .name = "ami305" }, + { .name = "ami306" }, + { .name = "ak8974" }, + { .name = "hscdtd008a" }, { } }; MODULE_DEVICE_TABLE(i2c, ak8974_id); diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index d30315ad85de..8b0c07f82602 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -7,24 +7,30 @@ * Copyright (c) 2010, NVIDIA Corporation. */ -#include <linux/module.h> -#include <linux/mod_devicetable.h> -#include <linux/kernel.h> -#include <linux/slab.h> +#include <linux/array_size.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/interrupt.h> -#include <linux/err.h> +#include <linux/iopoll.h> +#include <linux/jiffies.h> +#include <linux/minmax.h> +#include <linux/module.h> #include <linux/mutex.h> -#include <linux/delay.h> -#include <linux/bitops.h> -#include <linux/gpio/consumer.h> -#include <linux/regulator/consumer.h> #include <linux/pm_runtime.h> +#include <linux/property.h> +#include <linux/regulator/consumer.h> +#include <linux/time.h> +#include <linux/types.h> +#include <linux/wait.h> + +#include <asm/byteorder.h> -#include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> #include <linux/iio/buffer.h> -#include <linux/iio/trigger.h> +#include <linux/iio/iio.h> #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> @@ -128,13 +134,6 @@ #define AK09912_MAX_REGS AK09912_REG_ASAZ /* - * Miscellaneous values. - */ -#define AK8975_MAX_CONVERSION_TIMEOUT 500 -#define AK8975_CONVERSION_DONE_POLL_TIME 10 -#define AK8975_DATA_READY_TIMEOUT ((100*HZ)/1000) - -/* * Precalculate scale factor (in Gauss units) for each axis and * store in the device data. * @@ -456,7 +455,8 @@ static int ak8975_power_on(const struct ak8975_data *data) * and the minimum wait time before mode setting is 100us, in * total 300us. Add some margin and say minimum 500us here. */ - usleep_range(500, 1000); + fsleep(500); + return 0; } @@ -473,9 +473,10 @@ static void ak8975_power_off(const struct ak8975_data *data) * Return 0 if the i2c device is the one we expect. * return a negative error number otherwise */ -static int ak8975_who_i_am(struct i2c_client *client, +static int ak8975_who_i_am(const struct ak8975_data *data, enum asahi_compass_chipset type) { + struct i2c_client *client = data->client; u8 wia_val[2]; int ret; @@ -489,12 +490,18 @@ static int ak8975_who_i_am(struct i2c_client *client, * AK8975 | DEVICE_ID | NA * AK8963 | DEVICE_ID | NA */ - ret = i2c_smbus_read_i2c_block_data_or_emulated( - client, AK09912_REG_WIA1, 2, wia_val); + ret = i2c_smbus_read_i2c_block_data_or_emulated(client, + AK09912_REG_WIA1, + sizeof(wia_val), + wia_val); if (ret < 0) { dev_err(&client->dev, "Error reading WIA\n"); return ret; } + if (ret != sizeof(wia_val)) { + dev_err(&client->dev, "Error reading WIA\n"); + return -EIO; + } if (wia_val[0] != AK8975_DEVICE_ID) return -ENODEV; @@ -541,12 +548,12 @@ static int ak8975_set_mode(struct ak8975_data *data, enum ak_ctrl_mode mode) data->def->ctrl_modes[mode]; ret = i2c_smbus_write_byte_data(data->client, data->def->ctrl_regs[CNTL], regval); - if (ret < 0) { + if (ret < 0) return ret; - } + data->cntl_cache = regval; - /* After mode change wait atleast 100us */ - usleep_range(100, 500); + /* After mode change wait at least 100us */ + fsleep(100); return 0; } @@ -570,8 +577,8 @@ static irqreturn_t ak8975_irq_handler(int irq, void *data) static int ak8975_setup_irq(struct ak8975_data *data) { struct i2c_client *client = data->client; - int rc; int irq; + int ret; init_waitqueue_head(&data->data_ready_queue); clear_bit(0, &data->flags); @@ -580,28 +587,24 @@ static int ak8975_setup_irq(struct ak8975_data *data) else irq = gpiod_to_irq(data->eoc_gpiod); - rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler, - IRQF_TRIGGER_RISING, - dev_name(&client->dev), data); - if (rc < 0) { - dev_err(&client->dev, "irq %d request failed: %d\n", irq, rc); - return rc; - } + ret = devm_request_irq(&client->dev, irq, ak8975_irq_handler, + IRQF_TRIGGER_RISING, + dev_name(&client->dev), data); + if (ret) + return ret; data->eoc_irq = irq; - return rc; + return 0; } - /* * Perform some start-of-day setup, including reading the asa calibration * values and caching them. */ -static int ak8975_setup(struct i2c_client *client) +static int ak8975_setup(struct ak8975_data *data) { - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct ak8975_data *data = iio_priv(indio_dev); + struct i2c_client *client = data->client; int ret; /* Write the fused rom access mode. */ @@ -612,13 +615,18 @@ static int ak8975_setup(struct i2c_client *client) } /* Get asa data and store in the device data. */ - ret = i2c_smbus_read_i2c_block_data_or_emulated( - client, data->def->ctrl_regs[ASA_BASE], - 3, data->asa); + ret = i2c_smbus_read_i2c_block_data_or_emulated(client, + data->def->ctrl_regs[ASA_BASE], + sizeof(data->asa), + data->asa); if (ret < 0) { dev_err(&client->dev, "Not able to read asa data\n"); return ret; } + if (ret != sizeof(data->asa)) { + dev_err(&client->dev, "Error reading asa data\n"); + return -EIO; + } /* After reading fuse ROM data set power-down mode */ ret = ak8975_set_mode(data, POWER_DOWN); @@ -643,22 +651,23 @@ static int ak8975_setup(struct i2c_client *client) return 0; } -static int wait_conversion_complete_gpio(struct ak8975_data *data) +static int wait_conversion_complete_gpio(struct ak8975_data *data, + unsigned int poll_ms, + unsigned int timeout_ms) { struct i2c_client *client = data->client; - u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT; int ret; + int val; /* Wait for the conversion to complete. */ - while (timeout_ms) { - msleep(AK8975_CONVERSION_DONE_POLL_TIME); - if (gpiod_get_value(data->eoc_gpiod)) - break; - timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME; - } - if (!timeout_ms) { - dev_err(&client->dev, "Conversion timeout happened\n"); - return -EINVAL; + ret = readx_poll_timeout(gpiod_get_value, data->eoc_gpiod, val, val != 0, + poll_ms * USEC_PER_MSEC, + timeout_ms * USEC_PER_MSEC); + if (ret) + return ret; + if (val < 0) { + dev_err(&client->dev, "Error in reading GPIOD\n"); + return val; } ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST1]); @@ -668,54 +677,49 @@ static int wait_conversion_complete_gpio(struct ak8975_data *data) return ret; } -static int wait_conversion_complete_polled(struct ak8975_data *data) +static int wait_conversion_complete_polled(struct ak8975_data *data, + unsigned int poll_ms, + unsigned int timeout_ms) { struct i2c_client *client = data->client; - u8 read_status; - u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT; int ret; + int val; /* Wait for the conversion to complete. */ - while (timeout_ms) { - msleep(AK8975_CONVERSION_DONE_POLL_TIME); - ret = i2c_smbus_read_byte_data(client, - data->def->ctrl_regs[ST1]); - if (ret < 0) { - dev_err(&client->dev, "Error in reading ST1\n"); - return ret; - } - read_status = ret; - if (read_status) - break; - timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME; - } - if (!timeout_ms) { - dev_err(&client->dev, "Conversion timeout happened\n"); - return -EINVAL; - } + ret = read_poll_timeout(i2c_smbus_read_byte_data, val, val != 0, + poll_ms * USEC_PER_MSEC, + timeout_ms * USEC_PER_MSEC, + true, + client, data->def->ctrl_regs[ST1]); + if (ret) + return ret; + if (val < 0) + dev_err(&client->dev, "Error in reading ST1\n"); - return read_status; + return val; } -/* Returns 0 if the end of conversion interrupt occured or -ETIME otherwise */ -static int wait_conversion_complete_interrupt(struct ak8975_data *data) +/* Returns 0 if the end of conversion interrupt occurred or -ETIMEDOUT otherwise */ +static int wait_conversion_complete_interrupt(struct ak8975_data *data, + unsigned int timeout_ms) { int ret; ret = wait_event_timeout(data->data_ready_queue, test_bit(0, &data->flags), - AK8975_DATA_READY_TIMEOUT); + msecs_to_jiffies(timeout_ms)); clear_bit(0, &data->flags); - return ret > 0 ? 0 : -ETIME; + return ret > 0 ? 0 : -ETIMEDOUT; } -static int ak8975_start_read_axis(struct ak8975_data *data, - const struct i2c_client *client) +static int ak8975_start_read_axis(struct ak8975_data *data) { - /* Set up the device for taking a sample. */ - int ret = ak8975_set_mode(data, MODE_ONCE); + struct i2c_client *client = data->client; + int ret; + /* Set up the device for taking a sample. */ + ret = ak8975_set_mode(data, MODE_ONCE); if (ret < 0) { dev_err(&client->dev, "Error in setting operating mode\n"); return ret; @@ -723,11 +727,11 @@ static int ak8975_start_read_axis(struct ak8975_data *data, /* Wait for the conversion to complete. */ if (data->eoc_irq) - ret = wait_conversion_complete_interrupt(data); + ret = wait_conversion_complete_interrupt(data, 100); else if (data->eoc_gpiod) - ret = wait_conversion_complete_gpio(data); + ret = wait_conversion_complete_gpio(data, 10, 500); else - ret = wait_conversion_complete_polled(data); + ret = wait_conversion_complete_polled(data, 10, 500); if (ret < 0) return ret; @@ -742,24 +746,28 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) const struct i2c_client *client = data->client; const struct ak_def *def = data->def; __le16 rval; - u16 buff; int ret; pm_runtime_get_sync(&data->client->dev); mutex_lock(&data->lock); - ret = ak8975_start_read_axis(data, client); + ret = ak8975_start_read_axis(data); if (ret) goto exit; - ret = i2c_smbus_read_i2c_block_data_or_emulated( - client, def->data_regs[index], - sizeof(rval), (u8*)&rval); + ret = i2c_smbus_read_i2c_block_data_or_emulated(client, + def->data_regs[index], + sizeof(rval), + (u8 *)&rval); if (ret < 0) goto exit; + if (ret != sizeof(rval)) { + ret = -EIO; + goto exit; + } - /* Read out ST2 for release lock on measurment data. */ + /* Read out ST2 for release lock on measurement data. */ ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST2]); if (ret < 0) { dev_err(&client->dev, "Error in reading ST2\n"); @@ -778,12 +786,13 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) pm_runtime_put_autosuspend(&data->client->dev); /* Swap bytes and convert to valid range. */ - buff = le16_to_cpu(rval); - *val = clamp_t(s16, buff, -def->range, def->range); + *val = clamp_t(s16, le16_to_cpu(rval), -def->range, def->range); + return IIO_VAL_INT; exit: mutex_unlock(&data->lock); + pm_runtime_put_autosuspend(&data->client->dev); dev_err(&client->dev, "Error in reading axis\n"); return ret; } @@ -859,7 +868,7 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev) mutex_lock(&data->lock); - ret = ak8975_start_read_axis(data, client); + ret = ak8975_start_read_axis(data); if (ret) goto unlock; @@ -869,10 +878,12 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev) */ ret = i2c_smbus_read_i2c_block_data_or_emulated(client, def->data_regs[0], - 3 * sizeof(fval[0]), + sizeof(fval), (u8 *)fval); if (ret < 0) goto unlock; + if (ret != sizeof(fval)) + goto unlock; mutex_unlock(&data->lock); @@ -901,6 +912,28 @@ static irqreturn_t ak8975_handle_trigger(int irq, void *p) return IRQ_HANDLED; } +static int ak8975_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ak8975_data *data = iio_priv(indio_dev); + struct device *dev = &data->client->dev; + + return pm_runtime_resume_and_get(dev); +} + +static int ak8975_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ak8975_data *data = iio_priv(indio_dev); + struct device *dev = &data->client->dev; + + pm_runtime_put_autosuspend(dev); + + return 0; +} + +static const struct iio_buffer_setup_ops ak8975_buffer_setup_ops = { + .preenable = ak8975_buffer_preenable, + .postdisable = ak8975_buffer_postdisable, +}; static int ak8975_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); @@ -908,8 +941,8 @@ static int ak8975_probe(struct i2c_client *client) struct iio_dev *indio_dev; struct gpio_desc *eoc_gpiod; struct gpio_desc *reset_gpiod; - int err; const char *name = NULL; + int ret; /* * Grab and set up the supplied GPIO. @@ -919,8 +952,7 @@ static int ak8975_probe(struct i2c_client *client) eoc_gpiod = devm_gpiod_get_optional(&client->dev, NULL, GPIOD_IN); if (IS_ERR(eoc_gpiod)) return PTR_ERR(eoc_gpiod); - if (eoc_gpiod) - gpiod_set_consumer_name(eoc_gpiod, "ak_8975"); + gpiod_set_consumer_name(eoc_gpiod, "ak_8975"); /* * According to AK09911 datasheet, if reset GPIO is provided then @@ -945,9 +977,9 @@ static int ak8975_probe(struct i2c_client *client) data->reset_gpiod = reset_gpiod; data->eoc_irq = 0; - err = iio_read_mount_matrix(&client->dev, &data->orientation); - if (err) - return err; + ret = iio_read_mount_matrix(&client->dev, &data->orientation); + if (ret) + return ret; /* id will be NULL when enumerated via ACPI */ data->def = i2c_get_match_data(client); @@ -968,20 +1000,20 @@ static int ak8975_probe(struct i2c_client *client) if (IS_ERR(data->vid)) return PTR_ERR(data->vid); - err = ak8975_power_on(data); - if (err) - return err; + ret = ak8975_power_on(data); + if (ret) + return ret; - err = ak8975_who_i_am(client, data->def->type); - if (err < 0) { + ret = ak8975_who_i_am(data, data->def->type); + if (ret) { dev_err(&client->dev, "Unexpected device\n"); goto power_off; } dev_dbg(&client->dev, "Asahi compass chip %s\n", name); /* Perform some basic start-of-day setup of the device. */ - err = ak8975_setup(client); - if (err < 0) { + ret = ak8975_setup(data); + if (ret) { dev_err(&client->dev, "%s initialization fails\n", name); goto power_off; } @@ -994,15 +1026,15 @@ static int ak8975_probe(struct i2c_client *client) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->name = name; - err = iio_triggered_buffer_setup(indio_dev, NULL, ak8975_handle_trigger, - NULL); - if (err) { + ret = iio_triggered_buffer_setup(indio_dev, NULL, ak8975_handle_trigger, + &ak8975_buffer_setup_ops); + if (ret) { dev_err(&client->dev, "triggered buffer setup failed\n"); goto power_off; } - err = iio_device_register(indio_dev); - if (err) { + ret = iio_device_register(indio_dev); + if (ret) { dev_err(&client->dev, "device register failed\n"); goto cleanup_buffer; } @@ -1025,7 +1057,7 @@ cleanup_buffer: iio_triggered_buffer_cleanup(indio_dev); power_off: ak8975_power_off(data); - return err; + return ret; } static void ak8975_remove(struct i2c_client *client) @@ -1099,13 +1131,13 @@ static const struct acpi_device_id ak_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, ak_acpi_match); static const struct i2c_device_id ak8975_id[] = { - {"AK8963", (kernel_ulong_t)&ak_def_array[AK8963] }, - {"ak8963", (kernel_ulong_t)&ak_def_array[AK8963] }, - {"ak8975", (kernel_ulong_t)&ak_def_array[AK8975] }, - {"ak09911", (kernel_ulong_t)&ak_def_array[AK09911] }, - {"ak09912", (kernel_ulong_t)&ak_def_array[AK09912] }, - {"ak09916", (kernel_ulong_t)&ak_def_array[AK09916] }, - {"ak09918", (kernel_ulong_t)&ak_def_array[AK09918] }, + { .name = "AK8963", .driver_data = (kernel_ulong_t)&ak_def_array[AK8963] }, + { .name = "ak8963", .driver_data = (kernel_ulong_t)&ak_def_array[AK8963] }, + { .name = "ak8975", .driver_data = (kernel_ulong_t)&ak_def_array[AK8975] }, + { .name = "ak09911", .driver_data = (kernel_ulong_t)&ak_def_array[AK09911] }, + { .name = "ak09912", .driver_data = (kernel_ulong_t)&ak_def_array[AK09912] }, + { .name = "ak09916", .driver_data = (kernel_ulong_t)&ak_def_array[AK09916] }, + { .name = "ak09918", .driver_data = (kernel_ulong_t)&ak_def_array[AK09918] }, { } }; MODULE_DEVICE_TABLE(i2c, ak8975_id); diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index a022e1805dff..32dff9cdd0f7 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -9,22 +9,25 @@ * (C) Copyright 2011~2014 Bosch Sensortec GmbH All Rights Reserved */ -#include <linux/module.h> +#include <linux/bitfield.h> +#include <linux/cleanup.h> +#include <linux/delay.h> #include <linux/i2c.h> #include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/slab.h> +#include <linux/module.h> #include <linux/pm.h> #include <linux/pm_runtime.h> -#include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> + #include <linux/iio/buffer.h> #include <linux/iio/events.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> #include <linux/iio/trigger.h> #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> -#include <linux/regmap.h> -#include <linux/regulator/consumer.h> #include "bmc150_magn.h" @@ -148,14 +151,16 @@ struct bmc150_magn_data { static const struct { int freq; u8 reg_val; -} bmc150_magn_samp_freq_table[] = { {2, 0x01}, - {6, 0x02}, - {8, 0x03}, - {10, 0x00}, - {15, 0x04}, - {20, 0x05}, - {25, 0x06}, - {30, 0x07} }; +} bmc150_magn_samp_freq_table[] = { + { 2, 0x01 }, + { 6, 0x02 }, + { 8, 0x03 }, + { 10, 0x00 }, + { 15, 0x04 }, + { 20, 0x05 }, + { 25, 0x06 }, + { 30, 0x07 }, +}; enum bmc150_magn_presets { LOW_POWER_PRESET, @@ -169,10 +174,10 @@ static const struct bmc150_magn_preset { u8 rep_z; u8 odr; } bmc150_magn_presets_table[] = { - [LOW_POWER_PRESET] = {3, 3, 10}, - [REGULAR_PRESET] = {9, 15, 10}, - [ENHANCED_REGULAR_PRESET] = {15, 27, 10}, - [HIGH_ACCURACY_PRESET] = {47, 83, 20}, + [LOW_POWER_PRESET] = { 3, 3, 10 }, + [REGULAR_PRESET] = { 9, 15, 10 }, + [ENHANCED_REGULAR_PRESET] = { 15, 27, 10 }, + [HIGH_ACCURACY_PRESET] = { 47, 83, 20 }, }; #define BMC150_MAGN_DEFAULT_PRESET REGULAR_PRESET @@ -242,19 +247,26 @@ static int bmc150_magn_set_power_mode(struct bmc150_magn_data *data, return regmap_update_bits(data->regmap, BMC150_MAGN_REG_OPMODE_ODR, BMC150_MAGN_MASK_OPMODE, - BMC150_MAGN_MODE_SLEEP << - BMC150_MAGN_SHIFT_OPMODE); + FIELD_PREP(BMC150_MAGN_MASK_OPMODE, + BMC150_MAGN_MODE_SLEEP)); case BMC150_MAGN_POWER_MODE_NORMAL: return regmap_update_bits(data->regmap, BMC150_MAGN_REG_OPMODE_ODR, BMC150_MAGN_MASK_OPMODE, - BMC150_MAGN_MODE_NORMAL << - BMC150_MAGN_SHIFT_OPMODE); + FIELD_PREP(BMC150_MAGN_MASK_OPMODE, + BMC150_MAGN_MODE_NORMAL)); } return -EINVAL; } +static int bmc150_magn_set_power_mode_locked(struct bmc150_magn_data *data, + enum bmc150_magn_power_modes mode) +{ + guard(mutex)(&data->mutex); + return bmc150_magn_set_power_mode(data, mode, true); +} + static int bmc150_magn_set_power_state(struct bmc150_magn_data *data, bool on) { int ret = 0; @@ -280,7 +292,7 @@ static int bmc150_magn_get_odr(struct bmc150_magn_data *data, int *val) ret = regmap_read(data->regmap, BMC150_MAGN_REG_OPMODE_ODR, ®_val); if (ret < 0) return ret; - odr_val = (reg_val & BMC150_MAGN_MASK_ODR) >> BMC150_MAGN_SHIFT_ODR; + odr_val = FIELD_GET(BMC150_MAGN_MASK_ODR, reg_val); for (i = 0; i < ARRAY_SIZE(bmc150_magn_samp_freq_table); i++) if (bmc150_magn_samp_freq_table[i].reg_val == odr_val) { @@ -293,21 +305,17 @@ static int bmc150_magn_get_odr(struct bmc150_magn_data *data, int *val) static int bmc150_magn_set_odr(struct bmc150_magn_data *data, int val) { - int ret; u8 i; for (i = 0; i < ARRAY_SIZE(bmc150_magn_samp_freq_table); i++) { - if (bmc150_magn_samp_freq_table[i].freq == val) { - ret = regmap_update_bits(data->regmap, - BMC150_MAGN_REG_OPMODE_ODR, - BMC150_MAGN_MASK_ODR, - bmc150_magn_samp_freq_table[i]. - reg_val << - BMC150_MAGN_SHIFT_ODR); - if (ret < 0) - return ret; - return 0; - } + if (bmc150_magn_samp_freq_table[i].freq != val) + continue; + + return regmap_update_bits(data->regmap, + BMC150_MAGN_REG_OPMODE_ODR, + BMC150_MAGN_MASK_ODR, + FIELD_PREP(BMC150_MAGN_MASK_ODR, + bmc150_magn_samp_freq_table[i].reg_val)); } return -EINVAL; @@ -453,33 +461,29 @@ static int bmc150_magn_read_raw(struct iio_dev *indio_dev, s32 values[AXIS_XYZ_MAX]; switch (mask) { - case IIO_CHAN_INFO_RAW: + case IIO_CHAN_INFO_RAW: { if (iio_buffer_enabled(indio_dev)) return -EBUSY; - mutex_lock(&data->mutex); + + guard(mutex)(&data->mutex); ret = bmc150_magn_set_power_state(data, true); - if (ret < 0) { - mutex_unlock(&data->mutex); + if (ret < 0) return ret; - } ret = bmc150_magn_read_xyz(data, values); if (ret < 0) { bmc150_magn_set_power_state(data, false); - mutex_unlock(&data->mutex); return ret; } *val = values[chan->scan_index]; ret = bmc150_magn_set_power_state(data, false); - if (ret < 0) { - mutex_unlock(&data->mutex); + if (ret < 0) return ret; - } - mutex_unlock(&data->mutex); return IIO_VAL_INT; + } case IIO_CHAN_INFO_SCALE: /* * The API/driver performs an off-chip temperature @@ -527,48 +531,39 @@ static int bmc150_magn_write_raw(struct iio_dev *indio_dev, int ret; switch (mask) { - case IIO_CHAN_INFO_SAMP_FREQ: + case IIO_CHAN_INFO_SAMP_FREQ: { if (val > data->max_odr) return -EINVAL; - mutex_lock(&data->mutex); - ret = bmc150_magn_set_odr(data, val); - mutex_unlock(&data->mutex); - return ret; + guard(mutex)(&data->mutex); + return bmc150_magn_set_odr(data, val); + } case IIO_CHAN_INFO_OVERSAMPLING_RATIO: switch (chan->channel2) { case IIO_MOD_X: - case IIO_MOD_Y: + case IIO_MOD_Y: { if (val < 1 || val > 511) return -EINVAL; - mutex_lock(&data->mutex); + guard(mutex)(&data->mutex); ret = bmc150_magn_set_max_odr(data, val, 0, 0); - if (ret < 0) { - mutex_unlock(&data->mutex); + if (ret < 0) return ret; - } - ret = regmap_update_bits(data->regmap, + return regmap_update_bits(data->regmap, BMC150_MAGN_REG_REP_XY, BMC150_MAGN_REG_REP_DATAMASK, - BMC150_MAGN_REPXY_TO_REGVAL - (val)); - mutex_unlock(&data->mutex); - return ret; - case IIO_MOD_Z: + BMC150_MAGN_REPXY_TO_REGVAL(val)); + } + case IIO_MOD_Z: { if (val < 1 || val > 256) return -EINVAL; - mutex_lock(&data->mutex); + guard(mutex)(&data->mutex); ret = bmc150_magn_set_max_odr(data, 0, val, 0); - if (ret < 0) { - mutex_unlock(&data->mutex); + if (ret < 0) return ret; - } - ret = regmap_update_bits(data->regmap, + return regmap_update_bits(data->regmap, BMC150_MAGN_REG_REP_Z, BMC150_MAGN_REG_REP_DATAMASK, - BMC150_MAGN_REPZ_TO_REGVAL - (val)); - mutex_unlock(&data->mutex); - return ret; + BMC150_MAGN_REPZ_TO_REGVAL(val)); + } default: return -EINVAL; } @@ -655,8 +650,9 @@ static const struct iio_info bmc150_magn_info = { }; static const unsigned long bmc150_magn_scan_masks[] = { - BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), - 0}; + BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), + 0 +}; static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p) { @@ -695,7 +691,7 @@ static int bmc150_magn_init(struct bmc150_magn_data *data) * 3ms power-on time according to datasheet, let's better * be safe than sorry and set this delay to 5ms. */ - msleep(5); + fsleep(5 * USEC_PER_MSEC); ret = bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, false); @@ -782,9 +778,8 @@ static void bmc150_magn_trig_reen(struct iio_trigger *trig) if (!data->dready_trigger_on) return; - mutex_lock(&data->mutex); + guard(mutex)(&data->mutex); ret = bmc150_magn_reset_intr(data); - mutex_unlock(&data->mutex); if (ret) dev_err(data->dev, "Failed to reset interrupt\n"); } @@ -794,32 +789,28 @@ static int bmc150_magn_data_rdy_trigger_set_state(struct iio_trigger *trig, { struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); struct bmc150_magn_data *data = iio_priv(indio_dev); - int ret = 0; + int ret; + + guard(mutex)(&data->mutex); - mutex_lock(&data->mutex); if (state == data->dready_trigger_on) - goto err_unlock; + return 0; ret = regmap_update_bits(data->regmap, BMC150_MAGN_REG_INT_DRDY, BMC150_MAGN_MASK_DRDY_EN, - state << BMC150_MAGN_SHIFT_DRDY_EN); + FIELD_PREP(BMC150_MAGN_MASK_DRDY_EN, state)); if (ret < 0) - goto err_unlock; + return ret; data->dready_trigger_on = state; if (state) { ret = bmc150_magn_reset_intr(data); if (ret < 0) - goto err_unlock; + return ret; } - mutex_unlock(&data->mutex); return 0; - -err_unlock: - mutex_unlock(&data->mutex); - return ret; } static const struct iio_trigger_ops bmc150_magn_trigger_ops = { @@ -977,9 +968,7 @@ void bmc150_magn_remove(struct device *dev) if (data->dready_trig) iio_trigger_unregister(data->dready_trig); - mutex_lock(&data->mutex); - bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, true); - mutex_unlock(&data->mutex); + bmc150_magn_set_power_mode_locked(data, BMC150_MAGN_POWER_MODE_SUSPEND); regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators); } @@ -992,10 +981,8 @@ static int bmc150_magn_runtime_suspend(struct device *dev) struct bmc150_magn_data *data = iio_priv(indio_dev); int ret; - mutex_lock(&data->mutex); - ret = bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SLEEP, - true); - mutex_unlock(&data->mutex); + ret = bmc150_magn_set_power_mode_locked(data, + BMC150_MAGN_POWER_MODE_SLEEP); if (ret < 0) { dev_err(dev, "powering off device failed\n"); return ret; @@ -1021,28 +1008,18 @@ static int bmc150_magn_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct bmc150_magn_data *data = iio_priv(indio_dev); - int ret; - mutex_lock(&data->mutex); - ret = bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SLEEP, - true); - mutex_unlock(&data->mutex); - - return ret; + return bmc150_magn_set_power_mode_locked(data, + BMC150_MAGN_POWER_MODE_SLEEP); } static int bmc150_magn_resume(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct bmc150_magn_data *data = iio_priv(indio_dev); - int ret; - mutex_lock(&data->mutex); - ret = bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_NORMAL, - true); - mutex_unlock(&data->mutex); - - return ret; + return bmc150_magn_set_power_mode_locked(data, + BMC150_MAGN_POWER_MODE_NORMAL); } #endif diff --git a/drivers/iio/magnetometer/bmc150_magn_i2c.c b/drivers/iio/magnetometer/bmc150_magn_i2c.c index b110791f688a..28f2bee217d1 100644 --- a/drivers/iio/magnetometer/bmc150_magn_i2c.c +++ b/drivers/iio/magnetometer/bmc150_magn_i2c.c @@ -8,7 +8,6 @@ * Copyright (c) 2016, Intel Corporation. */ #include <linux/device.h> -#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/regmap.h> @@ -39,9 +38,9 @@ static void bmc150_magn_i2c_remove(struct i2c_client *client) } static const struct i2c_device_id bmc150_magn_i2c_id[] = { - { "bmc150_magn" }, - { "bmc156_magn" }, - { "bmm150_magn" }, + { .name = "bmc150_magn" }, + { .name = "bmc156_magn" }, + { .name = "bmm150_magn" }, { } }; MODULE_DEVICE_TABLE(i2c, bmc150_magn_i2c_id); diff --git a/drivers/iio/magnetometer/bmc150_magn_spi.c b/drivers/iio/magnetometer/bmc150_magn_spi.c index 896b1d280731..27ab845fb257 100644 --- a/drivers/iio/magnetometer/bmc150_magn_spi.c +++ b/drivers/iio/magnetometer/bmc150_magn_spi.c @@ -8,7 +8,6 @@ * Copyright (c) 2016, Intel Corporation. */ #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/spi/spi.h> #include <linux/regmap.h> @@ -34,9 +33,9 @@ static void bmc150_magn_spi_remove(struct spi_device *spi) } static const struct spi_device_id bmc150_magn_spi_id[] = { - {"bmc150_magn", 0}, - {"bmc156_magn", 0}, - {"bmm150_magn", 0}, + { .name = "bmc150_magn" }, + { .name = "bmc156_magn" }, + { .name = "bmm150_magn" }, { } }; MODULE_DEVICE_TABLE(spi, bmc150_magn_spi_id); diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index c673f9323e47..ad18f233ee16 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -3,10 +3,10 @@ * HID Sensors Driver * Copyright (c) 2012, Intel Corporation. */ +#include <linux/bitops.h> #include <linux/device.h> #include <linux/platform_device.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/hid-sensor-hub.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> @@ -132,22 +132,10 @@ static const struct iio_chan_spec magn_3d_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(7) }; -/* Adjust channel real bits based on report descriptor */ -static void magn_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels, - int channel, int size) -{ - channels[channel].scan_type.sign = 's'; - /* Real storage bits will change based on the report desc. */ - channels[channel].scan_type.realbits = size * 8; - /* Maximum size of a sample to capture is u32 */ - channels[channel].scan_type.storagebits = sizeof(u32) * 8; -} - /* Channel read_raw handler */ static int magn_3d_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, - long mask) + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { struct magn_3d_state *magn_state = iio_priv(indio_dev); int report_id = -1; @@ -177,8 +165,7 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev, false); return -EINVAL; } - hid_sensor_power_state(&magn_state->magn_flux_attributes, - false); + hid_sensor_power_state(&magn_state->magn_flux_attributes, false); ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SCALE: @@ -239,10 +226,8 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev, /* Channel write_raw handler */ static int magn_3d_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct magn_3d_state *magn_state = iio_priv(indio_dev); int ret = 0; @@ -280,8 +265,7 @@ static const struct iio_info magn_3d_info = { /* Callback handler to send event after all samples are received and captured */ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - void *priv) + u32 usage_id, void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct magn_3d_state *magn_state = iio_priv(indio_dev); @@ -302,9 +286,9 @@ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - size_t raw_len, char *raw_data, - void *priv) + u32 usage_id, + size_t raw_len, char *raw_data, + void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct magn_3d_state *magn_state = iio_priv(indio_dev); @@ -337,7 +321,7 @@ static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev, iio_val = magn_state->magn_val_addr[offset]; - if (iio_val != NULL) + if (iio_val) *iio_val = *((u32 *)raw_data); else ret = -EINVAL; @@ -350,7 +334,7 @@ static int magn_3d_parse_report(struct platform_device *pdev, struct hid_sensor_hub_device *hsdev, struct iio_chan_spec **channels, int *chan_count, - unsigned usage_id, + u32 usage_id, struct magn_3d_state *st) { int i; @@ -378,18 +362,17 @@ static int magn_3d_parse_report(struct platform_device *pdev, return -EINVAL; } - dev_dbg(&pdev->dev, "magn_3d Found %d usage attributes\n", - attr_count); + dev_dbg(&pdev->dev, "magn_3d Found %d usage attributes\n", attr_count); dev_dbg(&pdev->dev, "magn_3d X: %x:%x Y: %x:%x Z: %x:%x\n", - st->magn[0].index, - st->magn[0].report_id, - st->magn[1].index, st->magn[1].report_id, - st->magn[2].index, st->magn[2].report_id); + st->magn[0].index, + st->magn[0].report_id, + st->magn[1].index, st->magn[1].report_id, + st->magn[2].index, st->magn[2].report_id); /* Setup IIO channel array */ _channels = devm_kcalloc(&pdev->dev, attr_count, - sizeof(struct iio_chan_spec), - GFP_KERNEL); + sizeof(struct iio_chan_spec), + GFP_KERNEL); if (!_channels) { dev_err(&pdev->dev, "failed to allocate space for iio channels\n"); @@ -418,9 +401,11 @@ static int magn_3d_parse_report(struct platform_device *pdev, if (i != CHANNEL_SCAN_INDEX_TIMESTAMP) { /* Set magn_val_addr to iio value address */ st->magn_val_addr[i] = &st->iio_vals[*chan_count]; - magn_3d_adjust_channel_bit_mask(_channels, - *chan_count, - st->magn[i].size); + _channels[*chan_count].scan_type = (struct iio_scan_type) { + .format = 's', + .realbits = BYTES_TO_BITS(st->magn[i].size), + .storagebits = BITS_PER_TYPE(u32), + }; } (*chan_count)++; } @@ -434,8 +419,7 @@ static int magn_3d_parse_report(struct platform_device *pdev, *channels = _channels; - dev_dbg(&pdev->dev, "magn_3d Setup %d IIO channels\n", - *chan_count); + dev_dbg(&pdev->dev, "magn_3d Setup %d IIO channels\n", *chan_count); st->magn_flux_attr.scale_precision = hid_sensor_format_scale( HID_USAGE_SENSOR_COMPASS_3D, @@ -476,7 +460,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev) indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct magn_3d_state)); - if (indio_dev == NULL) + if (!indio_dev) return -ENOMEM; platform_set_drvdata(pdev, indio_dev); @@ -499,8 +483,8 @@ static int hid_magn_3d_probe(struct platform_device *pdev) magn_state->rot_attributes.sensitivity.index = -1; ret = magn_3d_parse_report(pdev, hsdev, - &channels, &chan_count, - HID_USAGE_SENSOR_COMPASS_3D, magn_state); + &channels, &chan_count, + HID_USAGE_SENSOR_COMPASS_3D, magn_state); if (ret) { dev_err(&pdev->dev, "failed to parse report\n"); return ret; @@ -515,32 +499,32 @@ static int hid_magn_3d_probe(struct platform_device *pdev) atomic_set(&magn_state->magn_flux_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, - &magn_state->magn_flux_attributes); + &magn_state->magn_flux_attributes); if (ret < 0) { dev_err(&pdev->dev, "trigger setup failed\n"); return ret; } - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(&pdev->dev, "device register failed\n"); - goto error_remove_trigger; - } - magn_state->callbacks.send_event = magn_3d_proc_event; magn_state->callbacks.capture_sample = magn_3d_capture_sample; magn_state->callbacks.pdev = pdev; ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D, - &magn_state->callbacks); + &magn_state->callbacks); if (ret < 0) { dev_err(&pdev->dev, "callback reg failed\n"); - goto error_iio_unreg; + goto error_remove_trigger; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "device register failed\n"); + goto error_remove_callback; } return ret; -error_iio_unreg: - iio_device_unregister(indio_dev); +error_remove_callback: + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D); error_remove_trigger: hid_sensor_remove_trigger(indio_dev, &magn_state->magn_flux_attributes); return ret; @@ -553,8 +537,8 @@ static void hid_magn_3d_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct magn_3d_state *magn_state = iio_priv(indio_dev); - sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D); iio_device_unregister(indio_dev); + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D); hid_sensor_remove_trigger(indio_dev, &magn_state->magn_flux_attributes); } diff --git a/drivers/iio/magnetometer/hmc5843_i2c.c b/drivers/iio/magnetometer/hmc5843_i2c.c index b41709959e2b..4c454b0057b1 100644 --- a/drivers/iio/magnetometer/hmc5843_i2c.c +++ b/drivers/iio/magnetometer/hmc5843_i2c.c @@ -71,10 +71,10 @@ static void hmc5843_i2c_remove(struct i2c_client *client) } static const struct i2c_device_id hmc5843_id[] = { - { "hmc5843", HMC5843_ID }, - { "hmc5883", HMC5883_ID }, - { "hmc5883l", HMC5883L_ID }, - { "hmc5983", HMC5983_ID }, + { .name = "hmc5843", .driver_data = HMC5843_ID }, + { .name = "hmc5883", .driver_data = HMC5883_ID }, + { .name = "hmc5883l", .driver_data = HMC5883L_ID }, + { .name = "hmc5983", .driver_data = HMC5983_ID }, { } }; MODULE_DEVICE_TABLE(i2c, hmc5843_id); diff --git a/drivers/iio/magnetometer/hmc5843_spi.c b/drivers/iio/magnetometer/hmc5843_spi.c index 6a55c1559b0d..29dee5dce2ae 100644 --- a/drivers/iio/magnetometer/hmc5843_spi.c +++ b/drivers/iio/magnetometer/hmc5843_spi.c @@ -56,7 +56,6 @@ static int hmc5843_spi_probe(struct spi_device *spi) { int ret; struct regmap *regmap; - const struct spi_device_id *id = spi_get_device_id(spi); spi->mode = SPI_MODE_3; spi->max_speed_hz = 8000000; @@ -69,8 +68,7 @@ static int hmc5843_spi_probe(struct spi_device *spi) return PTR_ERR(regmap); return hmc5843_common_probe(&spi->dev, - regmap, - id->driver_data, id->name); + regmap, HMC5983_ID, "hmc5983"); } static void hmc5843_spi_remove(struct spi_device *spi) @@ -79,7 +77,7 @@ static void hmc5843_spi_remove(struct spi_device *spi) } static const struct spi_device_id hmc5843_id[] = { - { "hmc5983", HMC5983_ID }, + { .name = "hmc5983" }, { } }; MODULE_DEVICE_TABLE(spi, hmc5843_id); diff --git a/drivers/iio/magnetometer/mag3110.c b/drivers/iio/magnetometer/mag3110.c index ff09250a06e7..479a12ece8f6 100644 --- a/drivers/iio/magnetometer/mag3110.c +++ b/drivers/iio/magnetometer/mag3110.c @@ -619,7 +619,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mag3110_pm_ops, mag3110_suspend, mag3110_resume); static const struct i2c_device_id mag3110_id[] = { - { "mag3110" }, + { .name = "mag3110" }, { } }; MODULE_DEVICE_TABLE(i2c, mag3110_id); diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c index f3d48d03f7c3..6f40cba4b1ba 100644 --- a/drivers/iio/magnetometer/mmc35240.c +++ b/drivers/iio/magnetometer/mmc35240.c @@ -10,7 +10,6 @@ */ #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/init.h> #include <linux/i2c.h> #include <linux/delay.h> @@ -560,7 +559,7 @@ static const struct acpi_device_id mmc35240_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, mmc35240_acpi_match); static const struct i2c_device_id mmc35240_id[] = { - { "mmc35240" }, + { .name = "mmc35240" }, { } }; MODULE_DEVICE_TABLE(i2c, mmc35240_id); diff --git a/drivers/iio/magnetometer/mmc5633.c b/drivers/iio/magnetometer/mmc5633.c index 9d8e27486963..f4dae7ba1335 100644 --- a/drivers/iio/magnetometer/mmc5633.c +++ b/drivers/iio/magnetometer/mmc5633.c @@ -24,7 +24,6 @@ #include <linux/init.h> #include <linux/iopoll.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/pm.h> #include <linux/regmap.h> @@ -532,8 +531,8 @@ static const struct of_device_id mmc5633_of_match[] = { MODULE_DEVICE_TABLE(of, mmc5633_of_match); static const struct i2c_device_id mmc5633_i2c_id[] = { - { "mmc5603" }, - { "mmc5633" }, + { .name = "mmc5603" }, + { .name = "mmc5633" }, { } }; MODULE_DEVICE_TABLE(i2c, mmc5633_i2c_id); diff --git a/drivers/iio/magnetometer/mmc5983.c b/drivers/iio/magnetometer/mmc5983.c new file mode 100644 index 000000000000..d10a6288e147 --- /dev/null +++ b/drivers/iio/magnetometer/mmc5983.c @@ -0,0 +1,347 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * MMC5983 - MEMSIC 3-axis Magnetic Sensor + * + * Copyright (c) 2026, Vlad Kulikov <vlad.kulikov.c@gmail.com> + * + * IIO driver for MMC5983 + */ + +#include <linux/array_size.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/regmap.h> +#include <linux/time.h> +#include <linux/types.h> + +#define MMC5983_REG_XOUT0 0x00 +#define MMC5983_REG_XOUT1 0x01 +#define MMC5983_REG_YOUT0 0x02 +#define MMC5983_REG_YOUT1 0x03 +#define MMC5983_REG_ZOUT0 0x04 +#define MMC5983_REG_ZOUT1 0x05 +#define MMC5983_REG_XYZOUT2 0x06 + +#define MMC5983_REG_STATUS 0x08 + +#define MMC5983_REG_CTRL0 0x09 +#define MMC5983_REG_CTRL1 0x0A +#define MMC5983_REG_CTRL2 0x0B +#define MMC5983_REG_CTRL3 0x0C + +#define MMC5983_REG_ID 0x2F + +#define MMC5983_PRODUCT_ID 0x30 + +#define MMC5983_STATUS_MEAS_M_DONE_BIT BIT(0) +#define MMC5983_STATUS_OTP_RD_DONE_BIT BIT(4) + +#define MMC5983_CTRL0_TM_M_BIT BIT(0) +#define MMC5983_CTRL0_SET_BIT BIT(3) +#define MMC5983_CTRL0_RESET_BIT BIT(4) +#define MMC5983_CTRL0_OTP_RD_BIT BIT(6) + +#define MMC5983_CTRL1_SW_RST_BIT BIT(7) + +enum mmc5983_axis { + MMC5983_AXIS_X, + MMC5983_AXIS_Y, + MMC5983_AXIS_Z, +}; + +struct mmc5983_data { + struct regmap *regmap; + /* Protects chip access during SET/RESET measurement sequence */ + struct mutex mutex; +}; + +#define MMC5983_CHANNEL(_axis) { \ + .type = IIO_MAGN, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .address = MMC5983_AXIS_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +} + +static const struct iio_chan_spec mmc5983_channels[] = { + MMC5983_CHANNEL(X), + MMC5983_CHANNEL(Y), + MMC5983_CHANNEL(Z), +}; + +static int mmc5983_pulse_coil(struct mmc5983_data *data, unsigned int coil_bit) +{ + int ret; + + ret = regmap_write(data->regmap, MMC5983_REG_CTRL0, coil_bit); + if (ret) + return ret; + + /* + * Datasheet page 15: SET/RESET coil pulse is 500 ns. + * Vendor sample code waits 500 us before the next operation. + */ + fsleep(500); + + return 0; +} + +static int mmc5983_take_measurement(struct mmc5983_data *data, int m[3]) +{ + unsigned int status; + u8 buf[7]; + int ret; + + ret = regmap_write(data->regmap, MMC5983_REG_CTRL0, + MMC5983_CTRL0_TM_M_BIT); + if (ret) + return ret; + + /* + * Datasheet page 15: measurement time is 8 ms at BW=00 (default, + * slowest setting). Use a 50 ms timeout for margin. + */ + ret = regmap_read_poll_timeout(data->regmap, MMC5983_REG_STATUS, + status, + status & MMC5983_STATUS_MEAS_M_DONE_BIT, + 10 * USEC_PER_MSEC, + 50 * USEC_PER_MSEC); + if (ret) + return ret; + + ret = regmap_bulk_read(data->regmap, MMC5983_REG_XOUT0, buf, + sizeof(buf)); + if (ret) + return ret; + + m[0] = (buf[0] << 10) | (buf[1] << 2) | ((buf[6] >> 6) & 0x3); + m[1] = (buf[2] << 10) | (buf[3] << 2) | ((buf[6] >> 4) & 0x3); + m[2] = (buf[4] << 10) | (buf[5] << 2) | ((buf[6] >> 2) & 0x3); + + return 0; +} + +static int mmc5983_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int *val, + int *val2, long mask) +{ + struct mmc5983_data *data = iio_priv(indio_dev); + int m1[3], m2[3]; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: { + guard(mutex)(&data->mutex); + + /* SET: magnetize sensor elements in forward direction */ + ret = mmc5983_pulse_coil(data, MMC5983_CTRL0_SET_BIT); + if (ret) + return ret; + + ret = mmc5983_take_measurement(data, m1); + if (ret) + return ret; + + /* RESET: magnetize sensor elements in reverse direction */ + ret = mmc5983_pulse_coil(data, MMC5983_CTRL0_RESET_BIT); + if (ret) + return ret; + + ret = mmc5983_take_measurement(data, m2); + if (ret) + return ret; + + *val = (m1[chan->address] - m2[chan->address]) / 2; + return IIO_VAL_INT; + } + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = 61035; + return IIO_VAL_INT_PLUS_NANO; + default: + return -EINVAL; + } +} + +static const struct iio_info mmc5983_info = { + .read_raw = mmc5983_read_raw, +}; + +static bool mmc5983_is_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MMC5983_REG_CTRL0: + case MMC5983_REG_CTRL1: + case MMC5983_REG_CTRL2: + case MMC5983_REG_CTRL3: + return true; + default: + return false; + } +} + +static bool mmc5983_is_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MMC5983_REG_XOUT0: + case MMC5983_REG_XOUT1: + case MMC5983_REG_YOUT0: + case MMC5983_REG_YOUT1: + case MMC5983_REG_ZOUT0: + case MMC5983_REG_ZOUT1: + case MMC5983_REG_XYZOUT2: + case MMC5983_REG_STATUS: + case MMC5983_REG_CTRL0: + case MMC5983_REG_CTRL1: + case MMC5983_REG_CTRL2: + case MMC5983_REG_CTRL3: + case MMC5983_REG_ID: + return true; + default: + return false; + } +} + +static bool mmc5983_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MMC5983_REG_XOUT0: + case MMC5983_REG_XOUT1: + case MMC5983_REG_YOUT0: + case MMC5983_REG_YOUT1: + case MMC5983_REG_ZOUT0: + case MMC5983_REG_ZOUT1: + case MMC5983_REG_XYZOUT2: + case MMC5983_REG_STATUS: + case MMC5983_REG_CTRL0: + case MMC5983_REG_CTRL1: + return true; + default: + return false; + } +} + +static const struct regmap_config mmc5983_regmap_config = { + .name = "mmc5983_regmap", + .reg_bits = 8, + .val_bits = 8, + .max_register = MMC5983_REG_ID, + .writeable_reg = mmc5983_is_writeable_reg, + .readable_reg = mmc5983_is_readable_reg, + .volatile_reg = mmc5983_is_volatile_reg, +}; + +static int mmc5983_init(struct mmc5983_data *data) +{ + struct regmap *regmap = data->regmap; + struct device *dev = regmap_get_device(regmap); + unsigned int reg_id, status; + int ret; + + ret = regmap_read(regmap, MMC5983_REG_ID, ®_id); + if (ret) + return dev_err_probe(dev, ret, "Error reading product id\n"); + + if (reg_id != MMC5983_PRODUCT_ID) + dev_info(dev, "unexpected product id 0x%02x\n", reg_id); + + ret = regmap_write(regmap, MMC5983_REG_CTRL1, MMC5983_CTRL1_SW_RST_BIT); + if (ret) + return ret; + + /* Datasheet page 15: power-on time after SW_RST is 10 ms */ + fsleep(10 * USEC_PER_MSEC); + + ret = regmap_write(regmap, MMC5983_REG_CTRL0, MMC5983_CTRL0_OTP_RD_BIT); + if (ret) + return ret; + + /* + * Datasheet page 15: OTP read completes and self-clears. No separate + * OTP refresh timeout is specified, so use the 10 ms power-on time as + * a conservative upper bound. + */ + ret = regmap_read_poll_timeout(regmap, MMC5983_REG_STATUS, status, + status & MMC5983_STATUS_OTP_RD_DONE_BIT, + USEC_PER_MSEC, + 10 * USEC_PER_MSEC); + if (ret) + return ret; + + /* SET: magnetize sensor elements in forward direction */ + ret = mmc5983_pulse_coil(data, MMC5983_CTRL0_SET_BIT); + if (ret) + return ret; + + /* RESET: magnetize sensor elements in reverse direction */ + return mmc5983_pulse_coil(data, MMC5983_CTRL0_RESET_BIT); +} + +static int mmc5983_probe(struct i2c_client *i2c) +{ + struct device *dev = &i2c->dev; + struct mmc5983_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + + ret = devm_mutex_init(dev, &data->mutex); + if (ret) + return ret; + + data->regmap = devm_regmap_init_i2c(i2c, &mmc5983_regmap_config); + if (IS_ERR(data->regmap)) + return dev_err_probe(dev, PTR_ERR(data->regmap), + "failed to allocate register map\n"); + + indio_dev->info = &mmc5983_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->name = "mmc5983"; + indio_dev->channels = mmc5983_channels; + indio_dev->num_channels = ARRAY_SIZE(mmc5983_channels); + + ret = mmc5983_init(data); + if (ret) + return dev_err_probe(dev, ret, "mmc5983 chip init failed\n"); + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id mmc5983_of_match[] = { + { .compatible = "memsic,mmc5983" }, + { } +}; +MODULE_DEVICE_TABLE(of, mmc5983_of_match); + +static const struct i2c_device_id mmc5983_id[] = { + { .name = "mmc5983" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mmc5983_id); + +static struct i2c_driver mmc5983_driver = { + .driver = { + .name = "mmc5983", + .of_match_table = mmc5983_of_match, + }, + .probe = mmc5983_probe, + .id_table = mmc5983_id, +}; +module_i2c_driver(mmc5983_driver); + +MODULE_AUTHOR("Vladislav Kulikov <vlad.kulikov.c@gmail.com>"); +MODULE_DESCRIPTION("MEMSIC MMC5983 magnetic sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/magnetometer/qmc5883l.c b/drivers/iio/magnetometer/qmc5883l.c new file mode 100644 index 000000000000..c3469715dc63 --- /dev/null +++ b/drivers/iio/magnetometer/qmc5883l.c @@ -0,0 +1,516 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * Support for QST QMC5883L 3-Axis Magnetic Sensor on I2C bus. + * + * Copyright (C) 2026 Siratul Islam <siratul.islam@linux.dev> + * + * Datasheet available at + * <https://www.qstcorp.com/upload/pdf/202512/13-52-04%20QMC5883L%20Datasheet%20Rev.%20B.pdf> + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/time.h> +#include <linux/types.h> + +#include <asm/byteorder.h> + +#include <linux/iio/iio.h> + +#define QMC5883L_REG_X_LSB 0x00 +#define QMC5883L_REG_STATUS1 0x06 +#define QMC5883L_REG_CTRL1 0x09 +#define QMC5883L_REG_CTRL2 0x0A +#define QMC5883L_REG_SET_RESET 0x0B +#define QMC5883L_REG_ID 0x0D + +#define QMC5883L_CHIP_ID 0xFF + +#define QMC5883L_MODE_MASK GENMASK(1, 0) +#define QMC5883L_ODR_MASK GENMASK(3, 2) +#define QMC5883L_RNG_MASK GENMASK(5, 4) +#define QMC5883L_OSR_MASK GENMASK(7, 6) + +#define QMC5883L_MODE_STANDBY 0x00 +#define QMC5883L_MODE_CONT 0x01 + +#define QMC5883L_ODR_10HZ 0x00 +#define QMC5883L_ODR_50HZ 0x01 +#define QMC5883L_ODR_100HZ 0x02 +#define QMC5883L_ODR_200HZ 0x03 + +#define QMC5883L_RNG_2G 0x00 +#define QMC5883L_RNG_8G 0x01 + +#define QMC5883L_OSR_512 0x00 +#define QMC5883L_OSR_256 0x01 +#define QMC5883L_OSR_128 0x02 +#define QMC5883L_OSR_64 0x03 + +#define QMC5883L_STATUS_DRDY BIT(0) +#define QMC5883L_STATUS_OVL BIT(1) + +#define QMC5883L_SET_RESET_VAL BIT(0) +#define QMC5883L_INT_DISABLE BIT(0) +#define QMC5883L_SOFT_RESET BIT(7) + +#define QMC5883L_PORT_US 350 + +struct qmc5883l_data { + struct regmap *regmap; + /* + * Protect data->range/odr/osr. + * Protect poll and read during measurement. + */ + struct mutex mutex; + u8 range; + u8 odr; + u8 osr; +}; + +enum qmc5883l_chan { + QMC5883L_AXIS_X, + QMC5883L_AXIS_Y, + QMC5883L_AXIS_Z, +}; + +static const int qmc5883l_odr_avail[] = { 10, 50, 100, 200 }; + +static const int qmc5883l_osr_avail[] = { 512, 256, 128, 64 }; + +static const int qmc5883l_scales[][2] = { + [QMC5883L_RNG_2G] = { 0, 83333 }, + [QMC5883L_RNG_8G] = { 0, 333333 }, +}; + +static int qmc5883l_take_measurement(struct iio_dev *indio_dev, int index, + int *val) +{ + struct qmc5883l_data *data = iio_priv(indio_dev); + struct regmap *map = data->regmap; + unsigned int status; + __le16 buf[3]; + int ret; + + guard(mutex) (&data->mutex); + + /* 50ms headroom over the slowest ODR (10Hz) */ + ret = regmap_read_poll_timeout(map, QMC5883L_REG_STATUS1, + status, (status & QMC5883L_STATUS_DRDY), + 2 * USEC_PER_MSEC, 150 * USEC_PER_MSEC); + if (ret) + return ret; + + ret = regmap_bulk_read(map, QMC5883L_REG_X_LSB, buf, sizeof(buf)); + if (ret) + return ret; + + if (status & QMC5883L_STATUS_OVL) + return -ERANGE; + + *val = (s16)le16_to_cpu(buf[index]); + + return 0; +} + +static int qmc5883l_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct qmc5883l_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = qmc5883l_take_measurement(indio_dev, chan->address, val); + if (ret) + return ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: { + guard(mutex)(&data->mutex); + + *val = qmc5883l_scales[data->range][0]; + *val2 = qmc5883l_scales[data->range][1]; + + return IIO_VAL_INT_PLUS_NANO; + } + case IIO_CHAN_INFO_SAMP_FREQ: { + guard(mutex)(&data->mutex); + + switch (data->odr) { + case QMC5883L_ODR_200HZ: + *val = 200; + break; + case QMC5883L_ODR_100HZ: + *val = 100; + break; + case QMC5883L_ODR_50HZ: + *val = 50; + break; + case QMC5883L_ODR_10HZ: + *val = 10; + break; + default: + return -EINVAL; + } + + return IIO_VAL_INT; + } + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { + guard(mutex)(&data->mutex); + + switch (data->osr) { + case QMC5883L_OSR_64: + *val = 64; + break; + case QMC5883L_OSR_128: + *val = 128; + break; + case QMC5883L_OSR_256: + *val = 256; + break; + case QMC5883L_OSR_512: + *val = 512; + break; + default: + return -EINVAL; + } + + return IIO_VAL_INT; + } + default: + return -EINVAL; + } +} + +static int qmc5883l_write_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int val, int val2, long mask) +{ + struct qmc5883l_data *data = iio_priv(indio_dev); + u8 rng, osr, odr; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: { + if (val != 0) + return -EINVAL; + + if (val2 == qmc5883l_scales[QMC5883L_RNG_2G][1]) + rng = QMC5883L_RNG_2G; + else if (val2 == qmc5883l_scales[QMC5883L_RNG_8G][1]) + rng = QMC5883L_RNG_8G; + else + return -EINVAL; + + guard(mutex)(&data->mutex); + + ret = regmap_update_bits(data->regmap, QMC5883L_REG_CTRL1, + QMC5883L_RNG_MASK, + FIELD_PREP(QMC5883L_RNG_MASK, rng)); + if (ret) + return ret; + + data->range = rng; + + return 0; + } + case IIO_CHAN_INFO_SAMP_FREQ: { + switch (val) { + case 200: + odr = QMC5883L_ODR_200HZ; + break; + case 100: + odr = QMC5883L_ODR_100HZ; + break; + case 50: + odr = QMC5883L_ODR_50HZ; + break; + case 10: + odr = QMC5883L_ODR_10HZ; + break; + default: + return -EINVAL; + } + + guard(mutex)(&data->mutex); + + ret = regmap_update_bits(data->regmap, QMC5883L_REG_CTRL1, + QMC5883L_ODR_MASK, + FIELD_PREP(QMC5883L_ODR_MASK, odr)); + if (ret) + return ret; + + data->odr = odr; + + return 0; + } + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { + switch (val) { + case 64: + osr = QMC5883L_OSR_64; + break; + case 128: + osr = QMC5883L_OSR_128; + break; + case 256: + osr = QMC5883L_OSR_256; + break; + case 512: + osr = QMC5883L_OSR_512; + break; + default: + return -EINVAL; + } + + guard(mutex)(&data->mutex); + + ret = regmap_update_bits(data->regmap, QMC5883L_REG_CTRL1, + QMC5883L_OSR_MASK, + FIELD_PREP(QMC5883L_OSR_MASK, osr)); + if (ret) + return ret; + + data->osr = osr; + + return 0; + } + default: + return -EINVAL; + } +} + +static int qmc5883l_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_SAMP_FREQ: + *vals = qmc5883l_odr_avail; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(qmc5883l_odr_avail); + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *vals = qmc5883l_osr_avail; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(qmc5883l_osr_avail); + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SCALE: + *vals = (const int *)qmc5883l_scales; + *type = IIO_VAL_INT_PLUS_NANO; + *length = ARRAY_SIZE(qmc5883l_scales) * 2; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int qmc5883l_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; + default: + return IIO_VAL_INT; + } +} + +static const struct iio_info qmc5883l_info = { + .read_raw = qmc5883l_read_raw, + .write_raw = qmc5883l_write_raw, + .read_avail = qmc5883l_read_avail, + .write_raw_get_fmt = qmc5883l_write_raw_get_fmt, +}; + +static int qmc5883l_init(struct qmc5883l_data *data) +{ + struct regmap *map = data->regmap; + unsigned int reg; + int ret; + + ret = regmap_read(map, QMC5883L_REG_ID, ®); + if (ret) + return ret; + + /* Not failing because rev 1.0 had this register reserved */ + if (reg != QMC5883L_CHIP_ID) + dev_warn(regmap_get_device(map), + "Unknown chip id: 0x%02x, continuing\n", reg); + + ret = regmap_write(map, QMC5883L_REG_CTRL2, QMC5883L_SOFT_RESET); + if (ret) + return ret; + + /* Use POR completion time as a conservative bound */ + fsleep(QMC5883L_PORT_US); + + /* DRDY pin not used in this version of the driver */ + ret = regmap_write(map, QMC5883L_REG_CTRL2, QMC5883L_INT_DISABLE); + if (ret) + return ret; + + ret = regmap_write(map, QMC5883L_REG_SET_RESET, QMC5883L_SET_RESET_VAL); + if (ret) + return ret; + + data->odr = QMC5883L_ODR_50HZ; + data->range = QMC5883L_RNG_2G; + data->osr = QMC5883L_OSR_64; + + return regmap_write(map, QMC5883L_REG_CTRL1, + FIELD_PREP(QMC5883L_MODE_MASK, QMC5883L_MODE_CONT) | + FIELD_PREP(QMC5883L_ODR_MASK, data->odr) | + FIELD_PREP(QMC5883L_RNG_MASK, data->range) | + FIELD_PREP(QMC5883L_OSR_MASK, data->osr)); +} + +static void qmc5883l_power_down_action(void *priv) +{ + struct qmc5883l_data *data = priv; + + regmap_update_bits(data->regmap, QMC5883L_REG_CTRL1, + QMC5883L_MODE_MASK, + FIELD_PREP(QMC5883L_MODE_MASK, QMC5883L_MODE_STANDBY)); +} + +static bool qmc5883l_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg <= QMC5883L_REG_STATUS1; +} + +static bool qmc5883l_writable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case QMC5883L_REG_CTRL1: + case QMC5883L_REG_CTRL2: + case QMC5883L_REG_SET_RESET: + return true; + default: + return false; + } +} + +static const struct regmap_config qmc5883l_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = QMC5883L_REG_ID, + .cache_type = REGCACHE_MAPLE, + .volatile_reg = qmc5883l_volatile_reg, + .writeable_reg = qmc5883l_writable_reg, +}; + +#define QMC5883L_CHANNEL(_axis) \ + { \ + .type = IIO_MAGN, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .address = QMC5883L_AXIS_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + } + +static const struct iio_chan_spec qmc5883l_channels[] = { + QMC5883L_CHANNEL(X), + QMC5883L_CHANNEL(Y), + QMC5883L_CHANNEL(Z), +}; + +static int qmc5883l_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct qmc5883l_data *data; + struct iio_dev *indio_dev; + struct regmap *map; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + map = devm_regmap_init_i2c(client, &qmc5883l_regmap_config); + if (IS_ERR(map)) + return dev_err_probe(dev, PTR_ERR(map), + "regmap initialization failed\n"); + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, + "Failed to enable VDD regulator\n"); + + ret = devm_regulator_get_enable(dev, "vddio"); + if (ret) + return dev_err_probe(dev, ret, + "Failed to enable VDDIO regulator\n"); + + /* POR completion time max per datasheet Table 7 */ + fsleep(QMC5883L_PORT_US); + + data = iio_priv(indio_dev); + data->regmap = map; + + ret = devm_mutex_init(dev, &data->mutex); + if (ret) + return ret; + + indio_dev->name = "qmc5883l"; + indio_dev->info = &qmc5883l_info; + indio_dev->channels = qmc5883l_channels; + indio_dev->num_channels = ARRAY_SIZE(qmc5883l_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = qmc5883l_init(data); + if (ret) + return dev_err_probe(dev, ret, "qmc5883l init failed\n"); + + ret = devm_add_action_or_reset(dev, qmc5883l_power_down_action, data); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id qmc5883l_match[] = { + { .compatible = "qstcorp,qmc5883l" }, + { } +}; +MODULE_DEVICE_TABLE(of, qmc5883l_match); + +static const struct i2c_device_id qmc5883l_id[] = { + { .name = "qmc5883l" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, qmc5883l_id); + +static struct i2c_driver qmc5883l_driver = { + .driver = { + .name = "qmc5883l", + .of_match_table = qmc5883l_match, + }, + .id_table = qmc5883l_id, + .probe = qmc5883l_probe, +}; +module_i2c_driver(qmc5883l_driver); + +MODULE_DESCRIPTION("QST QMC5883L 3-Axis Magnetic Sensor driver"); +MODULE_AUTHOR("Siratul Islam <siratul.islam@linux.dev>"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/iio/magnetometer/qmc6308.c b/drivers/iio/magnetometer/qmc6308.c new file mode 100644 index 000000000000..72348cd9ef01 --- /dev/null +++ b/drivers/iio/magnetometer/qmc6308.c @@ -0,0 +1,601 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Support for QST QMC6308 3-Axis Magnetic Sensor on I2C bus. + * + * Copyright (C) 2026 Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net> + * + * Datasheet available at + * <https://qstcorp.com/upload/pdf/202202/13-52-15%20QMC6308%20Datasheet%20Rev.%20F(1).pdf> + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/time.h> +#include <linux/types.h> + +#include <asm/byteorder.h> + +#include <linux/iio/iio.h> + +#define QMC6308_REG_ID 0x00 +#define QMC6308_REG_X_LSB 0x01 +#define QMC6308_REG_STATUS 0x09 +#define QMC6308_REG_CTRL1 0x0A +#define QMC6308_REG_CTRL2 0x0B +#define QMC6308_REG_CTRL3 0x0D +#define QMC6308_REG_CTRL4 0x29 + +#define QMC6308_CHIP_ID 0x80 + +/* Control register 1 */ +#define QMC6308_MODE_MASK GENMASK(1, 0) +#define QMC6308_ODR_MASK GENMASK(3, 2) +#define QMC6308_OSR1_MASK GENMASK(5, 4) +#define QMC6308_OSR2_MASK GENMASK(7, 6) + +#define QMC6308_MODE_SUSPEND 0x00 +#define QMC6308_MODE_NORMAL 0x01 + +#define QMC6308_ODR_10HZ 0x00 +#define QMC6308_ODR_50HZ 0x01 +#define QMC6308_ODR_100HZ 0x02 +#define QMC6308_ODR_200HZ 0x03 + +#define QMC6308_OSR1_8 0x00 +#define QMC6308_OSR1_4 0x01 +#define QMC6308_OSR1_2 0x02 +#define QMC6308_OSR1_1 0x03 + +/* Control register 2 */ +#define QMC6308_SET_RESET_MASK GENMASK(1, 0) +#define QMC6308_RNG_MASK GENMASK(3, 2) +#define QMC6308_SELF_TEST BIT(6) +#define QMC6308_SOFT_RST BIT(7) + +#define QMC6308_SET_RESET_ON 0x00 + +#define QMC6308_RNG_30G 0x00 +#define QMC6308_RNG_12G 0x01 +#define QMC6308_RNG_8G 0x02 +#define QMC6308_RNG_2G 0x03 + +/* Status register */ +#define QMC6308_STATUS_DRDY BIT(0) +#define QMC6308_STATUS_OVFL BIT(1) + +/* Power-on completion time (datasheet Table 7) */ +#define QMC6308_POR_US 250 + +#define QMC6308_AUTOSUSPEND_DELAY_MS 500 + +struct qmc6308_data { + struct regmap *regmap; + /* Protect data->range/odr/osr and serialize measurements */ + struct mutex mutex; + struct iio_mount_matrix orientation; + u8 range; + u8 odr; + u8 osr; +}; + +enum qmc6308_axis { + QMC6308_AXIS_X, + QMC6308_AXIS_Y, + QMC6308_AXIS_Z, +}; + +static const int qmc6308_odr_avail[] = { + [QMC6308_ODR_10HZ] = 10, + [QMC6308_ODR_50HZ] = 50, + [QMC6308_ODR_100HZ] = 100, + [QMC6308_ODR_200HZ] = 200, +}; + +static const int qmc6308_osr1_avail[] = { + [QMC6308_OSR1_8] = 8, + [QMC6308_OSR1_4] = 4, + [QMC6308_OSR1_2] = 2, + [QMC6308_OSR1_1] = 1, +}; + +/* + * Sensitivity is 1000/2500/3750/15000 LSB/Gauss for the + * +-30/12/8/2 Gauss ranges respectively. + */ +static const int qmc6308_scales[][2] = { + [QMC6308_RNG_30G] = { 0, 1000000 }, + [QMC6308_RNG_12G] = { 0, 400000 }, + [QMC6308_RNG_8G] = { 0, 266667 }, + [QMC6308_RNG_2G] = { 0, 66667 }, +}; + +static int qmc6308_set_mode(struct qmc6308_data *data, unsigned int mode) +{ + return regmap_update_bits(data->regmap, QMC6308_REG_CTRL1, + QMC6308_MODE_MASK, + FIELD_PREP(QMC6308_MODE_MASK, mode)); +} + +static int qmc6308_take_measurement(struct iio_dev *indio_dev, int index, + int *val) +{ + struct qmc6308_data *data = iio_priv(indio_dev); + struct device *dev = regmap_get_device(data->regmap); + unsigned int status; + __le16 buf[3]; + int ret; + + PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) { + dev_err(dev, "Failed to power on (%d)\n", ret); + return ret; + } + + guard(mutex)(&data->mutex); + + /* + * Reading the status register clears DRDY, which is why the poll + * and the data read stay under one mutex hold. A runtime resume + * clears DRDY too, so a sample converted before the last suspend + * is never returned here. + * + * The timeout is 50ms of headroom over the slowest ODR (10Hz). + */ + ret = regmap_read_poll_timeout(data->regmap, QMC6308_REG_STATUS, + status, (status & QMC6308_STATUS_DRDY), + 2 * USEC_PER_MSEC, + 150 * USEC_PER_MSEC); + if (ret) + return ret; + + ret = regmap_bulk_read(data->regmap, QMC6308_REG_X_LSB, buf, + sizeof(buf)); + if (ret) + return ret; + + if (status & QMC6308_STATUS_OVFL) + return -ERANGE; + + *val = (s16)le16_to_cpu(buf[index]); + + return 0; +} + +static int qmc6308_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct qmc6308_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = qmc6308_take_measurement(indio_dev, chan->address, val); + if (ret) + return ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: { + guard(mutex)(&data->mutex); + + *val = qmc6308_scales[data->range][0]; + *val2 = qmc6308_scales[data->range][1]; + + return IIO_VAL_INT_PLUS_NANO; + } + case IIO_CHAN_INFO_SAMP_FREQ: { + guard(mutex)(&data->mutex); + + *val = qmc6308_odr_avail[data->odr]; + + return IIO_VAL_INT; + } + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { + guard(mutex)(&data->mutex); + + *val = qmc6308_osr1_avail[data->osr]; + + return IIO_VAL_INT; + } + default: + return -EINVAL; + } +} + +static int qmc6308_write_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int val, int val2, long mask) +{ + struct qmc6308_data *data = iio_priv(indio_dev); + unsigned int status; + unsigned int i; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: { + if (val != 0) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(qmc6308_scales); i++) { + if (val2 == qmc6308_scales[i][1]) + break; + } + if (i == ARRAY_SIZE(qmc6308_scales)) + return -EINVAL; + + guard(mutex)(&data->mutex); + + ret = regmap_update_bits(data->regmap, QMC6308_REG_CTRL2, + QMC6308_RNG_MASK, + FIELD_PREP(QMC6308_RNG_MASK, i)); + if (ret) + return ret; + + data->range = i; + + /* + * The data registers still hold (and DRDY still + * advertises) a sample converted at the previous range; + * discard it so that a read does not pair old-range data + * with the new scale. A conversion already in flight may + * still complete at the old range, so this narrows the + * window rather than closing it. The range change itself + * took effect, so only log a failure here: an error + * would mislead userspace about an effective write. + */ + ret = regmap_read(data->regmap, QMC6308_REG_STATUS, + &status); + if (ret) + dev_warn(regmap_get_device(data->regmap), + "Failed to discard stale sample (%d)\n", ret); + + return 0; + } + case IIO_CHAN_INFO_SAMP_FREQ: { + for (i = 0; i < ARRAY_SIZE(qmc6308_odr_avail); i++) { + if (val == qmc6308_odr_avail[i]) + break; + } + if (i == ARRAY_SIZE(qmc6308_odr_avail)) + return -EINVAL; + + guard(mutex)(&data->mutex); + + ret = regmap_update_bits(data->regmap, QMC6308_REG_CTRL1, + QMC6308_ODR_MASK, + FIELD_PREP(QMC6308_ODR_MASK, i)); + if (ret) + return ret; + + data->odr = i; + + return 0; + } + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { + for (i = 0; i < ARRAY_SIZE(qmc6308_osr1_avail); i++) { + if (val == qmc6308_osr1_avail[i]) + break; + } + if (i == ARRAY_SIZE(qmc6308_osr1_avail)) + return -EINVAL; + + guard(mutex)(&data->mutex); + + ret = regmap_update_bits(data->regmap, QMC6308_REG_CTRL1, + QMC6308_OSR1_MASK, + FIELD_PREP(QMC6308_OSR1_MASK, i)); + if (ret) + return ret; + + data->osr = i; + + return 0; + } + default: + return -EINVAL; + } +} + +static int qmc6308_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_SAMP_FREQ: + *vals = qmc6308_odr_avail; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(qmc6308_odr_avail); + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *vals = qmc6308_osr1_avail; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(qmc6308_osr1_avail); + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SCALE: + *vals = (const int *)qmc6308_scales; + *type = IIO_VAL_INT_PLUS_NANO; + *length = ARRAY_SIZE(qmc6308_scales) * 2; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int qmc6308_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; + default: + return IIO_VAL_INT; + } +} + +static const struct iio_mount_matrix * +qmc6308_get_mount_matrix(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct qmc6308_data *data = iio_priv(indio_dev); + + return &data->orientation; +} + +static const struct iio_chan_spec_ext_info qmc6308_ext_info[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, qmc6308_get_mount_matrix), + { } +}; + +static const struct iio_info qmc6308_info = { + .read_raw = qmc6308_read_raw, + .write_raw = qmc6308_write_raw, + .read_avail = qmc6308_read_avail, + .write_raw_get_fmt = qmc6308_write_raw_get_fmt, +}; + +static int qmc6308_init(struct qmc6308_data *data) +{ + struct regmap *map = data->regmap; + unsigned int reg; + int ret; + + ret = regmap_read(map, QMC6308_REG_ID, ®); + if (ret) + return ret; + + /* Allow unknown IDs so that fallback compatibles work */ + if (reg != QMC6308_CHIP_ID) + dev_warn(regmap_get_device(map), + "Unknown chip id: 0x%02x, continuing\n", reg); + + /* The SOFT_RST bit is not auto-cleared and must be written back 0 */ + ret = regmap_write(map, QMC6308_REG_CTRL2, QMC6308_SOFT_RST); + if (ret) + return ret; + + /* + * The datasheet gives no soft-reset completion figure; reuse the + * power-on time as a conservative bound. + */ + fsleep(QMC6308_POR_US); + + data->range = QMC6308_RNG_30G; + data->odr = QMC6308_ODR_50HZ; + data->osr = QMC6308_OSR1_8; + + ret = regmap_write(map, QMC6308_REG_CTRL2, + FIELD_PREP(QMC6308_SET_RESET_MASK, + QMC6308_SET_RESET_ON) | + FIELD_PREP(QMC6308_RNG_MASK, data->range)); + if (ret) + return ret; + + /* OSR2 (second-stage filter) set to its power-on default of 0 */ + return regmap_write(map, QMC6308_REG_CTRL1, + FIELD_PREP(QMC6308_MODE_MASK, + QMC6308_MODE_NORMAL) | + FIELD_PREP(QMC6308_ODR_MASK, data->odr) | + FIELD_PREP(QMC6308_OSR1_MASK, data->osr) | + FIELD_PREP(QMC6308_OSR2_MASK, 0)); +} + +static void qmc6308_power_down_action(void *priv) +{ + struct qmc6308_data *data = priv; + + if (!pm_runtime_status_suspended(regmap_get_device(data->regmap))) + qmc6308_set_mode(data, QMC6308_MODE_SUSPEND); +} + +static bool qmc6308_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg >= QMC6308_REG_X_LSB && reg <= QMC6308_REG_STATUS; +} + +static bool qmc6308_writable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case QMC6308_REG_CTRL1: + case QMC6308_REG_CTRL2: + case QMC6308_REG_CTRL3: + case QMC6308_REG_CTRL4: + return true; + default: + return false; + } +} + +static const struct regmap_config qmc6308_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = QMC6308_REG_CTRL4, + .cache_type = REGCACHE_MAPLE, + .volatile_reg = qmc6308_volatile_reg, + .writeable_reg = qmc6308_writable_reg, +}; + +#define QMC6308_CHANNEL(_axis) \ + { \ + .type = IIO_MAGN, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .address = QMC6308_AXIS_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .ext_info = qmc6308_ext_info, \ + } + +static const struct iio_chan_spec qmc6308_channels[] = { + QMC6308_CHANNEL(X), + QMC6308_CHANNEL(Y), + QMC6308_CHANNEL(Z), +}; + +static int qmc6308_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct qmc6308_data *data; + struct iio_dev *indio_dev; + struct regmap *map; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + i2c_set_clientdata(client, indio_dev); + + map = devm_regmap_init_i2c(client, &qmc6308_regmap_config); + if (IS_ERR(map)) + return dev_err_probe(dev, PTR_ERR(map), + "regmap initialization failed\n"); + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, + "Failed to enable VDD regulator\n"); + + fsleep(QMC6308_POR_US); + + data = iio_priv(indio_dev); + data->regmap = map; + + ret = devm_mutex_init(dev, &data->mutex); + if (ret) + return ret; + + ret = iio_read_mount_matrix(dev, &data->orientation); + if (ret) + return dev_err_probe(dev, ret, + "Failed to read mount matrix\n"); + + indio_dev->name = "qmc6308"; + indio_dev->info = &qmc6308_info; + indio_dev->channels = qmc6308_channels; + indio_dev->num_channels = ARRAY_SIZE(qmc6308_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = qmc6308_init(data); + if (ret) + return dev_err_probe(dev, ret, "qmc6308 init failed\n"); + + ret = pm_runtime_set_active(dev); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, qmc6308_power_down_action, data); + if (ret) + return ret; + + pm_runtime_use_autosuspend(dev); + pm_runtime_set_autosuspend_delay(dev, QMC6308_AUTOSUSPEND_DELAY_MS); + + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static int qmc6308_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct qmc6308_data *data = iio_priv(indio_dev); + + return qmc6308_set_mode(data, QMC6308_MODE_SUSPEND); +} + +static int qmc6308_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct qmc6308_data *data = iio_priv(indio_dev); + unsigned int status; + int ret; + + ret = qmc6308_set_mode(data, QMC6308_MODE_NORMAL); + if (ret) + return ret; + + /* + * DRDY may still be set for a sample converted before the last + * suspend; reading the status register clears it so the next + * measurement waits for fresh data. + */ + ret = regmap_read(data->regmap, QMC6308_REG_STATUS, &status); + if (ret) { + /* Best effort to leave the chip in a consistent state */ + qmc6308_set_mode(data, QMC6308_MODE_SUSPEND); + } + + return ret; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(qmc6308_pm_ops, qmc6308_runtime_suspend, + qmc6308_runtime_resume, NULL); + +static const struct of_device_id qmc6308_match[] = { + { .compatible = "qstcorp,qmc6308" }, + { } +}; +MODULE_DEVICE_TABLE(of, qmc6308_match); + +static const struct i2c_device_id qmc6308_id[] = { + { .name = "qmc6308" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, qmc6308_id); + +static struct i2c_driver qmc6308_driver = { + .driver = { + .name = "qmc6308", + .of_match_table = qmc6308_match, + .pm = pm_ptr(&qmc6308_pm_ops), + }, + .id_table = qmc6308_id, + .probe = qmc6308_probe, +}; +module_i2c_driver(qmc6308_driver); + +MODULE_DESCRIPTION("QST QMC6308 3-Axis Magnetic Sensor driver"); +MODULE_AUTHOR("Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/magnetometer/rm3100-core.c b/drivers/iio/magnetometer/rm3100-core.c index 2b2884425746..46fce2978d76 100644 --- a/drivers/iio/magnetometer/rm3100-core.c +++ b/drivers/iio/magnetometer/rm3100-core.c @@ -204,27 +204,23 @@ static int rm3100_read_mag(struct rm3100_data *data, int idx, int *val) u8 buffer[3]; int ret; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); + ret = regmap_write(regmap, RM3100_REG_POLL, BIT(4 + idx)); if (ret < 0) - goto unlock_return; + return ret; ret = rm3100_wait_measurement(data); if (ret < 0) - goto unlock_return; + return ret; ret = regmap_bulk_read(regmap, RM3100_REG_MX2 + 3 * idx, buffer, 3); if (ret < 0) - goto unlock_return; - mutex_unlock(&data->lock); + return ret; *val = sign_extend32(get_unaligned_be24(&buffer[0]), 23); return IIO_VAL_INT; - -unlock_return: - mutex_unlock(&data->lock); - return ret; } #define RM3100_CHANNEL(axis, idx) \ @@ -284,11 +280,12 @@ static int rm3100_get_samp_freq(struct rm3100_data *data, int *val, int *val2) unsigned int tmp; int ret; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); + ret = regmap_read(data->regmap, RM3100_REG_TMRC, &tmp); - mutex_unlock(&data->lock); if (ret < 0) return ret; + *val = rm3100_samp_rates[tmp - RM3100_TMRC_OFFSET][0]; *val2 = rm3100_samp_rates[tmp - RM3100_TMRC_OFFSET][1]; @@ -338,56 +335,50 @@ static int rm3100_set_samp_freq(struct iio_dev *indio_dev, int val, int val2) int ret; int i; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); + /* All cycle count registers use the same value. */ ret = regmap_read(regmap, RM3100_REG_CC_X, &cycle_count); if (ret < 0) - goto unlock_return; + return ret; for (i = 0; i < RM3100_SAMP_NUM; i++) { if (val == rm3100_samp_rates[i][0] && val2 == rm3100_samp_rates[i][1]) break; } - if (i == RM3100_SAMP_NUM) { - ret = -EINVAL; - goto unlock_return; - } + if (i == RM3100_SAMP_NUM) + return -EINVAL; ret = regmap_write(regmap, RM3100_REG_TMRC, i + RM3100_TMRC_OFFSET); if (ret < 0) - goto unlock_return; + return ret; /* Checking if cycle count registers need changing. */ if (val == 600 && cycle_count == 200) { ret = rm3100_set_cycle_count(data, 100); if (ret < 0) - goto unlock_return; + return ret; } else if (val != 600 && cycle_count == 100) { ret = rm3100_set_cycle_count(data, 200); if (ret < 0) - goto unlock_return; + return ret; } if (iio_buffer_enabled(indio_dev)) { /* Writing TMRC registers requires CMM reset. */ ret = regmap_write(regmap, RM3100_REG_CMM, 0); if (ret < 0) - goto unlock_return; + return ret; ret = regmap_write(data->regmap, RM3100_REG_CMM, (*indio_dev->active_scan_mask & 0x7) << RM3100_CMM_AXIS_SHIFT | RM3100_CMM_START); if (ret < 0) - goto unlock_return; + return ret; } - mutex_unlock(&data->lock); data->conversion_time = rm3100_samp_rates[i][2] * 2; return 0; - -unlock_return: - mutex_unlock(&data->lock); - return ret; } static int rm3100_read_raw(struct iio_dev *indio_dev, @@ -458,6 +449,27 @@ static const struct iio_buffer_setup_ops rm3100_buffer_ops = { .postdisable = rm3100_buffer_postdisable, }; +/** + * rm3100_regmap_bulk_read_locked() - Wrapper around regmap_bulk_read() with a mutex + * + * @data: Data structure containing regmap and mutex + * @reg: First register to be read from, passed to regmap_bulk_read() + * @val: Pointer to store read value, in native register size for device, + * passed to regmap_bulk_read() + * @val_count: Number of registers to read, passed to regmap_bulk_read() + * + * Intended for use only in rm3100_trigger_handler(). + * + * Return: + * A value of zero on success, a negative errno in error cases. + */ +static int rm3100_regmap_bulk_read_locked(struct rm3100_data *data, unsigned int reg, + void *val, size_t val_count) +{ + guard(mutex)(&data->lock); + return regmap_bulk_read(data->regmap, reg, val, val_count); +} + static irqreturn_t rm3100_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; @@ -465,14 +477,12 @@ static irqreturn_t rm3100_trigger_handler(int irq, void *p) unsigned long scan_mask = *indio_dev->active_scan_mask; unsigned int mask_len = iio_get_masklength(indio_dev); struct rm3100_data *data = iio_priv(indio_dev); - struct regmap *regmap = data->regmap; int ret, i, bit; - mutex_lock(&data->lock); switch (scan_mask) { case BIT(0) | BIT(1) | BIT(2): - ret = regmap_bulk_read(regmap, RM3100_REG_MX2, data->buffer, 9); - mutex_unlock(&data->lock); + ret = rm3100_regmap_bulk_read_locked(data, RM3100_REG_MX2, + data->buffer, 9); if (ret < 0) goto done; /* Convert XXXYYYZZZxxx to XXXxYYYxZZZx. x for paddings. */ @@ -480,36 +490,34 @@ static irqreturn_t rm3100_trigger_handler(int irq, void *p) memmove(data->buffer + i * 4, data->buffer + i * 3, 3); break; case BIT(0) | BIT(1): - ret = regmap_bulk_read(regmap, RM3100_REG_MX2, data->buffer, 6); - mutex_unlock(&data->lock); + ret = rm3100_regmap_bulk_read_locked(data, RM3100_REG_MX2, + data->buffer, 6); if (ret < 0) goto done; memmove(data->buffer + 4, data->buffer + 3, 3); break; case BIT(1) | BIT(2): - ret = regmap_bulk_read(regmap, RM3100_REG_MY2, data->buffer, 6); - mutex_unlock(&data->lock); + ret = rm3100_regmap_bulk_read_locked(data, RM3100_REG_MY2, + data->buffer, 6); if (ret < 0) goto done; memmove(data->buffer + 4, data->buffer + 3, 3); break; case BIT(0) | BIT(2): - ret = regmap_bulk_read(regmap, RM3100_REG_MX2, data->buffer, 9); - mutex_unlock(&data->lock); + ret = rm3100_regmap_bulk_read_locked(data, RM3100_REG_MX2, + data->buffer, 9); if (ret < 0) goto done; memmove(data->buffer + 4, data->buffer + 6, 3); break; default: for_each_set_bit(bit, &scan_mask, mask_len) { - ret = regmap_bulk_read(regmap, RM3100_REG_MX2 + 3 * bit, - data->buffer, 3); - if (ret < 0) { - mutex_unlock(&data->lock); + ret = rm3100_regmap_bulk_read_locked(data, + RM3100_REG_MX2 + 3 * bit, + data->buffer, 3); + if (ret < 0) goto done; - } } - mutex_unlock(&data->lock); } /* * Always using the same buffer so that we wouldn't need to set the @@ -560,10 +568,8 @@ int rm3100_common_probe(struct device *dev, struct regmap *regmap, int irq) IRQF_ONESHOT, indio_dev->name, indio_dev); - if (ret < 0) { - dev_err(dev, "request irq line failed.\n"); + if (ret) return ret; - } data->drdy_trig = devm_iio_trigger_alloc(dev, "%s-drdy%d", indio_dev->name, diff --git a/drivers/iio/magnetometer/si7210.c b/drivers/iio/magnetometer/si7210.c index 27e3feba7a0f..e9670d671a28 100644 --- a/drivers/iio/magnetometer/si7210.c +++ b/drivers/iio/magnetometer/si7210.c @@ -16,7 +16,6 @@ #include <linux/i2c.h> #include <linux/iio/iio.h> #include <linux/math64.h> -#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> @@ -128,8 +127,8 @@ static const struct regmap_config si7210_regmap_conf = { struct si7210_data { struct regmap *regmap; struct i2c_client *client; - struct regulator *vdd; struct mutex fetch_lock; /* lock for a single measurement fetch */ + unsigned int vdd_uV; s8 temp_offset; s8 temp_gain; s8 scale_20_a[A_REGS_COUNT]; @@ -221,12 +220,8 @@ static int si7210_read_raw(struct iio_dev *indio_dev, temp *= (1 + (data->temp_gain / 2048)); temp += (int)(MICRO / 16) * data->temp_offset; - ret = regulator_get_voltage(data->vdd); - if (ret < 0) - return ret; - /* temp -= 0.222 * VDD */ - temp -= 222 * div_s64(ret, MILLI); + temp -= 222 * (data->vdd_uV / MILLI); *val = div_s64(temp, MILLI); @@ -396,14 +391,11 @@ static int si7210_probe(struct i2c_client *client) return dev_err_probe(&client->dev, PTR_ERR(data->regmap), "failed to register regmap\n"); - data->vdd = devm_regulator_get(&client->dev, "vdd"); - if (IS_ERR(data->vdd)) - return dev_err_probe(&client->dev, PTR_ERR(data->vdd), - "failed to get VDD regulator\n"); - - ret = regulator_enable(data->vdd); - if (ret) - return ret; + ret = devm_regulator_get_enable_read_voltage(&client->dev, "vdd"); + if (ret < 0) + return dev_err_probe(&client->dev, ret, + "Failed to get vdd regulator\n"); + data->vdd_uV = ret; indio_dev->name = dev_name(&client->dev); indio_dev->modes = INDIO_DIRECT_MODE; @@ -420,7 +412,7 @@ static int si7210_probe(struct i2c_client *client) } static const struct i2c_device_id si7210_id[] = { - { "si7210" }, + { .name = "si7210" }, { } }; MODULE_DEVICE_TABLE(i2c, si7210_id); diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index ef348d316c00..7644bd04654b 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -506,6 +506,11 @@ static const struct st_sensors_platform_data default_magn_pdata = { .drdy_int_pin = 2, }; +/* LIS2MDL only supports DRDY on INT1 */ +static const struct st_sensors_platform_data alt_magn_pdata = { + .drdy_int_pin = 1, +}; + static int st_magn_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask) @@ -628,8 +633,12 @@ 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; - if (!pdata) - pdata = (struct st_sensors_platform_data *)&default_magn_pdata; + if (!pdata) { + if (mdata->sensor_settings->drdy_irq.int2.mask) + pdata = (struct st_sensors_platform_data *)&default_magn_pdata; + else + pdata = (struct st_sensors_platform_data *)&alt_magn_pdata; + } err = st_sensors_init_sensor(indio_dev, pdata); if (err < 0) diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c index ed70e782af5e..de66016811db 100644 --- a/drivers/iio/magnetometer/st_magn_i2c.c +++ b/drivers/iio/magnetometer/st_magn_i2c.c @@ -9,7 +9,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/iio/iio.h> @@ -93,15 +92,15 @@ static int st_magn_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id st_magn_id_table[] = { - { LSM303DLH_MAGN_DEV_NAME }, - { LSM303DLHC_MAGN_DEV_NAME }, - { LSM303DLM_MAGN_DEV_NAME }, - { LIS3MDL_MAGN_DEV_NAME }, - { LSM303AGR_MAGN_DEV_NAME }, - { LIS2MDL_MAGN_DEV_NAME }, - { LSM9DS1_MAGN_DEV_NAME }, - { IIS2MDC_MAGN_DEV_NAME }, - { LSM303C_MAGN_DEV_NAME }, + { .name = LSM303DLH_MAGN_DEV_NAME }, + { .name = LSM303DLHC_MAGN_DEV_NAME }, + { .name = LSM303DLM_MAGN_DEV_NAME }, + { .name = LIS3MDL_MAGN_DEV_NAME }, + { .name = LSM303AGR_MAGN_DEV_NAME }, + { .name = LIS2MDL_MAGN_DEV_NAME }, + { .name = LSM9DS1_MAGN_DEV_NAME }, + { .name = IIS2MDC_MAGN_DEV_NAME }, + { .name = LSM303C_MAGN_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, st_magn_id_table); diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c index 68816362bb95..af4642b6c3c0 100644 --- a/drivers/iio/magnetometer/st_magn_spi.c +++ b/drivers/iio/magnetometer/st_magn_spi.c @@ -9,7 +9,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/spi/spi.h> #include <linux/iio/iio.h> @@ -88,12 +87,12 @@ static int st_magn_spi_probe(struct spi_device *spi) } static const struct spi_device_id st_magn_id_table[] = { - { LIS3MDL_MAGN_DEV_NAME }, - { LSM303AGR_MAGN_DEV_NAME }, - { LIS2MDL_MAGN_DEV_NAME }, - { LSM9DS1_MAGN_DEV_NAME }, - { IIS2MDC_MAGN_DEV_NAME }, - { LSM303C_MAGN_DEV_NAME }, + { .name = LIS3MDL_MAGN_DEV_NAME }, + { .name = LSM303AGR_MAGN_DEV_NAME }, + { .name = LIS2MDL_MAGN_DEV_NAME }, + { .name = LSM9DS1_MAGN_DEV_NAME }, + { .name = IIS2MDC_MAGN_DEV_NAME }, + { .name = LSM303C_MAGN_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(spi, st_magn_id_table); diff --git a/drivers/iio/magnetometer/tlv493d.c b/drivers/iio/magnetometer/tlv493d.c index e5e050af2b74..03415cc2c9b3 100644 --- a/drivers/iio/magnetometer/tlv493d.c +++ b/drivers/iio/magnetometer/tlv493d.c @@ -14,7 +14,6 @@ #include <linux/i2c.h> #include <linux/iopoll.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/pm.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> @@ -499,7 +498,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(tlv493d_pm_ops, tlv493d_runtime_suspend, tlv493d_runtime_resume, NULL); static const struct i2c_device_id tlv493d_id[] = { - { "tlv493d" }, + { .name = "tlv493d" }, { } }; MODULE_DEVICE_TABLE(i2c, tlv493d_id); diff --git a/drivers/iio/magnetometer/tmag5273.c b/drivers/iio/magnetometer/tmag5273.c index 2adc3c036ab4..155294b66924 100644 --- a/drivers/iio/magnetometer/tmag5273.c +++ b/drivers/iio/magnetometer/tmag5273.c @@ -708,7 +708,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(tmag5273_pm_ops, NULL); static const struct i2c_device_id tmag5273_id[] = { - { "tmag5273" }, + { .name = "tmag5273" }, { } }; MODULE_DEVICE_TABLE(i2c, tmag5273_id); diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index d49e37edcbed..f9afe9a59464 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -29,7 +29,6 @@ #include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/pm_runtime.h> #include <linux/property.h> @@ -168,6 +167,7 @@ struct yas5xx; /** * struct yas5xx_chip_info - device-specific data and function pointers * @devid: device ID number + * @product_label: product label used in Linux * @product_name: product name of the YAS variant * @version_names: version letters or namings * @volatile_reg: device-specific volatile registers @@ -189,6 +189,7 @@ struct yas5xx; */ struct yas5xx_chip_info { unsigned int devid; + const char *product_label; const char *product_name; const char *version_names[2]; const int *volatile_reg; @@ -859,9 +860,9 @@ static int yas530_get_calibration_data(struct yas5xx *yas5xx) c->f[0] = FIELD_GET(GENMASK(22, 21), val); c->f[1] = FIELD_GET(GENMASK(14, 13), val); c->f[2] = FIELD_GET(GENMASK(6, 5), val); - c->r[0] = sign_extend32(FIELD_GET(GENMASK(28, 23), val), 5); - c->r[1] = sign_extend32(FIELD_GET(GENMASK(20, 15), val), 5); - c->r[2] = sign_extend32(FIELD_GET(GENMASK(12, 7), val), 5); + c->r[0] = FIELD_GET_SIGNED(GENMASK(28, 23), val); + c->r[1] = FIELD_GET_SIGNED(GENMASK(20, 15), val); + c->r[2] = FIELD_GET_SIGNED(GENMASK(12, 7), val); return 0; } @@ -914,9 +915,9 @@ static int yas532_get_calibration_data(struct yas5xx *yas5xx) c->f[0] = FIELD_GET(GENMASK(24, 23), val); c->f[1] = FIELD_GET(GENMASK(16, 15), val); c->f[2] = FIELD_GET(GENMASK(8, 7), val); - c->r[0] = sign_extend32(FIELD_GET(GENMASK(30, 25), val), 5); - c->r[1] = sign_extend32(FIELD_GET(GENMASK(22, 17), val), 5); - c->r[2] = sign_extend32(FIELD_GET(GENMASK(14, 7), val), 5); + c->r[0] = FIELD_GET_SIGNED(GENMASK(30, 25), val); + c->r[1] = FIELD_GET_SIGNED(GENMASK(22, 17), val); + c->r[2] = FIELD_GET_SIGNED(GENMASK(14, 7), val); return 0; } @@ -1223,7 +1224,7 @@ static int yas530_measure_offsets(struct yas5xx *yas5xx) * as the values for [x, y1, y2]. The value is +/-31 * but the effect on the raw values is much larger. * The effect of the offset is to bring the measure - * rougly to the center. + * roughly to the center. */ ox = 0; oy1 = 0; @@ -1315,7 +1316,7 @@ static int yas537_power_on(struct yas5xx *yas5xx) return ret; /* Wait until the coil has ramped up */ - usleep_range(YAS537_MAG_RCOIL_TIME_US, YAS537_MAG_RCOIL_TIME_US + 100); + fsleep(YAS537_MAG_RCOIL_TIME_US); return 0; } @@ -1323,6 +1324,7 @@ static int yas537_power_on(struct yas5xx *yas5xx) static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { [yas530] = { .devid = YAS530_DEVICE_ID, + .product_label = "yas530", .product_name = "YAS530 MS-3E", .version_names = { "A", "B" }, .volatile_reg = yas530_volatile_reg, @@ -1338,6 +1340,7 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { }, [yas532] = { .devid = YAS532_DEVICE_ID, + .product_label = "yas532", .product_name = "YAS532 MS-3R", .version_names = { "AB", "AC" }, .volatile_reg = yas530_volatile_reg, @@ -1353,6 +1356,7 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { }, [yas533] = { .devid = YAS532_DEVICE_ID, + .product_label = "yas533", .product_name = "YAS533 MS-3F", .version_names = { "AB", "AC" }, .volatile_reg = yas530_volatile_reg, @@ -1368,6 +1372,7 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { }, [yas537] = { .devid = YAS537_DEVICE_ID, + .product_label = "yas537", .product_name = "YAS537 MS-3T", .version_names = { "v0", "v1" }, /* version naming unknown */ .volatile_reg = yas537_volatile_reg, @@ -1385,7 +1390,6 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { static int yas5xx_probe(struct i2c_client *i2c) { - const struct i2c_device_id *id = i2c_client_get_device_id(i2c); struct iio_dev *indio_dev; struct device *dev = &i2c->dev; struct yas5xx *yas5xx; @@ -1400,7 +1404,10 @@ static int yas5xx_probe(struct i2c_client *i2c) yas5xx = iio_priv(indio_dev); i2c_set_clientdata(i2c, indio_dev); yas5xx->dev = dev; - mutex_init(&yas5xx->lock); + + ret = devm_mutex_init(dev, &yas5xx->lock); + if (ret) + return ret; ret = iio_read_mount_matrix(dev, &yas5xx->orientation); if (ret) @@ -1418,7 +1425,7 @@ static int yas5xx_probe(struct i2c_client *i2c) return dev_err_probe(dev, ret, "cannot enable regulators\n"); /* See comment in runtime resume callback */ - usleep_range(31000, 40000); + fsleep(31 * USEC_PER_MSEC); /* This will take the device out of reset if need be */ yas5xx->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); @@ -1443,7 +1450,7 @@ static int yas5xx_probe(struct i2c_client *i2c) if (id_check != ci->devid) { ret = dev_err_probe(dev, -ENODEV, "device ID %02x doesn't match %s\n", - id_check, id->name); + id_check, ci->product_label); goto assert_reset; } @@ -1469,7 +1476,7 @@ static int yas5xx_probe(struct i2c_client *i2c) indio_dev->info = &yas5xx_info; indio_dev->available_scan_masks = yas5xx_scan_masks; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->name = id->name; + indio_dev->name = ci->product_label; indio_dev->channels = yas5xx_channels; indio_dev->num_channels = ARRAY_SIZE(yas5xx_channels); @@ -1557,7 +1564,7 @@ static int yas5xx_runtime_resume(struct device *dev) * for all voltages to settle. The YAS532 is 10ms then 4ms for the * I2C to come online. Let's keep it safe and put this at 31ms. */ - usleep_range(31000, 40000); + fsleep(31 * USEC_PER_MSEC); gpiod_set_value_cansleep(yas5xx->reset, 0); ret = ci->power_on(yas5xx); @@ -1579,10 +1586,10 @@ static DEFINE_RUNTIME_DEV_PM_OPS(yas5xx_dev_pm_ops, yas5xx_runtime_suspend, yas5xx_runtime_resume, NULL); static const struct i2c_device_id yas5xx_id[] = { - {"yas530", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas530] }, - {"yas532", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas532] }, - {"yas533", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas533] }, - {"yas537", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas537] }, + { .name = "yas530", .driver_data = (kernel_ulong_t)&yas5xx_chip_info_tbl[yas530] }, + { .name = "yas532", .driver_data = (kernel_ulong_t)&yas5xx_chip_info_tbl[yas532] }, + { .name = "yas533", .driver_data = (kernel_ulong_t)&yas5xx_chip_info_tbl[yas533] }, + { .name = "yas537", .driver_data = (kernel_ulong_t)&yas5xx_chip_info_tbl[yas537] }, { } }; MODULE_DEVICE_TABLE(i2c, yas5xx_id); diff --git a/drivers/iio/multiplexer/iio-mux.c b/drivers/iio/multiplexer/iio-mux.c index b742ca9a99d1..562457a67382 100644 --- a/drivers/iio/multiplexer/iio-mux.c +++ b/drivers/iio/multiplexer/iio-mux.c @@ -11,7 +11,6 @@ #include <linux/err.h> #include <linux/iio/consumer.h> #include <linux/iio/iio.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/mux/consumer.h> @@ -464,3 +463,4 @@ module_platform_driver(mux_driver); MODULE_DESCRIPTION("IIO multiplexer driver"); MODULE_AUTHOR("Peter Rosin <peda@axentia.se>"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c index 4e23a598a3fb..aea28321db95 100644 --- a/drivers/iio/orientation/hid-sensor-incl-3d.c +++ b/drivers/iio/orientation/hid-sensor-incl-3d.c @@ -7,7 +7,6 @@ #include <linux/device.h> #include <linux/platform_device.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/slab.h> #include <linux/hid-sensor-hub.h> #include <linux/iio/iio.h> @@ -86,8 +85,7 @@ static const struct iio_chan_spec incl_3d_channels[] = { }; /* Adjust channel real bits based on report descriptor */ -static void incl_3d_adjust_channel_bit_mask(struct iio_chan_spec *chan, - int size) +static void incl_3d_adjust_channel_bit_mask(struct iio_chan_spec *chan, int size) { chan->scan_type.sign = 's'; /* Real storage bits will change based on the report desc. */ @@ -98,9 +96,8 @@ static void incl_3d_adjust_channel_bit_mask(struct iio_chan_spec *chan, /* Channel read_raw handler */ static int incl_3d_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, - long mask) + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { struct incl_3d_state *incl_state = iio_priv(indio_dev); int report_id = -1; @@ -125,7 +122,7 @@ static int incl_3d_read_raw(struct iio_dev *indio_dev, min < 0); else { hid_sensor_power_state(&incl_state->common_attributes, - false); + false); return -EINVAL; } hid_sensor_power_state(&incl_state->common_attributes, false); @@ -158,10 +155,8 @@ static int incl_3d_read_raw(struct iio_dev *indio_dev, /* Channel write_raw handler */ static int incl_3d_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct incl_3d_state *incl_state = iio_priv(indio_dev); int ret; @@ -189,8 +184,7 @@ static const struct iio_info incl_3d_info = { /* Callback handler to send event after all samples are received and captured */ static int incl_3d_proc_event(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - void *priv) + u32 usage_id, void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct incl_3d_state *incl_state = iio_priv(indio_dev); @@ -212,9 +206,9 @@ static int incl_3d_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int incl_3d_capture_sample(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - size_t raw_len, char *raw_data, - void *priv) + u32 usage_id, + size_t raw_len, char *raw_data, + void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct incl_3d_state *incl_state = iio_priv(indio_dev); @@ -247,7 +241,7 @@ static int incl_3d_capture_sample(struct hid_sensor_hub_device *hsdev, static int incl_3d_parse_report(struct platform_device *pdev, struct hid_sensor_hub_device *hsdev, struct iio_chan_spec *channels, - unsigned usage_id, + u32 usage_id, struct incl_3d_state *st) { int ret; @@ -307,7 +301,7 @@ static int hid_incl_3d_probe(struct platform_device *pdev) indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct incl_3d_state)); - if (indio_dev == NULL) + if (!indio_dev) return -ENOMEM; platform_set_drvdata(pdev, indio_dev); @@ -350,33 +344,33 @@ static int hid_incl_3d_probe(struct platform_device *pdev) atomic_set(&incl_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, - &incl_state->common_attributes); + &incl_state->common_attributes); if (ret) { dev_err(&pdev->dev, "trigger setup failed\n"); return ret; } - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(&pdev->dev, "device register failed\n"); - goto error_remove_trigger; - } - incl_state->callbacks.send_event = incl_3d_proc_event; incl_state->callbacks.capture_sample = incl_3d_capture_sample; incl_state->callbacks.pdev = pdev; ret = sensor_hub_register_callback(hsdev, - HID_USAGE_SENSOR_INCLINOMETER_3D, - &incl_state->callbacks); + HID_USAGE_SENSOR_INCLINOMETER_3D, + &incl_state->callbacks); if (ret) { dev_err(&pdev->dev, "callback reg failed\n"); - goto error_iio_unreg; + goto error_remove_trigger; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "device register failed\n"); + goto error_remove_callback; } return 0; -error_iio_unreg: - iio_device_unregister(indio_dev); +error_remove_callback: + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D); error_remove_trigger: hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes); return ret; @@ -389,8 +383,8 @@ static void hid_incl_3d_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct incl_3d_state *incl_state = iio_priv(indio_dev); - sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D); iio_device_unregister(indio_dev); + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D); hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes); } diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c index e759f91a710a..f8c98f866cb0 100644 --- a/drivers/iio/orientation/hid-sensor-rotation.c +++ b/drivers/iio/orientation/hid-sensor-rotation.c @@ -7,7 +7,6 @@ #include <linux/device.h> #include <linux/platform_device.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/hid-sensor-hub.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -19,8 +18,13 @@ struct dev_rot_state { struct hid_sensor_common common_attributes; struct hid_sensor_hub_attribute_info quaternion; struct { - s32 sampled_vals[4]; - aligned_s64 timestamp; + IIO_DECLARE_QUATERNION(s32, sampled_vals); + /* + * ABI regression avoidance: There are two copies of the same + * timestamp in case of userspace depending on broken alignment + * from older kernels. + */ + aligned_s64 timestamp[2]; } scan; int scale_pre_decml; int scale_post_decml; @@ -34,6 +38,27 @@ static const u32 rotation_sensitivity_addresses[] = { HID_USAGE_SENSOR_ORIENT_QUATERNION, }; +enum { + DEV_ROT_SCAN_TYPE_16BIT, + DEV_ROT_SCAN_TYPE_32BIT, +}; + +static const struct iio_scan_type dev_rot_scan_types[] = { + [DEV_ROT_SCAN_TYPE_16BIT] = { + .sign = 's', + .realbits = 16, + /* Storage bits has to stay 32 to not break userspace. */ + .storagebits = 32, + .repeat = 4, + }, + [DEV_ROT_SCAN_TYPE_32BIT] = { + .sign = 's', + .realbits = 32, + .storagebits = 32, + .repeat = 4, + }, +}; + /* Channel definitions */ static const struct iio_chan_spec dev_rot_channels[] = { { @@ -45,30 +70,27 @@ static const struct iio_chan_spec dev_rot_channels[] = { BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_HYSTERESIS), - .scan_index = 0 + .scan_index = 0, + .has_ext_scan_type = 1, + .ext_scan_type = dev_rot_scan_types, + .num_ext_scan_type = ARRAY_SIZE(dev_rot_scan_types), }, IIO_CHAN_SOFT_TIMESTAMP(1) }; -/* Adjust channel real bits based on report descriptor */ -static void dev_rot_adjust_channel_bit_mask(struct iio_chan_spec *chan, - int size) -{ - chan->scan_type.sign = 's'; - /* Real storage bits will change based on the report desc. */ - chan->scan_type.realbits = size * 8; - /* Maximum size of a sample to capture is u32 */ - chan->scan_type.storagebits = sizeof(u32) * 8; - chan->scan_type.repeat = 4; -} - /* Channel read_raw handler */ static int dev_rot_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int size, int *vals, int *val_len, - long mask) + struct iio_chan_spec const *chan, + int size, int *vals, int *val_len, long mask) { struct dev_rot_state *rot_state = iio_priv(indio_dev); + struct hid_sensor_hub_device *hsdev = rot_state->common_attributes.hsdev; + struct hid_sensor_hub_attribute_info *info = &rot_state->quaternion; + u32 usage_id = HID_USAGE_SENSOR_ORIENT_QUATERNION; + union { + s16 val16[4]; + s32 val32[4]; + } raw_buf; int ret_type; int i; @@ -78,8 +100,37 @@ static int dev_rot_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: if (size >= 4) { - for (i = 0; i < 4; ++i) - vals[i] = rot_state->scan.sampled_vals[i]; + if (info->size <= 0 || info->size > sizeof(raw_buf)) + return -EINVAL; + + hid_sensor_power_state(&rot_state->common_attributes, true); + + ret_type = sensor_hub_input_attr_read_values(hsdev, + hsdev->usage, + usage_id, + info->report_id, + SENSOR_HUB_SYNC, + info->size, + (u8 *)&raw_buf); + + hid_sensor_power_state(&rot_state->common_attributes, false); + + if (ret_type < 0) + return ret_type; + + switch (info->size) { + case sizeof(raw_buf.val16): + for (i = 0; i < ARRAY_SIZE(raw_buf.val16); i++) + vals[i] = raw_buf.val16[i]; + break; + case sizeof(raw_buf.val32): + for (i = 0; i < ARRAY_SIZE(raw_buf.val32); i++) + vals[i] = raw_buf.val32[i]; + break; + default: + return -EINVAL; + } + ret_type = IIO_VAL_INT_MULTIPLE; *val_len = 4; } else @@ -112,10 +163,8 @@ static int dev_rot_read_raw(struct iio_dev *indio_dev, /* Channel write_raw handler */ static int dev_rot_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct dev_rot_state *rot_state = iio_priv(indio_dev); int ret; @@ -136,15 +185,30 @@ static int dev_rot_write_raw(struct iio_dev *indio_dev, return ret; } +static int dev_rot_get_current_scan_type(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct dev_rot_state *rot_state = iio_priv(indio_dev); + + switch (rot_state->quaternion.size / 4) { + case sizeof(s16): + return DEV_ROT_SCAN_TYPE_16BIT; + case sizeof(s32): + return DEV_ROT_SCAN_TYPE_32BIT; + default: + return -EINVAL; + } +} + static const struct iio_info dev_rot_info = { .read_raw_multi = &dev_rot_read_raw, .write_raw = &dev_rot_write_raw, + .get_current_scan_type = &dev_rot_get_current_scan_type, }; /* Callback handler to send event after all samples are received and captured */ static int dev_rot_proc_event(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - void *priv) + u32 usage_id, void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct dev_rot_state *rot_state = iio_priv(indio_dev); @@ -154,8 +218,19 @@ static int dev_rot_proc_event(struct hid_sensor_hub_device *hsdev, if (!rot_state->timestamp) rot_state->timestamp = iio_get_time_ns(indio_dev); - iio_push_to_buffers_with_timestamp(indio_dev, &rot_state->scan, - rot_state->timestamp); + /* + * ABI regression avoidance: IIO previously had an incorrect + * implementation of iio_push_to_buffers_with_timestamp() that + * put the timestamp in the last 8 bytes of the buffer, which + * was incorrect according to the IIO ABI. To avoid breaking + * userspace that may be depending on this broken behavior, we + * put the timestamp in both the correct place [0] and the old + * incorrect place [1]. + */ + rot_state->scan.timestamp[0] = rot_state->timestamp; + rot_state->scan.timestamp[1] = rot_state->timestamp; + + iio_push_to_buffers(indio_dev, &rot_state->scan); rot_state->timestamp = 0; } @@ -165,9 +240,9 @@ static int dev_rot_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int dev_rot_capture_sample(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - size_t raw_len, char *raw_data, - void *priv) + u32 usage_id, + size_t raw_len, char *raw_data, + void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct dev_rot_state *rot_state = iio_priv(indio_dev); @@ -196,8 +271,7 @@ static int dev_rot_capture_sample(struct hid_sensor_hub_device *hsdev, /* Parse report which is specific to an usage id*/ static int dev_rot_parse_report(struct platform_device *pdev, struct hid_sensor_hub_device *hsdev, - struct iio_chan_spec *channels, - unsigned usage_id, + u32 usage_id, struct dev_rot_state *st) { int ret; @@ -210,9 +284,6 @@ static int dev_rot_parse_report(struct platform_device *pdev, if (ret) return ret; - dev_rot_adjust_channel_bit_mask(&channels[0], - st->quaternion.size / 4); - dev_dbg(&pdev->dev, "dev_rot %x:%x\n", st->quaternion.index, st->quaternion.report_id); @@ -238,7 +309,7 @@ static int hid_dev_rot_probe(struct platform_device *pdev) indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct dev_rot_state)); - if (indio_dev == NULL) + if (!indio_dev) return -ENOMEM; platform_set_drvdata(pdev, indio_dev); @@ -271,22 +342,13 @@ static int hid_dev_rot_probe(struct platform_device *pdev) return ret; } - indio_dev->channels = devm_kmemdup(&pdev->dev, dev_rot_channels, - sizeof(dev_rot_channels), - GFP_KERNEL); - if (!indio_dev->channels) { - dev_err(&pdev->dev, "failed to duplicate channels\n"); - return -ENOMEM; - } - - ret = dev_rot_parse_report(pdev, hsdev, - (struct iio_chan_spec *)indio_dev->channels, - hsdev->usage, rot_state); + ret = dev_rot_parse_report(pdev, hsdev, hsdev->usage, rot_state); if (ret) { dev_err(&pdev->dev, "failed to setup attributes\n"); return ret; } + indio_dev->channels = dev_rot_channels; indio_dev->num_channels = ARRAY_SIZE(dev_rot_channels); indio_dev->info = &dev_rot_info; indio_dev->name = name; @@ -295,32 +357,32 @@ static int hid_dev_rot_probe(struct platform_device *pdev) atomic_set(&rot_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, - &rot_state->common_attributes); + &rot_state->common_attributes); if (ret) { dev_err(&pdev->dev, "trigger setup failed\n"); return ret; } - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(&pdev->dev, "device register failed\n"); - goto error_remove_trigger; - } - rot_state->callbacks.send_event = dev_rot_proc_event; rot_state->callbacks.capture_sample = dev_rot_capture_sample; rot_state->callbacks.pdev = pdev; ret = sensor_hub_register_callback(hsdev, hsdev->usage, - &rot_state->callbacks); + &rot_state->callbacks); if (ret) { dev_err(&pdev->dev, "callback reg failed\n"); - goto error_iio_unreg; + goto error_remove_trigger; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "device register failed\n"); + goto error_remove_callback; } return 0; -error_iio_unreg: - iio_device_unregister(indio_dev); +error_remove_callback: + sensor_hub_remove_callback(hsdev, hsdev->usage); error_remove_trigger: hid_sensor_remove_trigger(indio_dev, &rot_state->common_attributes); return ret; @@ -333,8 +395,8 @@ static void hid_dev_rot_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct dev_rot_state *rot_state = iio_priv(indio_dev); - sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); + sensor_hub_remove_callback(hsdev, hsdev->usage); hid_sensor_remove_trigger(indio_dev, &rot_state->common_attributes); } diff --git a/drivers/iio/position/hid-sensor-custom-intel-hinge.c b/drivers/iio/position/hid-sensor-custom-intel-hinge.c index a26d391661fd..d275bc1413fe 100644 --- a/drivers/iio/position/hid-sensor-custom-intel-hinge.c +++ b/drivers/iio/position/hid-sensor-custom-intel-hinge.c @@ -8,7 +8,6 @@ #include <linux/iio/iio.h> #include <linux/platform_device.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include "../common/hid-sensors/hid-sensor-trigger.h" @@ -107,8 +106,8 @@ static void hinge_adjust_channel_realbits(struct iio_chan_spec *channels, /* Channel read_raw handler */ static int hinge_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, int *val, int *val2, - long mask) + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { struct hinge_state *st = iio_priv(indio_dev); struct hid_sensor_hub_device *hsdev; @@ -154,8 +153,8 @@ static int hinge_read_raw(struct iio_dev *indio_dev, /* Channel write_raw handler */ static int hinge_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, int val, int val2, - long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct hinge_state *st = iio_priv(indio_dev); @@ -190,7 +189,7 @@ static const struct iio_info hinge_info = { * and captured. */ static int hinge_proc_event(struct hid_sensor_hub_device *hsdev, - unsigned int usage_id, void *priv) + u32 usage_id, void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct hinge_state *st = iio_priv(indio_dev); @@ -209,8 +208,9 @@ static int hinge_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int hinge_capture_sample(struct hid_sensor_hub_device *hsdev, - unsigned int usage_id, size_t raw_len, - char *raw_data, void *priv) + u32 usage_id, + size_t raw_len, char *raw_data, + void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct hinge_state *st = iio_priv(indio_dev); @@ -236,7 +236,7 @@ static int hinge_capture_sample(struct hid_sensor_hub_device *hsdev, static int hinge_parse_report(struct platform_device *pdev, struct hid_sensor_hub_device *hsdev, struct iio_chan_spec *channels, - unsigned int usage_id, struct hinge_state *st) + u32 usage_id, struct hinge_state *st) { int ret; int i; @@ -292,7 +292,7 @@ static int hid_hinge_probe(struct platform_device *pdev) } indio_dev->num_channels = ARRAY_SIZE(hinge_channels); - indio_dev->channels = devm_kmemdup(&indio_dev->dev, hinge_channels, + indio_dev->channels = devm_kmemdup(&pdev->dev, hinge_channels, sizeof(hinge_channels), GFP_KERNEL); if (!indio_dev->channels) return -ENOMEM; diff --git a/drivers/iio/potentiometer/ad5272.c b/drivers/iio/potentiometer/ad5272.c index 672b1ca3a920..35fe1575e972 100644 --- a/drivers/iio/potentiometer/ad5272.c +++ b/drivers/iio/potentiometer/ad5272.c @@ -15,7 +15,6 @@ #include <linux/i2c.h> #include <linux/iio/iio.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #define AD5272_RDAC_WR 1 #define AD5272_RDAC_RD 2 @@ -204,11 +203,11 @@ static const struct of_device_id ad5272_dt_ids[] = { MODULE_DEVICE_TABLE(of, ad5272_dt_ids); static const struct i2c_device_id ad5272_id[] = { - { "ad5272-020", AD5272_020 }, - { "ad5272-050", AD5272_050 }, - { "ad5272-100", AD5272_100 }, - { "ad5274-020", AD5274_020 }, - { "ad5274-100", AD5274_100 }, + { .name = "ad5272-020", .driver_data = AD5272_020 }, + { .name = "ad5272-050", .driver_data = AD5272_050 }, + { .name = "ad5272-100", .driver_data = AD5272_100 }, + { .name = "ad5274-020", .driver_data = AD5274_020 }, + { .name = "ad5274-100", .driver_data = AD5274_100 }, { } }; MODULE_DEVICE_TABLE(i2c, ad5272_id); diff --git a/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c index 8a64d93f7e7b..5046119b78b0 100644 --- a/drivers/iio/potentiometer/ds1803.c +++ b/drivers/iio/potentiometer/ds1803.c @@ -16,7 +16,6 @@ #include <linux/i2c.h> #include <linux/iio/iio.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #define DS1803_WIPER_0 0xA9 @@ -235,10 +234,10 @@ static const struct of_device_id ds1803_dt_ids[] = { MODULE_DEVICE_TABLE(of, ds1803_dt_ids); static const struct i2c_device_id ds1803_id[] = { - { "ds1803-010", (kernel_ulong_t)&ds1803_cfg[DS1803_010] }, - { "ds1803-050", (kernel_ulong_t)&ds1803_cfg[DS1803_050] }, - { "ds1803-100", (kernel_ulong_t)&ds1803_cfg[DS1803_100] }, - { "ds3502", (kernel_ulong_t)&ds1803_cfg[DS3502] }, + { .name = "ds1803-010", .driver_data = (kernel_ulong_t)&ds1803_cfg[DS1803_010] }, + { .name = "ds1803-050", .driver_data = (kernel_ulong_t)&ds1803_cfg[DS1803_050] }, + { .name = "ds1803-100", .driver_data = (kernel_ulong_t)&ds1803_cfg[DS1803_100] }, + { .name = "ds3502", .driver_data = (kernel_ulong_t)&ds1803_cfg[DS3502] }, { } }; MODULE_DEVICE_TABLE(i2c, ds1803_id); diff --git a/drivers/iio/potentiometer/max5432.c b/drivers/iio/potentiometer/max5432.c index 26390be79d02..f6d3ec04fdcf 100644 --- a/drivers/iio/potentiometer/max5432.c +++ b/drivers/iio/potentiometer/max5432.c @@ -11,7 +11,6 @@ #include <linux/iio/iio.h> #include <linux/limits.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> /* All chip variants have 32 wiper positions. */ diff --git a/drivers/iio/potentiometer/max5481.c b/drivers/iio/potentiometer/max5481.c index b40e5ac218d7..ec1b7bdc706b 100644 --- a/drivers/iio/potentiometer/max5481.c +++ b/drivers/iio/potentiometer/max5481.c @@ -10,7 +10,6 @@ #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/spi/spi.h> @@ -170,10 +169,10 @@ static int max5481_probe(struct spi_device *spi) } static const struct spi_device_id max5481_id_table[] = { - { "max5481", max5481 }, - { "max5482", max5482 }, - { "max5483", max5483 }, - { "max5484", max5484 }, + { .name = "max5481", .driver_data = max5481 }, + { .name = "max5482", .driver_data = max5482 }, + { .name = "max5483", .driver_data = max5483 }, + { .name = "max5484", .driver_data = max5484 }, { } }; MODULE_DEVICE_TABLE(spi, max5481_id_table); diff --git a/drivers/iio/potentiometer/max5487.c b/drivers/iio/potentiometer/max5487.c index 3b11b991940b..1f0d0056f412 100644 --- a/drivers/iio/potentiometer/max5487.c +++ b/drivers/iio/potentiometer/max5487.c @@ -5,7 +5,6 @@ * Copyright (C) 2016 Cristina-Gabriela Moraru <cristina.moraru09@gmail.com> */ #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/spi/spi.h> #include <linux/iio/sysfs.h> @@ -126,9 +125,9 @@ static void max5487_spi_remove(struct spi_device *spi) } static const struct spi_device_id max5487_id[] = { - { "MAX5487", 10 }, - { "MAX5488", 50 }, - { "MAX5489", 100 }, + { .name = "MAX5487", .driver_data = 10 }, + { .name = "MAX5488", .driver_data = 50 }, + { .name = "MAX5489", .driver_data = 100 }, { } }; MODULE_DEVICE_TABLE(spi, max5487_id); diff --git a/drivers/iio/potentiometer/mcp4018.c b/drivers/iio/potentiometer/mcp4018.c index a88bb2231850..b10b4b920dc0 100644 --- a/drivers/iio/potentiometer/mcp4018.c +++ b/drivers/iio/potentiometer/mcp4018.c @@ -16,7 +16,6 @@ #include <linux/i2c.h> #include <linux/iio/iio.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #define MCP4018_WIPER_MAX 127 diff --git a/drivers/iio/potentiometer/mcp41010.c b/drivers/iio/potentiometer/mcp41010.c index f35fc4a6c55b..cfd5d0f6d368 100644 --- a/drivers/iio/potentiometer/mcp41010.c +++ b/drivers/iio/potentiometer/mcp41010.c @@ -21,7 +21,6 @@ #include <linux/iio/iio.h> #include <linux/iio/types.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/property.h> #include <linux/spi/spi.h> @@ -176,12 +175,12 @@ static const struct of_device_id mcp41010_match[] = { MODULE_DEVICE_TABLE(of, mcp41010_match); static const struct spi_device_id mcp41010_id[] = { - { "mcp41010", MCP41010 }, - { "mcp41050", MCP41050 }, - { "mcp41100", MCP41100 }, - { "mcp42010", MCP42010 }, - { "mcp42050", MCP42050 }, - { "mcp42100", MCP42100 }, + { .name = "mcp41010", .driver_data = MCP41010 }, + { .name = "mcp41050", .driver_data = MCP41050 }, + { .name = "mcp41100", .driver_data = MCP41100 }, + { .name = "mcp42010", .driver_data = MCP42010 }, + { .name = "mcp42050", .driver_data = MCP42050 }, + { .name = "mcp42100", .driver_data = MCP42100 }, { } }; MODULE_DEVICE_TABLE(spi, mcp41010_id); diff --git a/drivers/iio/potentiometer/mcp4131.c b/drivers/iio/potentiometer/mcp4131.c index 56c9111ef5e8..fadf9fcc1817 100644 --- a/drivers/iio/potentiometer/mcp4131.c +++ b/drivers/iio/potentiometer/mcp4131.c @@ -36,7 +36,6 @@ #include <linux/iio/iio.h> #include <linux/iio/types.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/property.h> #include <linux/spi/spi.h> @@ -407,70 +406,70 @@ static const struct of_device_id mcp4131_dt_ids[] = { MODULE_DEVICE_TABLE(of, mcp4131_dt_ids); static const struct spi_device_id mcp4131_id[] = { - { "mcp4131-502", MCP413x_502 }, - { "mcp4131-103", MCP413x_103 }, - { "mcp4131-503", MCP413x_503 }, - { "mcp4131-104", MCP413x_104 }, - { "mcp4132-502", MCP413x_502 }, - { "mcp4132-103", MCP413x_103 }, - { "mcp4132-503", MCP413x_503 }, - { "mcp4132-104", MCP413x_104 }, - { "mcp4141-502", MCP414x_502 }, - { "mcp4141-103", MCP414x_103 }, - { "mcp4141-503", MCP414x_503 }, - { "mcp4141-104", MCP414x_104 }, - { "mcp4142-502", MCP414x_502 }, - { "mcp4142-103", MCP414x_103 }, - { "mcp4142-503", MCP414x_503 }, - { "mcp4142-104", MCP414x_104 }, - { "mcp4151-502", MCP415x_502 }, - { "mcp4151-103", MCP415x_103 }, - { "mcp4151-503", MCP415x_503 }, - { "mcp4151-104", MCP415x_104 }, - { "mcp4152-502", MCP415x_502 }, - { "mcp4152-103", MCP415x_103 }, - { "mcp4152-503", MCP415x_503 }, - { "mcp4152-104", MCP415x_104 }, - { "mcp4161-502", MCP416x_502 }, - { "mcp4161-103", MCP416x_103 }, - { "mcp4161-503", MCP416x_503 }, - { "mcp4161-104", MCP416x_104 }, - { "mcp4162-502", MCP416x_502 }, - { "mcp4162-103", MCP416x_103 }, - { "mcp4162-503", MCP416x_503 }, - { "mcp4162-104", MCP416x_104 }, - { "mcp4231-502", MCP423x_502 }, - { "mcp4231-103", MCP423x_103 }, - { "mcp4231-503", MCP423x_503 }, - { "mcp4231-104", MCP423x_104 }, - { "mcp4232-502", MCP423x_502 }, - { "mcp4232-103", MCP423x_103 }, - { "mcp4232-503", MCP423x_503 }, - { "mcp4232-104", MCP423x_104 }, - { "mcp4241-502", MCP424x_502 }, - { "mcp4241-103", MCP424x_103 }, - { "mcp4241-503", MCP424x_503 }, - { "mcp4241-104", MCP424x_104 }, - { "mcp4242-502", MCP424x_502 }, - { "mcp4242-103", MCP424x_103 }, - { "mcp4242-503", MCP424x_503 }, - { "mcp4242-104", MCP424x_104 }, - { "mcp4251-502", MCP425x_502 }, - { "mcp4251-103", MCP425x_103 }, - { "mcp4251-503", MCP425x_503 }, - { "mcp4251-104", MCP425x_104 }, - { "mcp4252-502", MCP425x_502 }, - { "mcp4252-103", MCP425x_103 }, - { "mcp4252-503", MCP425x_503 }, - { "mcp4252-104", MCP425x_104 }, - { "mcp4261-502", MCP426x_502 }, - { "mcp4261-103", MCP426x_103 }, - { "mcp4261-503", MCP426x_503 }, - { "mcp4261-104", MCP426x_104 }, - { "mcp4262-502", MCP426x_502 }, - { "mcp4262-103", MCP426x_103 }, - { "mcp4262-503", MCP426x_503 }, - { "mcp4262-104", MCP426x_104 }, + { .name = "mcp4131-502", .driver_data = MCP413x_502 }, + { .name = "mcp4131-103", .driver_data = MCP413x_103 }, + { .name = "mcp4131-503", .driver_data = MCP413x_503 }, + { .name = "mcp4131-104", .driver_data = MCP413x_104 }, + { .name = "mcp4132-502", .driver_data = MCP413x_502 }, + { .name = "mcp4132-103", .driver_data = MCP413x_103 }, + { .name = "mcp4132-503", .driver_data = MCP413x_503 }, + { .name = "mcp4132-104", .driver_data = MCP413x_104 }, + { .name = "mcp4141-502", .driver_data = MCP414x_502 }, + { .name = "mcp4141-103", .driver_data = MCP414x_103 }, + { .name = "mcp4141-503", .driver_data = MCP414x_503 }, + { .name = "mcp4141-104", .driver_data = MCP414x_104 }, + { .name = "mcp4142-502", .driver_data = MCP414x_502 }, + { .name = "mcp4142-103", .driver_data = MCP414x_103 }, + { .name = "mcp4142-503", .driver_data = MCP414x_503 }, + { .name = "mcp4142-104", .driver_data = MCP414x_104 }, + { .name = "mcp4151-502", .driver_data = MCP415x_502 }, + { .name = "mcp4151-103", .driver_data = MCP415x_103 }, + { .name = "mcp4151-503", .driver_data = MCP415x_503 }, + { .name = "mcp4151-104", .driver_data = MCP415x_104 }, + { .name = "mcp4152-502", .driver_data = MCP415x_502 }, + { .name = "mcp4152-103", .driver_data = MCP415x_103 }, + { .name = "mcp4152-503", .driver_data = MCP415x_503 }, + { .name = "mcp4152-104", .driver_data = MCP415x_104 }, + { .name = "mcp4161-502", .driver_data = MCP416x_502 }, + { .name = "mcp4161-103", .driver_data = MCP416x_103 }, + { .name = "mcp4161-503", .driver_data = MCP416x_503 }, + { .name = "mcp4161-104", .driver_data = MCP416x_104 }, + { .name = "mcp4162-502", .driver_data = MCP416x_502 }, + { .name = "mcp4162-103", .driver_data = MCP416x_103 }, + { .name = "mcp4162-503", .driver_data = MCP416x_503 }, + { .name = "mcp4162-104", .driver_data = MCP416x_104 }, + { .name = "mcp4231-502", .driver_data = MCP423x_502 }, + { .name = "mcp4231-103", .driver_data = MCP423x_103 }, + { .name = "mcp4231-503", .driver_data = MCP423x_503 }, + { .name = "mcp4231-104", .driver_data = MCP423x_104 }, + { .name = "mcp4232-502", .driver_data = MCP423x_502 }, + { .name = "mcp4232-103", .driver_data = MCP423x_103 }, + { .name = "mcp4232-503", .driver_data = MCP423x_503 }, + { .name = "mcp4232-104", .driver_data = MCP423x_104 }, + { .name = "mcp4241-502", .driver_data = MCP424x_502 }, + { .name = "mcp4241-103", .driver_data = MCP424x_103 }, + { .name = "mcp4241-503", .driver_data = MCP424x_503 }, + { .name = "mcp4241-104", .driver_data = MCP424x_104 }, + { .name = "mcp4242-502", .driver_data = MCP424x_502 }, + { .name = "mcp4242-103", .driver_data = MCP424x_103 }, + { .name = "mcp4242-503", .driver_data = MCP424x_503 }, + { .name = "mcp4242-104", .driver_data = MCP424x_104 }, + { .name = "mcp4251-502", .driver_data = MCP425x_502 }, + { .name = "mcp4251-103", .driver_data = MCP425x_103 }, + { .name = "mcp4251-503", .driver_data = MCP425x_503 }, + { .name = "mcp4251-104", .driver_data = MCP425x_104 }, + { .name = "mcp4252-502", .driver_data = MCP425x_502 }, + { .name = "mcp4252-103", .driver_data = MCP425x_103 }, + { .name = "mcp4252-503", .driver_data = MCP425x_503 }, + { .name = "mcp4252-104", .driver_data = MCP425x_104 }, + { .name = "mcp4261-502", .driver_data = MCP426x_502 }, + { .name = "mcp4261-103", .driver_data = MCP426x_103 }, + { .name = "mcp4261-503", .driver_data = MCP426x_503 }, + { .name = "mcp4261-104", .driver_data = MCP426x_104 }, + { .name = "mcp4262-502", .driver_data = MCP426x_502 }, + { .name = "mcp4262-103", .driver_data = MCP426x_103 }, + { .name = "mcp4262-503", .driver_data = MCP426x_503 }, + { .name = "mcp4262-104", .driver_data = MCP426x_104 }, { } }; MODULE_DEVICE_TABLE(spi, mcp4131_id); diff --git a/drivers/iio/potentiometer/mcp4531.c b/drivers/iio/potentiometer/mcp4531.c index 9912e91ff7b4..7fb1fb5ab8a5 100644 --- a/drivers/iio/potentiometer/mcp4531.c +++ b/drivers/iio/potentiometer/mcp4531.c @@ -28,7 +28,6 @@ #include <linux/module.h> #include <linux/i2c.h> #include <linux/err.h> -#include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/iio/iio.h> diff --git a/drivers/iio/potentiometer/tpl0102.c b/drivers/iio/potentiometer/tpl0102.c index a42b57733363..77149908e1bf 100644 --- a/drivers/iio/potentiometer/tpl0102.c +++ b/drivers/iio/potentiometer/tpl0102.c @@ -149,10 +149,10 @@ static int tpl0102_probe(struct i2c_client *client) } static const struct i2c_device_id tpl0102_id[] = { - { "cat5140-503", CAT5140_503 }, - { "cat5140-104", CAT5140_104 }, - { "tpl0102-104", TPL0102_104 }, - { "tpl0401-103", TPL0401_103 }, + { .name = "cat5140-503", .driver_data = CAT5140_503 }, + { .name = "cat5140-104", .driver_data = CAT5140_104 }, + { .name = "tpl0102-104", .driver_data = TPL0102_104 }, + { .name = "tpl0401-103", .driver_data = TPL0401_103 }, { } }; MODULE_DEVICE_TABLE(i2c, tpl0102_id); diff --git a/drivers/iio/potentiometer/x9250.c b/drivers/iio/potentiometer/x9250.c index 735348492699..974e4447fc2c 100644 --- a/drivers/iio/potentiometer/x9250.c +++ b/drivers/iio/potentiometer/x9250.c @@ -198,8 +198,8 @@ static const struct of_device_id x9250_of_match[] = { MODULE_DEVICE_TABLE(of, x9250_of_match); static const struct spi_device_id x9250_id_table[] = { - { "x9250t", (kernel_ulong_t)&x9250_cfg[X9250T] }, - { "x9250u", (kernel_ulong_t)&x9250_cfg[X9250U] }, + { .name = "x9250t", .driver_data = (kernel_ulong_t)&x9250_cfg[X9250T] }, + { .name = "x9250u", .driver_data = (kernel_ulong_t)&x9250_cfg[X9250U] }, { } }; MODULE_DEVICE_TABLE(spi, x9250_id_table); diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c index eccc2a34358f..00cb3fea97ca 100644 --- a/drivers/iio/potentiostat/lmp91000.c +++ b/drivers/iio/potentiostat/lmp91000.c @@ -11,7 +11,6 @@ #include <linux/module.h> #include <linux/i2c.h> #include <linux/delay.h> -#include <linux/mod_devicetable.h> #include <linux/regmap.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> @@ -403,8 +402,8 @@ static const struct of_device_id lmp91000_of_match[] = { MODULE_DEVICE_TABLE(of, lmp91000_of_match); static const struct i2c_device_id lmp91000_id[] = { - { "lmp91000" }, - { "lmp91002" }, + { .name = "lmp91000" }, + { .name = "lmp91002" }, { } }; MODULE_DEVICE_TABLE(i2c, lmp91000_id); @@ -423,3 +422,4 @@ module_i2c_driver(lmp91000_driver); MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>"); MODULE_DESCRIPTION("LMP91000 digital potentiostat"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_CONSUMER"); diff --git a/drivers/iio/pressure/abp060mg.c b/drivers/iio/pressure/abp060mg.c index 699b0fd64985..fd48bed35088 100644 --- a/drivers/iio/pressure/abp060mg.c +++ b/drivers/iio/pressure/abp060mg.c @@ -209,44 +209,66 @@ static int abp060mg_probe(struct i2c_client *client) static const struct i2c_device_id abp060mg_id_table[] = { /* mbar & kPa variants (abp060m [60 mbar] == abp006k [6 kPa]) */ /* gage: */ - { "abp060mg", ABP006KG }, { "abp006kg", ABP006KG }, - { "abp100mg", ABP010KG }, { "abp010kg", ABP010KG }, - { "abp160mg", ABP016KG }, { "abp016kg", ABP016KG }, - { "abp250mg", ABP025KG }, { "abp025kg", ABP025KG }, - { "abp400mg", ABP040KG }, { "abp040kg", ABP040KG }, - { "abp600mg", ABP060KG }, { "abp060kg", ABP060KG }, - { "abp001bg", ABP100KG }, { "abp100kg", ABP100KG }, - { "abp1_6bg", ABP160KG }, { "abp160kg", ABP160KG }, - { "abp2_5bg", ABP250KG }, { "abp250kg", ABP250KG }, - { "abp004bg", ABP400KG }, { "abp400kg", ABP400KG }, - { "abp006bg", ABP600KG }, { "abp600kg", ABP600KG }, - { "abp010bg", ABP001GG }, { "abp001gg", ABP001GG }, + { .name = "abp060mg", .driver_data = ABP006KG }, + { .name = "abp006kg", .driver_data = ABP006KG }, + { .name = "abp100mg", .driver_data = ABP010KG }, + { .name = "abp010kg", .driver_data = ABP010KG }, + { .name = "abp160mg", .driver_data = ABP016KG }, + { .name = "abp016kg", .driver_data = ABP016KG }, + { .name = "abp250mg", .driver_data = ABP025KG }, + { .name = "abp025kg", .driver_data = ABP025KG }, + { .name = "abp400mg", .driver_data = ABP040KG }, + { .name = "abp040kg", .driver_data = ABP040KG }, + { .name = "abp600mg", .driver_data = ABP060KG }, + { .name = "abp060kg", .driver_data = ABP060KG }, + { .name = "abp001bg", .driver_data = ABP100KG }, + { .name = "abp100kg", .driver_data = ABP100KG }, + { .name = "abp1_6bg", .driver_data = ABP160KG }, + { .name = "abp160kg", .driver_data = ABP160KG }, + { .name = "abp2_5bg", .driver_data = ABP250KG }, + { .name = "abp250kg", .driver_data = ABP250KG }, + { .name = "abp004bg", .driver_data = ABP400KG }, + { .name = "abp400kg", .driver_data = ABP400KG }, + { .name = "abp006bg", .driver_data = ABP600KG }, + { .name = "abp600kg", .driver_data = ABP600KG }, + { .name = "abp010bg", .driver_data = ABP001GG }, + { .name = "abp001gg", .driver_data = ABP001GG }, /* differential: */ - { "abp060md", ABP006KD }, { "abp006kd", ABP006KD }, - { "abp100md", ABP010KD }, { "abp010kd", ABP010KD }, - { "abp160md", ABP016KD }, { "abp016kd", ABP016KD }, - { "abp250md", ABP025KD }, { "abp025kd", ABP025KD }, - { "abp400md", ABP040KD }, { "abp040kd", ABP040KD }, - { "abp600md", ABP060KD }, { "abp060kd", ABP060KD }, - { "abp001bd", ABP100KD }, { "abp100kd", ABP100KD }, - { "abp1_6bd", ABP160KD }, { "abp160kd", ABP160KD }, - { "abp2_5bd", ABP250KD }, { "abp250kd", ABP250KD }, - { "abp004bd", ABP400KD }, { "abp400kd", ABP400KD }, + { .name = "abp060md", .driver_data = ABP006KD }, + { .name = "abp006kd", .driver_data = ABP006KD }, + { .name = "abp100md", .driver_data = ABP010KD }, + { .name = "abp010kd", .driver_data = ABP010KD }, + { .name = "abp160md", .driver_data = ABP016KD }, + { .name = "abp016kd", .driver_data = ABP016KD }, + { .name = "abp250md", .driver_data = ABP025KD }, + { .name = "abp025kd", .driver_data = ABP025KD }, + { .name = "abp400md", .driver_data = ABP040KD }, + { .name = "abp040kd", .driver_data = ABP040KD }, + { .name = "abp600md", .driver_data = ABP060KD }, + { .name = "abp060kd", .driver_data = ABP060KD }, + { .name = "abp001bd", .driver_data = ABP100KD }, + { .name = "abp100kd", .driver_data = ABP100KD }, + { .name = "abp1_6bd", .driver_data = ABP160KD }, + { .name = "abp160kd", .driver_data = ABP160KD }, + { .name = "abp2_5bd", .driver_data = ABP250KD }, + { .name = "abp250kd", .driver_data = ABP250KD }, + { .name = "abp004bd", .driver_data = ABP400KD }, + { .name = "abp400kd", .driver_data = ABP400KD }, /* psi variants */ /* gage: */ - { "abp001pg", ABP001PG }, - { "abp005pg", ABP005PG }, - { "abp015pg", ABP015PG }, - { "abp030pg", ABP030PG }, - { "abp060pg", ABP060PG }, - { "abp100pg", ABP100PG }, - { "abp150pg", ABP150PG }, + { .name = "abp001pg", .driver_data = ABP001PG }, + { .name = "abp005pg", .driver_data = ABP005PG }, + { .name = "abp015pg", .driver_data = ABP015PG }, + { .name = "abp030pg", .driver_data = ABP030PG }, + { .name = "abp060pg", .driver_data = ABP060PG }, + { .name = "abp100pg", .driver_data = ABP100PG }, + { .name = "abp150pg", .driver_data = ABP150PG }, /* differential: */ - { "abp001pd", ABP001PD }, - { "abp005pd", ABP005PD }, - { "abp015pd", ABP015PD }, - { "abp030pd", ABP030PD }, - { "abp060pd", ABP060PD }, + { .name = "abp001pd", .driver_data = ABP001PD }, + { .name = "abp005pd", .driver_data = ABP005PD }, + { .name = "abp015pd", .driver_data = ABP015PD }, + { .name = "abp030pd", .driver_data = ABP030PD }, + { .name = "abp060pd", .driver_data = ABP060PD }, { } }; MODULE_DEVICE_TABLE(i2c, abp060mg_id_table); diff --git a/drivers/iio/pressure/abp2030pa.c b/drivers/iio/pressure/abp2030pa.c index 4ca056a73cef..41395036e9ad 100644 --- a/drivers/iio/pressure/abp2030pa.c +++ b/drivers/iio/pressure/abp2030pa.c @@ -379,7 +379,6 @@ static int abp2_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } - return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: switch (channel->type) { @@ -520,7 +519,7 @@ int abp2_common_probe(struct device *dev, const struct abp2_ops *ops, int irq) data->p_offset = div_s64(odelta * data->pmin, pdelta) - data->outmin; if (data->irq > 0) { - ret = devm_request_irq(dev, irq, abp2_eoc_handler, IRQF_ONESHOT, + ret = devm_request_irq(dev, irq, abp2_eoc_handler, 0, dev_name(dev), data); if (ret) return ret; diff --git a/drivers/iio/pressure/abp2030pa_i2c.c b/drivers/iio/pressure/abp2030pa_i2c.c index 9f1c1c8a9afb..fa4d290cfd3e 100644 --- a/drivers/iio/pressure/abp2030pa_i2c.c +++ b/drivers/iio/pressure/abp2030pa_i2c.c @@ -8,7 +8,6 @@ #include <linux/device.h> #include <linux/errno.h> #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/types.h> @@ -69,7 +68,7 @@ static const struct of_device_id abp2_i2c_match[] = { MODULE_DEVICE_TABLE(of, abp2_i2c_match); static const struct i2c_device_id abp2_i2c_id[] = { - { "abp2030pa" }, + { .name = "abp2030pa" }, { } }; MODULE_DEVICE_TABLE(i2c, abp2_i2c_id); diff --git a/drivers/iio/pressure/abp2030pa_spi.c b/drivers/iio/pressure/abp2030pa_spi.c index eaea9a3ebf11..60d078574827 100644 --- a/drivers/iio/pressure/abp2030pa_spi.c +++ b/drivers/iio/pressure/abp2030pa_spi.c @@ -6,7 +6,6 @@ */ #include <linux/errno.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/spi/spi.h> #include <linux/types.h> @@ -46,7 +45,7 @@ static const struct of_device_id abp2_spi_match[] = { MODULE_DEVICE_TABLE(of, abp2_spi_match); static const struct spi_device_id abp2_spi_id[] = { - { "abp2030pa" }, + { .name = "abp2030pa" }, { } }; MODULE_DEVICE_TABLE(spi, abp2_spi_id); diff --git a/drivers/iio/pressure/adp810.c b/drivers/iio/pressure/adp810.c index 5282612d1309..82aa433548d2 100644 --- a/drivers/iio/pressure/adp810.c +++ b/drivers/iio/pressure/adp810.c @@ -16,7 +16,6 @@ #include <linux/errno.h> #include <linux/i2c.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/types.h> #include <linux/unaligned.h> @@ -199,7 +198,7 @@ static int adp810_probe(struct i2c_client *client) } static const struct i2c_device_id adp810_id_table[] = { - { "adp810" }, + { .name = "adp810" }, { } }; MODULE_DEVICE_TABLE(i2c, adp810_id_table); diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index d983ce9c0b99..1066792b9087 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -392,7 +392,7 @@ static int bme280_read_calib(struct bmp280_data *data) h4_lower = FIELD_GET(BME280_COMP_H4_MASK_LOW, tmp_1); calib->H4 = sign_extend32(h4_upper | h4_lower, 11); tmp_3 = get_unaligned_le16(&data->bme280_humid_cal_buf[H5]); - calib->H5 = sign_extend32(FIELD_GET(BME280_COMP_H5_MASK, tmp_3), 11); + calib->H5 = FIELD_GET_SIGNED(BME280_COMP_H5_MASK, tmp_3); calib->H6 = data->bme280_humid_cal_buf[H6]; return 0; @@ -750,7 +750,10 @@ static int bmp280_read_raw(struct iio_dev *indio_dev, struct bmp280_data *data = iio_priv(indio_dev); int ret; - pm_runtime_get_sync(data->dev); + ret = pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return ret; + ret = bmp280_read_raw_impl(indio_dev, chan, val, val2, mask); pm_runtime_put_autosuspend(data->dev); @@ -924,7 +927,10 @@ static int bmp280_write_raw(struct iio_dev *indio_dev, struct bmp280_data *data = iio_priv(indio_dev); int ret; - pm_runtime_get_sync(data->dev); + ret = pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return ret; + ret = bmp280_write_raw_impl(indio_dev, chan, val, val2, mask); pm_runtime_put_autosuspend(data->dev); @@ -1333,7 +1339,7 @@ static int __bmp280_trigger_probe(struct iio_dev *indio_dev, irq_thread_handler, IRQF_ONESHOT, indio_dev->name, indio_dev); if (ret) - return dev_err_probe(dev, ret, "request IRQ failed.\n"); + return ret; ret = devm_iio_trigger_register(data->dev, data->trig); if (ret) @@ -1910,7 +1916,7 @@ static irqreturn_t bmp380_trigger_handler(int irq, void *p) u32 comp_press; s32 comp_temp; aligned_s64 timestamp; - } buffer; + } buffer = { }; int ret; guard(mutex)(&data->lock); @@ -2254,7 +2260,10 @@ static int bmp580_nvmem_read(void *priv, unsigned int offset, void *val, struct bmp280_data *data = priv; int ret; - pm_runtime_get_sync(data->dev); + ret = pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return ret; + ret = bmp580_nvmem_read_impl(priv, offset, val, bytes); pm_runtime_put_autosuspend(data->dev); @@ -2328,7 +2337,10 @@ static int bmp580_nvmem_write(void *priv, unsigned int offset, void *val, struct bmp280_data *data = priv; int ret; - pm_runtime_get_sync(data->dev); + ret = pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return ret; + ret = bmp580_nvmem_write_impl(priv, offset, val, bytes); pm_runtime_put_autosuspend(data->dev); @@ -2616,7 +2628,7 @@ static irqreturn_t bmp580_trigger_handler(int irq, void *p) __le32 comp_temp; __le32 comp_press; aligned_s64 timestamp; - } buffer; + } buffer = { }; int ret; guard(mutex)(&data->lock); @@ -3108,11 +3120,17 @@ EXPORT_SYMBOL_NS(bmp085_chip_info, "IIO_BMP280"); static int bmp280_buffer_preenable(struct iio_dev *indio_dev) { struct bmp280_data *data = iio_priv(indio_dev); + int ret; + + ret = pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return ret; - pm_runtime_get_sync(data->dev); - data->chip_info->set_mode(data, BMP280_NORMAL); + ret = data->chip_info->set_mode(data, BMP280_NORMAL); + if (ret) + pm_runtime_put_autosuspend(data->dev); - return 0; + return ret; } static int bmp280_buffer_postdisable(struct iio_dev *indio_dev) diff --git a/drivers/iio/pressure/bmp280-i2c.c b/drivers/iio/pressure/bmp280-i2c.c index 8e459b6c97ff..3f6e0723a9d7 100644 --- a/drivers/iio/pressure/bmp280-i2c.c +++ b/drivers/iio/pressure/bmp280-i2c.c @@ -38,12 +38,12 @@ static const struct of_device_id bmp280_of_i2c_match[] = { MODULE_DEVICE_TABLE(of, bmp280_of_i2c_match); static const struct i2c_device_id bmp280_i2c_id[] = { - {"bmp085", (kernel_ulong_t)&bmp085_chip_info }, - {"bmp180", (kernel_ulong_t)&bmp180_chip_info }, - {"bmp280", (kernel_ulong_t)&bmp280_chip_info }, - {"bme280", (kernel_ulong_t)&bme280_chip_info }, - {"bmp380", (kernel_ulong_t)&bmp380_chip_info }, - {"bmp580", (kernel_ulong_t)&bmp580_chip_info }, + { .name = "bmp085", .driver_data = (kernel_ulong_t)&bmp085_chip_info }, + { .name = "bmp180", .driver_data = (kernel_ulong_t)&bmp180_chip_info }, + { .name = "bmp280", .driver_data = (kernel_ulong_t)&bmp280_chip_info }, + { .name = "bme280", .driver_data = (kernel_ulong_t)&bme280_chip_info }, + { .name = "bmp380", .driver_data = (kernel_ulong_t)&bmp380_chip_info }, + { .name = "bmp580", .driver_data = (kernel_ulong_t)&bmp580_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, bmp280_i2c_id); diff --git a/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c index 3b90384f17d7..a02a621b8015 100644 --- a/drivers/iio/pressure/bmp280-spi.c +++ b/drivers/iio/pressure/bmp280-spi.c @@ -47,7 +47,7 @@ static int bmp380_regmap_spi_read(void *context, const void *reg, return -EINVAL; /* - * According to the BMP3xx datasheets, for a basic SPI read opertion, + * According to the BMP3xx datasheets, for a basic SPI read operation, * the first byte needs to be dropped and the rest are the requested * data. */ @@ -118,13 +118,13 @@ static const struct of_device_id bmp280_of_spi_match[] = { MODULE_DEVICE_TABLE(of, bmp280_of_spi_match); static const struct spi_device_id bmp280_spi_id[] = { - { "bmp085", (kernel_ulong_t)&bmp085_chip_info }, - { "bmp180", (kernel_ulong_t)&bmp180_chip_info }, - { "bmp181", (kernel_ulong_t)&bmp180_chip_info }, - { "bmp280", (kernel_ulong_t)&bmp280_chip_info }, - { "bme280", (kernel_ulong_t)&bme280_chip_info }, - { "bmp380", (kernel_ulong_t)&bmp380_chip_info }, - { "bmp580", (kernel_ulong_t)&bmp580_chip_info }, + { .name = "bmp085", .driver_data = (kernel_ulong_t)&bmp085_chip_info }, + { .name = "bmp180", .driver_data = (kernel_ulong_t)&bmp180_chip_info }, + { .name = "bmp181", .driver_data = (kernel_ulong_t)&bmp180_chip_info }, + { .name = "bmp280", .driver_data = (kernel_ulong_t)&bmp280_chip_info }, + { .name = "bme280", .driver_data = (kernel_ulong_t)&bme280_chip_info }, + { .name = "bmp380", .driver_data = (kernel_ulong_t)&bmp380_chip_info }, + { .name = "bmp580", .driver_data = (kernel_ulong_t)&bmp580_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, bmp280_spi_id); diff --git a/drivers/iio/pressure/cros_ec_baro.c b/drivers/iio/pressure/cros_ec_baro.c index c6b950c596c1..6a567b6075d9 100644 --- a/drivers/iio/pressure/cros_ec_baro.c +++ b/drivers/iio/pressure/cros_ec_baro.c @@ -14,7 +14,6 @@ #include <linux/iio/triggered_buffer.h> #include <linux/iio/trigger_consumer.h> #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/platform_data/cros_ec_commands.h> @@ -170,14 +169,8 @@ static int cros_ec_baro_probe(struct platform_device *pdev) return -EINVAL; } - /* Timestamp */ channel++; - channel->type = IIO_TIMESTAMP; - channel->channel = -1; - channel->scan_index = 1; - channel->scan_type.sign = 's'; - channel->scan_type.realbits = 64; - channel->scan_type.storagebits = 64; + *channel = IIO_CHAN_SOFT_TIMESTAMP(1); indio_dev->channels = state->channels; indio_dev->num_channels = CROS_EC_BARO_MAX_CHANNELS; diff --git a/drivers/iio/pressure/dlhl60d.c b/drivers/iio/pressure/dlhl60d.c index 46feb27fe632..961888fd03a7 100644 --- a/drivers/iio/pressure/dlhl60d.c +++ b/drivers/iio/pressure/dlhl60d.c @@ -309,10 +309,8 @@ static int dlh_probe(struct i2c_client *client) ret = devm_request_irq(&client->dev, client->irq, dlh_interrupt, IRQF_TRIGGER_RISING | IRQF_NO_THREAD, st->info->name, indio_dev); - if (ret) { - dev_err(&client->dev, "failed to allocate threaded irq"); + if (ret) return ret; - } st->use_interrupt = true; init_completion(&st->completion); @@ -340,8 +338,8 @@ static const struct of_device_id dlh_of_match[] = { MODULE_DEVICE_TABLE(of, dlh_of_match); static const struct i2c_device_id dlh_id[] = { - { "dlhl60d", (kernel_ulong_t)&dlhl60d_info }, - { "dlhl60g", (kernel_ulong_t)&dlhl60g_info }, + { .name = "dlhl60d", .driver_data = (kernel_ulong_t)&dlhl60d_info }, + { .name = "dlhl60g", .driver_data = (kernel_ulong_t)&dlhl60g_info }, { } }; MODULE_DEVICE_TABLE(i2c, dlh_id); diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c index 8edaa4d10a70..45bdb8c7670f 100644 --- a/drivers/iio/pressure/dps310.c +++ b/drivers/iio/pressure/dps310.c @@ -845,7 +845,6 @@ static const struct iio_info dps310_info = { static int dps310_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); struct dps310_data *data; struct iio_dev *iio; int rc; @@ -858,7 +857,7 @@ static int dps310_probe(struct i2c_client *client) data->client = client; mutex_init(&data->lock); - iio->name = id->name; + iio->name = DPS310_DEV_NAME; iio->channels = dps310_channels; iio->num_channels = ARRAY_SIZE(dps310_channels); iio->info = &dps310_info; @@ -887,7 +886,7 @@ static int dps310_probe(struct i2c_client *client) } static const struct i2c_device_id dps310_id[] = { - { DPS310_DEV_NAME }, + { .name = DPS310_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, dps310_id); diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c index 5f1d6abda3e4..e688b0776547 100644 --- a/drivers/iio/pressure/hid-sensor-press.c +++ b/drivers/iio/pressure/hid-sensor-press.c @@ -3,10 +3,10 @@ * HID Sensors Driver * Copyright (c) 2014, Intel Corporation. */ +#include <linux/bitops.h> #include <linux/device.h> #include <linux/platform_device.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/slab.h> #include <linux/hid-sensor-hub.h> #include <linux/iio/iio.h> @@ -53,22 +53,10 @@ static const struct iio_chan_spec press_channels[] = { }; -/* Adjust channel real bits based on report descriptor */ -static void press_adjust_channel_bit_mask(struct iio_chan_spec *channels, - int channel, int size) -{ - channels[channel].scan_type.sign = 's'; - /* Real storage bits will change based on the report desc. */ - channels[channel].scan_type.realbits = size * 8; - /* Maximum size of a sample to capture is u32 */ - channels[channel].scan_type.storagebits = sizeof(u32) * 8; -} - /* Channel read_raw handler */ static int press_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, - long mask) + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { struct press_state *press_state = iio_priv(indio_dev); int report_id = -1; @@ -92,7 +80,7 @@ static int press_read_raw(struct iio_dev *indio_dev, } if (report_id >= 0) { hid_sensor_power_state(&press_state->common_attributes, - true); + true); *val = sensor_hub_input_attr_get_raw_value( press_state->common_attributes.hsdev, HID_USAGE_SENSOR_PRESSURE, address, @@ -100,7 +88,7 @@ static int press_read_raw(struct iio_dev *indio_dev, SENSOR_HUB_SYNC, min < 0); hid_sensor_power_state(&press_state->common_attributes, - false); + false); } else { *val = 0; return -EINVAL; @@ -134,10 +122,8 @@ static int press_read_raw(struct iio_dev *indio_dev, /* Channel write_raw handler */ static int press_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct press_state *press_state = iio_priv(indio_dev); int ret = 0; @@ -165,8 +151,7 @@ static const struct iio_info press_info = { /* Callback handler to send event after all samples are received and captured */ static int press_proc_event(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, - void *priv) + u32 usage_id, void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct press_state *press_state = iio_priv(indio_dev); @@ -186,7 +171,7 @@ static int press_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int press_capture_sample(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, + u32 usage_id, size_t raw_len, char *raw_data, void *priv) { @@ -212,10 +197,10 @@ static int press_capture_sample(struct hid_sensor_hub_device *hsdev, /* Parse report which is specific to an usage id*/ static int press_parse_report(struct platform_device *pdev, - struct hid_sensor_hub_device *hsdev, - struct iio_chan_spec *channels, - unsigned usage_id, - struct press_state *st) + struct hid_sensor_hub_device *hsdev, + struct iio_chan_spec *channels, + u32 usage_id, + struct press_state *st) { int ret; @@ -225,11 +210,14 @@ static int press_parse_report(struct platform_device *pdev, &st->press_attr); if (ret < 0) return ret; - press_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_PRESSURE, - st->press_attr.size); + channels[CHANNEL_SCAN_INDEX_PRESSURE].scan_type = (struct iio_scan_type) { + .format = 's', + .realbits = BYTES_TO_BITS(st->press_attr.size), + .storagebits = BITS_PER_TYPE(u32), + }; dev_dbg(&pdev->dev, "press %x:%x\n", st->press_attr.index, - st->press_attr.report_id); + st->press_attr.report_id); st->scale_precision = hid_sensor_format_scale( HID_USAGE_SENSOR_PRESSURE, @@ -248,8 +236,7 @@ static int hid_press_probe(struct platform_device *pdev) struct iio_dev *indio_dev; struct press_state *press_state; - indio_dev = devm_iio_device_alloc(&pdev->dev, - sizeof(struct press_state)); + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct press_state)); if (!indio_dev) return -ENOMEM; platform_set_drvdata(pdev, indio_dev); @@ -292,32 +279,32 @@ static int hid_press_probe(struct platform_device *pdev) atomic_set(&press_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, - &press_state->common_attributes); + &press_state->common_attributes); if (ret) { dev_err(&pdev->dev, "trigger setup failed\n"); return ret; } - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(&pdev->dev, "device register failed\n"); - goto error_remove_trigger; - } - press_state->callbacks.send_event = press_proc_event; press_state->callbacks.capture_sample = press_capture_sample; press_state->callbacks.pdev = pdev; ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_PRESSURE, - &press_state->callbacks); + &press_state->callbacks); if (ret < 0) { dev_err(&pdev->dev, "callback reg failed\n"); - goto error_iio_unreg; + goto error_remove_trigger; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "device register failed\n"); + goto error_remove_callback; } return ret; -error_iio_unreg: - iio_device_unregister(indio_dev); +error_remove_callback: + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE); error_remove_trigger: hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes); return ret; @@ -330,8 +317,8 @@ static void hid_press_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct press_state *press_state = iio_priv(indio_dev); - sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE); iio_device_unregister(indio_dev); + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE); hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes); } diff --git a/drivers/iio/pressure/hp03.c b/drivers/iio/pressure/hp03.c index cbb4aaf45e2c..424523345060 100644 --- a/drivers/iio/pressure/hp03.c +++ b/drivers/iio/pressure/hp03.c @@ -266,7 +266,7 @@ static int hp03_probe(struct i2c_client *client) } static const struct i2c_device_id hp03_id[] = { - { "hp03" }, + { .name = "hp03" }, { } }; MODULE_DEVICE_TABLE(i2c, hp03_id); diff --git a/drivers/iio/pressure/hp206c.c b/drivers/iio/pressure/hp206c.c index abe10ccb6770..ee34c8908b74 100644 --- a/drivers/iio/pressure/hp206c.c +++ b/drivers/iio/pressure/hp206c.c @@ -11,7 +11,6 @@ */ #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -395,7 +394,7 @@ static int hp206c_probe(struct i2c_client *client) } static const struct i2c_device_id hp206c_id[] = { - {"hp206c"}, + { .name = "hp206c" }, { } }; MODULE_DEVICE_TABLE(i2c, hp206c_id); diff --git a/drivers/iio/pressure/hsc030pa.c b/drivers/iio/pressure/hsc030pa.c index 2d00c0656259..0374d406b401 100644 --- a/drivers/iio/pressure/hsc030pa.c +++ b/drivers/iio/pressure/hsc030pa.c @@ -13,7 +13,6 @@ #include <linux/cleanup.h> #include <linux/init.h> #include <linux/math64.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/printk.h> #include <linux/property.h> @@ -273,7 +272,7 @@ static const struct hsc_range_config hsc_range_config[HSC_VARIANTS_MAX] = { * @data: structure containing instantiated sensor data * Return: true only if both status bits are zero * - * the two MSB from the first transfered byte contain a status code + * The two MSB from the first transferred byte contain a status code * 00 - normal operation, valid data * 01 - device in factory programming mode * 10 - stale data diff --git a/drivers/iio/pressure/hsc030pa_i2c.c b/drivers/iio/pressure/hsc030pa_i2c.c index a34ef4653f34..050cacd9ea6a 100644 --- a/drivers/iio/pressure/hsc030pa_i2c.c +++ b/drivers/iio/pressure/hsc030pa_i2c.c @@ -12,7 +12,6 @@ #include <linux/device.h> #include <linux/errno.h> #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/types.h> @@ -34,8 +33,13 @@ static int hsc_i2c_recv(struct hsc_data *data) msg.buf = data->buffer; ret = i2c_transfer(client->adapter, &msg, 1); + if (ret < 0) + return ret; - return (ret == 2) ? 0 : ret; + if (ret != 1) + return -EIO; + + return 0; } static int hsc_i2c_probe(struct i2c_client *client) @@ -53,7 +57,7 @@ static const struct of_device_id hsc_i2c_match[] = { MODULE_DEVICE_TABLE(of, hsc_i2c_match); static const struct i2c_device_id hsc_i2c_id[] = { - { "hsc030pa" }, + { .name = "hsc030pa" }, { } }; MODULE_DEVICE_TABLE(i2c, hsc_i2c_id); diff --git a/drivers/iio/pressure/hsc030pa_spi.c b/drivers/iio/pressure/hsc030pa_spi.c index 5d331b3b6da8..02021b6f799a 100644 --- a/drivers/iio/pressure/hsc030pa_spi.c +++ b/drivers/iio/pressure/hsc030pa_spi.c @@ -10,7 +10,6 @@ #include <linux/delay.h> #include <linux/device.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/spi/spi.h> #include <linux/stddef.h> @@ -40,7 +39,7 @@ static const struct of_device_id hsc_spi_match[] = { MODULE_DEVICE_TABLE(of, hsc_spi_match); static const struct spi_device_id hsc_spi_id[] = { - { "hsc030pa" }, + { .name = "hsc030pa" }, { } }; MODULE_DEVICE_TABLE(spi, hsc_spi_id); diff --git a/drivers/iio/pressure/icp10100.c b/drivers/iio/pressure/icp10100.c index 3d83d0098a57..82824e3e8db9 100644 --- a/drivers/iio/pressure/icp10100.c +++ b/drivers/iio/pressure/icp10100.c @@ -10,7 +10,6 @@ #include <linux/device.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/pm_runtime.h> #include <linux/crc8.h> @@ -633,7 +632,7 @@ static const struct of_device_id icp10100_of_match[] = { MODULE_DEVICE_TABLE(of, icp10100_of_match); static const struct i2c_device_id icp10100_id[] = { - { "icp10100" }, + { .name = "icp10100" }, { } }; MODULE_DEVICE_TABLE(i2c, icp10100_id); diff --git a/drivers/iio/pressure/mpl115.c b/drivers/iio/pressure/mpl115.c index 830a5065c008..2929ea8e4e01 100644 --- a/drivers/iio/pressure/mpl115.c +++ b/drivers/iio/pressure/mpl115.c @@ -106,18 +106,18 @@ static int mpl115_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_PROCESSED: pm_runtime_get_sync(data->dev); ret = mpl115_comp_pressure(data, val, val2); + pm_runtime_put_autosuspend(data->dev); if (ret < 0) return ret; - pm_runtime_put_autosuspend(data->dev); return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_RAW: pm_runtime_get_sync(data->dev); /* temperature -5.35 C / LSB, 472 LSB is 25 C */ ret = mpl115_read_temp(data); + pm_runtime_put_autosuspend(data->dev); if (ret < 0) return ret; - pm_runtime_put_autosuspend(data->dev); *val = ret >> 6; return IIO_VAL_INT; @@ -203,9 +203,9 @@ int mpl115_probe(struct device *dev, const char *name, if (data->shutdown) { /* Enable runtime PM */ - pm_runtime_get_noresume(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); + ret = pm_runtime_set_active(dev); + if (ret) + return ret; /* * As the device takes 3 ms to come up with a fresh @@ -215,7 +215,10 @@ int mpl115_probe(struct device *dev, const char *name, */ pm_runtime_set_autosuspend_delay(dev, 2000); pm_runtime_use_autosuspend(dev); - pm_runtime_put(dev); + + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; dev_dbg(dev, "low-power mode enabled"); } else diff --git a/drivers/iio/pressure/mpl115_i2c.c b/drivers/iio/pressure/mpl115_i2c.c index 3db9ef4e2770..4a43eba078a8 100644 --- a/drivers/iio/pressure/mpl115_i2c.c +++ b/drivers/iio/pressure/mpl115_i2c.c @@ -45,7 +45,7 @@ static int mpl115_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id mpl115_i2c_id[] = { - { "mpl115" }, + { .name = "mpl115" }, { } }; MODULE_DEVICE_TABLE(i2c, mpl115_i2c_id); diff --git a/drivers/iio/pressure/mpl115_spi.c b/drivers/iio/pressure/mpl115_spi.c index 4e1d24beff94..3cff616e8d2f 100644 --- a/drivers/iio/pressure/mpl115_spi.c +++ b/drivers/iio/pressure/mpl115_spi.c @@ -84,7 +84,7 @@ static int mpl115_spi_probe(struct spi_device *spi) } static const struct spi_device_id mpl115_spi_ids[] = { - { "mpl115", 0 }, + { .name = "mpl115" }, { } }; MODULE_DEVICE_TABLE(spi, mpl115_spi_ids); diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c index aeac1586f12e..f20fa6ad16fe 100644 --- a/drivers/iio/pressure/mpl3115.c +++ b/drivers/iio/pressure/mpl3115.c @@ -783,7 +783,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mpl3115_pm_ops, mpl3115_suspend, mpl3115_resume); static const struct i2c_device_id mpl3115_id[] = { - { "mpl3115" }, + { .name = "mpl3115" }, { } }; MODULE_DEVICE_TABLE(i2c, mpl3115_id); diff --git a/drivers/iio/pressure/mprls0025pa.c b/drivers/iio/pressure/mprls0025pa.c index e8c495f336ff..c21f0a050660 100644 --- a/drivers/iio/pressure/mprls0025pa.c +++ b/drivers/iio/pressure/mprls0025pa.c @@ -20,7 +20,6 @@ #include <linux/interrupt.h> #include <linux/jiffies.h> #include <linux/math64.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/property.h> #include <linux/string.h> diff --git a/drivers/iio/pressure/mprls0025pa_i2c.c b/drivers/iio/pressure/mprls0025pa_i2c.c index 0fe8cfe0d7e7..06907b64a596 100644 --- a/drivers/iio/pressure/mprls0025pa_i2c.c +++ b/drivers/iio/pressure/mprls0025pa_i2c.c @@ -11,7 +11,6 @@ #include <linux/device.h> #include <linux/errno.h> #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/types.h> @@ -69,7 +68,7 @@ static const struct of_device_id mpr_i2c_match[] = { MODULE_DEVICE_TABLE(of, mpr_i2c_match); static const struct i2c_device_id mpr_i2c_id[] = { - { "mprls0025pa" }, + { .name = "mprls0025pa" }, { } }; MODULE_DEVICE_TABLE(i2c, mpr_i2c_id); diff --git a/drivers/iio/pressure/mprls0025pa_spi.c b/drivers/iio/pressure/mprls0025pa_spi.c index 8c8c726f703f..6270370383c3 100644 --- a/drivers/iio/pressure/mprls0025pa_spi.c +++ b/drivers/iio/pressure/mprls0025pa_spi.c @@ -11,7 +11,6 @@ #include <linux/array_size.h> #include <linux/device.h> #include <linux/errno.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/spi/spi.h> #include <linux/stddef.h> @@ -60,7 +59,7 @@ static const struct of_device_id mpr_spi_match[] = { MODULE_DEVICE_TABLE(of, mpr_spi_match); static const struct spi_device_id mpr_spi_id[] = { - { "mprls0025pa" }, + { .name = "mprls0025pa" }, { } }; MODULE_DEVICE_TABLE(spi, mpr_spi_id); diff --git a/drivers/iio/pressure/ms5611_i2c.c b/drivers/iio/pressure/ms5611_i2c.c index 1c041b9085fb..c57ad473b21f 100644 --- a/drivers/iio/pressure/ms5611_i2c.c +++ b/drivers/iio/pressure/ms5611_i2c.c @@ -14,7 +14,6 @@ #include <linux/delay.h> #include <linux/i2c.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/unaligned.h> @@ -113,8 +112,8 @@ static const struct of_device_id ms5611_i2c_matches[] = { MODULE_DEVICE_TABLE(of, ms5611_i2c_matches); static const struct i2c_device_id ms5611_id[] = { - { "ms5611", MS5611 }, - { "ms5607", MS5607 }, + { .name = "ms5611", .driver_data = MS5611 }, + { .name = "ms5607", .driver_data = MS5607 }, { } }; MODULE_DEVICE_TABLE(i2c, ms5611_id); diff --git a/drivers/iio/pressure/ms5611_spi.c b/drivers/iio/pressure/ms5611_spi.c index 25c7bd2d8fdf..7133e6744e3f 100644 --- a/drivers/iio/pressure/ms5611_spi.c +++ b/drivers/iio/pressure/ms5611_spi.c @@ -9,7 +9,6 @@ #include <linux/delay.h> #include <linux/module.h> #include <linux/spi/spi.h> -#include <linux/mod_devicetable.h> #include <linux/unaligned.h> @@ -114,8 +113,8 @@ static const struct of_device_id ms5611_spi_matches[] = { MODULE_DEVICE_TABLE(of, ms5611_spi_matches); static const struct spi_device_id ms5611_id[] = { - { "ms5611", MS5611 }, - { "ms5607", MS5607 }, + { .name = "ms5611", .driver_data = MS5611 }, + { .name = "ms5607", .driver_data = MS5607 }, { } }; MODULE_DEVICE_TABLE(spi, ms5611_id); diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c index 59705a666979..be8921644558 100644 --- a/drivers/iio/pressure/ms5637.c +++ b/drivers/iio/pressure/ms5637.c @@ -22,7 +22,6 @@ #include <linux/kernel.h> #include <linux/stat.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -215,10 +214,10 @@ static const struct ms_tp_data ms8607_data = { }; static const struct i2c_device_id ms5637_id[] = { - {"ms5637", (kernel_ulong_t)&ms5637_data }, - {"ms5805", (kernel_ulong_t)&ms5805_data }, - {"ms5837", (kernel_ulong_t)&ms5837_data }, - {"ms8607-temppressure", (kernel_ulong_t)&ms8607_data }, + { .name = "ms5637", .driver_data = (kernel_ulong_t)&ms5637_data }, + { .name = "ms5805", .driver_data = (kernel_ulong_t)&ms5805_data }, + { .name = "ms5837", .driver_data = (kernel_ulong_t)&ms5837_data }, + { .name = "ms8607-temppressure", .driver_data = (kernel_ulong_t)&ms8607_data }, { } }; MODULE_DEVICE_TABLE(i2c, ms5637_id); diff --git a/drivers/iio/pressure/rohm-bm1390.c b/drivers/iio/pressure/rohm-bm1390.c index dac27fd359ad..57941fb4a535 100644 --- a/drivers/iio/pressure/rohm-bm1390.c +++ b/drivers/iio/pressure/rohm-bm1390.c @@ -440,7 +440,7 @@ static int bm1390_fifo_flush(struct iio_dev *idev, unsigned int samples) * the timestamps. If we are ran from IRQ, then the * IRQF_ONESHOT has us covered - but if we are ran by the * user-space read we need to disable the IRQ to be on a safe - * side. We do this usng synchronous disable so that if the + * side. We do this using synchronous disable so that if the * IRQ thread is being ran on other CPU we wait for it to be * finished. */ @@ -621,17 +621,15 @@ static const struct iio_buffer_setup_ops bm1390_buffer_ops = { .predisable = bm1390_buffer_predisable, }; -static irqreturn_t bm1390_trigger_handler(int irq, void *p) +static bool bm1390_handle_trigger(struct iio_dev *idev) { - struct iio_poll_func *pf = p; - struct iio_dev *idev = pf->indio_dev; struct bm1390_data *data = iio_priv(idev); int ret, status; /* DRDY is acked by reading status reg */ ret = regmap_read(data->regmap, BM1390_REG_STATUS, &status); if (ret || !status) - return IRQ_NONE; + return false; dev_dbg(data->dev, "DRDY trig status 0x%x\n", status); @@ -639,7 +637,7 @@ static irqreturn_t bm1390_trigger_handler(int irq, void *p) ret = bm1390_pressure_read(data, &data->buf.pressure); if (ret) { dev_warn(data->dev, "sample read failed %d\n", ret); - return IRQ_NONE; + return false; } } @@ -648,15 +646,26 @@ static irqreturn_t bm1390_trigger_handler(int irq, void *p) &data->buf.temp, sizeof(data->buf.temp)); if (ret) { dev_warn(data->dev, "temp read failed %d\n", ret); - return IRQ_HANDLED; + return true; } } iio_push_to_buffers_with_ts(idev, &data->buf, sizeof(data->buf), data->timestamp); + + return true; +} + +static irqreturn_t bm1390_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *idev = pf->indio_dev; + bool result; + + result = bm1390_handle_trigger(idev); iio_trigger_notify_done(idev->trig); - return IRQ_HANDLED; + return IRQ_RETVAL(result); } /* Get timestamps and wake the thread if we need to read data */ @@ -796,7 +805,7 @@ static int bm1390_setup_trigger(struct bm1390_data *data, struct iio_dev *idev, &bm1390_irq_thread_handler, IRQF_ONESHOT, name, idev); if (ret) - return dev_err_probe(data->dev, ret, "Could not request IRQ\n"); + return ret; ret = devm_iio_trigger_register(data->dev, itrig); @@ -888,7 +897,7 @@ static const struct of_device_id bm1390_of_match[] = { MODULE_DEVICE_TABLE(of, bm1390_of_match); static const struct i2c_device_id bm1390_id[] = { - { "bm1390glv-z", }, + { .name = "bm1390glv-z" }, { } }; MODULE_DEVICE_TABLE(i2c, bm1390_id); diff --git a/drivers/iio/pressure/sdp500.c b/drivers/iio/pressure/sdp500.c index 9828c73c4855..153f335ebf1e 100644 --- a/drivers/iio/pressure/sdp500.c +++ b/drivers/iio/pressure/sdp500.c @@ -8,7 +8,6 @@ #include <linux/i2c.h> #include <linux/crc8.h> #include <linux/iio/iio.h> -#include <linux/mod_devicetable.h> #include <linux/regulator/consumer.h> #include <linux/unaligned.h> @@ -130,7 +129,7 @@ static int sdp500_probe(struct i2c_client *client) } static const struct i2c_device_id sdp500_id[] = { - { "sdp500" }, + { .name = "sdp500" }, { } }; MODULE_DEVICE_TABLE(i2c, sdp500_id); diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c index 0f50bac1fb4d..2b7c84b7e6b4 100644 --- a/drivers/iio/pressure/st_pressure_i2c.c +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -9,7 +9,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/iio/iio.h> @@ -61,14 +60,14 @@ static const struct acpi_device_id st_press_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, st_press_acpi_match); static const struct i2c_device_id st_press_id_table[] = { - { LPS001WP_PRESS_DEV_NAME, LPS001WP }, - { LPS25H_PRESS_DEV_NAME, LPS25H }, - { LPS331AP_PRESS_DEV_NAME, LPS331AP }, - { LPS22HB_PRESS_DEV_NAME, LPS22HB }, - { LPS33HW_PRESS_DEV_NAME, LPS33HW }, - { LPS35HW_PRESS_DEV_NAME, LPS35HW }, - { LPS22HH_PRESS_DEV_NAME, LPS22HH }, - { LPS22DF_PRESS_DEV_NAME, LPS22DF }, + { .name = LPS001WP_PRESS_DEV_NAME, .driver_data = LPS001WP }, + { .name = LPS25H_PRESS_DEV_NAME, .driver_data = LPS25H }, + { .name = LPS331AP_PRESS_DEV_NAME, .driver_data = LPS331AP }, + { .name = LPS22HB_PRESS_DEV_NAME, .driver_data = LPS22HB }, + { .name = LPS33HW_PRESS_DEV_NAME, .driver_data = LPS33HW }, + { .name = LPS35HW_PRESS_DEV_NAME, .driver_data = LPS35HW }, + { .name = LPS22HH_PRESS_DEV_NAME, .driver_data = LPS22HH }, + { .name = LPS22DF_PRESS_DEV_NAME, .driver_data = LPS22DF }, { } }; MODULE_DEVICE_TABLE(i2c, st_press_id_table); diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c index 39827e6841ca..8add0c392c6a 100644 --- a/drivers/iio/pressure/st_pressure_spi.c +++ b/drivers/iio/pressure/st_pressure_spi.c @@ -9,7 +9,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/spi/spi.h> #include <linux/iio/iio.h> @@ -94,18 +93,18 @@ static int st_press_spi_probe(struct spi_device *spi) } static const struct spi_device_id st_press_id_table[] = { - { LPS001WP_PRESS_DEV_NAME }, - { LPS25H_PRESS_DEV_NAME }, - { LPS331AP_PRESS_DEV_NAME }, - { LPS22HB_PRESS_DEV_NAME }, - { LPS33HW_PRESS_DEV_NAME }, - { LPS35HW_PRESS_DEV_NAME }, - { LPS22HH_PRESS_DEV_NAME }, - { LPS22DF_PRESS_DEV_NAME }, - { "lps001wp-press" }, - { "lps25h-press", }, - { "lps331ap-press" }, - { "lps22hb-press" }, + { .name = LPS001WP_PRESS_DEV_NAME }, + { .name = LPS25H_PRESS_DEV_NAME }, + { .name = LPS331AP_PRESS_DEV_NAME }, + { .name = LPS22HB_PRESS_DEV_NAME }, + { .name = LPS33HW_PRESS_DEV_NAME }, + { .name = LPS35HW_PRESS_DEV_NAME }, + { .name = LPS22HH_PRESS_DEV_NAME }, + { .name = LPS22DF_PRESS_DEV_NAME }, + { .name = "lps001wp-press" }, + { .name = "lps25h-press" }, + { .name = "lps331ap-press" }, + { .name = "lps22hb-press" }, { } }; MODULE_DEVICE_TABLE(spi, st_press_id_table); diff --git a/drivers/iio/pressure/t5403.c b/drivers/iio/pressure/t5403.c index c7cb0fd816d3..ab30f6745181 100644 --- a/drivers/iio/pressure/t5403.c +++ b/drivers/iio/pressure/t5403.c @@ -251,7 +251,7 @@ static int t5403_probe(struct i2c_client *client) } static const struct i2c_device_id t5403_id[] = { - { "t5403" }, + { .name = "t5403" }, { } }; MODULE_DEVICE_TABLE(i2c, t5403_id); diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c index 4923a558a26a..b38493ff3b8b 100644 --- a/drivers/iio/pressure/zpa2326.c +++ b/drivers/iio/pressure/zpa2326.c @@ -840,7 +840,7 @@ static irqreturn_t zpa2326_handle_threaded_irq(int irq, void *data) complete: /* - * Wake up direct or externaly triggered buffer mode waiters: see + * Wake up direct or externally triggered buffer mode waiters: see * zpa2326_sample_oneshot() and zpa2326_trigger_handler(). */ complete(&priv->data_ready); @@ -911,11 +911,8 @@ static int zpa2326_init_managed_irq(struct device *parent, zpa2326_handle_threaded_irq, IRQF_TRIGGER_RISING | IRQF_ONESHOT, dev_name(parent), indio_dev); - if (err) { - dev_err(parent, "failed to request interrupt %d (%d)", irq, - err); + if (err) return err; - } dev_info(parent, "using interrupt %d", irq); diff --git a/drivers/iio/pressure/zpa2326_i2c.c b/drivers/iio/pressure/zpa2326_i2c.c index a6034bf05d97..e04a61c2388b 100644 --- a/drivers/iio/pressure/zpa2326_i2c.c +++ b/drivers/iio/pressure/zpa2326_i2c.c @@ -10,7 +10,6 @@ #include <linux/module.h> #include <linux/regmap.h> #include <linux/i2c.h> -#include <linux/mod_devicetable.h> #include "zpa2326.h" /* @@ -58,7 +57,7 @@ static void zpa2326_remove_i2c(struct i2c_client *client) } static const struct i2c_device_id zpa2326_i2c_ids[] = { - { "zpa2326" }, + { .name = "zpa2326" }, { } }; MODULE_DEVICE_TABLE(i2c, zpa2326_i2c_ids); diff --git a/drivers/iio/pressure/zpa2326_spi.c b/drivers/iio/pressure/zpa2326_spi.c index af756e2b0f31..dfbb74a58dc0 100644 --- a/drivers/iio/pressure/zpa2326_spi.c +++ b/drivers/iio/pressure/zpa2326_spi.c @@ -10,7 +10,6 @@ #include <linux/module.h> #include <linux/regmap.h> #include <linux/spi/spi.h> -#include <linux/mod_devicetable.h> #include "zpa2326.h" /* @@ -61,7 +60,7 @@ static void zpa2326_remove_spi(struct spi_device *spi) } static const struct spi_device_id zpa2326_spi_ids[] = { - { "zpa2326", 0 }, + { .name = "zpa2326" }, { } }; MODULE_DEVICE_TABLE(spi, zpa2326_spi_ids); diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig index 6070974c2c85..bb77fad2a1b3 100644 --- a/drivers/iio/proximity/Kconfig +++ b/drivers/iio/proximity/Kconfig @@ -244,6 +244,21 @@ config VL53L0X_I2C To compile this driver as a module, choose M here: the module will be called vl53l0x-i2c. +config VL53L1X_I2C + tristate "STMicroelectronics VL53L1X ToF ranger sensor (I2C)" + depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select REGMAP_I2C + select RESET_CONTROLLER + help + Say Y here to build a driver for STMicroelectronics VL53L1X + ToF ranger sensors with i2c interface. + This driver can be used to measure the distance of objects. + + To compile this driver as a module, choose M here: the + module will be called vl53l1x-i2c. + config AW96103 tristate "AW96103/AW96105 Awinic proximity sensor" select REGMAP_I2C diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile index 152034d38c49..4352833dd8a4 100644 --- a/drivers/iio/proximity/Makefile +++ b/drivers/iio/proximity/Makefile @@ -23,5 +23,6 @@ obj-$(CONFIG_SX_COMMON) += sx_common.o obj-$(CONFIG_SX9500) += sx9500.o obj-$(CONFIG_VCNL3020) += vcnl3020.o obj-$(CONFIG_VL53L0X_I2C) += vl53l0x-i2c.o +obj-$(CONFIG_VL53L1X_I2C) += vl53l1x-i2c.o obj-$(CONFIG_AW96103) += aw96103.o diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index f1018b14aecf..d7f43c3af165 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -7,7 +7,6 @@ */ #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/delay.h> @@ -429,10 +428,8 @@ static int as3935_probe(struct spi_device *spi) dev_name(dev), indio_dev); - if (ret) { - dev_err(dev, "unable to request irq\n"); + if (ret) return ret; - } ret = devm_iio_device_register(dev, indio_dev); if (ret < 0) { @@ -449,7 +446,7 @@ static const struct of_device_id as3935_of_match[] = { MODULE_DEVICE_TABLE(of, as3935_of_match); static const struct spi_device_id as3935_id[] = { - {"as3935", 0}, + { .name = "as3935" }, { } }; MODULE_DEVICE_TABLE(spi, as3935_id); diff --git a/drivers/iio/proximity/aw96103.c b/drivers/iio/proximity/aw96103.c index 3472a2c36e44..8fbb755dcae0 100644 --- a/drivers/iio/proximity/aw96103.c +++ b/drivers/iio/proximity/aw96103.c @@ -825,8 +825,8 @@ static const struct of_device_id aw96103_dt_match[] = { MODULE_DEVICE_TABLE(of, aw96103_dt_match); static const struct i2c_device_id aw96103_i2c_id[] = { - { "aw96103", (kernel_ulong_t)&aw_chip_info_tbl[AW96103_VAL] }, - { "aw96105", (kernel_ulong_t)&aw_chip_info_tbl[AW96105_VAL] }, + { .name = "aw96103", .driver_data = (kernel_ulong_t)&aw_chip_info_tbl[AW96103_VAL] }, + { .name = "aw96105", .driver_data = (kernel_ulong_t)&aw_chip_info_tbl[AW96105_VAL] }, { } }; MODULE_DEVICE_TABLE(i2c, aw96103_i2c_id); diff --git a/drivers/iio/proximity/cros_ec_mkbp_proximity.c b/drivers/iio/proximity/cros_ec_mkbp_proximity.c index 1f9de7066ebf..63f9b45bef7b 100644 --- a/drivers/iio/proximity/cros_ec_mkbp_proximity.c +++ b/drivers/iio/proximity/cros_ec_mkbp_proximity.c @@ -6,7 +6,6 @@ */ #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/notifier.h> diff --git a/drivers/iio/proximity/d3323aa.c b/drivers/iio/proximity/d3323aa.c index 30821f583454..1f43c1fed342 100644 --- a/drivers/iio/proximity/d3323aa.c +++ b/drivers/iio/proximity/d3323aa.c @@ -13,7 +13,6 @@ #include <linux/gpio/consumer.h> #include <linux/interrupt.h> #include <linux/jiffies.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/platform_device.h> @@ -772,7 +771,7 @@ static int d3323aa_probe(struct platform_device *pdev) IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, dev_name(dev), indio_dev); if (ret) - return dev_err_probe(dev, ret, "Could not request IRQ\n"); + return ret; ret = d3323aa_setup(indio_dev, D3323AA_LP_FILTER_FREQ_DEFAULT_IDX, D3323AA_FILTER_GAIN_DEFAULT_IDX, diff --git a/drivers/iio/proximity/hx9023s.c b/drivers/iio/proximity/hx9023s.c index 17e00ee2b6f8..0199a6351a46 100644 --- a/drivers/iio/proximity/hx9023s.c +++ b/drivers/iio/proximity/hx9023s.c @@ -19,7 +19,6 @@ #include <linux/interrupt.h> #include <linux/irqreturn.h> #include <linux/math64.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/pm.h> @@ -1088,6 +1087,7 @@ static int hx9023s_probe(struct i2c_client *client) struct device *dev = &client->dev; struct iio_dev *indio_dev; struct hx9023s_data *data; + const char *fw_name; int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); @@ -1125,7 +1125,9 @@ static int hx9023s_probe(struct i2c_client *client) if (ret) return dev_err_probe(dev, ret, "channel config failed\n"); - ret = request_firmware_nowait(THIS_MODULE, true, "hx9023s.bin", dev, + fw_name = "hx9023s.bin"; + device_property_read_string(dev, "firmware-name", &fw_name); + ret = request_firmware_nowait(THIS_MODULE, true, fw_name, dev, GFP_KERNEL, data, hx9023s_cfg_update); if (ret) return dev_err_probe(dev, ret, "reg config failed\n"); @@ -1137,7 +1139,7 @@ static int hx9023s_probe(struct i2c_client *client) IRQF_ONESHOT, "hx9023s_event", indio_dev); if (ret) - return dev_err_probe(dev, ret, "irq request failed\n"); + return ret; data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, @@ -1196,7 +1198,7 @@ static const struct of_device_id hx9023s_of_match[] = { MODULE_DEVICE_TABLE(of, hx9023s_of_match); static const struct i2c_device_id hx9023s_id[] = { - { "hx9023s" }, + { .name = "hx9023s" }, { } }; MODULE_DEVICE_TABLE(i2c, hx9023s_id); diff --git a/drivers/iio/proximity/irsd200.c b/drivers/iio/proximity/irsd200.c index 65af31d43453..b3db7f3a49f6 100644 --- a/drivers/iio/proximity/irsd200.c +++ b/drivers/iio/proximity/irsd200.c @@ -910,7 +910,7 @@ static int irsd200_probe(struct i2c_client *client) IRQF_TRIGGER_RISING | IRQF_ONESHOT, NULL, indio_dev); if (ret) - return dev_err_probe(data->dev, ret, "Could not request irq\n"); + return ret; trigger = devm_iio_trigger_alloc(data->dev, "%s-dev%d", indio_dev->name, iio_device_id(indio_dev)); diff --git a/drivers/iio/proximity/isl29501.c b/drivers/iio/proximity/isl29501.c index f69db6f2f380..95fb7238f678 100644 --- a/drivers/iio/proximity/isl29501.c +++ b/drivers/iio/proximity/isl29501.c @@ -12,7 +12,6 @@ #include <linux/module.h> #include <linux/i2c.h> #include <linux/err.h> -#include <linux/mod_devicetable.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -995,7 +994,7 @@ static int isl29501_probe(struct i2c_client *client) } static const struct i2c_device_id isl29501_id[] = { - { "isl29501" }, + { .name = "isl29501" }, { } }; diff --git a/drivers/iio/proximity/mb1232.c b/drivers/iio/proximity/mb1232.c index 34b49c54e68b..accfc296e1f0 100644 --- a/drivers/iio/proximity/mb1232.c +++ b/drivers/iio/proximity/mb1232.c @@ -14,7 +14,6 @@ #include <linux/err.h> #include <linux/i2c.h> #include <linux/delay.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/property.h> @@ -214,10 +213,8 @@ static int mb1232_probe(struct i2c_client *client) if (data->irqnr > 0) { ret = devm_request_irq(dev, data->irqnr, mb1232_handle_irq, IRQF_TRIGGER_FALLING, id->name, indio_dev); - if (ret < 0) { - dev_err(dev, "request_irq: %d\n", ret); + if (ret) return ret; - } } ret = devm_iio_triggered_buffer_setup(dev, indio_dev, @@ -244,13 +241,13 @@ static const struct of_device_id of_mb1232_match[] = { MODULE_DEVICE_TABLE(of, of_mb1232_match); static const struct i2c_device_id mb1232_id[] = { - { "maxbotix-mb1202", }, - { "maxbotix-mb1212", }, - { "maxbotix-mb1222", }, - { "maxbotix-mb1232", }, - { "maxbotix-mb1242", }, - { "maxbotix-mb7040", }, - { "maxbotix-mb7137", }, + { .name = "maxbotix-mb1202" }, + { .name = "maxbotix-mb1212" }, + { .name = "maxbotix-mb1222" }, + { .name = "maxbotix-mb1232" }, + { .name = "maxbotix-mb1242" }, + { .name = "maxbotix-mb7040" }, + { .name = "maxbotix-mb7137" }, { } }; MODULE_DEVICE_TABLE(i2c, mb1232_id); diff --git a/drivers/iio/proximity/ping.c b/drivers/iio/proximity/ping.c index e3487094d7be..1e646b858468 100644 --- a/drivers/iio/proximity/ping.c +++ b/drivers/iio/proximity/ping.c @@ -29,7 +29,6 @@ #include <linux/err.h> #include <linux/gpio/consumer.h> #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/property.h> diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c index 21336b8f122a..400477b4c740 100644 --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c @@ -13,7 +13,6 @@ #include <linux/i2c.h> #include <linux/delay.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/pm_runtime.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -319,8 +318,8 @@ static void lidar_remove(struct i2c_client *client) } static const struct i2c_device_id lidar_id[] = { - { "lidar-lite-v2" }, - { "lidar-lite-v3" }, + { .name = "lidar-lite-v2" }, + { .name = "lidar-lite-v3" }, { } }; MODULE_DEVICE_TABLE(i2c, lidar_id); diff --git a/drivers/iio/proximity/rfd77402.c b/drivers/iio/proximity/rfd77402.c index 6afdbfca3e5a..db1e94fc5658 100644 --- a/drivers/iio/proximity/rfd77402.c +++ b/drivers/iio/proximity/rfd77402.c @@ -173,10 +173,8 @@ static int rfd77402_wait_for_result(struct rfd77402_data *data) struct i2c_client *client = data->client; int val, ret; - if (data->irq_en) { - reinit_completion(&data->completion); + if (data->irq_en) return rfd77402_wait_for_irq(data); - } /* * As per RFD77402 datasheet section '3.1.1 Single Measure', the @@ -204,6 +202,9 @@ static int rfd77402_measure(struct rfd77402_data *data) if (ret < 0) return ret; + if (data->irq_en) + reinit_completion(&data->completion); + ret = i2c_smbus_write_byte_data(client, RFD77402_CMD_R, RFD77402_CMD_SINGLE | RFD77402_CMD_VALID); @@ -432,7 +433,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(rfd77402_pm_ops, rfd77402_suspend, rfd77402_resume); static const struct i2c_device_id rfd77402_id[] = { - { "rfd77402" }, + { .name = "rfd77402" }, { } }; MODULE_DEVICE_TABLE(i2c, rfd77402_id); diff --git a/drivers/iio/proximity/srf04.c b/drivers/iio/proximity/srf04.c index e97f9a20ac7a..4e042214df29 100644 --- a/drivers/iio/proximity/srf04.c +++ b/drivers/iio/proximity/srf04.c @@ -37,7 +37,6 @@ #include <linux/err.h> #include <linux/gpio/consumer.h> #include <linux/kernel.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/property.h> @@ -304,10 +303,8 @@ static int srf04_probe(struct platform_device *pdev) ret = devm_request_irq(dev, data->irqnr, srf04_handle_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, pdev->name, indio_dev); - if (ret < 0) { - dev_err(data->dev, "request_irq: %d\n", ret); + if (ret) return ret; - } platform_set_drvdata(pdev, indio_dev); @@ -331,6 +328,7 @@ static int srf04_probe(struct platform_device *pdev) if (ret) { dev_err(data->dev, "pm_runtime_set_active: %d\n", ret); iio_device_unregister(indio_dev); + return ret; } pm_runtime_enable(data->dev); diff --git a/drivers/iio/proximity/srf08.c b/drivers/iio/proximity/srf08.c index d7e4cc48cfbf..35eb3fd7e700 100644 --- a/drivers/iio/proximity/srf08.c +++ b/drivers/iio/proximity/srf08.c @@ -226,7 +226,7 @@ static int srf08_read_raw(struct iio_dev *indio_dev, static ssize_t srf08_show_range_mm_available(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "[0.043 0.043 11.008]\n"); + return sysfs_emit(buf, "[0.043 0.043 11.008]\n"); } static IIO_DEVICE_ATTR(sensor_max_range_available, S_IRUGO, @@ -238,8 +238,8 @@ static ssize_t srf08_show_range_mm(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct srf08_data *data = iio_priv(indio_dev); - return sprintf(buf, "%d.%03d\n", data->range_mm / 1000, - data->range_mm % 1000); + return sysfs_emit(buf, "%d.%03d\n", + data->range_mm / 1000, data->range_mm % 1000); } /* @@ -316,10 +316,10 @@ static ssize_t srf08_show_sensitivity_available(struct device *dev, for (i = 0; i < data->chip_info->num_sensitivity_avail; i++) if (data->chip_info->sensitivity_avail[i]) - len += sprintf(buf + len, "%d ", - data->chip_info->sensitivity_avail[i]); + len += sysfs_emit_at(buf, len, "%d ", + data->chip_info->sensitivity_avail[i]); - len += sprintf(buf + len, "\n"); + len += sysfs_emit_at(buf, len, "\n"); return len; } @@ -332,11 +332,8 @@ static ssize_t srf08_show_sensitivity(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct srf08_data *data = iio_priv(indio_dev); - int len; - len = sprintf(buf, "%d\n", data->sensitivity); - - return len; + return sysfs_emit(buf, "%d\n", data->sensitivity); } static ssize_t srf08_write_sensitivity(struct srf08_data *data, @@ -533,9 +530,9 @@ static const struct of_device_id of_srf08_match[] = { MODULE_DEVICE_TABLE(of, of_srf08_match); static const struct i2c_device_id srf08_id[] = { - { "srf02", SRF02 }, - { "srf08", SRF08 }, - { "srf10", SRF10 }, + { .name = "srf02", .driver_data = SRF02 }, + { .name = "srf08", .driver_data = SRF08 }, + { .name = "srf10", .driver_data = SRF10 }, { } }; MODULE_DEVICE_TABLE(i2c, srf08_id); diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c index fb02eac78ed4..79ba46d8a0aa 100644 --- a/drivers/iio/proximity/sx9310.c +++ b/drivers/iio/proximity/sx9310.c @@ -16,7 +16,6 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/log2.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/pm.h> #include <linux/property.h> @@ -1007,8 +1006,8 @@ static const struct of_device_id sx9310_of_match[] = { MODULE_DEVICE_TABLE(of, sx9310_of_match); static const struct i2c_device_id sx9310_id[] = { - { "sx9310", (kernel_ulong_t)&sx9310_info }, - { "sx9311", (kernel_ulong_t)&sx9311_info }, + { .name = "sx9310", .driver_data = (kernel_ulong_t)&sx9310_info }, + { .name = "sx9311", .driver_data = (kernel_ulong_t)&sx9311_info }, { } }; MODULE_DEVICE_TABLE(i2c, sx9310_id); diff --git a/drivers/iio/proximity/sx9324.c b/drivers/iio/proximity/sx9324.c index c7b2d03c23bc..13b4ef2896e3 100644 --- a/drivers/iio/proximity/sx9324.c +++ b/drivers/iio/proximity/sx9324.c @@ -15,7 +15,6 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/log2.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/pm.h> #include <linux/property.h> @@ -821,7 +820,7 @@ static const struct sx_common_reg_default sx9324_default_regs[] = { { SX9324_REG_ADV_CTRL10, 0x00, "adv_ctrl10" }, { SX9324_REG_ADV_CTRL11, 0x00, "adv_ctrl11" }, { SX9324_REG_ADV_CTRL12, 0x00, "adv_ctrl12" }, - /* TODO(gwendal): SAR currenly disabled */ + /* TODO(gwendal): SAR currently disabled */ { SX9324_REG_ADV_CTRL13, 0x00, "adv_ctrl13" }, { SX9324_REG_ADV_CTRL14, 0x00, "adv_ctrl14" }, { SX9324_REG_ADV_CTRL15, 0x00, "adv_ctrl15" }, @@ -1123,19 +1122,19 @@ static int sx9324_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(sx9324_pm_ops, sx9324_suspend, sx9324_resume); static const struct acpi_device_id sx9324_acpi_match[] = { - { "STH9324", SX9324_WHOAMI_VALUE }, + { .id = "STH9324" }, { } }; MODULE_DEVICE_TABLE(acpi, sx9324_acpi_match); static const struct of_device_id sx9324_of_match[] = { - { .compatible = "semtech,sx9324", (void *)SX9324_WHOAMI_VALUE }, + { .compatible = "semtech,sx9324" }, { } }; MODULE_DEVICE_TABLE(of, sx9324_of_match); static const struct i2c_device_id sx9324_id[] = { - { "sx9324", SX9324_WHOAMI_VALUE }, + { .name = "sx9324" }, { } }; MODULE_DEVICE_TABLE(i2c, sx9324_id); diff --git a/drivers/iio/proximity/sx9360.c b/drivers/iio/proximity/sx9360.c index 4448988d4e7e..ed83d809ecf5 100644 --- a/drivers/iio/proximity/sx9360.c +++ b/drivers/iio/proximity/sx9360.c @@ -14,7 +14,6 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/log2.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/pm.h> #include <linux/property.h> @@ -832,20 +831,20 @@ static int sx9360_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(sx9360_pm_ops, sx9360_suspend, sx9360_resume); static const struct acpi_device_id sx9360_acpi_match[] = { - { "STH9360", SX9360_WHOAMI_VALUE }, - { "SAMM0208", SX9360_WHOAMI_VALUE }, + { .id = "STH9360" }, + { .id = "SAMM0208" }, { } }; MODULE_DEVICE_TABLE(acpi, sx9360_acpi_match); static const struct of_device_id sx9360_of_match[] = { - { .compatible = "semtech,sx9360", (void *)SX9360_WHOAMI_VALUE }, + { .compatible = "semtech,sx9360" }, { } }; MODULE_DEVICE_TABLE(of, sx9360_of_match); static const struct i2c_device_id sx9360_id[] = { - {"sx9360", SX9360_WHOAMI_VALUE }, + { .name = "sx9360" }, { } }; MODULE_DEVICE_TABLE(i2c, sx9360_id); diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index 6c67bae7488c..dadce9b44227 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -1025,7 +1025,7 @@ static const struct of_device_id sx9500_of_match[] = { MODULE_DEVICE_TABLE(of, sx9500_of_match); static const struct i2c_device_id sx9500_id[] = { - { "sx9500" }, + { .name = "sx9500" }, { } }; MODULE_DEVICE_TABLE(i2c, sx9500_id); diff --git a/drivers/iio/proximity/sx_common.c b/drivers/iio/proximity/sx_common.c index 59b35e40739b..4d4937395d9a 100644 --- a/drivers/iio/proximity/sx_common.c +++ b/drivers/iio/proximity/sx_common.c @@ -517,7 +517,7 @@ int sx_common_probe(struct i2c_client *client, IRQF_ONESHOT, "sx_event", indio_dev); if (ret) - return dev_err_probe(dev, ret, "No IRQ\n"); + return ret; data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, diff --git a/drivers/iio/proximity/vcnl3020.c b/drivers/iio/proximity/vcnl3020.c index 7f417372566a..6b0d7a9038d9 100644 --- a/drivers/iio/proximity/vcnl3020.c +++ b/drivers/iio/proximity/vcnl3020.c @@ -638,12 +638,8 @@ static int vcnl3020_probe(struct i2c_client *client) NULL, vcnl3020_handle_irq_thread, IRQF_ONESHOT, indio_dev->name, indio_dev); - if (rc) { - dev_err(&client->dev, - "Error (%d) irq request failed (%u)\n", rc, - client->irq); + if (rc) return rc; - } } return devm_iio_device_register(&client->dev, indio_dev); diff --git a/drivers/iio/proximity/vl53l0x-i2c.c b/drivers/iio/proximity/vl53l0x-i2c.c index ad3e46d47fa8..9fe14ceb8be7 100644 --- a/drivers/iio/proximity/vl53l0x-i2c.c +++ b/drivers/iio/proximity/vl53l0x-i2c.c @@ -87,15 +87,14 @@ static irqreturn_t vl53l0x_trigger_handler(int irq, void *priv) ret = i2c_smbus_read_i2c_block_data(data->client, VL_REG_RESULT_RANGE_STATUS, sizeof(buffer), buffer); - if (ret < 0) - return ret; - else if (ret != 12) - return -EREMOTEIO; + if (ret != 12) + goto done; scan.chan = get_unaligned_be16(&buffer[10]); iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), iio_get_time_ns(indio_dev)); +done: iio_trigger_notify_done(indio_dev->trig); vl53l0x_clear_irq(data); @@ -128,10 +127,8 @@ static int vl53l0x_configure_irq(struct i2c_client *client, ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, vl53l0x_threaded_irq, irq_flags | IRQF_ONESHOT, indio_dev->name, indio_dev); - if (ret) { - dev_err(&client->dev, "devm_request_irq error: %d\n", ret); + if (ret) return ret; - } ret = i2c_smbus_write_byte_data(data->client, VL_REG_SYSTEM_INTERRUPT_CONFIG_GPIO, @@ -393,7 +390,7 @@ static int vl53l0x_probe(struct i2c_client *client) } static const struct i2c_device_id vl53l0x_id[] = { - { "vl53l0x" }, + { .name = "vl53l0x" }, { } }; MODULE_DEVICE_TABLE(i2c, vl53l0x_id); diff --git a/drivers/iio/proximity/vl53l1x-i2c.c b/drivers/iio/proximity/vl53l1x-i2c.c new file mode 100644 index 000000000000..bce238d1b6de --- /dev/null +++ b/drivers/iio/proximity/vl53l1x-i2c.c @@ -0,0 +1,756 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * Support for ST VL53L1X FlightSense ToF Ranging Sensor on a i2c bus. + * + * Copyright (C) 2026 Siratul Islam <siratul.islam@linux.dev> + * + * Datasheet available at + * <https://www.st.com/resource/en/datasheet/vl53l1x.pdf> + * + * Default 7-bit i2c slave address 0x29. + * + * The VL53L1X requires a firmware configuration blob to be loaded at boot. + * Register values for the default configuration are taken from + * ST's VL53L1X Ultra Lite Driver (STSW-IMG009). + */ + +#include <linux/array_size.h> +#include <linux/bits.h> +#include <linux/bitfield.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/math.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/reset.h> +#include <linux/time.h> +#include <linux/types.h> + +#include <asm/byteorder.h> + +#include <linux/iio/buffer.h> +#include <linux/iio/iio.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#define VL53L1X_REG_SOFT_RESET 0x0000 +#define VL53L1X_REG_VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND 0x0008 +#define VL53L1X_REG_VHV_CONFIG__INIT 0x000B +#define VL53L1X_REG_DEFAULT_CONFIG 0x002D +#define VL53L1X_REG_GPIO_HV_MUX__CTRL 0x0030 +#define VL53L1X_REG_GPIO__TIO_HV_STATUS 0x0031 +#define VL53L1X_REG_SYSTEM__INTERRUPT_CONFIG_GPIO 0x0046 +#define VL53L1X_REG_PHASECAL_CONFIG__TIMEOUT_MACROP 0x004B +#define VL53L1X_REG_RANGE_CONFIG__TIMEOUT_MACROP_A 0x005E +#define VL53L1X_REG_RANGE_CONFIG__VCSEL_PERIOD_A 0x0060 +#define VL53L1X_REG_RANGE_CONFIG__TIMEOUT_MACROP_B 0x0061 +#define VL53L1X_REG_RANGE_CONFIG__VCSEL_PERIOD_B 0x0063 +#define VL53L1X_REG_RANGE_CONFIG__VALID_PHASE_HIGH 0x0069 +#define VL53L1X_REG_SYSTEM__INTERMEASUREMENT_PERIOD 0x006C +#define VL53L1X_REG_SD_CONFIG__WOI_SD0 0x0078 +#define VL53L1X_REG_SD_CONFIG__WOI_SD1 0x0079 +#define VL53L1X_REG_SD_CONFIG__INITIAL_PHASE_SD0 0x007A +#define VL53L1X_REG_SD_CONFIG__INITIAL_PHASE_SD1 0x007B +#define VL53L1X_REG_SYSTEM__INTERRUPT_CLEAR 0x0086 +#define VL53L1X_REG_SYSTEM__MODE_START 0x0087 +#define VL53L1X_REG_RESULT__RANGE_STATUS 0x0089 +#define VL53L1X_REG_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0 0x0096 +#define VL53L1X_REG_RESULT__OSC_CALIBRATE_VAL 0x00DE +#define VL53L1X_REG_FIRMWARE__SYSTEM_STATUS 0x00E5 +#define VL53L1X_REG_IDENTIFICATION__MODEL_ID 0x010F + +#define VL53L1X_MODEL_ID_VAL 0xEACC + +#define VL53L1X_MODE_START_TIMED 0x40 +#define VL53L1X_MODE_START_STOP 0x00 + +#define VL53L1X_INT_NEW_SAMPLE_READY 0x02 + +#define VL53L1X_GPIO_HV_MUX_POLARITY BIT(4) + +#define VL53L1X_VHV_LOOP_BOUND_TWO 0x09 + +#define VL53L1X_RANGE_STATUS_MASK GENMASK(4, 0) +#define VL53L1X_RANGE_STATUS_VALID 9 + +#define VL53L1X_OSC_CALIBRATE_MASK GENMASK(9, 0) + +#define VL53L1X_FIRMWARE__SYSTEM_STATUS_BOOTED BIT(0) +#define VL53L1X_GPIO__TIO_HV_STATUS_DATA_READY BIT(0) + +/* Inter-measurement period uses PLL divider with 1.075 oscillator correction */ +static const struct u32_fract vl53l1x_osc_correction = { + .numerator = 1075, + .denominator = 1000, +}; + +enum vl53l1x_distance_mode { + VL53L1X_SHORT, + VL53L1X_LONG, +}; + +struct vl53l1x_data { + struct regmap *regmap; + struct completion completion; + struct reset_control *xshut_reset; + enum vl53l1x_distance_mode distance_mode; + u8 gpio_polarity; + int irq; +}; + +static const struct regmap_range vl53l1x_volatile_ranges[] = { + regmap_reg_range(VL53L1X_REG_GPIO__TIO_HV_STATUS, + VL53L1X_REG_GPIO__TIO_HV_STATUS), + regmap_reg_range(VL53L1X_REG_RESULT__RANGE_STATUS, + VL53L1X_REG_RESULT__RANGE_STATUS), + regmap_reg_range(VL53L1X_REG_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0, + VL53L1X_REG_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0 + 1), + regmap_reg_range(VL53L1X_REG_RESULT__OSC_CALIBRATE_VAL, + VL53L1X_REG_RESULT__OSC_CALIBRATE_VAL + 1), + regmap_reg_range(VL53L1X_REG_FIRMWARE__SYSTEM_STATUS, + VL53L1X_REG_FIRMWARE__SYSTEM_STATUS), +}; + +static const struct regmap_access_table vl53l1x_volatile_table = { + .yes_ranges = vl53l1x_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(vl53l1x_volatile_ranges), +}; + +static const struct regmap_range vl53l1x_write_only_ranges[] = { + regmap_reg_range(VL53L1X_REG_SOFT_RESET, VL53L1X_REG_SOFT_RESET), + regmap_reg_range(VL53L1X_REG_SYSTEM__INTERRUPT_CLEAR, + VL53L1X_REG_SYSTEM__MODE_START), +}; + +static const struct regmap_access_table vl53l1x_readable_table = { + .no_ranges = vl53l1x_write_only_ranges, + .n_no_ranges = ARRAY_SIZE(vl53l1x_write_only_ranges), +}; + +static const struct regmap_config vl53l1x_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + /* MODEL_ID is 16-bit. +1 covers the second byte at 0x0110 */ + .max_register = VL53L1X_REG_IDENTIFICATION__MODEL_ID + 1, + .cache_type = REGCACHE_MAPLE, + .volatile_table = &vl53l1x_volatile_table, + .rd_table = &vl53l1x_readable_table, +}; + +static int vl53l1x_read_u16(struct vl53l1x_data *data, u16 reg, u16 *val) +{ + __be16 buf; + int ret; + + ret = regmap_bulk_read(data->regmap, reg, &buf, sizeof(buf)); + if (ret) + return ret; + + *val = be16_to_cpu(buf); + return 0; +} + +static int vl53l1x_write_u16(struct vl53l1x_data *data, u16 reg, u16 val) +{ + __be16 buf = cpu_to_be16(val); + + return regmap_bulk_write(data->regmap, reg, &buf, sizeof(buf)); +} + +static int vl53l1x_write_u32(struct vl53l1x_data *data, u16 reg, u32 val) +{ + __be32 buf = cpu_to_be32(val); + + return regmap_bulk_write(data->regmap, reg, &buf, sizeof(buf)); +} + +static int vl53l1x_clear_irq(struct vl53l1x_data *data) +{ + return regmap_write(data->regmap, VL53L1X_REG_SYSTEM__INTERRUPT_CLEAR, 0x01); +} + +static int vl53l1x_start_ranging(struct vl53l1x_data *data) +{ + int ret; + + ret = vl53l1x_clear_irq(data); + if (ret) + return ret; + + return regmap_write(data->regmap, VL53L1X_REG_SYSTEM__MODE_START, + VL53L1X_MODE_START_TIMED); +} + +static int vl53l1x_stop_ranging(struct vl53l1x_data *data) +{ + return regmap_write(data->regmap, VL53L1X_REG_SYSTEM__MODE_START, + VL53L1X_MODE_START_STOP); +} + +static int vl53l1x_wait_data_ready(struct vl53l1x_data *data) +{ + unsigned int val; + + /* 1ms poll, 1s timeout covers max timing budgets (per ST Ultra Lite Driver) */ + return regmap_read_poll_timeout(data->regmap, + VL53L1X_REG_GPIO__TIO_HV_STATUS, val, + (val & VL53L1X_GPIO__TIO_HV_STATUS_DATA_READY) != data->gpio_polarity, + 1 * USEC_PER_MSEC, 1 * USEC_PER_SEC); +} + +/* + * Default configuration blob from ST's VL53L1X Ultra Lite Driver + * (STSW-IMG009). + */ +static const u8 vl53l1x_default_config[] = { + 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x02, 0x08, /* reg 0x2d..0x34 */ + 0x00, 0x08, 0x10, 0x01, 0x01, 0x00, 0x00, 0x00, /* reg 0x35..0x3c */ + 0x00, 0xFF, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, /* reg 0x3d..0x44 */ + 0x00, 0x20, 0x0B, 0x00, 0x00, 0x02, 0x0A, 0x21, /* reg 0x45..0x4c */ + 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0xC8, /* reg 0x4d..0x54 */ + 0x00, 0x00, 0x38, 0xFF, 0x01, 0x00, 0x08, 0x00, /* reg 0x55..0x5c */ + 0x00, 0x01, 0xCC, 0x0F, 0x01, 0xF1, 0x0D, 0x01, /* reg 0x5d..0x64 */ + 0x68, 0x00, 0x80, 0x08, 0xB8, 0x00, 0x00, 0x00, /* reg 0x65..0x6c */ + 0x00, 0x0F, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, /* reg 0x6d..0x74 */ + 0x00, 0x00, 0x01, 0x0F, 0x0D, 0x0E, 0x0E, 0x00, /* reg 0x75..0x7c */ + 0x00, 0x02, 0xC7, 0xFF, 0x9B, 0x00, 0x00, 0x00, /* reg 0x7d..0x84 */ + 0x01, 0x00, 0x00, /* reg 0x85..0x87 */ +}; + +static int vl53l1x_chip_init(struct vl53l1x_data *data) +{ + struct device *dev = regmap_get_device(data->regmap); + unsigned int val; + u16 model_id; + int ret; + + if (!data->xshut_reset) { + ret = regmap_write(data->regmap, VL53L1X_REG_SOFT_RESET, 0x00); + if (ret) + return ret; + fsleep(100); /* conservative reset pulse, no spec */ + + ret = regmap_write(data->regmap, VL53L1X_REG_SOFT_RESET, 0x01); + if (ret) + return ret; + fsleep(1000); /* conservative boot wait, no spec */ + } + + ret = regmap_read_poll_timeout(data->regmap, + VL53L1X_REG_FIRMWARE__SYSTEM_STATUS, + val, val & VL53L1X_FIRMWARE__SYSTEM_STATUS_BOOTED, + 1 * USEC_PER_MSEC, 100 * USEC_PER_MSEC); + if (ret) + return dev_err_probe(dev, ret, "firmware boot timeout\n"); + + ret = vl53l1x_read_u16(data, VL53L1X_REG_IDENTIFICATION__MODEL_ID, + &model_id); + if (ret) + return ret; + + if (model_id != VL53L1X_MODEL_ID_VAL) + dev_info(dev, "unknown model id: 0x%04x, continuing\n", model_id); + + ret = regmap_bulk_write(data->regmap, VL53L1X_REG_DEFAULT_CONFIG, + vl53l1x_default_config, + sizeof(vl53l1x_default_config)); + if (ret) + return ret; + + ret = regmap_read(data->regmap, VL53L1X_REG_GPIO_HV_MUX__CTRL, &val); + if (ret) + return ret; + data->gpio_polarity = !!(val & VL53L1X_GPIO_HV_MUX_POLARITY); + + /* Initial ranging cycle for VHV calibration */ + ret = vl53l1x_start_ranging(data); + if (ret) + return ret; + + ret = vl53l1x_wait_data_ready(data); + if (ret) + return ret; + + ret = vl53l1x_clear_irq(data); + if (ret) + return ret; + + ret = vl53l1x_stop_ranging(data); + if (ret) + return ret; + + ret = regmap_write(data->regmap, + VL53L1X_REG_VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND, + VL53L1X_VHV_LOOP_BOUND_TWO); + if (ret) + return ret; + + return regmap_write(data->regmap, VL53L1X_REG_VHV_CONFIG__INIT, 0x00); +} + +static const struct reg_sequence vl53l1x_mode_short[] = { + { VL53L1X_REG_PHASECAL_CONFIG__TIMEOUT_MACROP, 0x14 }, + { VL53L1X_REG_RANGE_CONFIG__VCSEL_PERIOD_A, 0x07 }, + { VL53L1X_REG_RANGE_CONFIG__VCSEL_PERIOD_B, 0x05 }, + { VL53L1X_REG_RANGE_CONFIG__VALID_PHASE_HIGH, 0x38 }, + { VL53L1X_REG_SD_CONFIG__WOI_SD0, 0x07 }, + { VL53L1X_REG_SD_CONFIG__WOI_SD1, 0x05 }, + { VL53L1X_REG_SD_CONFIG__INITIAL_PHASE_SD0, 0x06 }, + { VL53L1X_REG_SD_CONFIG__INITIAL_PHASE_SD1, 0x06 }, +}; + +static const struct reg_sequence vl53l1x_mode_long[] = { + { VL53L1X_REG_PHASECAL_CONFIG__TIMEOUT_MACROP, 0x0A }, + { VL53L1X_REG_RANGE_CONFIG__VCSEL_PERIOD_A, 0x0F }, + { VL53L1X_REG_RANGE_CONFIG__VCSEL_PERIOD_B, 0x0D }, + { VL53L1X_REG_RANGE_CONFIG__VALID_PHASE_HIGH, 0xB8 }, + { VL53L1X_REG_SD_CONFIG__WOI_SD0, 0x0F }, + { VL53L1X_REG_SD_CONFIG__WOI_SD1, 0x0D }, + { VL53L1X_REG_SD_CONFIG__INITIAL_PHASE_SD0, 0x0E }, + { VL53L1X_REG_SD_CONFIG__INITIAL_PHASE_SD1, 0x0E }, +}; + +static const struct { + const struct reg_sequence *regs; + size_t num_regs; +} vl53l1x_mode_configs[] = { + [VL53L1X_SHORT] = { vl53l1x_mode_short, ARRAY_SIZE(vl53l1x_mode_short) }, + [VL53L1X_LONG] = { vl53l1x_mode_long, ARRAY_SIZE(vl53l1x_mode_long) }, +}; + +static int vl53l1x_set_distance_mode(struct vl53l1x_data *data, + enum vl53l1x_distance_mode mode) +{ + int ret; + + if (mode >= ARRAY_SIZE(vl53l1x_mode_configs)) + return -EINVAL; + + ret = regmap_multi_reg_write(data->regmap, + vl53l1x_mode_configs[mode].regs, + vl53l1x_mode_configs[mode].num_regs); + if (ret) + return ret; + + data->distance_mode = mode; + return 0; +} + +/* + * The timing budget controls how long the sensor spends collecting + * a single range measurement. Pre-computed TIMEOUT_MACROP register + * values from ST's VL53L1X Ultra Lite Driver. + */ +static int vl53l1x_set_timing_budget(struct vl53l1x_data *data, u16 budget_ms) +{ + u16 timeout_a, timeout_b; + int ret; + + switch (data->distance_mode) { + case VL53L1X_SHORT: + switch (budget_ms) { + case 15: + timeout_a = 0x001D; + timeout_b = 0x0027; + break; + case 20: + timeout_a = 0x0051; + timeout_b = 0x006E; + break; + case 33: + timeout_a = 0x00D6; + timeout_b = 0x006E; + break; + case 50: + timeout_a = 0x01AE; + timeout_b = 0x01E8; + break; + case 100: + timeout_a = 0x02E1; + timeout_b = 0x0388; + break; + case 200: + timeout_a = 0x03E1; + timeout_b = 0x0496; + break; + case 500: + timeout_a = 0x0591; + timeout_b = 0x05C1; + break; + default: + return -EINVAL; + } + break; + case VL53L1X_LONG: + switch (budget_ms) { + case 20: + timeout_a = 0x001E; + timeout_b = 0x0022; + break; + case 33: + timeout_a = 0x0060; + timeout_b = 0x006E; + break; + case 50: + timeout_a = 0x00AD; + timeout_b = 0x00C6; + break; + case 100: + timeout_a = 0x01CC; + timeout_b = 0x01EA; + break; + case 200: + timeout_a = 0x02D9; + timeout_b = 0x02F8; + break; + case 500: + timeout_a = 0x048F; + timeout_b = 0x04A4; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + ret = vl53l1x_write_u16(data, VL53L1X_REG_RANGE_CONFIG__TIMEOUT_MACROP_A, + timeout_a); + if (ret) + return ret; + + return vl53l1x_write_u16(data, VL53L1X_REG_RANGE_CONFIG__TIMEOUT_MACROP_B, + timeout_b); +} + +static int vl53l1x_set_inter_measurement_ms(struct vl53l1x_data *data, + u16 period_ms) +{ + u16 osc_calibrate_val; + u16 clock_pll; + u32 inter_meas; + int ret; + + ret = vl53l1x_read_u16(data, VL53L1X_REG_RESULT__OSC_CALIBRATE_VAL, + &osc_calibrate_val); + if (ret) + return ret; + + clock_pll = osc_calibrate_val & VL53L1X_OSC_CALIBRATE_MASK; + inter_meas = (clock_pll * period_ms * vl53l1x_osc_correction.numerator) / + vl53l1x_osc_correction.denominator; + + return vl53l1x_write_u32(data, + VL53L1X_REG_SYSTEM__INTERMEASUREMENT_PERIOD, + inter_meas); +} + +static int vl53l1x_read_proximity(struct vl53l1x_data *data, int *val) +{ + unsigned int range_status; + u16 distance; + int ret; + + if (data->irq) { + reinit_completion(&data->completion); + + ret = vl53l1x_clear_irq(data); + if (ret) + return ret; + + if (!wait_for_completion_timeout(&data->completion, HZ)) + return -ETIMEDOUT; + } else { + ret = vl53l1x_wait_data_ready(data); + if (ret) + return ret; + } + + ret = regmap_read(data->regmap, VL53L1X_REG_RESULT__RANGE_STATUS, + &range_status); + if (ret) + goto clear_irq; + + if (FIELD_GET(VL53L1X_RANGE_STATUS_MASK, range_status) != + VL53L1X_RANGE_STATUS_VALID) { + ret = -EIO; + goto clear_irq; + } + + ret = vl53l1x_read_u16(data, + VL53L1X_REG_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0, + &distance); + if (ret) + goto clear_irq; + + *val = distance; + +clear_irq: + vl53l1x_clear_irq(data); + return ret; +} + +static const struct iio_chan_spec vl53l1x_channels[] = { + { + .type = IIO_DISTANCE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .scan_index = 0, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static int vl53l1x_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct vl53l1x_data *data = iio_priv(indio_dev); + int ret; + + if (chan->type != IIO_DISTANCE) + return -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + ret = vl53l1x_read_proximity(data, val); + iio_device_release_direct(indio_dev); + if (ret) + return ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = 1000; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static const struct iio_info vl53l1x_info = { + .read_raw = vl53l1x_read_raw, + .validate_trigger = iio_validate_own_trigger, +}; + +static irqreturn_t vl53l1x_trigger_handler(int irq, void *priv) +{ + struct iio_poll_func *pf = priv; + struct iio_dev *indio_dev = pf->indio_dev; + struct vl53l1x_data *data = iio_priv(indio_dev); + struct { + u16 distance; + aligned_s64 timestamp; + } scan = { }; + unsigned int range_status; + int ret; + + ret = regmap_read(data->regmap, VL53L1X_REG_RESULT__RANGE_STATUS, + &range_status); + if (ret) + goto notify_and_clear_irq; + if (FIELD_GET(VL53L1X_RANGE_STATUS_MASK, range_status) != + VL53L1X_RANGE_STATUS_VALID) + goto notify_and_clear_irq; + + ret = vl53l1x_read_u16(data, + VL53L1X_REG_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0, + &scan.distance); + if (ret) + goto notify_and_clear_irq; + + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), + iio_get_time_ns(indio_dev)); + +notify_and_clear_irq: + iio_trigger_notify_done(indio_dev->trig); + vl53l1x_clear_irq(data); + + return IRQ_HANDLED; +} + +static irqreturn_t vl53l1x_irq_handler(int irq, void *priv) +{ + struct iio_dev *indio_dev = priv; + struct vl53l1x_data *data = iio_priv(indio_dev); + + if (iio_buffer_enabled(indio_dev)) + iio_trigger_poll(indio_dev->trig); + else + complete(&data->completion); + + return IRQ_HANDLED; +} + +static const struct iio_trigger_ops vl53l1x_trigger_ops = { + .validate_device = iio_trigger_validate_own_device, +}; + +static void vl53l1x_stop_ranging_action(void *priv) +{ + vl53l1x_stop_ranging(priv); +} + +static int vl53l1x_configure_irq(struct device *dev, int irq, + struct iio_dev *indio_dev) +{ + struct vl53l1x_data *data = iio_priv(indio_dev); + int ret; + + ret = devm_request_irq(dev, irq, vl53l1x_irq_handler, IRQF_NO_THREAD, + indio_dev->name, indio_dev); + if (ret) + return ret; + + ret = regmap_write(data->regmap, VL53L1X_REG_SYSTEM__INTERRUPT_CONFIG_GPIO, + VL53L1X_INT_NEW_SAMPLE_READY); + if (ret) + return dev_err_probe(dev, ret, "failed to configure IRQ\n"); + + return 0; +} + +static int vl53l1x_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct vl53l1x_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->irq = client->irq; + + data->regmap = devm_regmap_init_i2c(client, &vl53l1x_regmap_config); + if (IS_ERR(data->regmap)) + return dev_err_probe(dev, PTR_ERR(data->regmap), + "regmap initialization failed\n"); + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable VDD regulator\n"); + + /* + * XSHUT held low puts the chip in hardware standby. All register + * state is lost on de-assert so this is functionally a reset. + */ + data->xshut_reset = devm_reset_control_get_optional_exclusive_deasserted(dev, NULL); + if (IS_ERR(data->xshut_reset)) + return dev_err_probe(dev, PTR_ERR(data->xshut_reset), + "Cannot get reset control\n"); + + /* + * 1.2 ms max boot duration. + * Datasheet Section 3.6 "Power up and boot sequence". + */ + fsleep(1200); + + ret = vl53l1x_chip_init(data); + if (ret) + return ret; + + ret = vl53l1x_set_distance_mode(data, VL53L1X_LONG); + if (ret) + return ret; + + /* 50 ms timing budget (per ST Ultra Lite Driver) */ + ret = vl53l1x_set_timing_budget(data, 50); + if (ret) + return ret; + + /* 50 ms inter-measurement period (per ST Ultra Lite Driver) */ + ret = vl53l1x_set_inter_measurement_ms(data, 50); + if (ret) + return ret; + + /* + * The hardware only supports "autonomous" continuous ranging mode. + * Start ranging here and leave it running for the lifetime of + * the device. Both direct reads and the buffer path rely on this. + */ + ret = vl53l1x_start_ranging(data); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, vl53l1x_stop_ranging_action, data); + if (ret) + return ret; + + indio_dev->name = "vl53l1x"; + indio_dev->info = &vl53l1x_info; + indio_dev->channels = vl53l1x_channels; + indio_dev->num_channels = ARRAY_SIZE(vl53l1x_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + if (client->irq) { + struct iio_trigger *trig; + + init_completion(&data->completion); + + trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, + iio_device_id(indio_dev)); + if (!trig) + return -ENOMEM; + + trig->ops = &vl53l1x_trigger_ops; + iio_trigger_set_drvdata(trig, indio_dev); + ret = devm_iio_trigger_register(dev, trig); + if (ret) + return ret; + + indio_dev->trig = iio_trigger_get(trig); + + ret = vl53l1x_configure_irq(dev, client->irq, indio_dev); + if (ret) + return ret; + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, + &vl53l1x_trigger_handler, + NULL); + if (ret) + return ret; + } + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct i2c_device_id vl53l1x_id[] = { + { .name = "vl53l1x" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, vl53l1x_id); + +static const struct of_device_id st_vl53l1x_dt_match[] = { + { .compatible = "st,vl53l1x" }, + { } +}; +MODULE_DEVICE_TABLE(of, st_vl53l1x_dt_match); + +static struct i2c_driver vl53l1x_driver = { + .driver = { + .name = "vl53l1x-i2c", + .of_match_table = st_vl53l1x_dt_match, + }, + .probe = vl53l1x_probe, + .id_table = vl53l1x_id, +}; +module_i2c_driver(vl53l1x_driver); + +MODULE_AUTHOR("Siratul Islam <siratul.islam@linux.dev>"); +MODULE_DESCRIPTION("ST VL53L1X ToF ranging sensor driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/iio/resolver/ad2s1200.c b/drivers/iio/resolver/ad2s1200.c index c00a60cb31a5..27ecc434eee9 100644 --- a/drivers/iio/resolver/ad2s1200.c +++ b/drivers/iio/resolver/ad2s1200.c @@ -12,7 +12,6 @@ #include <linux/device.h> #include <linux/gpio/consumer.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/spi/spi.h> #include <linux/sysfs.h> @@ -144,18 +143,14 @@ static int ad2s1200_probe(struct spi_device *spi) st->sdev = spi; st->sample = devm_gpiod_get(&spi->dev, "adi,sample", GPIOD_OUT_LOW); - if (IS_ERR(st->sample)) { - dev_err(&spi->dev, "Failed to claim SAMPLE gpio: err=%ld\n", - PTR_ERR(st->sample)); - return PTR_ERR(st->sample); - } + if (IS_ERR(st->sample)) + return dev_err_probe(&spi->dev, PTR_ERR(st->sample), + "Failed to claim SAMPLE gpio\n"); st->rdvel = devm_gpiod_get(&spi->dev, "adi,rdvel", GPIOD_OUT_LOW); - if (IS_ERR(st->rdvel)) { - dev_err(&spi->dev, "Failed to claim RDVEL gpio: err=%ld\n", - PTR_ERR(st->rdvel)); - return PTR_ERR(st->rdvel); - } + if (IS_ERR(st->rdvel)) + return dev_err_probe(&spi->dev, PTR_ERR(st->rdvel), + "Failed to claim RDVEL gpio\n"); indio_dev->info = &ad2s1200_info; indio_dev->modes = INDIO_DIRECT_MODE; @@ -183,8 +178,8 @@ static const struct of_device_id ad2s1200_of_match[] = { MODULE_DEVICE_TABLE(of, ad2s1200_of_match); static const struct spi_device_id ad2s1200_id[] = { - { "ad2s1200" }, - { "ad2s1205" }, + { .name = "ad2s1200" }, + { .name = "ad2s1205" }, { } }; MODULE_DEVICE_TABLE(spi, ad2s1200_id); diff --git a/drivers/iio/resolver/ad2s1210.c b/drivers/iio/resolver/ad2s1210.c index 06d9c784f93e..3b5ec21e3446 100644 --- a/drivers/iio/resolver/ad2s1210.c +++ b/drivers/iio/resolver/ad2s1210.c @@ -896,14 +896,14 @@ static const struct iio_event_spec ad2s1210_monitor_signal_event_spec[] = { .mask_separate = BIT(IIO_EV_INFO_VALUE), }, { - /* Sine/cosine DOS overrange fault.*/ + /* Sine/cosine DOS overrange fault. */ .type = IIO_EV_TYPE_THRESH, .dir = IIO_EV_DIR_RISING, - /* Degredation of signal overrange threshold. */ + /* Degradation of signal overrange threshold. */ .mask_separate = BIT(IIO_EV_INFO_VALUE), }, { - /* Sine/cosine DOS mismatch fault.*/ + /* Sine/cosine DOS mismatch fault. */ .type = IIO_EV_TYPE_MAG, .dir = IIO_EV_DIR_RISING, .mask_separate = BIT(IIO_EV_INFO_VALUE), @@ -1276,10 +1276,8 @@ static int ad2s1210_debugfs_reg_access(struct iio_dev *indio_dev, return regmap_write(st->regmap, reg, writeval); } -static irqreturn_t ad2s1210_trigger_handler(int irq, void *p) +static void ad2s1210_scan_to_buffers(struct iio_dev *indio_dev, s64 timestamp) { - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; struct ad2s1210_state *st = iio_priv(indio_dev); size_t chan = 0; int ret; @@ -1295,15 +1293,15 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p) AD2S1210_REG_POSITION_MSB, &st->sample.raw, 2); if (ret < 0) - goto error_ret; + return; } else { ret = ad2s1210_set_mode(st, MOD_POS); if (ret < 0) - goto error_ret; + return; ret = spi_read(st->sdev, &st->sample, 3); if (ret < 0) - goto error_ret; + return; } memcpy(&st->scan.chan[chan++], &st->sample.raw, 2); @@ -1315,15 +1313,15 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p) AD2S1210_REG_VELOCITY_MSB, &st->sample.raw, 2); if (ret < 0) - goto error_ret; + return; } else { ret = ad2s1210_set_mode(st, MOD_VEL); if (ret < 0) - goto error_ret; + return; ret = spi_read(st->sdev, &st->sample, 3); if (ret < 0) - goto error_ret; + return; } memcpy(&st->scan.chan[chan++], &st->sample.raw, 2); @@ -1334,16 +1332,22 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p) ret = regmap_read(st->regmap, AD2S1210_REG_FAULT, ®_val); if (ret < 0) - return ret; + return; st->sample.fault = reg_val; } - ad2s1210_push_events(indio_dev, st->sample.fault, pf->timestamp); + ad2s1210_push_events(indio_dev, st->sample.fault, timestamp); iio_push_to_buffers_with_ts(indio_dev, &st->scan, sizeof(st->scan), - pf->timestamp); + timestamp); +} + +static irqreturn_t ad2s1210_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; -error_ret: + ad2s1210_scan_to_buffers(indio_dev, pf->timestamp); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; @@ -1597,7 +1601,7 @@ static const struct of_device_id ad2s1210_of_match[] = { MODULE_DEVICE_TABLE(of, ad2s1210_of_match); static const struct spi_device_id ad2s1210_id[] = { - { "ad2s1210" }, + { .name = "ad2s1210" }, { } }; MODULE_DEVICE_TABLE(spi, ad2s1210_id); diff --git a/drivers/iio/resolver/ad2s90.c b/drivers/iio/resolver/ad2s90.c index 18f1c905eeac..b7a2dcc42871 100644 --- a/drivers/iio/resolver/ad2s90.c +++ b/drivers/iio/resolver/ad2s90.c @@ -110,7 +110,7 @@ static const struct of_device_id ad2s90_of_match[] = { MODULE_DEVICE_TABLE(of, ad2s90_of_match); static const struct spi_device_id ad2s90_id[] = { - { "ad2s90" }, + { .name = "ad2s90" }, { } }; MODULE_DEVICE_TABLE(spi, ad2s90_id); diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile index 07d6e65709f7..0850bf691820 100644 --- a/drivers/iio/temperature/Makefile +++ b/drivers/iio/temperature/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_MAX31865) += max31865.o obj-$(CONFIG_MCP9600) += mcp9600.o obj-$(CONFIG_MLX90614) += mlx90614.o obj-$(CONFIG_MLX90632) += mlx90632.o -obj-$(CONFIG_MLX90632) += mlx90635.o +obj-$(CONFIG_MLX90635) += mlx90635.o obj-$(CONFIG_TMP006) += tmp006.o obj-$(CONFIG_TMP007) += tmp007.o obj-$(CONFIG_TMP117) += tmp117.o diff --git a/drivers/iio/temperature/hid-sensor-temperature.c b/drivers/iio/temperature/hid-sensor-temperature.c index 9f628a8e5cfb..5e3262e461f4 100644 --- a/drivers/iio/temperature/hid-sensor-temperature.c +++ b/drivers/iio/temperature/hid-sensor-temperature.c @@ -8,7 +8,6 @@ #include <linux/iio/buffer.h> #include <linux/iio/iio.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include "../common/hid-sensors/hid-sensor-trigger.h" @@ -45,7 +44,7 @@ static const struct iio_chan_spec temperature_channels[] = { /* Adjust channel real bits based on report descriptor */ static void temperature_adjust_channel_bit_mask(struct iio_chan_spec *channels, - int channel, int size) + int channel, int size) { channels[channel].scan_type.sign = 's'; /* Real storage bits will change based on the report desc. */ @@ -101,8 +100,8 @@ static int temperature_read_raw(struct iio_dev *indio_dev, } static int temperature_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct temperature_state *temp_st = iio_priv(indio_dev); @@ -125,7 +124,7 @@ static const struct iio_info temperature_info = { /* Callback handler to send event after all samples are received and captured */ static int temperature_proc_event(struct hid_sensor_hub_device *hsdev, - unsigned int usage_id, void *pdev) + u32 usage_id, void *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct temperature_state *temp_st = iio_priv(indio_dev); @@ -140,8 +139,9 @@ static int temperature_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int temperature_capture_sample(struct hid_sensor_hub_device *hsdev, - unsigned int usage_id, size_t raw_len, - char *raw_data, void *pdev) + u32 usage_id, + size_t raw_len, char *raw_data, + void *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct temperature_state *temp_st = iio_priv(indio_dev); @@ -157,10 +157,10 @@ static int temperature_capture_sample(struct hid_sensor_hub_device *hsdev, /* Parse report which is specific to an usage id*/ static int temperature_parse_report(struct platform_device *pdev, - struct hid_sensor_hub_device *hsdev, - struct iio_chan_spec *channels, - unsigned int usage_id, - struct temperature_state *st) + struct hid_sensor_hub_device *hsdev, + struct iio_chan_spec *channels, + u32 usage_id, + struct temperature_state *st) { int ret; @@ -171,8 +171,7 @@ static int temperature_parse_report(struct platform_device *pdev, if (ret < 0) return ret; - temperature_adjust_channel_bit_mask(channels, 0, - st->temperature_attr.size); + temperature_adjust_channel_bit_mask(channels, 0, st->temperature_attr.size); st->scale_precision = hid_sensor_format_scale( HID_USAGE_SENSOR_TEMPERATURE, @@ -213,13 +212,13 @@ static int hid_temperature_probe(struct platform_device *pdev) if (ret) return ret; - temp_chans = devm_kmemdup(&indio_dev->dev, temperature_channels, - sizeof(temperature_channels), GFP_KERNEL); + temp_chans = devm_kmemdup(&pdev->dev, temperature_channels, + sizeof(temperature_channels), GFP_KERNEL); if (!temp_chans) return -ENOMEM; ret = temperature_parse_report(pdev, hsdev, temp_chans, - HID_USAGE_SENSOR_TEMPERATURE, temp_st); + HID_USAGE_SENSOR_TEMPERATURE, temp_st); if (ret) return ret; @@ -232,7 +231,7 @@ static int hid_temperature_probe(struct platform_device *pdev) atomic_set(&temp_st->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, - &temp_st->common_attributes); + &temp_st->common_attributes); if (ret) return ret; @@ -240,11 +239,11 @@ static int hid_temperature_probe(struct platform_device *pdev) temperature_callbacks.pdev = pdev; ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_TEMPERATURE, - &temperature_callbacks); + &temperature_callbacks); if (ret) goto error_remove_trigger; - ret = devm_iio_device_register(indio_dev->dev.parent, indio_dev); + ret = iio_device_register(indio_dev); if (ret) goto error_remove_callback; @@ -264,6 +263,7 @@ static void hid_temperature_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct temperature_state *temp_st = iio_priv(indio_dev); + iio_device_unregister(indio_dev); sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TEMPERATURE); hid_sensor_remove_trigger(indio_dev, &temp_st->common_attributes); } diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c index 7dd40d69cce6..6efb5252a773 100644 --- a/drivers/iio/temperature/ltc2983.c +++ b/drivers/iio/temperature/ltc2983.c @@ -14,7 +14,6 @@ #include <linux/iio/iio.h> #include <linux/interrupt.h> #include <linux/list.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/property.h> #include <linux/regmap.h> @@ -28,6 +27,8 @@ #define LTC2983_STATUS_REG 0x0000 #define LTC2983_TEMP_RES_START_REG 0x0010 #define LTC2983_TEMP_RES_END_REG 0x005F +#define ADT7604_RES_RES_START_REG 0x0060 +#define ADT7604_RES_RES_END_REG 0x00AF #define LTC2983_EEPROM_KEY_REG 0x00B0 #define LTC2983_EEPROM_READ_STATUS_REG 0x00D0 #define LTC2983_GLOBAL_CONFIG_REG 0x00F0 @@ -56,10 +57,10 @@ #define LTC2983_EEPROM_WRITE_TIME_MS 2600 #define LTC2983_EEPROM_READ_TIME_MS 20 -#define LTC2983_CHAN_START_ADDR(chan) \ - (((chan - 1) * 4) + LTC2983_CHAN_ASSIGN_START_REG) -#define LTC2983_CHAN_RES_ADDR(chan) \ - (((chan - 1) * 4) + LTC2983_TEMP_RES_START_REG) +#define LTC2983_CHAN_ASSIGN_ADDR(chan) \ + ((((chan) - 1) * 4) + LTC2983_CHAN_ASSIGN_START_REG) +#define LTC2983_RESULT_ADDR(chan, base) \ + ((((chan) - 1) * 4) + (base)) #define LTC2983_THERMOCOUPLE_DIFF_MASK BIT(3) #define LTC2983_THERMOCOUPLE_SGL(x) \ FIELD_PREP(LTC2983_THERMOCOUPLE_DIFF_MASK, x) @@ -186,17 +187,44 @@ enum { LTC2983_SENSOR_SENSE_RESISTOR = 29, LTC2983_SENSOR_DIRECT_ADC = 30, LTC2983_SENSOR_ACTIVE_TEMP = 31, + /* Sensor types for some parts only; map to RTD_CUSTOM/THERMISTOR_CUSTOM in HW */ + LTC2983_SENSOR_COPPER_TRACE = 32, + LTC2983_SENSOR_LEAK_DETECTOR = 33, + LTC2983_SENSOR_NUM }; +/* Bitmask of sensor types supported by LTC2983/LTC2984 and derivatives */ +#define LTC2983_COMMON_SENSORS \ + (GENMASK_ULL(LTC2983_SENSOR_THERMOCOUPLE_CUSTOM, LTC2983_SENSOR_THERMOCOUPLE) | \ + GENMASK_ULL(LTC2983_SENSOR_RTD_CUSTOM, LTC2983_SENSOR_RTD) | \ + GENMASK_ULL(LTC2983_SENSOR_THERMISTOR_CUSTOM, LTC2983_SENSOR_THERMISTOR) | \ + BIT_ULL(LTC2983_SENSOR_DIODE) | \ + BIT_ULL(LTC2983_SENSOR_SENSE_RESISTOR) | \ + BIT_ULL(LTC2983_SENSOR_DIRECT_ADC)) + +/* Bitmask of sensor types supported by ADT7604 */ +#define ADT7604_SENSORS \ + (GENMASK_ULL(LTC2983_SENSOR_RTD_CUSTOM - 1, LTC2983_SENSOR_RTD) | \ + GENMASK_ULL(LTC2983_SENSOR_THERMISTOR_CUSTOM - 1, LTC2983_SENSOR_THERMISTOR) | \ + BIT_ULL(LTC2983_SENSOR_SENSE_RESISTOR) | \ + BIT_ULL(LTC2983_SENSOR_COPPER_TRACE) | \ + BIT_ULL(LTC2983_SENSOR_LEAK_DETECTOR)) + #define to_thermocouple(_sensor) \ container_of(_sensor, struct ltc2983_thermocouple, sensor) #define to_rtd(_sensor) \ container_of(_sensor, struct ltc2983_rtd, sensor) +#define to_copper_trace(_sensor) \ + container_of(_sensor, struct ltc2983_copper_trace, sensor) + #define to_thermistor(_sensor) \ container_of(_sensor, struct ltc2983_thermistor, sensor) +#define to_leak_detector(_sensor) \ + container_of(_sensor, struct ltc2983_leak_detector, sensor) + #define to_diode(_sensor) \ container_of(_sensor, struct ltc2983_diode, sensor) @@ -212,7 +240,7 @@ enum { struct ltc2983_chip_info { const char *name; unsigned int max_channels_nr; - bool has_temp; + u64 supported_sensors; bool has_eeprom; }; @@ -247,6 +275,8 @@ struct ltc2983_sensor { u32 chan; /* sensor type */ u32 type; + /* number of IIO channels this sensor produces */ + u8 n_iio_chan; }; struct ltc2983_custom_sensor { @@ -274,6 +304,25 @@ struct ltc2983_rtd { u32 rtd_curve; }; +struct ltc2983_copper_trace { + struct ltc2983_sensor sensor; + struct ltc2983_custom_sensor *custom; + u32 r_sense_chan; + u32 excitation_current; + /* selects the <1Ω variant: bits 17:0 of the channel word are zeroed, + * disabling excitation current and custom table fields (ADT7604 + * datasheet Table 26) + */ + bool is_sub_ohm; +}; + +struct ltc2983_leak_detector { + struct ltc2983_sensor sensor; + struct ltc2983_custom_sensor *custom; + u32 r_sense_chan; + u32 excitation_current; +}; + struct ltc2983_thermistor { struct ltc2983_sensor sensor; struct ltc2983_custom_sensor *custom; @@ -351,11 +400,17 @@ static int __ltc2983_chan_assign_common(struct ltc2983_data *st, const struct ltc2983_sensor *sensor, u32 chan_val) { - u32 reg = LTC2983_CHAN_START_ADDR(sensor->chan); + struct device *dev = &st->spi->dev; + u32 reg = LTC2983_CHAN_ASSIGN_ADDR(sensor->chan); + u32 hw_type = sensor->type; + + if (hw_type == LTC2983_SENSOR_COPPER_TRACE) + hw_type = LTC2983_SENSOR_RTD_CUSTOM; + else if (hw_type == LTC2983_SENSOR_LEAK_DETECTOR) + hw_type = LTC2983_SENSOR_THERMISTOR_CUSTOM; - chan_val |= LTC2983_CHAN_TYPE(sensor->type); - dev_dbg(&st->spi->dev, "Assign reg:0x%04X, val:0x%08X\n", reg, - chan_val); + chan_val |= LTC2983_CHAN_TYPE(hw_type); + dev_dbg(dev, "Assign reg:0x%04X, val:0x%08X\n", reg, chan_val); st->chan_val = cpu_to_be32(chan_val); return regmap_bulk_write(st->regmap, reg, &st->chan_val, sizeof(st->chan_val)); @@ -485,6 +540,14 @@ __ltc2983_custom_sensor_new(struct ltc2983_data *st, const struct fwnode_handle for (index = 0; index < n_entries; index++) { u64 temp = ((u64 *)new_custom->table)[index]; + /* + * Users specify plain coverage percentage (0-100). Convert + * to µK so __convert_to_raw() produces the correct hardware + * encoding: P + 273.15 K. + */ + if ((index % 2) != 0 && !strcmp(propname, "adi,custom-leak-detector")) + temp = temp * 1000000 + 273150000; + if ((index % 2) != 0) temp = __convert_to_raw(temp, 1024); else if (has_signed && (s64)temp < 0) @@ -578,6 +641,31 @@ static int ltc2983_rtd_assign_chan(struct ltc2983_data *st, return __ltc2983_chan_assign_common(st, sensor, chan_val); } +static int ltc2983_copper_trace_assign_chan(struct ltc2983_data *st, + const struct ltc2983_sensor *sensor) +{ + struct ltc2983_copper_trace *ct = to_copper_trace(sensor); + u32 chan_val; + + chan_val = LTC2983_CHAN_ASSIGN(ct->r_sense_chan); + /* Sensor config bits 21:18 must be 0b1001 (ADT7604 datasheet Table 26) */ + chan_val |= LTC2983_RTD_CFG(0x9); + + if (ct->is_sub_ohm) { + chan_val &= ~GENMASK(17, 0); + } else { + int ret; + + chan_val |= LTC2983_RTD_EXC_CURRENT(ct->excitation_current); + ret = __ltc2983_chan_custom_sensor_assign(st, ct->custom, + &chan_val); + if (ret) + return ret; + } + + return __ltc2983_chan_assign_common(st, sensor, chan_val); +} + static int ltc2983_thermistor_assign_chan(struct ltc2983_data *st, const struct ltc2983_sensor *sensor) { @@ -601,6 +689,25 @@ static int ltc2983_thermistor_assign_chan(struct ltc2983_data *st, return __ltc2983_chan_assign_common(st, sensor, chan_val); } +static int ltc2983_leak_detector_assign_chan(struct ltc2983_data *st, + const struct ltc2983_sensor *sensor) +{ + struct ltc2983_leak_detector *ld = to_leak_detector(sensor); + u32 chan_val; + int ret; + + chan_val = LTC2983_CHAN_ASSIGN(ld->r_sense_chan); + /* bits 21:19 must be 0b001 (ADT7604 datasheet Table 38) */ + chan_val |= LTC2983_THERMISTOR_CFG(1); + chan_val |= LTC2983_THERMISTOR_EXC_CURRENT(ld->excitation_current); + + ret = __ltc2983_chan_custom_sensor_assign(st, ld->custom, &chan_val); + if (ret) + return ret; + + return __ltc2983_chan_assign_common(st, sensor, chan_val); +} + static int ltc2983_diode_assign_chan(struct ltc2983_data *st, const struct ltc2983_sensor *sensor) { @@ -656,19 +763,26 @@ static struct ltc2983_sensor * ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data *st, const struct ltc2983_sensor *sensor) { + struct device *dev = &st->spi->dev; struct ltc2983_thermocouple *thermo; u32 oc_current; int ret; - thermo = devm_kzalloc(&st->spi->dev, sizeof(*thermo), GFP_KERNEL); + thermo = devm_kzalloc(dev, sizeof(*thermo), GFP_KERNEL); if (!thermo) return ERR_PTR(-ENOMEM); if (fwnode_property_read_bool(child, "adi,single-ended")) thermo->sensor_config = LTC2983_THERMOCOUPLE_SGL(1); - ret = fwnode_property_read_u32(child, "adi,sensor-oc-current-microamp", &oc_current); - if (!ret) { + if (fwnode_property_present(child, "adi,sensor-oc-current-microamp")) { + ret = fwnode_property_read_u32(child, + "adi,sensor-oc-current-microamp", + &oc_current); + if (ret) + return dev_err_ptr_probe(dev, ret, + "Failed to read adi,sensor-oc-current-microamp\n"); + switch (oc_current) { case 10: thermo->sensor_config |= @@ -687,7 +801,7 @@ ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data LTC2983_THERMOCOUPLE_OC_CURR(3); break; default: - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + return dev_err_ptr_probe(dev, -EINVAL, "Invalid open circuit current:%u\n", oc_current); } @@ -697,8 +811,8 @@ ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data /* validate channel index */ if (!(thermo->sensor_config & LTC2983_THERMOCOUPLE_DIFF_MASK) && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, - "Invalid chann:%d for differential thermocouple\n", + return dev_err_ptr_probe(dev, -EINVAL, + "Invalid channel %d for differential thermocouple\n", sensor->chan); struct fwnode_handle *ref __free(fwnode_handle) = @@ -709,10 +823,10 @@ ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data ret = fwnode_property_read_u32(ref, "reg", &thermo->cold_junction_chan); if (ret) /* - * This would be catched later but we can just return + * This would be caught later but we can just return * the error right away. */ - return dev_err_ptr_probe(&st->spi->dev, ret, + return dev_err_ptr_probe(dev, ret, "Property reg must be given\n"); } @@ -741,7 +855,7 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, struct ltc2983_rtd *rtd; int ret = 0; struct device *dev = &st->spi->dev; - u32 excitation_current = 0, n_wires = 0; + u32 excitation_current = 0, n_wires = 2; rtd = devm_kzalloc(dev, sizeof(*rtd), GFP_KERNEL); if (!rtd) @@ -758,8 +872,12 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, return dev_err_ptr_probe(dev, ret, "Property reg must be given\n"); - ret = fwnode_property_read_u32(child, "adi,number-of-wires", &n_wires); - if (!ret) { + if (fwnode_property_present(child, "adi,number-of-wires")) { + ret = fwnode_property_read_u32(child, "adi,number-of-wires", &n_wires); + if (ret) + return dev_err_ptr_probe(dev, ret, + "Failed to read adi,number-of-wires\n"); + switch (n_wires) { case 2: rtd->sensor_config = LTC2983_RTD_N_WIRES(0); @@ -796,9 +914,9 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, /* * rtd channel indexes are a bit more complicated to validate. * For 4wire RTD with rotation, the channel selection cannot be - * >=19 since the chann + 1 is used in this configuration. + * >=19 since the channel + 1 is used in this configuration. * For 4wire RTDs with kelvin rsense, the rsense channel cannot be - * <=1 since chanel - 1 and channel - 2 are used. + * <=1 since channel - 1 and channel - 2 are used. */ if (rtd->sensor_config & LTC2983_RTD_4_WIRE_MASK) { /* 4-wire */ @@ -813,18 +931,18 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, (rtd->r_sense_chan <= min)) /* kelvin rsense*/ return dev_err_ptr_probe(dev, -EINVAL, - "Invalid rsense chann:%d to use in kelvin rsense\n", + "Invalid channel %d for kelvin rsense\n", rtd->r_sense_chan); if (sensor->chan < min || sensor->chan > max) return dev_err_ptr_probe(dev, -EINVAL, - "Invalid chann:%d for the rtd config\n", + "Invalid channel %d for RTD config\n", sensor->chan); } else { /* same as differential case */ if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, - "Invalid chann:%d for RTD\n", + return dev_err_ptr_probe(dev, -EINVAL, + "Invalid channel %d for RTD\n", sensor->chan); } @@ -841,12 +959,13 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, rtd->sensor.fault_handler = ltc2983_common_fault_handler; rtd->sensor.assign_chan = ltc2983_rtd_assign_chan; - ret = fwnode_property_read_u32(child, "adi,excitation-current-microamp", - &excitation_current); - if (ret) { - /* default to 5uA */ - rtd->excitation_current = 1; - } else { + if (fwnode_property_present(child, "adi,excitation-current-microamp")) { + ret = fwnode_property_read_u32(child, "adi,excitation-current-microamp", + &excitation_current); + if (ret) + return dev_err_ptr_probe(dev, ret, + "Failed to read adi,excitation-current-microamp\n"); + switch (excitation_current) { case 5: rtd->excitation_current = 0x01; @@ -873,13 +992,21 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, rtd->excitation_current = 0x08; break; default: - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + return dev_err_ptr_probe(dev, -EINVAL, "Invalid value for excitation current(%u)\n", excitation_current); } + } else { + /* default to 5uA */ + rtd->excitation_current = 1; } - fwnode_property_read_u32(child, "adi,rtd-curve", &rtd->rtd_curve); + if (fwnode_property_present(child, "adi,rtd-curve")) { + ret = fwnode_property_read_u32(child, "adi,rtd-curve", &rtd->rtd_curve); + if (ret) + return dev_err_ptr_probe(dev, ret, + "Failed to read adi,rtd-curve\n"); + } return &rtd->sensor; } @@ -922,8 +1049,8 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s /* validate channel index */ if (!(thermistor->sensor_config & LTC2983_THERMISTOR_DIFF_MASK) && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, - "Invalid chann:%d for differential thermistor\n", + return dev_err_ptr_probe(dev, -EINVAL, + "Invalid channel %d for differential thermistor\n", sensor->chan); /* check custom sensor */ @@ -949,22 +1076,18 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s thermistor->sensor.fault_handler = ltc2983_common_fault_handler; thermistor->sensor.assign_chan = ltc2983_thermistor_assign_chan; - ret = fwnode_property_read_u32(child, "adi,excitation-current-nanoamp", - &excitation_current); - if (ret) { - /* Auto range is not allowed for custom sensors */ - if (sensor->type >= LTC2983_SENSOR_THERMISTOR_STEINHART) - /* default to 1uA */ - thermistor->excitation_current = 0x03; - else - /* default to auto-range */ - thermistor->excitation_current = 0x0c; - } else { + if (fwnode_property_present(child, "adi,excitation-current-nanoamp")) { + ret = fwnode_property_read_u32(child, "adi,excitation-current-nanoamp", + &excitation_current); + if (ret) + return dev_err_ptr_probe(dev, ret, + "Failed to read adi,excitation-current-nanoamp\n"); + switch (excitation_current) { case 0: /* auto range */ if (sensor->type >= LTC2983_SENSOR_THERMISTOR_STEINHART) - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + return dev_err_ptr_probe(dev, -EINVAL, "Auto Range not allowed for custom sensors\n"); thermistor->excitation_current = 0x0c; @@ -1003,24 +1126,222 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s thermistor->excitation_current = 0x0b; break; default: - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + return dev_err_ptr_probe(dev, -EINVAL, "Invalid value for excitation current(%u)\n", excitation_current); } + } else { + /* Auto range is not allowed for custom sensors */ + if (sensor->type >= LTC2983_SENSOR_THERMISTOR_STEINHART) + /* default to 1uA */ + thermistor->excitation_current = 0x03; + else + /* default to auto-range */ + thermistor->excitation_current = 0x0c; } return &thermistor->sensor; } static struct ltc2983_sensor * +ltc2983_copper_trace_new(const struct fwnode_handle *child, struct ltc2983_data *st, + const struct ltc2983_sensor *sensor) +{ + struct device *dev = &st->spi->dev; + struct ltc2983_copper_trace *ct; + int ret; + + if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) + return dev_err_ptr_probe(dev, -EINVAL, + "Invalid channel %d for copper trace\n", + sensor->chan); + + ct = devm_kzalloc(dev, sizeof(*ct), GFP_KERNEL); + if (!ct) + return ERR_PTR(-ENOMEM); + + struct fwnode_handle *ref __free(fwnode_handle) = + fwnode_find_reference(child, "adi,rsense-handle", 0); + if (IS_ERR(ref)) + return dev_err_cast_probe(dev, ref, + "Property adi,rsense-handle missing or invalid\n"); + + ret = fwnode_property_read_u32(ref, "reg", &ct->r_sense_chan); + if (ret) + return dev_err_ptr_probe(dev, ret, "Property reg must be given\n"); + + ct->is_sub_ohm = fwnode_property_read_bool(child, "adi,copper-trace-sub-ohm"); + + if (ct->is_sub_ohm && fwnode_property_present(child, "adi,custom-copper-trace")) + return dev_err_ptr_probe(dev, -EINVAL, + "sub-ohm copper trace cannot have a custom table\n"); + + if (!ct->is_sub_ohm) { + u32 excitation_current = 0; + + if (!fwnode_property_present(child, "adi,custom-copper-trace")) + return dev_err_ptr_probe(dev, -EINVAL, + "adi,custom-copper-trace is required for >1 ohm copper trace\n"); + + ct->custom = __ltc2983_custom_sensor_new(st, child, "adi,custom-copper-trace", + false, 2048, false); + if (IS_ERR(ct->custom)) + return ERR_CAST(ct->custom); + + if (fwnode_property_present(child, "adi,excitation-current-microamp")) { + ret = fwnode_property_read_u32(child, "adi,excitation-current-microamp", + &excitation_current); + if (ret) + return dev_err_ptr_probe(dev, ret, + "Failed to read adi,excitation-current-microamp\n"); + + switch (excitation_current) { + case 5: + ct->excitation_current = 0x01; + break; + case 10: + ct->excitation_current = 0x02; + break; + case 25: + ct->excitation_current = 0x03; + break; + case 50: + ct->excitation_current = 0x04; + break; + case 100: + ct->excitation_current = 0x05; + break; + case 250: + ct->excitation_current = 0x06; + break; + case 500: + ct->excitation_current = 0x07; + break; + case 1000: + ct->excitation_current = 0x08; + break; + default: + return dev_err_ptr_probe(dev, -EINVAL, + "Invalid value for excitation current(%u)\n", + excitation_current); + } + } else { + /* default to 1mA per datasheet recommendation for copper trace */ + ct->excitation_current = 0x08; + } + } + + ct->sensor.fault_handler = ltc2983_common_fault_handler; + ct->sensor.assign_chan = ltc2983_copper_trace_assign_chan; + if (ct->is_sub_ohm) + ct->sensor.n_iio_chan = 1; + else + ct->sensor.n_iio_chan = 2; + + return &ct->sensor; +} + +static struct ltc2983_sensor * +ltc2983_leak_detector_new(const struct fwnode_handle *child, struct ltc2983_data *st, + const struct ltc2983_sensor *sensor) +{ + struct device *dev = &st->spi->dev; + struct ltc2983_leak_detector *ld; + int ret; + u32 excitation_current = 0; + + if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) + return dev_err_ptr_probe(dev, -EINVAL, + "Invalid channel %d for leak detector\n", + sensor->chan); + + ld = devm_kzalloc(dev, sizeof(*ld), GFP_KERNEL); + if (!ld) + return ERR_PTR(-ENOMEM); + + struct fwnode_handle *ref __free(fwnode_handle) = + fwnode_find_reference(child, "adi,rsense-handle", 0); + if (IS_ERR(ref)) + return dev_err_cast_probe(dev, ref, + "Property adi,rsense-handle missing or invalid\n"); + + ret = fwnode_property_read_u32(ref, "reg", &ld->r_sense_chan); + if (ret) + return dev_err_ptr_probe(dev, ret, + "rsense channel must be configured\n"); + + if (!fwnode_property_present(child, "adi,custom-leak-detector")) + return dev_err_ptr_probe(dev, -EINVAL, + "adi,custom-leak-detector is required for leak detectors\n"); + + ld->custom = __ltc2983_custom_sensor_new(st, child, "adi,custom-leak-detector", + false, 16, false); + if (IS_ERR(ld->custom)) + return ERR_CAST(ld->custom); + + ret = fwnode_property_read_u32(child, "adi,excitation-current-nanoamp", + &excitation_current); + if (ret) + return dev_err_ptr_probe(dev, ret, + "adi,excitation-current-nanoamp is required for leak detectors\n"); + + switch (excitation_current) { + case 250: + ld->excitation_current = 0x01; + break; + case 500: + ld->excitation_current = 0x02; + break; + case 1000: + ld->excitation_current = 0x03; + break; + case 5000: + ld->excitation_current = 0x04; + break; + case 10000: + ld->excitation_current = 0x05; + break; + case 25000: + ld->excitation_current = 0x06; + break; + case 50000: + ld->excitation_current = 0x07; + break; + case 100000: + ld->excitation_current = 0x08; + break; + case 250000: + ld->excitation_current = 0x09; + break; + case 500000: + ld->excitation_current = 0x0a; + break; + case 1000000: + ld->excitation_current = 0x0b; + break; + default: + return dev_err_ptr_probe(dev, -EINVAL, + "Invalid value for excitation current(%u)\n", + excitation_current); + } + + ld->sensor.fault_handler = ltc2983_common_fault_handler; + ld->sensor.assign_chan = ltc2983_leak_detector_assign_chan; + ld->sensor.n_iio_chan = 2; + + return &ld->sensor; +} + +static struct ltc2983_sensor * ltc2983_diode_new(const struct fwnode_handle *child, const struct ltc2983_data *st, const struct ltc2983_sensor *sensor) { + struct device *dev = &st->spi->dev; struct ltc2983_diode *diode; u32 temp = 0, excitation_current = 0; int ret; - diode = devm_kzalloc(&st->spi->dev, sizeof(*diode), GFP_KERNEL); + diode = devm_kzalloc(dev, sizeof(*diode), GFP_KERNEL); if (!diode) return ERR_PTR(-ENOMEM); @@ -1036,17 +1357,21 @@ ltc2983_diode_new(const struct fwnode_handle *child, const struct ltc2983_data * /* validate channel index */ if (!(diode->sensor_config & LTC2983_DIODE_DIFF_MASK) && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, - "Invalid chann:%d for differential thermistor\n", + return dev_err_ptr_probe(dev, -EINVAL, + "Invalid channel %d for differential diode\n", sensor->chan); /* set common parameters */ diode->sensor.fault_handler = ltc2983_common_fault_handler; diode->sensor.assign_chan = ltc2983_diode_assign_chan; - ret = fwnode_property_read_u32(child, "adi,excitation-current-microamp", - &excitation_current); - if (!ret) { + if (fwnode_property_present(child, "adi,excitation-current-microamp")) { + ret = fwnode_property_read_u32(child, "adi,excitation-current-microamp", + &excitation_current); + if (ret) + return dev_err_ptr_probe(dev, ret, + "Failed to read adi,excitation-current-microamp\n"); + switch (excitation_current) { case 10: diode->excitation_current = 0x00; @@ -1061,13 +1386,18 @@ ltc2983_diode_new(const struct fwnode_handle *child, const struct ltc2983_data * diode->excitation_current = 0x03; break; default: - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + return dev_err_ptr_probe(dev, -EINVAL, "Invalid value for excitation current(%u)\n", excitation_current); } } - fwnode_property_read_u32(child, "adi,ideal-factor-value", &temp); + if (fwnode_property_present(child, "adi,ideal-factor-value")) { + ret = fwnode_property_read_u32(child, "adi,ideal-factor-value", &temp); + if (ret) + return dev_err_ptr_probe(dev, ret, + "Failed to read adi,ideal-factor-value\n"); + } /* 2^20 resolution */ diode->ideal_factor_value = __convert_to_raw(temp, 1048576); @@ -1079,23 +1409,24 @@ static struct ltc2983_sensor *ltc2983_r_sense_new(struct fwnode_handle *child, struct ltc2983_data *st, const struct ltc2983_sensor *sensor) { + struct device *dev = &st->spi->dev; struct ltc2983_rsense *rsense; int ret; u32 temp; - rsense = devm_kzalloc(&st->spi->dev, sizeof(*rsense), GFP_KERNEL); + rsense = devm_kzalloc(dev, sizeof(*rsense), GFP_KERNEL); if (!rsense) return ERR_PTR(-ENOMEM); /* validate channel index */ if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, - "Invalid chann:%d for r_sense\n", + return dev_err_ptr_probe(dev, -EINVAL, + "Invalid channel %d for r_sense\n", sensor->chan); ret = fwnode_property_read_u32(child, "adi,rsense-val-milli-ohms", &temp); if (ret) - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + return dev_err_ptr_probe(dev, -EINVAL, "Property adi,rsense-val-milli-ohms missing\n"); /* * Times 1000 because we have milli-ohms and __convert_to_raw @@ -1115,9 +1446,10 @@ static struct ltc2983_sensor *ltc2983_adc_new(struct fwnode_handle *child, struct ltc2983_data *st, const struct ltc2983_sensor *sensor) { + struct device *dev = &st->spi->dev; struct ltc2983_adc *adc; - adc = devm_kzalloc(&st->spi->dev, sizeof(*adc), GFP_KERNEL); + adc = devm_kzalloc(dev, sizeof(*adc), GFP_KERNEL); if (!adc) return ERR_PTR(-ENOMEM); @@ -1125,8 +1457,8 @@ static struct ltc2983_sensor *ltc2983_adc_new(struct fwnode_handle *child, adc->single_ended = true; if (!adc->single_ended && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, - "Invalid chan:%d for differential adc\n", + return dev_err_ptr_probe(dev, -EINVAL, + "Invalid channel %d for differential ADC\n", sensor->chan); /* set common parameters */ @@ -1140,9 +1472,10 @@ static struct ltc2983_sensor *ltc2983_temp_new(struct fwnode_handle *child, struct ltc2983_data *st, const struct ltc2983_sensor *sensor) { + struct device *dev = &st->spi->dev; struct ltc2983_temp *temp; - temp = devm_kzalloc(&st->spi->dev, sizeof(*temp), GFP_KERNEL); + temp = devm_kzalloc(dev, sizeof(*temp), GFP_KERNEL); if (!temp) return ERR_PTR(-ENOMEM); @@ -1150,8 +1483,8 @@ static struct ltc2983_sensor *ltc2983_temp_new(struct fwnode_handle *child, temp->single_ended = true; if (!temp->single_ended && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, - "Invalid chan:%d for differential temp\n", + return dev_err_ptr_probe(dev, -EINVAL, + "Invalid channel %d for differential temp\n", sensor->chan); temp->custom = __ltc2983_custom_sensor_new(st, child, "adi,custom-temp", @@ -1167,22 +1500,23 @@ static struct ltc2983_sensor *ltc2983_temp_new(struct fwnode_handle *child, } static int ltc2983_chan_read(struct ltc2983_data *st, - const struct ltc2983_sensor *sensor, int *val) + const struct ltc2983_sensor *sensor, + u32 base_reg, int *val) { + struct device *dev = &st->spi->dev; u32 start_conversion = 0; int ret; unsigned long time; start_conversion = LTC2983_STATUS_START(true); start_conversion |= LTC2983_STATUS_CHAN_SEL(sensor->chan); - dev_dbg(&st->spi->dev, "Start conversion on chan:%d, status:%02X\n", + dev_dbg(dev, "Start conversion on channel:%d, status:%02X\n", sensor->chan, start_conversion); + reinit_completion(&st->completion); /* start conversion */ ret = regmap_write(st->regmap, LTC2983_STATUS_REG, start_conversion); if (ret) return ret; - - reinit_completion(&st->completion); /* * wait for conversion to complete. * 300 ms should be more than enough to complete the conversion. @@ -1192,20 +1526,30 @@ static int ltc2983_chan_read(struct ltc2983_data *st, time = wait_for_completion_timeout(&st->completion, msecs_to_jiffies(300)); if (!time) { - dev_warn(&st->spi->dev, "Conversion timed out\n"); + dev_warn(dev, "Conversion timed out\n"); return -ETIMEDOUT; } /* read the converted data */ - ret = regmap_bulk_read(st->regmap, LTC2983_CHAN_RES_ADDR(sensor->chan), + ret = regmap_bulk_read(st->regmap, LTC2983_RESULT_ADDR(sensor->chan, base_reg), &st->temp, sizeof(st->temp)); if (ret) return ret; *val = __be32_to_cpu(st->temp); + if (base_reg == ADT7604_RES_RES_START_REG) { + /* + * Resistance result register gives a plain unsigned value, + * D31 is always 0, no valid bit, no fault bits. Read bits[30:0] + * directly — the temperature result format does not apply here. + */ + *val &= GENMASK(30, 0); + return 0; + } + if (!(LTC2983_RES_VALID_MASK & *val)) { - dev_err(&st->spi->dev, "Invalid conversion detected\n"); + dev_err(dev, "Invalid conversion detected\n"); return -EIO; } @@ -1222,19 +1566,28 @@ static int ltc2983_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct ltc2983_data *st = iio_priv(indio_dev); + struct device *dev = &st->spi->dev; int ret; /* sanity check */ if (chan->address >= st->num_channels) { - dev_err(&st->spi->dev, "Invalid chan address:%ld", - chan->address); + dev_err(dev, "Invalid channel address: %ld\n", chan->address); return -EINVAL; } switch (mask) { case IIO_CHAN_INFO_RAW: mutex_lock(&st->lock); - ret = ltc2983_chan_read(st, st->sensors[chan->address], val); + switch (chan->type) { + case IIO_RESISTANCE: + ret = ltc2983_chan_read(st, st->sensors[chan->address], + ADT7604_RES_RES_START_REG, val); + break; + default: + ret = ltc2983_chan_read(st, st->sensors[chan->address], + LTC2983_TEMP_RES_START_REG, val); + break; + } mutex_unlock(&st->lock); return ret ?: IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: @@ -1251,6 +1604,13 @@ static int ltc2983_read_raw(struct iio_dev *indio_dev, /* 2^21 */ *val2 = 2097152; return IIO_VAL_FRACTIONAL; + case IIO_RESISTANCE: + case IIO_COVERAGE: + /* value in ohm/percent */ + *val = 1; + /* 2^10 */ + *val2 = 1024; + return IIO_VAL_FRACTIONAL; default: return -EINVAL; } @@ -1303,7 +1663,7 @@ static int ltc2983_parse_fw(struct ltc2983_data *st) st->num_channels = device_get_child_node_count(dev); if (!st->num_channels) - return dev_err_probe(&st->spi->dev, -EINVAL, + return dev_err_probe(dev, -EINVAL, "At least one channel must be given!\n"); st->sensors = devm_kcalloc(dev, st->num_channels, sizeof(*st->sensors), @@ -1311,7 +1671,7 @@ static int ltc2983_parse_fw(struct ltc2983_data *st) if (!st->sensors) return -ENOMEM; - st->iio_channels = st->num_channels; + st->iio_channels = 0; device_for_each_child_node_scoped(dev, child) { struct ltc2983_sensor sensor; @@ -1324,14 +1684,14 @@ static int ltc2983_parse_fw(struct ltc2983_data *st) if (sensor.chan < LTC2983_MIN_CHANNELS_NR || sensor.chan > st->info->max_channels_nr) return dev_err_probe(dev, -EINVAL, - "chan:%d must be from %u to %u\n", + "channel:%d must be from %u to %u\n", sensor.chan, LTC2983_MIN_CHANNELS_NR, st->info->max_channels_nr); if (channel_avail_mask & BIT(sensor.chan)) return dev_err_probe(dev, -EINVAL, - "chan:%d already in use\n", + "channel:%d already in use\n", sensor.chan); ret = fwnode_property_read_u32(child, "adi,sensor-type", &sensor.type); @@ -1339,7 +1699,13 @@ static int ltc2983_parse_fw(struct ltc2983_data *st) return dev_err_probe(dev, ret, "adi,sensor-type property must given for child nodes\n"); - dev_dbg(dev, "Create new sensor, type %u, chann %u", + if (sensor.type >= LTC2983_SENSOR_NUM || + !(st->info->supported_sensors & BIT_ULL(sensor.type))) + return dev_err_probe(dev, -EINVAL, + "sensor type %d not supported on %s\n", + sensor.type, st->info->name); + + dev_dbg(dev, "Create new sensor, type %u, channel %u", sensor.type, sensor.chan); if (sensor.type >= LTC2983_SENSOR_THERMOCOUPLE && @@ -1359,13 +1725,14 @@ static int ltc2983_parse_fw(struct ltc2983_data *st) } else if (sensor.type == LTC2983_SENSOR_SENSE_RESISTOR) { st->sensors[chan] = ltc2983_r_sense_new(child, st, &sensor); - /* don't add rsense to iio */ - st->iio_channels--; } else if (sensor.type == LTC2983_SENSOR_DIRECT_ADC) { st->sensors[chan] = ltc2983_adc_new(child, st, &sensor); - } else if (st->info->has_temp && - sensor.type == LTC2983_SENSOR_ACTIVE_TEMP) { + } else if (sensor.type == LTC2983_SENSOR_ACTIVE_TEMP) { st->sensors[chan] = ltc2983_temp_new(child, st, &sensor); + } else if (sensor.type == LTC2983_SENSOR_COPPER_TRACE) { + st->sensors[chan] = ltc2983_copper_trace_new(child, st, &sensor); + } else if (sensor.type == LTC2983_SENSOR_LEAK_DETECTOR) { + st->sensors[chan] = ltc2983_leak_detector_new(child, st, &sensor); } else { return dev_err_probe(dev, -EINVAL, "Unknown sensor type %d\n", @@ -1380,6 +1747,16 @@ static int ltc2983_parse_fw(struct ltc2983_data *st) st->sensors[chan]->chan = sensor.chan; st->sensors[chan]->type = sensor.type; + /* + * Dedicated functions set n_iio_chan themselves; for all other + * sensor types rsense produces 0 channels, everything else 1. + */ + if (!st->sensors[chan]->n_iio_chan) { + if (sensor.type != LTC2983_SENSOR_SENSE_RESISTOR) + st->sensors[chan]->n_iio_chan = 1; + } + st->iio_channels += st->sensors[chan]->n_iio_chan; + channel_avail_mask |= BIT(sensor.chan); chan++; } @@ -1391,6 +1768,7 @@ static int ltc2983_eeprom_cmd(struct ltc2983_data *st, unsigned int cmd, unsigned int wait_time, unsigned int status_reg, unsigned long status_fail_mask) { + struct device *dev = &st->spi->dev; unsigned long time; unsigned int val; int ret; @@ -1410,7 +1788,7 @@ static int ltc2983_eeprom_cmd(struct ltc2983_data *st, unsigned int cmd, time = wait_for_completion_timeout(&st->completion, msecs_to_jiffies(wait_time)); if (!time) - return dev_err_probe(&st->spi->dev, -ETIMEDOUT, + return dev_err_probe(dev, -ETIMEDOUT, "EEPROM command timed out\n"); ret = regmap_read(st->regmap, status_reg, &val); @@ -1418,7 +1796,7 @@ static int ltc2983_eeprom_cmd(struct ltc2983_data *st, unsigned int cmd, return ret; if (val & status_fail_mask) - return dev_err_probe(&st->spi->dev, -EINVAL, + return dev_err_probe(dev, -EINVAL, "EEPROM command failed: 0x%02X\n", val); return 0; @@ -1426,7 +1804,9 @@ static int ltc2983_eeprom_cmd(struct ltc2983_data *st, unsigned int cmd, static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio) { - u32 iio_chan_t = 0, iio_chan_v = 0, chan, iio_idx = 0, status; + struct device *dev = &st->spi->dev; + u32 iio_chan_t = 0, iio_chan_v = 0, iio_chan_r = 0, iio_chan_c = 0; + u32 chan, iio_idx = 0, status; int ret; /* make sure the device is up: start bit (7) is 0 and done bit (6) is 1 */ @@ -1434,8 +1814,7 @@ static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio) LTC2983_STATUS_UP(status) == 1, 25000, 25000 * 10); if (ret) - return dev_err_probe(&st->spi->dev, ret, - "Device startup timed out\n"); + return dev_err_probe(dev, ret, "Device startup timed out\n"); ret = regmap_update_bits(st->regmap, LTC2983_GLOBAL_CONFIG_REG, LTC2983_NOTCH_FREQ_MASK, @@ -1474,12 +1853,33 @@ static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio) continue; /* assign iio channel */ - if (st->sensors[chan]->type != LTC2983_SENSOR_DIRECT_ADC) { - chan_type = IIO_TEMP; - iio_chan = &iio_chan_t; - } else { + switch (st->sensors[chan]->type) { + case LTC2983_SENSOR_COPPER_TRACE: + if (st->sensors[chan]->n_iio_chan == 1) { + /* sub-ohm copper traces produce only a resistance result */ + st->iio_chan[iio_idx++] = + LTC2983_CHAN(IIO_RESISTANCE, iio_chan_r++, chan); + } else { + st->iio_chan[iio_idx++] = + LTC2983_CHAN(IIO_TEMP, iio_chan_t++, chan); + st->iio_chan[iio_idx++] = + LTC2983_CHAN(IIO_RESISTANCE, iio_chan_r++, chan); + } + continue; + case LTC2983_SENSOR_LEAK_DETECTOR: + st->iio_chan[iio_idx++] = + LTC2983_CHAN(IIO_COVERAGE, iio_chan_c++, chan); + st->iio_chan[iio_idx++] = + LTC2983_CHAN(IIO_RESISTANCE, iio_chan_r++, chan); + continue; + case LTC2983_SENSOR_DIRECT_ADC: chan_type = IIO_VOLTAGE; iio_chan = &iio_chan_v; + break; + default: + chan_type = IIO_TEMP; + iio_chan = &iio_chan_t; + break; } /* @@ -1496,6 +1896,7 @@ static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio) static const struct regmap_range ltc2983_reg_ranges[] = { regmap_reg_range(LTC2983_STATUS_REG, LTC2983_STATUS_REG), regmap_reg_range(LTC2983_TEMP_RES_START_REG, LTC2983_TEMP_RES_END_REG), + regmap_reg_range(ADT7604_RES_RES_START_REG, ADT7604_RES_RES_END_REG), regmap_reg_range(LTC2983_EEPROM_KEY_REG, LTC2983_EEPROM_KEY_REG), regmap_reg_range(LTC2983_EEPROM_READ_STATUS_REG, LTC2983_EEPROM_READ_STATUS_REG), @@ -1535,12 +1936,13 @@ static const struct iio_info ltc2983_iio_info = { static int ltc2983_probe(struct spi_device *spi) { + struct device *dev = &spi->dev; struct ltc2983_data *st; struct iio_dev *indio_dev; struct gpio_desc *gpio; int ret; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; @@ -1552,7 +1954,7 @@ static int ltc2983_probe(struct spi_device *spi) st->regmap = devm_regmap_init_spi(spi, <c2983_regmap_config); if (IS_ERR(st->regmap)) - return dev_err_probe(&spi->dev, PTR_ERR(st->regmap), + return dev_err_probe(dev, PTR_ERR(st->regmap), "Failed to initialize regmap\n"); mutex_init(&st->lock); @@ -1565,11 +1967,11 @@ static int ltc2983_probe(struct spi_device *spi) if (ret) return ret; - ret = devm_regulator_get_enable(&spi->dev, "vdd"); + ret = devm_regulator_get_enable(dev, "vdd"); if (ret) return ret; - gpio = devm_gpiod_get_optional(&st->spi->dev, "reset", GPIOD_OUT_HIGH); + gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(gpio)) return PTR_ERR(gpio); @@ -1579,7 +1981,7 @@ static int ltc2983_probe(struct spi_device *spi) gpiod_set_value_cansleep(gpio, 0); } - st->iio_chan = devm_kzalloc(&spi->dev, + st->iio_chan = devm_kzalloc(dev, st->iio_channels * sizeof(*st->iio_chan), GFP_KERNEL); if (!st->iio_chan) @@ -1589,11 +1991,10 @@ static int ltc2983_probe(struct spi_device *spi) if (ret) return ret; - ret = devm_request_irq(&spi->dev, spi->irq, ltc2983_irq_handler, + ret = devm_request_irq(dev, spi->irq, ltc2983_irq_handler, IRQF_TRIGGER_RISING, st->info->name, st); if (ret) - return dev_err_probe(&spi->dev, ret, - "failed to request an irq\n"); + return ret; if (st->info->has_eeprom) { ret = ltc2983_eeprom_cmd(st, LTC2983_EEPROM_WRITE_CMD, @@ -1610,7 +2011,7 @@ static int ltc2983_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = <c2983_iio_info; - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static int ltc2983_resume(struct device *dev) @@ -1634,41 +2035,52 @@ static int ltc2983_suspend(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(ltc2983_pm_ops, ltc2983_suspend, ltc2983_resume); +static const struct ltc2983_chip_info adt7604_chip_info_data = { + .name = "adt7604", + .max_channels_nr = 20, + .has_eeprom = true, + .supported_sensors = ADT7604_SENSORS, +}; + static const struct ltc2983_chip_info ltc2983_chip_info_data = { .name = "ltc2983", .max_channels_nr = 20, + .supported_sensors = LTC2983_COMMON_SENSORS, }; static const struct ltc2983_chip_info ltc2984_chip_info_data = { .name = "ltc2984", .max_channels_nr = 20, .has_eeprom = true, + .supported_sensors = LTC2983_COMMON_SENSORS, }; static const struct ltc2983_chip_info ltc2986_chip_info_data = { .name = "ltc2986", .max_channels_nr = 10, - .has_temp = true, .has_eeprom = true, + .supported_sensors = LTC2983_COMMON_SENSORS | BIT_ULL(LTC2983_SENSOR_ACTIVE_TEMP), }; static const struct ltc2983_chip_info ltm2985_chip_info_data = { .name = "ltm2985", .max_channels_nr = 10, - .has_temp = true, .has_eeprom = true, + .supported_sensors = LTC2983_COMMON_SENSORS | BIT_ULL(LTC2983_SENSOR_ACTIVE_TEMP), }; static const struct spi_device_id ltc2983_id_table[] = { - { "ltc2983", (kernel_ulong_t)<c2983_chip_info_data }, - { "ltc2984", (kernel_ulong_t)<c2984_chip_info_data }, - { "ltc2986", (kernel_ulong_t)<c2986_chip_info_data }, - { "ltm2985", (kernel_ulong_t)<m2985_chip_info_data }, + { .name = "adt7604", .driver_data = (kernel_ulong_t)&adt7604_chip_info_data }, + { .name = "ltc2983", .driver_data = (kernel_ulong_t)<c2983_chip_info_data }, + { .name = "ltc2984", .driver_data = (kernel_ulong_t)<c2984_chip_info_data }, + { .name = "ltc2986", .driver_data = (kernel_ulong_t)<c2986_chip_info_data }, + { .name = "ltm2985", .driver_data = (kernel_ulong_t)<m2985_chip_info_data }, { } }; MODULE_DEVICE_TABLE(spi, ltc2983_id_table); static const struct of_device_id ltc2983_of_match[] = { + { .compatible = "adi,adt7604", .data = &adt7604_chip_info_data }, { .compatible = "adi,ltc2983", .data = <c2983_chip_info_data }, { .compatible = "adi,ltc2984", .data = <c2984_chip_info_data }, { .compatible = "adi,ltc2986", .data = <c2986_chip_info_data }, diff --git a/drivers/iio/temperature/max30208.c b/drivers/iio/temperature/max30208.c index 720469f9dc36..6172abc6d533 100644 --- a/drivers/iio/temperature/max30208.c +++ b/drivers/iio/temperature/max30208.c @@ -218,7 +218,7 @@ static int max30208_probe(struct i2c_client *i2c) } static const struct i2c_device_id max30208_id_table[] = { - { "max30208" }, + { .name = "max30208" }, { } }; MODULE_DEVICE_TABLE(i2c, max30208_id_table); diff --git a/drivers/iio/temperature/max31856.c b/drivers/iio/temperature/max31856.c index 7ddec5cbe558..061f6fe6de5e 100644 --- a/drivers/iio/temperature/max31856.c +++ b/drivers/iio/temperature/max31856.c @@ -7,7 +7,6 @@ */ #include <linux/ctype.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/init.h> #include <linux/err.h> @@ -462,7 +461,7 @@ static int max31856_probe(struct spi_device *spi) } static const struct spi_device_id max31856_id[] = { - { "max31856", 0 }, + { .name = "max31856" }, { } }; MODULE_DEVICE_TABLE(spi, max31856_id); diff --git a/drivers/iio/temperature/max31865.c b/drivers/iio/temperature/max31865.c index 5a6fbe3c80e5..f9c93f95d80b 100644 --- a/drivers/iio/temperature/max31865.c +++ b/drivers/iio/temperature/max31865.c @@ -12,7 +12,6 @@ #include <linux/delay.h> #include <linux/err.h> #include <linux/init.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -325,7 +324,7 @@ static int max31865_probe(struct spi_device *spi) } static const struct spi_device_id max31865_id[] = { - { "max31865", 0 }, + { .name = "max31865" }, { } }; MODULE_DEVICE_TABLE(spi, max31865_id); diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c index 205939680fd4..5f216e238d55 100644 --- a/drivers/iio/temperature/maxim_thermocouple.c +++ b/drivers/iio/temperature/maxim_thermocouple.c @@ -7,7 +7,6 @@ */ #include <linux/init.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/err.h> #include <linux/spi/spi.h> @@ -263,22 +262,22 @@ static int maxim_thermocouple_probe(struct spi_device *spi) } static const struct spi_device_id maxim_thermocouple_id[] = { - {"max6675", MAX6675}, - {"max31855", MAX31855}, - {"max31855k", MAX31855K}, - {"max31855j", MAX31855J}, - {"max31855n", MAX31855N}, - {"max31855s", MAX31855S}, - {"max31855t", MAX31855T}, - {"max31855e", MAX31855E}, - {"max31855r", MAX31855R}, + { .name = "max6675", .driver_data = MAX6675 }, + { .name = "max31855", .driver_data = MAX31855 }, + { .name = "max31855k", .driver_data = MAX31855K }, + { .name = "max31855j", .driver_data = MAX31855J }, + { .name = "max31855n", .driver_data = MAX31855N }, + { .name = "max31855s", .driver_data = MAX31855S }, + { .name = "max31855t", .driver_data = MAX31855T }, + { .name = "max31855e", .driver_data = MAX31855E }, + { .name = "max31855r", .driver_data = MAX31855R }, { } }; MODULE_DEVICE_TABLE(spi, maxim_thermocouple_id); static const struct of_device_id maxim_thermocouple_of_match[] = { - { .compatible = "maxim,max6675" }, - { .compatible = "maxim,max31855" }, + { .compatible = "maxim,max6675" }, + { .compatible = "maxim,max31855" }, { .compatible = "maxim,max31855k" }, { .compatible = "maxim,max31855j" }, { .compatible = "maxim,max31855n" }, @@ -286,7 +285,7 @@ static const struct of_device_id maxim_thermocouple_of_match[] = { { .compatible = "maxim,max31855t" }, { .compatible = "maxim,max31855e" }, { .compatible = "maxim,max31855r" }, - { }, + { }, }; MODULE_DEVICE_TABLE(of, maxim_thermocouple_of_match); diff --git a/drivers/iio/temperature/mcp9600.c b/drivers/iio/temperature/mcp9600.c index aa42c2b1a369..b0ff0c7b4891 100644 --- a/drivers/iio/temperature/mcp9600.c +++ b/drivers/iio/temperature/mcp9600.c @@ -16,7 +16,6 @@ #include <linux/irq.h> #include <linux/math.h> #include <linux/minmax.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/iio/events.h> @@ -297,7 +296,7 @@ static int mcp9600_read_thresh(struct iio_dev *indio_dev, * Temperature is stored in two’s complement format in * bits(15:2), LSB is 0.25 degree celsius. */ - *val = sign_extend32(FIELD_GET(MCP9600_ALERT_LIMIT_MASK, ret), 13); + *val = FIELD_GET_SIGNED(MCP9600_ALERT_LIMIT_MASK, ret); *val2 = 4; return IIO_VAL_FRACTIONAL; case IIO_EV_INFO_HYSTERESIS: @@ -551,8 +550,8 @@ static const struct mcp_chip_info mcp9601_chip_info = { }; static const struct i2c_device_id mcp9600_id[] = { - { "mcp9600", .driver_data = (kernel_ulong_t)&mcp9600_chip_info }, - { "mcp9601", .driver_data = (kernel_ulong_t)&mcp9601_chip_info }, + { .name = "mcp9600", .driver_data = (kernel_ulong_t)&mcp9600_chip_info }, + { .name = "mcp9601", .driver_data = (kernel_ulong_t)&mcp9601_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, mcp9600_id); diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c index 1ad21b73e1b4..27d6ab5f5d7a 100644 --- a/drivers/iio/temperature/mlx90614.c +++ b/drivers/iio/temperature/mlx90614.c @@ -28,7 +28,6 @@ #include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/jiffies.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/pm_runtime.h> @@ -699,8 +698,8 @@ static const struct mlx_chip_info mlx90615_chip_info = { }; static const struct i2c_device_id mlx90614_id[] = { - { "mlx90614", .driver_data = (kernel_ulong_t)&mlx90614_chip_info }, - { "mlx90615", .driver_data = (kernel_ulong_t)&mlx90615_chip_info }, + { .name = "mlx90614", .driver_data = (kernel_ulong_t)&mlx90614_chip_info }, + { .name = "mlx90615", .driver_data = (kernel_ulong_t)&mlx90615_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, mlx90614_id); diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c index b44f7036c2cc..2fde48f337e2 100644 --- a/drivers/iio/temperature/mlx90632.c +++ b/drivers/iio/temperature/mlx90632.c @@ -16,7 +16,6 @@ #include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/limits.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/math64.h> #include <linux/pm_runtime.h> @@ -1276,7 +1275,7 @@ static int mlx90632_probe(struct i2c_client *client) } static const struct i2c_device_id mlx90632_id[] = { - { "mlx90632" }, + { .name = "mlx90632" }, { } }; MODULE_DEVICE_TABLE(i2c, mlx90632_id); diff --git a/drivers/iio/temperature/mlx90635.c b/drivers/iio/temperature/mlx90635.c index 1c8948ca54df..0f31879a4f64 100644 --- a/drivers/iio/temperature/mlx90635.c +++ b/drivers/iio/temperature/mlx90635.c @@ -16,7 +16,6 @@ #include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/limits.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/math64.h> #include <linux/pm_runtime.h> @@ -1026,7 +1025,7 @@ static int mlx90635_probe(struct i2c_client *client) } static const struct i2c_device_id mlx90635_id[] = { - { "mlx90635" }, + { .name = "mlx90635" }, { } }; MODULE_DEVICE_TABLE(i2c, mlx90635_id); diff --git a/drivers/iio/temperature/tmp006.c b/drivers/iio/temperature/tmp006.c index d8d8c8936d17..d9f6449ec0d8 100644 --- a/drivers/iio/temperature/tmp006.c +++ b/drivers/iio/temperature/tmp006.c @@ -13,7 +13,6 @@ #include <linux/i2c.h> #include <linux/delay.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/pm.h> #include <linux/bitops.h> @@ -350,7 +349,7 @@ static int tmp006_probe(struct i2c_client *client) data->drdy_trig->ops = &tmp006_trigger_ops; iio_trigger_set_drvdata(data->drdy_trig, indio_dev); - ret = iio_trigger_register(data->drdy_trig); + ret = devm_iio_trigger_register(&client->dev, data->drdy_trig); if (ret) return ret; @@ -391,7 +390,7 @@ static const struct of_device_id tmp006_of_match[] = { MODULE_DEVICE_TABLE(of, tmp006_of_match); static const struct i2c_device_id tmp006_id[] = { - { "tmp006" }, + { .name = "tmp006" }, { } }; MODULE_DEVICE_TABLE(i2c, tmp006_id); diff --git a/drivers/iio/temperature/tmp007.c b/drivers/iio/temperature/tmp007.c index 043283b02c4d..4e743424f88e 100644 --- a/drivers/iio/temperature/tmp007.c +++ b/drivers/iio/temperature/tmp007.c @@ -20,7 +20,6 @@ #include <linux/module.h> #include <linux/pm.h> #include <linux/bitops.h> -#include <linux/mod_devicetable.h> #include <linux/irq.h> #include <linux/interrupt.h> @@ -528,10 +527,8 @@ static int tmp007_probe(struct i2c_client *client) NULL, tmp007_interrupt_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, tmp007_id->name, indio_dev); - if (ret) { - dev_err(&client->dev, "irq request error %d\n", -ret); + if (ret) return ret; - } } return devm_iio_device_register(&client->dev, indio_dev); @@ -563,7 +560,7 @@ static const struct of_device_id tmp007_of_match[] = { MODULE_DEVICE_TABLE(of, tmp007_of_match); static const struct i2c_device_id tmp007_id[] = { - { "tmp007" }, + { .name = "tmp007" }, { } }; MODULE_DEVICE_TABLE(i2c, tmp007_id); diff --git a/drivers/iio/temperature/tmp117.c b/drivers/iio/temperature/tmp117.c index 8972083d903a..74cb8d62bef3 100644 --- a/drivers/iio/temperature/tmp117.c +++ b/drivers/iio/temperature/tmp117.c @@ -9,6 +9,7 @@ * Note: This driver assumes that the sensor has been calibrated beforehand. */ +#include <linux/array_size.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/i2c.h> @@ -38,6 +39,7 @@ #define TMP116_DEVICE_ID 0x1116 #define TMP117_DEVICE_ID 0x0117 +#define TMP119_DEVICE_ID 0x2117 struct tmp117_data { struct i2c_client *client; @@ -139,6 +141,12 @@ static const struct tmp11x_info tmp117_channels_info = { .num_channels = ARRAY_SIZE(tmp117_channels) }; +static const struct tmp11x_info tmp119_channels_info = { + .name = "tmp119", + .channels = tmp117_channels, + .num_channels = ARRAY_SIZE(tmp117_channels) +}; + static const struct iio_info tmp117_info = { .read_raw = tmp117_read_raw, .write_raw = tmp117_write_raw, @@ -172,6 +180,9 @@ static int tmp117_probe(struct i2c_client *client) case TMP117_DEVICE_ID: match_data = &tmp117_channels_info; break; + case TMP119_DEVICE_ID: + match_data = &tmp119_channels_info; + break; default: dev_info(&client->dev, "Unknown device id (0x%x), use fallback compatible\n", @@ -204,13 +215,15 @@ static int tmp117_probe(struct i2c_client *client) static const struct of_device_id tmp117_of_match[] = { { .compatible = "ti,tmp116", .data = &tmp116_channels_info }, { .compatible = "ti,tmp117", .data = &tmp117_channels_info }, + { .compatible = "ti,tmp119", .data = &tmp119_channels_info }, { } }; MODULE_DEVICE_TABLE(of, tmp117_of_match); static const struct i2c_device_id tmp117_id[] = { - { "tmp116", (kernel_ulong_t)&tmp116_channels_info }, - { "tmp117", (kernel_ulong_t)&tmp117_channels_info }, + { .name = "tmp116", .driver_data = (kernel_ulong_t)&tmp116_channels_info }, + { .name = "tmp117", .driver_data = (kernel_ulong_t)&tmp117_channels_info }, + { .name = "tmp119", .driver_data = (kernel_ulong_t)&tmp119_channels_info }, { } }; MODULE_DEVICE_TABLE(i2c, tmp117_id); diff --git a/drivers/iio/temperature/tsys01.c b/drivers/iio/temperature/tsys01.c index 334bba6fdae6..28b3ce022ce7 100644 --- a/drivers/iio/temperature/tsys01.c +++ b/drivers/iio/temperature/tsys01.c @@ -13,7 +13,6 @@ #include <linux/device.h> #include <linux/mutex.h> #include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/stat.h> @@ -119,7 +118,7 @@ static bool tsys01_crc_valid(u16 *n_prom) u8 sum = 0; for (cnt = 0; cnt < TSYS01_PROM_WORDS_NB; cnt++) - sum += ((n_prom[0] >> 8) + (n_prom[0] & 0xFF)); + sum += ((n_prom[cnt] >> 8) + (n_prom[cnt] & 0xFF)); return (sum == 0); } @@ -206,7 +205,7 @@ static int tsys01_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id tsys01_id[] = { - { "tsys01" }, + { .name = "tsys01" }, { } }; MODULE_DEVICE_TABLE(i2c, tsys01_id); diff --git a/drivers/iio/temperature/tsys02d.c b/drivers/iio/temperature/tsys02d.c index 0cad27205667..3ef72347456e 100644 --- a/drivers/iio/temperature/tsys02d.c +++ b/drivers/iio/temperature/tsys02d.c @@ -168,7 +168,7 @@ static int tsys02d_probe(struct i2c_client *client) } static const struct i2c_device_id tsys02d_id[] = { - { "tsys02d" }, + { .name = "tsys02d" }, { } }; MODULE_DEVICE_TABLE(i2c, tsys02d_id); diff --git a/drivers/iio/test/iio-test-format.c b/drivers/iio/test/iio-test-format.c index 872dd8582003..e5d0a2ac4670 100644 --- a/drivers/iio/test/iio-test-format.c +++ b/drivers/iio/test/iio-test-format.c @@ -200,56 +200,108 @@ static void iio_test_iio_format_value_multiple(struct kunit *test) static void iio_test_iio_format_value_integer_64(struct kunit *test) { int values[2]; - s64 value; char *buf; int ret; buf = kunit_kmalloc(test, PAGE_SIZE, GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); - value = 24; - values[0] = lower_32_bits(value); - values[1] = upper_32_bits(value); + iio_val_s64_decompose(24, &values[0], &values[1]); ret = iio_format_value(buf, IIO_VAL_INT_64, ARRAY_SIZE(values), values); IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "24\n"); - value = -24; - values[0] = lower_32_bits(value); - values[1] = upper_32_bits(value); + iio_val_s64_decompose(-24, &values[0], &values[1]); ret = iio_format_value(buf, IIO_VAL_INT_64, ARRAY_SIZE(values), values); IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-24\n"); - value = 0; - values[0] = lower_32_bits(value); - values[1] = upper_32_bits(value); + iio_val_s64_decompose(0, &values[0], &values[1]); ret = iio_format_value(buf, IIO_VAL_INT_64, ARRAY_SIZE(values), values); IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0\n"); - value = UINT_MAX; - values[0] = lower_32_bits(value); - values[1] = upper_32_bits(value); + iio_val_s64_decompose(UINT_MAX, &values[0], &values[1]); ret = iio_format_value(buf, IIO_VAL_INT_64, ARRAY_SIZE(values), values); IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "4294967295\n"); - value = -((s64)UINT_MAX); - values[0] = lower_32_bits(value); - values[1] = upper_32_bits(value); + iio_val_s64_decompose(-((s64)UINT_MAX), &values[0], &values[1]); ret = iio_format_value(buf, IIO_VAL_INT_64, ARRAY_SIZE(values), values); IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-4294967295\n"); - value = LLONG_MAX; - values[0] = lower_32_bits(value); - values[1] = upper_32_bits(value); + iio_val_s64_decompose(LLONG_MAX, &values[0], &values[1]); ret = iio_format_value(buf, IIO_VAL_INT_64, ARRAY_SIZE(values), values); IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "9223372036854775807\n"); - value = LLONG_MIN; - values[0] = lower_32_bits(value); - values[1] = upper_32_bits(value); + iio_val_s64_decompose(LLONG_MIN, &values[0], &values[1]); ret = iio_format_value(buf, IIO_VAL_INT_64, ARRAY_SIZE(values), values); IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-9223372036854775808\n"); } +static void iio_test_iio_format_value_decimal_64(struct kunit *test) +{ + int values[2]; + char *buf; + int ret; + + buf = kunit_kmalloc(test, PAGE_SIZE, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); + + /* DECIMAL64_MILLI: positive >= 1, value 1.234 */ + iio_val_s64_decompose(1234, &values[0], &values[1]); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MILLI, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "1.234\n"); + + /* DECIMAL64_MICRO: positive >= 1, value 3.141592 */ + iio_val_s64_decompose(3141592, &values[0], &values[1]); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MICRO, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "3.141592\n"); + + /* DECIMAL64_MILLI: positive < 1, value 0.042 */ + iio_val_s64_decompose(42, &values[0], &values[1]); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MILLI, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0.042\n"); + + /* DECIMAL64_MILLI: negative <= -1, value -1.234 */ + iio_val_s64_decompose(-1234, &values[0], &values[1]); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MILLI, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-1.234\n"); + + /* DECIMAL64_MILLI: negative > -1, value -0.123 */ + iio_val_s64_decompose(-123, &values[0], &values[1]); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MILLI, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-0.123\n"); + + /* DECIMAL64_MILLI: zero */ + iio_val_s64_decompose(0, &values[0], &values[1]); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MILLI, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "0.000\n"); + + /* DECIMAL64_NANO: value 1.000000001 */ + iio_val_s64_decompose(1000000001, &values[0], &values[1]); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_NANO, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "1.000000001\n"); + + /* DECIMAL64_MICRO: large value using upper 32 bits */ + iio_val_s64_decompose(5000000000000042LL, &values[0], &values[1]); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MICRO, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "5000000000.000042\n"); + + /* limits */ + iio_val_s64_decompose(LLONG_MAX, &values[0], &values[1]); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_PICO, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "9223372.036854775807\n"); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_NANO, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "9223372036.854775807\n"); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MICRO, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "9223372036854.775807\n"); + + iio_val_s64_decompose(LLONG_MIN, &values[0], &values[1]); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_PICO, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-9223372.036854775808\n"); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_NANO, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-9223372036.854775808\n"); + ret = iio_format_value(buf, IIO_VAL_DECIMAL64_MICRO, ARRAY_SIZE(values), values); + IIO_TEST_FORMAT_EXPECT_EQ(test, buf, ret, "-9223372036854.775808\n"); +} + static struct kunit_case iio_format_test_cases[] = { KUNIT_CASE(iio_test_iio_format_value_integer), KUNIT_CASE(iio_test_iio_format_value_fixedpoint), @@ -257,6 +309,7 @@ static struct kunit_case iio_format_test_cases[] = { KUNIT_CASE(iio_test_iio_format_value_fractional_log2), KUNIT_CASE(iio_test_iio_format_value_multiple), KUNIT_CASE(iio_test_iio_format_value_integer_64), + KUNIT_CASE(iio_test_iio_format_value_decimal_64), { } }; diff --git a/drivers/iio/test/iio-test-gts.c b/drivers/iio/test/iio-test-gts.c index 11250bc905c9..6ffff85ba853 100644 --- a/drivers/iio/test/iio-test-gts.c +++ b/drivers/iio/test/iio-test-gts.c @@ -20,7 +20,7 @@ * * If yes, then adding a test is probably a good idea but please stop for a * moment and consider the effort of changing all the tests when code gets - * refactored. Eventually it neeeds to be. + * refactored. Eventually it needs to be. */ #define TEST_TSEL_50 1 diff --git a/drivers/iio/test/iio-test-rescale.c b/drivers/iio/test/iio-test-rescale.c index ac6942cf1e44..bcd4a607be19 100644 --- a/drivers/iio/test/iio-test-rescale.c +++ b/drivers/iio/test/iio-test-rescale.c @@ -575,7 +575,7 @@ static const struct rescale_tc_data offset_cases[] = { static void case_to_desc(const struct rescale_tc_data *t, char *desc) { - strcpy(desc, t->name); + strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); } KUNIT_ARRAY_PARAM(iio_rescale_scale, scale_cases, case_to_desc); diff --git a/drivers/iio/trigger/Kconfig b/drivers/iio/trigger/Kconfig index 7ecb69725b1d..52899c22d57c 100644 --- a/drivers/iio/trigger/Kconfig +++ b/drivers/iio/trigger/Kconfig @@ -16,15 +16,6 @@ config IIO_HRTIMER_TRIGGER To compile this driver as a module, choose M here: the module will be called iio-trig-hrtimer. -config IIO_INTERRUPT_TRIGGER - tristate "Generic interrupt trigger" - help - Provides support for using an interrupt of any type as an IIO - trigger. This may be provided by a gpio driver for example. - - To compile this driver as a module, choose M here: the - module will be called iio-trig-interrupt. - config IIO_STM32_LPTIMER_TRIGGER tristate "STM32 Low-Power Timer Trigger" depends on MFD_STM32_LPTIMER || COMPILE_TEST diff --git a/drivers/iio/trigger/Makefile b/drivers/iio/trigger/Makefile index f3d11acb8a0b..fc1fd5661c94 100644 --- a/drivers/iio/trigger/Makefile +++ b/drivers/iio/trigger/Makefile @@ -6,7 +6,6 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_IIO_HRTIMER_TRIGGER) += iio-trig-hrtimer.o -obj-$(CONFIG_IIO_INTERRUPT_TRIGGER) += iio-trig-interrupt.o obj-$(CONFIG_IIO_STM32_LPTIMER_TRIGGER) += stm32-lptimer-trigger.o obj-$(CONFIG_IIO_STM32_TIMER_TRIGGER) += stm32-timer-trigger.o obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o diff --git a/drivers/iio/trigger/iio-trig-interrupt.c b/drivers/iio/trigger/iio-trig-interrupt.c deleted file mode 100644 index a100c2e3a0d9..000000000000 --- a/drivers/iio/trigger/iio-trig-interrupt.c +++ /dev/null @@ -1,109 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Industrial I/O - generic interrupt based trigger support - * - * Copyright (c) 2008-2013 Jonathan Cameron - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/slab.h> - -#include <linux/iio/iio.h> -#include <linux/iio/trigger.h> - - -struct iio_interrupt_trigger_info { - unsigned int irq; -}; - -static irqreturn_t iio_interrupt_trigger_poll(int irq, void *private) -{ - iio_trigger_poll(private); - return IRQ_HANDLED; -} - -static int iio_interrupt_trigger_probe(struct platform_device *pdev) -{ - struct iio_interrupt_trigger_info *trig_info; - struct iio_trigger *trig; - unsigned long irqflags; - struct resource *irq_res; - int irq, ret = 0; - - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - - if (irq_res == NULL) - return -ENODEV; - - irqflags = (irq_res->flags & IRQF_TRIGGER_MASK) | IRQF_SHARED; - - irq = irq_res->start; - - trig = iio_trigger_alloc(NULL, "irqtrig%d", irq); - if (!trig) { - ret = -ENOMEM; - goto error_ret; - } - - trig_info = kzalloc_obj(*trig_info); - if (!trig_info) { - ret = -ENOMEM; - goto error_free_trigger; - } - iio_trigger_set_drvdata(trig, trig_info); - trig_info->irq = irq; - ret = request_irq(irq, iio_interrupt_trigger_poll, - irqflags, trig->name, trig); - if (ret) { - dev_err(&pdev->dev, - "request IRQ-%d failed", irq); - goto error_free_trig_info; - } - - ret = iio_trigger_register(trig); - if (ret) - goto error_release_irq; - platform_set_drvdata(pdev, trig); - - return 0; - -/* First clean up the partly allocated trigger */ -error_release_irq: - free_irq(irq, trig); -error_free_trig_info: - kfree(trig_info); -error_free_trigger: - iio_trigger_free(trig); -error_ret: - return ret; -} - -static void iio_interrupt_trigger_remove(struct platform_device *pdev) -{ - struct iio_trigger *trig; - struct iio_interrupt_trigger_info *trig_info; - - trig = platform_get_drvdata(pdev); - trig_info = iio_trigger_get_drvdata(trig); - iio_trigger_unregister(trig); - free_irq(trig_info->irq, trig); - kfree(trig_info); - iio_trigger_free(trig); -} - -static struct platform_driver iio_interrupt_trigger_driver = { - .probe = iio_interrupt_trigger_probe, - .remove = iio_interrupt_trigger_remove, - .driver = { - .name = "iio_interrupt_trigger", - }, -}; - -module_platform_driver(iio_interrupt_trigger_driver); - -MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); -MODULE_DESCRIPTION("Interrupt trigger for the iio subsystem"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/trigger/stm32-lptimer-trigger.c b/drivers/iio/trigger/stm32-lptimer-trigger.c index c7bab18221c7..828890fe353c 100644 --- a/drivers/iio/trigger/stm32-lptimer-trigger.c +++ b/drivers/iio/trigger/stm32-lptimer-trigger.c @@ -12,7 +12,6 @@ #include <linux/export.h> #include <linux/iio/timer/stm32-lptim-trigger.h> #include <linux/mfd/stm32-lptimer.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/property.h> diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c index 3b9a3a6cbb25..4f6ff1e72f2e 100644 --- a/drivers/iio/trigger/stm32-timer-trigger.c +++ b/drivers/iio/trigger/stm32-timer-trigger.c @@ -12,7 +12,6 @@ #include <linux/iio/timer/stm32-timer-trigger.h> #include <linux/iio/trigger.h> #include <linux/mfd/stm32-timers.h> -#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/property.h> |
