diff options
Diffstat (limited to 'drivers/iio')
86 files changed, 2419 insertions, 695 deletions
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 0e56ace61103..a0e9061f6d6b 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -143,10 +143,11 @@ config BMC150_ACCEL select BMC150_ACCEL_SPI if SPI help Say yes here to build support for the following Bosch accelerometers: - BMA222, BMA222E, BMA250E, BMA253, BMA254, BMA255, BMA280, BMC150, BMI055. + BMA222, BMA222E, BMA250E, BMA253, BMA254, BMA255, BMA280, BMC150, BMC156 + BMI055. Note that some of these are combo modules: - - BMC150: accelerometer and magnetometer + - BMC150/BMC156: accelerometer and magnetometer - BMI055: accelerometer and gyroscope This driver is only implementing accelerometer part, which has @@ -231,6 +232,7 @@ config DMARD10 config FXLS8962AF tristate + depends on I2C || !I2C # cannot be built-in for modular I2C config FXLS8962AF_I2C tristate "NXP FXLS8962AF/FXLS8964AF Accelerometer I2C Driver" @@ -247,6 +249,7 @@ config FXLS8962AF_I2C config FXLS8962AF_SPI tristate "NXP FXLS8962AF/FXLS8964AF Accelerometer SPI Driver" depends on SPI + depends on I2C || !I2C select FXLS8962AF select REGMAP_SPI help diff --git a/drivers/iio/accel/adxl345.h b/drivers/iio/accel/adxl345.h index 384497776b67..af0fdd02c4f2 100644 --- a/drivers/iio/accel/adxl345.h +++ b/drivers/iio/accel/adxl345.h @@ -15,6 +15,5 @@ enum adxl345_device_type { int adxl345_core_probe(struct device *dev, struct regmap *regmap, enum adxl345_device_type type, const char *name); -int adxl345_core_remove(struct device *dev); #endif /* _ADXL345_H_ */ diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index 312866530065..4b275051ef61 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -208,6 +208,11 @@ static const struct iio_info adxl345_info = { .write_raw_get_fmt = adxl345_write_raw_get_fmt, }; +static void adxl345_powerdown(void *regmap) +{ + regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_STANDBY); +} + int adxl345_core_probe(struct device *dev, struct regmap *regmap, enum adxl345_device_type type, const char *name) { @@ -233,7 +238,6 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, return -ENOMEM; data = iio_priv(indio_dev); - dev_set_drvdata(dev, indio_dev); data->regmap = regmap; data->type = type; /* Enable full-resolution mode */ @@ -260,29 +264,14 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, return ret; } - ret = iio_device_register(indio_dev); - if (ret < 0) { - dev_err(dev, "iio_device_register failed: %d\n", ret); - regmap_write(data->regmap, ADXL345_REG_POWER_CTL, - ADXL345_POWER_CTL_STANDBY); - } + ret = devm_add_action_or_reset(dev, adxl345_powerdown, data->regmap); + if (ret < 0) + return ret; - return ret; + return devm_iio_device_register(dev, indio_dev); } EXPORT_SYMBOL_GPL(adxl345_core_probe); -int adxl345_core_remove(struct device *dev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct adxl345_data *data = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - - return regmap_write(data->regmap, ADXL345_REG_POWER_CTL, - ADXL345_POWER_CTL_STANDBY); -} -EXPORT_SYMBOL_GPL(adxl345_core_remove); - MODULE_AUTHOR("Eva Rachel Retuya <eraretuya@gmail.com>"); MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer core driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c index 1561364ae296..a431cba216e6 100644 --- a/drivers/iio/accel/adxl345_i2c.c +++ b/drivers/iio/accel/adxl345_i2c.c @@ -38,11 +38,6 @@ static int adxl345_i2c_probe(struct i2c_client *client, id->name); } -static int adxl345_i2c_remove(struct i2c_client *client) -{ - return adxl345_core_remove(&client->dev); -} - static const struct i2c_device_id adxl345_i2c_id[] = { { "adxl345", ADXL345 }, { "adxl375", ADXL375 }, @@ -65,7 +60,6 @@ static struct i2c_driver adxl345_i2c_driver = { .of_match_table = adxl345_of_match, }, .probe = adxl345_i2c_probe, - .remove = adxl345_i2c_remove, .id_table = adxl345_i2c_id, }; diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c index da4591c7ef23..ea559ac2e87d 100644 --- a/drivers/iio/accel/adxl345_spi.c +++ b/drivers/iio/accel/adxl345_spi.c @@ -42,11 +42,6 @@ static int adxl345_spi_probe(struct spi_device *spi) return adxl345_core_probe(&spi->dev, regmap, id->driver_data, id->name); } -static int adxl345_spi_remove(struct spi_device *spi) -{ - return adxl345_core_remove(&spi->dev); -} - static const struct spi_device_id adxl345_spi_id[] = { { "adxl345", ADXL345 }, { "adxl375", ADXL375 }, @@ -69,7 +64,6 @@ static struct spi_driver adxl345_spi_driver = { .of_match_table = adxl345_of_match, }, .probe = adxl345_spi_probe, - .remove = adxl345_spi_remove, .id_table = adxl345_spi_id, }; diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c index 0622c7936499..bc4c626e454d 100644 --- a/drivers/iio/accel/bma220_spi.c +++ b/drivers/iio/accel/bma220_spi.c @@ -218,20 +218,33 @@ static int bma220_init(struct spi_device *spi) return 0; } -static int bma220_deinit(struct spi_device *spi) +static int bma220_power(struct spi_device *spi, bool up) { - int ret; - - /* Make sure the chip is powered off */ - ret = bma220_read_reg(spi, BMA220_REG_SUSPEND); - if (ret == BMA220_SUSPEND_SLEEP) + int i, ret; + + /** + * The chip can be suspended/woken up by a simple register read. + * So, we need up to 2 register reads of the suspend register + * to make sure that the device is in the desired state. + */ + for (i = 0; i < 2; i++) { ret = bma220_read_reg(spi, BMA220_REG_SUSPEND); - if (ret < 0) - return ret; - if (ret == BMA220_SUSPEND_SLEEP) - return -EBUSY; + if (ret < 0) + return ret; - return 0; + if (up && ret == BMA220_SUSPEND_SLEEP) + return 0; + + if (!up && ret == BMA220_SUSPEND_WAKE) + return 0; + } + + return -EBUSY; +} + +static void bma220_deinit(void *spi) +{ + bma220_power(spi, false); } static int bma220_probe(struct spi_device *spi) @@ -248,7 +261,6 @@ static int bma220_probe(struct spi_device *spi) data = iio_priv(indio_dev); data->spi_device = spi; - spi_set_drvdata(spi, indio_dev); mutex_init(&data->lock); indio_dev->info = &bma220_info; @@ -262,49 +274,33 @@ static int bma220_probe(struct spi_device *spi) if (ret) return ret; - ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time, - bma220_trigger_handler, NULL); - if (ret < 0) { - dev_err(&spi->dev, "iio triggered buffer setup failed\n"); - goto err_suspend; - } + ret = devm_add_action_or_reset(&spi->dev, bma220_deinit, spi); + if (ret) + return ret; - ret = iio_device_register(indio_dev); + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, + iio_pollfunc_store_time, + bma220_trigger_handler, NULL); if (ret < 0) { - dev_err(&spi->dev, "iio_device_register failed\n"); - iio_triggered_buffer_cleanup(indio_dev); - goto err_suspend; + dev_err(&spi->dev, "iio triggered buffer setup failed\n"); + return ret; } - return 0; - -err_suspend: - return bma220_deinit(spi); -} - -static int bma220_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - - return bma220_deinit(spi); + return devm_iio_device_register(&spi->dev, indio_dev); } static __maybe_unused int bma220_suspend(struct device *dev) { - struct bma220_data *data = iio_priv(dev_get_drvdata(dev)); + struct spi_device *spi = to_spi_device(dev); - /* The chip can be suspended/woken up by a simple register read. */ - return bma220_read_reg(data->spi_device, BMA220_REG_SUSPEND); + return bma220_power(spi, false); } static __maybe_unused int bma220_resume(struct device *dev) { - struct bma220_data *data = iio_priv(dev_get_drvdata(dev)); + struct spi_device *spi = to_spi_device(dev); - return bma220_read_reg(data->spi_device, BMA220_REG_SUSPEND); + return bma220_power(spi, true); } static SIMPLE_DEV_PM_OPS(bma220_pm_ops, bma220_suspend, bma220_resume); @@ -326,7 +322,6 @@ static struct spi_driver bma220_driver = { .acpi_match_table = bma220_acpi_id, }, .probe = bma220_probe, - .remove = bma220_remove, .id_table = bma220_spi_id, }; module_spi_driver(bma220_driver); diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index 5ce384ebe6c7..e8693a42ad46 100644 --- a/drivers/iio/accel/bmc150-accel-core.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -10,6 +10,7 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/acpi.h> +#include <linux/of_irq.h> #include <linux/pm.h> #include <linux/pm_runtime.h> #include <linux/iio/iio.h> @@ -57,12 +58,18 @@ #define BMC150_ACCEL_RESET_VAL 0xB6 #define BMC150_ACCEL_REG_INT_MAP_0 0x19 -#define BMC150_ACCEL_INT_MAP_0_BIT_SLOPE BIT(2) +#define BMC150_ACCEL_INT_MAP_0_BIT_INT1_SLOPE BIT(2) #define BMC150_ACCEL_REG_INT_MAP_1 0x1A -#define BMC150_ACCEL_INT_MAP_1_BIT_DATA BIT(0) -#define BMC150_ACCEL_INT_MAP_1_BIT_FWM BIT(1) -#define BMC150_ACCEL_INT_MAP_1_BIT_FFULL BIT(2) +#define BMC150_ACCEL_INT_MAP_1_BIT_INT1_DATA BIT(0) +#define BMC150_ACCEL_INT_MAP_1_BIT_INT1_FWM BIT(1) +#define BMC150_ACCEL_INT_MAP_1_BIT_INT1_FFULL BIT(2) +#define BMC150_ACCEL_INT_MAP_1_BIT_INT2_FFULL BIT(5) +#define BMC150_ACCEL_INT_MAP_1_BIT_INT2_FWM BIT(6) +#define BMC150_ACCEL_INT_MAP_1_BIT_INT2_DATA BIT(7) + +#define BMC150_ACCEL_REG_INT_MAP_2 0x1B +#define BMC150_ACCEL_INT_MAP_2_BIT_INT2_SLOPE BIT(2) #define BMC150_ACCEL_REG_INT_RST_LATCH 0x21 #define BMC150_ACCEL_INT_MODE_LATCH_RESET 0x80 @@ -81,6 +88,7 @@ #define BMC150_ACCEL_REG_INT_OUT_CTRL 0x20 #define BMC150_ACCEL_INT_OUT_CTRL_INT1_LVL BIT(0) +#define BMC150_ACCEL_INT_OUT_CTRL_INT2_LVL BIT(2) #define BMC150_ACCEL_REG_INT_5 0x27 #define BMC150_ACCEL_SLOPE_DUR_MASK 0x03 @@ -476,21 +484,24 @@ static bool bmc150_apply_acpi_orientation(struct device *dev, } #endif -static const struct bmc150_accel_interrupt_info { +struct bmc150_accel_interrupt_info { u8 map_reg; u8 map_bitmask; u8 en_reg; u8 en_bitmask; -} bmc150_accel_interrupts[BMC150_ACCEL_INTERRUPTS] = { +}; + +static const struct bmc150_accel_interrupt_info +bmc150_accel_interrupts_int1[BMC150_ACCEL_INTERRUPTS] = { { /* data ready interrupt */ .map_reg = BMC150_ACCEL_REG_INT_MAP_1, - .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_DATA, + .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_INT1_DATA, .en_reg = BMC150_ACCEL_REG_INT_EN_1, .en_bitmask = BMC150_ACCEL_INT_EN_BIT_DATA_EN, }, { /* motion interrupt */ .map_reg = BMC150_ACCEL_REG_INT_MAP_0, - .map_bitmask = BMC150_ACCEL_INT_MAP_0_BIT_SLOPE, + .map_bitmask = BMC150_ACCEL_INT_MAP_0_BIT_INT1_SLOPE, .en_reg = BMC150_ACCEL_REG_INT_EN_0, .en_bitmask = BMC150_ACCEL_INT_EN_BIT_SLP_X | BMC150_ACCEL_INT_EN_BIT_SLP_Y | @@ -498,19 +509,56 @@ static const struct bmc150_accel_interrupt_info { }, { /* fifo watermark interrupt */ .map_reg = BMC150_ACCEL_REG_INT_MAP_1, - .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_FWM, + .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_INT1_FWM, + .en_reg = BMC150_ACCEL_REG_INT_EN_1, + .en_bitmask = BMC150_ACCEL_INT_EN_BIT_FWM_EN, + }, +}; + +static const struct bmc150_accel_interrupt_info +bmc150_accel_interrupts_int2[BMC150_ACCEL_INTERRUPTS] = { + { /* data ready interrupt */ + .map_reg = BMC150_ACCEL_REG_INT_MAP_1, + .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_INT2_DATA, + .en_reg = BMC150_ACCEL_REG_INT_EN_1, + .en_bitmask = BMC150_ACCEL_INT_EN_BIT_DATA_EN, + }, + { /* motion interrupt */ + .map_reg = BMC150_ACCEL_REG_INT_MAP_2, + .map_bitmask = BMC150_ACCEL_INT_MAP_2_BIT_INT2_SLOPE, + .en_reg = BMC150_ACCEL_REG_INT_EN_0, + .en_bitmask = BMC150_ACCEL_INT_EN_BIT_SLP_X | + BMC150_ACCEL_INT_EN_BIT_SLP_Y | + BMC150_ACCEL_INT_EN_BIT_SLP_Z + }, + { /* fifo watermark interrupt */ + .map_reg = BMC150_ACCEL_REG_INT_MAP_1, + .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_INT2_FWM, .en_reg = BMC150_ACCEL_REG_INT_EN_1, .en_bitmask = BMC150_ACCEL_INT_EN_BIT_FWM_EN, }, }; static void bmc150_accel_interrupts_setup(struct iio_dev *indio_dev, - struct bmc150_accel_data *data) + struct bmc150_accel_data *data, int irq) { + const struct bmc150_accel_interrupt_info *irq_info = NULL; + struct device *dev = regmap_get_device(data->regmap); int i; + /* + * For now we map all interrupts to the same output pin. + * However, some boards may have just INT2 (and not INT1) connected, + * so we try to detect which IRQ it is based on the interrupt-names. + * Without interrupt-names, we assume the irq belongs to INT1. + */ + irq_info = bmc150_accel_interrupts_int1; + if (data->type == BOSCH_BMC156 || + irq == of_irq_get_byname(dev->of_node, "INT2")) + irq_info = bmc150_accel_interrupts_int2; + for (i = 0; i < BMC150_ACCEL_INTERRUPTS; i++) - data->interrupts[i].info = &bmc150_accel_interrupts[i]; + data->interrupts[i].info = &irq_info[i]; } static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i, @@ -1127,7 +1175,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { {306458, BMC150_ACCEL_DEF_RANGE_16G} }, }, { - .name = "BMA253/BMA254/BMA255/BMC150/BMI055", + .name = "BMA253/BMA254/BMA255/BMC150/BMC156/BMI055", .chip_id = 0xFA, .channels = bmc150_accel_channels, .num_channels = ARRAY_SIZE(bmc150_accel_channels), @@ -1614,7 +1662,8 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data) } int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, - const char *name, bool block_supported) + enum bmc150_type type, const char *name, + bool block_supported) { const struct attribute **fifo_attrs; struct bmc150_accel_data *data; @@ -1629,6 +1678,7 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, dev_set_drvdata(dev, indio_dev); data->regmap = regmap; + data->type = type; if (!bmc150_apply_acpi_orientation(dev, &data->orientation)) { ret = iio_read_mount_matrix(dev, &data->orientation); @@ -1714,7 +1764,7 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, goto err_buffer_cleanup; } - bmc150_accel_interrupts_setup(indio_dev, data); + bmc150_accel_interrupts_setup(indio_dev, data, irq); ret = bmc150_accel_triggers_setup(indio_dev, data); if (ret) diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c index 999495f0669d..88bd8a25f142 100644 --- a/drivers/iio/accel/bmc150-accel-i2c.c +++ b/drivers/iio/accel/bmc150-accel-i2c.c @@ -176,6 +176,7 @@ static int bmc150_accel_probe(struct i2c_client *client, { struct regmap *regmap; const char *name = NULL; + enum bmc150_type type = BOSCH_UNKNOWN; bool block_supported = i2c_check_functionality(client->adapter, I2C_FUNC_I2C) || i2c_check_functionality(client->adapter, @@ -188,10 +189,13 @@ static int bmc150_accel_probe(struct i2c_client *client, return PTR_ERR(regmap); } - if (id) + if (id) { name = id->name; + type = id->driver_data; + } - ret = bmc150_accel_core_probe(&client->dev, regmap, client->irq, name, block_supported); + ret = bmc150_accel_core_probe(&client->dev, regmap, client->irq, + type, name, block_supported); if (ret) return ret; @@ -236,6 +240,7 @@ static const struct i2c_device_id bmc150_accel_id[] = { {"bma255"}, {"bma280"}, {"bmc150_accel"}, + {"bmc156_accel", BOSCH_BMC156}, {"bmi055_accel"}, {} }; @@ -251,6 +256,7 @@ static const struct of_device_id bmc150_accel_of_match[] = { { .compatible = "bosch,bma255" }, { .compatible = "bosch,bma280" }, { .compatible = "bosch,bmc150_accel" }, + { .compatible = "bosch,bmc156_accel" }, { .compatible = "bosch,bmi055_accel" }, { }, }; diff --git a/drivers/iio/accel/bmc150-accel-spi.c b/drivers/iio/accel/bmc150-accel-spi.c index 54b8c9c8068b..191e312dc91a 100644 --- a/drivers/iio/accel/bmc150-accel-spi.c +++ b/drivers/iio/accel/bmc150-accel-spi.c @@ -16,6 +16,8 @@ static int bmc150_accel_probe(struct spi_device *spi) { struct regmap *regmap; + const char *name = NULL; + enum bmc150_type type = BOSCH_UNKNOWN; const struct spi_device_id *id = spi_get_device_id(spi); regmap = devm_regmap_init_spi(spi, &bmc150_regmap_conf); @@ -24,7 +26,12 @@ static int bmc150_accel_probe(struct spi_device *spi) return PTR_ERR(regmap); } - return bmc150_accel_core_probe(&spi->dev, regmap, spi->irq, id->name, + if (id) { + name = id->name; + type = id->driver_data; + } + + return bmc150_accel_core_probe(&spi->dev, regmap, spi->irq, type, name, true); } @@ -54,6 +61,7 @@ static const struct spi_device_id bmc150_accel_id[] = { {"bma255"}, {"bma280"}, {"bmc150_accel"}, + {"bmc156_accel", BOSCH_BMC156}, {"bmi055_accel"}, {} }; diff --git a/drivers/iio/accel/bmc150-accel.h b/drivers/iio/accel/bmc150-accel.h index 47121f070fe9..1bb5023e8ed9 100644 --- a/drivers/iio/accel/bmc150-accel.h +++ b/drivers/iio/accel/bmc150-accel.h @@ -13,6 +13,22 @@ struct i2c_client; struct bmc150_accel_chip_info; struct bmc150_accel_interrupt_info; +/* + * We can often guess better than "UNKNOWN" based on the device IDs + * but unfortunately this information is not always accurate. There are some + * devices where ACPI firmware specifies an ID like "BMA250E" when the device + * actually has a BMA222E. The driver attempts to detect those by reading the + * chip ID from the registers but this information is not always enough either. + * + * Therefore, this enum should be only used when the chip ID detection is not + * enough and we can be reasonably sure that the device IDs are reliable + * in practice (e.g. for device tree platforms). + */ +enum bmc150_type { + BOSCH_UNKNOWN, + BOSCH_BMC156, +}; + struct bmc150_accel_interrupt { const struct bmc150_accel_interrupt_info *info; atomic_t users; @@ -62,6 +78,7 @@ struct bmc150_accel_data { int ev_enable_state; int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */ const struct bmc150_accel_chip_info *chip_info; + enum bmc150_type type; struct i2c_client *second_device; void (*resume_callback)(struct device *dev); struct delayed_work resume_work; @@ -69,7 +86,8 @@ struct bmc150_accel_data { }; int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, - const char *name, bool block_supported); + enum bmc150_type type, const char *name, + bool block_supported); int bmc150_accel_core_remove(struct device *dev); extern const struct dev_pm_ops bmc150_accel_pm_ops; extern const struct regmap_config bmc150_regmap_conf; diff --git a/drivers/iio/accel/da280.c b/drivers/iio/accel/da280.c index 5edff9ba72da..9633bdae5fd4 100644 --- a/drivers/iio/accel/da280.c +++ b/drivers/iio/accel/da280.c @@ -100,6 +100,11 @@ static enum da280_chipset da280_match_acpi_device(struct device *dev) return (enum da280_chipset) id->driver_data; } +static void da280_disable(void *client) +{ + da280_enable(client, false); +} + static int da280_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -118,7 +123,6 @@ static int da280_probe(struct i2c_client *client, data = iio_priv(indio_dev); data->client = client; - i2c_set_clientdata(client, indio_dev); indio_dev->info = &da280_info; indio_dev->modes = INDIO_DIRECT_MODE; @@ -142,22 +146,11 @@ static int da280_probe(struct i2c_client *client, if (ret < 0) return ret; - ret = iio_device_register(indio_dev); - if (ret < 0) { - dev_err(&client->dev, "device_register failed\n"); - da280_enable(client, false); - } - - return ret; -} - -static int da280_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - - iio_device_unregister(indio_dev); + ret = devm_add_action_or_reset(&client->dev, da280_disable, client); + if (ret) + return ret; - return da280_enable(client, false); + return devm_iio_device_register(&client->dev, indio_dev); } #ifdef CONFIG_PM_SLEEP @@ -194,7 +187,6 @@ static struct i2c_driver da280_driver = { .pm = &da280_pm_ops, }, .probe = da280_probe, - .remove = da280_remove, .id_table = da280_i2c_id, }; diff --git a/drivers/iio/accel/da311.c b/drivers/iio/accel/da311.c index 92593a1cd1aa..04e13487e706 100644 --- a/drivers/iio/accel/da311.c +++ b/drivers/iio/accel/da311.c @@ -212,6 +212,11 @@ static const struct iio_info da311_info = { .read_raw = da311_read_raw, }; +static void da311_disable(void *client) +{ + da311_enable(client, false); +} + static int da311_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -229,7 +234,6 @@ static int da311_probe(struct i2c_client *client, data = iio_priv(indio_dev); data->client = client; - i2c_set_clientdata(client, indio_dev); indio_dev->info = &da311_info; indio_dev->name = "da311"; @@ -245,22 +249,11 @@ static int da311_probe(struct i2c_client *client, if (ret < 0) return ret; - ret = iio_device_register(indio_dev); - if (ret < 0) { - dev_err(&client->dev, "device_register failed\n"); - da311_enable(client, false); - } - - return ret; -} - -static int da311_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - - iio_device_unregister(indio_dev); + ret = devm_add_action_or_reset(&client->dev, da311_disable, client); + if (ret) + return ret; - return da311_enable(client, false); + return devm_iio_device_register(&client->dev, indio_dev); } #ifdef CONFIG_PM_SLEEP @@ -289,7 +282,6 @@ static struct i2c_driver da311_driver = { .pm = &da311_pm_ops, }, .probe = da311_probe, - .remove = da311_remove, .id_table = da311_i2c_id, }; diff --git a/drivers/iio/accel/dmard10.c b/drivers/iio/accel/dmard10.c index e84bf8db1e89..f9f173eec202 100644 --- a/drivers/iio/accel/dmard10.c +++ b/drivers/iio/accel/dmard10.c @@ -170,6 +170,11 @@ static const struct iio_info dmard10_info = { .read_raw = dmard10_read_raw, }; +static void dmard10_shutdown_cleanup(void *client) +{ + dmard10_shutdown(client); +} + static int dmard10_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -194,7 +199,6 @@ static int dmard10_probe(struct i2c_client *client, data = iio_priv(indio_dev); data->client = client; - i2c_set_clientdata(client, indio_dev); indio_dev->info = &dmard10_info; indio_dev->name = "dmard10"; @@ -206,22 +210,12 @@ static int dmard10_probe(struct i2c_client *client, if (ret < 0) return ret; - ret = iio_device_register(indio_dev); - if (ret < 0) { - dev_err(&client->dev, "device_register failed\n"); - dmard10_shutdown(client); - } - - return ret; -} - -static int dmard10_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - - iio_device_unregister(indio_dev); + ret = devm_add_action_or_reset(&client->dev, dmard10_shutdown_cleanup, + client); + if (ret) + return ret; - return dmard10_shutdown(client); + return devm_iio_device_register(&client->dev, indio_dev); } #ifdef CONFIG_PM_SLEEP @@ -250,7 +244,6 @@ static struct i2c_driver dmard10_driver = { .pm = &dmard10_pm_ops, }, .probe = dmard10_probe, - .remove = dmard10_remove, .id_table = dmard10_i2c_id, }; diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index 078d87865fde..0019f1ea7df2 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -637,7 +637,7 @@ static int fxls8962af_i2c_raw_read_errata3(struct fxls8962af_data *data, return ret; } - return ret; + return 0; } static int fxls8962af_fifo_transfer(struct fxls8962af_data *data, diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index 55cdca818b3b..a2def6f9380a 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -367,7 +367,8 @@ static int hid_accel_3d_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to setup common attributes\n"); return ret; } - indio_dev->channels = kmemdup(channel_spec, channel_size, GFP_KERNEL); + indio_dev->channels = devm_kmemdup(&pdev->dev, channel_spec, + channel_size, GFP_KERNEL); if (!indio_dev->channels) { dev_err(&pdev->dev, "failed to duplicate channels\n"); @@ -378,7 +379,7 @@ static int hid_accel_3d_probe(struct platform_device *pdev) hsdev->usage, accel_state); if (ret) { dev_err(&pdev->dev, "failed to setup attributes\n"); - goto error_free_dev_mem; + return ret; } indio_dev->info = &accel_3d_info; @@ -391,7 +392,7 @@ static int hid_accel_3d_probe(struct platform_device *pdev) &accel_state->common_attributes); if (ret < 0) { dev_err(&pdev->dev, "trigger setup failed\n"); - goto error_free_dev_mem; + return ret; } ret = iio_device_register(indio_dev); @@ -416,8 +417,6 @@ error_iio_unreg: iio_device_unregister(indio_dev); error_remove_trigger: hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes); -error_free_dev_mem: - kfree(indio_dev->channels); return ret; } @@ -431,7 +430,6 @@ static int hid_accel_3d_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes); - kfree(indio_dev->channels); return 0; } diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h index f5b0b8bbaff7..8750dea56fcb 100644 --- a/drivers/iio/accel/st_accel.h +++ b/drivers/iio/accel/st_accel.h @@ -64,7 +64,6 @@ enum st_accel_type { #ifdef CONFIG_IIO_BUFFER int st_accel_allocate_ring(struct iio_dev *indio_dev); -void st_accel_deallocate_ring(struct iio_dev *indio_dev); int st_accel_trig_set_state(struct iio_trigger *trig, bool state); #define ST_ACCEL_TRIGGER_SET_STATE (&st_accel_trig_set_state) #else /* CONFIG_IIO_BUFFER */ @@ -72,9 +71,6 @@ static inline int st_accel_allocate_ring(struct iio_dev *indio_dev) { return 0; } -static inline void st_accel_deallocate_ring(struct iio_dev *indio_dev) -{ -} #define ST_ACCEL_TRIGGER_SET_STATE NULL #endif /* CONFIG_IIO_BUFFER */ diff --git a/drivers/iio/accel/st_accel_buffer.c b/drivers/iio/accel/st_accel_buffer.c index 492263589e04..fc82fa83f1fb 100644 --- a/drivers/iio/accel/st_accel_buffer.c +++ b/drivers/iio/accel/st_accel_buffer.c @@ -9,14 +9,9 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/stat.h> -#include <linux/interrupt.h> -#include <linux/i2c.h> -#include <linux/delay.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> -#include <linux/iio/trigger_consumer.h> +#include <linux/iio/trigger.h> #include <linux/iio/triggered_buffer.h> #include <linux/iio/common/st_sensors.h> @@ -67,13 +62,8 @@ static const struct iio_buffer_setup_ops st_accel_buffer_setup_ops = { int st_accel_allocate_ring(struct iio_dev *indio_dev) { - return iio_triggered_buffer_setup(indio_dev, NULL, - &st_sensors_trigger_handler, &st_accel_buffer_setup_ops); -} - -void st_accel_deallocate_ring(struct iio_dev *indio_dev) -{ - iio_triggered_buffer_cleanup(indio_dev); + return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev, + NULL, &st_sensors_trigger_handler, &st_accel_buffer_setup_ops); } MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 28fceac9f2f6..f1e6ec380667 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -9,17 +9,13 @@ #include <linux/kernel.h> #include <linux/module.h> +#include <linux/mutex.h> +#include <linux/sysfs.h> #include <linux/slab.h> #include <linux/acpi.h> -#include <linux/errno.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/i2c.h> -#include <linux/irq.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/iio/trigger.h> -#include <linux/iio/buffer.h> #include <linux/iio/common/st_sensors.h> #include "st_accel.h" @@ -1381,7 +1377,7 @@ int st_accel_common_probe(struct iio_dev *indio_dev) err = st_sensors_allocate_trigger(indio_dev, ST_ACCEL_TRIGGER_OPS); if (err < 0) - goto st_accel_probe_trigger_error; + return err; } err = iio_device_register(indio_dev); @@ -1396,8 +1392,6 @@ int st_accel_common_probe(struct iio_dev *indio_dev) st_accel_device_register_error: if (adata->irq > 0) st_sensors_deallocate_trigger(indio_dev); -st_accel_probe_trigger_error: - st_accel_deallocate_ring(indio_dev); return err; } EXPORT_SYMBOL(st_accel_common_probe); @@ -1409,8 +1403,6 @@ void st_accel_common_remove(struct iio_dev *indio_dev) iio_device_unregister(indio_dev); if (adata->irq > 0) st_sensors_deallocate_trigger(indio_dev); - - st_accel_deallocate_ring(indio_dev); } EXPORT_SYMBOL(st_accel_common_remove); diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index 95e305b88d5e..f711756e41e3 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -9,11 +9,10 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/slab.h> +#include <linux/mod_devicetable.h> #include <linux/acpi.h> #include <linux/i2c.h> #include <linux/iio/iio.h> -#include <linux/property.h> #include <linux/iio/common/st_sensors_i2c.h> #include "st_accel.h" diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index 83d3308ce5cc..bb45d9ff95b8 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -9,7 +9,7 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/slab.h> +#include <linux/mod_devicetable.h> #include <linux/spi/spi.h> #include <linux/iio/iio.h> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index db0c8fb60515..af168e1c9fdb 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -887,6 +887,16 @@ config ROCKCHIP_SARADC To compile this driver as a module, choose M here: the module will be called rockchip_saradc. +config RZG2L_ADC + tristate "Renesas RZ/G2L ADC driver" + depends on ARCH_R9A07G044 || COMPILE_TEST + help + Say yes here to build support for the ADC found in Renesas + RZ/G2L family. + + To compile this driver as a module, choose M here: the + module will be called rzg2l_adc. + config SC27XX_ADC tristate "Spreadtrum SC27xx series PMICs ADC" depends on MFD_SC27XX_PMIC || COMPILE_TEST diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index f70d877c555a..d68550f493e3 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o obj-$(CONFIG_RN5T618_ADC) += rn5t618-adc.o obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o +obj-$(CONFIG_RZG2L_ADC) += rzg2l_adc.o obj-$(CONFIG_SC27XX_ADC) += sc27xx_adc.o obj-$(CONFIG_SPEAR_ADC) += spear_adc.o obj-$(CONFIG_STX104) += stx104.o diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c index a10a4e8d94fd..8edd6407b7c3 100644 --- a/drivers/iio/adc/ep93xx_adc.c +++ b/drivers/iio/adc/ep93xx_adc.c @@ -205,7 +205,7 @@ static int ep93xx_adc_probe(struct platform_device *pdev) */ } - ret = clk_enable(priv->clk); + ret = clk_prepare_enable(priv->clk); if (ret) { dev_err(&pdev->dev, "Cannot enable clock\n"); return ret; @@ -213,7 +213,7 @@ static int ep93xx_adc_probe(struct platform_device *pdev) ret = iio_device_register(iiodev); if (ret) - clk_disable(priv->clk); + clk_disable_unprepare(priv->clk); return ret; } @@ -224,7 +224,7 @@ static int ep93xx_adc_remove(struct platform_device *pdev) struct ep93xx_adc_priv *priv = iio_priv(iiodev); iio_device_unregister(iiodev); - clk_disable(priv->clk); + clk_disable_unprepare(priv->clk); return 0; } diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c index ab5139e911c3..329c555b55cc 100644 --- a/drivers/iio/adc/fsl-imx25-gcq.c +++ b/drivers/iio/adc/fsl-imx25-gcq.c @@ -201,11 +201,11 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev, */ priv->vref[MX25_ADC_REFP_INT] = NULL; priv->vref[MX25_ADC_REFP_EXT] = - devm_regulator_get_optional(&pdev->dev, "vref-ext"); + devm_regulator_get_optional(dev, "vref-ext"); priv->vref[MX25_ADC_REFP_XP] = - devm_regulator_get_optional(&pdev->dev, "vref-xp"); + devm_regulator_get_optional(dev, "vref-xp"); priv->vref[MX25_ADC_REFP_YP] = - devm_regulator_get_optional(&pdev->dev, "vref-yp"); + devm_regulator_get_optional(dev, "vref-yp"); for_each_child_of_node(np, child) { u32 reg; @@ -307,7 +307,7 @@ static int mx25_gcq_probe(struct platform_device *pdev) int ret; int i; - indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); if (!indio_dev) return -ENOMEM; @@ -347,14 +347,11 @@ static int mx25_gcq_probe(struct platform_device *pdev) goto err_vref_disable; } - priv->irq = platform_get_irq(pdev, 0); - if (priv->irq <= 0) { - ret = priv->irq; - if (!ret) - ret = -ENXIO; + ret = platform_get_irq(pdev, 0); + if (ret < 0) goto err_clk_unprepare; - } + priv->irq = ret; ret = request_irq(priv->irq, mx25_gcq_irq, 0, pdev->name, priv); if (ret) { dev_err(dev, "Failed requesting IRQ\n"); diff --git a/drivers/iio/adc/ingenic-adc.c b/drivers/iio/adc/ingenic-adc.c index 34c03a264f74..2b3912c6ca6b 100644 --- a/drivers/iio/adc/ingenic-adc.c +++ b/drivers/iio/adc/ingenic-adc.c @@ -37,6 +37,7 @@ #define JZ_ADC_REG_CFG_SAMPLE_NUM(n) ((n) << 10) #define JZ_ADC_REG_CFG_PULL_UP(n) ((n) << 16) #define JZ_ADC_REG_CFG_CMD_SEL BIT(22) +#define JZ_ADC_REG_CFG_VBAT_SEL BIT(30) #define JZ_ADC_REG_CFG_TOUCH_OPS_MASK (BIT(31) | GENMASK(23, 10)) #define JZ_ADC_REG_ADCLK_CLKDIV_LSB 0 #define JZ4725B_ADC_REG_ADCLK_CLKDIV10US_LSB 16 @@ -71,6 +72,7 @@ #define JZ4725B_ADC_BATTERY_HIGH_VREF_BITS 10 #define JZ4740_ADC_BATTERY_HIGH_VREF (7500 * 0.986) #define JZ4740_ADC_BATTERY_HIGH_VREF_BITS 12 +#define JZ4760_ADC_BATTERY_VREF 2500 #define JZ4770_ADC_BATTERY_VREF 1200 #define JZ4770_ADC_BATTERY_VREF_BITS 12 @@ -92,7 +94,7 @@ struct ingenic_adc_soc_data { const int *battery_scale_avail; size_t battery_scale_avail_size; unsigned int battery_vref_mode: 1; - unsigned int has_aux2: 1; + unsigned int has_aux_md: 1; const struct iio_chan_spec *channels; unsigned int num_channels; int (*init_clk_div)(struct device *dev, struct ingenic_adc *adc); @@ -295,6 +297,10 @@ static const int jz4740_adc_battery_scale_avail[] = { JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS, }; +static const int jz4760_adc_battery_scale_avail[] = { + JZ4760_ADC_BATTERY_VREF, JZ4770_ADC_BATTERY_VREF_BITS, +}; + static const int jz4770_adc_battery_raw_avail[] = { 0, 1, (1 << JZ4770_ADC_BATTERY_VREF_BITS) - 1, }; @@ -400,6 +406,47 @@ static const struct iio_chan_spec jz4740_channels[] = { }, }; +static const struct iio_chan_spec jz4760_channels[] = { + { + .extend_name = "aux", + .type = IIO_VOLTAGE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .indexed = 1, + .channel = INGENIC_ADC_AUX0, + .scan_index = -1, + }, + { + .extend_name = "aux1", + .type = IIO_VOLTAGE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .indexed = 1, + .channel = INGENIC_ADC_AUX, + .scan_index = -1, + }, + { + .extend_name = "aux2", + .type = IIO_VOLTAGE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .indexed = 1, + .channel = INGENIC_ADC_AUX2, + .scan_index = -1, + }, + { + .extend_name = "battery", + .type = IIO_VOLTAGE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .indexed = 1, + .channel = INGENIC_ADC_BATTERY, + .scan_index = -1, + }, +}; + static const struct iio_chan_spec jz4770_channels[] = { { .type = IIO_VOLTAGE, @@ -506,7 +553,7 @@ static const struct ingenic_adc_soc_data jz4725b_adc_soc_data = { .battery_scale_avail = jz4725b_adc_battery_scale_avail, .battery_scale_avail_size = ARRAY_SIZE(jz4725b_adc_battery_scale_avail), .battery_vref_mode = true, - .has_aux2 = false, + .has_aux_md = false, .channels = jz4740_channels, .num_channels = ARRAY_SIZE(jz4740_channels), .init_clk_div = jz4725b_adc_init_clk_div, @@ -520,12 +567,26 @@ static const struct ingenic_adc_soc_data jz4740_adc_soc_data = { .battery_scale_avail = jz4740_adc_battery_scale_avail, .battery_scale_avail_size = ARRAY_SIZE(jz4740_adc_battery_scale_avail), .battery_vref_mode = true, - .has_aux2 = false, + .has_aux_md = false, .channels = jz4740_channels, .num_channels = ARRAY_SIZE(jz4740_channels), .init_clk_div = NULL, /* no ADCLK register on JZ4740 */ }; +static const struct ingenic_adc_soc_data jz4760_adc_soc_data = { + .battery_high_vref = JZ4760_ADC_BATTERY_VREF, + .battery_high_vref_bits = JZ4770_ADC_BATTERY_VREF_BITS, + .battery_raw_avail = jz4770_adc_battery_raw_avail, + .battery_raw_avail_size = ARRAY_SIZE(jz4770_adc_battery_raw_avail), + .battery_scale_avail = jz4760_adc_battery_scale_avail, + .battery_scale_avail_size = ARRAY_SIZE(jz4760_adc_battery_scale_avail), + .battery_vref_mode = false, + .has_aux_md = true, + .channels = jz4760_channels, + .num_channels = ARRAY_SIZE(jz4760_channels), + .init_clk_div = jz4770_adc_init_clk_div, +}; + static const struct ingenic_adc_soc_data jz4770_adc_soc_data = { .battery_high_vref = JZ4770_ADC_BATTERY_VREF, .battery_high_vref_bits = JZ4770_ADC_BATTERY_VREF_BITS, @@ -534,7 +595,7 @@ static const struct ingenic_adc_soc_data jz4770_adc_soc_data = { .battery_scale_avail = jz4770_adc_battery_scale_avail, .battery_scale_avail_size = ARRAY_SIZE(jz4770_adc_battery_scale_avail), .battery_vref_mode = false, - .has_aux2 = true, + .has_aux_md = true, .channels = jz4770_channels, .num_channels = ARRAY_SIZE(jz4770_channels), .init_clk_div = jz4770_adc_init_clk_div, @@ -569,7 +630,7 @@ static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev, struct iio_chan_spec const *chan, int *val) { - int bit, ret, engine = (chan->channel == INGENIC_ADC_BATTERY); + int cmd, ret, engine = (chan->channel == INGENIC_ADC_BATTERY); struct ingenic_adc *adc = iio_priv(iio_dev); ret = clk_enable(adc->clk); @@ -579,11 +640,22 @@ static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev, return ret; } - /* We cannot sample AUX/AUX2 in parallel. */ + /* We cannot sample the aux channels in parallel. */ mutex_lock(&adc->aux_lock); - if (adc->soc_data->has_aux2 && engine == 0) { - bit = BIT(chan->channel == INGENIC_ADC_AUX2); - ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_AUX_MD, bit); + if (adc->soc_data->has_aux_md && engine == 0) { + switch (chan->channel) { + case INGENIC_ADC_AUX0: + cmd = 0; + break; + case INGENIC_ADC_AUX: + cmd = 1; + break; + case INGENIC_ADC_AUX2: + cmd = 2; + break; + } + + ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_AUX_MD, cmd); } ret = ingenic_adc_capture(adc, engine); @@ -591,6 +663,7 @@ static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev, goto out; switch (chan->channel) { + case INGENIC_ADC_AUX0: case INGENIC_ADC_AUX: case INGENIC_ADC_AUX2: *val = readw(adc->base + JZ_ADC_REG_ADSDAT); @@ -621,6 +694,7 @@ static int ingenic_adc_read_raw(struct iio_dev *iio_dev, return ingenic_adc_read_chan_info_raw(iio_dev, chan, val); case IIO_CHAN_INFO_SCALE: switch (chan->channel) { + case INGENIC_ADC_AUX0: case INGENIC_ADC_AUX: case INGENIC_ADC_AUX2: *val = JZ_ADC_AUX_VREF; @@ -806,6 +880,14 @@ static int ingenic_adc_probe(struct platform_device *pdev) /* Put hardware in a known passive state. */ writeb(0x00, adc->base + JZ_ADC_REG_ENABLE); writeb(0xff, adc->base + JZ_ADC_REG_CTRL); + + /* JZ4760B specific */ + if (device_property_present(dev, "ingenic,use-internal-divider")) + ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_VBAT_SEL, + JZ_ADC_REG_CFG_VBAT_SEL); + else + ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_VBAT_SEL, 0); + usleep_range(2000, 3000); /* Must wait at least 2ms. */ clk_disable(adc->clk); @@ -832,6 +914,8 @@ static int ingenic_adc_probe(struct platform_device *pdev) static const struct of_device_id ingenic_adc_of_match[] = { { .compatible = "ingenic,jz4725b-adc", .data = &jz4725b_adc_soc_data, }, { .compatible = "ingenic,jz4740-adc", .data = &jz4740_adc_soc_data, }, + { .compatible = "ingenic,jz4760-adc", .data = &jz4760_adc_soc_data, }, + { .compatible = "ingenic,jz4760b-adc", .data = &jz4760_adc_soc_data, }, { .compatible = "ingenic,jz4770-adc", .data = &jz4770_adc_soc_data, }, { }, }; diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index 66dc452d643a..705d5e11a54b 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -347,7 +347,7 @@ static int meson_sar_adc_read_raw_sample(struct iio_dev *indio_dev, struct meson_sar_adc_priv *priv = iio_priv(indio_dev); int regval, fifo_chan, fifo_val, count; - if(!wait_for_completion_timeout(&priv->done, + if (!wait_for_completion_timeout(&priv->done, msecs_to_jiffies(MESON_SAR_ADC_TIMEOUT))) return -ETIMEDOUT; @@ -497,8 +497,8 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev) if (priv->param->has_bl30_integration) { /* prevent BL30 from using the SAR ADC while we are using it */ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, - MESON_SAR_ADC_DELAY_KERNEL_BUSY, - MESON_SAR_ADC_DELAY_KERNEL_BUSY); + MESON_SAR_ADC_DELAY_KERNEL_BUSY, + MESON_SAR_ADC_DELAY_KERNEL_BUSY); /* * wait until BL30 releases it's lock (so we can use the SAR @@ -525,7 +525,7 @@ static void meson_sar_adc_unlock(struct iio_dev *indio_dev) if (priv->param->has_bl30_integration) /* allow BL30 to use the SAR ADC again */ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, - MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0); + MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0); mutex_unlock(&indio_dev->mlock); } @@ -791,7 +791,7 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) * on the vendor driver), which we don't support at the moment. */ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, - MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL, 0); + MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL, 0); /* disable all channels by default */ regmap_write(priv->regmap, MESON_SAR_ADC_CHAN_LIST, 0x0); @@ -1104,6 +1104,14 @@ static const struct meson_sar_adc_param meson_sar_adc_gxl_param = { .resolution = 12, }; +static const struct meson_sar_adc_param meson_sar_adc_g12a_param = { + .has_bl30_integration = false, + .clock_rate = 1200000, + .bandgap_reg = MESON_SAR_ADC_REG11, + .regmap_config = &meson_sar_adc_regmap_config_gxbb, + .resolution = 12, +}; + static const struct meson_sar_adc_data meson_sar_adc_meson8_data = { .param = &meson_sar_adc_meson8_param, .name = "meson-meson8-saradc", @@ -1140,7 +1148,7 @@ static const struct meson_sar_adc_data meson_sar_adc_axg_data = { }; static const struct meson_sar_adc_data meson_sar_adc_g12a_data = { - .param = &meson_sar_adc_gxl_param, + .param = &meson_sar_adc_g12a_param, .name = "meson-g12a-saradc", }; diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c index 6ef09609be9f..f9c8385c72d3 100644 --- a/drivers/iio/adc/palmas_gpadc.c +++ b/drivers/iio/adc/palmas_gpadc.c @@ -664,8 +664,8 @@ static int palmas_adc_wakeup_configure(struct palmas_gpadc *adc) adc_period = adc->auto_conversion_period; for (i = 0; i < 16; ++i) { - if (((1000 * (1 << i)) / 32) < adc_period) - continue; + if (((1000 * (1 << i)) / 32) >= adc_period) + break; } if (i > 0) i--; diff --git a/drivers/iio/adc/rn5t618-adc.c b/drivers/iio/adc/rn5t618-adc.c index 7010c4276947..c56fccb2c8e1 100644 --- a/drivers/iio/adc/rn5t618-adc.c +++ b/drivers/iio/adc/rn5t618-adc.c @@ -16,6 +16,8 @@ #include <linux/completion.h> #include <linux/regmap.h> #include <linux/iio/iio.h> +#include <linux/iio/driver.h> +#include <linux/iio/machine.h> #include <linux/slab.h> #define RN5T618_ADC_CONVERSION_TIMEOUT (msecs_to_jiffies(500)) @@ -189,6 +191,19 @@ static const struct iio_chan_spec rn5t618_adc_iio_channels[] = { RN5T618_ADC_CHANNEL(AIN0, IIO_VOLTAGE, "AIN0") }; +static struct iio_map rn5t618_maps[] = { + IIO_MAP("VADP", "rn5t618-power", "vadp"), + IIO_MAP("VUSB", "rn5t618-power", "vusb"), + { /* sentinel */ } +}; + +static void unregister_map(void *data) +{ + struct iio_dev *iio_dev = (struct iio_dev *) data; + + iio_map_array_unregister(iio_dev); +} + static int rn5t618_adc_probe(struct platform_device *pdev) { int ret; @@ -239,6 +254,14 @@ static int rn5t618_adc_probe(struct platform_device *pdev) return ret; } + ret = iio_map_array_register(iio_dev, rn5t618_maps); + if (ret < 0) + return ret; + + ret = devm_add_action_or_reset(adc->dev, unregister_map, iio_dev); + if (ret < 0) + return ret; + return devm_iio_device_register(adc->dev, iio_dev); } diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c index 12584f1631d8..a237fe469a30 100644 --- a/drivers/iio/adc/rockchip_saradc.c +++ b/drivers/iio/adc/rockchip_saradc.c @@ -35,7 +35,7 @@ #define SARADC_DLY_PU_SOC_MASK 0x3f #define SARADC_TIMEOUT msecs_to_jiffies(100) -#define SARADC_MAX_CHANNELS 6 +#define SARADC_MAX_CHANNELS 8 struct rockchip_saradc_data { const struct iio_chan_spec *channels; @@ -49,10 +49,12 @@ struct rockchip_saradc { struct clk *clk; struct completion completion; struct regulator *vref; + int uv_vref; struct reset_control *reset; const struct rockchip_saradc_data *data; u16 last_val; const struct iio_chan_spec *last_chan; + struct notifier_block nb; }; static void rockchip_saradc_power_down(struct rockchip_saradc *info) @@ -105,13 +107,7 @@ static int rockchip_saradc_read_raw(struct iio_dev *indio_dev, mutex_unlock(&indio_dev->mlock); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - ret = regulator_get_voltage(info->vref); - if (ret < 0) { - dev_err(&indio_dev->dev, "failed to get voltage\n"); - return ret; - } - - *val = ret / 1000; + *val = info->uv_vref / 1000; *val2 = chan->scan_type.realbits; return IIO_VAL_FRACTIONAL_LOG2; default: @@ -192,6 +188,23 @@ static const struct rockchip_saradc_data rk3399_saradc_data = { .clk_rate = 1000000, }; +static const struct iio_chan_spec rockchip_rk3568_saradc_iio_channels[] = { + SARADC_CHANNEL(0, "adc0", 10), + SARADC_CHANNEL(1, "adc1", 10), + SARADC_CHANNEL(2, "adc2", 10), + SARADC_CHANNEL(3, "adc3", 10), + SARADC_CHANNEL(4, "adc4", 10), + SARADC_CHANNEL(5, "adc5", 10), + SARADC_CHANNEL(6, "adc6", 10), + SARADC_CHANNEL(7, "adc7", 10), +}; + +static const struct rockchip_saradc_data rk3568_saradc_data = { + .channels = rockchip_rk3568_saradc_iio_channels, + .num_channels = ARRAY_SIZE(rockchip_rk3568_saradc_iio_channels), + .clk_rate = 1000000, +}; + static const struct of_device_id rockchip_saradc_match[] = { { .compatible = "rockchip,saradc", @@ -202,6 +215,9 @@ static const struct of_device_id rockchip_saradc_match[] = { }, { .compatible = "rockchip,rk3399-saradc", .data = &rk3399_saradc_data, + }, { + .compatible = "rockchip,rk3568-saradc", + .data = &rk3568_saradc_data, }, {}, }; @@ -278,6 +294,26 @@ out: return IRQ_HANDLED; } +static int rockchip_saradc_volt_notify(struct notifier_block *nb, + unsigned long event, + void *data) +{ + struct rockchip_saradc *info = + container_of(nb, struct rockchip_saradc, nb); + + if (event & REGULATOR_EVENT_VOLTAGE_CHANGE) + info->uv_vref = (unsigned long)data; + + return NOTIFY_OK; +} + +static void rockchip_saradc_regulator_unreg_notifier(void *data) +{ + struct rockchip_saradc *info = data; + + regulator_unregister_notifier(info->vref, &info->nb); +} + static int rockchip_saradc_probe(struct platform_device *pdev) { struct rockchip_saradc *info = NULL; @@ -390,6 +426,12 @@ static int rockchip_saradc_probe(struct platform_device *pdev) return ret; } + ret = regulator_get_voltage(info->vref); + if (ret < 0) + return ret; + + info->uv_vref = ret; + ret = clk_prepare_enable(info->pclk); if (ret < 0) { dev_err(&pdev->dev, "failed to enable pclk\n"); @@ -430,6 +472,17 @@ static int rockchip_saradc_probe(struct platform_device *pdev) if (ret) return ret; + info->nb.notifier_call = rockchip_saradc_volt_notify; + ret = regulator_register_notifier(info->vref, &info->nb); + if (ret) + return ret; + + ret = devm_add_action_or_reset(&pdev->dev, + rockchip_saradc_regulator_unreg_notifier, + info); + if (ret) + return ret; + return devm_iio_device_register(&pdev->dev, indio_dev); } diff --git a/drivers/iio/adc/rzg2l_adc.c b/drivers/iio/adc/rzg2l_adc.c new file mode 100644 index 000000000000..9996d5eef289 --- /dev/null +++ b/drivers/iio/adc/rzg2l_adc.c @@ -0,0 +1,600 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * RZ/G2L A/D Converter driver + * + * Copyright (c) 2021 Renesas Electronics Europe GmbH + * + * Author: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> + */ + +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/iio/iio.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/pm_runtime.h> +#include <linux/reset.h> + +#define DRIVER_NAME "rzg2l-adc" + +#define RZG2L_ADM(n) ((n) * 0x4) +#define RZG2L_ADM0_ADCE BIT(0) +#define RZG2L_ADM0_ADBSY BIT(1) +#define RZG2L_ADM0_PWDWNB BIT(2) +#define RZG2L_ADM0_SRESB BIT(15) +#define RZG2L_ADM1_TRG BIT(0) +#define RZG2L_ADM1_MS BIT(2) +#define RZG2L_ADM1_BS BIT(4) +#define RZG2L_ADM1_EGA_MASK GENMASK(13, 12) +#define RZG2L_ADM2_CHSEL_MASK GENMASK(7, 0) +#define RZG2L_ADM3_ADIL_MASK GENMASK(31, 24) +#define RZG2L_ADM3_ADCMP_MASK GENMASK(23, 16) +#define RZG2L_ADM3_ADCMP_E FIELD_PREP(RZG2L_ADM3_ADCMP_MASK, 0xe) +#define RZG2L_ADM3_ADSMP_MASK GENMASK(15, 0) + +#define RZG2L_ADINT 0x20 +#define RZG2L_ADINT_INTEN_MASK GENMASK(7, 0) +#define RZG2L_ADINT_CSEEN BIT(16) +#define RZG2L_ADINT_INTS BIT(31) + +#define RZG2L_ADSTS 0x24 +#define RZG2L_ADSTS_CSEST BIT(16) +#define RZG2L_ADSTS_INTST_MASK GENMASK(7, 0) + +#define RZG2L_ADIVC 0x28 +#define RZG2L_ADIVC_DIVADC_MASK GENMASK(8, 0) +#define RZG2L_ADIVC_DIVADC_4 FIELD_PREP(RZG2L_ADIVC_DIVADC_MASK, 0x4) + +#define RZG2L_ADFIL 0x2c + +#define RZG2L_ADCR(n) (0x30 + ((n) * 0x4)) +#define RZG2L_ADCR_AD_MASK GENMASK(11, 0) + +#define RZG2L_ADSMP_DEFUALT_SAMPLING 0x578 + +#define RZG2L_ADC_MAX_CHANNELS 8 +#define RZG2L_ADC_CHN_MASK 0x7 +#define RZG2L_ADC_TIMEOUT usecs_to_jiffies(1 * 4) + +struct rzg2l_adc_data { + const struct iio_chan_spec *channels; + u8 num_channels; +}; + +struct rzg2l_adc { + void __iomem *base; + struct clk *pclk; + struct clk *adclk; + struct reset_control *presetn; + struct reset_control *adrstn; + struct completion completion; + const struct rzg2l_adc_data *data; + struct mutex lock; + u16 last_val[RZG2L_ADC_MAX_CHANNELS]; +}; + +static const char * const rzg2l_adc_channel_name[] = { + "adc0", + "adc1", + "adc2", + "adc3", + "adc4", + "adc5", + "adc6", + "adc7", +}; + +static unsigned int rzg2l_adc_readl(struct rzg2l_adc *adc, u32 reg) +{ + return readl(adc->base + reg); +} + +static void rzg2l_adc_writel(struct rzg2l_adc *adc, unsigned int reg, u32 val) +{ + writel(val, adc->base + reg); +} + +static void rzg2l_adc_pwr(struct rzg2l_adc *adc, bool on) +{ + u32 reg; + + reg = rzg2l_adc_readl(adc, RZG2L_ADM(0)); + if (on) + reg |= RZG2L_ADM0_PWDWNB; + else + reg &= ~RZG2L_ADM0_PWDWNB; + rzg2l_adc_writel(adc, RZG2L_ADM(0), reg); + udelay(2); +} + +static void rzg2l_adc_start_stop(struct rzg2l_adc *adc, bool start) +{ + int timeout = 5; + u32 reg; + + reg = rzg2l_adc_readl(adc, RZG2L_ADM(0)); + if (start) + reg |= RZG2L_ADM0_ADCE; + else + reg &= ~RZG2L_ADM0_ADCE; + rzg2l_adc_writel(adc, RZG2L_ADM(0), reg); + + if (start) + return; + + do { + usleep_range(100, 200); + reg = rzg2l_adc_readl(adc, RZG2L_ADM(0)); + timeout--; + if (!timeout) { + pr_err("%s stopping ADC timed out\n", __func__); + break; + } + } while (((reg & RZG2L_ADM0_ADBSY) || (reg & RZG2L_ADM0_ADCE))); +} + +static void rzg2l_set_trigger(struct rzg2l_adc *adc) +{ + u32 reg; + + /* + * Setup ADM1 for SW trigger + * EGA[13:12] - Set 00 to indicate hardware trigger is invalid + * BS[4] - Enable 1-buffer mode + * MS[1] - Enable Select mode + * TRG[0] - Enable software trigger mode + */ + reg = rzg2l_adc_readl(adc, RZG2L_ADM(1)); + reg &= ~RZG2L_ADM1_EGA_MASK; + reg &= ~RZG2L_ADM1_BS; + reg &= ~RZG2L_ADM1_TRG; + reg |= RZG2L_ADM1_MS; + rzg2l_adc_writel(adc, RZG2L_ADM(1), reg); +} + +static int rzg2l_adc_conversion_setup(struct rzg2l_adc *adc, u8 ch) +{ + u32 reg; + + if (rzg2l_adc_readl(adc, RZG2L_ADM(0)) & RZG2L_ADM0_ADBSY) + return -EBUSY; + + rzg2l_set_trigger(adc); + + /* Select analog input channel subjected to conversion. */ + reg = rzg2l_adc_readl(adc, RZG2L_ADM(2)); + reg &= ~RZG2L_ADM2_CHSEL_MASK; + reg |= BIT(ch); + rzg2l_adc_writel(adc, RZG2L_ADM(2), reg); + + /* + * Setup ADINT + * INTS[31] - Select pulse signal + * CSEEN[16] - Enable channel select error interrupt + * INTEN[7:0] - Select channel interrupt + */ + reg = rzg2l_adc_readl(adc, RZG2L_ADINT); + reg &= ~RZG2L_ADINT_INTS; + reg &= ~RZG2L_ADINT_INTEN_MASK; + reg |= (RZG2L_ADINT_CSEEN | BIT(ch)); + rzg2l_adc_writel(adc, RZG2L_ADINT, reg); + + return 0; +} + +static int rzg2l_adc_set_power(struct iio_dev *indio_dev, bool on) +{ + struct device *dev = indio_dev->dev.parent; + + if (on) + return pm_runtime_resume_and_get(dev); + + return pm_runtime_put_sync(dev); +} + +static int rzg2l_adc_conversion(struct iio_dev *indio_dev, struct rzg2l_adc *adc, u8 ch) +{ + int ret; + + ret = rzg2l_adc_set_power(indio_dev, true); + if (ret) + return ret; + + ret = rzg2l_adc_conversion_setup(adc, ch); + if (ret) { + rzg2l_adc_set_power(indio_dev, false); + return ret; + } + + reinit_completion(&adc->completion); + + rzg2l_adc_start_stop(adc, true); + + if (!wait_for_completion_timeout(&adc->completion, RZG2L_ADC_TIMEOUT)) { + rzg2l_adc_writel(adc, RZG2L_ADINT, + rzg2l_adc_readl(adc, RZG2L_ADINT) & ~RZG2L_ADINT_INTEN_MASK); + rzg2l_adc_start_stop(adc, false); + rzg2l_adc_set_power(indio_dev, false); + return -ETIMEDOUT; + } + + return rzg2l_adc_set_power(indio_dev, false); +} + +static int rzg2l_adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct rzg2l_adc *adc = iio_priv(indio_dev); + int ret; + u8 ch; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (chan->type != IIO_VOLTAGE) + return -EINVAL; + + mutex_lock(&adc->lock); + ch = chan->channel & RZG2L_ADC_CHN_MASK; + ret = rzg2l_adc_conversion(indio_dev, adc, ch); + if (ret) { + mutex_unlock(&adc->lock); + return ret; + } + *val = adc->last_val[ch]; + mutex_unlock(&adc->lock); + + return IIO_VAL_INT; + + default: + return -EINVAL; + } +} + +static int rzg2l_adc_read_label(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, + char *label) +{ + if (chan->channel >= RZG2L_ADC_MAX_CHANNELS) + return -EINVAL; + + return sysfs_emit(label, "%s\n", rzg2l_adc_channel_name[chan->channel]); +} + +static const struct iio_info rzg2l_adc_iio_info = { + .read_raw = rzg2l_adc_read_raw, + .read_label = rzg2l_adc_read_label, +}; + +static irqreturn_t rzg2l_adc_isr(int irq, void *dev_id) +{ + struct rzg2l_adc *adc = dev_id; + unsigned long intst; + u32 reg; + int ch; + + reg = rzg2l_adc_readl(adc, RZG2L_ADSTS); + + /* A/D conversion channel select error interrupt */ + if (reg & RZG2L_ADSTS_CSEST) { + rzg2l_adc_writel(adc, RZG2L_ADSTS, reg); + return IRQ_HANDLED; + } + + intst = reg & RZG2L_ADSTS_INTST_MASK; + if (!intst) + return IRQ_NONE; + + for_each_set_bit(ch, &intst, RZG2L_ADC_MAX_CHANNELS) + adc->last_val[ch] = rzg2l_adc_readl(adc, RZG2L_ADCR(ch)) & RZG2L_ADCR_AD_MASK; + + /* clear the channel interrupt */ + rzg2l_adc_writel(adc, RZG2L_ADSTS, reg); + + complete(&adc->completion); + + return IRQ_HANDLED; +} + +static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l_adc *adc) +{ + struct iio_chan_spec *chan_array; + struct fwnode_handle *fwnode; + struct rzg2l_adc_data *data; + unsigned int channel; + int num_channels; + int ret; + u8 i; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + num_channels = device_get_child_node_count(&pdev->dev); + if (!num_channels) { + dev_err(&pdev->dev, "no channel children\n"); + return -ENODEV; + } + + if (num_channels > RZG2L_ADC_MAX_CHANNELS) { + dev_err(&pdev->dev, "num of channel children out of range\n"); + return -EINVAL; + } + + chan_array = devm_kcalloc(&pdev->dev, num_channels, sizeof(*chan_array), + GFP_KERNEL); + if (!chan_array) + return -ENOMEM; + + i = 0; + device_for_each_child_node(&pdev->dev, fwnode) { + ret = fwnode_property_read_u32(fwnode, "reg", &channel); + if (ret) + return ret; + + if (channel >= RZG2L_ADC_MAX_CHANNELS) + return -EINVAL; + + chan_array[i].type = IIO_VOLTAGE; + chan_array[i].indexed = 1; + chan_array[i].channel = channel; + chan_array[i].info_mask_separate = BIT(IIO_CHAN_INFO_RAW); + chan_array[i].datasheet_name = rzg2l_adc_channel_name[channel]; + i++; + } + + data->num_channels = num_channels; + data->channels = chan_array; + adc->data = data; + + return 0; +} + +static int rzg2l_adc_hw_init(struct rzg2l_adc *adc) +{ + int timeout = 5; + u32 reg; + int ret; + + ret = clk_prepare_enable(adc->pclk); + if (ret) + return ret; + + /* SW reset */ + reg = rzg2l_adc_readl(adc, RZG2L_ADM(0)); + reg |= RZG2L_ADM0_SRESB; + rzg2l_adc_writel(adc, RZG2L_ADM(0), reg); + + while (!(rzg2l_adc_readl(adc, RZG2L_ADM(0)) & RZG2L_ADM0_SRESB)) { + if (!timeout) { + ret = -EBUSY; + goto exit_hw_init; + } + timeout--; + usleep_range(100, 200); + } + + /* Only division by 4 can be set */ + reg = rzg2l_adc_readl(adc, RZG2L_ADIVC); + reg &= ~RZG2L_ADIVC_DIVADC_MASK; + reg |= RZG2L_ADIVC_DIVADC_4; + rzg2l_adc_writel(adc, RZG2L_ADIVC, reg); + + /* + * Setup AMD3 + * ADIL[31:24] - Should be always set to 0 + * ADCMP[23:16] - Should be always set to 0xe + * ADSMP[15:0] - Set default (0x578) sampling period + */ + reg = rzg2l_adc_readl(adc, RZG2L_ADM(3)); + reg &= ~RZG2L_ADM3_ADIL_MASK; + reg &= ~RZG2L_ADM3_ADCMP_MASK; + reg &= ~RZG2L_ADM3_ADSMP_MASK; + reg |= (RZG2L_ADM3_ADCMP_E | RZG2L_ADSMP_DEFUALT_SAMPLING); + rzg2l_adc_writel(adc, RZG2L_ADM(3), reg); + +exit_hw_init: + clk_disable_unprepare(adc->pclk); + + return 0; +} + +static void rzg2l_adc_pm_runtime_disable(void *data) +{ + struct device *dev = data; + + pm_runtime_disable(dev->parent); +} + +static void rzg2l_adc_pm_runtime_set_suspended(void *data) +{ + struct device *dev = data; + + pm_runtime_set_suspended(dev->parent); +} + +static void rzg2l_adc_reset_assert(void *data) +{ + reset_control_assert(data); +} + +static int rzg2l_adc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct iio_dev *indio_dev; + struct rzg2l_adc *adc; + int ret; + int irq; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*adc)); + if (!indio_dev) + return -ENOMEM; + + adc = iio_priv(indio_dev); + + ret = rzg2l_adc_parse_properties(pdev, adc); + if (ret) + return ret; + + mutex_init(&adc->lock); + + adc->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(adc->base)) + return PTR_ERR(adc->base); + + adc->pclk = devm_clk_get(dev, "pclk"); + if (IS_ERR(adc->pclk)) { + dev_err(dev, "Failed to get pclk"); + return PTR_ERR(adc->pclk); + } + + adc->adclk = devm_clk_get(dev, "adclk"); + if (IS_ERR(adc->adclk)) { + dev_err(dev, "Failed to get adclk"); + return PTR_ERR(adc->adclk); + } + + adc->adrstn = devm_reset_control_get_exclusive(dev, "adrst-n"); + if (IS_ERR(adc->adrstn)) { + dev_err(dev, "failed to get adrstn\n"); + return PTR_ERR(adc->adrstn); + } + + adc->presetn = devm_reset_control_get_exclusive(dev, "presetn"); + if (IS_ERR(adc->presetn)) { + dev_err(dev, "failed to get presetn\n"); + return PTR_ERR(adc->presetn); + } + + ret = reset_control_deassert(adc->adrstn); + if (ret) { + dev_err(&pdev->dev, "failed to deassert adrstn pin, %d\n", ret); + return ret; + } + + ret = devm_add_action_or_reset(&pdev->dev, + rzg2l_adc_reset_assert, adc->adrstn); + if (ret) { + dev_err(&pdev->dev, "failed to register adrstn assert devm action, %d\n", + ret); + return ret; + } + + ret = reset_control_deassert(adc->presetn); + if (ret) { + dev_err(&pdev->dev, "failed to deassert presetn pin, %d\n", ret); + return ret; + } + + ret = devm_add_action_or_reset(&pdev->dev, + rzg2l_adc_reset_assert, adc->presetn); + if (ret) { + dev_err(&pdev->dev, "failed to register presetn assert devm action, %d\n", + ret); + return ret; + } + + ret = rzg2l_adc_hw_init(adc); + if (ret) { + dev_err(&pdev->dev, "failed to initialize ADC HW, %d\n", ret); + return ret; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "no irq resource\n"); + return irq; + } + + ret = devm_request_irq(dev, irq, rzg2l_adc_isr, + 0, dev_name(dev), adc); + if (ret < 0) + return ret; + + init_completion(&adc->completion); + + platform_set_drvdata(pdev, indio_dev); + + indio_dev->name = DRIVER_NAME; + indio_dev->info = &rzg2l_adc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = adc->data->channels; + indio_dev->num_channels = adc->data->num_channels; + + pm_runtime_set_suspended(dev); + ret = devm_add_action_or_reset(&pdev->dev, + rzg2l_adc_pm_runtime_set_suspended, &indio_dev->dev); + if (ret) + return ret; + + pm_runtime_enable(dev); + ret = devm_add_action_or_reset(&pdev->dev, + rzg2l_adc_pm_runtime_disable, &indio_dev->dev); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id rzg2l_adc_match[] = { + { .compatible = "renesas,rzg2l-adc",}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rzg2l_adc_match); + +static int __maybe_unused rzg2l_adc_pm_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct rzg2l_adc *adc = iio_priv(indio_dev); + + rzg2l_adc_pwr(adc, false); + clk_disable_unprepare(adc->adclk); + clk_disable_unprepare(adc->pclk); + + return 0; +} + +static int __maybe_unused rzg2l_adc_pm_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct rzg2l_adc *adc = iio_priv(indio_dev); + int ret; + + ret = clk_prepare_enable(adc->pclk); + if (ret) + return ret; + + ret = clk_prepare_enable(adc->adclk); + if (ret) + return ret; + + rzg2l_adc_pwr(adc, true); + + return 0; +} + +static const struct dev_pm_ops rzg2l_adc_pm_ops = { + SET_RUNTIME_PM_OPS(rzg2l_adc_pm_runtime_suspend, + rzg2l_adc_pm_runtime_resume, + NULL) +}; + +static struct platform_driver rzg2l_adc_driver = { + .probe = rzg2l_adc_probe, + .driver = { + .name = DRIVER_NAME, + .of_match_table = rzg2l_adc_match, + .pm = &rzg2l_adc_pm_ops, + }, +}; + +module_platform_driver(rzg2l_adc_driver); + +MODULE_AUTHOR("Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>"); +MODULE_DESCRIPTION("Renesas RZ/G2L ADC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c index 2383eacada87..a2b83f0bd526 100644 --- a/drivers/iio/adc/ti-ads7950.c +++ b/drivers/iio/adc/ti-ads7950.c @@ -568,7 +568,6 @@ static int ti_ads7950_probe(struct spi_device *spi) st->ring_xfer.tx_buf = &st->tx_buf[0]; st->ring_xfer.rx_buf = &st->rx_buf[0]; /* len will be set later */ - st->ring_xfer.cs_change = true; spi_message_add_tail(&st->ring_xfer, &st->ring_msg); diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig index a4920646e9be..c03667e62732 100644 --- a/drivers/iio/chemical/Kconfig +++ b/drivers/iio/chemical/Kconfig @@ -131,6 +131,17 @@ config SENSIRION_SGP30 To compile this driver as module, choose M here: the module will be called sgp30. +config SENSIRION_SGP40 + tristate "Sensirion SGP40 gas sensor" + depends on I2C + select CRC8 + help + Say Y here to build I2C interface to support Sensirion SGP40 gas + sensor + + To compile this driver as module, choose M here: the + module will be called sgp40. + config SPS30 tristate select IIO_BUFFER diff --git a/drivers/iio/chemical/Makefile b/drivers/iio/chemical/Makefile index 4898690cc155..d07af581f234 100644 --- a/drivers/iio/chemical/Makefile +++ b/drivers/iio/chemical/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_SCD30_CORE) += scd30_core.o obj-$(CONFIG_SCD30_I2C) += scd30_i2c.o obj-$(CONFIG_SCD30_SERIAL) += scd30_serial.o obj-$(CONFIG_SENSIRION_SGP30) += sgp30.o +obj-$(CONFIG_SENSIRION_SGP40) += sgp40.o obj-$(CONFIG_SPS30) += sps30.o obj-$(CONFIG_SPS30_I2C) += sps30_i2c.o obj-$(CONFIG_SPS30_SERIAL) += sps30_serial.o diff --git a/drivers/iio/chemical/sgp40.c b/drivers/iio/chemical/sgp40.c new file mode 100644 index 000000000000..8a56394cea4e --- /dev/null +++ b/drivers/iio/chemical/sgp40.c @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * sgp40.c - Support for Sensirion SGP40 Gas Sensor + * + * Copyright (C) 2021 Andreas Klinger <ak@it-klinger.de> + * + * I2C slave address: 0x59 + * + * Datasheet can be found here: + * https://www.sensirion.com/file/datasheet_sgp40 + * + * There are two functionalities supported: + * + * 1) read raw logarithmic resistance value from sensor + * --> useful to pass it to the algorithm of the sensor vendor for + * measuring deteriorations and improvements of air quality. + * + * 2) calculate an estimated absolute voc index (0 - 500 index points) for + * measuring the air quality. + * For this purpose the value of the resistance for which the voc index + * will be 250 can be set up using calibbias. + * + * Compensation values of relative humidity and temperature can be set up + * by writing to the out values of temp and humidityrelative. + */ + +#include <linux/delay.h> +#include <linux/crc8.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> + +/* + * floating point calculation of voc is done as integer + * where numbers are multiplied by 1 << SGP40_CALC_POWER + */ +#define SGP40_CALC_POWER 14 + +#define SGP40_CRC8_POLYNOMIAL 0x31 +#define SGP40_CRC8_INIT 0xff + +DECLARE_CRC8_TABLE(sgp40_crc8_table); + +struct sgp40_data { + struct device *dev; + struct i2c_client *client; + int rht; + int temp; + int res_calibbias; + /* Prevent concurrent access to rht, tmp, calibbias */ + struct mutex lock; +}; + +struct sgp40_tg_measure { + u8 command[2]; + __be16 rht_ticks; + u8 rht_crc; + __be16 temp_ticks; + u8 temp_crc; +} __packed; + +struct sgp40_tg_result { + __be16 res_ticks; + u8 res_crc; +} __packed; + +static const struct iio_chan_spec sgp40_channels[] = { + { + .type = IIO_CONCENTRATION, + .channel2 = IIO_MOD_VOC, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + }, + { + .type = IIO_RESISTANCE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_CALIBBIAS), + }, + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .output = 1, + }, + { + .type = IIO_HUMIDITYRELATIVE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .output = 1, + }, +}; + +/* + * taylor approximation of e^x: + * y = 1 + x + x^2 / 2 + x^3 / 6 + x^4 / 24 + ... + x^n / n! + * + * Because we are calculating x real value multiplied by 2^power we get + * an additional 2^power^n to divide for every element. For a reasonable + * precision this would overflow after a few iterations. Therefore we + * divide the x^n part whenever its about to overflow (xmax). + */ + +static u32 sgp40_exp(int exp, u32 power, u32 rounds) +{ + u32 x, y, xp; + u32 factorial, divider, xmax; + int sign = 1; + int i; + + if (exp == 0) + return 1 << power; + else if (exp < 0) { + sign = -1; + exp *= -1; + } + + xmax = 0x7FFFFFFF / exp; + x = exp; + xp = 1; + factorial = 1; + y = 1 << power; + divider = 0; + + for (i = 1; i <= rounds; i++) { + xp *= x; + factorial *= i; + y += (xp >> divider) / factorial; + divider += power; + /* divide when next multiplication would overflow */ + if (xp >= xmax) { + xp >>= power; + divider -= power; + } + } + + if (sign == -1) + return (1 << (power * 2)) / y; + else + return y; +} + +static int sgp40_calc_voc(struct sgp40_data *data, u16 resistance_raw, int *voc) +{ + int x; + u32 exp = 0; + + /* we calculate as a multiple of 16384 (2^14) */ + mutex_lock(&data->lock); + x = ((int)resistance_raw - data->res_calibbias) * 106; + mutex_unlock(&data->lock); + + /* voc = 500 / (1 + e^x) */ + exp = sgp40_exp(x, SGP40_CALC_POWER, 18); + *voc = 500 * ((1 << (SGP40_CALC_POWER * 2)) / ((1<<SGP40_CALC_POWER) + exp)); + + dev_dbg(data->dev, "raw: %d res_calibbias: %d x: %d exp: %d voc: %d\n", + resistance_raw, data->res_calibbias, x, exp, *voc); + + return 0; +} + +static int sgp40_measure_resistance_raw(struct sgp40_data *data, u16 *resistance_raw) +{ + int ret; + struct i2c_client *client = data->client; + u32 ticks; + u16 ticks16; + u8 crc; + struct sgp40_tg_measure tg = {.command = {0x26, 0x0F}}; + struct sgp40_tg_result tgres; + + mutex_lock(&data->lock); + + ticks = (data->rht / 10) * 65535 / 10000; + ticks16 = (u16)clamp(ticks, 0u, 65535u); /* clamp between 0 .. 100 %rH */ + tg.rht_ticks = cpu_to_be16(ticks16); + tg.rht_crc = crc8(sgp40_crc8_table, (u8 *)&tg.rht_ticks, 2, SGP40_CRC8_INIT); + + ticks = ((data->temp + 45000) / 10 ) * 65535 / 17500; + ticks16 = (u16)clamp(ticks, 0u, 65535u); /* clamp between -45 .. +130 °C */ + tg.temp_ticks = cpu_to_be16(ticks16); + tg.temp_crc = crc8(sgp40_crc8_table, (u8 *)&tg.temp_ticks, 2, SGP40_CRC8_INIT); + + mutex_unlock(&data->lock); + + ret = i2c_master_send(client, (const char *)&tg, sizeof(tg)); + if (ret != sizeof(tg)) { + dev_warn(data->dev, "i2c_master_send ret: %d sizeof: %zu\n", ret, sizeof(tg)); + return -EIO; + } + msleep(30); + + ret = i2c_master_recv(client, (u8 *)&tgres, sizeof(tgres)); + if (ret < 0) + return ret; + if (ret != sizeof(tgres)) { + dev_warn(data->dev, "i2c_master_recv ret: %d sizeof: %zu\n", ret, sizeof(tgres)); + return -EIO; + } + + crc = crc8(sgp40_crc8_table, (u8 *)&tgres.res_ticks, 2, SGP40_CRC8_INIT); + if (crc != tgres.res_crc) { + dev_err(data->dev, "CRC error while measure-raw\n"); + return -EIO; + } + + *resistance_raw = be16_to_cpu(tgres.res_ticks); + + return 0; +} + +static int sgp40_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct sgp40_data *data = iio_priv(indio_dev); + int ret, voc; + u16 resistance_raw; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_RESISTANCE: + ret = sgp40_measure_resistance_raw(data, &resistance_raw); + if (ret) + return ret; + + *val = resistance_raw; + return IIO_VAL_INT; + case IIO_TEMP: + mutex_lock(&data->lock); + *val = data->temp; + mutex_unlock(&data->lock); + return IIO_VAL_INT; + case IIO_HUMIDITYRELATIVE: + mutex_lock(&data->lock); + *val = data->rht; + mutex_unlock(&data->lock); + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_PROCESSED: + ret = sgp40_measure_resistance_raw(data, &resistance_raw); + if (ret) + return ret; + + ret = sgp40_calc_voc(data, resistance_raw, &voc); + if (ret) + return ret; + + *val = voc / (1 << SGP40_CALC_POWER); + /* + * calculation should fit into integer, where: + * voc <= (500 * 2^SGP40_CALC_POWER) = 8192000 + * (with SGP40_CALC_POWER = 14) + */ + *val2 = ((voc % (1 << SGP40_CALC_POWER)) * 244) / (1 << (SGP40_CALC_POWER - 12)); + dev_dbg(data->dev, "voc: %d val: %d.%06d\n", voc, *val, *val2); + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_CALIBBIAS: + mutex_lock(&data->lock); + *val = data->res_calibbias; + mutex_unlock(&data->lock); + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int sgp40_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct sgp40_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_TEMP: + if ((val < -45000) || (val > 130000)) + return -EINVAL; + + mutex_lock(&data->lock); + data->temp = val; + mutex_unlock(&data->lock); + return 0; + case IIO_HUMIDITYRELATIVE: + if ((val < 0) || (val > 100000)) + return -EINVAL; + + mutex_lock(&data->lock); + data->rht = val; + mutex_unlock(&data->lock); + return 0; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_CALIBBIAS: + if ((val < 20000) || (val > 52768)) + return -EINVAL; + + mutex_lock(&data->lock); + data->res_calibbias = val; + mutex_unlock(&data->lock); + return 0; + } + return -EINVAL; +} + +static const struct iio_info sgp40_info = { + .read_raw = sgp40_read_raw, + .write_raw = sgp40_write_raw, +}; + +static int sgp40_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct iio_dev *indio_dev; + struct sgp40_data *data; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->client = client; + data->dev = dev; + + crc8_populate_msb(sgp40_crc8_table, SGP40_CRC8_POLYNOMIAL); + + mutex_init(&data->lock); + + /* set default values */ + data->rht = 50000; /* 50 % */ + data->temp = 25000; /* 25 °C */ + data->res_calibbias = 30000; /* resistance raw value for voc index of 250 */ + + indio_dev->info = &sgp40_info; + indio_dev->name = id->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = sgp40_channels; + indio_dev->num_channels = ARRAY_SIZE(sgp40_channels); + + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + dev_err(dev, "failed to register iio device\n"); + + return ret; +} + +static const struct i2c_device_id sgp40_id[] = { + { "sgp40" }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, sgp40_id); + +static const struct of_device_id sgp40_dt_ids[] = { + { .compatible = "sensirion,sgp40" }, + { } +}; + +MODULE_DEVICE_TABLE(of, sgp40_dt_ids); + +static struct i2c_driver sgp40_driver = { + .driver = { + .name = "sgp40", + .of_match_table = sgp40_dt_ids, + }, + .probe = sgp40_probe, + .id_table = sgp40_id, +}; +module_i2c_driver(sgp40_driver); + +MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>"); +MODULE_DESCRIPTION("Sensirion SGP40 gas sensor"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c index 802f9ae04cf4..dccc471e79da 100644 --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c @@ -9,13 +9,11 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/slab.h> #include <linux/iio/iio.h> #include <linux/iio/trigger.h> #include <linux/interrupt.h> #include <linux/iio/buffer.h> #include <linux/iio/trigger_consumer.h> -#include <linux/iio/triggered_buffer.h> #include <linux/irqreturn.h> #include <linux/regmap.h> diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index 7a69c1be7393..0bbb090b108c 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -12,6 +12,7 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/iio/iio.h> +#include <linux/mutex.h> #include <linux/property.h> #include <linux/regulator/consumer.h> #include <linux/regmap.h> diff --git a/drivers/iio/common/st_sensors/st_sensors_core.h b/drivers/iio/common/st_sensors/st_sensors_core.h index e8894be55660..09f3e602a2e2 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.h +++ b/drivers/iio/common/st_sensors/st_sensors_core.h @@ -4,6 +4,7 @@ */ #ifndef __ST_SENSORS_CORE_H #define __ST_SENSORS_CORE_H +struct iio_dev; int st_sensors_write_data_with_mask(struct iio_dev *indio_dev, u8 reg_addr, u8 mask, u8 data); #endif diff --git a/drivers/iio/common/st_sensors/st_sensors_i2c.c b/drivers/iio/common/st_sensors/st_sensors_i2c.c index b9e59ad32a02..b3ff88700866 100644 --- a/drivers/iio/common/st_sensors/st_sensors_i2c.c +++ b/drivers/iio/common/st_sensors/st_sensors_i2c.c @@ -7,15 +7,14 @@ * Denis Ciocca <denis.ciocca@st.com> */ +#include <linux/i2c.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/slab.h> #include <linux/iio/iio.h> #include <linux/regmap.h> #include <linux/iio/common/st_sensors_i2c.h> - #define ST_SENSORS_I2C_MULTIREAD 0x80 static const struct regmap_config st_sensors_i2c_regmap_config = { diff --git a/drivers/iio/common/st_sensors/st_sensors_spi.c b/drivers/iio/common/st_sensors/st_sensors_spi.c index 48fc41dc5633..0d1d66c77cd8 100644 --- a/drivers/iio/common/st_sensors/st_sensors_spi.c +++ b/drivers/iio/common/st_sensors/st_sensors_spi.c @@ -9,13 +9,12 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/slab.h> #include <linux/iio/iio.h> #include <linux/property.h> #include <linux/regmap.h> +#include <linux/spi/spi.h> #include <linux/iio/common/st_sensors_spi.h> -#include "st_sensors_core.h" #define ST_SENSORS_SPI_MULTIREAD 0xc0 diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c index 0b511665dee5..64e0a748a855 100644 --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c @@ -9,7 +9,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/slab.h> #include <linux/iio/iio.h> #include <linux/iio/trigger.h> #include <linux/interrupt.h> diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c index 9bde86982912..530529feebb5 100644 --- a/drivers/iio/dac/ad5624r_spi.c +++ b/drivers/iio/dac/ad5624r_spi.c @@ -229,7 +229,7 @@ static int ad5624r_probe(struct spi_device *spi) if (!indio_dev) return -ENOMEM; st = iio_priv(indio_dev); - st->reg = devm_regulator_get(&spi->dev, "vcc"); + st->reg = devm_regulator_get_optional(&spi->dev, "vref"); if (!IS_ERR(st->reg)) { ret = regulator_enable(st->reg); if (ret) @@ -240,6 +240,22 @@ static int ad5624r_probe(struct spi_device *spi) goto error_disable_reg; voltage_uv = ret; + } else { + if (PTR_ERR(st->reg) != -ENODEV) + return PTR_ERR(st->reg); + /* Backwards compatibility. This naming is not correct */ + st->reg = devm_regulator_get_optional(&spi->dev, "vcc"); + if (!IS_ERR(st->reg)) { + ret = regulator_enable(st->reg); + if (ret) + return ret; + + ret = regulator_get_voltage(st->reg); + if (ret < 0) + goto error_disable_reg; + + voltage_uv = ret; + } } spi_set_drvdata(spi, indio_dev); diff --git a/drivers/iio/dac/max5821.c b/drivers/iio/dac/max5821.c index bd6e75699a63..bd0b7f361154 100644 --- a/drivers/iio/dac/max5821.c +++ b/drivers/iio/dac/max5821.c @@ -294,6 +294,11 @@ static const struct iio_info max5821_info = { .write_raw = max5821_write_raw, }; +static void max5821_regulator_disable(void *reg) +{ + regulator_disable(reg); +} + static int max5821_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -306,7 +311,6 @@ static int max5821_probe(struct i2c_client *client, if (!indio_dev) return -ENOMEM; data = iio_priv(indio_dev); - i2c_set_clientdata(client, indio_dev); data->client = client; mutex_init(&data->lock); @@ -321,21 +325,29 @@ static int max5821_probe(struct i2c_client *client, ret = PTR_ERR(data->vref_reg); dev_err(&client->dev, "Failed to get vref regulator: %d\n", ret); - goto error_free_reg; + return ret; } ret = regulator_enable(data->vref_reg); if (ret) { dev_err(&client->dev, "Failed to enable vref regulator: %d\n", ret); - goto error_free_reg; + return ret; + } + + ret = devm_add_action_or_reset(&client->dev, max5821_regulator_disable, + data->vref_reg); + if (ret) { + dev_err(&client->dev, + "Failed to add action to managed regulator: %d\n", ret); + return ret; } ret = regulator_get_voltage(data->vref_reg); if (ret < 0) { dev_err(&client->dev, "Failed to get voltage on regulator: %d\n", ret); - goto error_disable_reg; + return ret; } data->vref_mv = ret / 1000; @@ -346,25 +358,7 @@ static int max5821_probe(struct i2c_client *client, indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &max5821_info; - return iio_device_register(indio_dev); - -error_disable_reg: - regulator_disable(data->vref_reg); - -error_free_reg: - - return ret; -} - -static int max5821_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct max5821_data *data = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - regulator_disable(data->vref_reg); - - return 0; + return devm_iio_device_register(&client->dev, indio_dev); } static const struct i2c_device_id max5821_id[] = { @@ -386,7 +380,6 @@ static struct i2c_driver max5821_driver = { .pm = &max5821_pm_ops, }, .probe = max5821_probe, - .remove = max5821_remove, .id_table = max5821_id, }; module_i2c_driver(max5821_driver); diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index bc63c2a34c5e..8f0ad022c7f1 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -303,8 +303,8 @@ static int hid_gyro_3d_probe(struct platform_device *pdev) return ret; } - indio_dev->channels = kmemdup(gyro_3d_channels, - sizeof(gyro_3d_channels), GFP_KERNEL); + indio_dev->channels = devm_kmemdup(&pdev->dev, gyro_3d_channels, + sizeof(gyro_3d_channels), GFP_KERNEL); if (!indio_dev->channels) { dev_err(&pdev->dev, "failed to duplicate channels\n"); return -ENOMEM; @@ -315,7 +315,7 @@ static int hid_gyro_3d_probe(struct platform_device *pdev) HID_USAGE_SENSOR_GYRO_3D, gyro_state); if (ret) { dev_err(&pdev->dev, "failed to setup attributes\n"); - goto error_free_dev_mem; + return ret; } indio_dev->num_channels = ARRAY_SIZE(gyro_3d_channels); @@ -329,7 +329,7 @@ static int hid_gyro_3d_probe(struct platform_device *pdev) &gyro_state->common_attributes); if (ret < 0) { dev_err(&pdev->dev, "trigger setup failed\n"); - goto error_free_dev_mem; + return ret; } ret = iio_device_register(indio_dev); @@ -354,8 +354,6 @@ error_iio_unreg: iio_device_unregister(indio_dev); error_remove_trigger: hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes); -error_free_dev_mem: - kfree(indio_dev->channels); return ret; } @@ -369,7 +367,6 @@ static int hid_gyro_3d_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes); - kfree(indio_dev->channels); return 0; } diff --git a/drivers/iio/gyro/st_gyro.h b/drivers/iio/gyro/st_gyro.h index 6537f5cb8320..f5332b6a02bc 100644 --- a/drivers/iio/gyro/st_gyro.h +++ b/drivers/iio/gyro/st_gyro.h @@ -26,7 +26,6 @@ #ifdef CONFIG_IIO_BUFFER int st_gyro_allocate_ring(struct iio_dev *indio_dev); -void st_gyro_deallocate_ring(struct iio_dev *indio_dev); int st_gyro_trig_set_state(struct iio_trigger *trig, bool state); #define ST_GYRO_TRIGGER_SET_STATE (&st_gyro_trig_set_state) #else /* CONFIG_IIO_BUFFER */ @@ -34,9 +33,6 @@ static inline int st_gyro_allocate_ring(struct iio_dev *indio_dev) { return 0; } -static inline void st_gyro_deallocate_ring(struct iio_dev *indio_dev) -{ -} #define ST_GYRO_TRIGGER_SET_STATE NULL #endif /* CONFIG_IIO_BUFFER */ diff --git a/drivers/iio/gyro/st_gyro_buffer.c b/drivers/iio/gyro/st_gyro_buffer.c index 4feb7ada7195..4ae33ef25b9c 100644 --- a/drivers/iio/gyro/st_gyro_buffer.c +++ b/drivers/iio/gyro/st_gyro_buffer.c @@ -9,14 +9,9 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/stat.h> -#include <linux/interrupt.h> -#include <linux/i2c.h> -#include <linux/delay.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> -#include <linux/iio/trigger_consumer.h> +#include <linux/iio/trigger.h> #include <linux/iio/triggered_buffer.h> #include <linux/iio/common/st_sensors.h> @@ -66,13 +61,8 @@ static const struct iio_buffer_setup_ops st_gyro_buffer_setup_ops = { int st_gyro_allocate_ring(struct iio_dev *indio_dev) { - return iio_triggered_buffer_setup(indio_dev, NULL, - &st_sensors_trigger_handler, &st_gyro_buffer_setup_ops); -} - -void st_gyro_deallocate_ring(struct iio_dev *indio_dev) -{ - iio_triggered_buffer_cleanup(indio_dev); + return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev, + NULL, &st_sensors_trigger_handler, &st_gyro_buffer_setup_ops); } MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index b86ee4d940d9..e8fc8af65143 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -9,17 +9,12 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/types.h> +#include <linux/mutex.h> #include <linux/interrupt.h> -#include <linux/i2c.h> -#include <linux/irq.h> -#include <linux/delay.h> +#include <linux/sysfs.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/iio/trigger.h> -#include <linux/iio/buffer.h> #include <linux/iio/common/st_sensors.h> #include "st_gyro.h" @@ -517,7 +512,7 @@ int st_gyro_common_probe(struct iio_dev *indio_dev) err = st_sensors_allocate_trigger(indio_dev, ST_GYRO_TRIGGER_OPS); if (err < 0) - goto st_gyro_probe_trigger_error; + return err; } err = iio_device_register(indio_dev); @@ -532,8 +527,6 @@ int st_gyro_common_probe(struct iio_dev *indio_dev) st_gyro_device_register_error: if (gdata->irq > 0) st_sensors_deallocate_trigger(indio_dev); -st_gyro_probe_trigger_error: - st_gyro_deallocate_ring(indio_dev); return err; } EXPORT_SYMBOL(st_gyro_common_probe); @@ -545,8 +538,6 @@ void st_gyro_common_remove(struct iio_dev *indio_dev) iio_device_unregister(indio_dev); if (gdata->irq > 0) st_sensors_deallocate_trigger(indio_dev); - - st_gyro_deallocate_ring(indio_dev); } EXPORT_SYMBOL(st_gyro_common_remove); diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c index a25cc0379e16..3ef86e16ee65 100644 --- a/drivers/iio/gyro/st_gyro_i2c.c +++ b/drivers/iio/gyro/st_gyro_i2c.c @@ -9,7 +9,7 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/slab.h> +#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/iio/iio.h> diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c index 18d6a2aeda45..41d835493347 100644 --- a/drivers/iio/gyro/st_gyro_spi.c +++ b/drivers/iio/gyro/st_gyro_spi.c @@ -9,7 +9,7 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/slab.h> +#include <linux/mod_devicetable.h> #include <linux/spi/spi.h> #include <linux/iio/iio.h> diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c index 2a957f19048e..9e0fce917ce4 100644 --- a/drivers/iio/humidity/hdc100x.c +++ b/drivers/iio/humidity/hdc100x.c @@ -25,6 +25,8 @@ #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> +#include <linux/time.h> + #define HDC100X_REG_TEMP 0x00 #define HDC100X_REG_HUMIDITY 0x01 @@ -166,7 +168,7 @@ static int hdc100x_get_measurement(struct hdc100x_data *data, struct iio_chan_spec const *chan) { struct i2c_client *client = data->client; - int delay = data->adc_int_us[chan->address]; + int delay = data->adc_int_us[chan->address] + 1*USEC_PER_MSEC; int ret; __be16 val; @@ -316,7 +318,7 @@ static irqreturn_t hdc100x_trigger_handler(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct hdc100x_data *data = iio_priv(indio_dev); struct i2c_client *client = data->client; - int delay = data->adc_int_us[0] + data->adc_int_us[1]; + int delay = data->adc_int_us[0] + data->adc_int_us[1] + 2*USEC_PER_MSEC; int ret; /* dual read starts at temp register */ diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c index a5b421f42287..b9a06ca29bee 100644 --- a/drivers/iio/imu/adis.c +++ b/drivers/iio/imu/adis.c @@ -411,12 +411,11 @@ int __adis_initial_startup(struct adis *adis) int ret; /* check if the device has rst pin low */ - gpio = devm_gpiod_get_optional(&adis->spi->dev, "reset", GPIOD_ASIS); + gpio = devm_gpiod_get_optional(&adis->spi->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(gpio)) return PTR_ERR(gpio); if (gpio) { - gpiod_set_value_cansleep(gpio, 1); msleep(10); /* bring device out of reset */ gpiod_set_value_cansleep(gpio, 0); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 8a7a920e6200..597768c29a72 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -143,6 +143,7 @@ static const struct inv_mpu6050_hw hw_info[] = { .config = &chip_config_6050, .fifo_size = 1024, .temp = {INV_MPU6050_TEMP_OFFSET, INV_MPU6050_TEMP_SCALE}, + .startup_time = {INV_MPU6050_GYRO_STARTUP_TIME, INV_MPU6050_ACCEL_STARTUP_TIME}, }, { .whoami = INV_MPU6500_WHOAMI_VALUE, @@ -151,6 +152,7 @@ static const struct inv_mpu6050_hw hw_info[] = { .config = &chip_config_6500, .fifo_size = 512, .temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE}, + .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME}, }, { .whoami = INV_MPU6515_WHOAMI_VALUE, @@ -159,6 +161,7 @@ static const struct inv_mpu6050_hw hw_info[] = { .config = &chip_config_6500, .fifo_size = 512, .temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE}, + .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME}, }, { .whoami = INV_MPU6880_WHOAMI_VALUE, @@ -167,6 +170,7 @@ static const struct inv_mpu6050_hw hw_info[] = { .config = &chip_config_6500, .fifo_size = 4096, .temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE}, + .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME}, }, { .whoami = INV_MPU6000_WHOAMI_VALUE, @@ -175,6 +179,7 @@ static const struct inv_mpu6050_hw hw_info[] = { .config = &chip_config_6050, .fifo_size = 1024, .temp = {INV_MPU6050_TEMP_OFFSET, INV_MPU6050_TEMP_SCALE}, + .startup_time = {INV_MPU6050_GYRO_STARTUP_TIME, INV_MPU6050_ACCEL_STARTUP_TIME}, }, { .whoami = INV_MPU9150_WHOAMI_VALUE, @@ -183,6 +188,7 @@ static const struct inv_mpu6050_hw hw_info[] = { .config = &chip_config_6050, .fifo_size = 1024, .temp = {INV_MPU6050_TEMP_OFFSET, INV_MPU6050_TEMP_SCALE}, + .startup_time = {INV_MPU6050_GYRO_STARTUP_TIME, INV_MPU6050_ACCEL_STARTUP_TIME}, }, { .whoami = INV_MPU9250_WHOAMI_VALUE, @@ -191,6 +197,7 @@ static const struct inv_mpu6050_hw hw_info[] = { .config = &chip_config_6500, .fifo_size = 512, .temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE}, + .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME}, }, { .whoami = INV_MPU9255_WHOAMI_VALUE, @@ -199,6 +206,7 @@ static const struct inv_mpu6050_hw hw_info[] = { .config = &chip_config_6500, .fifo_size = 512, .temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE}, + .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME}, }, { .whoami = INV_ICM20608_WHOAMI_VALUE, @@ -207,6 +215,7 @@ static const struct inv_mpu6050_hw hw_info[] = { .config = &chip_config_6500, .fifo_size = 512, .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE}, + .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME}, }, { .whoami = INV_ICM20609_WHOAMI_VALUE, @@ -215,6 +224,7 @@ static const struct inv_mpu6050_hw hw_info[] = { .config = &chip_config_6500, .fifo_size = 4 * 1024, .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE}, + .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME}, }, { .whoami = INV_ICM20689_WHOAMI_VALUE, @@ -223,6 +233,7 @@ static const struct inv_mpu6050_hw hw_info[] = { .config = &chip_config_6500, .fifo_size = 4 * 1024, .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE}, + .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME}, }, { .whoami = INV_ICM20602_WHOAMI_VALUE, @@ -231,6 +242,7 @@ static const struct inv_mpu6050_hw hw_info[] = { .config = &chip_config_6500, .fifo_size = 1008, .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE}, + .startup_time = {INV_ICM20602_GYRO_STARTUP_TIME, INV_ICM20602_ACCEL_STARTUP_TIME}, }, { .whoami = INV_ICM20690_WHOAMI_VALUE, @@ -239,6 +251,7 @@ static const struct inv_mpu6050_hw hw_info[] = { .config = &chip_config_6500, .fifo_size = 1024, .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE}, + .startup_time = {INV_ICM20690_GYRO_STARTUP_TIME, INV_ICM20690_ACCEL_STARTUP_TIME}, }, { .whoami = INV_IAM20680_WHOAMI_VALUE, @@ -247,6 +260,7 @@ static const struct inv_mpu6050_hw hw_info[] = { .config = &chip_config_6500, .fifo_size = 512, .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE}, + .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME}, }, }; @@ -379,12 +393,12 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, sleep = 0; if (en) { if (mask & INV_MPU6050_SENSOR_ACCL) { - if (sleep < INV_MPU6050_ACCEL_UP_TIME) - sleep = INV_MPU6050_ACCEL_UP_TIME; + if (sleep < st->hw->startup_time.accel) + sleep = st->hw->startup_time.accel; } if (mask & INV_MPU6050_SENSOR_GYRO) { - if (sleep < INV_MPU6050_GYRO_UP_TIME) - sleep = INV_MPU6050_GYRO_UP_TIME; + if (sleep < st->hw->startup_time.gyro) + sleep = st->hw->startup_time.gyro; } } else { if (mask & INV_MPU6050_SENSOR_GYRO) { diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h index 58188dc0dd13..c6aa36ee966a 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -149,6 +149,10 @@ struct inv_mpu6050_hw { int offset; int scale; } temp; + struct { + unsigned int accel; + unsigned int gyro; + } startup_time; }; /* @@ -320,11 +324,21 @@ struct inv_mpu6050_state { /* delay time in milliseconds */ #define INV_MPU6050_POWER_UP_TIME 100 #define INV_MPU6050_TEMP_UP_TIME 100 -#define INV_MPU6050_ACCEL_UP_TIME 20 -#define INV_MPU6050_GYRO_UP_TIME 35 +#define INV_MPU6050_ACCEL_STARTUP_TIME 20 +#define INV_MPU6050_GYRO_STARTUP_TIME 60 #define INV_MPU6050_GYRO_DOWN_TIME 150 #define INV_MPU6050_SUSPEND_DELAY_MS 2000 +#define INV_MPU6500_GYRO_STARTUP_TIME 70 +#define INV_MPU6500_ACCEL_STARTUP_TIME 30 + +#define INV_ICM20602_GYRO_STARTUP_TIME 100 +#define INV_ICM20602_ACCEL_STARTUP_TIME 20 + +#define INV_ICM20690_GYRO_STARTUP_TIME 80 +#define INV_ICM20690_ACCEL_STARTUP_TIME 10 + + /* delay time in microseconds */ #define INV_MPU6050_REG_UP_TIME_MIN 5000 #define INV_MPU6050_REG_UP_TIME_MAX 10000 diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c index 2d0e8cdd4848..882546897255 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c @@ -91,22 +91,11 @@ static unsigned int inv_scan_query(struct iio_dev *indio_dev) static unsigned int inv_compute_skip_samples(const struct inv_mpu6050_state *st) { - unsigned int gyro_skip = 0; - unsigned int magn_skip = 0; - unsigned int skip_samples; - - /* gyro first sample is out of specs, skip it */ - if (st->chip_config.gyro_fifo_enable) - gyro_skip = 1; + unsigned int skip_samples = 0; /* mag first sample is always not ready, skip it */ if (st->chip_config.magn_fifo_enable) - magn_skip = 1; - - /* compute first samples to skip */ - skip_samples = gyro_skip; - if (magn_skip > skip_samples) - skip_samples = magn_skip; + skip_samples = 1; return skip_samples; } diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c index 8204f7303fd7..5e6625140db7 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c @@ -10,6 +10,7 @@ #include <linux/device.h> #include <linux/err.h> #include <linux/module.h> +#include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/iio/common/st_sensors.h> diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c index 50a36ab53bc3..78bede358747 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c @@ -10,7 +10,8 @@ #include <linux/i2c.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/slab.h> +#include <linux/mod_devicetable.h> +#include <linux/regmap.h> #include <linux/iio/common/st_sensors_i2c.h> diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c index 272c88990dd0..180b54e66438 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c @@ -9,7 +9,8 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/slab.h> +#include <linux/mod_devicetable.h> +#include <linux/regmap.h> #include <linux/spi/spi.h> #include <linux/iio/common/st_sensors_spi.h> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index fdd623407b96..a95cc2da56be 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -354,13 +354,14 @@ static int iio_scan_mask_set(struct iio_dev *indio_dev, const unsigned long *mask; unsigned long *trialmask; - trialmask = bitmap_zalloc(indio_dev->masklength, GFP_KERNEL); - if (trialmask == NULL) - return -ENOMEM; if (!indio_dev->masklength) { WARN(1, "Trying to set scanmask prior to registering buffer\n"); - goto err_invalid_mask; + return -EINVAL; } + + trialmask = bitmap_alloc(indio_dev->masklength, GFP_KERNEL); + if (!trialmask) + return -ENOMEM; bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength); set_bit(bit, trialmask); diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 6d2175eb7af2..2dbb37e09b8c 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -740,10 +740,13 @@ static ssize_t iio_read_channel_label(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - if (!indio_dev->info->read_label) - return -EINVAL; + if (indio_dev->info->read_label) + return indio_dev->info->read_label(indio_dev, this_attr->c, buf); + + if (this_attr->c->extend_name) + return sprintf(buf, "%s\n", this_attr->c->extend_name); - return indio_dev->info->read_label(indio_dev, this_attr->c, buf); + return -EINVAL; } static ssize_t iio_read_channel_info(struct device *dev, @@ -1183,7 +1186,7 @@ static int iio_device_add_channel_label(struct iio_dev *indio_dev, struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); int ret; - if (!indio_dev->info->read_label) + if (!indio_dev->info->read_label && !chan->extend_name) return 0; ret = __iio_add_chan_devattr("label", @@ -1858,6 +1861,24 @@ static int iio_check_unique_scan_index(struct iio_dev *indio_dev) return 0; } +static int iio_check_extended_name(const struct iio_dev *indio_dev) +{ + unsigned int i; + + if (!indio_dev->info->read_label) + return 0; + + for (i = 0; i < indio_dev->num_channels; i++) { + if (indio_dev->channels[i].extend_name) { + dev_err(&indio_dev->dev, + "Cannot use labels and extend_name at the same time\n"); + return -EINVAL; + } + } + + return 0; +} + static const struct iio_buffer_setup_ops noop_ring_setup_ops; int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod) @@ -1882,6 +1903,10 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod) if (ret < 0) return ret; + ret = iio_check_extended_name(indio_dev); + if (ret < 0) + return ret; + iio_device_register_debugfs(indio_dev); ret = iio_buffers_alloc_sysfs_and_mask(indio_dev); diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c index 17dac8d0e11d..6b33975c8d73 100644 --- a/drivers/iio/light/adjd_s311.c +++ b/drivers/iio/light/adjd_s311.c @@ -54,7 +54,10 @@ struct adjd_s311_data { struct i2c_client *client; - u16 *buffer; + struct { + s16 chans[4]; + s64 ts __aligned(8); + } scan; }; enum adjd_s311_channel_idx { @@ -129,10 +132,10 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p) if (ret < 0) goto done; - data->buffer[j++] = ret & ADJD_S311_DATA_MASK; + data->scan.chans[j++] = ret & ADJD_S311_DATA_MASK; } - iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, time_ns); + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, time_ns); done: iio_trigger_notify_done(indio_dev->trig); @@ -225,23 +228,9 @@ static int adjd_s311_write_raw(struct iio_dev *indio_dev, return -EINVAL; } -static int adjd_s311_update_scan_mode(struct iio_dev *indio_dev, - const unsigned long *scan_mask) -{ - struct adjd_s311_data *data = iio_priv(indio_dev); - - kfree(data->buffer); - data->buffer = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); - if (data->buffer == NULL) - return -ENOMEM; - - return 0; -} - static const struct iio_info adjd_s311_info = { .read_raw = adjd_s311_read_raw, .write_raw = adjd_s311_write_raw, - .update_scan_mode = adjd_s311_update_scan_mode, }; static int adjd_s311_probe(struct i2c_client *client, @@ -256,7 +245,6 @@ static int adjd_s311_probe(struct i2c_client *client, return -ENOMEM; data = iio_priv(indio_dev); - i2c_set_clientdata(client, indio_dev); data->client = client; indio_dev->info = &adjd_s311_info; @@ -265,34 +253,12 @@ static int adjd_s311_probe(struct i2c_client *client, indio_dev->num_channels = ARRAY_SIZE(adjd_s311_channels); indio_dev->modes = INDIO_DIRECT_MODE; - err = iio_triggered_buffer_setup(indio_dev, NULL, - adjd_s311_trigger_handler, NULL); + err = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL, + adjd_s311_trigger_handler, NULL); if (err < 0) return err; - err = iio_device_register(indio_dev); - if (err) - goto exit_unreg_buffer; - - dev_info(&client->dev, "ADJD-S311 color sensor registered\n"); - - return 0; - -exit_unreg_buffer: - iio_triggered_buffer_cleanup(indio_dev); - return err; -} - -static int adjd_s311_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct adjd_s311_data *data = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - kfree(data->buffer); - - return 0; + return devm_iio_device_register(&client->dev, indio_dev); } static const struct i2c_device_id adjd_s311_id[] = { @@ -306,7 +272,6 @@ static struct i2c_driver adjd_s311_driver = { .name = ADJD_S311_DRV_NAME, }, .probe = adjd_s311_probe, - .remove = adjd_s311_remove, .id_table = adjd_s311_id, }; module_i2c_driver(adjd_s311_driver); diff --git a/drivers/iio/light/cm3323.c b/drivers/iio/light/cm3323.c index 6d1b0ffd144b..fd9a8c27de2e 100644 --- a/drivers/iio/light/cm3323.c +++ b/drivers/iio/light/cm3323.c @@ -256,9 +256,16 @@ static const struct i2c_device_id cm3323_id[] = { }; MODULE_DEVICE_TABLE(i2c, cm3323_id); +static const struct of_device_id cm3323_of_match[] = { + { .compatible = "capella,cm3323", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, cm3323_of_match); + static struct i2c_driver cm3323_driver = { .driver = { .name = CM3323_DRV_NAME, + .of_match_table = cm3323_of_match, }, .probe = cm3323_probe, .id_table = cm3323_id, diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index 2ff252c75c03..5a1a625d8d16 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -294,8 +294,8 @@ static int hid_als_probe(struct platform_device *pdev) return ret; } - indio_dev->channels = kmemdup(als_channels, - sizeof(als_channels), GFP_KERNEL); + indio_dev->channels = devm_kmemdup(&pdev->dev, als_channels, + sizeof(als_channels), GFP_KERNEL); if (!indio_dev->channels) { dev_err(&pdev->dev, "failed to duplicate channels\n"); return -ENOMEM; @@ -306,7 +306,7 @@ static int hid_als_probe(struct platform_device *pdev) HID_USAGE_SENSOR_ALS, als_state); if (ret) { dev_err(&pdev->dev, "failed to setup attributes\n"); - goto error_free_dev_mem; + return ret; } indio_dev->num_channels = @@ -321,7 +321,7 @@ static int hid_als_probe(struct platform_device *pdev) &als_state->common_attributes); if (ret < 0) { dev_err(&pdev->dev, "trigger setup failed\n"); - goto error_free_dev_mem; + return ret; } ret = iio_device_register(indio_dev); @@ -346,8 +346,6 @@ error_iio_unreg: iio_device_unregister(indio_dev); error_remove_trigger: hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes); -error_free_dev_mem: - kfree(indio_dev->channels); return ret; } @@ -361,7 +359,6 @@ static int hid_als_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ALS); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes); - kfree(indio_dev->channels); return 0; } diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c index 1621530f5f61..f10fa2abfe72 100644 --- a/drivers/iio/light/hid-sensor-prox.c +++ b/drivers/iio/light/hid-sensor-prox.c @@ -253,8 +253,8 @@ static int hid_prox_probe(struct platform_device *pdev) return ret; } - indio_dev->channels = kmemdup(prox_channels, sizeof(prox_channels), - GFP_KERNEL); + indio_dev->channels = devm_kmemdup(&pdev->dev, prox_channels, + sizeof(prox_channels), GFP_KERNEL); if (!indio_dev->channels) { dev_err(&pdev->dev, "failed to duplicate channels\n"); return -ENOMEM; @@ -265,7 +265,7 @@ static int hid_prox_probe(struct platform_device *pdev) HID_USAGE_SENSOR_PROX, prox_state); if (ret) { dev_err(&pdev->dev, "failed to setup attributes\n"); - goto error_free_dev_mem; + return ret; } indio_dev->num_channels = ARRAY_SIZE(prox_channels); @@ -279,7 +279,7 @@ static int hid_prox_probe(struct platform_device *pdev) &prox_state->common_attributes); if (ret) { dev_err(&pdev->dev, "trigger setup failed\n"); - goto error_free_dev_mem; + return ret; } ret = iio_device_register(indio_dev); @@ -304,8 +304,6 @@ error_iio_unreg: iio_device_unregister(indio_dev); error_remove_trigger: hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes); -error_free_dev_mem: - kfree(indio_dev->channels); return ret; } @@ -319,7 +317,6 @@ static int hid_prox_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PROX); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes); - kfree(indio_dev->channels); return 0; } diff --git a/drivers/iio/light/si1145.c b/drivers/iio/light/si1145.c index e2abad48b9f4..e8f6cdf26f22 100644 --- a/drivers/iio/light/si1145.c +++ b/drivers/iio/light/si1145.c @@ -220,7 +220,6 @@ static int __si1145_command_reset(struct si1145_data *data) return -ETIMEDOUT; } msleep(SI1145_COMMAND_MINSLEEP_MS); - continue; } } diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c index 0593abd600ec..b87222141429 100644 --- a/drivers/iio/light/tcs3414.c +++ b/drivers/iio/light/tcs3414.c @@ -267,6 +267,18 @@ static const struct iio_buffer_setup_ops tcs3414_buffer_setup_ops = { .predisable = tcs3414_buffer_predisable, }; +static int tcs3414_powerdown(struct tcs3414_data *data) +{ + return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL, + data->control & ~(TCS3414_CONTROL_POWER | + TCS3414_CONTROL_ADC_EN)); +} + +static void tcs3414_powerdown_cleanup(void *data) +{ + tcs3414_powerdown(data); +} + static int tcs3414_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -309,6 +321,11 @@ static int tcs3414_probe(struct i2c_client *client, if (ret < 0) return ret; + ret = devm_add_action_or_reset(&client->dev, tcs3414_powerdown_cleanup, + data); + if (ret < 0) + return ret; + data->timing = TCS3414_INTEG_12MS; /* free running */ ret = i2c_smbus_write_byte_data(data->client, TCS3414_TIMING, data->timing); @@ -320,38 +337,12 @@ static int tcs3414_probe(struct i2c_client *client, return ret; data->gain = ret; - ret = iio_triggered_buffer_setup(indio_dev, NULL, + ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL, tcs3414_trigger_handler, &tcs3414_buffer_setup_ops); if (ret < 0) return ret; - ret = iio_device_register(indio_dev); - if (ret < 0) - goto buffer_cleanup; - - return 0; - -buffer_cleanup: - iio_triggered_buffer_cleanup(indio_dev); - return ret; -} - -static int tcs3414_powerdown(struct tcs3414_data *data) -{ - return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL, - data->control & ~(TCS3414_CONTROL_POWER | - TCS3414_CONTROL_ADC_EN)); -} - -static int tcs3414_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - tcs3414_powerdown(iio_priv(indio_dev)); - - return 0; + return devm_iio_device_register(&client->dev, indio_dev); } #ifdef CONFIG_PM_SLEEP @@ -385,7 +376,6 @@ static struct i2c_driver tcs3414_driver = { .pm = &tcs3414_pm_ops, }, .probe = tcs3414_probe, - .remove = tcs3414_remove, .id_table = tcs3414_id, }; module_i2c_driver(tcs3414_driver); diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h index fb6c906c4c0c..785b7f7b8b06 100644 --- a/drivers/iio/magnetometer/st_magn.h +++ b/drivers/iio/magnetometer/st_magn.h @@ -25,25 +25,13 @@ #ifdef CONFIG_IIO_BUFFER int st_magn_allocate_ring(struct iio_dev *indio_dev); -void st_magn_deallocate_ring(struct iio_dev *indio_dev); int st_magn_trig_set_state(struct iio_trigger *trig, bool state); #define ST_MAGN_TRIGGER_SET_STATE (&st_magn_trig_set_state) #else /* CONFIG_IIO_BUFFER */ -static inline int st_magn_probe_trigger(struct iio_dev *indio_dev, int irq) -{ - return 0; -} -static inline void st_magn_remove_trigger(struct iio_dev *indio_dev, int irq) -{ - return; -} static inline int st_magn_allocate_ring(struct iio_dev *indio_dev) { return 0; } -static inline void st_magn_deallocate_ring(struct iio_dev *indio_dev) -{ -} #define ST_MAGN_TRIGGER_SET_STATE NULL #endif /* CONFIG_IIO_BUFFER */ diff --git a/drivers/iio/magnetometer/st_magn_buffer.c b/drivers/iio/magnetometer/st_magn_buffer.c index 4917721fa2e5..cb43ccda808d 100644 --- a/drivers/iio/magnetometer/st_magn_buffer.c +++ b/drivers/iio/magnetometer/st_magn_buffer.c @@ -9,14 +9,9 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/stat.h> -#include <linux/interrupt.h> -#include <linux/i2c.h> -#include <linux/delay.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> -#include <linux/iio/trigger_consumer.h> +#include <linux/iio/trigger.h> #include <linux/iio/triggered_buffer.h> #include <linux/iio/common/st_sensors.h> @@ -46,13 +41,8 @@ static const struct iio_buffer_setup_ops st_magn_buffer_setup_ops = { int st_magn_allocate_ring(struct iio_dev *indio_dev) { - return iio_triggered_buffer_setup(indio_dev, NULL, - &st_sensors_trigger_handler, &st_magn_buffer_setup_ops); -} - -void st_magn_deallocate_ring(struct iio_dev *indio_dev) -{ - iio_triggered_buffer_cleanup(indio_dev); + return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev, + NULL, &st_sensors_trigger_handler, &st_magn_buffer_setup_ops); } MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 0048c3cd36ee..9ffd50d796bf 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -9,16 +9,11 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/i2c.h> -#include <linux/irq.h> -#include <linux/delay.h> +#include <linux/mutex.h> +#include <linux/sysfs.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> -#include <linux/iio/buffer.h> +#include <linux/iio/trigger.h> #include <linux/iio/common/st_sensors.h> #include "st_magn.h" @@ -652,7 +647,7 @@ int st_magn_common_probe(struct iio_dev *indio_dev) err = st_sensors_allocate_trigger(indio_dev, ST_MAGN_TRIGGER_OPS); if (err < 0) - goto st_magn_probe_trigger_error; + return err; } err = iio_device_register(indio_dev); @@ -667,8 +662,6 @@ int st_magn_common_probe(struct iio_dev *indio_dev) st_magn_device_register_error: if (mdata->irq > 0) st_sensors_deallocate_trigger(indio_dev); -st_magn_probe_trigger_error: - st_magn_deallocate_ring(indio_dev); return err; } EXPORT_SYMBOL(st_magn_common_probe); @@ -680,8 +673,6 @@ void st_magn_common_remove(struct iio_dev *indio_dev) iio_device_unregister(indio_dev); if (mdata->irq > 0) st_sensors_deallocate_trigger(indio_dev); - - st_magn_deallocate_ring(indio_dev); } EXPORT_SYMBOL(st_magn_common_remove); diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c index 3e23c117de8e..2dfe4ee99591 100644 --- a/drivers/iio/magnetometer/st_magn_i2c.c +++ b/drivers/iio/magnetometer/st_magn_i2c.c @@ -9,7 +9,7 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/slab.h> +#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/iio/iio.h> diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c index 03c0a737aba6..fba978796395 100644 --- a/drivers/iio/magnetometer/st_magn_spi.c +++ b/drivers/iio/magnetometer/st_magn_spi.c @@ -9,7 +9,7 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/slab.h> +#include <linux/mod_devicetable.h> #include <linux/spi/spi.h> #include <linux/iio/iio.h> diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c index c0079e2c8807..ba5b581d5b25 100644 --- a/drivers/iio/orientation/hid-sensor-incl-3d.c +++ b/drivers/iio/orientation/hid-sensor-incl-3d.c @@ -326,8 +326,8 @@ static int hid_incl_3d_probe(struct platform_device *pdev) return ret; } - indio_dev->channels = kmemdup(incl_3d_channels, - sizeof(incl_3d_channels), GFP_KERNEL); + indio_dev->channels = devm_kmemdup(&pdev->dev, incl_3d_channels, + sizeof(incl_3d_channels), GFP_KERNEL); if (!indio_dev->channels) { dev_err(&pdev->dev, "failed to duplicate channels\n"); return -ENOMEM; @@ -339,7 +339,7 @@ static int hid_incl_3d_probe(struct platform_device *pdev) incl_state); if (ret) { dev_err(&pdev->dev, "failed to setup attributes\n"); - goto error_free_dev_mem; + return ret; } indio_dev->num_channels = ARRAY_SIZE(incl_3d_channels); @@ -353,7 +353,7 @@ static int hid_incl_3d_probe(struct platform_device *pdev) &incl_state->common_attributes); if (ret) { dev_err(&pdev->dev, "trigger setup failed\n"); - goto error_free_dev_mem; + return ret; } ret = iio_device_register(indio_dev); @@ -379,8 +379,6 @@ error_iio_unreg: iio_device_unregister(indio_dev); error_remove_trigger: hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes); -error_free_dev_mem: - kfree(indio_dev->channels); return ret; } @@ -394,7 +392,6 @@ static int hid_incl_3d_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes); - kfree(indio_dev->channels); return 0; } diff --git a/drivers/iio/potentiometer/Kconfig b/drivers/iio/potentiometer/Kconfig index 4cac0173db8b..832df8da2bc6 100644 --- a/drivers/iio/potentiometer/Kconfig +++ b/drivers/iio/potentiometer/Kconfig @@ -6,6 +6,16 @@ menu "Digital potentiometers" +config AD5110 + tristate "Analog Devices AD5110 and similar Digital Potentiometer driver" + depends on I2C + help + Say yes here to build support for the Analog Devices AD5110, AD5112 + and AD5114 digital potentiometer chip. + + To compile this driver as a module, choose M here: the + module will be called ad5110. + config AD5272 tristate "Analog Devices AD5272 and similar Digital Potentiometer driver" depends on I2C diff --git a/drivers/iio/potentiometer/Makefile b/drivers/iio/potentiometer/Makefile index 091adf3cdd0b..5ebb8e3bbd76 100644 --- a/drivers/iio/potentiometer/Makefile +++ b/drivers/iio/potentiometer/Makefile @@ -4,6 +4,7 @@ # # When adding new entries keep the list in alphabetical order +obj-$(CONFIG_AD5110) += ad5110.o obj-$(CONFIG_AD5272) += ad5272.o obj-$(CONFIG_DS1803) += ds1803.o obj-$(CONFIG_MAX5432) += max5432.o diff --git a/drivers/iio/potentiometer/ad5110.c b/drivers/iio/potentiometer/ad5110.c new file mode 100644 index 000000000000..d4eeedae56e5 --- /dev/null +++ b/drivers/iio/potentiometer/ad5110.c @@ -0,0 +1,344 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Analog Devices AD5110 digital potentiometer driver + * + * Copyright (C) 2021 Mugilraj Dhavachelvan <dmugil2000@gmail.com> + * + * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/AD5110_5112_5114.pdf + */ + +#include <linux/bitfield.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/i2c.h> +#include <linux/module.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> + +/* AD5110 commands */ +#define AD5110_EEPROM_WR 1 +#define AD5110_RDAC_WR 2 +#define AD5110_SHUTDOWN 3 +#define AD5110_RESET 4 +#define AD5110_RDAC_RD 5 +#define AD5110_EEPROM_RD 6 + +/* AD5110_EEPROM_RD data */ +#define AD5110_WIPER_POS 0 +#define AD5110_RESISTOR_TOL 1 + +#define AD5110_WIPER_RESISTANCE 70 + +struct ad5110_cfg { + int max_pos; + int kohms; + int shift; +}; + +enum ad5110_type { + AD5110_10, + AD5110_80, + AD5112_05, + AD5112_10, + AD5112_80, + AD5114_10, + AD5114_80, +}; + +static const struct ad5110_cfg ad5110_cfg[] = { + [AD5110_10] = { .max_pos = 128, .kohms = 10 }, + [AD5110_80] = { .max_pos = 128, .kohms = 80 }, + [AD5112_05] = { .max_pos = 64, .kohms = 5, .shift = 1 }, + [AD5112_10] = { .max_pos = 64, .kohms = 10, .shift = 1 }, + [AD5112_80] = { .max_pos = 64, .kohms = 80, .shift = 1 }, + [AD5114_10] = { .max_pos = 32, .kohms = 10, .shift = 2 }, + [AD5114_80] = { .max_pos = 32, .kohms = 80, .shift = 2 }, +}; + +struct ad5110_data { + struct i2c_client *client; + s16 tol; /* resistor tolerance */ + bool enable; + struct mutex lock; + const struct ad5110_cfg *cfg; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + u8 buf[2] ____cacheline_aligned; +}; + +static const struct iio_chan_spec ad5110_channels[] = { + { + .type = IIO_RESISTANCE, + .output = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_ENABLE), + }, +}; + +static int ad5110_read(struct ad5110_data *data, u8 cmd, int *val) +{ + int ret; + + mutex_lock(&data->lock); + data->buf[0] = cmd; + data->buf[1] = *val; + + ret = i2c_master_send_dmasafe(data->client, data->buf, sizeof(data->buf)); + if (ret < 0) { + goto error; + } else if (ret != sizeof(data->buf)) { + ret = -EIO; + goto error; + } + + ret = i2c_master_recv_dmasafe(data->client, data->buf, 1); + if (ret < 0) { + goto error; + } else if (ret != 1) { + ret = -EIO; + goto error; + } + + *val = data->buf[0]; + ret = 0; + +error: + mutex_unlock(&data->lock); + return ret; +} + +static int ad5110_write(struct ad5110_data *data, u8 cmd, u8 val) +{ + int ret; + + mutex_lock(&data->lock); + data->buf[0] = cmd; + data->buf[1] = val; + + ret = i2c_master_send_dmasafe(data->client, data->buf, sizeof(data->buf)); + if (ret < 0) { + goto error; + } else if (ret != sizeof(data->buf)) { + ret = -EIO; + goto error; + } + + ret = 0; + +error: + mutex_unlock(&data->lock); + return ret; +} + +static int ad5110_resistor_tol(struct ad5110_data *data, u8 cmd, int val) +{ + int ret; + + ret = ad5110_read(data, cmd, &val); + if (ret) + return ret; + + data->tol = data->cfg->kohms * (val & GENMASK(6, 0)) * 10 / 8; + if (!(val & BIT(7))) + data->tol *= -1; + + return 0; +} + +static ssize_t store_eeprom_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct ad5110_data *data = iio_priv(indio_dev); + int val = AD5110_WIPER_POS; + int ret; + + ret = ad5110_read(data, AD5110_EEPROM_RD, &val); + if (ret) + return ret; + + val = val >> data->cfg->shift; + return iio_format_value(buf, IIO_VAL_INT, 1, &val); +} + +static ssize_t store_eeprom_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 ad5110_data *data = iio_priv(indio_dev); + int ret; + + ret = ad5110_write(data, AD5110_EEPROM_WR, 0); + if (ret) { + dev_err(&data->client->dev, "RDAC to EEPROM write failed\n"); + return ret; + } + + /* The storing of EEPROM data takes approximately 18 ms. */ + msleep(20); + + return len; +} + +static IIO_DEVICE_ATTR_RW(store_eeprom, 0); + +static struct attribute *ad5110_attributes[] = { + &iio_dev_attr_store_eeprom.dev_attr.attr, + NULL +}; + +static const struct attribute_group ad5110_attribute_group = { + .attrs = ad5110_attributes, +}; + +static int ad5110_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct ad5110_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = ad5110_read(data, AD5110_RDAC_RD, val); + if (ret) + return ret; + + *val = *val >> data->cfg->shift; + return IIO_VAL_INT; + case IIO_CHAN_INFO_OFFSET: + *val = AD5110_WIPER_RESISTANCE * data->cfg->max_pos; + *val2 = 1000 * data->cfg->kohms + data->tol; + return IIO_VAL_FRACTIONAL; + case IIO_CHAN_INFO_SCALE: + *val = 1000 * data->cfg->kohms + data->tol; + *val2 = data->cfg->max_pos; + return IIO_VAL_FRACTIONAL; + case IIO_CHAN_INFO_ENABLE: + *val = data->enable; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int ad5110_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct ad5110_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (val > data->cfg->max_pos || val < 0) + return -EINVAL; + + return ad5110_write(data, AD5110_RDAC_WR, val << data->cfg->shift); + case IIO_CHAN_INFO_ENABLE: + if (val < 0 || val > 1) + return -EINVAL; + if (data->enable == val) + return 0; + ret = ad5110_write(data, AD5110_SHUTDOWN, val ? 0 : 1); + if (ret) + return ret; + data->enable = val; + return 0; + default: + return -EINVAL; + } +} + +static const struct iio_info ad5110_info = { + .read_raw = ad5110_read_raw, + .write_raw = ad5110_write_raw, + .attrs = &ad5110_attribute_group, +}; + +#define AD5110_COMPATIBLE(of_compatible, cfg) { \ + .compatible = of_compatible, \ + .data = &ad5110_cfg[cfg], \ +} + +static const struct of_device_id ad5110_of_match[] = { + AD5110_COMPATIBLE("adi,ad5110-10", AD5110_10), + AD5110_COMPATIBLE("adi,ad5110-80", AD5110_80), + AD5110_COMPATIBLE("adi,ad5112-05", AD5112_05), + AD5110_COMPATIBLE("adi,ad5112-10", AD5112_10), + AD5110_COMPATIBLE("adi,ad5112-80", AD5112_80), + AD5110_COMPATIBLE("adi,ad5114-10", AD5114_10), + AD5110_COMPATIBLE("adi,ad5114-80", AD5114_80), + { } +}; +MODULE_DEVICE_TABLE(of, ad5110_of_match); + +static const struct i2c_device_id ad5110_id[] = { + { "ad5110-10", AD5110_10 }, + { "ad5110-80", AD5110_80 }, + { "ad5112-05", AD5112_05 }, + { "ad5112-10", AD5112_10 }, + { "ad5112-80", AD5112_80 }, + { "ad5114-10", AD5114_10 }, + { "ad5114-80", AD5114_80 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ad5110_id); + +static int ad5110_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct iio_dev *indio_dev; + struct ad5110_data *data; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->client = client; + mutex_init(&data->lock); + data->enable = 1; + data->cfg = device_get_match_data(dev); + + /* refresh RDAC register with EEPROM */ + ret = ad5110_write(data, AD5110_RESET, 0); + if (ret) { + dev_err(dev, "Refresh RDAC with EEPROM failed\n"); + return ret; + } + + ret = ad5110_resistor_tol(data, AD5110_EEPROM_RD, AD5110_RESISTOR_TOL); + if (ret) { + dev_err(dev, "Read resistor tolerance failed\n"); + return ret; + } + + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &ad5110_info; + indio_dev->channels = ad5110_channels; + indio_dev->num_channels = ARRAY_SIZE(ad5110_channels); + indio_dev->name = client->name; + + return devm_iio_device_register(dev, indio_dev); +} + +static struct i2c_driver ad5110_driver = { + .driver = { + .name = "ad5110", + .of_match_table = ad5110_of_match, + }, + .probe_new = ad5110_probe, + .id_table = ad5110_id, +}; +module_i2c_driver(ad5110_driver); + +MODULE_AUTHOR("Mugilraj Dhavachelvan <dmugil2000@gmail.com>"); +MODULE_DESCRIPTION("AD5110 digital potentiometer"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/potentiometer/max5481.c b/drivers/iio/potentiometer/max5481.c index 6e22b538091f..098d144a8fdd 100644 --- a/drivers/iio/potentiometer/max5481.c +++ b/drivers/iio/potentiometer/max5481.c @@ -125,6 +125,11 @@ static const struct of_device_id max5481_match[] = { }; MODULE_DEVICE_TABLE(of, max5481_match); +static void max5481_wiper_save(void *data) +{ + max5481_write_cmd(data, MAX5481_COPY_AB_TO_NV, 0); +} + static int max5481_probe(struct spi_device *spi) { struct iio_dev *indio_dev; @@ -136,7 +141,6 @@ static int max5481_probe(struct spi_device *spi) if (!indio_dev) return -ENOMEM; - spi_set_drvdata(spi, indio_dev); data = iio_priv(indio_dev); data->spi = spi; @@ -158,18 +162,11 @@ static int max5481_probe(struct spi_device *spi) if (ret < 0) return ret; - return iio_device_register(indio_dev); -} - -static int max5481_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct max5481_data *data = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); + ret = devm_add_action(&spi->dev, max5481_wiper_save, data); + if (ret < 0) + return ret; - /* save wiper reg to NV reg */ - return max5481_write_cmd(data, MAX5481_COPY_AB_TO_NV, 0); + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id max5481_id_table[] = { @@ -187,7 +184,6 @@ static struct spi_driver max5481_driver = { .of_match_table = max5481_match, }, .probe = max5481_probe, - .remove = max5481_remove, .id_table = max5481_id_table, }; diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c index 10c52b8df2ba..a9215eb32d70 100644 --- a/drivers/iio/pressure/hid-sensor-press.c +++ b/drivers/iio/pressure/hid-sensor-press.c @@ -13,17 +13,24 @@ #include <linux/iio/buffer.h> #include "../common/hid-sensors/hid-sensor-trigger.h" -#define CHANNEL_SCAN_INDEX_PRESSURE 0 +enum { + CHANNEL_SCAN_INDEX_PRESSURE, + CHANNEL_SCAN_INDEX_TIMESTAMP, +}; struct press_state { struct hid_sensor_hub_callbacks callbacks; struct hid_sensor_common common_attributes; struct hid_sensor_hub_attribute_info press_attr; - u32 press_data; + struct { + u32 press_data; + u64 timestamp __aligned(8); + } scan; int scale_pre_decml; int scale_post_decml; int scale_precision; int value_offset; + s64 timestamp; }; static const u32 press_sensitivity_addresses[] = { @@ -41,7 +48,9 @@ static const struct iio_chan_spec press_channels[] = { BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_HYSTERESIS), .scan_index = CHANNEL_SCAN_INDEX_PRESSURE, - } + }, + IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP) + }; /* Adjust channel real bits based on report descriptor */ @@ -154,14 +163,6 @@ static const struct iio_info press_info = { .write_raw = &press_write_raw, }; -/* Function to push data to buffer */ -static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data, - int len) -{ - dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); - iio_push_to_buffers(indio_dev, data); -} - /* 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, @@ -171,10 +172,13 @@ static int press_proc_event(struct hid_sensor_hub_device *hsdev, struct press_state *press_state = iio_priv(indio_dev); dev_dbg(&indio_dev->dev, "press_proc_event\n"); - if (atomic_read(&press_state->common_attributes.data_ready)) - hid_sensor_push_data(indio_dev, - &press_state->press_data, - sizeof(press_state->press_data)); + if (atomic_read(&press_state->common_attributes.data_ready)) { + if (!press_state->timestamp) + press_state->timestamp = iio_get_time_ns(indio_dev); + + iio_push_to_buffers_with_timestamp( + indio_dev, &press_state->scan, press_state->timestamp); + } return 0; } @@ -191,9 +195,13 @@ static int press_capture_sample(struct hid_sensor_hub_device *hsdev, switch (usage_id) { case HID_USAGE_SENSOR_ATMOSPHERIC_PRESSURE: - press_state->press_data = *(u32 *)raw_data; + press_state->scan.press_data = *(u32 *)raw_data; ret = 0; break; + case HID_USAGE_SENSOR_TIME_TIMESTAMP: + press_state->timestamp = hid_sensor_convert_timestamp( + &press_state->common_attributes, *(s64 *)raw_data); + break; default: break; } @@ -259,8 +267,8 @@ static int hid_press_probe(struct platform_device *pdev) return ret; } - indio_dev->channels = kmemdup(press_channels, sizeof(press_channels), - GFP_KERNEL); + indio_dev->channels = devm_kmemdup(&pdev->dev, press_channels, + sizeof(press_channels), GFP_KERNEL); if (!indio_dev->channels) { dev_err(&pdev->dev, "failed to duplicate channels\n"); return -ENOMEM; @@ -271,7 +279,7 @@ static int hid_press_probe(struct platform_device *pdev) HID_USAGE_SENSOR_PRESSURE, press_state); if (ret) { dev_err(&pdev->dev, "failed to setup attributes\n"); - goto error_free_dev_mem; + return ret; } indio_dev->num_channels = @@ -286,7 +294,7 @@ static int hid_press_probe(struct platform_device *pdev) &press_state->common_attributes); if (ret) { dev_err(&pdev->dev, "trigger setup failed\n"); - goto error_free_dev_mem; + return ret; } ret = iio_device_register(indio_dev); @@ -311,8 +319,6 @@ error_iio_unreg: iio_device_unregister(indio_dev); error_remove_trigger: hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes); -error_free_dev_mem: - kfree(indio_dev->channels); return ret; } @@ -326,7 +332,6 @@ static int hid_press_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes); - kfree(indio_dev->channels); return 0; } diff --git a/drivers/iio/pressure/hp03.c b/drivers/iio/pressure/hp03.c index e40b1d7dc129..9538118c9648 100644 --- a/drivers/iio/pressure/hp03.c +++ b/drivers/iio/pressure/hp03.c @@ -242,47 +242,26 @@ static int hp03_probe(struct i2c_client *client, * which has it's dedicated I2C address and contains * the calibration constants for the sensor. */ - priv->eeprom_client = i2c_new_dummy_device(client->adapter, HP03_EEPROM_ADDR); + priv->eeprom_client = devm_i2c_new_dummy_device(dev, client->adapter, + HP03_EEPROM_ADDR); if (IS_ERR(priv->eeprom_client)) { dev_err(dev, "New EEPROM I2C device failed\n"); return PTR_ERR(priv->eeprom_client); } - priv->eeprom_regmap = regmap_init_i2c(priv->eeprom_client, - &hp03_regmap_config); + priv->eeprom_regmap = devm_regmap_init_i2c(priv->eeprom_client, + &hp03_regmap_config); if (IS_ERR(priv->eeprom_regmap)) { dev_err(dev, "Failed to allocate EEPROM regmap\n"); - ret = PTR_ERR(priv->eeprom_regmap); - goto err_cleanup_eeprom_client; + return PTR_ERR(priv->eeprom_regmap); } - ret = iio_device_register(indio_dev); + ret = devm_iio_device_register(dev, indio_dev); if (ret) { dev_err(dev, "Failed to register IIO device\n"); - goto err_cleanup_eeprom_regmap; + return ret; } - i2c_set_clientdata(client, indio_dev); - - return 0; - -err_cleanup_eeprom_regmap: - regmap_exit(priv->eeprom_regmap); - -err_cleanup_eeprom_client: - i2c_unregister_device(priv->eeprom_client); - return ret; -} - -static int hp03_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct hp03_priv *priv = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - regmap_exit(priv->eeprom_regmap); - i2c_unregister_device(priv->eeprom_client); - return 0; } @@ -304,7 +283,6 @@ static struct i2c_driver hp03_driver = { .of_match_table = hp03_of_match, }, .probe = hp03_probe, - .remove = hp03_remove, .id_table = hp03_id, }; module_i2c_driver(hp03_driver); diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h index 9417b3bd7513..156e6a72dc5c 100644 --- a/drivers/iio/pressure/st_pressure.h +++ b/drivers/iio/pressure/st_pressure.h @@ -43,7 +43,6 @@ static __maybe_unused const struct st_sensors_platform_data default_press_pdata #ifdef CONFIG_IIO_BUFFER int st_press_allocate_ring(struct iio_dev *indio_dev); -void st_press_deallocate_ring(struct iio_dev *indio_dev); int st_press_trig_set_state(struct iio_trigger *trig, bool state); #define ST_PRESS_TRIGGER_SET_STATE (&st_press_trig_set_state) #else /* CONFIG_IIO_BUFFER */ @@ -51,10 +50,6 @@ static inline int st_press_allocate_ring(struct iio_dev *indio_dev) { return 0; } - -static inline void st_press_deallocate_ring(struct iio_dev *indio_dev) -{ -} #define ST_PRESS_TRIGGER_SET_STATE NULL #endif /* CONFIG_IIO_BUFFER */ diff --git a/drivers/iio/pressure/st_pressure_buffer.c b/drivers/iio/pressure/st_pressure_buffer.c index 7cf6f06797e1..25dbd5476b26 100644 --- a/drivers/iio/pressure/st_pressure_buffer.c +++ b/drivers/iio/pressure/st_pressure_buffer.c @@ -9,14 +9,9 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/stat.h> -#include <linux/interrupt.h> -#include <linux/i2c.h> -#include <linux/delay.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> -#include <linux/iio/trigger_consumer.h> +#include <linux/iio/trigger.h> #include <linux/iio/triggered_buffer.h> #include <linux/iio/common/st_sensors.h> @@ -46,13 +41,8 @@ static const struct iio_buffer_setup_ops st_press_buffer_setup_ops = { int st_press_allocate_ring(struct iio_dev *indio_dev) { - return iio_triggered_buffer_setup(indio_dev, NULL, - &st_sensors_trigger_handler, &st_press_buffer_setup_ops); -} - -void st_press_deallocate_ring(struct iio_dev *indio_dev) -{ - iio_triggered_buffer_cleanup(indio_dev); + return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev, + NULL, &st_sensors_trigger_handler, &st_press_buffer_setup_ops); } MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index 7912b5a68395..ab1c17fac807 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -9,17 +9,11 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/i2c.h> -#include <linux/irq.h> -#include <linux/delay.h> +#include <linux/mutex.h> +#include <linux/sysfs.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/iio/trigger.h> -#include <linux/iio/buffer.h> #include <asm/unaligned.h> #include <linux/iio/common/st_sensors.h> @@ -724,7 +718,7 @@ int st_press_common_probe(struct iio_dev *indio_dev) err = st_sensors_allocate_trigger(indio_dev, ST_PRESS_TRIGGER_OPS); if (err < 0) - goto st_press_probe_trigger_error; + return err; } err = iio_device_register(indio_dev); @@ -739,8 +733,6 @@ int st_press_common_probe(struct iio_dev *indio_dev) st_press_device_register_error: if (press_data->irq > 0) st_sensors_deallocate_trigger(indio_dev); -st_press_probe_trigger_error: - st_press_deallocate_ring(indio_dev); return err; } EXPORT_SYMBOL(st_press_common_probe); @@ -752,8 +744,6 @@ void st_press_common_remove(struct iio_dev *indio_dev) iio_device_unregister(indio_dev); if (press_data->irq > 0) st_sensors_deallocate_trigger(indio_dev); - - st_press_deallocate_ring(indio_dev); } EXPORT_SYMBOL(st_press_common_remove); diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c index f0a5af314ceb..52fa98f24478 100644 --- a/drivers/iio/pressure/st_pressure_i2c.c +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -7,9 +7,10 @@ * Denis Ciocca <denis.ciocca@st.com> */ +#include <linux/acpi.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/slab.h> +#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/iio/iio.h> diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c index b48cf7d01cd7..ee393df54cee 100644 --- a/drivers/iio/pressure/st_pressure_spi.c +++ b/drivers/iio/pressure/st_pressure_spi.c @@ -9,7 +9,7 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/slab.h> +#include <linux/mod_devicetable.h> #include <linux/spi/spi.h> #include <linux/iio/iio.h> diff --git a/drivers/iio/proximity/rfd77402.c b/drivers/iio/proximity/rfd77402.c index 7a0472323f17..8c06d02139b6 100644 --- a/drivers/iio/proximity/rfd77402.c +++ b/drivers/iio/proximity/rfd77402.c @@ -90,18 +90,18 @@ static const struct iio_chan_spec rfd77402_channels[] = { }, }; -static int rfd77402_set_state(struct rfd77402_data *data, u8 state, u16 check) +static int rfd77402_set_state(struct i2c_client *client, u8 state, u16 check) { int ret; - ret = i2c_smbus_write_byte_data(data->client, RFD77402_CMD_R, + ret = i2c_smbus_write_byte_data(client, RFD77402_CMD_R, state | RFD77402_CMD_VALID); if (ret < 0) return ret; usleep_range(10000, 20000); - ret = i2c_smbus_read_word_data(data->client, RFD77402_STATUS_R); + ret = i2c_smbus_read_word_data(client, RFD77402_STATUS_R); if (ret < 0) return ret; if ((ret & RFD77402_STATUS_PM_MASK) != check) @@ -110,24 +110,24 @@ static int rfd77402_set_state(struct rfd77402_data *data, u8 state, u16 check) return 0; } -static int rfd77402_measure(struct rfd77402_data *data) +static int rfd77402_measure(struct i2c_client *client) { int ret; int tries = 10; - ret = rfd77402_set_state(data, RFD77402_CMD_MCPU_ON, + ret = rfd77402_set_state(client, RFD77402_CMD_MCPU_ON, RFD77402_STATUS_MCPU_ON); if (ret < 0) return ret; - ret = i2c_smbus_write_byte_data(data->client, RFD77402_CMD_R, + ret = i2c_smbus_write_byte_data(client, RFD77402_CMD_R, RFD77402_CMD_SINGLE | RFD77402_CMD_VALID); if (ret < 0) goto err; while (tries-- > 0) { - ret = i2c_smbus_read_byte_data(data->client, RFD77402_ICSR); + ret = i2c_smbus_read_byte_data(client, RFD77402_ICSR); if (ret < 0) goto err; if (ret & RFD77402_ICSR_RESULT) @@ -140,7 +140,7 @@ static int rfd77402_measure(struct rfd77402_data *data) goto err; } - ret = i2c_smbus_read_word_data(data->client, RFD77402_RESULT_R); + ret = i2c_smbus_read_word_data(client, RFD77402_RESULT_R); if (ret < 0) goto err; @@ -153,7 +153,7 @@ static int rfd77402_measure(struct rfd77402_data *data) return (ret & RFD77402_RESULT_DIST_MASK) >> 2; err: - rfd77402_set_state(data, RFD77402_CMD_MCPU_OFF, + rfd77402_set_state(client, RFD77402_CMD_MCPU_OFF, RFD77402_STATUS_MCPU_OFF); return ret; } @@ -168,7 +168,7 @@ static int rfd77402_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: mutex_lock(&data->lock); - ret = rfd77402_measure(data); + ret = rfd77402_measure(data->client); mutex_unlock(&data->lock); if (ret < 0) return ret; @@ -188,23 +188,23 @@ static const struct iio_info rfd77402_info = { .read_raw = rfd77402_read_raw, }; -static int rfd77402_init(struct rfd77402_data *data) +static int rfd77402_init(struct i2c_client *client) { int ret, i; - ret = rfd77402_set_state(data, RFD77402_CMD_STANDBY, + ret = rfd77402_set_state(client, RFD77402_CMD_STANDBY, RFD77402_STATUS_STANDBY); if (ret < 0) return ret; /* configure INT pad as push-pull, active low */ - ret = i2c_smbus_write_byte_data(data->client, RFD77402_ICSR, + ret = i2c_smbus_write_byte_data(client, RFD77402_ICSR, RFD77402_ICSR_INT_MODE); if (ret < 0) return ret; /* I2C configuration */ - ret = i2c_smbus_write_word_data(data->client, RFD77402_I2C_INIT_CFG, + ret = i2c_smbus_write_word_data(client, RFD77402_I2C_INIT_CFG, RFD77402_I2C_ADDR_INCR | RFD77402_I2C_DATA_INCR | RFD77402_I2C_HOST_DEBUG | @@ -213,45 +213,50 @@ static int rfd77402_init(struct rfd77402_data *data) return ret; /* set initialization */ - ret = i2c_smbus_write_word_data(data->client, RFD77402_PMU_CFG, 0x0500); + ret = i2c_smbus_write_word_data(client, RFD77402_PMU_CFG, 0x0500); if (ret < 0) return ret; - ret = rfd77402_set_state(data, RFD77402_CMD_MCPU_OFF, + ret = rfd77402_set_state(client, RFD77402_CMD_MCPU_OFF, RFD77402_STATUS_MCPU_OFF); if (ret < 0) return ret; /* set initialization */ - ret = i2c_smbus_write_word_data(data->client, RFD77402_PMU_CFG, 0x0600); + ret = i2c_smbus_write_word_data(client, RFD77402_PMU_CFG, 0x0600); if (ret < 0) return ret; - ret = rfd77402_set_state(data, RFD77402_CMD_MCPU_ON, + ret = rfd77402_set_state(client, RFD77402_CMD_MCPU_ON, RFD77402_STATUS_MCPU_ON); if (ret < 0) return ret; for (i = 0; i < ARRAY_SIZE(rf77402_tof_config); i++) { - ret = i2c_smbus_write_word_data(data->client, + ret = i2c_smbus_write_word_data(client, rf77402_tof_config[i].reg, rf77402_tof_config[i].val); if (ret < 0) return ret; } - ret = rfd77402_set_state(data, RFD77402_CMD_STANDBY, + ret = rfd77402_set_state(client, RFD77402_CMD_STANDBY, RFD77402_STATUS_STANDBY); return ret; } -static int rfd77402_powerdown(struct rfd77402_data *data) +static int rfd77402_powerdown(struct i2c_client *client) { - return rfd77402_set_state(data, RFD77402_CMD_STANDBY, + return rfd77402_set_state(client, RFD77402_CMD_STANDBY, RFD77402_STATUS_STANDBY); } +static void rfd77402_disable(void *client) +{ + rfd77402_powerdown(client); +} + static int rfd77402_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -270,7 +275,6 @@ static int rfd77402_probe(struct i2c_client *client, return -ENOMEM; data = iio_priv(indio_dev); - i2c_set_clientdata(client, indio_dev); data->client = client; mutex_init(&data->lock); @@ -280,46 +284,26 @@ static int rfd77402_probe(struct i2c_client *client, indio_dev->name = RFD77402_DRV_NAME; indio_dev->modes = INDIO_DIRECT_MODE; - ret = rfd77402_init(data); + ret = rfd77402_init(client); if (ret < 0) return ret; - ret = iio_device_register(indio_dev); + ret = devm_add_action_or_reset(&client->dev, rfd77402_disable, client); if (ret) - goto err_powerdown; - - return 0; - -err_powerdown: - rfd77402_powerdown(data); - return ret; -} - -static int rfd77402_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - - iio_device_unregister(indio_dev); - rfd77402_powerdown(iio_priv(indio_dev)); + return ret; - return 0; + return devm_iio_device_register(&client->dev, indio_dev); } #ifdef CONFIG_PM_SLEEP static int rfd77402_suspend(struct device *dev) { - struct rfd77402_data *data = iio_priv(i2c_get_clientdata( - to_i2c_client(dev))); - - return rfd77402_powerdown(data); + return rfd77402_powerdown(to_i2c_client(dev)); } static int rfd77402_resume(struct device *dev) { - struct rfd77402_data *data = iio_priv(i2c_get_clientdata( - to_i2c_client(dev))); - - return rfd77402_init(data); + return rfd77402_init(to_i2c_client(dev)); } #endif @@ -337,7 +321,6 @@ static struct i2c_driver rfd77402_driver = { .pm = &rfd77402_pm_ops, }, .probe = rfd77402_probe, - .remove = rfd77402_remove, .id_table = rfd77402_id, }; diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c index 175f3b7c61d7..a3fdb59b06d2 100644 --- a/drivers/iio/proximity/sx9310.c +++ b/drivers/iio/proximity/sx9310.c @@ -20,6 +20,7 @@ #include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/pm.h> +#include <linux/property.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> @@ -1221,10 +1222,9 @@ static int sx9310_init_compensation(struct iio_dev *indio_dev) } static const struct sx9310_reg_default * -sx9310_get_default_reg(struct sx9310_data *data, int idx, +sx9310_get_default_reg(struct device *dev, int idx, struct sx9310_reg_default *reg_def) { - const struct device_node *np = data->client->dev.of_node; u32 combined[SX9310_NUM_CHANNELS]; u32 start = 0, raw = 0, pos = 0; unsigned long comb_mask = 0; @@ -1232,40 +1232,24 @@ sx9310_get_default_reg(struct sx9310_data *data, int idx, const char *res; memcpy(reg_def, &sx9310_default_regs[idx], sizeof(*reg_def)); - if (!np) - return reg_def; - switch (reg_def->reg) { case SX9310_REG_PROX_CTRL2: - if (of_property_read_bool(np, "semtech,cs0-ground")) { + if (device_property_read_bool(dev, "semtech,cs0-ground")) { reg_def->def &= ~SX9310_REG_PROX_CTRL2_SHIELDEN_MASK; reg_def->def |= SX9310_REG_PROX_CTRL2_SHIELDEN_GROUND; } - count = of_property_count_elems_of_size(np, "semtech,combined-sensors", - sizeof(u32)); - if (count > 0 && count <= ARRAY_SIZE(combined)) { - ret = of_property_read_u32_array(np, "semtech,combined-sensors", - combined, count); - if (ret) - break; - } else { - /* - * Either the property does not exist in the DT or the - * number of entries is incorrect. - */ + count = device_property_count_u32(dev, "semtech,combined-sensors"); + if (count < 0 || count > ARRAY_SIZE(combined)) break; - } - for (i = 0; i < count; i++) { - if (combined[i] >= SX9310_NUM_CHANNELS) { - /* Invalid sensor (invalid DT). */ - break; - } - comb_mask |= BIT(combined[i]); - } - if (i < count) + ret = device_property_read_u32_array(dev, "semtech,combined-sensors", + combined, count); + if (ret) break; + for (i = 0; i < count; i++) + comb_mask |= BIT(combined[i]); + reg_def->def &= ~SX9310_REG_PROX_CTRL2_COMBMODE_MASK; if (comb_mask == (BIT(3) | BIT(2) | BIT(1) | BIT(0))) reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1_CS2_CS3; @@ -1278,7 +1262,7 @@ sx9310_get_default_reg(struct sx9310_data *data, int idx, break; case SX9310_REG_PROX_CTRL4: - ret = of_property_read_string(np, "semtech,resolution", &res); + ret = device_property_read_string(dev, "semtech,resolution", &res); if (ret) break; @@ -1302,7 +1286,7 @@ sx9310_get_default_reg(struct sx9310_data *data, int idx, break; case SX9310_REG_PROX_CTRL5: - ret = of_property_read_u32(np, "semtech,startup-sensor", &start); + ret = device_property_read_u32(dev, "semtech,startup-sensor", &start); if (ret) { start = FIELD_GET(SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK, reg_def->def); @@ -1312,7 +1296,7 @@ sx9310_get_default_reg(struct sx9310_data *data, int idx, reg_def->def |= FIELD_PREP(SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK, start); - ret = of_property_read_u32(np, "semtech,proxraw-strength", &raw); + ret = device_property_read_u32(dev, "semtech,proxraw-strength", &raw); if (ret) { raw = FIELD_GET(SX9310_REG_PROX_CTRL5_RAWFILT_MASK, reg_def->def); @@ -1325,7 +1309,7 @@ sx9310_get_default_reg(struct sx9310_data *data, int idx, raw); break; case SX9310_REG_PROX_CTRL7: - ret = of_property_read_u32(np, "semtech,avg-pos-strength", &pos); + ret = device_property_read_u32(dev, "semtech,avg-pos-strength", &pos); if (ret) break; @@ -1361,7 +1345,7 @@ static int sx9310_init_device(struct iio_dev *indio_dev) /* Program some sane defaults. */ for (i = 0; i < ARRAY_SIZE(sx9310_default_regs); i++) { - initval = sx9310_get_default_reg(data, i, &tmp); + initval = sx9310_get_default_reg(&indio_dev->dev, i, &tmp); ret = regmap_write(data->regmap, initval->reg, initval->def); if (ret) return ret; diff --git a/drivers/iio/proximity/vcnl3020.c b/drivers/iio/proximity/vcnl3020.c index 43817f6b3086..ff83638db16f 100644 --- a/drivers/iio/proximity/vcnl3020.c +++ b/drivers/iio/proximity/vcnl3020.c @@ -2,8 +2,6 @@ /* * Support for Vishay VCNL3020 proximity sensor on i2c bus. * Based on Vishay VCNL4000 driver code. - * - * TODO: interrupts. */ #include <linux/module.h> @@ -11,9 +9,10 @@ #include <linux/err.h> #include <linux/delay.h> #include <linux/regmap.h> +#include <linux/interrupt.h> #include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> +#include <linux/iio/events.h> #define VCNL3020_PROD_ID 0x21 @@ -37,6 +36,21 @@ * measurement */ +/* Enables periodic proximity measurement */ +#define VCNL_PS_EN BIT(1) + +/* Enables state machine and LP oscillator for self timed measurements */ +#define VCNL_PS_SELFTIMED_EN BIT(0) + +/* Bit masks for ICR */ + +/* Enable interrupts on low or high thresholds */ +#define VCNL_ICR_THRES_EN BIT(1) + +/* Bit masks for ISR */ +#define VCNL_INT_TH_HI BIT(0) /* High threshold hit */ +#define VCNL_INT_TH_LOW BIT(1) /* Low threshold hit */ + #define VCNL_ON_DEMAND_TIMEOUT_US 100000 #define VCNL_POLL_US 20000 @@ -57,12 +71,14 @@ static const int vcnl3020_prox_sampling_frequency[][2] = { * @dev: vcnl3020 device. * @rev: revision id. * @lock: lock for protecting access to device hardware registers. + * @buf: DMA safe __be16 buffer. */ struct vcnl3020_data { struct regmap *regmap; struct device *dev; u8 rev; struct mutex lock; + __be16 buf ____cacheline_aligned; }; /** @@ -140,14 +156,34 @@ static int vcnl3020_init(struct vcnl3020_data *data) vcnl3020_led_current_property); }; +static bool vcnl3020_is_in_periodic_mode(struct vcnl3020_data *data) +{ + int rc; + unsigned int cmd; + + rc = regmap_read(data->regmap, VCNL_COMMAND, &cmd); + if (rc) { + dev_err(data->dev, + "Error (%d) reading command register\n", rc); + return false; + } + + return !!(cmd & VCNL_PS_SELFTIMED_EN); +} + static int vcnl3020_measure_proximity(struct vcnl3020_data *data, int *val) { int rc; unsigned int reg; - __be16 res; mutex_lock(&data->lock); + /* Protect against event capture. */ + if (vcnl3020_is_in_periodic_mode(data)) { + rc = -EBUSY; + goto err_unlock; + } + rc = regmap_write(data->regmap, VCNL_COMMAND, VCNL_PS_OD); if (rc) goto err_unlock; @@ -163,12 +199,12 @@ static int vcnl3020_measure_proximity(struct vcnl3020_data *data, int *val) } /* high & low result bytes read */ - rc = regmap_bulk_read(data->regmap, VCNL_PS_RESULT_HI, &res, - sizeof(res)); + rc = regmap_bulk_read(data->regmap, VCNL_PS_RESULT_HI, &data->buf, + sizeof(data->buf)); if (rc) goto err_unlock; - *val = be16_to_cpu(res); + *val = be16_to_cpu(data->buf); err_unlock: mutex_unlock(&data->lock); @@ -200,6 +236,15 @@ static int vcnl3020_write_proxy_samp_freq(struct vcnl3020_data *data, int val, { unsigned int i; int index = -1; + int rc; + + mutex_lock(&data->lock); + + /* Protect against event capture. */ + if (vcnl3020_is_in_periodic_mode(data)) { + rc = -EBUSY; + goto err_unlock; + } for (i = 0; i < ARRAY_SIZE(vcnl3020_prox_sampling_frequency); i++) { if (val == vcnl3020_prox_sampling_frequency[i][0] && @@ -209,18 +254,250 @@ static int vcnl3020_write_proxy_samp_freq(struct vcnl3020_data *data, int val, } } - if (index < 0) + if (index < 0) { + rc = -EINVAL; + goto err_unlock; + } + + rc = regmap_write(data->regmap, VCNL_PROXIMITY_RATE, index); + if (rc) + dev_err(data->dev, + "Error (%d) writing proximity rate register\n", rc); + +err_unlock: + mutex_unlock(&data->lock); + + return rc; +} + +static bool vcnl3020_is_thr_enabled(struct vcnl3020_data *data) +{ + int rc; + unsigned int icr; + + rc = regmap_read(data->regmap, VCNL_PS_ICR, &icr); + if (rc) { + dev_err(data->dev, + "Error (%d) reading ICR register\n", rc); + return false; + } + + return !!(icr & VCNL_ICR_THRES_EN); +} + +static int vcnl3020_read_event(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) +{ + int rc; + struct vcnl3020_data *data = iio_priv(indio_dev); + + switch (info) { + case IIO_EV_INFO_VALUE: + switch (dir) { + case IIO_EV_DIR_RISING: + rc = regmap_bulk_read(data->regmap, VCNL_PS_HI_THR_HI, + &data->buf, sizeof(data->buf)); + if (rc < 0) + return rc; + *val = be16_to_cpu(data->buf); + return IIO_VAL_INT; + case IIO_EV_DIR_FALLING: + rc = regmap_bulk_read(data->regmap, VCNL_PS_LO_THR_HI, + &data->buf, sizeof(data->buf)); + if (rc < 0) + return rc; + *val = be16_to_cpu(data->buf); + return IIO_VAL_INT; + default: + return -EINVAL; + } + default: return -EINVAL; + } +} + +static int vcnl3020_write_event(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) +{ + int rc; + struct vcnl3020_data *data = iio_priv(indio_dev); + + mutex_lock(&data->lock); - return regmap_write(data->regmap, VCNL_PROXIMITY_RATE, index); + switch (info) { + case IIO_EV_INFO_VALUE: + switch (dir) { + case IIO_EV_DIR_RISING: + /* 16 bit word/ low * high */ + data->buf = cpu_to_be16(val); + rc = regmap_bulk_write(data->regmap, VCNL_PS_HI_THR_HI, + &data->buf, sizeof(data->buf)); + if (rc < 0) + goto err_unlock; + rc = IIO_VAL_INT; + goto err_unlock; + case IIO_EV_DIR_FALLING: + data->buf = cpu_to_be16(val); + rc = regmap_bulk_write(data->regmap, VCNL_PS_LO_THR_HI, + &data->buf, sizeof(data->buf)); + if (rc < 0) + goto err_unlock; + rc = IIO_VAL_INT; + goto err_unlock; + default: + rc = -EINVAL; + goto err_unlock; + } + default: + rc = -EINVAL; + goto err_unlock; + } +err_unlock: + mutex_unlock(&data->lock); + + return rc; } +static int vcnl3020_enable_periodic(struct iio_dev *indio_dev, + struct vcnl3020_data *data) +{ + int rc; + int cmd; + + mutex_lock(&data->lock); + + /* Enable periodic measurement of proximity data. */ + cmd = VCNL_PS_EN | VCNL_PS_SELFTIMED_EN; + + rc = regmap_write(data->regmap, VCNL_COMMAND, cmd); + if (rc) { + dev_err(data->dev, + "Error (%d) writing command register\n", rc); + goto err_unlock; + } + + /* + * Enable interrupts on threshold, for proximity data by + * default. + */ + rc = regmap_write(data->regmap, VCNL_PS_ICR, VCNL_ICR_THRES_EN); + if (rc) + dev_err(data->dev, + "Error (%d) reading ICR register\n", rc); + +err_unlock: + mutex_unlock(&data->lock); + + return rc; +} + +static int vcnl3020_disable_periodic(struct iio_dev *indio_dev, + struct vcnl3020_data *data) +{ + int rc; + + mutex_lock(&data->lock); + + rc = regmap_write(data->regmap, VCNL_COMMAND, 0); + if (rc) { + dev_err(data->dev, + "Error (%d) writing command register\n", rc); + goto err_unlock; + } + + rc = regmap_write(data->regmap, VCNL_PS_ICR, 0); + if (rc) { + dev_err(data->dev, + "Error (%d) writing ICR register\n", rc); + goto err_unlock; + } + + /* Clear interrupt flag bit */ + rc = regmap_write(data->regmap, VCNL_ISR, 0); + if (rc) + dev_err(data->dev, + "Error (%d) writing ISR register\n", rc); + +err_unlock: + mutex_unlock(&data->lock); + + return rc; +} + +static int vcnl3020_config_threshold(struct iio_dev *indio_dev, bool state) +{ + struct vcnl3020_data *data = iio_priv(indio_dev); + + if (state) { + return vcnl3020_enable_periodic(indio_dev, data); + } else { + if (!vcnl3020_is_thr_enabled(data)) + return 0; + return vcnl3020_disable_periodic(indio_dev, data); + } +} + +static int vcnl3020_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + int state) +{ + switch (chan->type) { + case IIO_PROXIMITY: + return vcnl3020_config_threshold(indio_dev, state); + default: + return -EINVAL; + } +} + +static int vcnl3020_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 vcnl3020_data *data = iio_priv(indio_dev); + + switch (chan->type) { + case IIO_PROXIMITY: + return vcnl3020_is_thr_enabled(data); + default: + return -EINVAL; + } +} + +static const struct iio_event_spec vcnl3020_event_spec[] = { + { + .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 const struct iio_chan_spec vcnl3020_channels[] = { { .type = IIO_PROXIMITY, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SAMP_FREQ), .info_mask_separate_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), + .event_spec = vcnl3020_event_spec, + .num_event_specs = ARRAY_SIZE(vcnl3020_event_spec), }, }; @@ -251,17 +528,11 @@ static int vcnl3020_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { - int rc; struct vcnl3020_data *data = iio_priv(indio_dev); switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: - rc = iio_device_claim_direct_mode(indio_dev); - if (rc) - return rc; - rc = vcnl3020_write_proxy_samp_freq(data, val, val2); - iio_device_release_direct_mode(indio_dev); - return rc; + return vcnl3020_write_proxy_samp_freq(data, val, val2); default: return -EINVAL; } @@ -287,6 +558,10 @@ static const struct iio_info vcnl3020_info = { .read_raw = vcnl3020_read_raw, .write_raw = vcnl3020_write_raw, .read_avail = vcnl3020_read_avail, + .read_event_value = vcnl3020_read_event, + .write_event_value = vcnl3020_write_event, + .read_event_config = vcnl3020_read_event_config, + .write_event_config = vcnl3020_write_event_config, }; static const struct regmap_config vcnl3020_regmap_config = { @@ -295,6 +570,37 @@ static const struct regmap_config vcnl3020_regmap_config = { .max_register = VCNL_PS_MOD_ADJ, }; +static irqreturn_t vcnl3020_handle_irq_thread(int irq, void *p) +{ + struct iio_dev *indio_dev = p; + struct vcnl3020_data *data = iio_priv(indio_dev); + unsigned int isr; + int rc; + + rc = regmap_read(data->regmap, VCNL_ISR, &isr); + if (rc) { + dev_err(data->dev, "Error (%d) reading reg (0x%x)\n", + rc, VCNL_ISR); + return IRQ_HANDLED; + } + + if (!(isr & VCNL_ICR_THRES_EN)) + return IRQ_NONE; + + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 1, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + iio_get_time_ns(indio_dev)); + + rc = regmap_write(data->regmap, VCNL_ISR, isr & VCNL_ICR_THRES_EN); + if (rc) + dev_err(data->dev, "Error (%d) writing in reg (0x%x)\n", + rc, VCNL_ISR); + + return IRQ_HANDLED; +} + static int vcnl3020_probe(struct i2c_client *client) { struct vcnl3020_data *data; @@ -327,6 +633,19 @@ static int vcnl3020_probe(struct i2c_client *client) indio_dev->name = "vcnl3020"; indio_dev->modes = INDIO_DIRECT_MODE; + if (client->irq) { + rc = devm_request_threaded_irq(&client->dev, client->irq, + 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); + return rc; + } + } + return devm_iio_device_register(&client->dev, indio_dev); } diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c index 3b5ba26d7d86..3b4a0e60e605 100644 --- a/drivers/iio/temperature/ltc2983.c +++ b/drivers/iio/temperature/ltc2983.c @@ -89,6 +89,8 @@ #define LTC2983_STATUS_START_MASK BIT(7) #define LTC2983_STATUS_START(x) FIELD_PREP(LTC2983_STATUS_START_MASK, x) +#define LTC2983_STATUS_UP_MASK GENMASK(7, 6) +#define LTC2983_STATUS_UP(reg) FIELD_GET(LTC2983_STATUS_UP_MASK, reg) #define LTC2983_STATUS_CHAN_SEL_MASK GENMASK(4, 0) #define LTC2983_STATUS_CHAN_SEL(x) \ @@ -1362,17 +1364,16 @@ put_child: static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio) { - u32 iio_chan_t = 0, iio_chan_v = 0, chan, iio_idx = 0; + u32 iio_chan_t = 0, iio_chan_v = 0, chan, iio_idx = 0, status; int ret; - unsigned long time; - - /* make sure the device is up */ - time = wait_for_completion_timeout(&st->completion, - msecs_to_jiffies(250)); - if (!time) { + /* make sure the device is up: start bit (7) is 0 and done bit (6) is 1 */ + ret = regmap_read_poll_timeout(st->regmap, LTC2983_STATUS_REG, status, + LTC2983_STATUS_UP(status) == 1, 25000, + 25000 * 10); + if (ret) { dev_err(&st->spi->dev, "Device startup timed out\n"); - return -ETIMEDOUT; + return ret; } st->iio_chan = devm_kzalloc(&st->spi->dev, @@ -1492,10 +1493,11 @@ static int ltc2983_probe(struct spi_device *spi) ret = ltc2983_parse_dt(st); if (ret) return ret; - /* - * let's request the irq now so it is used to sync the device - * startup in ltc2983_setup() - */ + + ret = ltc2983_setup(st, true); + if (ret) + return ret; + ret = devm_request_irq(&spi->dev, spi->irq, ltc2983_irq_handler, IRQF_TRIGGER_RISING, name, st); if (ret) { @@ -1503,10 +1505,6 @@ static int ltc2983_probe(struct spi_device *spi) return ret; } - ret = ltc2983_setup(st, true); - if (ret) - return ret; - indio_dev->name = name; indio_dev->num_channels = st->iio_channels; indio_dev->channels = st->iio_chan; diff --git a/drivers/iio/temperature/tmp006.c b/drivers/iio/temperature/tmp006.c index 54976c7dad92..e4943a0bc9aa 100644 --- a/drivers/iio/temperature/tmp006.c +++ b/drivers/iio/temperature/tmp006.c @@ -193,6 +193,25 @@ static bool tmp006_check_identification(struct i2c_client *client) return mid == TMP006_MANUFACTURER_MAGIC && did == TMP006_DEVICE_MAGIC; } +static int tmp006_power(struct device *dev, bool up) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct tmp006_data *data = iio_priv(indio_dev); + + if (up) + data->config |= TMP006_CONFIG_MOD_MASK; + else + data->config &= ~TMP006_CONFIG_MOD_MASK; + + return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG, + data->config); +} + +static void tmp006_powerdown_cleanup(void *dev) +{ + tmp006_power(dev, false); +} + static int tmp006_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -228,38 +247,29 @@ static int tmp006_probe(struct i2c_client *client, return ret; data->config = ret; - return iio_device_register(indio_dev); -} - -static int tmp006_powerdown(struct tmp006_data *data) -{ - return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG, - data->config & ~TMP006_CONFIG_MOD_MASK); -} - -static int tmp006_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); + if ((ret & TMP006_CONFIG_MOD_MASK) != TMP006_CONFIG_MOD_MASK) { + ret = tmp006_power(&client->dev, true); + if (ret < 0) + return ret; + } - iio_device_unregister(indio_dev); - tmp006_powerdown(iio_priv(indio_dev)); + ret = devm_add_action_or_reset(&client->dev, tmp006_powerdown_cleanup, + &client->dev); + if (ret < 0) + return ret; - return 0; + return devm_iio_device_register(&client->dev, indio_dev); } #ifdef CONFIG_PM_SLEEP static int tmp006_suspend(struct device *dev) { - struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); - return tmp006_powerdown(iio_priv(indio_dev)); + return tmp006_power(dev, false); } static int tmp006_resume(struct device *dev) { - struct tmp006_data *data = iio_priv(i2c_get_clientdata( - to_i2c_client(dev))); - return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG, - data->config | TMP006_CONFIG_MOD_MASK); + return tmp006_power(dev, true); } #endif @@ -277,7 +287,6 @@ static struct i2c_driver tmp006_driver = { .pm = &tmp006_pm_ops, }, .probe = tmp006_probe, - .remove = tmp006_remove, .id_table = tmp006_id, }; module_i2c_driver(tmp006_driver); |