aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio')
-rw-r--r--drivers/iio/accel/Kconfig5
-rw-r--r--drivers/iio/accel/adxl345.h1
-rw-r--r--drivers/iio/accel/adxl345_core.c29
-rw-r--r--drivers/iio/accel/adxl345_i2c.c6
-rw-r--r--drivers/iio/accel/adxl345_spi.c6
-rw-r--r--drivers/iio/accel/bma220_spi.c79
-rw-r--r--drivers/iio/accel/bmc150-accel-core.c78
-rw-r--r--drivers/iio/accel/bmc150-accel-i2c.c10
-rw-r--r--drivers/iio/accel/bmc150-accel-spi.c10
-rw-r--r--drivers/iio/accel/bmc150-accel.h20
-rw-r--r--drivers/iio/accel/da280.c26
-rw-r--r--drivers/iio/accel/da311.c26
-rw-r--r--drivers/iio/accel/dmard10.c27
-rw-r--r--drivers/iio/accel/hid-sensor-accel-3d.c10
-rw-r--r--drivers/iio/accel/st_accel.h4
-rw-r--r--drivers/iio/accel/st_accel_buffer.c16
-rw-r--r--drivers/iio/accel/st_accel_core.c14
-rw-r--r--drivers/iio/accel/st_accel_i2c.c3
-rw-r--r--drivers/iio/accel/st_accel_spi.c2
-rw-r--r--drivers/iio/adc/Kconfig10
-rw-r--r--drivers/iio/adc/Makefile1
-rw-r--r--drivers/iio/adc/ep93xx_adc.c6
-rw-r--r--drivers/iio/adc/fsl-imx25-gcq.c17
-rw-r--r--drivers/iio/adc/ingenic-adc.c102
-rw-r--r--drivers/iio/adc/meson_saradc.c20
-rw-r--r--drivers/iio/adc/rn5t618-adc.c23
-rw-r--r--drivers/iio/adc/rockchip_saradc.c69
-rw-r--r--drivers/iio/adc/rzg2l_adc.c600
-rw-r--r--drivers/iio/chemical/Kconfig11
-rw-r--r--drivers/iio/chemical/Makefile1
-rw-r--r--drivers/iio/chemical/sgp40.c378
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_buffer.c2
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_core.c1
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_core.h1
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_i2c.c3
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_spi.c3
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_trigger.c1
-rw-r--r--drivers/iio/dac/ad5624r_spi.c18
-rw-r--r--drivers/iio/dac/max5821.c41
-rw-r--r--drivers/iio/gyro/hid-sensor-gyro-3d.c11
-rw-r--r--drivers/iio/gyro/st_gyro.h4
-rw-r--r--drivers/iio/gyro/st_gyro_buffer.c16
-rw-r--r--drivers/iio/gyro/st_gyro_core.c15
-rw-r--r--drivers/iio/gyro/st_gyro_i2c.c2
-rw-r--r--drivers/iio/gyro/st_gyro_spi.c2
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c22
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h18
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c15
-rw-r--r--drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c1
-rw-r--r--drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c3
-rw-r--r--drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c3
-rw-r--r--drivers/iio/industrialio-buffer.c9
-rw-r--r--drivers/iio/industrialio-core.c33
-rw-r--r--drivers/iio/light/adjd_s311.c53
-rw-r--r--drivers/iio/light/cm3323.c7
-rw-r--r--drivers/iio/light/hid-sensor-als.c11
-rw-r--r--drivers/iio/light/hid-sensor-prox.c11
-rw-r--r--drivers/iio/light/si1145.c1
-rw-r--r--drivers/iio/light/tcs3414.c48
-rw-r--r--drivers/iio/magnetometer/st_magn.h12
-rw-r--r--drivers/iio/magnetometer/st_magn_buffer.c16
-rw-r--r--drivers/iio/magnetometer/st_magn_core.c17
-rw-r--r--drivers/iio/magnetometer/st_magn_i2c.c2
-rw-r--r--drivers/iio/magnetometer/st_magn_spi.c2
-rw-r--r--drivers/iio/orientation/hid-sensor-incl-3d.c11
-rw-r--r--drivers/iio/potentiometer/Kconfig10
-rw-r--r--drivers/iio/potentiometer/Makefile1
-rw-r--r--drivers/iio/potentiometer/ad5110.c344
-rw-r--r--drivers/iio/potentiometer/max5481.c22
-rw-r--r--drivers/iio/pressure/hid-sensor-press.c51
-rw-r--r--drivers/iio/pressure/hp03.c36
-rw-r--r--drivers/iio/pressure/st_pressure.h5
-rw-r--r--drivers/iio/pressure/st_pressure_buffer.c16
-rw-r--r--drivers/iio/pressure/st_pressure_core.c16
-rw-r--r--drivers/iio/pressure/st_pressure_i2c.c3
-rw-r--r--drivers/iio/pressure/st_pressure_spi.c2
-rw-r--r--drivers/iio/proximity/rfd77402.c83
-rw-r--r--drivers/iio/proximity/sx9310.c48
-rw-r--r--drivers/iio/proximity/vcnl3020.c351
-rw-r--r--drivers/iio/temperature/ltc2983.c30
-rw-r--r--drivers/iio/temperature/tmp006.c53
81 files changed, 2409 insertions, 687 deletions
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 8d8b1ba42ff8..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
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/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/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/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/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);