summaryrefslogtreecommitdiffstats
path: root/drivers/iio
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--drivers/iio/accel/Kconfig12
-rw-r--r--drivers/iio/accel/adxl345.h21
-rw-r--r--drivers/iio/accel/adxl345_core.c47
-rw-r--r--drivers/iio/accel/adxl345_i2c.c20
-rw-r--r--drivers/iio/accel/adxl345_spi.c20
-rw-r--r--drivers/iio/accel/bma180.c27
-rw-r--r--drivers/iio/accel/fxls8962af.h1
-rw-r--r--drivers/iio/accel/hid-sensor-accel-3d.c6
-rw-r--r--drivers/iio/accel/kionix-kx022a-i2c.c24
-rw-r--r--drivers/iio/accel/kionix-kx022a-spi.c19
-rw-r--r--drivers/iio/accel/kionix-kx022a.c351
-rw-r--r--drivers/iio/accel/kionix-kx022a.h114
-rw-r--r--drivers/iio/accel/mma8452.c28
-rw-r--r--drivers/iio/accel/msa311.c2
-rw-r--r--drivers/iio/accel/mxc4005.c8
-rw-r--r--drivers/iio/adc/Kconfig29
-rw-r--r--drivers/iio/adc/Makefile2
-rw-r--r--drivers/iio/adc/ab8500-gpadc.c6
-rw-r--r--drivers/iio/adc/ad4130.c27
-rw-r--r--drivers/iio/adc/ad7192.c269
-rw-r--r--drivers/iio/adc/at91-sama5d2_adc.c6
-rw-r--r--drivers/iio/adc/at91_adc.c114
-rw-r--r--drivers/iio/adc/axp20x_adc.c6
-rw-r--r--drivers/iio/adc/bcm_iproc_adc.c6
-rw-r--r--drivers/iio/adc/dln2-adc.c5
-rw-r--r--drivers/iio/adc/ep93xx_adc.c6
-rw-r--r--drivers/iio/adc/exynos_adc.c6
-rw-r--r--drivers/iio/adc/fsl-imx25-gcq.c6
-rw-r--r--drivers/iio/adc/hx711.c6
-rw-r--r--drivers/iio/adc/imx8qxp-adc.c6
-rw-r--r--drivers/iio/adc/imx93_adc.c6
-rw-r--r--drivers/iio/adc/ltc2309.c246
-rw-r--r--drivers/iio/adc/ltc2497.c5
-rw-r--r--drivers/iio/adc/max1363.c87
-rw-r--r--drivers/iio/adc/mcp3564.c1513
-rw-r--r--drivers/iio/adc/mcp3911.c562
-rw-r--r--drivers/iio/adc/meson_saradc.c22
-rw-r--r--drivers/iio/adc/mp2629_adc.c6
-rw-r--r--drivers/iio/adc/mt6577_auxadc.c72
-rw-r--r--drivers/iio/adc/mxs-lradc-adc.c6
-rw-r--r--drivers/iio/adc/npcm_adc.c6
-rw-r--r--drivers/iio/adc/palmas_gpadc.c2
-rw-r--r--drivers/iio/adc/qcom-pm8xxx-xoadc.c6
-rw-r--r--drivers/iio/adc/rcar-gyroadc.c6
-rw-r--r--drivers/iio/adc/spear_adc.c64
-rw-r--r--drivers/iio/adc/stm32-adc-core.c17
-rw-r--r--drivers/iio/adc/stm32-adc.c8
-rw-r--r--drivers/iio/adc/stm32-dfsdm-adc.c6
-rw-r--r--drivers/iio/adc/stm32-dfsdm-core.c6
-rw-r--r--drivers/iio/adc/sun4i-gpadc-iio.c8
-rw-r--r--drivers/iio/adc/ti-adc081c.c12
-rw-r--r--drivers/iio/adc/ti-ads1015.c7
-rw-r--r--drivers/iio/adc/ti_am335x_adc.c6
-rw-r--r--drivers/iio/adc/twl4030-madc.c6
-rw-r--r--drivers/iio/adc/twl6030-gpadc.c16
-rw-r--r--drivers/iio/adc/vf610_adc.c6
-rw-r--r--drivers/iio/addac/Kconfig1
-rw-r--r--drivers/iio/addac/ad74413r.c24
-rw-r--r--drivers/iio/addac/stx104.c61
-rw-r--r--drivers/iio/amplifiers/hmc425a.c17
-rw-r--r--drivers/iio/chemical/atlas-ezo-sensor.c6
-rw-r--r--drivers/iio/chemical/atlas-sensor.c32
-rw-r--r--drivers/iio/chemical/sgp30.c24
-rw-r--r--drivers/iio/chemical/vz89x.c16
-rw-r--r--drivers/iio/dac/dpot-dac.c6
-rw-r--r--drivers/iio/dac/lpc18xx_dac.c6
-rw-r--r--drivers/iio/dac/mcp4725.c42
-rw-r--r--drivers/iio/dac/stm32-dac-core.c15
-rw-r--r--drivers/iio/dac/stm32-dac.c9
-rw-r--r--drivers/iio/dac/ti-dac5571.c48
-rw-r--r--drivers/iio/dac/vf610_dac.c6
-rw-r--r--drivers/iio/gyro/hid-sensor-gyro-3d.c6
-rw-r--r--drivers/iio/humidity/hid-sensor-humidity.c6
-rw-r--r--drivers/iio/humidity/si7005.c7
-rw-r--r--drivers/iio/iio_core.h3
-rw-r--r--drivers/iio/imu/adis16475.c238
-rw-r--r--drivers/iio/imu/bno055/Kconfig1
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c13
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c3
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h2
-rw-r--r--drivers/iio/industrialio-core.c9
-rw-r--r--drivers/iio/industrialio-event.c55
-rw-r--r--drivers/iio/light/cm3605.c6
-rw-r--r--drivers/iio/light/hid-sensor-als.c45
-rw-r--r--drivers/iio/light/hid-sensor-prox.c6
-rw-r--r--drivers/iio/light/lm3533-als.c6
-rw-r--r--drivers/iio/light/opt4001.c2
-rw-r--r--drivers/iio/magnetometer/ak8975.c97
-rw-r--r--drivers/iio/magnetometer/hid-sensor-magn-3d.c6
-rw-r--r--drivers/iio/magnetometer/rm3100-core.c10
-rw-r--r--drivers/iio/magnetometer/yamaha-yas530.c4
-rw-r--r--drivers/iio/orientation/hid-sensor-incl-3d.c6
-rw-r--r--drivers/iio/orientation/hid-sensor-rotation.c6
-rw-r--r--drivers/iio/position/hid-sensor-custom-intel-hinge.c6
-rw-r--r--drivers/iio/potentiometer/ad5110.c21
-rw-r--r--drivers/iio/potentiometer/ds1803.c13
-rw-r--r--drivers/iio/pressure/Kconfig9
-rw-r--r--drivers/iio/pressure/Makefile1
-rw-r--r--drivers/iio/pressure/bmp280-spi.c1
-rw-r--r--drivers/iio/pressure/hid-sensor-press.c6
-rw-r--r--drivers/iio/pressure/ms5637.c6
-rw-r--r--drivers/iio/pressure/rohm-bm1390.c934
-rw-r--r--drivers/iio/proximity/cros_ec_mkbp_proximity.c6
-rw-r--r--drivers/iio/proximity/srf04.c6
-rw-r--r--drivers/iio/proximity/sx9310.c46
-rw-r--r--drivers/iio/resolver/Kconfig13
-rw-r--r--drivers/iio/resolver/Makefile1
-rw-r--r--drivers/iio/resolver/ad2s1210.c1519
-rw-r--r--drivers/iio/temperature/hid-sensor-temperature.c6
-rw-r--r--drivers/iio/temperature/mlx90614.c2
-rw-r--r--drivers/iio/temperature/tmp117.c94
-rw-r--r--drivers/iio/trigger/iio-trig-interrupt.c6
-rw-r--r--drivers/iio/trigger/stm32-timer-trigger.c6
113 files changed, 6314 insertions, 1145 deletions
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index b6b45d359f..d2221fe9ad 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -219,10 +219,12 @@ config BMA400
config BMA400_I2C
tristate
+ select REGMAP_I2C
depends on BMA400
config BMA400_SPI
tristate
+ select REGMAP_SPI
depends on BMA400
config BMC150_ACCEL
@@ -418,8 +420,9 @@ config IIO_KX022A_SPI
select IIO_KX022A
select REGMAP_SPI
help
- Enable support for the Kionix KX022A digital tri-axis
- accelerometer connected to I2C interface.
+ Enable support for the Kionix digital tri-axis accelerometers
+ connected to SPI interface. Supported devices are:
+ KX022A, KX132-1211, KX132ACR-LBZ
config IIO_KX022A_I2C
tristate "Kionix KX022A tri-axis digital accelerometer I2C interface"
@@ -427,8 +430,9 @@ config IIO_KX022A_I2C
select IIO_KX022A
select REGMAP_I2C
help
- Enable support for the Kionix KX022A digital tri-axis
- accelerometer connected to I2C interface.
+ Enable support for the Kionix digital tri-axis accelerometers
+ connected to I2C interface. Supported devices are:
+ KX022A, KX132-1211, KX132ACR-LBZ
config KXSD9
tristate "Kionix KXSD9 Accelerometer Driver"
diff --git a/drivers/iio/accel/adxl345.h b/drivers/iio/accel/adxl345.h
index d7e67cb085..284bd387ce 100644
--- a/drivers/iio/accel/adxl345.h
+++ b/drivers/iio/accel/adxl345.h
@@ -8,9 +8,24 @@
#ifndef _ADXL345_H_
#define _ADXL345_H_
-enum adxl345_device_type {
- ADXL345 = 1,
- ADXL375 = 2,
+/*
+ * In full-resolution mode, scale factor is maintained at ~4 mg/LSB
+ * in all g ranges.
+ *
+ * At +/- 16g with 13-bit resolution, scale is computed as:
+ * (16 + 16) * 9.81 / (2^13 - 1) = 0.0383
+ */
+#define ADXL345_USCALE 38300
+
+/*
+ * The Datasheet lists a resolution of Resolution is ~49 mg per LSB. That's
+ * ~480mm/s**2 per LSB.
+ */
+#define ADXL375_USCALE 480000
+
+struct adxl345_chip_info {
+ const char *name;
+ int uscale;
};
int adxl345_core_probe(struct device *dev, struct regmap *regmap);
diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c
index 1919e0089c..8bd30a23ed 100644
--- a/drivers/iio/accel/adxl345_core.c
+++ b/drivers/iio/accel/adxl345_core.c
@@ -45,25 +45,10 @@
#define ADXL345_DEVID 0xE5
-/*
- * In full-resolution mode, scale factor is maintained at ~4 mg/LSB
- * in all g ranges.
- *
- * At +/- 16g with 13-bit resolution, scale is computed as:
- * (16 + 16) * 9.81 / (2^13 - 1) = 0.0383
- */
-static const int adxl345_uscale = 38300;
-
-/*
- * The Datasheet lists a resolution of Resolution is ~49 mg per LSB. That's
- * ~480mm/s**2 per LSB.
- */
-static const int adxl375_uscale = 480000;
-
struct adxl345_data {
+ const struct adxl345_chip_info *info;
struct regmap *regmap;
u8 data_range;
- enum adxl345_device_type type;
};
#define ADXL345_CHANNEL(index, axis) { \
@@ -110,15 +95,7 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
- switch (data->type) {
- case ADXL345:
- *val2 = adxl345_uscale;
- break;
- case ADXL375:
- *val2 = adxl375_uscale;
- break;
- }
-
+ *val2 = data->info->uscale;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_CALIBBIAS:
ret = regmap_read(data->regmap,
@@ -222,25 +199,11 @@ static void adxl345_powerdown(void *regmap)
int adxl345_core_probe(struct device *dev, struct regmap *regmap)
{
- enum adxl345_device_type type;
struct adxl345_data *data;
struct iio_dev *indio_dev;
- const char *name;
u32 regval;
int ret;
- type = (uintptr_t)device_get_match_data(dev);
- switch (type) {
- case ADXL345:
- name = "adxl345";
- break;
- case ADXL375:
- name = "adxl375";
- break;
- default:
- return -EINVAL;
- }
-
ret = regmap_read(regmap, ADXL345_REG_DEVID, &regval);
if (ret < 0)
return dev_err_probe(dev, ret, "Error reading device ID\n");
@@ -255,16 +218,18 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap)
data = iio_priv(indio_dev);
data->regmap = regmap;
- data->type = type;
/* Enable full-resolution mode */
data->data_range = ADXL345_DATA_FORMAT_FULL_RES;
+ data->info = device_get_match_data(dev);
+ if (!data->info)
+ return -ENODEV;
ret = regmap_write(data->regmap, ADXL345_REG_DATA_FORMAT,
data->data_range);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to set data range\n");
- indio_dev->name = name;
+ indio_dev->name = data->info->name;
indio_dev->info = &adxl345_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = adxl345_channels;
diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c
index e47d12f196..a3084b0a8f 100644
--- a/drivers/iio/accel/adxl345_i2c.c
+++ b/drivers/iio/accel/adxl345_i2c.c
@@ -30,22 +30,32 @@ static int adxl345_i2c_probe(struct i2c_client *client)
return adxl345_core_probe(&client->dev, regmap);
}
+static const struct adxl345_chip_info adxl345_i2c_info = {
+ .name = "adxl345",
+ .uscale = ADXL345_USCALE,
+};
+
+static const struct adxl345_chip_info adxl375_i2c_info = {
+ .name = "adxl375",
+ .uscale = ADXL375_USCALE,
+};
+
static const struct i2c_device_id adxl345_i2c_id[] = {
- { "adxl345", ADXL345 },
- { "adxl375", ADXL375 },
+ { "adxl345", (kernel_ulong_t)&adxl345_i2c_info },
+ { "adxl375", (kernel_ulong_t)&adxl375_i2c_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, adxl345_i2c_id);
static const struct of_device_id adxl345_of_match[] = {
- { .compatible = "adi,adxl345", .data = (const void *)ADXL345 },
- { .compatible = "adi,adxl375", .data = (const void *)ADXL375 },
+ { .compatible = "adi,adxl345", .data = &adxl345_i2c_info },
+ { .compatible = "adi,adxl375", .data = &adxl375_i2c_info },
{ }
};
MODULE_DEVICE_TABLE(of, adxl345_of_match);
static const struct acpi_device_id adxl345_acpi_match[] = {
- { "ADS0345", ADXL345 },
+ { "ADS0345", (kernel_ulong_t)&adxl345_i2c_info },
{ }
};
MODULE_DEVICE_TABLE(acpi, adxl345_acpi_match);
diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c
index aaade58086..93ca349f17 100644
--- a/drivers/iio/accel/adxl345_spi.c
+++ b/drivers/iio/accel/adxl345_spi.c
@@ -36,22 +36,32 @@ static int adxl345_spi_probe(struct spi_device *spi)
return adxl345_core_probe(&spi->dev, regmap);
}
+static const struct adxl345_chip_info adxl345_spi_info = {
+ .name = "adxl345",
+ .uscale = ADXL345_USCALE,
+};
+
+static const struct adxl345_chip_info adxl375_spi_info = {
+ .name = "adxl375",
+ .uscale = ADXL375_USCALE,
+};
+
static const struct spi_device_id adxl345_spi_id[] = {
- { "adxl345", ADXL345 },
- { "adxl375", ADXL375 },
+ { "adxl345", (kernel_ulong_t)&adxl345_spi_info },
+ { "adxl375", (kernel_ulong_t)&adxl375_spi_info },
{ }
};
MODULE_DEVICE_TABLE(spi, adxl345_spi_id);
static const struct of_device_id adxl345_of_match[] = {
- { .compatible = "adi,adxl345", .data = (const void *)ADXL345 },
- { .compatible = "adi,adxl375", .data = (const void *)ADXL375 },
+ { .compatible = "adi,adxl345", .data = &adxl345_spi_info },
+ { .compatible = "adi,adxl375", .data = &adxl375_spi_info },
{ }
};
MODULE_DEVICE_TABLE(of, adxl345_of_match);
static const struct acpi_device_id adxl345_acpi_match[] = {
- { "ADS0345", ADXL345 },
+ { "ADS0345", (kernel_ulong_t)&adxl345_spi_info },
{ }
};
MODULE_DEVICE_TABLE(acpi, adxl345_acpi_match);
diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c
index 13439f52d2..ab4fccb24b 100644
--- a/drivers/iio/accel/bma180.c
+++ b/drivers/iio/accel/bma180.c
@@ -926,7 +926,6 @@ static int bma180_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct bma180_data *data;
struct iio_dev *indio_dev;
- enum chip_ids chip;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
@@ -936,11 +935,7 @@ static int bma180_probe(struct i2c_client *client)
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
- if (client->dev.of_node)
- chip = (uintptr_t)of_device_get_match_data(dev);
- else
- chip = id->driver_data;
- data->part_info = &bma180_part_info[chip];
+ data->part_info = i2c_get_match_data(client);
ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
@@ -1092,11 +1087,11 @@ static int bma180_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume);
static const struct i2c_device_id bma180_ids[] = {
- { "bma023", BMA023 },
- { "bma150", BMA150 },
- { "bma180", BMA180 },
- { "bma250", BMA250 },
- { "smb380", BMA150 },
+ { "bma023", (kernel_ulong_t)&bma180_part_info[BMA023] },
+ { "bma150", (kernel_ulong_t)&bma180_part_info[BMA150] },
+ { "bma180", (kernel_ulong_t)&bma180_part_info[BMA180] },
+ { "bma250", (kernel_ulong_t)&bma180_part_info[BMA250] },
+ { "smb380", (kernel_ulong_t)&bma180_part_info[BMA150] },
{ }
};
@@ -1105,23 +1100,23 @@ MODULE_DEVICE_TABLE(i2c, bma180_ids);
static const struct of_device_id bma180_of_match[] = {
{
.compatible = "bosch,bma023",
- .data = (void *)BMA023
+ .data = &bma180_part_info[BMA023]
},
{
.compatible = "bosch,bma150",
- .data = (void *)BMA150
+ .data = &bma180_part_info[BMA150]
},
{
.compatible = "bosch,bma180",
- .data = (void *)BMA180
+ .data = &bma180_part_info[BMA180]
},
{
.compatible = "bosch,bma250",
- .data = (void *)BMA250
+ .data = &bma180_part_info[BMA250]
},
{
.compatible = "bosch,smb380",
- .data = (void *)BMA150
+ .data = &bma180_part_info[BMA150]
},
{ }
};
diff --git a/drivers/iio/accel/fxls8962af.h b/drivers/iio/accel/fxls8962af.h
index 9cbe98c3ba..6eaa2803b2 100644
--- a/drivers/iio/accel/fxls8962af.h
+++ b/drivers/iio/accel/fxls8962af.h
@@ -14,7 +14,6 @@ enum {
};
int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq);
-int fxls8962af_core_remove(struct device *dev);
extern const struct dev_pm_ops fxls8962af_pm_ops;
extern const struct regmap_config fxls8962af_i2c_regmap_conf;
diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
index 5eac7ea199..9b7a73a4c4 100644
--- a/drivers/iio/accel/hid-sensor-accel-3d.c
+++ b/drivers/iio/accel/hid-sensor-accel-3d.c
@@ -422,7 +422,7 @@ error_remove_trigger:
}
/* Function to deinitialize the processing for usage id */
-static int hid_accel_3d_remove(struct platform_device *pdev)
+static void hid_accel_3d_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -431,8 +431,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);
-
- return 0;
}
static const struct platform_device_id hid_accel_3d_ids[] = {
@@ -454,7 +452,7 @@ static struct platform_driver hid_accel_3d_platform_driver = {
.pm = &hid_sensor_pm_ops,
},
.probe = hid_accel_3d_probe,
- .remove = hid_accel_3d_remove,
+ .remove_new = hid_accel_3d_remove,
};
module_platform_driver(hid_accel_3d_platform_driver);
diff --git a/drivers/iio/accel/kionix-kx022a-i2c.c b/drivers/iio/accel/kionix-kx022a-i2c.c
index b0ac78e85d..8a1d4fc28d 100644
--- a/drivers/iio/accel/kionix-kx022a-i2c.c
+++ b/drivers/iio/accel/kionix-kx022a-i2c.c
@@ -2,7 +2,7 @@
/*
* Copyright (C) 2022 ROHM Semiconductors
*
- * ROHM/KIONIX KX022A accelerometer driver
+ * ROHM/KIONIX accelerometer driver
*/
#include <linux/i2c.h>
@@ -15,6 +15,7 @@
static int kx022a_i2c_probe(struct i2c_client *i2c)
{
struct device *dev = &i2c->dev;
+ const struct kx022a_chip_info *chip_info;
struct regmap *regmap;
if (!i2c->irq) {
@@ -22,16 +23,30 @@ static int kx022a_i2c_probe(struct i2c_client *i2c)
return -EINVAL;
}
- regmap = devm_regmap_init_i2c(i2c, &kx022a_regmap);
+ chip_info = i2c_get_match_data(i2c);
+ if (!chip_info)
+ return -EINVAL;
+
+ regmap = devm_regmap_init_i2c(i2c, chip_info->regmap_config);
if (IS_ERR(regmap))
return dev_err_probe(dev, PTR_ERR(regmap),
"Failed to initialize Regmap\n");
- return kx022a_probe_internal(dev);
+ return kx022a_probe_internal(dev, chip_info);
}
+static const struct i2c_device_id kx022a_i2c_id[] = {
+ { .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info },
+ { .name = "kx132-1211", .driver_data = (kernel_ulong_t)&kx132_chip_info },
+ { .name = "kx132acr-lbz", .driver_data = (kernel_ulong_t)&kx132acr_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, kx022a_i2c_id);
+
static const struct of_device_id kx022a_of_match[] = {
- { .compatible = "kionix,kx022a", },
+ { .compatible = "kionix,kx022a", .data = &kx022a_chip_info },
+ { .compatible = "kionix,kx132-1211", .data = &kx132_chip_info },
+ { .compatible = "rohm,kx132acr-lbz", .data = &kx132acr_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, kx022a_of_match);
@@ -43,6 +58,7 @@ static struct i2c_driver kx022a_i2c_driver = {
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.probe = kx022a_i2c_probe,
+ .id_table = kx022a_i2c_id,
};
module_i2c_driver(kx022a_i2c_driver);
diff --git a/drivers/iio/accel/kionix-kx022a-spi.c b/drivers/iio/accel/kionix-kx022a-spi.c
index f45a46899a..f798b964d0 100644
--- a/drivers/iio/accel/kionix-kx022a-spi.c
+++ b/drivers/iio/accel/kionix-kx022a-spi.c
@@ -2,7 +2,7 @@
/*
* Copyright (C) 2022 ROHM Semiconductors
*
- * ROHM/KIONIX KX022A accelerometer driver
+ * ROHM/KIONIX accelerometer driver
*/
#include <linux/interrupt.h>
@@ -15,6 +15,7 @@
static int kx022a_spi_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
+ const struct kx022a_chip_info *chip_info;
struct regmap *regmap;
if (!spi->irq) {
@@ -22,22 +23,30 @@ static int kx022a_spi_probe(struct spi_device *spi)
return -EINVAL;
}
- regmap = devm_regmap_init_spi(spi, &kx022a_regmap);
+ chip_info = spi_get_device_match_data(spi);
+ if (!chip_info)
+ return -EINVAL;
+
+ regmap = devm_regmap_init_spi(spi, chip_info->regmap_config);
if (IS_ERR(regmap))
return dev_err_probe(dev, PTR_ERR(regmap),
"Failed to initialize Regmap\n");
- return kx022a_probe_internal(dev);
+ return kx022a_probe_internal(dev, chip_info);
}
static const struct spi_device_id kx022a_id[] = {
- { "kx022a" },
+ { .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info },
+ { .name = "kx132-1211", .driver_data = (kernel_ulong_t)&kx132_chip_info },
+ { .name = "kx132acr-lbz", .driver_data = (kernel_ulong_t)&kx132acr_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, kx022a_id);
static const struct of_device_id kx022a_of_match[] = {
- { .compatible = "kionix,kx022a", },
+ { .compatible = "kionix,kx022a", .data = &kx022a_chip_info },
+ { .compatible = "kionix,kx132-1211", .data = &kx132_chip_info },
+ { .compatible = "rohm,kx132acr-lbz", .data = &kx132acr_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, kx022a_of_match);
diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c
index 971fc60efe..53d59a04ae 100644
--- a/drivers/iio/accel/kionix-kx022a.c
+++ b/drivers/iio/accel/kionix-kx022a.c
@@ -2,7 +2,7 @@
/*
* Copyright (C) 2022 ROHM Semiconductors
*
- * ROHM/KIONIX KX022A accelerometer driver
+ * ROHM/KIONIX accelerometer driver
*/
#include <linux/delay.h>
@@ -15,7 +15,7 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
-#include <linux/string_helpers.h>
+#include <linux/string_choices.h>
#include <linux/units.h>
#include <linux/iio/iio.h>
@@ -48,7 +48,7 @@ enum {
KX022A_STATE_FIFO,
};
-/* Regmap configs */
+/* kx022a Regmap configs */
static const struct regmap_range kx022a_volatile_ranges[] = {
{
.range_min = KX022A_REG_XHP_L,
@@ -138,7 +138,7 @@ static const struct regmap_access_table kx022a_nir_regs = {
.n_yes_ranges = ARRAY_SIZE(kx022a_noinc_read_ranges),
};
-const struct regmap_config kx022a_regmap = {
+static const struct regmap_config kx022a_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.volatile_table = &kx022a_volatile_regs,
@@ -149,10 +149,121 @@ const struct regmap_config kx022a_regmap = {
.max_register = KX022A_MAX_REGISTER,
.cache_type = REGCACHE_RBTREE,
};
-EXPORT_SYMBOL_NS_GPL(kx022a_regmap, IIO_KX022A);
+
+/* Regmap configs kx132 */
+static const struct regmap_range kx132_volatile_ranges[] = {
+ {
+ .range_min = KX132_REG_XADP_L,
+ .range_max = KX132_REG_COTR,
+ }, {
+ .range_min = KX132_REG_TSCP,
+ .range_max = KX132_REG_INT_REL,
+ }, {
+ /* The reset bit will be cleared by sensor */
+ .range_min = KX132_REG_CNTL2,
+ .range_max = KX132_REG_CNTL2,
+ }, {
+ .range_min = KX132_REG_CNTL5,
+ .range_max = KX132_REG_CNTL5,
+ }, {
+ .range_min = KX132_REG_BUF_STATUS_1,
+ .range_max = KX132_REG_BUF_READ,
+ },
+};
+
+static const struct regmap_access_table kx132_volatile_regs = {
+ .yes_ranges = &kx132_volatile_ranges[0],
+ .n_yes_ranges = ARRAY_SIZE(kx132_volatile_ranges),
+};
+
+static const struct regmap_range kx132_precious_ranges[] = {
+ {
+ .range_min = KX132_REG_INT_REL,
+ .range_max = KX132_REG_INT_REL,
+ },
+};
+
+static const struct regmap_access_table kx132_precious_regs = {
+ .yes_ranges = &kx132_precious_ranges[0],
+ .n_yes_ranges = ARRAY_SIZE(kx132_precious_ranges),
+};
+
+static const struct regmap_range kx132_read_only_ranges[] = {
+ {
+ .range_min = KX132_REG_XADP_L,
+ .range_max = KX132_REG_INT_REL,
+ }, {
+ .range_min = KX132_REG_BUF_STATUS_1,
+ .range_max = KX132_REG_BUF_STATUS_2,
+ }, {
+ .range_min = KX132_REG_BUF_READ,
+ .range_max = KX132_REG_BUF_READ,
+ }, {
+ /* Kionix reserved registers: should not be written */
+ .range_min = 0x28,
+ .range_max = 0x28,
+ }, {
+ .range_min = 0x35,
+ .range_max = 0x36,
+ }, {
+ .range_min = 0x3c,
+ .range_max = 0x48,
+ }, {
+ .range_min = 0x4e,
+ .range_max = 0x5c,
+ }, {
+ .range_min = 0x77,
+ .range_max = 0x7f,
+ },
+};
+
+static const struct regmap_access_table kx132_ro_regs = {
+ .no_ranges = &kx132_read_only_ranges[0],
+ .n_no_ranges = ARRAY_SIZE(kx132_read_only_ranges),
+};
+
+static const struct regmap_range kx132_write_only_ranges[] = {
+ {
+ .range_min = KX132_REG_SELF_TEST,
+ .range_max = KX132_REG_SELF_TEST,
+ }, {
+ .range_min = KX132_REG_BUF_CLEAR,
+ .range_max = KX132_REG_BUF_CLEAR,
+ },
+};
+
+static const struct regmap_access_table kx132_wo_regs = {
+ .no_ranges = &kx132_write_only_ranges[0],
+ .n_no_ranges = ARRAY_SIZE(kx132_write_only_ranges),
+};
+
+static const struct regmap_range kx132_noinc_read_ranges[] = {
+ {
+ .range_min = KX132_REG_BUF_READ,
+ .range_max = KX132_REG_BUF_READ,
+ },
+};
+
+static const struct regmap_access_table kx132_nir_regs = {
+ .yes_ranges = &kx132_noinc_read_ranges[0],
+ .n_yes_ranges = ARRAY_SIZE(kx132_noinc_read_ranges),
+};
+
+static const struct regmap_config kx132_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_table = &kx132_volatile_regs,
+ .rd_table = &kx132_wo_regs,
+ .wr_table = &kx132_ro_regs,
+ .rd_noinc_table = &kx132_nir_regs,
+ .precious_table = &kx132_precious_regs,
+ .max_register = KX132_MAX_REGISTER,
+ .cache_type = REGCACHE_RBTREE,
+};
struct kx022a_data {
struct regmap *regmap;
+ const struct kx022a_chip_info *chip_info;
struct iio_trigger *trig;
struct device *dev;
struct iio_mount_matrix orientation;
@@ -175,6 +286,8 @@ struct kx022a_data {
struct mutex mutex;
u8 watermark;
+ __le16 *fifo_buffer;
+
/* 3 x 16bit accel data + timestamp */
__le16 buffer[8] __aligned(IIO_DMA_MINALIGN);
struct {
@@ -208,7 +321,7 @@ static const struct iio_chan_spec_ext_info kx022a_ext_info[] = {
{ }
};
-#define KX022A_ACCEL_CHAN(axis, index) \
+#define KX022A_ACCEL_CHAN(axis, reg, index) \
{ \
.type = IIO_ACCEL, \
.modified = 1, \
@@ -220,7 +333,7 @@ static const struct iio_chan_spec_ext_info kx022a_ext_info[] = {
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.ext_info = kx022a_ext_info, \
- .address = KX022A_REG_##axis##OUT_L, \
+ .address = reg, \
.scan_index = index, \
.scan_type = { \
.sign = 's', \
@@ -231,9 +344,16 @@ static const struct iio_chan_spec_ext_info kx022a_ext_info[] = {
}
static const struct iio_chan_spec kx022a_channels[] = {
- KX022A_ACCEL_CHAN(X, 0),
- KX022A_ACCEL_CHAN(Y, 1),
- KX022A_ACCEL_CHAN(Z, 2),
+ KX022A_ACCEL_CHAN(X, KX022A_REG_XOUT_L, 0),
+ KX022A_ACCEL_CHAN(Y, KX022A_REG_YOUT_L, 1),
+ KX022A_ACCEL_CHAN(Z, KX022A_REG_ZOUT_L, 2),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static const struct iio_chan_spec kx132_channels[] = {
+ KX022A_ACCEL_CHAN(X, KX132_REG_XOUT_L, 0),
+ KX022A_ACCEL_CHAN(Y, KX132_REG_YOUT_L, 1),
+ KX022A_ACCEL_CHAN(Z, KX132_REG_ZOUT_L, 2),
IIO_CHAN_SOFT_TIMESTAMP(3),
};
@@ -332,16 +452,15 @@ static int kx022a_turn_on_off_unlocked(struct kx022a_data *data, bool on)
int ret;
if (on)
- ret = regmap_set_bits(data->regmap, KX022A_REG_CNTL,
+ ret = regmap_set_bits(data->regmap, data->chip_info->cntl,
KX022A_MASK_PC1);
else
- ret = regmap_clear_bits(data->regmap, KX022A_REG_CNTL,
+ ret = regmap_clear_bits(data->regmap, data->chip_info->cntl,
KX022A_MASK_PC1);
if (ret)
dev_err(data->dev, "Turn %s fail %d\n", str_on_off(on), ret);
return ret;
-
}
static int kx022a_turn_off_lock(struct kx022a_data *data)
@@ -417,7 +536,7 @@ static int kx022a_write_raw(struct iio_dev *idev,
break;
ret = regmap_update_bits(data->regmap,
- KX022A_REG_ODCNTL,
+ data->chip_info->odcntl,
KX022A_MASK_ODR, n);
data->odr_ns = kx022a_odrs[n];
kx022a_turn_on_unlock(data);
@@ -438,7 +557,7 @@ static int kx022a_write_raw(struct iio_dev *idev,
if (ret)
break;
- ret = regmap_update_bits(data->regmap, KX022A_REG_CNTL,
+ ret = regmap_update_bits(data->regmap, data->chip_info->cntl,
KX022A_MASK_GSEL,
n << KX022A_GSEL_SHIFT);
kx022a_turn_on_unlock(data);
@@ -460,7 +579,7 @@ static int kx022a_fifo_set_wmi(struct kx022a_data *data)
threshold = data->watermark;
- return regmap_update_bits(data->regmap, KX022A_REG_BUF_CNTL1,
+ return regmap_update_bits(data->regmap, data->chip_info->buf_cntl1,
KX022A_MASK_WM_TH, threshold);
}
@@ -503,7 +622,7 @@ static int kx022a_read_raw(struct iio_dev *idev,
return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
- ret = regmap_read(data->regmap, KX022A_REG_ODCNTL, &regval);
+ ret = regmap_read(data->regmap, data->chip_info->odcntl, &regval);
if (ret)
return ret;
@@ -518,7 +637,7 @@ static int kx022a_read_raw(struct iio_dev *idev,
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SCALE:
- ret = regmap_read(data->regmap, KX022A_REG_CNTL, &regval);
+ ret = regmap_read(data->regmap, data->chip_info->cntl, &regval);
if (ret < 0)
return ret;
@@ -534,8 +653,7 @@ static int kx022a_set_watermark(struct iio_dev *idev, unsigned int val)
{
struct kx022a_data *data = iio_priv(idev);
- if (val > KX022A_FIFO_LENGTH)
- val = KX022A_FIFO_LENGTH;
+ val = min(data->chip_info->fifo_length, val);
mutex_lock(&data->mutex);
data->watermark = val;
@@ -596,30 +714,56 @@ static int kx022a_drop_fifo_contents(struct kx022a_data *data)
*/
data->timestamp = 0;
- return regmap_write(data->regmap, KX022A_REG_BUF_CLEAR, 0x0);
+ return regmap_write(data->regmap, data->chip_info->buf_clear, 0x0);
+}
+
+static int kx022a_get_fifo_bytes_available(struct kx022a_data *data)
+{
+ int ret, fifo_bytes;
+
+ ret = regmap_read(data->regmap, KX022A_REG_BUF_STATUS_1, &fifo_bytes);
+ if (ret) {
+ dev_err(data->dev, "Error reading buffer status\n");
+ return ret;
+ }
+
+ if (fifo_bytes == KX022A_FIFO_FULL_VALUE)
+ return KX022A_FIFO_MAX_BYTES;
+
+ return fifo_bytes;
+}
+
+static int kx132_get_fifo_bytes_available(struct kx022a_data *data)
+{
+ __le16 buf_status;
+ int ret, fifo_bytes;
+
+ ret = regmap_bulk_read(data->regmap, data->chip_info->buf_status1,
+ &buf_status, sizeof(buf_status));
+ if (ret) {
+ dev_err(data->dev, "Error reading buffer status\n");
+ return ret;
+ }
+
+ fifo_bytes = le16_to_cpu(buf_status);
+ fifo_bytes &= data->chip_info->buf_smp_lvl_mask;
+ fifo_bytes = min((unsigned int)fifo_bytes, data->chip_info->fifo_length *
+ KX022A_FIFO_SAMPLES_SIZE_BYTES);
+
+ return fifo_bytes;
}
static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples,
bool irq)
{
struct kx022a_data *data = iio_priv(idev);
- struct device *dev = regmap_get_device(data->regmap);
- __le16 buffer[KX022A_FIFO_LENGTH * 3];
uint64_t sample_period;
int count, fifo_bytes;
bool renable = false;
int64_t tstamp;
int ret, i;
- ret = regmap_read(data->regmap, KX022A_REG_BUF_STATUS_1, &fifo_bytes);
- if (ret) {
- dev_err(dev, "Error reading buffer status\n");
- return ret;
- }
-
- /* Let's not overflow if we for some reason get bogus value from i2c */
- if (fifo_bytes == KX022A_FIFO_FULL_VALUE)
- fifo_bytes = KX022A_FIFO_MAX_BYTES;
+ fifo_bytes = data->chip_info->get_fifo_bytes_available(data);
if (fifo_bytes % KX022A_FIFO_SAMPLES_SIZE_BYTES)
dev_warn(data->dev, "Bad FIFO alignment. Data may be corrupt\n");
@@ -683,13 +827,13 @@ static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples,
}
fifo_bytes = count * KX022A_FIFO_SAMPLES_SIZE_BYTES;
- ret = regmap_noinc_read(data->regmap, KX022A_REG_BUF_READ,
- &buffer[0], fifo_bytes);
+ ret = regmap_noinc_read(data->regmap, data->chip_info->buf_read,
+ data->fifo_buffer, fifo_bytes);
if (ret)
goto renable_out;
for (i = 0; i < count; i++) {
- __le16 *sam = &buffer[i * 3];
+ __le16 *sam = &data->fifo_buffer[i * 3];
__le16 *chs;
int bit;
@@ -737,10 +881,10 @@ static const struct iio_info kx022a_info = {
static int kx022a_set_drdy_irq(struct kx022a_data *data, bool en)
{
if (en)
- return regmap_set_bits(data->regmap, KX022A_REG_CNTL,
+ return regmap_set_bits(data->regmap, data->chip_info->cntl,
KX022A_MASK_DRDY);
- return regmap_clear_bits(data->regmap, KX022A_REG_CNTL,
+ return regmap_clear_bits(data->regmap, data->chip_info->cntl,
KX022A_MASK_DRDY);
}
@@ -775,7 +919,7 @@ static int kx022a_fifo_disable(struct kx022a_data *data)
if (ret)
goto unlock_out;
- ret = regmap_clear_bits(data->regmap, KX022A_REG_BUF_CNTL2,
+ ret = regmap_clear_bits(data->regmap, data->chip_info->buf_cntl2,
KX022A_MASK_BUF_EN);
if (ret)
goto unlock_out;
@@ -784,6 +928,8 @@ static int kx022a_fifo_disable(struct kx022a_data *data)
kx022a_drop_fifo_contents(data);
+ kfree(data->fifo_buffer);
+
return kx022a_turn_on_unlock(data);
unlock_out:
@@ -806,6 +952,12 @@ static int kx022a_fifo_enable(struct kx022a_data *data)
{
int ret;
+ data->fifo_buffer = kmalloc_array(data->chip_info->fifo_length,
+ KX022A_FIFO_SAMPLES_SIZE_BYTES,
+ GFP_KERNEL);
+ if (!data->fifo_buffer)
+ return -ENOMEM;
+
ret = kx022a_turn_off_lock(data);
if (ret)
return ret;
@@ -816,7 +968,7 @@ static int kx022a_fifo_enable(struct kx022a_data *data)
goto unlock_out;
/* Enable buffer */
- ret = regmap_set_bits(data->regmap, KX022A_REG_BUF_CNTL2,
+ ret = regmap_set_bits(data->regmap, data->chip_info->buf_cntl2,
KX022A_MASK_BUF_EN);
if (ret)
goto unlock_out;
@@ -862,7 +1014,7 @@ static irqreturn_t kx022a_trigger_handler(int irq, void *p)
struct kx022a_data *data = iio_priv(idev);
int ret;
- ret = regmap_bulk_read(data->regmap, KX022A_REG_XOUT_L, data->buffer,
+ ret = regmap_bulk_read(data->regmap, data->chip_info->xout_l, data->buffer,
KX022A_FIFO_SAMPLES_SIZE_BYTES);
if (ret < 0)
goto err_read;
@@ -910,7 +1062,7 @@ static irqreturn_t kx022a_irq_thread_handler(int irq, void *private)
if (data->state & KX022A_STATE_FIFO) {
int ok;
- ok = __kx022a_fifo_flush(idev, KX022A_FIFO_LENGTH, true);
+ ok = __kx022a_fifo_flush(idev, data->chip_info->fifo_length, true);
if (ok > 0)
ret = IRQ_HANDLED;
}
@@ -963,7 +1115,7 @@ static int kx022a_chip_init(struct kx022a_data *data)
int ret, val;
/* Reset the senor */
- ret = regmap_write(data->regmap, KX022A_REG_CNTL2, KX022A_MASK_SRST);
+ ret = regmap_write(data->regmap, data->chip_info->cntl2, KX022A_MASK_SRST);
if (ret)
return ret;
@@ -973,7 +1125,7 @@ static int kx022a_chip_init(struct kx022a_data *data)
*/
msleep(1);
- ret = regmap_read_poll_timeout(data->regmap, KX022A_REG_CNTL2, val,
+ ret = regmap_read_poll_timeout(data->regmap, data->chip_info->cntl2, val,
!(val & KX022A_MASK_SRST),
KX022A_SOFT_RESET_WAIT_TIME_US,
KX022A_SOFT_RESET_TOTAL_WAIT_TIME_US);
@@ -983,14 +1135,14 @@ static int kx022a_chip_init(struct kx022a_data *data)
return ret;
}
- ret = regmap_reinit_cache(data->regmap, &kx022a_regmap);
+ ret = regmap_reinit_cache(data->regmap, data->chip_info->regmap_config);
if (ret) {
dev_err(data->dev, "Failed to reinit reg cache\n");
return ret;
}
/* set data res 16bit */
- ret = regmap_set_bits(data->regmap, KX022A_REG_BUF_CNTL2,
+ ret = regmap_set_bits(data->regmap, data->chip_info->buf_cntl2,
KX022A_MASK_BRES16);
if (ret) {
dev_err(data->dev, "Failed to set data resolution\n");
@@ -1000,7 +1152,90 @@ static int kx022a_chip_init(struct kx022a_data *data)
return kx022a_prepare_irq_pin(data);
}
-int kx022a_probe_internal(struct device *dev)
+const struct kx022a_chip_info kx022a_chip_info = {
+ .name = "kx022-accel",
+ .regmap_config = &kx022a_regmap_config,
+ .channels = kx022a_channels,
+ .num_channels = ARRAY_SIZE(kx022a_channels),
+ .fifo_length = KX022A_FIFO_LENGTH,
+ .who = KX022A_REG_WHO,
+ .id = KX022A_ID,
+ .cntl = KX022A_REG_CNTL,
+ .cntl2 = KX022A_REG_CNTL2,
+ .odcntl = KX022A_REG_ODCNTL,
+ .buf_cntl1 = KX022A_REG_BUF_CNTL1,
+ .buf_cntl2 = KX022A_REG_BUF_CNTL2,
+ .buf_clear = KX022A_REG_BUF_CLEAR,
+ .buf_status1 = KX022A_REG_BUF_STATUS_1,
+ .buf_read = KX022A_REG_BUF_READ,
+ .inc1 = KX022A_REG_INC1,
+ .inc4 = KX022A_REG_INC4,
+ .inc5 = KX022A_REG_INC5,
+ .inc6 = KX022A_REG_INC6,
+ .xout_l = KX022A_REG_XOUT_L,
+ .get_fifo_bytes_available = kx022a_get_fifo_bytes_available,
+};
+EXPORT_SYMBOL_NS_GPL(kx022a_chip_info, IIO_KX022A);
+
+const struct kx022a_chip_info kx132_chip_info = {
+ .name = "kx132-1211",
+ .regmap_config = &kx132_regmap_config,
+ .channels = kx132_channels,
+ .num_channels = ARRAY_SIZE(kx132_channels),
+ .fifo_length = KX132_FIFO_LENGTH,
+ .who = KX132_REG_WHO,
+ .id = KX132_ID,
+ .cntl = KX132_REG_CNTL,
+ .cntl2 = KX132_REG_CNTL2,
+ .odcntl = KX132_REG_ODCNTL,
+ .buf_cntl1 = KX132_REG_BUF_CNTL1,
+ .buf_cntl2 = KX132_REG_BUF_CNTL2,
+ .buf_clear = KX132_REG_BUF_CLEAR,
+ .buf_status1 = KX132_REG_BUF_STATUS_1,
+ .buf_smp_lvl_mask = KX132_MASK_BUF_SMP_LVL,
+ .buf_read = KX132_REG_BUF_READ,
+ .inc1 = KX132_REG_INC1,
+ .inc4 = KX132_REG_INC4,
+ .inc5 = KX132_REG_INC5,
+ .inc6 = KX132_REG_INC6,
+ .xout_l = KX132_REG_XOUT_L,
+ .get_fifo_bytes_available = kx132_get_fifo_bytes_available,
+};
+EXPORT_SYMBOL_NS_GPL(kx132_chip_info, IIO_KX022A);
+
+/*
+ * Despite the naming, KX132ACR-LBZ is not similar to KX132-1211 but it is
+ * exact subset of KX022A. KX132ACR-LBZ is meant to be used for industrial
+ * applications and the tap/double tap, free fall and tilt engines were
+ * removed. Rest of the registers and functionalities (excluding the ID
+ * register) are exact match to what is found in KX022.
+ */
+const struct kx022a_chip_info kx132acr_chip_info = {
+ .name = "kx132acr-lbz",
+ .regmap_config = &kx022a_regmap_config,
+ .channels = kx022a_channels,
+ .num_channels = ARRAY_SIZE(kx022a_channels),
+ .fifo_length = KX022A_FIFO_LENGTH,
+ .who = KX022A_REG_WHO,
+ .id = KX132ACR_LBZ_ID,
+ .cntl = KX022A_REG_CNTL,
+ .cntl2 = KX022A_REG_CNTL2,
+ .odcntl = KX022A_REG_ODCNTL,
+ .buf_cntl1 = KX022A_REG_BUF_CNTL1,
+ .buf_cntl2 = KX022A_REG_BUF_CNTL2,
+ .buf_clear = KX022A_REG_BUF_CLEAR,
+ .buf_status1 = KX022A_REG_BUF_STATUS_1,
+ .buf_read = KX022A_REG_BUF_READ,
+ .inc1 = KX022A_REG_INC1,
+ .inc4 = KX022A_REG_INC4,
+ .inc5 = KX022A_REG_INC5,
+ .inc6 = KX022A_REG_INC6,
+ .xout_l = KX022A_REG_XOUT_L,
+ .get_fifo_bytes_available = kx022a_get_fifo_bytes_available,
+};
+EXPORT_SYMBOL_NS_GPL(kx132acr_chip_info, IIO_KX022A);
+
+int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info)
{
static const char * const regulator_names[] = {"io-vdd", "vdd"};
struct iio_trigger *indio_trig;
@@ -1027,6 +1262,7 @@ int kx022a_probe_internal(struct device *dev)
return -ENOMEM;
data = iio_priv(idev);
+ data->chip_info = chip_info;
/*
* VDD is the analog and digital domain voltage supply and
@@ -1037,26 +1273,24 @@ int kx022a_probe_internal(struct device *dev)
if (ret && ret != -ENODEV)
return dev_err_probe(dev, ret, "failed to enable regulator\n");
- ret = regmap_read(regmap, KX022A_REG_WHO, &chip_id);
+ ret = regmap_read(regmap, chip_info->who, &chip_id);
if (ret)
return dev_err_probe(dev, ret, "Failed to access sensor\n");
- if (chip_id != KX022A_ID) {
- dev_err(dev, "unsupported device 0x%x\n", chip_id);
- return -EINVAL;
- }
+ if (chip_id != chip_info->id)
+ dev_warn(dev, "unknown device 0x%x\n", chip_id);
irq = fwnode_irq_get_byname(fwnode, "INT1");
if (irq > 0) {
- data->inc_reg = KX022A_REG_INC1;
- data->ien_reg = KX022A_REG_INC4;
+ data->inc_reg = chip_info->inc1;
+ data->ien_reg = chip_info->inc4;
} else {
irq = fwnode_irq_get_byname(fwnode, "INT2");
if (irq < 0)
return dev_err_probe(dev, irq, "No suitable IRQ\n");
- data->inc_reg = KX022A_REG_INC5;
- data->ien_reg = KX022A_REG_INC6;
+ data->inc_reg = chip_info->inc5;
+ data->ien_reg = chip_info->inc6;
}
data->regmap = regmap;
@@ -1065,9 +1299,9 @@ int kx022a_probe_internal(struct device *dev)
data->odr_ns = KX022A_DEFAULT_PERIOD_NS;
mutex_init(&data->mutex);
- idev->channels = kx022a_channels;
- idev->num_channels = ARRAY_SIZE(kx022a_channels);
- idev->name = "kx022-accel";
+ idev->channels = chip_info->channels;
+ idev->num_channels = chip_info->num_channels;
+ idev->name = chip_info->name;
idev->info = &kx022a_info;
idev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
idev->available_scan_masks = kx022a_scan_masks;
@@ -1125,7 +1359,6 @@ int kx022a_probe_internal(struct device *dev)
if (ret)
return dev_err_probe(data->dev, ret, "Could not request IRQ\n");
-
ret = devm_iio_trigger_register(dev, indio_trig);
if (ret)
return dev_err_probe(data->dev, ret,
diff --git a/drivers/iio/accel/kionix-kx022a.h b/drivers/iio/accel/kionix-kx022a.h
index 12424649d4..7060438ad8 100644
--- a/drivers/iio/accel/kionix-kx022a.h
+++ b/drivers/iio/accel/kionix-kx022a.h
@@ -13,6 +13,7 @@
#define KX022A_REG_WHO 0x0f
#define KX022A_ID 0xc8
+#define KX132ACR_LBZ_ID 0xd8
#define KX022A_REG_CNTL2 0x19
#define KX022A_MASK_SRST BIT(7)
@@ -74,9 +75,118 @@
#define KX022A_REG_SELF_TEST 0x60
#define KX022A_MAX_REGISTER 0x60
+#define KX132_REG_WHO 0x13
+#define KX132_ID 0x3d
+
+#define KX132_FIFO_LENGTH 86
+
+#define KX132_REG_CNTL 0x1b
+#define KX132_REG_CNTL2 0x1c
+#define KX132_REG_CNTL5 0x1f
+#define KX132_MASK_RES BIT(6)
+#define KX132_GSEL_2 0x0
+#define KX132_GSEL_4 BIT(3)
+#define KX132_GSEL_8 BIT(4)
+#define KX132_GSEL_16 GENMASK(4, 3)
+
+#define KX132_REG_INS2 0x17
+#define KX132_MASK_INS2_WMI BIT(5)
+
+#define KX132_REG_XADP_L 0x02
+#define KX132_REG_XOUT_L 0x08
+#define KX132_REG_YOUT_L 0x0a
+#define KX132_REG_ZOUT_L 0x0c
+#define KX132_REG_COTR 0x12
+#define KX132_REG_TSCP 0x14
+#define KX132_REG_INT_REL 0x1a
+
+#define KX132_REG_ODCNTL 0x21
+
+#define KX132_REG_BTS_WUF_TH 0x4a
+
+#define KX132_REG_BUF_CNTL1 0x5e
+#define KX132_REG_BUF_CNTL2 0x5f
+#define KX132_REG_BUF_STATUS_1 0x60
+#define KX132_REG_BUF_STATUS_2 0x61
+#define KX132_MASK_BUF_SMP_LVL GENMASK(9, 0)
+#define KX132_REG_BUF_CLEAR 0x62
+#define KX132_REG_BUF_READ 0x63
+#define KX132_ODR_SHIFT 3
+#define KX132_FIFO_MAX_WMI_TH 86
+
+#define KX132_REG_INC1 0x22
+#define KX132_REG_INC5 0x26
+#define KX132_REG_INC6 0x27
+#define KX132_IPOL_LOW 0
+#define KX132_IPOL_HIGH KX022A_MASK_IPOL
+#define KX132_ITYP_PULSE KX022A_MASK_ITYP
+
+#define KX132_REG_INC4 0x25
+
+#define KX132_REG_SELF_TEST 0x5d
+#define KX132_MAX_REGISTER 0x76
+
struct device;
-int kx022a_probe_internal(struct device *dev);
-extern const struct regmap_config kx022a_regmap;
+struct kx022a_data;
+
+/**
+ * struct kx022a_chip_info - Kionix accelerometer chip specific information
+ *
+ * @name: name of the device
+ * @regmap_config: pointer to register map configuration
+ * @channels: pointer to iio_chan_spec array
+ * @num_channels: number of iio_chan_spec channels
+ * @fifo_length: number of 16-bit samples in a full buffer
+ * @buf_smp_lvl_mask: buffer sample level mask
+ * @who: WHO_AM_I register
+ * @id: WHO_AM_I register value
+ * @cntl: control register 1
+ * @cntl2: control register 2
+ * @odcntl: output data control register
+ * @buf_cntl1: buffer control register 1
+ * @buf_cntl2: buffer control register 2
+ * @buf_clear: buffer clear register
+ * @buf_status1: buffer status register 1
+ * @buf_read: buffer read register
+ * @inc1: interrupt control register 1
+ * @inc4: interrupt control register 4
+ * @inc5: interrupt control register 5
+ * @inc6: interrupt control register 6
+ * @xout_l: x-axis output least significant byte
+ * @get_fifo_bytes_available: function pointer to get amount of acceleration
+ * data bytes currently stored in the sensor's FIFO
+ * buffer
+ */
+struct kx022a_chip_info {
+ const char *name;
+ const struct regmap_config *regmap_config;
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+ unsigned int fifo_length;
+ u16 buf_smp_lvl_mask;
+ u8 who;
+ u8 id;
+ u8 cntl;
+ u8 cntl2;
+ u8 odcntl;
+ u8 buf_cntl1;
+ u8 buf_cntl2;
+ u8 buf_clear;
+ u8 buf_status1;
+ u8 buf_read;
+ u8 inc1;
+ u8 inc4;
+ u8 inc5;
+ u8 inc6;
+ u8 xout_l;
+ int (*get_fifo_bytes_available)(struct kx022a_data *);
+};
+
+int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info);
+
+extern const struct kx022a_chip_info kx022a_chip_info;
+extern const struct kx022a_chip_info kx132_chip_info;
+extern const struct kx022a_chip_info kx132acr_chip_info;
#endif
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index f42a887114..d3fd0318e4 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -1535,19 +1535,18 @@ static int mma8452_reset(struct i2c_client *client)
}
static const struct of_device_id mma8452_dt_ids[] = {
+ { .compatible = "fsl,fxls8471", .data = &mma_chip_info_table[fxls8471] },
{ .compatible = "fsl,mma8451", .data = &mma_chip_info_table[mma8451] },
{ .compatible = "fsl,mma8452", .data = &mma_chip_info_table[mma8452] },
{ .compatible = "fsl,mma8453", .data = &mma_chip_info_table[mma8453] },
{ .compatible = "fsl,mma8652", .data = &mma_chip_info_table[mma8652] },
{ .compatible = "fsl,mma8653", .data = &mma_chip_info_table[mma8653] },
- { .compatible = "fsl,fxls8471", .data = &mma_chip_info_table[fxls8471] },
{ }
};
MODULE_DEVICE_TABLE(of, mma8452_dt_ids);
static int mma8452_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct mma8452_data *data;
struct iio_dev *indio_dev;
int ret;
@@ -1560,15 +1559,10 @@ static int mma8452_probe(struct i2c_client *client)
data->client = client;
mutex_init(&data->lock);
- data->chip_info = device_get_match_data(&client->dev);
- if (!data->chip_info) {
- if (id) {
- data->chip_info = &mma_chip_info_table[id->driver_data];
- } else {
- dev_err(&client->dev, "unknown device model\n");
- return -ENODEV;
- }
- }
+ data->chip_info = i2c_get_match_data(client);
+ if (!data->chip_info)
+ return dev_err_probe(&client->dev, -ENODEV,
+ "unknown device model\n");
ret = iio_read_mount_matrix(&client->dev, &data->orientation);
if (ret)
@@ -1830,12 +1824,12 @@ static const struct dev_pm_ops mma8452_pm_ops = {
};
static const struct i2c_device_id mma8452_id[] = {
- { "mma8451", mma8451 },
- { "mma8452", mma8452 },
- { "mma8453", mma8453 },
- { "mma8652", mma8652 },
- { "mma8653", mma8653 },
- { "fxls8471", fxls8471 },
+ { "fxls8471", (kernel_ulong_t)&mma_chip_info_table[fxls8471] },
+ { "mma8451", (kernel_ulong_t)&mma_chip_info_table[mma8451] },
+ { "mma8452", (kernel_ulong_t)&mma_chip_info_table[mma8452] },
+ { "mma8453", (kernel_ulong_t)&mma_chip_info_table[mma8453] },
+ { "mma8652", (kernel_ulong_t)&mma_chip_info_table[mma8652] },
+ { "mma8653", (kernel_ulong_t)&mma_chip_info_table[mma8653] },
{ }
};
MODULE_DEVICE_TABLE(i2c, mma8452_id);
diff --git a/drivers/iio/accel/msa311.c b/drivers/iio/accel/msa311.c
index 6ddcc3c2f8..b8ddbfd98f 100644
--- a/drivers/iio/accel/msa311.c
+++ b/drivers/iio/accel/msa311.c
@@ -33,7 +33,7 @@
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
-#include <linux/string_helpers.h>
+#include <linux/string_choices.h>
#include <linux/units.h>
#include <linux/iio/buffer.h>
diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c
index 75d142bc14..82e8d0b390 100644
--- a/drivers/iio/accel/mxc4005.c
+++ b/drivers/iio/accel/mxc4005.c
@@ -476,6 +476,13 @@ static const struct acpi_device_id mxc4005_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, mxc4005_acpi_match);
+static const struct of_device_id mxc4005_of_match[] = {
+ { .compatible = "memsic,mxc4005", },
+ { .compatible = "memsic,mxc6655", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, mxc4005_of_match);
+
static const struct i2c_device_id mxc4005_id[] = {
{"mxc4005", 0},
{"mxc6655", 0},
@@ -487,6 +494,7 @@ static struct i2c_driver mxc4005_driver = {
.driver = {
.name = MXC4005_DRV_NAME,
.acpi_match_table = ACPI_PTR(mxc4005_acpi_match),
+ .of_match_table = mxc4005_of_match,
},
.probe = mxc4005_probe,
.id_table = mxc4005_id,
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 517b3db114..35f9867da1 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -607,6 +607,16 @@ config LPC32XX_ADC
activate only one via device tree selection. Provides direct access
via sysfs.
+config LTC2309
+ tristate "Linear Technology LTC2309 ADC driver"
+ depends on I2C
+ help
+ Say yes here to build support for Linear Technology LTC2309, a low
+ noise, low power, 8-channel, 12-bit SAR ADC
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc2309.
+
config LTC2471
tristate "Linear Technology LTC2471 and LTC2473 ADC driver"
depends on I2C
@@ -779,14 +789,29 @@ config MCP3422
This driver can also be built as a module. If so, the module will be
called mcp3422.
+config MCP3564
+ tristate "Microchip Technology MCP3461/2/4/R, MCP3561/2/4/R driver"
+ depends on SPI
+ depends on IIO
+ help
+ Say yes here to build support for Microchip Technology's MCP3461,
+ MCP3462, MCP3464, MCP3461R, MCP3462R, MCP3464R, MCP3561, MCP3562,
+ MCP3564, MCP3561R, MCP3562R and MCP3564R analog to digital
+ converters.
+
+ This driver can also be built as a module. If so, the module will be
+ called mcp3564.
+
config MCP3911
tristate "Microchip Technology MCP3911 driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
- Say yes here to build support for Microchip Technology's MCP3911
- analog to digital converter.
+ Say yes here to build support for one of the following
+ Microchip Technology's analog to digital converters:
+ MCP3910, MCP3911, MCP3912, MCP3913, MCP3914,
+ MCP3918 and MCP3919.
This driver can also be built as a module. If so, the module will be
called mcp3911.
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 2facf97932..bee11d442a 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_INTEL_MRFLD_ADC) += intel_mrfld_adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
+obj-$(CONFIG_LTC2309) += ltc2309.o
obj-$(CONFIG_LTC2471) += ltc2471.o
obj-$(CONFIG_LTC2485) += ltc2485.o
obj-$(CONFIG_LTC2496) += ltc2496.o ltc2497-core.o
@@ -71,6 +72,7 @@ obj-$(CONFIG_MAX77541_ADC) += max77541-adc.o
obj-$(CONFIG_MAX9611) += max9611.o
obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
+obj-$(CONFIG_MCP3564) += mcp3564.o
obj-$(CONFIG_MCP3911) += mcp3911.o
obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o
obj-$(CONFIG_MEDIATEK_MT6370_ADC) += mt6370-adc.o
diff --git a/drivers/iio/adc/ab8500-gpadc.c b/drivers/iio/adc/ab8500-gpadc.c
index 3b1bdd0b53..80645fee79 100644
--- a/drivers/iio/adc/ab8500-gpadc.c
+++ b/drivers/iio/adc/ab8500-gpadc.c
@@ -1179,7 +1179,7 @@ out_dis_pm:
return ret;
}
-static int ab8500_gpadc_remove(struct platform_device *pdev)
+static void ab8500_gpadc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct ab8500_gpadc *gpadc = iio_priv(indio_dev);
@@ -1188,8 +1188,6 @@ static int ab8500_gpadc_remove(struct platform_device *pdev)
pm_runtime_put_noidle(gpadc->dev);
pm_runtime_disable(gpadc->dev);
regulator_disable(gpadc->vddadc);
-
- return 0;
}
static DEFINE_RUNTIME_DEV_PM_OPS(ab8500_gpadc_pm_ops,
@@ -1198,7 +1196,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ab8500_gpadc_pm_ops,
static struct platform_driver ab8500_gpadc_driver = {
.probe = ab8500_gpadc_probe,
- .remove = ab8500_gpadc_remove,
+ .remove_new = ab8500_gpadc_remove,
.driver = {
.name = "ab8500-gpadc",
.pm = pm_ptr(&ab8500_gpadc_pm_ops),
diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c
index 5a5dd5e87f..62490424b6 100644
--- a/drivers/iio/adc/ad4130.c
+++ b/drivers/iio/adc/ad4130.c
@@ -1817,18 +1817,12 @@ static const struct clk_ops ad4130_int_clk_ops = {
.unprepare = ad4130_int_clk_unprepare,
};
-static void ad4130_clk_del_provider(void *of_node)
-{
- of_clk_del_provider(of_node);
-}
-
static int ad4130_setup_int_clk(struct ad4130_state *st)
{
struct device *dev = &st->spi->dev;
struct device_node *of_node = dev_of_node(dev);
- struct clk_init_data init;
+ struct clk_init_data init = {};
const char *clk_name;
- struct clk *clk;
int ret;
if (st->int_pin_sel == AD4130_INT_PIN_CLK ||
@@ -1845,15 +1839,12 @@ static int ad4130_setup_int_clk(struct ad4130_state *st)
init.ops = &ad4130_int_clk_ops;
st->int_clk_hw.init = &init;
- clk = devm_clk_register(dev, &st->int_clk_hw);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
-
- ret = of_clk_add_provider(of_node, of_clk_src_simple_get, clk);
+ ret = devm_clk_hw_register(dev, &st->int_clk_hw);
if (ret)
return ret;
- return devm_add_action_or_reset(dev, ad4130_clk_del_provider, of_node);
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
+ &st->int_clk_hw);
}
static int ad4130_setup(struct iio_dev *indio_dev)
@@ -1900,10 +1891,14 @@ static int ad4130_setup(struct iio_dev *indio_dev)
return ret;
/*
- * Configure all GPIOs for output. If configured, the interrupt function
- * of P2 takes priority over the GPIO out function.
+ * Configure unused GPIOs for output. If configured, the interrupt
+ * function of P2 takes priority over the GPIO out function.
*/
- val = AD4130_IO_CONTROL_GPIO_CTRL_MASK;
+ val = 0;
+ for (i = 0; i < AD4130_MAX_GPIOS; i++)
+ if (st->pins_fn[i + AD4130_AIN2_P1] == AD4130_PIN_FN_NONE)
+ val |= FIELD_PREP(AD4130_IO_CONTROL_GPIO_CTRL_MASK, BIT(i));
+
val |= FIELD_PREP(AD4130_IO_CONTROL_INT_PIN_SEL_MASK, st->int_pin_sel);
ret = regmap_write(st->regmap, AD4130_IO_CONTROL_REG, val);
diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c
index b64fd365f8..adc3cbe92d 100644
--- a/drivers/iio/adc/ad7192.c
+++ b/drivers/iio/adc/ad7192.c
@@ -6,6 +6,7 @@
*/
#include <linux/interrupt.h>
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/kernel.h>
@@ -43,7 +44,7 @@
#define AD7192_COMM_WEN BIT(7) /* Write Enable */
#define AD7192_COMM_WRITE 0 /* Write Operation */
#define AD7192_COMM_READ BIT(6) /* Read Operation */
-#define AD7192_COMM_ADDR(x) (((x) & 0x7) << 3) /* Register Address */
+#define AD7192_COMM_ADDR_MASK GENMASK(5, 3) /* Register Address Mask */
#define AD7192_COMM_CREAD BIT(2) /* Continuous Read of Data Register */
/* Status Register Bit Designations (AD7192_REG_STAT) */
@@ -56,17 +57,18 @@
#define AD7192_STAT_CH1 BIT(0) /* Channel 1 */
/* Mode Register Bit Designations (AD7192_REG_MODE) */
-#define AD7192_MODE_SEL(x) (((x) & 0x7) << 21) /* Operation Mode Select */
-#define AD7192_MODE_SEL_MASK (0x7 << 21) /* Operation Mode Select Mask */
-#define AD7192_MODE_STA(x) (((x) & 0x1) << 20) /* Status Register transmission */
+#define AD7192_MODE_SEL_MASK GENMASK(23, 21) /* Operation Mode Select Mask */
#define AD7192_MODE_STA_MASK BIT(20) /* Status Register transmission Mask */
-#define AD7192_MODE_CLKSRC(x) (((x) & 0x3) << 18) /* Clock Source Select */
+#define AD7192_MODE_CLKSRC_MASK GENMASK(19, 18) /* Clock Source Select Mask */
+#define AD7192_MODE_AVG_MASK GENMASK(17, 16)
+ /* Fast Settling Filter Average Select Mask (AD7193 only) */
#define AD7192_MODE_SINC3 BIT(15) /* SINC3 Filter Select */
#define AD7192_MODE_ENPAR BIT(13) /* Parity Enable */
#define AD7192_MODE_CLKDIV BIT(12) /* Clock divide by 2 (AD7190/2 only)*/
#define AD7192_MODE_SCYCLE BIT(11) /* Single cycle conversion */
#define AD7192_MODE_REJ60 BIT(10) /* 50/60Hz notch filter */
-#define AD7192_MODE_RATE(x) ((x) & 0x3FF) /* Filter Update Rate Select */
+ /* Filter Update Rate Select Mask */
+#define AD7192_MODE_RATE_MASK GENMASK(9, 0)
/* Mode Register: AD7192_MODE_SEL options */
#define AD7192_MODE_CONT 0 /* Continuous Conversion Mode */
@@ -92,13 +94,12 @@
#define AD7192_CONF_CHOP BIT(23) /* CHOP enable */
#define AD7192_CONF_ACX BIT(22) /* AC excitation enable(AD7195 only) */
#define AD7192_CONF_REFSEL BIT(20) /* REFIN1/REFIN2 Reference Select */
-#define AD7192_CONF_CHAN(x) ((x) << 8) /* Channel select */
-#define AD7192_CONF_CHAN_MASK (0x7FF << 8) /* Channel select mask */
+#define AD7192_CONF_CHAN_MASK GENMASK(18, 8) /* Channel select mask */
#define AD7192_CONF_BURN BIT(7) /* Burnout current enable */
#define AD7192_CONF_REFDET BIT(6) /* Reference detect enable */
#define AD7192_CONF_BUF BIT(4) /* Buffered Mode Enable */
#define AD7192_CONF_UNIPOLAR BIT(3) /* Unipolar/Bipolar Enable */
-#define AD7192_CONF_GAIN(x) ((x) & 0x7) /* Gain Select */
+#define AD7192_CONF_GAIN_MASK GENMASK(2, 0) /* Gain Select */
#define AD7192_CH_AIN1P_AIN2M BIT(0) /* AIN1(+) - AIN2(-) */
#define AD7192_CH_AIN3P_AIN4M BIT(1) /* AIN3(+) - AIN4(-) */
@@ -130,7 +131,7 @@
#define CHIPID_AD7192 0x0
#define CHIPID_AD7193 0x2
#define CHIPID_AD7195 0x6
-#define AD7192_ID_MASK 0x0F
+#define AD7192_ID_MASK GENMASK(3, 0)
/* GPOCON Register Bit Designations (AD7192_REG_GPOCON) */
#define AD7192_GPOCON_BPDSW BIT(6) /* Bridge power-down switch enable */
@@ -172,6 +173,9 @@ enum {
struct ad7192_chip_info {
unsigned int chip_id;
const char *name;
+ const struct iio_chan_spec *channels;
+ u8 num_channels;
+ const struct iio_info *info;
};
struct ad7192_state {
@@ -181,10 +185,10 @@ struct ad7192_state {
struct clk *mclk;
u16 int_vref_mv;
u32 fclk;
- u32 f_order;
u32 mode;
u32 conf;
u32 scale_avail[8][2];
+ u32 oversampling_ratio_avail[4];
u8 gpocon;
u8 clock_sel;
struct mutex lock; /* protect sensor state */
@@ -273,7 +277,7 @@ static int ad7192_set_channel(struct ad_sigma_delta *sd, unsigned int channel)
struct ad7192_state *st = ad_sigma_delta_to_ad7192(sd);
st->conf &= ~AD7192_CONF_CHAN_MASK;
- st->conf |= AD7192_CONF_CHAN(channel);
+ st->conf |= FIELD_PREP(AD7192_CONF_CHAN_MASK, channel);
return ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, st->conf);
}
@@ -284,7 +288,7 @@ static int ad7192_set_mode(struct ad_sigma_delta *sd,
struct ad7192_state *st = ad_sigma_delta_to_ad7192(sd);
st->mode &= ~AD7192_MODE_SEL_MASK;
- st->mode |= AD7192_MODE_SEL(mode);
+ st->mode |= FIELD_PREP(AD7192_MODE_SEL_MASK, mode);
return ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
}
@@ -296,7 +300,7 @@ static int ad7192_append_status(struct ad_sigma_delta *sd, bool append)
int ret;
mode &= ~AD7192_MODE_STA_MASK;
- mode |= AD7192_MODE_STA(append);
+ mode |= FIELD_PREP(AD7192_MODE_STA_MASK, append);
ret = ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, mode);
if (ret < 0)
@@ -400,17 +404,17 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device_node *np)
if (ret)
return ret;
- id &= AD7192_ID_MASK;
+ id = FIELD_GET(AD7192_ID_MASK, id);
if (id != st->chip_info->chip_id)
dev_warn(&st->sd.spi->dev, "device ID query failed (0x%X != 0x%X)\n",
id, st->chip_info->chip_id);
- st->mode = AD7192_MODE_SEL(AD7192_MODE_IDLE) |
- AD7192_MODE_CLKSRC(st->clock_sel) |
- AD7192_MODE_RATE(480);
+ st->mode = FIELD_PREP(AD7192_MODE_SEL_MASK, AD7192_MODE_IDLE) |
+ FIELD_PREP(AD7192_MODE_CLKSRC_MASK, st->clock_sel) |
+ FIELD_PREP(AD7192_MODE_RATE_MASK, 480);
- st->conf = AD7192_CONF_GAIN(0);
+ st->conf = FIELD_PREP(AD7192_CONF_GAIN_MASK, 0);
rej60_en = of_property_read_bool(np, "adi,rejection-60-Hz-enable");
if (rej60_en)
@@ -421,7 +425,6 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device_node *np)
st->conf |= AD7192_CONF_REFSEL;
st->conf &= ~AD7192_CONF_CHOP;
- st->f_order = AD7192_NO_SYNC_FILTER;
buf_en = of_property_read_bool(np, "adi,buffer-enable");
if (buf_en)
@@ -456,13 +459,18 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device_node *np)
for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) {
scale_uv = ((u64)st->int_vref_mv * 100000000)
>> (indio_dev->channels[0].scan_type.realbits -
- ((st->conf & AD7192_CONF_UNIPOLAR) ? 0 : 1));
+ !FIELD_GET(AD7192_CONF_UNIPOLAR, st->conf));
scale_uv >>= i;
st->scale_avail[i][1] = do_div(scale_uv, 100000000) * 10;
st->scale_avail[i][0] = scale_uv;
}
+ st->oversampling_ratio_avail[0] = 1;
+ st->oversampling_ratio_avail[1] = 2;
+ st->oversampling_ratio_avail[2] = 8;
+ st->oversampling_ratio_avail[3] = 16;
+
return 0;
}
@@ -473,7 +481,7 @@ static ssize_t ad7192_show_ac_excitation(struct device *dev,
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7192_state *st = iio_priv(indio_dev);
- return sysfs_emit(buf, "%d\n", !!(st->conf & AD7192_CONF_ACX));
+ return sysfs_emit(buf, "%ld\n", FIELD_GET(AD7192_CONF_ACX, st->conf));
}
static ssize_t ad7192_show_bridge_switch(struct device *dev,
@@ -483,7 +491,8 @@ static ssize_t ad7192_show_bridge_switch(struct device *dev,
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7192_state *st = iio_priv(indio_dev);
- return sysfs_emit(buf, "%d\n", !!(st->gpocon & AD7192_GPOCON_BPDSW));
+ return sysfs_emit(buf, "%ld\n",
+ FIELD_GET(AD7192_GPOCON_BPDSW, st->gpocon));
}
static ssize_t ad7192_set(struct device *dev,
@@ -531,22 +540,66 @@ static ssize_t ad7192_set(struct device *dev,
return ret ? ret : len;
}
+static int ad7192_compute_f_order(struct ad7192_state *st, bool sinc3_en, bool chop_en)
+{
+ u8 avg_factor_selected, oversampling_ratio;
+
+ avg_factor_selected = FIELD_GET(AD7192_MODE_AVG_MASK, st->mode);
+
+ if (!avg_factor_selected && !chop_en)
+ return 1;
+
+ oversampling_ratio = st->oversampling_ratio_avail[avg_factor_selected];
+
+ if (sinc3_en)
+ return AD7192_SYNC3_FILTER + oversampling_ratio - 1;
+
+ return AD7192_SYNC4_FILTER + oversampling_ratio - 1;
+}
+
+static int ad7192_get_f_order(struct ad7192_state *st)
+{
+ bool sinc3_en, chop_en;
+
+ sinc3_en = FIELD_GET(AD7192_MODE_SINC3, st->mode);
+ chop_en = FIELD_GET(AD7192_CONF_CHOP, st->conf);
+
+ return ad7192_compute_f_order(st, sinc3_en, chop_en);
+}
+
+static int ad7192_compute_f_adc(struct ad7192_state *st, bool sinc3_en,
+ bool chop_en)
+{
+ unsigned int f_order = ad7192_compute_f_order(st, sinc3_en, chop_en);
+
+ return DIV_ROUND_CLOSEST(st->fclk,
+ f_order * FIELD_GET(AD7192_MODE_RATE_MASK, st->mode));
+}
+
+static int ad7192_get_f_adc(struct ad7192_state *st)
+{
+ unsigned int f_order = ad7192_get_f_order(st);
+
+ return DIV_ROUND_CLOSEST(st->fclk,
+ f_order * FIELD_GET(AD7192_MODE_RATE_MASK, st->mode));
+}
+
static void ad7192_get_available_filter_freq(struct ad7192_state *st,
int *freq)
{
unsigned int fadc;
/* Formulas for filter at page 25 of the datasheet */
- fadc = DIV_ROUND_CLOSEST(st->fclk,
- AD7192_SYNC4_FILTER * AD7192_MODE_RATE(st->mode));
+ fadc = ad7192_compute_f_adc(st, false, true);
freq[0] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
- fadc = DIV_ROUND_CLOSEST(st->fclk,
- AD7192_SYNC3_FILTER * AD7192_MODE_RATE(st->mode));
+ fadc = ad7192_compute_f_adc(st, true, true);
freq[1] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
- fadc = DIV_ROUND_CLOSEST(st->fclk, AD7192_MODE_RATE(st->mode));
+ fadc = ad7192_compute_f_adc(st, false, false);
freq[2] = DIV_ROUND_CLOSEST(fadc * 230, 1024);
+
+ fadc = ad7192_compute_f_adc(st, true, false);
freq[3] = DIV_ROUND_CLOSEST(fadc * 272, 1024);
}
@@ -629,25 +682,21 @@ static int ad7192_set_3db_filter_freq(struct ad7192_state *st,
switch (idx) {
case 0:
- st->f_order = AD7192_SYNC4_FILTER;
st->mode &= ~AD7192_MODE_SINC3;
st->conf |= AD7192_CONF_CHOP;
break;
case 1:
- st->f_order = AD7192_SYNC3_FILTER;
st->mode |= AD7192_MODE_SINC3;
st->conf |= AD7192_CONF_CHOP;
break;
case 2:
- st->f_order = AD7192_NO_SYNC_FILTER;
st->mode &= ~AD7192_MODE_SINC3;
st->conf &= ~AD7192_CONF_CHOP;
break;
case 3:
- st->f_order = AD7192_NO_SYNC_FILTER;
st->mode |= AD7192_MODE_SINC3;
st->conf &= ~AD7192_CONF_CHOP;
@@ -665,12 +714,11 @@ static int ad7192_get_3db_filter_freq(struct ad7192_state *st)
{
unsigned int fadc;
- fadc = DIV_ROUND_CLOSEST(st->fclk,
- st->f_order * AD7192_MODE_RATE(st->mode));
+ fadc = ad7192_get_f_adc(st);
- if (st->conf & AD7192_CONF_CHOP)
+ if (FIELD_GET(AD7192_CONF_CHOP, st->conf))
return DIV_ROUND_CLOSEST(fadc * 240, 1024);
- if (st->mode & AD7192_MODE_SINC3)
+ if (FIELD_GET(AD7192_MODE_SINC3, st->mode))
return DIV_ROUND_CLOSEST(fadc * 272, 1024);
else
return DIV_ROUND_CLOSEST(fadc * 230, 1024);
@@ -683,7 +731,8 @@ static int ad7192_read_raw(struct iio_dev *indio_dev,
long m)
{
struct ad7192_state *st = iio_priv(indio_dev);
- bool unipolar = !!(st->conf & AD7192_CONF_UNIPOLAR);
+ bool unipolar = FIELD_GET(AD7192_CONF_UNIPOLAR, st->conf);
+ u8 gain = FIELD_GET(AD7192_CONF_GAIN_MASK, st->conf);
switch (m) {
case IIO_CHAN_INFO_RAW:
@@ -692,8 +741,8 @@ static int ad7192_read_raw(struct iio_dev *indio_dev,
switch (chan->type) {
case IIO_VOLTAGE:
mutex_lock(&st->lock);
- *val = st->scale_avail[AD7192_CONF_GAIN(st->conf)][0];
- *val2 = st->scale_avail[AD7192_CONF_GAIN(st->conf)][1];
+ *val = st->scale_avail[gain][0];
+ *val2 = st->scale_avail[gain][1];
mutex_unlock(&st->lock);
return IIO_VAL_INT_PLUS_NANO;
case IIO_TEMP:
@@ -713,13 +762,15 @@ static int ad7192_read_raw(struct iio_dev *indio_dev,
*val -= 273 * ad7192_get_temp_scale(unipolar);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SAMP_FREQ:
- *val = st->fclk /
- (st->f_order * 1024 * AD7192_MODE_RATE(st->mode));
+ *val = DIV_ROUND_CLOSEST(ad7192_get_f_adc(st), 1024);
return IIO_VAL_INT;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
*val = ad7192_get_3db_filter_freq(st);
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *val = st->oversampling_ratio_avail[FIELD_GET(AD7192_MODE_AVG_MASK, st->mode)];
+ return IIO_VAL_INT;
}
return -EINVAL;
@@ -747,8 +798,8 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
if (val2 == st->scale_avail[i][1]) {
ret = 0;
tmp = st->conf;
- st->conf &= ~AD7192_CONF_GAIN(-1);
- st->conf |= AD7192_CONF_GAIN(i);
+ st->conf &= ~AD7192_CONF_GAIN_MASK;
+ st->conf |= FIELD_PREP(AD7192_CONF_GAIN_MASK, i);
if (tmp == st->conf)
break;
ad_sd_write_reg(&st->sd, AD7192_REG_CONF,
@@ -764,19 +815,36 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
break;
}
- div = st->fclk / (val * st->f_order * 1024);
+ div = st->fclk / (val * ad7192_get_f_order(st) * 1024);
if (div < 1 || div > 1023) {
ret = -EINVAL;
break;
}
- st->mode &= ~AD7192_MODE_RATE(-1);
- st->mode |= AD7192_MODE_RATE(div);
+ st->mode &= ~AD7192_MODE_RATE_MASK;
+ st->mode |= FIELD_PREP(AD7192_MODE_RATE_MASK, div);
ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
break;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
ret = ad7192_set_3db_filter_freq(st, val, val2 / 1000);
break;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ ret = -EINVAL;
+ mutex_lock(&st->lock);
+ for (i = 0; i < ARRAY_SIZE(st->oversampling_ratio_avail); i++)
+ if (val == st->oversampling_ratio_avail[i]) {
+ ret = 0;
+ tmp = st->mode;
+ st->mode &= ~AD7192_MODE_AVG_MASK;
+ st->mode |= FIELD_PREP(AD7192_MODE_AVG_MASK, i);
+ if (tmp == st->mode)
+ break;
+ ad_sd_write_reg(&st->sd, AD7192_REG_MODE,
+ 3, st->mode);
+ break;
+ }
+ mutex_unlock(&st->lock);
+ break;
default:
ret = -EINVAL;
}
@@ -797,6 +865,8 @@ static int ad7192_write_raw_get_fmt(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ return IIO_VAL_INT;
default:
return -EINVAL;
}
@@ -817,6 +887,12 @@ static int ad7192_read_avail(struct iio_dev *indio_dev,
*length = ARRAY_SIZE(st->scale_avail) * 2;
return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *vals = (int *)st->oversampling_ratio_avail;
+ *type = IIO_VAL_INT;
+ *length = ARRAY_SIZE(st->oversampling_ratio_avail);
+
+ return IIO_AVAIL_LIST;
}
return -EINVAL;
@@ -831,7 +907,7 @@ static int ad7192_update_scan_mode(struct iio_dev *indio_dev, const unsigned lon
conf &= ~AD7192_CONF_CHAN_MASK;
for_each_set_bit(i, scan_mask, 8)
- conf |= AD7192_CONF_CHAN(i);
+ conf |= FIELD_PREP(AD7192_CONF_CHAN_MASK, i);
ret = ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, conf);
if (ret < 0)
@@ -862,8 +938,8 @@ static const struct iio_info ad7195_info = {
.update_scan_mode = ad7192_update_scan_mode,
};
-#define __AD719x_CHANNEL(_si, _channel1, _channel2, _address, _extend_name, \
- _type, _mask_type_av, _ext_info) \
+#define __AD719x_CHANNEL(_si, _channel1, _channel2, _address, _type, \
+ _mask_all, _mask_type_av, _mask_all_av, _ext_info) \
{ \
.type = (_type), \
.differential = ((_channel2) == -1 ? 0 : 1), \
@@ -871,13 +947,14 @@ static const struct iio_info ad7195_info = {
.channel = (_channel1), \
.channel2 = (_channel2), \
.address = (_address), \
- .extend_name = (_extend_name), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_OFFSET), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
- BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
+ (_mask_all), \
.info_mask_shared_by_type_available = (_mask_type_av), \
+ .info_mask_shared_by_all_available = (_mask_all_av), \
.ext_info = (_ext_info), \
.scan_index = (_si), \
.scan_type = { \
@@ -889,16 +966,26 @@ static const struct iio_info ad7195_info = {
}
#define AD719x_DIFF_CHANNEL(_si, _channel1, _channel2, _address) \
- __AD719x_CHANNEL(_si, _channel1, _channel2, _address, NULL, \
- IIO_VOLTAGE, BIT(IIO_CHAN_INFO_SCALE), \
- ad7192_calibsys_ext_info)
+ __AD719x_CHANNEL(_si, _channel1, _channel2, _address, IIO_VOLTAGE, 0, \
+ BIT(IIO_CHAN_INFO_SCALE), 0, ad7192_calibsys_ext_info)
#define AD719x_CHANNEL(_si, _channel1, _address) \
- __AD719x_CHANNEL(_si, _channel1, -1, _address, NULL, IIO_VOLTAGE, \
- BIT(IIO_CHAN_INFO_SCALE), ad7192_calibsys_ext_info)
+ __AD719x_CHANNEL(_si, _channel1, -1, _address, IIO_VOLTAGE, 0, \
+ BIT(IIO_CHAN_INFO_SCALE), 0, ad7192_calibsys_ext_info)
#define AD719x_TEMP_CHANNEL(_si, _address) \
- __AD719x_CHANNEL(_si, 0, -1, _address, NULL, IIO_TEMP, 0, NULL)
+ __AD719x_CHANNEL(_si, 0, -1, _address, IIO_TEMP, 0, 0, 0, NULL)
+
+#define AD7193_DIFF_CHANNEL(_si, _channel1, _channel2, _address) \
+ __AD719x_CHANNEL(_si, _channel1, _channel2, _address, \
+ IIO_VOLTAGE, \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ ad7192_calibsys_ext_info)
+
+#define AD7193_CHANNEL(_si, _channel1, _address) \
+ AD7193_DIFF_CHANNEL(_si, _channel1, -1, _address)
static const struct iio_chan_spec ad7192_channels[] = {
AD719x_DIFF_CHANNEL(0, 1, 2, AD7192_CH_AIN1P_AIN2M),
@@ -913,20 +1000,20 @@ static const struct iio_chan_spec ad7192_channels[] = {
};
static const struct iio_chan_spec ad7193_channels[] = {
- AD719x_DIFF_CHANNEL(0, 1, 2, AD7193_CH_AIN1P_AIN2M),
- AD719x_DIFF_CHANNEL(1, 3, 4, AD7193_CH_AIN3P_AIN4M),
- AD719x_DIFF_CHANNEL(2, 5, 6, AD7193_CH_AIN5P_AIN6M),
- AD719x_DIFF_CHANNEL(3, 7, 8, AD7193_CH_AIN7P_AIN8M),
+ AD7193_DIFF_CHANNEL(0, 1, 2, AD7193_CH_AIN1P_AIN2M),
+ AD7193_DIFF_CHANNEL(1, 3, 4, AD7193_CH_AIN3P_AIN4M),
+ AD7193_DIFF_CHANNEL(2, 5, 6, AD7193_CH_AIN5P_AIN6M),
+ AD7193_DIFF_CHANNEL(3, 7, 8, AD7193_CH_AIN7P_AIN8M),
AD719x_TEMP_CHANNEL(4, AD7193_CH_TEMP),
- AD719x_DIFF_CHANNEL(5, 2, 2, AD7193_CH_AIN2P_AIN2M),
- AD719x_CHANNEL(6, 1, AD7193_CH_AIN1),
- AD719x_CHANNEL(7, 2, AD7193_CH_AIN2),
- AD719x_CHANNEL(8, 3, AD7193_CH_AIN3),
- AD719x_CHANNEL(9, 4, AD7193_CH_AIN4),
- AD719x_CHANNEL(10, 5, AD7193_CH_AIN5),
- AD719x_CHANNEL(11, 6, AD7193_CH_AIN6),
- AD719x_CHANNEL(12, 7, AD7193_CH_AIN7),
- AD719x_CHANNEL(13, 8, AD7193_CH_AIN8),
+ AD7193_DIFF_CHANNEL(5, 2, 2, AD7193_CH_AIN2P_AIN2M),
+ AD7193_CHANNEL(6, 1, AD7193_CH_AIN1),
+ AD7193_CHANNEL(7, 2, AD7193_CH_AIN2),
+ AD7193_CHANNEL(8, 3, AD7193_CH_AIN3),
+ AD7193_CHANNEL(9, 4, AD7193_CH_AIN4),
+ AD7193_CHANNEL(10, 5, AD7193_CH_AIN5),
+ AD7193_CHANNEL(11, 6, AD7193_CH_AIN6),
+ AD7193_CHANNEL(12, 7, AD7193_CH_AIN7),
+ AD7193_CHANNEL(13, 8, AD7193_CH_AIN8),
IIO_CHAN_SOFT_TIMESTAMP(14),
};
@@ -934,39 +1021,33 @@ static const struct ad7192_chip_info ad7192_chip_info_tbl[] = {
[ID_AD7190] = {
.chip_id = CHIPID_AD7190,
.name = "ad7190",
+ .channels = ad7192_channels,
+ .num_channels = ARRAY_SIZE(ad7192_channels),
+ .info = &ad7192_info,
},
[ID_AD7192] = {
.chip_id = CHIPID_AD7192,
.name = "ad7192",
+ .channels = ad7192_channels,
+ .num_channels = ARRAY_SIZE(ad7192_channels),
+ .info = &ad7192_info,
},
[ID_AD7193] = {
.chip_id = CHIPID_AD7193,
.name = "ad7193",
+ .channels = ad7193_channels,
+ .num_channels = ARRAY_SIZE(ad7193_channels),
+ .info = &ad7192_info,
},
[ID_AD7195] = {
.chip_id = CHIPID_AD7195,
.name = "ad7195",
+ .channels = ad7192_channels,
+ .num_channels = ARRAY_SIZE(ad7192_channels),
+ .info = &ad7195_info,
},
};
-static int ad7192_channels_config(struct iio_dev *indio_dev)
-{
- struct ad7192_state *st = iio_priv(indio_dev);
-
- switch (st->chip_info->chip_id) {
- case CHIPID_AD7193:
- indio_dev->channels = ad7193_channels;
- indio_dev->num_channels = ARRAY_SIZE(ad7193_channels);
- break;
- default:
- indio_dev->channels = ad7192_channels;
- indio_dev->num_channels = ARRAY_SIZE(ad7192_channels);
- break;
- }
-
- return 0;
-}
-
static void ad7192_reg_disable(void *reg)
{
regulator_disable(reg);
@@ -1041,15 +1122,9 @@ static int ad7192_probe(struct spi_device *spi)
st->chip_info = (void *)spi_get_device_id(spi)->driver_data;
indio_dev->name = st->chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
-
- ret = ad7192_channels_config(indio_dev);
- if (ret < 0)
- return ret;
-
- if (st->chip_info->chip_id == CHIPID_AD7195)
- indio_dev->info = &ad7195_info;
- else
- indio_dev->info = &ad7192_info;
+ indio_dev->channels = st->chip_info->channels;
+ indio_dev->num_channels = st->chip_info->num_channels;
+ indio_dev->info = st->chip_info->info;
ret = ad_sd_init(&st->sd, indio_dev, spi, &ad7192_sigma_delta_info);
if (ret)
diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
index df67b63ccf..d7fd21e7c6 100644
--- a/drivers/iio/adc/at91-sama5d2_adc.c
+++ b/drivers/iio/adc/at91-sama5d2_adc.c
@@ -2486,7 +2486,7 @@ reg_disable:
return ret;
}
-static int at91_adc_remove(struct platform_device *pdev)
+static void at91_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct at91_adc_state *st = iio_priv(indio_dev);
@@ -2501,8 +2501,6 @@ static int at91_adc_remove(struct platform_device *pdev)
regulator_disable(st->vref);
regulator_disable(st->reg);
-
- return 0;
}
static int at91_adc_suspend(struct device *dev)
@@ -2627,7 +2625,7 @@ MODULE_DEVICE_TABLE(of, at91_adc_dt_match);
static struct platform_driver at91_adc_driver = {
.probe = at91_adc_probe,
- .remove = at91_adc_remove,
+ .remove_new = at91_adc_remove,
.driver = {
.name = "at91-sama5d2_adc",
.of_match_table = at91_adc_dt_match,
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index de6650f9c4..eb501e3c86 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -1013,28 +1013,25 @@ static int at91_adc_probe(struct platform_device *pdev)
st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
- if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
- dev_err(&idev->dev, "Missing adc-channels-used property in the DT.\n");
- return -EINVAL;
- }
+ if (of_property_read_u32(node, "atmel,adc-channels-used", &prop))
+ return dev_err_probe(&idev->dev, -EINVAL,
+ "Missing adc-channels-used property in the DT.\n");
st->channels_mask = prop;
st->sleep_mode = of_property_read_bool(node, "atmel,adc-sleep-mode");
- if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) {
- dev_err(&idev->dev, "Missing adc-startup-time property in the DT.\n");
- return -EINVAL;
- }
+ if (of_property_read_u32(node, "atmel,adc-startup-time", &prop))
+ return dev_err_probe(&idev->dev, -EINVAL,
+ "Missing adc-startup-time property in the DT.\n");
st->startup_time = prop;
prop = 0;
of_property_read_u32(node, "atmel,adc-sample-hold-time", &prop);
st->sample_hold_time = prop;
- if (of_property_read_u32(node, "atmel,adc-vref", &prop)) {
- dev_err(&idev->dev, "Missing adc-vref property in the DT.\n");
- return -EINVAL;
- }
+ if (of_property_read_u32(node, "atmel,adc-vref", &prop))
+ return dev_err_probe(&idev->dev, -EINVAL,
+ "Missing adc-vref property in the DT.\n");
st->vref_mv = prop;
st->res = st->caps->high_res_bits;
@@ -1069,7 +1066,6 @@ static int at91_adc_probe(struct platform_device *pdev)
if (IS_ERR(st->reg_base))
return PTR_ERR(st->reg_base);
-
/*
* Disable all IRQs before setting up the handler
*/
@@ -1077,43 +1073,26 @@ static int at91_adc_probe(struct platform_device *pdev)
at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF);
if (st->caps->has_tsmr)
- ret = request_irq(st->irq, at91_adc_9x5_interrupt, 0,
- pdev->dev.driver->name, idev);
+ ret = devm_request_irq(&pdev->dev, st->irq,
+ at91_adc_9x5_interrupt, 0,
+ pdev->dev.driver->name, idev);
else
- ret = request_irq(st->irq, at91_adc_rl_interrupt, 0,
- pdev->dev.driver->name, idev);
- if (ret) {
- dev_err(&pdev->dev, "Failed to allocate IRQ.\n");
- return ret;
- }
-
- st->clk = devm_clk_get(&pdev->dev, "adc_clk");
- if (IS_ERR(st->clk)) {
- dev_err(&pdev->dev, "Failed to get the clock.\n");
- ret = PTR_ERR(st->clk);
- goto error_free_irq;
- }
-
- ret = clk_prepare_enable(st->clk);
- if (ret) {
- dev_err(&pdev->dev,
- "Could not prepare or enable the clock.\n");
- goto error_free_irq;
- }
+ ret = devm_request_irq(&pdev->dev, st->irq,
+ at91_adc_rl_interrupt, 0,
+ pdev->dev.driver->name, idev);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to allocate IRQ.\n");
- st->adc_clk = devm_clk_get(&pdev->dev, "adc_op_clk");
- if (IS_ERR(st->adc_clk)) {
- dev_err(&pdev->dev, "Failed to get the ADC clock.\n");
- ret = PTR_ERR(st->adc_clk);
- goto error_disable_clk;
- }
+ st->clk = devm_clk_get_enabled(&pdev->dev, "adc_clk");
+ if (IS_ERR(st->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(st->clk),
+ "Could not prepare or enable the clock.\n");
- ret = clk_prepare_enable(st->adc_clk);
- if (ret) {
- dev_err(&pdev->dev,
- "Could not prepare or enable the ADC clock.\n");
- goto error_disable_clk;
- }
+ st->adc_clk = devm_clk_get_enabled(&pdev->dev, "adc_op_clk");
+ if (IS_ERR(st->adc_clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(st->adc_clk),
+ "Could not prepare or enable the ADC clock.\n");
/*
* Prescaler rate computation using the formula from the Atmel's
@@ -1129,11 +1108,9 @@ static int at91_adc_probe(struct platform_device *pdev)
prsc = (mstrclk / (2 * adc_clk)) - 1;
- if (!st->startup_time) {
- dev_err(&pdev->dev, "No startup time available.\n");
- ret = -EINVAL;
- goto error_disable_adc_clk;
- }
+ if (!st->startup_time)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "No startup time available.\n");
ticks = (*st->caps->calc_startup_ticks)(st->startup_time, adc_clk_khz);
/*
@@ -1158,10 +1135,9 @@ static int at91_adc_probe(struct platform_device *pdev)
/* Setup the ADC channels available on the board */
ret = at91_adc_channel_init(idev);
- if (ret < 0) {
- dev_err(&pdev->dev, "Couldn't initialize the channels.\n");
- goto error_disable_adc_clk;
- }
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret,
+ "Couldn't initialize the channels.\n");
init_waitqueue_head(&st->wq_data_avail);
mutex_init(&st->lock);
@@ -1173,21 +1149,20 @@ static int at91_adc_probe(struct platform_device *pdev)
*/
if (!st->touchscreen_type) {
ret = at91_adc_buffer_init(idev);
- if (ret < 0) {
- dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
- goto error_disable_adc_clk;
- }
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret,
+ "Couldn't initialize the buffer.\n");
ret = at91_adc_trigger_init(idev);
if (ret < 0) {
dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
at91_adc_buffer_remove(idev);
- goto error_disable_adc_clk;
+ return ret;
}
} else {
ret = at91_ts_register(idev, pdev);
if (ret)
- goto error_disable_adc_clk;
+ return ret;
at91_ts_hw_init(idev, adc_clk_khz);
}
@@ -1207,16 +1182,10 @@ error_iio_device_register:
} else {
at91_ts_unregister(st);
}
-error_disable_adc_clk:
- clk_disable_unprepare(st->adc_clk);
-error_disable_clk:
- clk_disable_unprepare(st->clk);
-error_free_irq:
- free_irq(st->irq, idev);
return ret;
}
-static int at91_adc_remove(struct platform_device *pdev)
+static void at91_adc_remove(struct platform_device *pdev)
{
struct iio_dev *idev = platform_get_drvdata(pdev);
struct at91_adc_state *st = iio_priv(idev);
@@ -1228,11 +1197,6 @@ static int at91_adc_remove(struct platform_device *pdev)
} else {
at91_ts_unregister(st);
}
- clk_disable_unprepare(st->adc_clk);
- clk_disable_unprepare(st->clk);
- free_irq(st->irq, idev);
-
- return 0;
}
static int at91_adc_suspend(struct device *dev)
@@ -1382,7 +1346,7 @@ MODULE_DEVICE_TABLE(of, at91_adc_dt_ids);
static struct platform_driver at91_adc_driver = {
.probe = at91_adc_probe,
- .remove = at91_adc_remove,
+ .remove_new = at91_adc_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = at91_adc_dt_ids,
diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
index 75bda94dbc..d6c51b0f48 100644
--- a/drivers/iio/adc/axp20x_adc.c
+++ b/drivers/iio/adc/axp20x_adc.c
@@ -745,7 +745,7 @@ fail_map:
return ret;
}
-static int axp20x_remove(struct platform_device *pdev)
+static void axp20x_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct axp20x_adc_iio *info = iio_priv(indio_dev);
@@ -757,8 +757,6 @@ static int axp20x_remove(struct platform_device *pdev)
if (info->data->adc_en2_mask)
regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
-
- return 0;
}
static struct platform_driver axp20x_adc_driver = {
@@ -768,7 +766,7 @@ static struct platform_driver axp20x_adc_driver = {
},
.id_table = axp20x_adc_id_match,
.probe = axp20x_probe,
- .remove = axp20x_remove,
+ .remove_new = axp20x_remove,
};
module_platform_driver(axp20x_adc_driver);
diff --git a/drivers/iio/adc/bcm_iproc_adc.c b/drivers/iio/adc/bcm_iproc_adc.c
index 0d6885413a..5bc514bd5e 100644
--- a/drivers/iio/adc/bcm_iproc_adc.c
+++ b/drivers/iio/adc/bcm_iproc_adc.c
@@ -594,7 +594,7 @@ err_adc_enable:
return ret;
}
-static int iproc_adc_remove(struct platform_device *pdev)
+static void iproc_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct iproc_adc_priv *adc_priv = iio_priv(indio_dev);
@@ -602,8 +602,6 @@ static int iproc_adc_remove(struct platform_device *pdev)
iio_device_unregister(indio_dev);
iproc_adc_disable(indio_dev);
clk_disable_unprepare(adc_priv->adc_clk);
-
- return 0;
}
static const struct of_device_id iproc_adc_of_match[] = {
@@ -614,7 +612,7 @@ MODULE_DEVICE_TABLE(of, iproc_adc_of_match);
static struct platform_driver iproc_adc_driver = {
.probe = iproc_adc_probe,
- .remove = iproc_adc_remove,
+ .remove_new = iproc_adc_remove,
.driver = {
.name = "iproc-static-adc",
.of_match_table = iproc_adc_of_match,
diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c
index 97d162a3cb..06cfbbabaf 100644
--- a/drivers/iio/adc/dln2-adc.c
+++ b/drivers/iio/adc/dln2-adc.c
@@ -691,19 +691,18 @@ unregister_event:
return ret;
}
-static int dln2_adc_remove(struct platform_device *pdev)
+static void dln2_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
iio_device_unregister(indio_dev);
dln2_unregister_event_cb(pdev, DLN2_ADC_CONDITION_MET_EV);
- return 0;
}
static struct platform_driver dln2_adc_driver = {
.driver.name = DLN2_ADC_MOD_NAME,
.probe = dln2_adc_probe,
- .remove = dln2_adc_remove,
+ .remove_new = dln2_adc_remove,
};
module_platform_driver(dln2_adc_driver);
diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c
index a35e6cead6..971942ce4c 100644
--- a/drivers/iio/adc/ep93xx_adc.c
+++ b/drivers/iio/adc/ep93xx_adc.c
@@ -217,15 +217,13 @@ static int ep93xx_adc_probe(struct platform_device *pdev)
return ret;
}
-static int ep93xx_adc_remove(struct platform_device *pdev)
+static void ep93xx_adc_remove(struct platform_device *pdev)
{
struct iio_dev *iiodev = platform_get_drvdata(pdev);
struct ep93xx_adc_priv *priv = iio_priv(iiodev);
iio_device_unregister(iiodev);
clk_disable_unprepare(priv->clk);
-
- return 0;
}
static const struct of_device_id ep93xx_adc_of_ids[] = {
@@ -240,7 +238,7 @@ static struct platform_driver ep93xx_adc_driver = {
.of_match_table = ep93xx_adc_of_ids,
},
.probe = ep93xx_adc_probe,
- .remove = ep93xx_adc_remove,
+ .remove_new = ep93xx_adc_remove,
};
module_platform_driver(ep93xx_adc_driver);
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index 43c8af41b4..614de96448 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -950,7 +950,7 @@ err_disable_reg:
return ret;
}
-static int exynos_adc_remove(struct platform_device *pdev)
+static void exynos_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct exynos_adc *info = iio_priv(indio_dev);
@@ -968,8 +968,6 @@ static int exynos_adc_remove(struct platform_device *pdev)
exynos_adc_disable_clk(info);
exynos_adc_unprepare_clk(info);
regulator_disable(info->vdd);
-
- return 0;
}
static int exynos_adc_suspend(struct device *dev)
@@ -1010,7 +1008,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(exynos_adc_pm_ops, exynos_adc_suspend,
static struct platform_driver exynos_adc_driver = {
.probe = exynos_adc_probe,
- .remove = exynos_adc_remove,
+ .remove_new = exynos_adc_remove,
.driver = {
.name = "exynos-adc",
.of_match_table = exynos_adc_match,
diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c
index 551e83ae57..68c813de06 100644
--- a/drivers/iio/adc/fsl-imx25-gcq.c
+++ b/drivers/iio/adc/fsl-imx25-gcq.c
@@ -384,7 +384,7 @@ err_regulator_disable:
return ret;
}
-static int mx25_gcq_remove(struct platform_device *pdev)
+static void mx25_gcq_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct mx25_gcq_priv *priv = iio_priv(indio_dev);
@@ -397,8 +397,6 @@ static int mx25_gcq_remove(struct platform_device *pdev)
if (priv->vref[i])
regulator_disable(priv->vref[i]);
}
-
- return 0;
}
static const struct of_device_id mx25_gcq_ids[] = {
@@ -413,7 +411,7 @@ static struct platform_driver mx25_gcq_driver = {
.of_match_table = mx25_gcq_ids,
},
.probe = mx25_gcq_probe,
- .remove = mx25_gcq_remove,
+ .remove_new = mx25_gcq_remove,
};
module_platform_driver(mx25_gcq_driver);
diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c
index f7ee856a6b..c80c55fb8c 100644
--- a/drivers/iio/adc/hx711.c
+++ b/drivers/iio/adc/hx711.c
@@ -580,7 +580,7 @@ error_regulator:
return ret;
}
-static int hx711_remove(struct platform_device *pdev)
+static void hx711_remove(struct platform_device *pdev)
{
struct hx711_data *hx711_data;
struct iio_dev *indio_dev;
@@ -593,8 +593,6 @@ static int hx711_remove(struct platform_device *pdev)
iio_triggered_buffer_cleanup(indio_dev);
regulator_disable(hx711_data->reg_avdd);
-
- return 0;
}
static const struct of_device_id of_hx711_match[] = {
@@ -606,7 +604,7 @@ MODULE_DEVICE_TABLE(of, of_hx711_match);
static struct platform_driver hx711_driver = {
.probe = hx711_probe,
- .remove = hx711_remove,
+ .remove_new = hx711_remove,
.driver = {
.name = "hx711-gpio",
.of_match_table = of_hx711_match,
diff --git a/drivers/iio/adc/imx8qxp-adc.c b/drivers/iio/adc/imx8qxp-adc.c
index fff6e5a2d9..fe82198170 100644
--- a/drivers/iio/adc/imx8qxp-adc.c
+++ b/drivers/iio/adc/imx8qxp-adc.c
@@ -404,7 +404,7 @@ error_regulator_disable:
return ret;
}
-static int imx8qxp_adc_remove(struct platform_device *pdev)
+static void imx8qxp_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct imx8qxp_adc *adc = iio_priv(indio_dev);
@@ -422,8 +422,6 @@ static int imx8qxp_adc_remove(struct platform_device *pdev)
pm_runtime_disable(dev);
pm_runtime_put_noidle(dev);
-
- return 0;
}
static int imx8qxp_adc_runtime_suspend(struct device *dev)
@@ -489,7 +487,7 @@ MODULE_DEVICE_TABLE(of, imx8qxp_adc_match);
static struct platform_driver imx8qxp_adc_driver = {
.probe = imx8qxp_adc_probe,
- .remove = imx8qxp_adc_remove,
+ .remove_new = imx8qxp_adc_remove,
.driver = {
.name = ADC_DRIVER_NAME,
.of_match_table = imx8qxp_adc_match,
diff --git a/drivers/iio/adc/imx93_adc.c b/drivers/iio/adc/imx93_adc.c
index 512d7b95b0..4ccf4819f1 100644
--- a/drivers/iio/adc/imx93_adc.c
+++ b/drivers/iio/adc/imx93_adc.c
@@ -396,7 +396,7 @@ error_regulator_disable:
return ret;
}
-static int imx93_adc_remove(struct platform_device *pdev)
+static void imx93_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct imx93_adc *adc = iio_priv(indio_dev);
@@ -414,8 +414,6 @@ static int imx93_adc_remove(struct platform_device *pdev)
free_irq(adc->irq, adc);
clk_disable_unprepare(adc->ipg_clk);
regulator_disable(adc->vref);
-
- return 0;
}
static int imx93_adc_runtime_suspend(struct device *dev)
@@ -472,7 +470,7 @@ MODULE_DEVICE_TABLE(of, imx93_adc_match);
static struct platform_driver imx93_adc_driver = {
.probe = imx93_adc_probe,
- .remove = imx93_adc_remove,
+ .remove_new = imx93_adc_remove,
.driver = {
.name = IMX93_ADC_DRIVER_NAME,
.of_match_table = imx93_adc_match,
diff --git a/drivers/iio/adc/ltc2309.c b/drivers/iio/adc/ltc2309.c
new file mode 100644
index 0000000000..8b3a89c1b8
--- /dev/null
+++ b/drivers/iio/adc/ltc2309.c
@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The LTC2309 is an 8-Channel, 12-Bit SAR ADC with an I2C Interface.
+ *
+ * Datasheet:
+ * https://www.analog.com/media/en/technical-documentation/data-sheets/2309fd.pdf
+ *
+ * Copyright (c) 2023, Liam Beguin <liambeguin@gmail.com>
+ */
+#include <linux/bitfield.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regulator/consumer.h>
+
+#define LTC2309_ADC_RESOLUTION 12
+
+#define LTC2309_DIN_CH_MASK GENMASK(7, 4)
+#define LTC2309_DIN_SDN BIT(7)
+#define LTC2309_DIN_OSN BIT(6)
+#define LTC2309_DIN_S1 BIT(5)
+#define LTC2309_DIN_S0 BIT(4)
+#define LTC2309_DIN_UNI BIT(3)
+#define LTC2309_DIN_SLEEP BIT(2)
+
+/**
+ * struct ltc2309 - internal device data structure
+ * @dev: Device reference
+ * @client: I2C reference
+ * @vref: External reference source
+ * @lock: Lock to serialize data access
+ * @vref_mv: Internal voltage reference
+ */
+struct ltc2309 {
+ struct device *dev;
+ struct i2c_client *client;
+ struct regulator *vref;
+ struct mutex lock; /* serialize data access */
+ int vref_mv;
+};
+
+/* Order matches expected channel address, See datasheet Table 1. */
+enum ltc2309_channels {
+ LTC2309_CH0_CH1 = 0,
+ LTC2309_CH2_CH3,
+ LTC2309_CH4_CH5,
+ LTC2309_CH6_CH7,
+ LTC2309_CH1_CH0,
+ LTC2309_CH3_CH2,
+ LTC2309_CH5_CH4,
+ LTC2309_CH7_CH6,
+ LTC2309_CH0,
+ LTC2309_CH2,
+ LTC2309_CH4,
+ LTC2309_CH6,
+ LTC2309_CH1,
+ LTC2309_CH3,
+ LTC2309_CH5,
+ LTC2309_CH7,
+};
+
+#define LTC2309_CHAN(_chan, _addr) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .address = _addr, \
+ .channel = _chan, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+}
+
+#define LTC2309_DIFF_CHAN(_chan, _chan2, _addr) { \
+ .type = IIO_VOLTAGE, \
+ .differential = 1, \
+ .indexed = 1, \
+ .address = _addr, \
+ .channel = _chan, \
+ .channel2 = _chan2, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+}
+
+static const struct iio_chan_spec ltc2309_channels[] = {
+ LTC2309_CHAN(0, LTC2309_CH0),
+ LTC2309_CHAN(1, LTC2309_CH1),
+ LTC2309_CHAN(2, LTC2309_CH2),
+ LTC2309_CHAN(3, LTC2309_CH3),
+ LTC2309_CHAN(4, LTC2309_CH4),
+ LTC2309_CHAN(5, LTC2309_CH5),
+ LTC2309_CHAN(6, LTC2309_CH6),
+ LTC2309_CHAN(7, LTC2309_CH7),
+ LTC2309_DIFF_CHAN(0, 1, LTC2309_CH0_CH1),
+ LTC2309_DIFF_CHAN(2, 3, LTC2309_CH2_CH3),
+ LTC2309_DIFF_CHAN(4, 5, LTC2309_CH4_CH5),
+ LTC2309_DIFF_CHAN(6, 7, LTC2309_CH6_CH7),
+ LTC2309_DIFF_CHAN(1, 0, LTC2309_CH1_CH0),
+ LTC2309_DIFF_CHAN(3, 2, LTC2309_CH3_CH2),
+ LTC2309_DIFF_CHAN(5, 4, LTC2309_CH5_CH4),
+ LTC2309_DIFF_CHAN(7, 6, LTC2309_CH7_CH6),
+};
+
+static int ltc2309_read_raw_channel(struct ltc2309 *ltc2309,
+ unsigned long address, int *val)
+{
+ int ret;
+ u16 buf;
+ u8 din;
+
+ din = FIELD_PREP(LTC2309_DIN_CH_MASK, address & 0x0f) |
+ FIELD_PREP(LTC2309_DIN_UNI, 1) |
+ FIELD_PREP(LTC2309_DIN_SLEEP, 0);
+
+ ret = i2c_smbus_write_byte(ltc2309->client, din);
+ if (ret < 0) {
+ dev_err(ltc2309->dev, "i2c command failed: %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+
+ ret = i2c_master_recv(ltc2309->client, (char *)&buf, 2);
+ if (ret < 0) {
+ dev_err(ltc2309->dev, "i2c read failed: %pe\n", ERR_PTR(ret));
+ return ret;
+ }
+
+ *val = be16_to_cpu(buf) >> 4;
+
+ return ret;
+}
+
+static int ltc2309_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct ltc2309 *ltc2309 = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&ltc2309->lock);
+ ret = ltc2309_read_raw_channel(ltc2309, chan->address, val);
+ mutex_unlock(&ltc2309->lock);
+ if (ret < 0)
+ return -EINVAL;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = ltc2309->vref_mv;
+ *val2 = LTC2309_ADC_RESOLUTION;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info ltc2309_info = {
+ .read_raw = ltc2309_read_raw,
+};
+
+static void ltc2309_regulator_disable(void *regulator)
+{
+ regulator_disable(regulator);
+}
+
+static int ltc2309_probe(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev;
+ struct ltc2309 *ltc2309;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*ltc2309));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ ltc2309 = iio_priv(indio_dev);
+ ltc2309->dev = &indio_dev->dev;
+ ltc2309->client = client;
+ ltc2309->vref_mv = 4096; /* Default to the internal ref */
+
+ indio_dev->name = "ltc2309";
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = ltc2309_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ltc2309_channels);
+ indio_dev->info = &ltc2309_info;
+
+ ltc2309->vref = devm_regulator_get_optional(&client->dev, "vref");
+ if (IS_ERR(ltc2309->vref)) {
+ ret = PTR_ERR(ltc2309->vref);
+ if (ret == -ENODEV)
+ ltc2309->vref = NULL;
+ else
+ return ret;
+ }
+
+ if (ltc2309->vref) {
+ ret = regulator_enable(ltc2309->vref);
+ if (ret)
+ return dev_err_probe(ltc2309->dev, ret,
+ "failed to enable vref\n");
+
+ ret = devm_add_action_or_reset(ltc2309->dev,
+ ltc2309_regulator_disable,
+ ltc2309->vref);
+ if (ret) {
+ return dev_err_probe(ltc2309->dev, ret,
+ "failed to add regulator_disable action: %d\n",
+ ret);
+ }
+
+ ret = regulator_get_voltage(ltc2309->vref);
+ if (ret < 0)
+ return ret;
+
+ ltc2309->vref_mv = ret / 1000;
+ }
+
+ mutex_init(&ltc2309->lock);
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct of_device_id ltc2309_of_match[] = {
+ { .compatible = "lltc,ltc2309" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ltc2309_of_match);
+
+static const struct i2c_device_id ltc2309_id[] = {
+ { "ltc2309" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ltc2309_id);
+
+static struct i2c_driver ltc2309_driver = {
+ .driver = {
+ .name = "ltc2309",
+ .of_match_table = ltc2309_of_match,
+ },
+ .probe = ltc2309_probe,
+ .id_table = ltc2309_id,
+};
+module_i2c_driver(ltc2309_driver);
+
+MODULE_AUTHOR("Liam Beguin <liambeguin@gmail.com>");
+MODULE_DESCRIPTION("Linear Technology LTC2309 ADC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c
index 5bdd407296..6401a7727c 100644
--- a/drivers/iio/adc/ltc2497.c
+++ b/drivers/iio/adc/ltc2497.c
@@ -95,7 +95,6 @@ static int ltc2497_result_and_measure(struct ltc2497core_driverdata *ddata,
static int ltc2497_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
const struct ltc2497_chip_info *chip_info;
struct iio_dev *indio_dev;
struct ltc2497_driverdata *st;
@@ -115,9 +114,7 @@ static int ltc2497_probe(struct i2c_client *client)
st->client = client;
st->common_ddata.result_and_measure = ltc2497_result_and_measure;
- chip_info = device_get_match_data(dev);
- if (!chip_info)
- chip_info = (const struct ltc2497_chip_info *)id->driver_data;
+ chip_info = i2c_get_match_data(client);
st->common_ddata.chip_info = chip_info;
resolution = chip_info->resolution;
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c
index b31581616c..7c2a98b8c3 100644
--- a/drivers/iio/adc/max1363.c
+++ b/drivers/iio/adc/max1363.c
@@ -1599,9 +1599,7 @@ static int max1363_probe(struct i2c_client *client)
if (ret)
return ret;
- st->chip_info = device_get_match_data(&client->dev);
- if (!st->chip_info)
- st->chip_info = &max1363_chip_info_tbl[id->driver_data];
+ st->chip_info = i2c_get_match_data(client);
st->client = client;
st->vref_uv = st->chip_info->int_vref_mv * 1000;
@@ -1669,46 +1667,51 @@ static int max1363_probe(struct i2c_client *client)
return devm_iio_device_register(&client->dev, indio_dev);
}
+#define MAX1363_ID_TABLE(_name, cfg) { \
+ .name = _name, \
+ .driver_data = (kernel_ulong_t)&max1363_chip_info_tbl[cfg], \
+}
+
static const struct i2c_device_id max1363_id[] = {
- { "max1361", max1361 },
- { "max1362", max1362 },
- { "max1363", max1363 },
- { "max1364", max1364 },
- { "max1036", max1036 },
- { "max1037", max1037 },
- { "max1038", max1038 },
- { "max1039", max1039 },
- { "max1136", max1136 },
- { "max1137", max1137 },
- { "max1138", max1138 },
- { "max1139", max1139 },
- { "max1236", max1236 },
- { "max1237", max1237 },
- { "max1238", max1238 },
- { "max1239", max1239 },
- { "max11600", max11600 },
- { "max11601", max11601 },
- { "max11602", max11602 },
- { "max11603", max11603 },
- { "max11604", max11604 },
- { "max11605", max11605 },
- { "max11606", max11606 },
- { "max11607", max11607 },
- { "max11608", max11608 },
- { "max11609", max11609 },
- { "max11610", max11610 },
- { "max11611", max11611 },
- { "max11612", max11612 },
- { "max11613", max11613 },
- { "max11614", max11614 },
- { "max11615", max11615 },
- { "max11616", max11616 },
- { "max11617", max11617 },
- { "max11644", max11644 },
- { "max11645", max11645 },
- { "max11646", max11646 },
- { "max11647", max11647 },
- {}
+ MAX1363_ID_TABLE("max1361", max1361),
+ MAX1363_ID_TABLE("max1362", max1362),
+ MAX1363_ID_TABLE("max1363", max1363),
+ MAX1363_ID_TABLE("max1364", max1364),
+ MAX1363_ID_TABLE("max1036", max1036),
+ MAX1363_ID_TABLE("max1037", max1037),
+ MAX1363_ID_TABLE("max1038", max1038),
+ MAX1363_ID_TABLE("max1039", max1039),
+ MAX1363_ID_TABLE("max1136", max1136),
+ MAX1363_ID_TABLE("max1137", max1137),
+ MAX1363_ID_TABLE("max1138", max1138),
+ MAX1363_ID_TABLE("max1139", max1139),
+ MAX1363_ID_TABLE("max1236", max1236),
+ MAX1363_ID_TABLE("max1237", max1237),
+ MAX1363_ID_TABLE("max1238", max1238),
+ MAX1363_ID_TABLE("max1239", max1239),
+ MAX1363_ID_TABLE("max11600", max11600),
+ MAX1363_ID_TABLE("max11601", max11601),
+ MAX1363_ID_TABLE("max11602", max11602),
+ MAX1363_ID_TABLE("max11603", max11603),
+ MAX1363_ID_TABLE("max11604", max11604),
+ MAX1363_ID_TABLE("max11605", max11605),
+ MAX1363_ID_TABLE("max11606", max11606),
+ MAX1363_ID_TABLE("max11607", max11607),
+ MAX1363_ID_TABLE("max11608", max11608),
+ MAX1363_ID_TABLE("max11609", max11609),
+ MAX1363_ID_TABLE("max11610", max11610),
+ MAX1363_ID_TABLE("max11611", max11611),
+ MAX1363_ID_TABLE("max11612", max11612),
+ MAX1363_ID_TABLE("max11613", max11613),
+ MAX1363_ID_TABLE("max11614", max11614),
+ MAX1363_ID_TABLE("max11615", max11615),
+ MAX1363_ID_TABLE("max11616", max11616),
+ MAX1363_ID_TABLE("max11617", max11617),
+ MAX1363_ID_TABLE("max11644", max11644),
+ MAX1363_ID_TABLE("max11645", max11645),
+ MAX1363_ID_TABLE("max11646", max11646),
+ MAX1363_ID_TABLE("max11647", max11647),
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, max1363_id);
diff --git a/drivers/iio/adc/mcp3564.c b/drivers/iio/adc/mcp3564.c
new file mode 100644
index 0000000000..311b613b60
--- /dev/null
+++ b/drivers/iio/adc/mcp3564.c
@@ -0,0 +1,1513 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * IIO driver for MCP356X/MCP356XR and MCP346X/MCP346XR series ADC chip family
+ *
+ * Copyright (C) 2022-2023 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Marius Cristea <marius.cristea@microchip.com>
+ *
+ * Datasheet for MCP3561, MCP3562, MCP3564 can be found here:
+ * https://ww1.microchip.com/downloads/aemDocuments/documents/MSLD/ProductDocuments/DataSheets/MCP3561-2-4-Family-Data-Sheet-DS20006181C.pdf
+ * Datasheet for MCP3561R, MCP3562R, MCP3564R can be found here:
+ * https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/MCP3561_2_4R-Data-Sheet-DS200006391C.pdf
+ * Datasheet for MCP3461, MCP3462, MCP3464 can be found here:
+ * https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/MCP3461-2-4-Two-Four-Eight-Channel-153.6-ksps-Low-Noise-16-Bit-Delta-Sigma-ADC-Data-Sheet-20006180D.pdf
+ * Datasheet for MCP3461R, MCP3462R, MCP3464R can be found here:
+ * https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/MCP3461-2-4R-Family-Data-Sheet-DS20006404C.pdf
+ */
+
+#include <linux/bitfield.h>
+#include <linux/iopoll.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/units.h>
+#include <linux/util_macros.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define MCP3564_ADCDATA_REG 0x00
+
+#define MCP3564_CONFIG0_REG 0x01
+#define MCP3564_CONFIG0_ADC_MODE_MASK GENMASK(1, 0)
+/* Current Source/Sink Selection Bits for Sensor Bias */
+#define MCP3564_CONFIG0_CS_SEL_MASK GENMASK(3, 2)
+/* Internal clock is selected and AMCLK is present on the analog master clock output pin */
+#define MCP3564_CONFIG0_USE_INT_CLK_OUTPUT_EN 0x03
+/* Internal clock is selected and no clock output is present on the CLK pin */
+#define MCP3564_CONFIG0_USE_INT_CLK 0x02
+/* External digital clock */
+#define MCP3564_CONFIG0_USE_EXT_CLK 0x01
+/* External digital clock (default) */
+#define MCP3564_CONFIG0_USE_EXT_CLK_DEFAULT 0x00
+#define MCP3564_CONFIG0_CLK_SEL_MASK GENMASK(5, 4)
+#define MCP3456_CONFIG0_BIT6_DEFAULT BIT(6)
+#define MCP3456_CONFIG0_VREF_MASK BIT(7)
+
+#define MCP3564_CONFIG1_REG 0x02
+#define MCP3564_CONFIG1_OVERSPL_RATIO_MASK GENMASK(5, 2)
+
+#define MCP3564_CONFIG2_REG 0x03
+#define MCP3564_CONFIG2_AZ_REF_MASK BIT(1)
+#define MCP3564_CONFIG2_AZ_MUX_MASK BIT(2)
+
+#define MCP3564_CONFIG2_HARDWARE_GAIN_MASK GENMASK(5, 3)
+#define MCP3564_DEFAULT_HARDWARE_GAIN 0x01
+#define MCP3564_CONFIG2_BOOST_CURRENT_MASK GENMASK(7, 6)
+
+#define MCP3564_CONFIG3_REG 0x04
+#define MCP3464_CONFIG3_EN_GAINCAL_MASK BIT(0)
+#define MCP3464_CONFIG3_EN_OFFCAL_MASK BIT(1)
+#define MCP3464_CONFIG3_EN_CRCCOM_MASK BIT(2)
+#define MCP3464_CONFIG3_CRC_FORMAT_MASK BIT(3)
+/*
+ * ADC Output Data Format 32-bit (25-bit right justified data + Channel ID):
+ * CHID[3:0] + SGN extension (4 bits) + 24-bit ADC data.
+ * It allows overrange with the SGN extension.
+ */
+#define MCP3464_CONFIG3_DATA_FMT_32B_WITH_CH_ID 3
+/*
+ * ADC Output Data Format 32-bit (25-bit right justified data):
+ * SGN extension (8-bit) + 24-bit ADC data.
+ * It allows overrange with the SGN extension.
+ */
+#define MCP3464_CONFIG3_DATA_FMT_32B_SGN_EXT 2
+/*
+ * ADC Output Data Format 32-bit (24-bit left justified data):
+ * 24-bit ADC data + 0x00 (8-bit).
+ * It does not allow overrange (ADC code locked to 0xFFFFFF or 0x800000).
+ */
+#define MCP3464_CONFIG3_DATA_FMT_32B_LEFT_JUSTIFIED 1
+/*
+ * ADC Output Data Format 24-bit (default ADC coding):
+ * 24-bit ADC data.
+ * It does not allow overrange (ADC code locked to 0xFFFFFF or 0x800000).
+ */
+#define MCP3464_CONFIG3_DATA_FMT_24B 0
+#define MCP3464_CONFIG3_DATA_FORMAT_MASK GENMASK(5, 4)
+
+/* Continuous Conversion mode or continuous conversion cycle in SCAN mode. */
+#define MCP3464_CONFIG3_CONV_MODE_CONTINUOUS 3
+/*
+ * One-shot conversion or one-shot cycle in SCAN mode. It sets ADC_MODE[1:0] to ‘10’
+ * (standby) at the end of the conversion or at the end of the conversion cycle in SCAN mode.
+ */
+#define MCP3464_CONFIG3_CONV_MODE_ONE_SHOT_STANDBY 2
+/*
+ * One-shot conversion or one-shot cycle in SCAN mode. It sets ADC_MODE[1:0] to ‘0x’ (ADC
+ * Shutdown) at the end of the conversion or at the end of the conversion cycle in SCAN
+ * mode (default).
+ */
+#define MCP3464_CONFIG3_CONV_MODE_ONE_SHOT_SHUTDOWN 0
+#define MCP3464_CONFIG3_CONV_MODE_MASK GENMASK(7, 6)
+
+#define MCP3564_IRQ_REG 0x05
+#define MCP3464_EN_STP_MASK BIT(0)
+#define MCP3464_EN_FASTCMD_MASK BIT(1)
+#define MCP3464_IRQ_MODE_0_MASK BIT(2)
+#define MCP3464_IRQ_MODE_1_MASK BIT(3)
+#define MCP3564_POR_STATUS_MASK BIT(4)
+#define MCP3564_CRCCFG_STATUS_MASK BIT(5)
+#define MCP3564_DATA_READY_MASK BIT(6)
+
+#define MCP3564_MUX_REG 0x06
+#define MCP3564_MUX_VIN_P_MASK GENMASK(7, 4)
+#define MCP3564_MUX_VIN_N_MASK GENMASK(3, 0)
+#define MCP3564_MUX_SET(x, y) (FIELD_PREP(MCP3564_MUX_VIN_P_MASK, (x)) | \
+ FIELD_PREP(MCP3564_MUX_VIN_N_MASK, (y)))
+
+#define MCP3564_SCAN_REG 0x07
+#define MCP3564_SCAN_CH_SEL_MASK GENMASK(15, 0)
+#define MCP3564_SCAN_CH_SEL_SET(x) FIELD_PREP(MCP3564_SCAN_CH_SEL_MASK, (x))
+#define MCP3564_SCAN_DELAY_TIME_MASK GENMASK(23, 21)
+#define MCP3564_SCAN_DELAY_TIME_SET(x) FIELD_PREP(MCP3564_SCAN_DELAY_TIME_MASK, (x))
+#define MCP3564_SCAN_DEFAULT_VALUE 0
+
+#define MCP3564_TIMER_REG 0x08
+#define MCP3564_TIMER_DEFAULT_VALUE 0
+
+#define MCP3564_OFFSETCAL_REG 0x09
+#define MCP3564_DEFAULT_OFFSETCAL 0
+
+#define MCP3564_GAINCAL_REG 0x0A
+#define MCP3564_DEFAULT_GAINCAL 0x00800000
+
+#define MCP3564_RESERVED_B_REG 0x0B
+
+#define MCP3564_RESERVED_C_REG 0x0C
+#define MCP3564_C_REG_DEFAULT 0x50
+#define MCP3564R_C_REG_DEFAULT 0x30
+
+#define MCP3564_LOCK_REG 0x0D
+#define MCP3564_LOCK_WRITE_ACCESS_PASSWORD 0xA5
+#define MCP3564_RESERVED_E_REG 0x0E
+#define MCP3564_CRCCFG_REG 0x0F
+
+#define MCP3564_CMD_HW_ADDR_MASK GENMASK(7, 6)
+#define MCP3564_CMD_ADDR_MASK GENMASK(5, 2)
+
+#define MCP3564_HW_ADDR_MASK GENMASK(1, 0)
+
+#define MCP3564_FASTCMD_START 0x0A
+#define MCP3564_FASTCMD_RESET 0x0E
+
+#define MCP3461_HW_ID 0x0008
+#define MCP3462_HW_ID 0x0009
+#define MCP3464_HW_ID 0x000B
+
+#define MCP3561_HW_ID 0x000C
+#define MCP3562_HW_ID 0x000D
+#define MCP3564_HW_ID 0x000F
+#define MCP3564_HW_ID_MASK GENMASK(3, 0)
+
+#define MCP3564R_INT_VREF_MV 2400
+
+#define MCP3564_DATA_READY_TIMEOUT_MS 2000
+
+#define MCP3564_MAX_PGA 8
+#define MCP3564_MAX_BURNOUT_IDX 4
+#define MCP3564_MAX_CHANNELS 66
+
+enum mcp3564_ids {
+ mcp3461,
+ mcp3462,
+ mcp3464,
+ mcp3561,
+ mcp3562,
+ mcp3564,
+ mcp3461r,
+ mcp3462r,
+ mcp3464r,
+ mcp3561r,
+ mcp3562r,
+ mcp3564r,
+};
+
+enum mcp3564_delay_time {
+ MCP3564_NO_DELAY,
+ MCP3564_DELAY_8_DMCLK,
+ MCP3564_DELAY_16_DMCLK,
+ MCP3564_DELAY_32_DMCLK,
+ MCP3564_DELAY_64_DMCLK,
+ MCP3564_DELAY_128_DMCLK,
+ MCP3564_DELAY_256_DMCLK,
+ MCP3564_DELAY_512_DMCLK
+};
+
+enum mcp3564_adc_conversion_mode {
+ MCP3564_ADC_MODE_DEFAULT,
+ MCP3564_ADC_MODE_SHUTDOWN,
+ MCP3564_ADC_MODE_STANDBY,
+ MCP3564_ADC_MODE_CONVERSION
+};
+
+enum mcp3564_adc_bias_current {
+ MCP3564_BOOST_CURRENT_x0_50,
+ MCP3564_BOOST_CURRENT_x0_66,
+ MCP3564_BOOST_CURRENT_x1_00,
+ MCP3564_BOOST_CURRENT_x2_00
+};
+
+enum mcp3564_burnout {
+ MCP3564_CONFIG0_CS_SEL_0_0_uA,
+ MCP3564_CONFIG0_CS_SEL_0_9_uA,
+ MCP3564_CONFIG0_CS_SEL_3_7_uA,
+ MCP3564_CONFIG0_CS_SEL_15_uA
+};
+
+enum mcp3564_channel_names {
+ MCP3564_CH0,
+ MCP3564_CH1,
+ MCP3564_CH2,
+ MCP3564_CH3,
+ MCP3564_CH4,
+ MCP3564_CH5,
+ MCP3564_CH6,
+ MCP3564_CH7,
+ MCP3564_AGND,
+ MCP3564_AVDD,
+ MCP3564_RESERVED, /* do not use */
+ MCP3564_REFIN_POZ,
+ MCP3564_REFIN_NEG,
+ MCP3564_TEMP_DIODE_P,
+ MCP3564_TEMP_DIODE_M,
+ MCP3564_INTERNAL_VCM,
+};
+
+enum mcp3564_oversampling {
+ MCP3564_OVERSAMPLING_RATIO_32,
+ MCP3564_OVERSAMPLING_RATIO_64,
+ MCP3564_OVERSAMPLING_RATIO_128,
+ MCP3564_OVERSAMPLING_RATIO_256,
+ MCP3564_OVERSAMPLING_RATIO_512,
+ MCP3564_OVERSAMPLING_RATIO_1024,
+ MCP3564_OVERSAMPLING_RATIO_2048,
+ MCP3564_OVERSAMPLING_RATIO_4096,
+ MCP3564_OVERSAMPLING_RATIO_8192,
+ MCP3564_OVERSAMPLING_RATIO_16384,
+ MCP3564_OVERSAMPLING_RATIO_20480,
+ MCP3564_OVERSAMPLING_RATIO_24576,
+ MCP3564_OVERSAMPLING_RATIO_40960,
+ MCP3564_OVERSAMPLING_RATIO_49152,
+ MCP3564_OVERSAMPLING_RATIO_81920,
+ MCP3564_OVERSAMPLING_RATIO_98304
+};
+
+static const unsigned int mcp3564_oversampling_avail[] = {
+ [MCP3564_OVERSAMPLING_RATIO_32] = 32,
+ [MCP3564_OVERSAMPLING_RATIO_64] = 64,
+ [MCP3564_OVERSAMPLING_RATIO_128] = 128,
+ [MCP3564_OVERSAMPLING_RATIO_256] = 256,
+ [MCP3564_OVERSAMPLING_RATIO_512] = 512,
+ [MCP3564_OVERSAMPLING_RATIO_1024] = 1024,
+ [MCP3564_OVERSAMPLING_RATIO_2048] = 2048,
+ [MCP3564_OVERSAMPLING_RATIO_4096] = 4096,
+ [MCP3564_OVERSAMPLING_RATIO_8192] = 8192,
+ [MCP3564_OVERSAMPLING_RATIO_16384] = 16384,
+ [MCP3564_OVERSAMPLING_RATIO_20480] = 20480,
+ [MCP3564_OVERSAMPLING_RATIO_24576] = 24576,
+ [MCP3564_OVERSAMPLING_RATIO_40960] = 40960,
+ [MCP3564_OVERSAMPLING_RATIO_49152] = 49152,
+ [MCP3564_OVERSAMPLING_RATIO_81920] = 81920,
+ [MCP3564_OVERSAMPLING_RATIO_98304] = 98304
+};
+
+/*
+ * Current Source/Sink Selection Bits for Sensor Bias (source on VIN+/sink on VIN-)
+ */
+static const int mcp3564_burnout_avail[][2] = {
+ [MCP3564_CONFIG0_CS_SEL_0_0_uA] = { 0, 0 },
+ [MCP3564_CONFIG0_CS_SEL_0_9_uA] = { 0, 900 },
+ [MCP3564_CONFIG0_CS_SEL_3_7_uA] = { 0, 3700 },
+ [MCP3564_CONFIG0_CS_SEL_15_uA] = { 0, 15000 }
+};
+
+/*
+ * BOOST[1:0]: ADC Bias Current Selection
+ */
+static const char * const mcp3564_boost_current_avail[] = {
+ [MCP3564_BOOST_CURRENT_x0_50] = "0.5",
+ [MCP3564_BOOST_CURRENT_x0_66] = "0.66",
+ [MCP3564_BOOST_CURRENT_x1_00] = "1",
+ [MCP3564_BOOST_CURRENT_x2_00] = "2",
+};
+
+/*
+ * Calibration bias values
+ */
+static const int mcp3564_calib_bias[] = {
+ -8388608, /* min: -2^23 */
+ 1, /* step: 1 */
+ 8388607 /* max: 2^23 - 1 */
+};
+
+/*
+ * Calibration scale values
+ * The Gain Error Calibration register (GAINCAL) is an
+ * unsigned 24-bit register that holds the digital gain error
+ * calibration value, GAINCAL which could be calculated by
+ * GAINCAL (V/V) = (GAINCAL[23:0])/8388608
+ * The gain error calibration value range in equivalent voltage is [0; 2-2^(-23)]
+ */
+static const unsigned int mcp3564_calib_scale[] = {
+ 0, /* min: 0 */
+ 1, /* step: 1/8388608 */
+ 16777215 /* max: 2 - 2^(-23) */
+};
+
+/* Programmable hardware gain x1/3, x1, x2, x4, x8, x16, x32, x64 */
+static const int mcp3564_hwgain_frac[] = {
+ 3, 10,
+ 1, 1,
+ 2, 1,
+ 4, 1,
+ 8, 1,
+ 16, 1,
+ 32, 1,
+ 64, 1
+};
+
+static const char *mcp3564_channel_labels[2] = {
+ "burnout_current", "temperature",
+};
+
+/**
+ * struct mcp3564_chip_info - chip specific data
+ * @name: device name
+ * @num_channels: number of channels
+ * @resolution: ADC resolution
+ * @have_vref: does the hardware have an internal voltage reference?
+ */
+struct mcp3564_chip_info {
+ const char *name;
+ unsigned int num_channels;
+ unsigned int resolution;
+ bool have_vref;
+};
+
+/**
+ * struct mcp3564_state - working data for a ADC device
+ * @chip_info: chip specific data
+ * @spi: SPI device structure
+ * @vref: the regulator device used as a voltage reference in case
+ * external voltage reference is used
+ * @vref_mv: voltage reference value in miliVolts
+ * @lock: synchronize access to driver's state members
+ * @dev_addr: hardware device address
+ * @oversampling: the index inside oversampling list of the ADC
+ * @hwgain: the index inside hardware gain list of the ADC
+ * @scale_tbls: table with precalculated scale
+ * @calib_bias: calibration bias value
+ * @calib_scale: calibration scale value
+ * @current_boost_mode: the index inside current boost list of the ADC
+ * @burnout_mode: the index inside current bias list of the ADC
+ * @auto_zeroing_mux: set if ADC auto-zeroing algorithm is enabled
+ * @auto_zeroing_ref: set if ADC auto-Zeroing Reference Buffer Setting is enabled
+ * @have_vref: does the ADC have an internal voltage reference?
+ * @labels: table with channels labels
+ */
+struct mcp3564_state {
+ const struct mcp3564_chip_info *chip_info;
+ struct spi_device *spi;
+ struct regulator *vref;
+ unsigned short vref_mv;
+ struct mutex lock; /* Synchronize access to driver's state members */
+ u8 dev_addr;
+ enum mcp3564_oversampling oversampling;
+ unsigned int hwgain;
+ unsigned int scale_tbls[MCP3564_MAX_PGA][2];
+ int calib_bias;
+ int calib_scale;
+ unsigned int current_boost_mode;
+ enum mcp3564_burnout burnout_mode;
+ bool auto_zeroing_mux;
+ bool auto_zeroing_ref;
+ bool have_vref;
+ const char *labels[MCP3564_MAX_CHANNELS];
+};
+
+static inline u8 mcp3564_cmd_write(u8 chip_addr, u8 reg)
+{
+ return FIELD_PREP(MCP3564_CMD_HW_ADDR_MASK, chip_addr) |
+ FIELD_PREP(MCP3564_CMD_ADDR_MASK, reg) |
+ BIT(1);
+}
+
+static inline u8 mcp3564_cmd_read(u8 chip_addr, u8 reg)
+{
+ return FIELD_PREP(MCP3564_CMD_HW_ADDR_MASK, chip_addr) |
+ FIELD_PREP(MCP3564_CMD_ADDR_MASK, reg) |
+ BIT(0);
+}
+
+static int mcp3564_read_8bits(struct mcp3564_state *adc, u8 reg, u8 *val)
+{
+ int ret;
+ u8 tx_buf;
+ u8 rx_buf;
+
+ tx_buf = mcp3564_cmd_read(adc->dev_addr, reg);
+
+ ret = spi_write_then_read(adc->spi, &tx_buf, sizeof(tx_buf),
+ &rx_buf, sizeof(rx_buf));
+ *val = rx_buf;
+
+ return ret;
+}
+
+static int mcp3564_read_16bits(struct mcp3564_state *adc, u8 reg, u16 *val)
+{
+ int ret;
+ u8 tx_buf;
+ __be16 rx_buf;
+
+ tx_buf = mcp3564_cmd_read(adc->dev_addr, reg);
+
+ ret = spi_write_then_read(adc->spi, &tx_buf, sizeof(tx_buf),
+ &rx_buf, sizeof(rx_buf));
+ *val = be16_to_cpu(rx_buf);
+
+ return ret;
+}
+
+static int mcp3564_read_32bits(struct mcp3564_state *adc, u8 reg, u32 *val)
+{
+ int ret;
+ u8 tx_buf;
+ __be32 rx_buf;
+
+ tx_buf = mcp3564_cmd_read(adc->dev_addr, reg);
+
+ ret = spi_write_then_read(adc->spi, &tx_buf, sizeof(tx_buf),
+ &rx_buf, sizeof(rx_buf));
+ *val = be32_to_cpu(rx_buf);
+
+ return ret;
+}
+
+static int mcp3564_write_8bits(struct mcp3564_state *adc, u8 reg, u8 val)
+{
+ u8 tx_buf[2];
+
+ tx_buf[0] = mcp3564_cmd_write(adc->dev_addr, reg);
+ tx_buf[1] = val;
+
+ return spi_write_then_read(adc->spi, tx_buf, sizeof(tx_buf), NULL, 0);
+}
+
+static int mcp3564_write_24bits(struct mcp3564_state *adc, u8 reg, u32 val)
+{
+ __be32 val_be;
+
+ val |= (mcp3564_cmd_write(adc->dev_addr, reg) << 24);
+ val_be = cpu_to_be32(val);
+
+ return spi_write_then_read(adc->spi, &val_be, sizeof(val_be), NULL, 0);
+}
+
+static int mcp3564_fast_cmd(struct mcp3564_state *adc, u8 fast_cmd)
+{
+ u8 val;
+
+ val = FIELD_PREP(MCP3564_CMD_HW_ADDR_MASK, adc->dev_addr) |
+ FIELD_PREP(MCP3564_CMD_ADDR_MASK, fast_cmd);
+
+ return spi_write_then_read(adc->spi, &val, 1, NULL, 0);
+}
+
+static int mcp3564_update_8bits(struct mcp3564_state *adc, u8 reg, u32 mask, u8 val)
+{
+ u8 tmp;
+ int ret;
+
+ val &= mask;
+
+ ret = mcp3564_read_8bits(adc, reg, &tmp);
+ if (ret < 0)
+ return ret;
+
+ tmp &= ~mask;
+ tmp |= val;
+
+ return mcp3564_write_8bits(adc, reg, tmp);
+}
+
+static int mcp3564_set_current_boost_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ unsigned int mode)
+{
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+ int ret;
+
+ dev_dbg(&indio_dev->dev, "%s: %d\n", __func__, mode);
+
+ mutex_lock(&adc->lock);
+ ret = mcp3564_update_8bits(adc, MCP3564_CONFIG2_REG, MCP3564_CONFIG2_BOOST_CURRENT_MASK,
+ FIELD_PREP(MCP3564_CONFIG2_BOOST_CURRENT_MASK, mode));
+
+ if (ret)
+ dev_err(&indio_dev->dev, "Failed to configure CONFIG2 register\n");
+ else
+ adc->current_boost_mode = mode;
+
+ mutex_unlock(&adc->lock);
+
+ return ret;
+}
+
+static int mcp3564_get_current_boost_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+
+ return adc->current_boost_mode;
+}
+
+static const struct iio_enum mcp3564_current_boost_mode_enum = {
+ .items = mcp3564_boost_current_avail,
+ .num_items = ARRAY_SIZE(mcp3564_boost_current_avail),
+ .set = mcp3564_set_current_boost_mode,
+ .get = mcp3564_get_current_boost_mode,
+};
+
+static const struct iio_chan_spec_ext_info mcp3564_ext_info[] = {
+ IIO_ENUM("boost_current_gain", IIO_SHARED_BY_ALL, &mcp3564_current_boost_mode_enum),
+ {
+ .name = "boost_current_gain_available",
+ .shared = IIO_SHARED_BY_ALL,
+ .read = iio_enum_available_read,
+ .private = (uintptr_t)&mcp3564_current_boost_mode_enum,
+ },
+ { }
+};
+
+static ssize_t mcp3564_auto_zeroing_mux_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+
+ return sysfs_emit(buf, "%d\n", adc->auto_zeroing_mux);
+}
+
+static ssize_t mcp3564_auto_zeroing_mux_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 mcp3564_state *adc = iio_priv(indio_dev);
+ bool auto_zero;
+ int ret;
+
+ ret = kstrtobool(buf, &auto_zero);
+ if (ret)
+ return ret;
+
+ mutex_lock(&adc->lock);
+ ret = mcp3564_update_8bits(adc, MCP3564_CONFIG2_REG, MCP3564_CONFIG2_AZ_MUX_MASK,
+ FIELD_PREP(MCP3564_CONFIG2_AZ_MUX_MASK, auto_zero));
+
+ if (ret)
+ dev_err(&indio_dev->dev, "Failed to update CONFIG2 register\n");
+ else
+ adc->auto_zeroing_mux = auto_zero;
+
+ mutex_unlock(&adc->lock);
+
+ return ret ? ret : len;
+}
+
+static ssize_t mcp3564_auto_zeroing_ref_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+
+ return sysfs_emit(buf, "%d\n", adc->auto_zeroing_ref);
+}
+
+static ssize_t mcp3564_auto_zeroing_ref_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 mcp3564_state *adc = iio_priv(indio_dev);
+ bool auto_zero;
+ int ret;
+
+ ret = kstrtobool(buf, &auto_zero);
+ if (ret)
+ return ret;
+
+ mutex_lock(&adc->lock);
+ ret = mcp3564_update_8bits(adc, MCP3564_CONFIG2_REG, MCP3564_CONFIG2_AZ_REF_MASK,
+ FIELD_PREP(MCP3564_CONFIG2_AZ_REF_MASK, auto_zero));
+
+ if (ret)
+ dev_err(&indio_dev->dev, "Failed to update CONFIG2 register\n");
+ else
+ adc->auto_zeroing_ref = auto_zero;
+
+ mutex_unlock(&adc->lock);
+
+ return ret ? ret : len;
+}
+
+static const struct iio_chan_spec mcp3564_channel_template = {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .differential = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .ext_info = mcp3564_ext_info,
+};
+
+static const struct iio_chan_spec mcp3564_temp_channel_template = {
+ .type = IIO_TEMP,
+ .channel = 0,
+ .address = ((MCP3564_TEMP_DIODE_P << 4) | MCP3564_TEMP_DIODE_M),
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+};
+
+static const struct iio_chan_spec mcp3564_burnout_channel_template = {
+ .type = IIO_CURRENT,
+ .output = true,
+ .channel = 0,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW),
+};
+
+/*
+ * Number of channels could be calculated:
+ * num_channels = single_ended_input + differential_input + temperature + burnout
+ * Eg. for MCP3561 (only 2 channels available: CH0 and CH1)
+ * single_ended_input = (CH0 - GND), (CH1 - GND) = 2
+ * differential_input = (CH0 - CH1), (CH0 - CH0) = 2
+ * num_channels = 2 + 2 + 2
+ * Generic formula is:
+ * num_channels = P^R(Number_of_single_ended_channels, 2) + 2 (temperature + burnout channels)
+ * P^R(Number_of_single_ended_channels, 2) is Permutations with Replacement of
+ * Number_of_single_ended_channels taken by 2
+ */
+static const struct mcp3564_chip_info mcp3564_chip_infos_tbl[] = {
+ [mcp3461] = {
+ .name = "mcp3461",
+ .num_channels = 6,
+ .resolution = 16,
+ .have_vref = false,
+ },
+ [mcp3462] = {
+ .name = "mcp3462",
+ .num_channels = 18,
+ .resolution = 16,
+ .have_vref = false,
+ },
+ [mcp3464] = {
+ .name = "mcp3464",
+ .num_channels = 66,
+ .resolution = 16,
+ .have_vref = false,
+ },
+ [mcp3561] = {
+ .name = "mcp3561",
+ .num_channels = 6,
+ .resolution = 24,
+ .have_vref = false,
+ },
+ [mcp3562] = {
+ .name = "mcp3562",
+ .num_channels = 18,
+ .resolution = 24,
+ .have_vref = false,
+ },
+ [mcp3564] = {
+ .name = "mcp3564",
+ .num_channels = 66,
+ .resolution = 24,
+ .have_vref = false,
+ },
+ [mcp3461r] = {
+ .name = "mcp3461r",
+ .num_channels = 6,
+ .resolution = 16,
+ .have_vref = false,
+ },
+ [mcp3462r] = {
+ .name = "mcp3462r",
+ .num_channels = 18,
+ .resolution = 16,
+ .have_vref = true,
+ },
+ [mcp3464r] = {
+ .name = "mcp3464r",
+ .num_channels = 66,
+ .resolution = 16,
+ .have_vref = true,
+ },
+ [mcp3561r] = {
+ .name = "mcp3561r",
+ .num_channels = 6,
+ .resolution = 24,
+ .have_vref = true,
+ },
+ [mcp3562r] = {
+ .name = "mcp3562r",
+ .num_channels = 18,
+ .resolution = 24,
+ .have_vref = true,
+ },
+ [mcp3564r] = {
+ .name = "mcp3564r",
+ .num_channels = 66,
+ .resolution = 24,
+ .have_vref = true,
+ },
+};
+
+static int mcp3564_read_single_value(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel,
+ int *val)
+{
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+ int ret;
+ u8 tmp;
+ int ret_read = 0;
+
+ ret = mcp3564_write_8bits(adc, MCP3564_MUX_REG, channel->address);
+ if (ret)
+ return ret;
+
+ /* Start ADC Conversion using fast command (overwrites ADC_MODE[1:0] = 11) */
+ ret = mcp3564_fast_cmd(adc, MCP3564_FASTCMD_START);
+ if (ret)
+ return ret;
+
+ /*
+ * Check if the conversion is ready. If not, wait a little bit, and
+ * in case of timeout exit with an error.
+ */
+ ret = read_poll_timeout(mcp3564_read_8bits, ret_read,
+ ret_read || !(tmp & MCP3564_DATA_READY_MASK),
+ 20000, MCP3564_DATA_READY_TIMEOUT_MS * 1000, true,
+ adc, MCP3564_IRQ_REG, &tmp);
+
+ /* failed to read status register */
+ if (ret_read)
+ return ret_read;
+
+ if (ret)
+ return ret;
+
+ if (tmp & MCP3564_DATA_READY_MASK)
+ /* failing to finish conversion */
+ return -EBUSY;
+
+ return mcp3564_read_32bits(adc, MCP3564_ADCDATA_REG, val);
+}
+
+static int mcp3564_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel,
+ const int **vals, int *type,
+ int *length, long mask)
+{
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (!channel->output)
+ return -EINVAL;
+
+ *vals = mcp3564_burnout_avail[0];
+ *length = ARRAY_SIZE(mcp3564_burnout_avail) * 2;
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *vals = mcp3564_oversampling_avail;
+ *length = ARRAY_SIZE(mcp3564_oversampling_avail);
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SCALE:
+ *vals = (int *)adc->scale_tbls;
+ *length = ARRAY_SIZE(adc->scale_tbls) * 2;
+ *type = IIO_VAL_INT_PLUS_NANO;
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ *vals = mcp3564_calib_bias;
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_RANGE;
+ case IIO_CHAN_INFO_CALIBSCALE:
+ *vals = mcp3564_calib_scale;
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_RANGE;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mcp3564_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel,
+ int *val, int *val2, long mask)
+{
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (channel->output) {
+ mutex_lock(&adc->lock);
+ *val = mcp3564_burnout_avail[adc->burnout_mode][0];
+ *val2 = mcp3564_burnout_avail[adc->burnout_mode][1];
+ mutex_unlock(&adc->lock);
+ return IIO_VAL_INT_PLUS_MICRO;
+ }
+
+ ret = mcp3564_read_single_value(indio_dev, channel, val);
+ if (ret)
+ return -EINVAL;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ mutex_lock(&adc->lock);
+ *val = adc->scale_tbls[adc->hwgain][0];
+ *val2 = adc->scale_tbls[adc->hwgain][1];
+ mutex_unlock(&adc->lock);
+ return IIO_VAL_INT_PLUS_NANO;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *val = mcp3564_oversampling_avail[adc->oversampling];
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ *val = adc->calib_bias;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_CALIBSCALE:
+ *val = adc->calib_scale;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mcp3564_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long info)
+{
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ case IIO_CHAN_INFO_CALIBSCALE:
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mcp3564_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int val,
+ int val2, long mask)
+{
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+ int tmp;
+ unsigned int hwgain;
+ enum mcp3564_burnout burnout;
+ int ret = 0;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (!channel->output)
+ return -EINVAL;
+
+ for (burnout = 0; burnout < MCP3564_MAX_BURNOUT_IDX; burnout++)
+ if (val == mcp3564_burnout_avail[burnout][0] &&
+ val2 == mcp3564_burnout_avail[burnout][1])
+ break;
+
+ if (burnout == MCP3564_MAX_BURNOUT_IDX)
+ return -EINVAL;
+
+ if (burnout == adc->burnout_mode)
+ return ret;
+
+ mutex_lock(&adc->lock);
+ ret = mcp3564_update_8bits(adc, MCP3564_CONFIG0_REG,
+ MCP3564_CONFIG0_CS_SEL_MASK,
+ FIELD_PREP(MCP3564_CONFIG0_CS_SEL_MASK, burnout));
+
+ if (ret)
+ dev_err(&indio_dev->dev, "Failed to configure burnout current\n");
+ else
+ adc->burnout_mode = burnout;
+ mutex_unlock(&adc->lock);
+ return ret;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ if (val < mcp3564_calib_bias[0] || val > mcp3564_calib_bias[2])
+ return -EINVAL;
+
+ mutex_lock(&adc->lock);
+ ret = mcp3564_write_24bits(adc, MCP3564_OFFSETCAL_REG, val);
+ if (!ret)
+ adc->calib_bias = val;
+ mutex_unlock(&adc->lock);
+ return ret;
+ case IIO_CHAN_INFO_CALIBSCALE:
+ if (val < mcp3564_calib_scale[0] || val > mcp3564_calib_scale[2])
+ return -EINVAL;
+
+ if (adc->calib_scale == val)
+ return ret;
+
+ mutex_lock(&adc->lock);
+ ret = mcp3564_write_24bits(adc, MCP3564_GAINCAL_REG, val);
+ if (!ret)
+ adc->calib_scale = val;
+ mutex_unlock(&adc->lock);
+ return ret;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ if (val < 0)
+ return -EINVAL;
+
+ tmp = find_closest(val, mcp3564_oversampling_avail,
+ ARRAY_SIZE(mcp3564_oversampling_avail));
+
+ if (adc->oversampling == tmp)
+ return ret;
+
+ mutex_lock(&adc->lock);
+ ret = mcp3564_update_8bits(adc, MCP3564_CONFIG1_REG,
+ MCP3564_CONFIG1_OVERSPL_RATIO_MASK,
+ FIELD_PREP(MCP3564_CONFIG1_OVERSPL_RATIO_MASK,
+ adc->oversampling));
+ if (!ret)
+ adc->oversampling = tmp;
+ mutex_unlock(&adc->lock);
+ return ret;
+ case IIO_CHAN_INFO_SCALE:
+ for (hwgain = 0; hwgain < MCP3564_MAX_PGA; hwgain++)
+ if (val == adc->scale_tbls[hwgain][0] &&
+ val2 == adc->scale_tbls[hwgain][1])
+ break;
+
+ if (hwgain == MCP3564_MAX_PGA)
+ return -EINVAL;
+
+ if (hwgain == adc->hwgain)
+ return ret;
+
+ mutex_lock(&adc->lock);
+ ret = mcp3564_update_8bits(adc, MCP3564_CONFIG2_REG,
+ MCP3564_CONFIG2_HARDWARE_GAIN_MASK,
+ FIELD_PREP(MCP3564_CONFIG2_HARDWARE_GAIN_MASK, hwgain));
+ if (!ret)
+ adc->hwgain = hwgain;
+
+ mutex_unlock(&adc->lock);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mcp3564_read_label(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, char *label)
+{
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+
+ return sprintf(label, "%s\n", adc->labels[chan->scan_index]);
+}
+
+static int mcp3564_parse_fw_children(struct iio_dev *indio_dev)
+{
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+ struct device *dev = &adc->spi->dev;
+ struct iio_chan_spec *channels;
+ struct fwnode_handle *child;
+ struct iio_chan_spec chanspec = mcp3564_channel_template;
+ struct iio_chan_spec temp_chanspec = mcp3564_temp_channel_template;
+ struct iio_chan_spec burnout_chanspec = mcp3564_burnout_channel_template;
+ int chan_idx = 0;
+ unsigned int num_ch;
+ u32 inputs[2];
+ const char *node_name;
+ const char *label;
+ int ret;
+
+ num_ch = device_get_child_node_count(dev);
+ if (num_ch == 0)
+ return dev_err_probe(&indio_dev->dev, -ENODEV,
+ "FW has no channels defined\n");
+
+ /* Reserve space for burnout and temperature channel */
+ num_ch += 2;
+
+ if (num_ch > adc->chip_info->num_channels)
+ return dev_err_probe(dev, -EINVAL, "Too many channels %d > %d\n",
+ num_ch, adc->chip_info->num_channels);
+
+ channels = devm_kcalloc(dev, num_ch, sizeof(*channels), GFP_KERNEL);
+ if (!channels)
+ return dev_err_probe(dev, -ENOMEM, "Can't allocate memory\n");
+
+ device_for_each_child_node(dev, child) {
+ node_name = fwnode_get_name(child);
+
+ if (fwnode_property_present(child, "diff-channels")) {
+ ret = fwnode_property_read_u32_array(child,
+ "diff-channels",
+ inputs,
+ ARRAY_SIZE(inputs));
+ chanspec.differential = 1;
+ } else {
+ ret = fwnode_property_read_u32(child, "reg", &inputs[0]);
+
+ chanspec.differential = 0;
+ inputs[1] = MCP3564_AGND;
+ }
+ if (ret) {
+ fwnode_handle_put(child);
+ return ret;
+ }
+
+ if (inputs[0] > MCP3564_INTERNAL_VCM ||
+ inputs[1] > MCP3564_INTERNAL_VCM) {
+ fwnode_handle_put(child);
+ return dev_err_probe(&indio_dev->dev, -EINVAL,
+ "Channel index > %d, for %s\n",
+ MCP3564_INTERNAL_VCM + 1,
+ node_name);
+ }
+
+ chanspec.address = (inputs[0] << 4) | inputs[1];
+ chanspec.channel = inputs[0];
+ chanspec.channel2 = inputs[1];
+ chanspec.scan_index = chan_idx;
+
+ if (fwnode_property_present(child, "label")) {
+ fwnode_property_read_string(child, "label", &label);
+ adc->labels[chan_idx] = label;
+ }
+
+ channels[chan_idx] = chanspec;
+ chan_idx++;
+ }
+
+ /* Add burnout current channel */
+ burnout_chanspec.scan_index = chan_idx;
+ channels[chan_idx] = burnout_chanspec;
+ adc->labels[chan_idx] = mcp3564_channel_labels[0];
+ chanspec.scan_index = chan_idx;
+ chan_idx++;
+
+ /* Add temperature channel */
+ temp_chanspec.scan_index = chan_idx;
+ channels[chan_idx] = temp_chanspec;
+ adc->labels[chan_idx] = mcp3564_channel_labels[1];
+ chan_idx++;
+
+ indio_dev->num_channels = chan_idx;
+ indio_dev->channels = channels;
+
+ return 0;
+}
+
+static void mcp3564_disable_reg(void *reg)
+{
+ regulator_disable(reg);
+}
+
+static void mcp3564_fill_scale_tbls(struct mcp3564_state *adc)
+{
+ unsigned int pow = adc->chip_info->resolution - 1;
+ int ref;
+ unsigned int i;
+ int tmp0;
+ u64 tmp1;
+
+ for (i = 0; i < MCP3564_MAX_PGA; i++) {
+ ref = adc->vref_mv;
+ tmp1 = ((u64)ref * NANO) >> pow;
+ div_u64_rem(tmp1, NANO, &tmp0);
+
+ tmp1 = tmp1 * mcp3564_hwgain_frac[(2 * i) + 1];
+ tmp0 = (int)div_u64(tmp1, mcp3564_hwgain_frac[2 * i]);
+
+ adc->scale_tbls[i][1] = tmp0;
+ }
+}
+
+static int mcp3564_config(struct iio_dev *indio_dev)
+{
+ struct mcp3564_state *adc = iio_priv(indio_dev);
+ struct device *dev = &adc->spi->dev;
+ const struct spi_device_id *dev_id;
+ u8 tmp_reg;
+ u16 tmp_u16;
+ enum mcp3564_ids ids;
+ int ret = 0;
+ unsigned int tmp = 0x01;
+ bool err = false;
+
+ /*
+ * The address is set on a per-device basis by fuses in the factory,
+ * configured on request. If not requested, the fuses are set for 0x1.
+ * The device address is part of the device markings to avoid
+ * potential confusion. This address is coded on two bits, so four possible
+ * addresses are available when multiple devices are present on the same
+ * SPI bus with only one Chip Select line for all devices.
+ */
+ device_property_read_u32(dev, "microchip,hw-device-address", &tmp);
+
+ if (tmp > 3) {
+ dev_err_probe(dev, tmp,
+ "invalid device address. Must be in range 0-3.\n");
+ return -EINVAL;
+ }
+
+ adc->dev_addr = FIELD_GET(MCP3564_HW_ADDR_MASK, tmp);
+
+ dev_dbg(dev, "use HW device address %i\n", adc->dev_addr);
+
+ ret = mcp3564_read_8bits(adc, MCP3564_RESERVED_C_REG, &tmp_reg);
+ if (ret < 0)
+ return ret;
+
+ switch (tmp_reg) {
+ case MCP3564_C_REG_DEFAULT:
+ adc->have_vref = false;
+ break;
+ case MCP3564R_C_REG_DEFAULT:
+ adc->have_vref = true;
+ break;
+ default:
+ dev_info(dev, "Unknown chip found: %d\n", tmp_reg);
+ err = true;
+ }
+
+ if (!err) {
+ ret = mcp3564_read_16bits(adc, MCP3564_RESERVED_E_REG, &tmp_u16);
+ if (ret < 0)
+ return ret;
+
+ switch (tmp_u16 & MCP3564_HW_ID_MASK) {
+ case MCP3461_HW_ID:
+ if (adc->have_vref)
+ ids = mcp3461r;
+ else
+ ids = mcp3461;
+ break;
+ case MCP3462_HW_ID:
+ if (adc->have_vref)
+ ids = mcp3462r;
+ else
+ ids = mcp3462;
+ break;
+ case MCP3464_HW_ID:
+ if (adc->have_vref)
+ ids = mcp3464r;
+ else
+ ids = mcp3464;
+ break;
+ case MCP3561_HW_ID:
+ if (adc->have_vref)
+ ids = mcp3561r;
+ else
+ ids = mcp3561;
+ break;
+ case MCP3562_HW_ID:
+ if (adc->have_vref)
+ ids = mcp3562r;
+ else
+ ids = mcp3562;
+ break;
+ case MCP3564_HW_ID:
+ if (adc->have_vref)
+ ids = mcp3564r;
+ else
+ ids = mcp3564;
+ break;
+ default:
+ dev_info(dev, "Unknown chip found: %d\n", tmp_u16);
+ err = true;
+ }
+ }
+
+ if (err) {
+ /*
+ * If failed to identify the hardware based on internal registers,
+ * try using fallback compatible in device tree to deal with some newer part number.
+ */
+ adc->chip_info = spi_get_device_match_data(adc->spi);
+ if (!adc->chip_info) {
+ dev_id = spi_get_device_id(adc->spi);
+ adc->chip_info = (const struct mcp3564_chip_info *)dev_id->driver_data;
+ }
+
+ adc->have_vref = adc->chip_info->have_vref;
+ } else {
+ adc->chip_info = &mcp3564_chip_infos_tbl[ids];
+ }
+
+ dev_dbg(dev, "Found %s chip\n", adc->chip_info->name);
+
+ adc->vref = devm_regulator_get_optional(dev, "vref");
+ if (IS_ERR(adc->vref)) {
+ if (PTR_ERR(adc->vref) != -ENODEV)
+ return dev_err_probe(dev, PTR_ERR(adc->vref),
+ "failed to get regulator\n");
+
+ /* Check if chip has internal vref */
+ if (!adc->have_vref)
+ return dev_err_probe(dev, PTR_ERR(adc->vref),
+ "Unknown Vref\n");
+ adc->vref = NULL;
+ dev_dbg(dev, "%s: Using internal Vref\n", __func__);
+ } else {
+ ret = regulator_enable(adc->vref);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, mcp3564_disable_reg,
+ adc->vref);
+ if (ret)
+ return ret;
+
+ dev_dbg(dev, "%s: Using External Vref\n", __func__);
+
+ ret = regulator_get_voltage(adc->vref);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Failed to read vref regulator\n");
+
+ adc->vref_mv = ret / MILLI;
+ }
+
+ ret = mcp3564_parse_fw_children(indio_dev);
+ if (ret)
+ return ret;
+
+ /*
+ * Command sequence that ensures a recovery with the desired settings
+ * in any cases of loss-of-power scenario (Full Chip Reset):
+ * - Write LOCK register to 0xA5
+ * - Write IRQ register to 0x03
+ * - Send "Device Full Reset" fast command
+ * - Wait 1ms for "Full Reset" to complete
+ */
+ ret = mcp3564_write_8bits(adc, MCP3564_LOCK_REG, MCP3564_LOCK_WRITE_ACCESS_PASSWORD);
+ if (ret)
+ return ret;
+
+ ret = mcp3564_write_8bits(adc, MCP3564_IRQ_REG, 0x03);
+ if (ret)
+ return ret;
+
+ ret = mcp3564_fast_cmd(adc, MCP3564_FASTCMD_RESET);
+ if (ret)
+ return ret;
+
+ /*
+ * After Full reset wait some time to be able to fully reset the part and place
+ * it back in a default configuration.
+ * From datasheet: POR (Power On Reset Time) is ~1us
+ * 1ms should be enough.
+ */
+ mdelay(1);
+
+ /* set a gain of 1x for GAINCAL */
+ ret = mcp3564_write_24bits(adc, MCP3564_GAINCAL_REG, MCP3564_DEFAULT_GAINCAL);
+ if (ret)
+ return ret;
+
+ adc->calib_scale = MCP3564_DEFAULT_GAINCAL;
+
+ ret = mcp3564_write_24bits(adc, MCP3564_OFFSETCAL_REG, MCP3564_DEFAULT_OFFSETCAL);
+ if (ret)
+ return ret;
+
+ ret = mcp3564_write_24bits(adc, MCP3564_TIMER_REG, MCP3564_TIMER_DEFAULT_VALUE);
+ if (ret)
+ return ret;
+
+ ret = mcp3564_write_24bits(adc, MCP3564_SCAN_REG,
+ MCP3564_SCAN_DELAY_TIME_SET(MCP3564_NO_DELAY) |
+ MCP3564_SCAN_CH_SEL_SET(MCP3564_SCAN_DEFAULT_VALUE));
+ if (ret)
+ return ret;
+
+ ret = mcp3564_write_8bits(adc, MCP3564_MUX_REG, MCP3564_MUX_SET(MCP3564_CH0, MCP3564_CH1));
+ if (ret)
+ return ret;
+
+ ret = mcp3564_write_8bits(adc, MCP3564_IRQ_REG,
+ FIELD_PREP(MCP3464_EN_FASTCMD_MASK, 1) |
+ FIELD_PREP(MCP3464_EN_STP_MASK, 1));
+ if (ret)
+ return ret;
+
+ tmp_reg = FIELD_PREP(MCP3464_CONFIG3_CONV_MODE_MASK,
+ MCP3464_CONFIG3_CONV_MODE_ONE_SHOT_STANDBY);
+ tmp_reg |= FIELD_PREP(MCP3464_CONFIG3_DATA_FORMAT_MASK,
+ MCP3464_CONFIG3_DATA_FMT_32B_SGN_EXT);
+ tmp_reg |= MCP3464_CONFIG3_EN_OFFCAL_MASK;
+ tmp_reg |= MCP3464_CONFIG3_EN_GAINCAL_MASK;
+
+ ret = mcp3564_write_8bits(adc, MCP3564_CONFIG3_REG, tmp_reg);
+ if (ret)
+ return ret;
+
+ tmp_reg = FIELD_PREP(MCP3564_CONFIG2_BOOST_CURRENT_MASK, MCP3564_BOOST_CURRENT_x1_00);
+ tmp_reg |= FIELD_PREP(MCP3564_CONFIG2_HARDWARE_GAIN_MASK, 0x01);
+ tmp_reg |= FIELD_PREP(MCP3564_CONFIG2_AZ_MUX_MASK, 1);
+
+ ret = mcp3564_write_8bits(adc, MCP3564_CONFIG2_REG, tmp_reg);
+ if (ret)
+ return ret;
+
+ adc->hwgain = 0x01;
+ adc->auto_zeroing_mux = true;
+ adc->auto_zeroing_ref = false;
+ adc->current_boost_mode = MCP3564_BOOST_CURRENT_x1_00;
+
+ tmp_reg = FIELD_PREP(MCP3564_CONFIG1_OVERSPL_RATIO_MASK, MCP3564_OVERSAMPLING_RATIO_98304);
+
+ ret = mcp3564_write_8bits(adc, MCP3564_CONFIG1_REG, tmp_reg);
+ if (ret)
+ return ret;
+
+ adc->oversampling = MCP3564_OVERSAMPLING_RATIO_98304;
+
+ tmp_reg = FIELD_PREP(MCP3564_CONFIG0_ADC_MODE_MASK, MCP3564_ADC_MODE_STANDBY);
+ tmp_reg |= FIELD_PREP(MCP3564_CONFIG0_CS_SEL_MASK, MCP3564_CONFIG0_CS_SEL_0_0_uA);
+ tmp_reg |= FIELD_PREP(MCP3564_CONFIG0_CLK_SEL_MASK, MCP3564_CONFIG0_USE_INT_CLK);
+ tmp_reg |= MCP3456_CONFIG0_BIT6_DEFAULT;
+
+ if (!adc->vref) {
+ tmp_reg |= FIELD_PREP(MCP3456_CONFIG0_VREF_MASK, 1);
+ adc->vref_mv = MCP3564R_INT_VREF_MV;
+ }
+
+ ret = mcp3564_write_8bits(adc, MCP3564_CONFIG0_REG, tmp_reg);
+
+ adc->burnout_mode = MCP3564_CONFIG0_CS_SEL_0_0_uA;
+
+ return ret;
+}
+
+static IIO_DEVICE_ATTR(auto_zeroing_ref_enable, 0644,
+ mcp3564_auto_zeroing_ref_show,
+ mcp3564_auto_zeroing_ref_store, 0);
+
+static IIO_DEVICE_ATTR(auto_zeroing_mux_enable, 0644,
+ mcp3564_auto_zeroing_mux_show,
+ mcp3564_auto_zeroing_mux_store, 0);
+
+static struct attribute *mcp3564_attributes[] = {
+ &iio_dev_attr_auto_zeroing_mux_enable.dev_attr.attr,
+ NULL
+};
+
+static struct attribute *mcp3564r_attributes[] = {
+ &iio_dev_attr_auto_zeroing_mux_enable.dev_attr.attr,
+ &iio_dev_attr_auto_zeroing_ref_enable.dev_attr.attr,
+ NULL
+};
+
+static struct attribute_group mcp3564_attribute_group = {
+ .attrs = mcp3564_attributes,
+};
+
+static struct attribute_group mcp3564r_attribute_group = {
+ .attrs = mcp3564r_attributes,
+};
+
+static const struct iio_info mcp3564_info = {
+ .read_raw = mcp3564_read_raw,
+ .read_avail = mcp3564_read_avail,
+ .write_raw = mcp3564_write_raw,
+ .write_raw_get_fmt = mcp3564_write_raw_get_fmt,
+ .read_label = mcp3564_read_label,
+ .attrs = &mcp3564_attribute_group,
+};
+
+static const struct iio_info mcp3564r_info = {
+ .read_raw = mcp3564_read_raw,
+ .read_avail = mcp3564_read_avail,
+ .write_raw = mcp3564_write_raw,
+ .write_raw_get_fmt = mcp3564_write_raw_get_fmt,
+ .read_label = mcp3564_read_label,
+ .attrs = &mcp3564r_attribute_group,
+};
+
+static int mcp3564_probe(struct spi_device *spi)
+{
+ int ret;
+ struct iio_dev *indio_dev;
+ struct mcp3564_state *adc;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ adc = iio_priv(indio_dev);
+ adc->spi = spi;
+
+ dev_dbg(&spi->dev, "%s: probe(spi = 0x%p)\n", __func__, spi);
+
+ /*
+ * Do any chip specific initialization, e.g:
+ * read/write some registers
+ * enable/disable certain channels
+ * change the sampling rate to the requested value
+ */
+ ret = mcp3564_config(indio_dev);
+ if (ret)
+ return dev_err_probe(&spi->dev, ret,
+ "Can't configure MCP356X device\n");
+
+ dev_dbg(&spi->dev, "%s: Vref (mV): %d\n", __func__, adc->vref_mv);
+
+ mcp3564_fill_scale_tbls(adc);
+
+ indio_dev->name = adc->chip_info->name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ if (!adc->vref)
+ indio_dev->info = &mcp3564r_info;
+ else
+ indio_dev->info = &mcp3564_info;
+
+ mutex_init(&adc->lock);
+
+ ret = devm_iio_device_register(&spi->dev, indio_dev);
+ if (ret)
+ return dev_err_probe(&spi->dev, ret,
+ "Can't register IIO device\n");
+
+ return 0;
+}
+
+static const struct of_device_id mcp3564_dt_ids[] = {
+ { .compatible = "microchip,mcp3461", .data = &mcp3564_chip_infos_tbl[mcp3461] },
+ { .compatible = "microchip,mcp3462", .data = &mcp3564_chip_infos_tbl[mcp3462] },
+ { .compatible = "microchip,mcp3464", .data = &mcp3564_chip_infos_tbl[mcp3464] },
+ { .compatible = "microchip,mcp3561", .data = &mcp3564_chip_infos_tbl[mcp3561] },
+ { .compatible = "microchip,mcp3562", .data = &mcp3564_chip_infos_tbl[mcp3562] },
+ { .compatible = "microchip,mcp3564", .data = &mcp3564_chip_infos_tbl[mcp3564] },
+ { .compatible = "microchip,mcp3461r", .data = &mcp3564_chip_infos_tbl[mcp3461r] },
+ { .compatible = "microchip,mcp3462r", .data = &mcp3564_chip_infos_tbl[mcp3462r] },
+ { .compatible = "microchip,mcp3464r", .data = &mcp3564_chip_infos_tbl[mcp3464r] },
+ { .compatible = "microchip,mcp3561r", .data = &mcp3564_chip_infos_tbl[mcp3561r] },
+ { .compatible = "microchip,mcp3562r", .data = &mcp3564_chip_infos_tbl[mcp3562r] },
+ { .compatible = "microchip,mcp3564r", .data = &mcp3564_chip_infos_tbl[mcp3564r] },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mcp3564_dt_ids);
+
+static const struct spi_device_id mcp3564_id[] = {
+ { "mcp3461", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3461] },
+ { "mcp3462", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3462] },
+ { "mcp3464", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3464] },
+ { "mcp3561", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3561] },
+ { "mcp3562", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3562] },
+ { "mcp3564", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3564] },
+ { "mcp3461r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3461r] },
+ { "mcp3462r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3462r] },
+ { "mcp3464r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3464r] },
+ { "mcp3561r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3561r] },
+ { "mcp3562r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3562r] },
+ { "mcp3564r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3564r] },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, mcp3564_id);
+
+static struct spi_driver mcp3564_driver = {
+ .driver = {
+ .name = "mcp3564",
+ .of_match_table = mcp3564_dt_ids,
+ },
+ .probe = mcp3564_probe,
+ .id_table = mcp3564_id,
+};
+
+module_spi_driver(mcp3564_driver);
+
+MODULE_AUTHOR("Marius Cristea <marius.cristea@microchip.com>");
+MODULE_DESCRIPTION("Microchip MCP346x/MCP346xR and MCP356x/MCP356xR ADCs");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c
index 974c5bd923..d864558bc0 100644
--- a/drivers/iio/adc/mcp3911.c
+++ b/drivers/iio/adc/mcp3911.c
@@ -29,11 +29,11 @@
#define MCP3911_REG_MOD 0x06
#define MCP3911_REG_PHASE 0x07
#define MCP3911_REG_GAIN 0x09
-#define MCP3911_GAIN_MASK(ch) (GENMASK(2, 0) << 3 * ch)
-#define MCP3911_GAIN_VAL(ch, val) ((val << 3 * ch) & MCP3911_GAIN_MASK(ch))
+#define MCP3911_GAIN_MASK(ch) (GENMASK(2, 0) << 3 * (ch))
+#define MCP3911_GAIN_VAL(ch, val) ((val << 3 * (ch)) & MCP3911_GAIN_MASK(ch))
#define MCP3911_REG_STATUSCOM 0x0a
-#define MCP3911_STATUSCOM_DRHIZ BIT(12)
+#define MCP3911_STATUSCOM_DRHIZ BIT(12)
#define MCP3911_STATUSCOM_READ GENMASK(7, 6)
#define MCP3911_STATUSCOM_CH1_24WIDTH BIT(4)
#define MCP3911_STATUSCOM_CH0_24WIDTH BIT(3)
@@ -51,8 +51,8 @@
#define MCP3911_REG_GAINCAL_CH1 0x17
#define MCP3911_REG_VREFCAL 0x1a
-#define MCP3911_CHANNEL(x) (MCP3911_REG_CHANNEL0 + x * 3)
-#define MCP3911_OFFCAL(x) (MCP3911_REG_OFFCAL_CH0 + x * 6)
+#define MCP3911_CHANNEL(ch) (MCP3911_REG_CHANNEL0 + (ch) * 3)
+#define MCP3911_OFFCAL(ch) (MCP3911_REG_OFFCAL_CH0 + (ch) * 6)
/* Internal voltage reference in mV */
#define MCP3911_INT_VREF_MV 1200
@@ -61,12 +61,56 @@
#define MCP3911_REG_WRITE(reg, id) ((((reg) << 1) | ((id) << 6) | (0 << 0)) & 0xff)
#define MCP3911_REG_MASK GENMASK(4, 1)
-#define MCP3911_NUM_CHANNELS 2
#define MCP3911_NUM_SCALES 6
+/* Registers compatible with MCP3910 */
+#define MCP3910_REG_STATUSCOM 0x0c
+#define MCP3910_STATUSCOM_READ GENMASK(23, 22)
+#define MCP3910_STATUSCOM_DRHIZ BIT(20)
+
+#define MCP3910_REG_GAIN 0x0b
+
+#define MCP3910_REG_CONFIG0 0x0d
+#define MCP3910_CONFIG0_EN_OFFCAL BIT(23)
+#define MCP3910_CONFIG0_OSR GENMASK(15, 13)
+
+#define MCP3910_REG_CONFIG1 0x0e
+#define MCP3910_CONFIG1_CLKEXT BIT(6)
+#define MCP3910_CONFIG1_VREFEXT BIT(7)
+
+#define MCP3910_REG_OFFCAL_CH0 0x0f
+#define MCP3910_OFFCAL(ch) (MCP3910_REG_OFFCAL_CH0 + (ch) * 6)
+
+/* Maximal number of channels used by the MCP39XX family */
+#define MCP39XX_MAX_NUM_CHANNELS 8
+
static const int mcp3911_osr_table[] = { 32, 64, 128, 256, 512, 1024, 2048, 4096 };
static u32 mcp3911_scale_table[MCP3911_NUM_SCALES][2];
+enum mcp3911_id {
+ MCP3910,
+ MCP3911,
+ MCP3912,
+ MCP3913,
+ MCP3914,
+ MCP3918,
+ MCP3919,
+};
+
+struct mcp3911;
+struct mcp3911_chip_info {
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+
+ int (*config)(struct mcp3911 *adc);
+ int (*get_osr)(struct mcp3911 *adc, u32 *val);
+ int (*set_osr)(struct mcp3911 *adc, u32 val);
+ int (*enable_offset)(struct mcp3911 *adc, bool enable);
+ int (*get_offset)(struct mcp3911 *adc, int channel, int *val);
+ int (*set_offset)(struct mcp3911 *adc, int channel, int val);
+ int (*set_scale)(struct mcp3911 *adc, int channel, u32 val);
+};
+
struct mcp3911 {
struct spi_device *spi;
struct mutex lock;
@@ -74,14 +118,15 @@ struct mcp3911 {
struct clk *clki;
u32 dev_addr;
struct iio_trigger *trig;
- u32 gain[MCP3911_NUM_CHANNELS];
+ u32 gain[MCP39XX_MAX_NUM_CHANNELS];
+ const struct mcp3911_chip_info *chip;
struct {
- u32 channels[MCP3911_NUM_CHANNELS];
+ u32 channels[MCP39XX_MAX_NUM_CHANNELS];
s64 ts __aligned(8);
} scan;
u8 tx_buf __aligned(IIO_DMA_MINALIGN);
- u8 rx_buf[MCP3911_NUM_CHANNELS * 3];
+ u8 rx_buf[MCP39XX_MAX_NUM_CHANNELS * 3];
};
static int mcp3911_read(struct mcp3911 *adc, u8 reg, u32 *val, u8 len)
@@ -111,8 +156,7 @@ static int mcp3911_write(struct mcp3911 *adc, u8 reg, u32 val, u8 len)
return spi_write(adc->spi, &val, len + 1);
}
-static int mcp3911_update(struct mcp3911 *adc, u8 reg, u32 mask,
- u32 val, u8 len)
+static int mcp3911_update(struct mcp3911 *adc, u8 reg, u32 mask, u32 val, u8 len)
{
u32 tmp;
int ret;
@@ -126,9 +170,115 @@ static int mcp3911_update(struct mcp3911 *adc, u8 reg, u32 mask,
return mcp3911_write(adc, reg, val, len);
}
+static int mcp3910_enable_offset(struct mcp3911 *adc, bool enable)
+{
+ unsigned int mask = MCP3910_CONFIG0_EN_OFFCAL;
+ unsigned int value = enable ? mask : 0;
+
+ return mcp3911_update(adc, MCP3910_REG_CONFIG0, mask, value, 3);
+}
+
+static int mcp3910_get_offset(struct mcp3911 *adc, int channel, int *val)
+{
+ return mcp3911_read(adc, MCP3910_OFFCAL(channel), val, 3);
+}
+
+static int mcp3910_set_offset(struct mcp3911 *adc, int channel, int val)
+{
+ int ret;
+
+ ret = mcp3911_write(adc, MCP3910_OFFCAL(channel), val, 3);
+ if (ret)
+ return ret;
+
+ return adc->chip->enable_offset(adc, 1);
+}
+
+static int mcp3911_enable_offset(struct mcp3911 *adc, bool enable)
+{
+ unsigned int mask = MCP3911_STATUSCOM_EN_OFFCAL;
+ unsigned int value = enable ? mask : 0;
+
+ return mcp3911_update(adc, MCP3911_REG_STATUSCOM, mask, value, 2);
+}
+
+static int mcp3911_get_offset(struct mcp3911 *adc, int channel, int *val)
+{
+ return mcp3911_read(adc, MCP3911_OFFCAL(channel), val, 3);
+}
+
+static int mcp3911_set_offset(struct mcp3911 *adc, int channel, int val)
+{
+ int ret;
+
+ ret = mcp3911_write(adc, MCP3911_OFFCAL(channel), val, 3);
+ if (ret)
+ return ret;
+
+ return adc->chip->enable_offset(adc, 1);
+}
+
+static int mcp3910_get_osr(struct mcp3911 *adc, u32 *val)
+{
+ int ret;
+ unsigned int osr;
+
+ ret = mcp3911_read(adc, MCP3910_REG_CONFIG0, val, 3);
+ if (ret)
+ return ret;
+
+ osr = FIELD_GET(MCP3910_CONFIG0_OSR, *val);
+ *val = 32 << osr;
+ return 0;
+}
+
+static int mcp3910_set_osr(struct mcp3911 *adc, u32 val)
+{
+ unsigned int osr = FIELD_PREP(MCP3910_CONFIG0_OSR, val);
+ unsigned int mask = MCP3910_CONFIG0_OSR;
+
+ return mcp3911_update(adc, MCP3910_REG_CONFIG0, mask, osr, 3);
+}
+
+static int mcp3911_set_osr(struct mcp3911 *adc, u32 val)
+{
+ unsigned int osr = FIELD_PREP(MCP3911_CONFIG_OSR, val);
+ unsigned int mask = MCP3911_CONFIG_OSR;
+
+ return mcp3911_update(adc, MCP3911_REG_CONFIG, mask, osr, 2);
+}
+
+static int mcp3911_get_osr(struct mcp3911 *adc, u32 *val)
+{
+ int ret;
+ unsigned int osr;
+
+ ret = mcp3911_read(adc, MCP3911_REG_CONFIG, val, 2);
+ if (ret)
+ return ret;
+
+ osr = FIELD_GET(MCP3911_CONFIG_OSR, *val);
+ *val = 32 << osr;
+ return ret;
+}
+
+static int mcp3910_set_scale(struct mcp3911 *adc, int channel, u32 val)
+{
+ return mcp3911_update(adc, MCP3910_REG_GAIN,
+ MCP3911_GAIN_MASK(channel),
+ MCP3911_GAIN_VAL(channel, val), 3);
+}
+
+static int mcp3911_set_scale(struct mcp3911 *adc, int channel, u32 val)
+{
+ return mcp3911_update(adc, MCP3911_REG_GAIN,
+ MCP3911_GAIN_MASK(channel),
+ MCP3911_GAIN_VAL(channel, val), 1);
+}
+
static int mcp3911_write_raw_get_fmt(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- long mask)
+ struct iio_chan_spec const *chan,
+ long mask)
{
switch (mask) {
case IIO_CHAN_INFO_SCALE:
@@ -141,9 +291,9 @@ static int mcp3911_write_raw_get_fmt(struct iio_dev *indio_dev,
}
static int mcp3911_read_avail(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- const int **vals, int *type, int *length,
- long info)
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long info)
{
switch (info) {
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
@@ -182,20 +332,18 @@ static int mcp3911_read_raw(struct iio_dev *indio_dev,
break;
case IIO_CHAN_INFO_OFFSET:
- ret = mcp3911_read(adc,
- MCP3911_OFFCAL(channel->channel), val, 3);
+
+ ret = adc->chip->get_offset(adc, channel->channel, val);
if (ret)
goto out;
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
- ret = mcp3911_read(adc, MCP3911_REG_CONFIG, val, 2);
+ ret = adc->chip->get_osr(adc, val);
if (ret)
goto out;
- *val = FIELD_GET(MCP3911_CONFIG_OSR, *val);
- *val = 32 << *val;
ret = IIO_VAL_INT;
break;
@@ -212,8 +360,8 @@ out:
}
static int mcp3911_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *channel, int val,
- int val2, long mask)
+ struct iio_chan_spec const *channel, int val,
+ int val2, long mask)
{
struct mcp3911 *adc = iio_priv(indio_dev);
int ret = -EINVAL;
@@ -223,12 +371,10 @@ static int mcp3911_write_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE:
for (int i = 0; i < MCP3911_NUM_SCALES; i++) {
if (val == mcp3911_scale_table[i][0] &&
- val2 == mcp3911_scale_table[i][1]) {
+ val2 == mcp3911_scale_table[i][1]) {
adc->gain[channel->channel] = BIT(i);
- ret = mcp3911_update(adc, MCP3911_REG_GAIN,
- MCP3911_GAIN_MASK(channel->channel),
- MCP3911_GAIN_VAL(channel->channel, i), 1);
+ ret = adc->chip->set_scale(adc, channel->channel, i);
}
}
break;
@@ -238,24 +384,13 @@ static int mcp3911_write_raw(struct iio_dev *indio_dev,
goto out;
}
- /* Write offset */
- ret = mcp3911_write(adc, MCP3911_OFFCAL(channel->channel), val,
- 3);
- if (ret)
- goto out;
-
- /* Enable offset*/
- ret = mcp3911_update(adc, MCP3911_REG_STATUSCOM,
- MCP3911_STATUSCOM_EN_OFFCAL,
- MCP3911_STATUSCOM_EN_OFFCAL, 2);
+ ret = adc->chip->set_offset(adc, channel->channel, val);
break;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
for (int i = 0; i < ARRAY_SIZE(mcp3911_osr_table); i++) {
if (val == mcp3911_osr_table[i]) {
- val = FIELD_PREP(MCP3911_CONFIG_OSR, i);
- ret = mcp3911_update(adc, MCP3911_REG_CONFIG, MCP3911_CONFIG_OSR,
- val, 2);
+ ret = adc->chip->set_osr(adc, i);
break;
}
}
@@ -269,6 +404,7 @@ out:
static int mcp3911_calc_scale_table(struct mcp3911 *adc)
{
+ struct device *dev = &adc->spi->dev;
u32 ref = MCP3911_INT_VREF_MV;
u32 div;
int ret;
@@ -277,10 +413,7 @@ static int mcp3911_calc_scale_table(struct mcp3911 *adc)
if (adc->vref) {
ret = regulator_get_voltage(adc->vref);
if (ret < 0) {
- dev_err(&adc->spi->dev,
- "failed to get vref voltage: %d\n",
- ret);
- return ret;
+ return dev_err_probe(dev, ret, "failed to get vref voltage\n");
}
ref = ret / 1000;
@@ -326,24 +459,73 @@ static int mcp3911_calc_scale_table(struct mcp3911 *adc)
}, \
}
+static const struct iio_chan_spec mcp3910_channels[] = {
+ MCP3911_CHAN(0),
+ MCP3911_CHAN(1),
+ IIO_CHAN_SOFT_TIMESTAMP(2),
+};
+
static const struct iio_chan_spec mcp3911_channels[] = {
MCP3911_CHAN(0),
MCP3911_CHAN(1),
IIO_CHAN_SOFT_TIMESTAMP(2),
};
+static const struct iio_chan_spec mcp3912_channels[] = {
+ MCP3911_CHAN(0),
+ MCP3911_CHAN(1),
+ MCP3911_CHAN(2),
+ MCP3911_CHAN(3),
+ IIO_CHAN_SOFT_TIMESTAMP(4),
+};
+
+static const struct iio_chan_spec mcp3913_channels[] = {
+ MCP3911_CHAN(0),
+ MCP3911_CHAN(1),
+ MCP3911_CHAN(2),
+ MCP3911_CHAN(3),
+ MCP3911_CHAN(4),
+ MCP3911_CHAN(5),
+ IIO_CHAN_SOFT_TIMESTAMP(6),
+};
+
+static const struct iio_chan_spec mcp3914_channels[] = {
+ MCP3911_CHAN(0),
+ MCP3911_CHAN(1),
+ MCP3911_CHAN(2),
+ MCP3911_CHAN(3),
+ MCP3911_CHAN(4),
+ MCP3911_CHAN(5),
+ MCP3911_CHAN(6),
+ MCP3911_CHAN(7),
+ IIO_CHAN_SOFT_TIMESTAMP(8),
+};
+
+static const struct iio_chan_spec mcp3918_channels[] = {
+ MCP3911_CHAN(0),
+ IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
+static const struct iio_chan_spec mcp3919_channels[] = {
+ MCP3911_CHAN(0),
+ MCP3911_CHAN(1),
+ MCP3911_CHAN(2),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
static irqreturn_t mcp3911_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct mcp3911 *adc = iio_priv(indio_dev);
+ struct device *dev = &adc->spi->dev;
struct spi_transfer xfer[] = {
{
.tx_buf = &adc->tx_buf,
.len = 1,
}, {
.rx_buf = adc->rx_buf,
- .len = sizeof(adc->rx_buf),
+ .len = (adc->chip->num_channels - 1) * 3,
},
};
int scan_index;
@@ -354,8 +536,7 @@ static irqreturn_t mcp3911_trigger_handler(int irq, void *p)
adc->tx_buf = MCP3911_REG_READ(MCP3911_CHANNEL(0), adc->dev_addr);
ret = spi_sync_transfer(adc->spi, xfer, ARRAY_SIZE(xfer));
if (ret < 0) {
- dev_warn(&adc->spi->dev,
- "failed to get conversion data\n");
+ dev_warn(dev, "failed to get conversion data\n");
goto out;
}
@@ -387,43 +568,25 @@ static int mcp3911_config(struct mcp3911 *adc)
u32 regval;
int ret;
- ret = device_property_read_u32(dev, "microchip,device-addr", &adc->dev_addr);
-
- /*
- * Fallback to "device-addr" due to historical mismatch between
- * dt-bindings and implementation
- */
- if (ret)
- device_property_read_u32(dev, "device-addr", &adc->dev_addr);
- if (adc->dev_addr > 3) {
- dev_err(&adc->spi->dev,
- "invalid device address (%i). Must be in range 0-3.\n",
- adc->dev_addr);
- return -EINVAL;
- }
- dev_dbg(&adc->spi->dev, "use device address %i\n", adc->dev_addr);
-
ret = mcp3911_read(adc, MCP3911_REG_CONFIG, &regval, 2);
if (ret)
return ret;
regval &= ~MCP3911_CONFIG_VREFEXT;
if (adc->vref) {
- dev_dbg(&adc->spi->dev, "use external voltage reference\n");
+ dev_dbg(dev, "use external voltage reference\n");
regval |= FIELD_PREP(MCP3911_CONFIG_VREFEXT, 1);
} else {
- dev_dbg(&adc->spi->dev,
- "use internal voltage reference (1.2V)\n");
+ dev_dbg(dev, "use internal voltage reference (1.2V)\n");
regval |= FIELD_PREP(MCP3911_CONFIG_VREFEXT, 0);
}
regval &= ~MCP3911_CONFIG_CLKEXT;
if (adc->clki) {
- dev_dbg(&adc->spi->dev, "use external clock as clocksource\n");
+ dev_dbg(dev, "use external clock as clocksource\n");
regval |= FIELD_PREP(MCP3911_CONFIG_CLKEXT, 1);
} else {
- dev_dbg(&adc->spi->dev,
- "use crystal oscillator as clocksource\n");
+ dev_dbg(dev, "use crystal oscillator as clocksource\n");
regval |= FIELD_PREP(MCP3911_CONFIG_CLKEXT, 0);
}
@@ -439,7 +602,97 @@ static int mcp3911_config(struct mcp3911 *adc)
regval &= ~MCP3911_STATUSCOM_READ;
regval |= FIELD_PREP(MCP3911_STATUSCOM_READ, 0x02);
- return mcp3911_write(adc, MCP3911_REG_STATUSCOM, regval, 2);
+ regval &= ~MCP3911_STATUSCOM_DRHIZ;
+ if (device_property_read_bool(dev, "microchip,data-ready-hiz"))
+ regval |= FIELD_PREP(MCP3911_STATUSCOM_DRHIZ, 0);
+ else
+ regval |= FIELD_PREP(MCP3911_STATUSCOM_DRHIZ, 1);
+
+ /* Disable offset to ignore any old values in offset register */
+ regval &= ~MCP3911_STATUSCOM_EN_OFFCAL;
+
+ ret = mcp3911_write(adc, MCP3911_REG_STATUSCOM, regval, 2);
+ if (ret)
+ return ret;
+
+ /* Set gain to 1 for all channels */
+ ret = mcp3911_read(adc, MCP3911_REG_GAIN, &regval, 1);
+ if (ret)
+ return ret;
+
+ for (int i = 0; i < adc->chip->num_channels - 1; i++) {
+ adc->gain[i] = 1;
+ regval &= ~MCP3911_GAIN_MASK(i);
+ }
+
+ return mcp3911_write(adc, MCP3911_REG_GAIN, regval, 1);
+}
+
+static int mcp3910_config(struct mcp3911 *adc)
+{
+ struct device *dev = &adc->spi->dev;
+ u32 regval;
+ int ret;
+
+ ret = mcp3911_read(adc, MCP3910_REG_CONFIG1, &regval, 3);
+ if (ret)
+ return ret;
+
+ regval &= ~MCP3910_CONFIG1_VREFEXT;
+ if (adc->vref) {
+ dev_dbg(dev, "use external voltage reference\n");
+ regval |= FIELD_PREP(MCP3910_CONFIG1_VREFEXT, 1);
+ } else {
+ dev_dbg(dev, "use internal voltage reference (1.2V)\n");
+ regval |= FIELD_PREP(MCP3910_CONFIG1_VREFEXT, 0);
+ }
+
+ regval &= ~MCP3910_CONFIG1_CLKEXT;
+ if (adc->clki) {
+ dev_dbg(dev, "use external clock as clocksource\n");
+ regval |= FIELD_PREP(MCP3910_CONFIG1_CLKEXT, 1);
+ } else {
+ dev_dbg(dev, "use crystal oscillator as clocksource\n");
+ regval |= FIELD_PREP(MCP3910_CONFIG1_CLKEXT, 0);
+ }
+
+ ret = mcp3911_write(adc, MCP3910_REG_CONFIG1, regval, 3);
+ if (ret)
+ return ret;
+
+ ret = mcp3911_read(adc, MCP3910_REG_STATUSCOM, &regval, 3);
+ if (ret)
+ return ret;
+
+ /* Address counter incremented, cycle through register types */
+ regval &= ~MCP3910_STATUSCOM_READ;
+ regval |= FIELD_PREP(MCP3910_STATUSCOM_READ, 0x02);
+
+ regval &= ~MCP3910_STATUSCOM_DRHIZ;
+ if (device_property_read_bool(dev, "microchip,data-ready-hiz"))
+ regval |= FIELD_PREP(MCP3910_STATUSCOM_DRHIZ, 0);
+ else
+ regval |= FIELD_PREP(MCP3910_STATUSCOM_DRHIZ, 1);
+
+ ret = mcp3911_write(adc, MCP3910_REG_STATUSCOM, regval, 3);
+ if (ret)
+ return ret;
+
+ /* Set gain to 1 for all channels */
+ ret = mcp3911_read(adc, MCP3910_REG_GAIN, &regval, 3);
+ if (ret)
+ return ret;
+
+ for (int i = 0; i < adc->chip->num_channels - 1; i++) {
+ adc->gain[i] = 1;
+ regval &= ~MCP3911_GAIN_MASK(i);
+ }
+ ret = mcp3911_write(adc, MCP3910_REG_GAIN, regval, 3);
+ if (ret)
+ return ret;
+
+ /* Disable offset to ignore any old values in offset register */
+ return adc->chip->enable_offset(adc, 0);
}
static void mcp3911_cleanup_regulator(void *vref)
@@ -466,26 +719,25 @@ static const struct iio_trigger_ops mcp3911_trigger_ops = {
static int mcp3911_probe(struct spi_device *spi)
{
+ struct device *dev = &spi->dev;
struct iio_dev *indio_dev;
struct mcp3911 *adc;
int ret;
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
if (!indio_dev)
return -ENOMEM;
adc = iio_priv(indio_dev);
adc->spi = spi;
+ adc->chip = spi_get_device_match_data(spi);
- adc->vref = devm_regulator_get_optional(&adc->spi->dev, "vref");
+ adc->vref = devm_regulator_get_optional(dev, "vref");
if (IS_ERR(adc->vref)) {
if (PTR_ERR(adc->vref) == -ENODEV) {
adc->vref = NULL;
} else {
- dev_err(&adc->spi->dev,
- "failed to get regulator (%ld)\n",
- PTR_ERR(adc->vref));
- return PTR_ERR(adc->vref);
+ return dev_err_probe(dev, PTR_ERR(adc->vref), "failed to get regulator\n");
}
} else {
@@ -493,34 +745,35 @@ static int mcp3911_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = devm_add_action_or_reset(&spi->dev,
- mcp3911_cleanup_regulator, adc->vref);
+ ret = devm_add_action_or_reset(dev, mcp3911_cleanup_regulator, adc->vref);
if (ret)
return ret;
}
- adc->clki = devm_clk_get_enabled(&adc->spi->dev, NULL);
+ adc->clki = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(adc->clki)) {
if (PTR_ERR(adc->clki) == -ENOENT) {
adc->clki = NULL;
} else {
- dev_err(&adc->spi->dev,
- "failed to get adc clk (%ld)\n",
- PTR_ERR(adc->clki));
- return PTR_ERR(adc->clki);
+ return dev_err_probe(dev, PTR_ERR(adc->clki), "failed to get adc clk\n");
}
}
- ret = mcp3911_config(adc);
+ /*
+ * Fallback to "device-addr" due to historical mismatch between
+ * dt-bindings and implementation.
+ */
+ ret = device_property_read_u32(dev, "microchip,device-addr", &adc->dev_addr);
if (ret)
- return ret;
+ device_property_read_u32(dev, "device-addr", &adc->dev_addr);
+ if (adc->dev_addr > 3) {
+ return dev_err_probe(dev, -EINVAL,
+ "invalid device address (%i). Must be in range 0-3.\n",
+ adc->dev_addr);
+ }
+ dev_dbg(dev, "use device address %i\n", adc->dev_addr);
- if (device_property_read_bool(&adc->spi->dev, "microchip,data-ready-hiz"))
- ret = mcp3911_update(adc, MCP3911_REG_STATUSCOM, MCP3911_STATUSCOM_DRHIZ,
- 0, 2);
- else
- ret = mcp3911_update(adc, MCP3911_REG_STATUSCOM, MCP3911_STATUSCOM_DRHIZ,
- MCP3911_STATUSCOM_DRHIZ, 2);
+ ret = adc->chip->config(adc);
if (ret)
return ret;
@@ -528,12 +781,12 @@ static int mcp3911_probe(struct spi_device *spi)
if (ret)
return ret;
- /* Set gain to 1 for all channels */
- for (int i = 0; i < MCP3911_NUM_CHANNELS; i++) {
+ /* Set gain to 1 for all channels */
+ for (int i = 0; i < adc->chip->num_channels - 1; i++) {
adc->gain[i] = 1;
ret = mcp3911_update(adc, MCP3911_REG_GAIN,
- MCP3911_GAIN_MASK(i),
- MCP3911_GAIN_VAL(i, 0), 1);
+ MCP3911_GAIN_MASK(i),
+ MCP3911_GAIN_VAL(i, 0), 1);
if (ret)
return ret;
}
@@ -543,21 +796,20 @@ static int mcp3911_probe(struct spi_device *spi)
indio_dev->info = &mcp3911_info;
spi_set_drvdata(spi, indio_dev);
- indio_dev->channels = mcp3911_channels;
- indio_dev->num_channels = ARRAY_SIZE(mcp3911_channels);
+ indio_dev->channels = adc->chip->channels;
+ indio_dev->num_channels = adc->chip->num_channels;
mutex_init(&adc->lock);
if (spi->irq > 0) {
- adc->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d",
- indio_dev->name,
- iio_device_id(indio_dev));
+ adc->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
+ iio_device_id(indio_dev));
if (!adc->trig)
return -ENOMEM;
adc->trig->ops = &mcp3911_trigger_ops;
iio_trigger_set_drvdata(adc->trig, adc);
- ret = devm_iio_trigger_register(&spi->dev, adc->trig);
+ ret = devm_iio_trigger_register(dev, adc->trig);
if (ret)
return ret;
@@ -566,30 +818,120 @@ static int mcp3911_probe(struct spi_device *spi)
* Some platforms might not allow the option to power it down so
* don't enable the interrupt to avoid extra load on the system.
*/
- ret = devm_request_irq(&spi->dev, spi->irq,
- &iio_trigger_generic_data_rdy_poll, IRQF_NO_AUTOEN | IRQF_ONESHOT,
- indio_dev->name, adc->trig);
+ ret = devm_request_irq(dev, spi->irq, &iio_trigger_generic_data_rdy_poll,
+ IRQF_NO_AUTOEN | IRQF_ONESHOT,
+ indio_dev->name, adc->trig);
if (ret)
return ret;
}
- ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
- NULL,
- mcp3911_trigger_handler, NULL);
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+ mcp3911_trigger_handler, NULL);
if (ret)
return ret;
- return devm_iio_device_register(&adc->spi->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
+static const struct mcp3911_chip_info mcp3911_chip_info[] = {
+ [MCP3910] = {
+ .channels = mcp3910_channels,
+ .num_channels = ARRAY_SIZE(mcp3910_channels),
+ .config = mcp3910_config,
+ .get_osr = mcp3910_get_osr,
+ .set_osr = mcp3910_set_osr,
+ .enable_offset = mcp3910_enable_offset,
+ .get_offset = mcp3910_get_offset,
+ .set_offset = mcp3910_set_offset,
+ .set_scale = mcp3910_set_scale,
+ },
+ [MCP3911] = {
+ .channels = mcp3911_channels,
+ .num_channels = ARRAY_SIZE(mcp3911_channels),
+ .config = mcp3911_config,
+ .get_osr = mcp3911_get_osr,
+ .set_osr = mcp3911_set_osr,
+ .enable_offset = mcp3911_enable_offset,
+ .get_offset = mcp3911_get_offset,
+ .set_offset = mcp3911_set_offset,
+ .set_scale = mcp3911_set_scale,
+ },
+ [MCP3912] = {
+ .channels = mcp3912_channels,
+ .num_channels = ARRAY_SIZE(mcp3912_channels),
+ .config = mcp3910_config,
+ .get_osr = mcp3910_get_osr,
+ .set_osr = mcp3910_set_osr,
+ .enable_offset = mcp3910_enable_offset,
+ .get_offset = mcp3910_get_offset,
+ .set_offset = mcp3910_set_offset,
+ .set_scale = mcp3910_set_scale,
+ },
+ [MCP3913] = {
+ .channels = mcp3913_channels,
+ .num_channels = ARRAY_SIZE(mcp3913_channels),
+ .config = mcp3910_config,
+ .get_osr = mcp3910_get_osr,
+ .set_osr = mcp3910_set_osr,
+ .enable_offset = mcp3910_enable_offset,
+ .get_offset = mcp3910_get_offset,
+ .set_offset = mcp3910_set_offset,
+ .set_scale = mcp3910_set_scale,
+ },
+ [MCP3914] = {
+ .channels = mcp3914_channels,
+ .num_channels = ARRAY_SIZE(mcp3914_channels),
+ .config = mcp3910_config,
+ .get_osr = mcp3910_get_osr,
+ .set_osr = mcp3910_set_osr,
+ .enable_offset = mcp3910_enable_offset,
+ .get_offset = mcp3910_get_offset,
+ .set_offset = mcp3910_set_offset,
+ .set_scale = mcp3910_set_scale,
+ },
+ [MCP3918] = {
+ .channels = mcp3918_channels,
+ .num_channels = ARRAY_SIZE(mcp3918_channels),
+ .config = mcp3910_config,
+ .get_osr = mcp3910_get_osr,
+ .set_osr = mcp3910_set_osr,
+ .enable_offset = mcp3910_enable_offset,
+ .get_offset = mcp3910_get_offset,
+ .set_offset = mcp3910_set_offset,
+ .set_scale = mcp3910_set_scale,
+ },
+ [MCP3919] = {
+ .channels = mcp3919_channels,
+ .num_channels = ARRAY_SIZE(mcp3919_channels),
+ .config = mcp3910_config,
+ .get_osr = mcp3910_get_osr,
+ .set_osr = mcp3910_set_osr,
+ .enable_offset = mcp3910_enable_offset,
+ .get_offset = mcp3910_get_offset,
+ .set_offset = mcp3910_set_offset,
+ .set_scale = mcp3910_set_scale,
+ },
+};
static const struct of_device_id mcp3911_dt_ids[] = {
- { .compatible = "microchip,mcp3911" },
+ { .compatible = "microchip,mcp3910", .data = &mcp3911_chip_info[MCP3910] },
+ { .compatible = "microchip,mcp3911", .data = &mcp3911_chip_info[MCP3911] },
+ { .compatible = "microchip,mcp3912", .data = &mcp3911_chip_info[MCP3912] },
+ { .compatible = "microchip,mcp3913", .data = &mcp3911_chip_info[MCP3913] },
+ { .compatible = "microchip,mcp3914", .data = &mcp3911_chip_info[MCP3914] },
+ { .compatible = "microchip,mcp3918", .data = &mcp3911_chip_info[MCP3918] },
+ { .compatible = "microchip,mcp3919", .data = &mcp3911_chip_info[MCP3919] },
{ }
};
MODULE_DEVICE_TABLE(of, mcp3911_dt_ids);
static const struct spi_device_id mcp3911_id[] = {
- { "mcp3911", 0 },
+ { "mcp3910", (kernel_ulong_t)&mcp3911_chip_info[MCP3910] },
+ { "mcp3911", (kernel_ulong_t)&mcp3911_chip_info[MCP3911] },
+ { "mcp3912", (kernel_ulong_t)&mcp3911_chip_info[MCP3912] },
+ { "mcp3913", (kernel_ulong_t)&mcp3911_chip_info[MCP3913] },
+ { "mcp3914", (kernel_ulong_t)&mcp3911_chip_info[MCP3914] },
+ { "mcp3918", (kernel_ulong_t)&mcp3911_chip_info[MCP3918] },
+ { "mcp3919", (kernel_ulong_t)&mcp3911_chip_info[MCP3919] },
{ }
};
MODULE_DEVICE_TABLE(spi, mcp3911_id);
diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
index 57cfabe80c..13b473d8c6 100644
--- a/drivers/iio/adc/meson_saradc.c
+++ b/drivers/iio/adc/meson_saradc.c
@@ -1045,8 +1045,10 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev)
u32 regval;
ret = meson_sar_adc_lock(indio_dev);
- if (ret)
+ if (ret) {
+ dev_err(dev, "failed to lock adc\n");
goto err_lock;
+ }
ret = regulator_enable(priv->vref);
if (ret < 0) {
@@ -1368,15 +1370,15 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
priv->regmap = devm_regmap_init_mmio(dev, base, priv->param->regmap_config);
if (IS_ERR(priv->regmap))
- return PTR_ERR(priv->regmap);
+ return dev_err_probe(dev, PTR_ERR(priv->regmap), "failed to init regmap\n");
irq = irq_of_parse_and_map(dev->of_node, 0);
if (!irq)
- return -EINVAL;
+ return dev_err_probe(dev, -EINVAL, "failed to get irq\n");
ret = devm_request_irq(dev, irq, meson_sar_adc_irq, IRQF_SHARED, dev_name(dev), indio_dev);
if (ret)
- return ret;
+ return dev_err_probe(dev, ret, "failed to request irq\n");
priv->clkin = devm_clk_get(dev, "clkin");
if (IS_ERR(priv->clkin))
@@ -1398,7 +1400,7 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
if (!priv->adc_clk) {
ret = meson_sar_adc_clk_init(indio_dev, base);
if (ret)
- return ret;
+ return dev_err_probe(dev, ret, "failed to init internal clk\n");
}
priv->vref = devm_regulator_get(dev, "vref");
@@ -1440,8 +1442,10 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, indio_dev);
ret = iio_device_register(indio_dev);
- if (ret)
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to register iio device\n");
goto err_hw;
+ }
return 0;
@@ -1451,15 +1455,13 @@ err:
return ret;
}
-static int meson_sar_adc_remove(struct platform_device *pdev)
+static void meson_sar_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
iio_device_unregister(indio_dev);
meson_sar_adc_hw_disable(indio_dev);
-
- return 0;
}
static int meson_sar_adc_suspend(struct device *dev)
@@ -1494,7 +1496,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(meson_sar_adc_pm_ops,
static struct platform_driver meson_sar_adc_driver = {
.probe = meson_sar_adc_probe,
- .remove = meson_sar_adc_remove,
+ .remove_new = meson_sar_adc_remove,
.driver = {
.name = "meson-saradc",
.of_match_table = meson_sar_adc_of_match,
diff --git a/drivers/iio/adc/mp2629_adc.c b/drivers/iio/adc/mp2629_adc.c
index 88e947f300..7c66c2cd5b 100644
--- a/drivers/iio/adc/mp2629_adc.c
+++ b/drivers/iio/adc/mp2629_adc.c
@@ -171,7 +171,7 @@ fail_disable:
return ret;
}
-static int mp2629_adc_remove(struct platform_device *pdev)
+static void mp2629_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct mp2629_adc *info = iio_priv(indio_dev);
@@ -184,8 +184,6 @@ static int mp2629_adc_remove(struct platform_device *pdev)
MP2629_ADC_CONTINUOUS, 0);
regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL,
MP2629_ADC_START, 0);
-
- return 0;
}
static const struct of_device_id mp2629_adc_of_match[] = {
@@ -200,7 +198,7 @@ static struct platform_driver mp2629_adc_driver = {
.of_match_table = mp2629_adc_of_match,
},
.probe = mp2629_adc_probe,
- .remove = mp2629_adc_remove,
+ .remove_new = mp2629_adc_remove,
};
module_platform_driver(mp2629_adc_driver);
diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c
index 0e134777bd..3343b54e8e 100644
--- a/drivers/iio/adc/mt6577_auxadc.c
+++ b/drivers/iio/adc/mt6577_auxadc.c
@@ -246,6 +246,14 @@ static int mt6577_auxadc_suspend(struct device *dev)
return 0;
}
+static void mt6577_power_off(void *data)
+{
+ struct mt6577_auxadc_device *adc_dev = data;
+
+ mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
+ 0, MT6577_AUXADC_PDN_EN);
+}
+
static int mt6577_auxadc_probe(struct platform_device *pdev)
{
struct mt6577_auxadc_device *adc_dev;
@@ -265,29 +273,18 @@ static int mt6577_auxadc_probe(struct platform_device *pdev)
indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels);
adc_dev->reg_base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(adc_dev->reg_base)) {
- dev_err(&pdev->dev, "failed to get auxadc base address\n");
- return PTR_ERR(adc_dev->reg_base);
- }
-
- adc_dev->adc_clk = devm_clk_get(&pdev->dev, "main");
- if (IS_ERR(adc_dev->adc_clk)) {
- dev_err(&pdev->dev, "failed to get auxadc clock\n");
- return PTR_ERR(adc_dev->adc_clk);
- }
+ if (IS_ERR(adc_dev->reg_base))
+ return dev_err_probe(&pdev->dev, PTR_ERR(adc_dev->reg_base),
+ "failed to get auxadc base address\n");
- ret = clk_prepare_enable(adc_dev->adc_clk);
- if (ret) {
- dev_err(&pdev->dev, "failed to enable auxadc clock\n");
- return ret;
- }
+ adc_dev->adc_clk = devm_clk_get_enabled(&pdev->dev, "main");
+ if (IS_ERR(adc_dev->adc_clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(adc_dev->adc_clk),
+ "failed to enable auxadc clock\n");
adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
- if (!adc_clk_rate) {
- ret = -EINVAL;
- dev_err(&pdev->dev, "null clock rate\n");
- goto err_disable_clk;
- }
+ if (!adc_clk_rate)
+ return dev_err_probe(&pdev->dev, -EINVAL, "null clock rate\n");
adc_dev->dev_comp = device_get_match_data(&pdev->dev);
@@ -296,36 +293,16 @@ static int mt6577_auxadc_probe(struct platform_device *pdev)
mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
MT6577_AUXADC_PDN_EN, 0);
mdelay(MT6577_AUXADC_POWER_READY_MS);
-
platform_set_drvdata(pdev, indio_dev);
- ret = iio_device_register(indio_dev);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to register iio device\n");
- goto err_power_off;
- }
-
- return 0;
-
-err_power_off:
- mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
- 0, MT6577_AUXADC_PDN_EN);
-err_disable_clk:
- clk_disable_unprepare(adc_dev->adc_clk);
- return ret;
-}
-
-static int mt6577_auxadc_remove(struct platform_device *pdev)
-{
- struct iio_dev *indio_dev = platform_get_drvdata(pdev);
- struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
+ ret = devm_add_action_or_reset(&pdev->dev, mt6577_power_off, adc_dev);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to add action to managed power off\n");
- mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
- 0, MT6577_AUXADC_PDN_EN);
-
- clk_disable_unprepare(adc_dev->adc_clk);
+ ret = devm_iio_device_register(&pdev->dev, indio_dev);
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret, "failed to register iio device\n");
return 0;
}
@@ -352,7 +329,6 @@ static struct platform_driver mt6577_auxadc_driver = {
.pm = pm_sleep_ptr(&mt6577_auxadc_pm_ops),
},
.probe = mt6577_auxadc_probe,
- .remove = mt6577_auxadc_remove,
};
module_platform_driver(mt6577_auxadc_driver);
diff --git a/drivers/iio/adc/mxs-lradc-adc.c b/drivers/iio/adc/mxs-lradc-adc.c
index a50f39143d..2e60c10ee4 100644
--- a/drivers/iio/adc/mxs-lradc-adc.c
+++ b/drivers/iio/adc/mxs-lradc-adc.c
@@ -807,7 +807,7 @@ err_trig:
return ret;
}
-static int mxs_lradc_adc_remove(struct platform_device *pdev)
+static void mxs_lradc_adc_remove(struct platform_device *pdev)
{
struct iio_dev *iio = platform_get_drvdata(pdev);
struct mxs_lradc_adc *adc = iio_priv(iio);
@@ -816,8 +816,6 @@ static int mxs_lradc_adc_remove(struct platform_device *pdev)
mxs_lradc_adc_hw_stop(adc);
iio_triggered_buffer_cleanup(iio);
mxs_lradc_adc_trigger_remove(iio);
-
- return 0;
}
static struct platform_driver mxs_lradc_adc_driver = {
@@ -825,7 +823,7 @@ static struct platform_driver mxs_lradc_adc_driver = {
.name = "mxs-lradc-adc",
},
.probe = mxs_lradc_adc_probe,
- .remove = mxs_lradc_adc_remove,
+ .remove_new = mxs_lradc_adc_remove,
};
module_platform_driver(mxs_lradc_adc_driver);
diff --git a/drivers/iio/adc/npcm_adc.c b/drivers/iio/adc/npcm_adc.c
index 3d9207c160..3a55465951 100644
--- a/drivers/iio/adc/npcm_adc.c
+++ b/drivers/iio/adc/npcm_adc.c
@@ -320,7 +320,7 @@ err_disable_clk:
return ret;
}
-static int npcm_adc_remove(struct platform_device *pdev)
+static void npcm_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct npcm_adc *info = iio_priv(indio_dev);
@@ -333,13 +333,11 @@ static int npcm_adc_remove(struct platform_device *pdev)
if (!IS_ERR(info->vref))
regulator_disable(info->vref);
clk_disable_unprepare(info->adc_clk);
-
- return 0;
}
static struct platform_driver npcm_adc_driver = {
.probe = npcm_adc_probe,
- .remove = npcm_adc_remove,
+ .remove_new = npcm_adc_remove,
.driver = {
.name = "npcm_adc",
.of_match_table = npcm_adc_match,
diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c
index e202ea18af..203cbbc707 100644
--- a/drivers/iio/adc/palmas_gpadc.c
+++ b/drivers/iio/adc/palmas_gpadc.c
@@ -457,7 +457,7 @@ static int palmas_gpadc_get_calibrated_code(struct palmas_gpadc *adc,
*
* The gain error include both gain error, as specified in the datasheet, and
* the gain error drift. These paramenters vary depending on device and whether
- * the the channel is calibrated (trimmed) or not.
+ * the channel is calibrated (trimmed) or not.
*/
static int palmas_gpadc_threshold_with_tolerance(int val, const int INL,
const int gain_error,
diff --git a/drivers/iio/adc/qcom-pm8xxx-xoadc.c b/drivers/iio/adc/qcom-pm8xxx-xoadc.c
index 64a3aeb626..01c5586df5 100644
--- a/drivers/iio/adc/qcom-pm8xxx-xoadc.c
+++ b/drivers/iio/adc/qcom-pm8xxx-xoadc.c
@@ -957,7 +957,7 @@ out_disable_vref:
return ret;
}
-static int pm8xxx_xoadc_remove(struct platform_device *pdev)
+static void pm8xxx_xoadc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct pm8xxx_xoadc *adc = iio_priv(indio_dev);
@@ -965,8 +965,6 @@ static int pm8xxx_xoadc_remove(struct platform_device *pdev)
iio_device_unregister(indio_dev);
regulator_disable(adc->vref);
-
- return 0;
}
static const struct xoadc_variant pm8018_variant = {
@@ -1019,7 +1017,7 @@ static struct platform_driver pm8xxx_xoadc_driver = {
.of_match_table = pm8xxx_xoadc_id_table,
},
.probe = pm8xxx_xoadc_probe,
- .remove = pm8xxx_xoadc_remove,
+ .remove_new = pm8xxx_xoadc_remove,
};
module_platform_driver(pm8xxx_xoadc_driver);
diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c
index b8972f673c..d524f2e8e9 100644
--- a/drivers/iio/adc/rcar-gyroadc.c
+++ b/drivers/iio/adc/rcar-gyroadc.c
@@ -559,7 +559,7 @@ err_clk_if_enable:
return ret;
}
-static int rcar_gyroadc_remove(struct platform_device *pdev)
+static void rcar_gyroadc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct rcar_gyroadc *priv = iio_priv(indio_dev);
@@ -573,8 +573,6 @@ static int rcar_gyroadc_remove(struct platform_device *pdev)
pm_runtime_set_suspended(dev);
clk_disable_unprepare(priv->clk);
rcar_gyroadc_deinit_supplies(indio_dev);
-
- return 0;
}
static int rcar_gyroadc_suspend(struct device *dev)
@@ -603,7 +601,7 @@ static const struct dev_pm_ops rcar_gyroadc_pm_ops = {
static struct platform_driver rcar_gyroadc_driver = {
.probe = rcar_gyroadc_probe,
- .remove = rcar_gyroadc_remove,
+ .remove_new = rcar_gyroadc_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = rcar_gyroadc_match,
diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c
index ad54ef7981..71362c2ddf 100644
--- a/drivers/iio/adc/spear_adc.c
+++ b/drivers/iio/adc/spear_adc.c
@@ -274,10 +274,9 @@ static int spear_adc_probe(struct platform_device *pdev)
int irq;
indio_dev = devm_iio_device_alloc(dev, sizeof(struct spear_adc_state));
- if (!indio_dev) {
- dev_err(dev, "failed allocating iio device\n");
- return -ENOMEM;
- }
+ if (!indio_dev)
+ return dev_err_probe(dev, -ENOMEM,
+ "failed allocating iio device\n");
st = iio_priv(indio_dev);
@@ -297,37 +296,24 @@ static int spear_adc_probe(struct platform_device *pdev)
st->adc_base_spear3xx =
(struct adc_regs_spear3xx __iomem *)st->adc_base_spear6xx;
- st->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(st->clk)) {
- dev_err(dev, "failed getting clock\n");
- return PTR_ERR(st->clk);
- }
-
- ret = clk_prepare_enable(st->clk);
- if (ret) {
- dev_err(dev, "failed enabling clock\n");
- return ret;
- }
+ st->clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(st->clk))
+ return dev_err_probe(dev, PTR_ERR(st->clk),
+ "failed enabling clock\n");
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- ret = irq;
- goto errout2;
- }
+ if (irq < 0)
+ return irq;
ret = devm_request_irq(dev, irq, spear_adc_isr, 0, SPEAR_ADC_MOD_NAME,
st);
- if (ret < 0) {
- dev_err(dev, "failed requesting interrupt\n");
- goto errout2;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed requesting interrupt\n");
if (of_property_read_u32(np, "sampling-frequency",
- &st->sampling_freq)) {
- dev_err(dev, "sampling-frequency missing in DT\n");
- ret = -EINVAL;
- goto errout2;
- }
+ &st->sampling_freq))
+ return dev_err_probe(dev, -EINVAL,
+ "sampling-frequency missing in DT\n");
/*
* Optional avg_samples defaults to 0, resulting in single data
@@ -343,8 +329,6 @@ static int spear_adc_probe(struct platform_device *pdev)
spear_adc_configure(st);
- platform_set_drvdata(pdev, indio_dev);
-
init_completion(&st->completion);
indio_dev->name = SPEAR_ADC_MOD_NAME;
@@ -353,28 +337,13 @@ static int spear_adc_probe(struct platform_device *pdev)
indio_dev->channels = spear_adc_iio_channels;
indio_dev->num_channels = ARRAY_SIZE(spear_adc_iio_channels);
- ret = iio_device_register(indio_dev);
+ ret = devm_iio_device_register(dev, indio_dev);
if (ret)
- goto errout2;
+ return ret;
dev_info(dev, "SPEAR ADC driver loaded, IRQ %d\n", irq);
return 0;
-
-errout2:
- clk_disable_unprepare(st->clk);
- return ret;
-}
-
-static int spear_adc_remove(struct platform_device *pdev)
-{
- struct iio_dev *indio_dev = platform_get_drvdata(pdev);
- struct spear_adc_state *st = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- clk_disable_unprepare(st->clk);
-
- return 0;
}
#ifdef CONFIG_OF
@@ -387,7 +356,6 @@ MODULE_DEVICE_TABLE(of, spear_adc_dt_ids);
static struct platform_driver spear_adc_driver = {
.probe = spear_adc_probe,
- .remove = spear_adc_remove,
.driver = {
.name = SPEAR_ADC_MOD_NAME,
.of_match_table = of_match_ptr(spear_adc_dt_ids),
diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index bbd5bdd732..616dd72966 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -17,10 +17,11 @@
#include <linux/irqdomain.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -708,8 +709,6 @@ static int stm32_adc_probe(struct platform_device *pdev)
struct stm32_adc_priv *priv;
struct device *dev = &pdev->dev;
struct device_node *np = pdev->dev.of_node;
- const struct of_device_id *of_id;
-
struct resource *res;
u32 max_rate;
int ret;
@@ -722,11 +721,7 @@ static int stm32_adc_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, &priv->common);
- of_id = of_match_device(dev->driver->of_match_table, dev);
- if (!of_id)
- return -ENODEV;
-
- priv->cfg = (const struct stm32_adc_priv_cfg *)of_id->data;
+ priv->cfg = device_get_match_data(dev);
priv->nb_adc_max = priv->cfg->num_adcs;
spin_lock_init(&priv->common.lock);
@@ -819,7 +814,7 @@ err_pm_stop:
return ret;
}
-static int stm32_adc_remove(struct platform_device *pdev)
+static void stm32_adc_remove(struct platform_device *pdev)
{
struct stm32_adc_common *common = platform_get_drvdata(pdev);
struct stm32_adc_priv *priv = to_stm32_adc_priv(common);
@@ -831,8 +826,6 @@ static int stm32_adc_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
-
- return 0;
}
static int stm32_adc_core_runtime_suspend(struct device *dev)
@@ -913,7 +906,7 @@ MODULE_DEVICE_TABLE(of, stm32_adc_of_match);
static struct platform_driver stm32_adc_driver = {
.probe = stm32_adc_probe,
- .remove = stm32_adc_remove,
+ .remove_new = stm32_adc_remove,
.driver = {
.name = "stm32-adc-core",
.of_match_table = stm32_adc_of_match,
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index f7613efb87..b5d3c9cea5 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -2209,7 +2209,7 @@ static int stm32_adc_generic_chan_init(struct iio_dev *indio_dev,
ret = -EINVAL;
goto err;
}
- strncpy(adc->chan_name[val], name, STM32_ADC_CH_SZ);
+ strscpy(adc->chan_name[val], name, STM32_ADC_CH_SZ);
ret = stm32_adc_populate_int_ch(indio_dev, name, val);
if (ret == -ENOENT)
continue;
@@ -2513,7 +2513,7 @@ err_dma_disable:
return ret;
}
-static int stm32_adc_remove(struct platform_device *pdev)
+static void stm32_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct stm32_adc *adc = iio_priv(indio_dev);
@@ -2532,8 +2532,6 @@ static int stm32_adc_remove(struct platform_device *pdev)
adc->rx_buf, adc->rx_dma_buf);
dma_release_channel(adc->dma_chan);
}
-
- return 0;
}
static int stm32_adc_suspend(struct device *dev)
@@ -2659,7 +2657,7 @@ MODULE_DEVICE_TABLE(of, stm32_adc_of_match);
static struct platform_driver stm32_adc_driver = {
.probe = stm32_adc_probe,
- .remove = stm32_adc_remove,
+ .remove_new = stm32_adc_remove,
.driver = {
.name = "stm32-adc",
.of_match_table = stm32_adc_of_match,
diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c
index b5cc43d12b..ca08ae3108 100644
--- a/drivers/iio/adc/stm32-dfsdm-adc.c
+++ b/drivers/iio/adc/stm32-dfsdm-adc.c
@@ -1620,7 +1620,7 @@ err_cleanup:
return ret;
}
-static int stm32_dfsdm_adc_remove(struct platform_device *pdev)
+static void stm32_dfsdm_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
@@ -1629,8 +1629,6 @@ static int stm32_dfsdm_adc_remove(struct platform_device *pdev)
of_platform_depopulate(&pdev->dev);
iio_device_unregister(indio_dev);
stm32_dfsdm_dma_release(indio_dev);
-
- return 0;
}
static int stm32_dfsdm_adc_suspend(struct device *dev)
@@ -1677,7 +1675,7 @@ static struct platform_driver stm32_dfsdm_adc_driver = {
.pm = pm_sleep_ptr(&stm32_dfsdm_adc_pm_ops),
},
.probe = stm32_dfsdm_adc_probe,
- .remove = stm32_dfsdm_adc_remove,
+ .remove_new = stm32_dfsdm_adc_remove,
};
module_platform_driver(stm32_dfsdm_adc_driver);
diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c
index 0f6ebb3061..a05d978b8c 100644
--- a/drivers/iio/adc/stm32-dfsdm-core.c
+++ b/drivers/iio/adc/stm32-dfsdm-core.c
@@ -436,7 +436,7 @@ pm_put:
return ret;
}
-static int stm32_dfsdm_core_remove(struct platform_device *pdev)
+static void stm32_dfsdm_core_remove(struct platform_device *pdev)
{
struct stm32_dfsdm *dfsdm = platform_get_drvdata(pdev);
@@ -446,8 +446,6 @@ static int stm32_dfsdm_core_remove(struct platform_device *pdev)
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
stm32_dfsdm_clk_disable_unprepare(dfsdm);
-
- return 0;
}
static int stm32_dfsdm_core_suspend(struct device *dev)
@@ -508,7 +506,7 @@ static const struct dev_pm_ops stm32_dfsdm_core_pm_ops = {
static struct platform_driver stm32_dfsdm_driver = {
.probe = stm32_dfsdm_probe,
- .remove = stm32_dfsdm_core_remove,
+ .remove_new = stm32_dfsdm_core_remove,
.driver = {
.name = "stm32-dfsdm",
.of_match_table = stm32_dfsdm_of_match,
diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index 25bba96367..100ecced5f 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -669,7 +669,7 @@ err_map:
return ret;
}
-static int sun4i_gpadc_remove(struct platform_device *pdev)
+static void sun4i_gpadc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
@@ -678,12 +678,10 @@ static int sun4i_gpadc_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
if (!IS_ENABLED(CONFIG_THERMAL_OF))
- return 0;
+ return;
if (!info->no_irq)
iio_map_array_unregister(indio_dev);
-
- return 0;
}
static const struct platform_device_id sun4i_gpadc_id[] = {
@@ -702,7 +700,7 @@ static struct platform_driver sun4i_gpadc_driver = {
},
.id_table = sun4i_gpadc_id,
.probe = sun4i_gpadc_probe,
- .remove = sun4i_gpadc_remove,
+ .remove_new = sun4i_gpadc_remove,
};
MODULE_DEVICE_TABLE(of, sun4i_gpadc_of_id);
diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c
index 50c450e7a5..6c2cb3dabb 100644
--- a/drivers/iio/adc/ti-adc081c.c
+++ b/drivers/iio/adc/ti-adc081c.c
@@ -154,7 +154,6 @@ static void adc081c_reg_disable(void *reg)
static int adc081c_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct iio_dev *iio;
struct adc081c *adc;
const struct adcxx1c_model *model;
@@ -163,10 +162,7 @@ static int adc081c_probe(struct i2c_client *client)
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -EOPNOTSUPP;
- if (dev_fwnode(&client->dev))
- model = device_get_match_data(&client->dev);
- else
- model = &adcxx1c_models[id->driver_data];
+ model = i2c_get_match_data(client);
iio = devm_iio_device_alloc(&client->dev, sizeof(*adc));
if (!iio)
@@ -207,9 +203,9 @@ static int adc081c_probe(struct i2c_client *client)
}
static const struct i2c_device_id adc081c_id[] = {
- { "adc081c", ADC081C },
- { "adc101c", ADC101C },
- { "adc121c", ADC121C },
+ { "adc081c", (kernel_ulong_t)&adcxx1c_models[ADC081C] },
+ { "adc101c", (kernel_ulong_t)&adcxx1c_models[ADC101C] },
+ { "adc121c", (kernel_ulong_t)&adcxx1c_models[ADC121C] },
{ }
};
MODULE_DEVICE_TABLE(i2c, adc081c_id);
diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c
index 075c75a875..6799ea49db 100644
--- a/drivers/iio/adc/ti-ads1015.c
+++ b/drivers/iio/adc/ti-ads1015.c
@@ -976,16 +976,13 @@ static int ads1015_set_conv_mode(struct ads1015_data *data, int mode)
static int ads1015_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
const struct ads1015_chip_data *chip;
struct iio_dev *indio_dev;
struct ads1015_data *data;
int ret;
int i;
- chip = device_get_match_data(&client->dev);
- if (!chip)
- chip = (const struct ads1015_chip_data *)id->driver_data;
+ chip = i2c_get_match_data(client);
if (!chip)
return dev_err_probe(&client->dev, -EINVAL, "Unknown chip\n");
@@ -1047,11 +1044,13 @@ static int ads1015_probe(struct i2c_client *client)
1 << ADS1015_CFG_COMP_LAT_SHIFT;
switch (irq_trig) {
+ case IRQF_TRIGGER_FALLING:
case IRQF_TRIGGER_LOW:
cfg_comp |= ADS1015_CFG_COMP_POL_LOW <<
ADS1015_CFG_COMP_POL_SHIFT;
break;
case IRQF_TRIGGER_HIGH:
+ case IRQF_TRIGGER_RISING:
cfg_comp |= ADS1015_CFG_COMP_POL_HIGH <<
ADS1015_CFG_COMP_POL_SHIFT;
break;
diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
index 5f87959869..95fa857e8a 100644
--- a/drivers/iio/adc/ti_am335x_adc.c
+++ b/drivers/iio/adc/ti_am335x_adc.c
@@ -683,7 +683,7 @@ err_dma:
return err;
}
-static int tiadc_remove(struct platform_device *pdev)
+static void tiadc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct tiadc_device *adc_dev = iio_priv(indio_dev);
@@ -699,8 +699,6 @@ static int tiadc_remove(struct platform_device *pdev)
step_en = get_adc_step_mask(adc_dev);
am335x_tsc_se_clr(adc_dev->mfd_tscadc, step_en);
-
- return 0;
}
static int tiadc_suspend(struct device *dev)
@@ -749,7 +747,7 @@ static struct platform_driver tiadc_driver = {
.of_match_table = ti_adc_dt_ids,
},
.probe = tiadc_probe,
- .remove = tiadc_remove,
+ .remove_new = tiadc_remove,
};
module_platform_driver(tiadc_driver);
diff --git a/drivers/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c
index c279c4f2c9..4a247ca25a 100644
--- a/drivers/iio/adc/twl4030-madc.c
+++ b/drivers/iio/adc/twl4030-madc.c
@@ -892,7 +892,7 @@ err_current_generator:
return ret;
}
-static int twl4030_madc_remove(struct platform_device *pdev)
+static void twl4030_madc_remove(struct platform_device *pdev)
{
struct iio_dev *iio_dev = platform_get_drvdata(pdev);
struct twl4030_madc_data *madc = iio_priv(iio_dev);
@@ -903,8 +903,6 @@ static int twl4030_madc_remove(struct platform_device *pdev)
twl4030_madc_set_power(madc, 0);
regulator_disable(madc->usb3v1);
-
- return 0;
}
#ifdef CONFIG_OF
@@ -917,7 +915,7 @@ MODULE_DEVICE_TABLE(of, twl_madc_of_match);
static struct platform_driver twl4030_madc_driver = {
.probe = twl4030_madc_probe,
- .remove = twl4030_madc_remove,
+ .remove_new = twl4030_madc_remove,
.driver = {
.name = "twl4030_madc",
.of_match_table = of_match_ptr(twl_madc_of_match),
diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c
index 32873fb5f3..78bf55438b 100644
--- a/drivers/iio/adc/twl6030-gpadc.c
+++ b/drivers/iio/adc/twl6030-gpadc.c
@@ -16,9 +16,10 @@
*/
#include <linux/interrupt.h>
#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/of_platform.h>
+#include <linux/property.h>
#include <linux/mfd/twl.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -879,17 +880,14 @@ static int twl6030_gpadc_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct twl6030_gpadc_data *gpadc;
const struct twl6030_gpadc_platform_data *pdata;
- const struct of_device_id *match;
struct iio_dev *indio_dev;
int irq;
int ret;
- match = of_match_device(of_twl6030_match_tbl, dev);
- if (!match)
+ pdata = device_get_match_data(&pdev->dev);
+ if (!pdata)
return -EINVAL;
- pdata = match->data;
-
indio_dev = devm_iio_device_alloc(dev, sizeof(*gpadc));
if (!indio_dev)
return -ENOMEM;
@@ -968,14 +966,12 @@ static int twl6030_gpadc_probe(struct platform_device *pdev)
return iio_device_register(indio_dev);
}
-static int twl6030_gpadc_remove(struct platform_device *pdev)
+static void twl6030_gpadc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
twl6030_gpadc_disable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK);
iio_device_unregister(indio_dev);
-
- return 0;
}
static int twl6030_gpadc_suspend(struct device *pdev)
@@ -1007,7 +1003,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(twl6030_gpadc_pm_ops, twl6030_gpadc_suspend,
static struct platform_driver twl6030_gpadc_driver = {
.probe = twl6030_gpadc_probe,
- .remove = twl6030_gpadc_remove,
+ .remove_new = twl6030_gpadc_remove,
.driver = {
.name = DRIVER_NAME,
.pm = pm_sleep_ptr(&twl6030_gpadc_pm_ops),
diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
index ae31aafd26..e4548df3f8 100644
--- a/drivers/iio/adc/vf610_adc.c
+++ b/drivers/iio/adc/vf610_adc.c
@@ -916,7 +916,7 @@ error_adc_clk_enable:
return ret;
}
-static int vf610_adc_remove(struct platform_device *pdev)
+static void vf610_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct vf610_adc *info = iio_priv(indio_dev);
@@ -925,8 +925,6 @@ static int vf610_adc_remove(struct platform_device *pdev)
iio_triggered_buffer_cleanup(indio_dev);
regulator_disable(info->vref);
clk_disable_unprepare(info->clk);
-
- return 0;
}
static int vf610_adc_suspend(struct device *dev)
@@ -974,7 +972,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops, vf610_adc_suspend,
static struct platform_driver vf610_adc_driver = {
.probe = vf610_adc_probe,
- .remove = vf610_adc_remove,
+ .remove_new = vf610_adc_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = vf610_adc_match,
diff --git a/drivers/iio/addac/Kconfig b/drivers/iio/addac/Kconfig
index 397544f23b..16876b8b5c 100644
--- a/drivers/iio/addac/Kconfig
+++ b/drivers/iio/addac/Kconfig
@@ -40,6 +40,7 @@ config STX104
select REGMAP_MMIO
select GPIOLIB
select GPIO_REGMAP
+ select I8254
help
Say yes here to build support for the Apex Embedded Systems STX104
integrated analog PC/104 card.
diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c
index 6b0e8218f1..7af3e4b8fe 100644
--- a/drivers/iio/addac/ad74413r.c
+++ b/drivers/iio/addac/ad74413r.c
@@ -442,11 +442,29 @@ static int ad74413r_set_channel_function(struct ad74413r_state *st,
int ret;
ret = regmap_update_bits(st->regmap,
+ AD74413R_REG_CH_FUNC_SETUP_X(channel),
+ AD74413R_CH_FUNC_SETUP_MASK,
+ CH_FUNC_HIGH_IMPEDANCE);
+ if (ret)
+ return ret;
+
+ /* Set DAC code to 0 prior to changing channel function */
+ ret = ad74413r_set_channel_dac_code(st, channel, 0);
+ if (ret)
+ return ret;
+
+ /* Delay required before transition to new desired mode */
+ usleep_range(130, 150);
+
+ ret = regmap_update_bits(st->regmap,
AD74413R_REG_CH_FUNC_SETUP_X(channel),
AD74413R_CH_FUNC_SETUP_MASK, func);
if (ret)
return ret;
+ /* Delay required before updating the new DAC code */
+ usleep_range(150, 170);
+
if (func == CH_FUNC_CURRENT_INPUT_LOOP_POWER)
ret = regmap_set_bits(st->regmap,
AD74413R_REG_ADC_CONFIG_X(channel),
@@ -705,8 +723,8 @@ static int ad74413r_get_input_current_scale(struct ad74413r_state *st,
return IIO_VAL_FRACTIONAL;
}
-static int ad74413_get_input_current_offset(struct ad74413r_state *st,
- unsigned int channel, int *val)
+static int ad74413r_get_input_current_offset(struct ad74413r_state *st,
+ unsigned int channel, int *val)
{
unsigned int range;
int voltage_range;
@@ -991,7 +1009,7 @@ static int ad74413r_read_raw(struct iio_dev *indio_dev,
return ad74413r_get_input_voltage_offset(st,
chan->channel, val);
case IIO_CURRENT:
- return ad74413_get_input_current_offset(st,
+ return ad74413r_get_input_current_offset(st,
chan->channel, val);
default:
return -EINVAL;
diff --git a/drivers/iio/addac/stx104.c b/drivers/iio/addac/stx104.c
index d1f7ce033b..6946a65512 100644
--- a/drivers/iio/addac/stx104.c
+++ b/drivers/iio/addac/stx104.c
@@ -8,6 +8,7 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio/regmap.h>
+#include <linux/i8254.h>
#include <linux/iio/iio.h>
#include <linux/iio/types.h>
#include <linux/isa.h>
@@ -55,6 +56,7 @@ MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses");
#define STX104_ADC_STATUS (STX104_AIO_BASE + 0x8)
#define STX104_ADC_CONTROL (STX104_AIO_BASE + 0x9)
#define STX104_ADC_CONFIGURATION (STX104_AIO_BASE + 0x11)
+#define STX104_I8254_BASE (STX104_AIO_BASE + 0x12)
#define STX104_AIO_DATA_STRIDE 2
#define STX104_DAC_OFFSET(_channel) (STX104_DAC_BASE + STX104_AIO_DATA_STRIDE * (_channel))
@@ -77,6 +79,7 @@ MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses");
/* ADC Configuration */
#define STX104_GAIN GENMASK(1, 0)
#define STX104_ADBU BIT(2)
+#define STX104_RBK GENMASK(7, 4)
#define STX104_BIPOLAR 0
#define STX104_GAIN_X1 0
#define STX104_GAIN_X2 1
@@ -168,6 +171,32 @@ static const struct regmap_config dio_regmap_config = {
.io_port = true,
};
+static const struct regmap_range pit_wr_ranges[] = {
+ regmap_reg_range(0x0, 0x3),
+};
+static const struct regmap_range pit_rd_ranges[] = {
+ regmap_reg_range(0x0, 0x2),
+};
+static const struct regmap_access_table pit_wr_table = {
+ .yes_ranges = pit_wr_ranges,
+ .n_yes_ranges = ARRAY_SIZE(pit_wr_ranges),
+};
+static const struct regmap_access_table pit_rd_table = {
+ .yes_ranges = pit_rd_ranges,
+ .n_yes_ranges = ARRAY_SIZE(pit_rd_ranges),
+};
+
+static const struct regmap_config pit_regmap_config = {
+ .name = "i8254",
+ .reg_bits = 8,
+ .reg_stride = 1,
+ .reg_base = STX104_I8254_BASE,
+ .val_bits = 8,
+ .io_port = true,
+ .wr_table = &pit_wr_table,
+ .rd_table = &pit_rd_table,
+};
+
static int stx104_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{
@@ -339,6 +368,21 @@ static const char *stx104_names[STX104_NGPIO] = {
"DIN0", "DIN1", "DIN2", "DIN3", "DOUT0", "DOUT1", "DOUT2", "DOUT3"
};
+static int bank_select_i8254(struct regmap *map)
+{
+ const u8 select_i8254[] = { 0x3, 0xB, 0xA };
+ size_t i;
+ int err;
+
+ for (i = 0; i < ARRAY_SIZE(select_i8254); i++) {
+ err = regmap_write_bits(map, STX104_ADC_CONFIGURATION, STX104_RBK, select_i8254[i]);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
static int stx104_init_hw(struct stx104_iio *const priv)
{
int err;
@@ -361,7 +405,7 @@ static int stx104_init_hw(struct stx104_iio *const priv)
if (err)
return err;
- return 0;
+ return bank_select_i8254(priv->aio_ctl_map);
}
static int stx104_probe(struct device *dev, unsigned int id)
@@ -369,6 +413,7 @@ static int stx104_probe(struct device *dev, unsigned int id)
struct iio_dev *indio_dev;
struct stx104_iio *priv;
struct gpio_regmap_config gpio_config;
+ struct i8254_regmap_config pit_config;
void __iomem *stx104_base;
struct regmap *aio_ctl_map;
struct regmap *aio_data_map;
@@ -406,6 +451,11 @@ static int stx104_probe(struct device *dev, unsigned int id)
return dev_err_probe(dev, PTR_ERR(dio_map),
"Unable to initialize dio register map\n");
+ pit_config.map = devm_regmap_init_mmio(dev, stx104_base, &pit_regmap_config);
+ if (IS_ERR(pit_config.map))
+ return dev_err_probe(dev, PTR_ERR(pit_config.map),
+ "Unable to initialize i8254 register map\n");
+
priv = iio_priv(indio_dev);
priv->aio_ctl_map = aio_ctl_map;
priv->aio_data_map = aio_data_map;
@@ -449,7 +499,13 @@ static int stx104_probe(struct device *dev, unsigned int id)
.drvdata = dio_map,
};
- return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config));
+ err = PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config));
+ if (err)
+ return err;
+
+ pit_config.parent = dev;
+
+ return devm_i8254_regmap_register(dev, &pit_config);
}
static struct isa_driver stx104_driver = {
@@ -464,3 +520,4 @@ module_isa_driver(stx104_driver, num_stx104);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
MODULE_DESCRIPTION("Apex Embedded Systems STX104 IIO driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(I8254);
diff --git a/drivers/iio/amplifiers/hmc425a.c b/drivers/iio/amplifiers/hmc425a.c
index 108f0f1685..e87d35d50a 100644
--- a/drivers/iio/amplifiers/hmc425a.c
+++ b/drivers/iio/amplifiers/hmc425a.c
@@ -21,6 +21,7 @@
enum hmc425a_type {
ID_HMC425A,
+ ID_HMC540S,
};
struct hmc425a_chip_info {
@@ -70,6 +71,9 @@ static int hmc425a_read_raw(struct iio_dev *indio_dev,
case ID_HMC425A:
gain = ~code * -500;
break;
+ case ID_HMC540S:
+ gain = ~code * -1000;
+ break;
}
*val = gain / 1000;
@@ -106,6 +110,9 @@ static int hmc425a_write_raw(struct iio_dev *indio_dev,
case ID_HMC425A:
code = ~((abs(gain) / 500) & 0x3F);
break;
+ case ID_HMC540S:
+ code = ~((abs(gain) / 1000) & 0xF);
+ break;
}
mutex_lock(&st->lock);
@@ -157,6 +164,7 @@ static const struct iio_chan_spec hmc425a_channels[] = {
/* Match table for of_platform binding */
static const struct of_device_id hmc425a_of_match[] = {
{ .compatible = "adi,hmc425a", .data = (void *)ID_HMC425A },
+ { .compatible = "adi,hmc540s", .data = (void *)ID_HMC540S },
{},
};
MODULE_DEVICE_TABLE(of, hmc425a_of_match);
@@ -171,6 +179,15 @@ static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = {
.gain_max = 0,
.default_gain = -0x40, /* set default gain -31.5db*/
},
+ [ID_HMC540S] = {
+ .name = "hmc540s",
+ .channels = hmc425a_channels,
+ .num_channels = ARRAY_SIZE(hmc425a_channels),
+ .num_gpios = 4,
+ .gain_min = -15000,
+ .gain_max = 0,
+ .default_gain = -0x10, /* set default gain -15.0db*/
+ },
};
static int hmc425a_probe(struct platform_device *pdev)
diff --git a/drivers/iio/chemical/atlas-ezo-sensor.c b/drivers/iio/chemical/atlas-ezo-sensor.c
index 8fc926a2d3..761a853a4d 100644
--- a/drivers/iio/chemical/atlas-ezo-sensor.c
+++ b/drivers/iio/chemical/atlas-ezo-sensor.c
@@ -203,7 +203,6 @@ MODULE_DEVICE_TABLE(of, atlas_ezo_dt_ids);
static int atlas_ezo_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
const struct atlas_ezo_device *chip;
struct atlas_ezo_data *data;
struct iio_dev *indio_dev;
@@ -212,10 +211,7 @@ static int atlas_ezo_probe(struct i2c_client *client)
if (!indio_dev)
return -ENOMEM;
- if (dev_fwnode(&client->dev))
- chip = device_get_match_data(&client->dev);
- else
- chip = (const struct atlas_ezo_device *)id->driver_data;
+ chip = i2c_get_match_data(client);
if (!chip)
return -EINVAL;
diff --git a/drivers/iio/chemical/atlas-sensor.c b/drivers/iio/chemical/atlas-sensor.c
index fb15bb2160..baf93e5e3c 100644
--- a/drivers/iio/chemical/atlas-sensor.c
+++ b/drivers/iio/chemical/atlas-sensor.c
@@ -87,7 +87,7 @@ enum {
struct atlas_data {
struct i2c_client *client;
struct iio_trigger *trig;
- struct atlas_device *chip;
+ const struct atlas_device *chip;
struct regmap *regmap;
struct irq_work work;
unsigned int interrupt_enabled;
@@ -353,7 +353,7 @@ struct atlas_device {
int delay;
};
-static struct atlas_device atlas_devices[] = {
+static const struct atlas_device atlas_devices[] = {
[ATLAS_PH_SM] = {
.channels = atlas_ph_channels,
.num_channels = 3,
@@ -589,30 +589,29 @@ static const struct iio_info atlas_info = {
};
static const struct i2c_device_id atlas_id[] = {
- { "atlas-ph-sm", ATLAS_PH_SM },
- { "atlas-ec-sm", ATLAS_EC_SM },
- { "atlas-orp-sm", ATLAS_ORP_SM },
- { "atlas-do-sm", ATLAS_DO_SM },
- { "atlas-rtd-sm", ATLAS_RTD_SM },
+ { "atlas-ph-sm", (kernel_ulong_t)&atlas_devices[ATLAS_PH_SM] },
+ { "atlas-ec-sm", (kernel_ulong_t)&atlas_devices[ATLAS_EC_SM] },
+ { "atlas-orp-sm", (kernel_ulong_t)&atlas_devices[ATLAS_ORP_SM] },
+ { "atlas-do-sm", (kernel_ulong_t)&atlas_devices[ATLAS_DO_SM] },
+ { "atlas-rtd-sm", (kernel_ulong_t)&atlas_devices[ATLAS_RTD_SM] },
{}
};
MODULE_DEVICE_TABLE(i2c, atlas_id);
static const struct of_device_id atlas_dt_ids[] = {
- { .compatible = "atlas,ph-sm", .data = (void *)ATLAS_PH_SM, },
- { .compatible = "atlas,ec-sm", .data = (void *)ATLAS_EC_SM, },
- { .compatible = "atlas,orp-sm", .data = (void *)ATLAS_ORP_SM, },
- { .compatible = "atlas,do-sm", .data = (void *)ATLAS_DO_SM, },
- { .compatible = "atlas,rtd-sm", .data = (void *)ATLAS_RTD_SM, },
+ { .compatible = "atlas,ph-sm", .data = &atlas_devices[ATLAS_PH_SM] },
+ { .compatible = "atlas,ec-sm", .data = &atlas_devices[ATLAS_EC_SM] },
+ { .compatible = "atlas,orp-sm", .data = &atlas_devices[ATLAS_ORP_SM] },
+ { .compatible = "atlas,do-sm", .data = &atlas_devices[ATLAS_DO_SM] },
+ { .compatible = "atlas,rtd-sm", .data = &atlas_devices[ATLAS_RTD_SM] },
{ }
};
MODULE_DEVICE_TABLE(of, atlas_dt_ids);
static int atlas_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct atlas_data *data;
- struct atlas_device *chip;
+ const struct atlas_device *chip;
struct iio_trigger *trig;
struct iio_dev *indio_dev;
int ret;
@@ -621,10 +620,7 @@ static int atlas_probe(struct i2c_client *client)
if (!indio_dev)
return -ENOMEM;
- if (!dev_fwnode(&client->dev))
- chip = &atlas_devices[id->driver_data];
- else
- chip = &atlas_devices[(unsigned long)device_get_match_data(&client->dev)];
+ chip = i2c_get_match_data(client);
indio_dev->info = &atlas_info;
indio_dev->name = ATLAS_DRV_NAME;
diff --git a/drivers/iio/chemical/sgp30.c b/drivers/iio/chemical/sgp30.c
index b509cff9ce..21730d62b5 100644
--- a/drivers/iio/chemical/sgp30.c
+++ b/drivers/iio/chemical/sgp30.c
@@ -114,6 +114,7 @@ struct sgp_data {
};
struct sgp_device {
+ unsigned long product_id;
const struct iio_chan_spec *channels;
int num_channels;
};
@@ -182,10 +183,12 @@ static const struct iio_chan_spec sgpc3_channels[] = {
static const struct sgp_device sgp_devices[] = {
[SGP30] = {
+ .product_id = SGP30,
.channels = sgp30_channels,
.num_channels = ARRAY_SIZE(sgp30_channels),
},
[SGPC3] = {
+ .product_id = SGPC3,
.channels = sgpc3_channels,
.num_channels = ARRAY_SIZE(sgpc3_channels),
},
@@ -491,28 +494,25 @@ static const struct iio_info sgp_info = {
};
static const struct of_device_id sgp_dt_ids[] = {
- { .compatible = "sensirion,sgp30", .data = (void *)SGP30 },
- { .compatible = "sensirion,sgpc3", .data = (void *)SGPC3 },
+ { .compatible = "sensirion,sgp30", .data = &sgp_devices[SGP30] },
+ { .compatible = "sensirion,sgpc3", .data = &sgp_devices[SGPC3] },
{ }
};
static int sgp_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
+ const struct sgp_device *match_data;
struct device *dev = &client->dev;
struct iio_dev *indio_dev;
struct sgp_data *data;
- unsigned long product_id;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
- if (dev_fwnode(dev))
- product_id = (unsigned long)device_get_match_data(dev);
- else
- product_id = id->driver_data;
+ match_data = i2c_get_match_data(client);
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
@@ -528,15 +528,15 @@ static int sgp_probe(struct i2c_client *client)
data->feature_set = be16_to_cpu(data->buffer.raw_words[0].value);
- ret = sgp_check_compat(data, product_id);
+ ret = sgp_check_compat(data, match_data->product_id);
if (ret)
return ret;
indio_dev->info = &sgp_info;
indio_dev->name = id->name;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = sgp_devices[product_id].channels;
- indio_dev->num_channels = sgp_devices[product_id].num_channels;
+ indio_dev->channels = match_data->channels;
+ indio_dev->num_channels = match_data->num_channels;
sgp_init(data);
@@ -562,8 +562,8 @@ static void sgp_remove(struct i2c_client *client)
}
static const struct i2c_device_id sgp_id[] = {
- { "sgp30", SGP30 },
- { "sgpc3", SGPC3 },
+ { "sgp30", (kernel_ulong_t)&sgp_devices[SGP30] },
+ { "sgpc3", (kernel_ulong_t)&sgp_devices[SGPC3] },
{ }
};
diff --git a/drivers/iio/chemical/vz89x.c b/drivers/iio/chemical/vz89x.c
index 13555f4f40..5b358bcd31 100644
--- a/drivers/iio/chemical/vz89x.c
+++ b/drivers/iio/chemical/vz89x.c
@@ -342,19 +342,17 @@ static const struct vz89x_chip_data vz89x_chips[] = {
};
static const struct of_device_id vz89x_dt_ids[] = {
- { .compatible = "sgx,vz89x", .data = (void *) VZ89X },
- { .compatible = "sgx,vz89te", .data = (void *) VZ89TE },
+ { .compatible = "sgx,vz89x", .data = &vz89x_chips[VZ89X] },
+ { .compatible = "sgx,vz89te", .data = &vz89x_chips[VZ89TE] },
{ }
};
MODULE_DEVICE_TABLE(of, vz89x_dt_ids);
static int vz89x_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device *dev = &client->dev;
struct iio_dev *indio_dev;
struct vz89x_data *data;
- int chip_id;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
@@ -369,14 +367,10 @@ static int vz89x_probe(struct i2c_client *client)
else
return -EOPNOTSUPP;
- if (!dev_fwnode(dev))
- chip_id = id->driver_data;
- else
- chip_id = (unsigned long)device_get_match_data(dev);
+ data->chip = i2c_get_match_data(client);
i2c_set_clientdata(client, indio_dev);
data->client = client;
- data->chip = &vz89x_chips[chip_id];
data->last_update = jiffies - HZ;
mutex_init(&data->lock);
@@ -391,8 +385,8 @@ static int vz89x_probe(struct i2c_client *client)
}
static const struct i2c_device_id vz89x_id[] = {
- { "vz89x", VZ89X },
- { "vz89te", VZ89TE },
+ { "vz89x", (kernel_ulong_t)&vz89x_chips[VZ89X] },
+ { "vz89te", (kernel_ulong_t)&vz89x_chips[VZ89TE] },
{ }
};
MODULE_DEVICE_TABLE(i2c, vz89x_id);
diff --git a/drivers/iio/dac/dpot-dac.c b/drivers/iio/dac/dpot-dac.c
index 83ce948925..7332064d08 100644
--- a/drivers/iio/dac/dpot-dac.c
+++ b/drivers/iio/dac/dpot-dac.c
@@ -226,15 +226,13 @@ disable_reg:
return ret;
}
-static int dpot_dac_remove(struct platform_device *pdev)
+static void dpot_dac_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct dpot_dac *dac = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
regulator_disable(dac->vref);
-
- return 0;
}
static const struct of_device_id dpot_dac_match[] = {
@@ -245,7 +243,7 @@ MODULE_DEVICE_TABLE(of, dpot_dac_match);
static struct platform_driver dpot_dac_driver = {
.probe = dpot_dac_probe,
- .remove = dpot_dac_remove,
+ .remove_new = dpot_dac_remove,
.driver = {
.name = "iio-dpot-dac",
.of_match_table = dpot_dac_match,
diff --git a/drivers/iio/dac/lpc18xx_dac.c b/drivers/iio/dac/lpc18xx_dac.c
index 60467c6f2c..b3aa4443a6 100644
--- a/drivers/iio/dac/lpc18xx_dac.c
+++ b/drivers/iio/dac/lpc18xx_dac.c
@@ -165,7 +165,7 @@ dis_reg:
return ret;
}
-static int lpc18xx_dac_remove(struct platform_device *pdev)
+static void lpc18xx_dac_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct lpc18xx_dac *dac = iio_priv(indio_dev);
@@ -175,8 +175,6 @@ static int lpc18xx_dac_remove(struct platform_device *pdev)
writel(0, dac->base + LPC18XX_DAC_CTRL);
clk_disable_unprepare(dac->clk);
regulator_disable(dac->vref);
-
- return 0;
}
static const struct of_device_id lpc18xx_dac_match[] = {
@@ -187,7 +185,7 @@ MODULE_DEVICE_TABLE(of, lpc18xx_dac_match);
static struct platform_driver lpc18xx_dac_driver = {
.probe = lpc18xx_dac_probe,
- .remove = lpc18xx_dac_remove,
+ .remove_new = lpc18xx_dac_remove,
.driver = {
.name = "lpc18xx-dac",
.of_match_table = lpc18xx_dac_match,
diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c
index f4a3124d29..25bb1c0490 100644
--- a/drivers/iio/dac/mcp4725.c
+++ b/drivers/iio/dac/mcp4725.c
@@ -30,9 +30,14 @@
#define MCP472X_REF_VREF_UNBUFFERED 0x02
#define MCP472X_REF_VREF_BUFFERED 0x03
+struct mcp4725_chip_info {
+ const struct iio_chan_spec *chan_spec;
+ u8 dac_reg_offset;
+ bool use_ext_ref_voltage;
+};
+
struct mcp4725_data {
struct i2c_client *client;
- int id;
unsigned ref_mode;
bool vref_buffered;
u16 dac_value;
@@ -384,6 +389,7 @@ static int mcp4725_probe_dt(struct device *dev,
static int mcp4725_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
+ const struct mcp4725_chip_info *info;
struct mcp4725_data *data;
struct iio_dev *indio_dev;
struct mcp4725_platform_data *pdata, pdata_dt;
@@ -398,10 +404,7 @@ static int mcp4725_probe(struct i2c_client *client)
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
- if (dev_fwnode(&client->dev))
- data->id = (uintptr_t)device_get_match_data(&client->dev);
- else
- data->id = id->driver_data;
+ info = i2c_get_match_data(client);
pdata = dev_get_platdata(&client->dev);
if (!pdata) {
@@ -414,7 +417,7 @@ static int mcp4725_probe(struct i2c_client *client)
pdata = &pdata_dt;
}
- if (data->id == MCP4725 && pdata->use_vref) {
+ if (info->use_ext_ref_voltage && pdata->use_vref) {
dev_err(&client->dev,
"external reference is unavailable on MCP4725");
return -EINVAL;
@@ -455,12 +458,12 @@ static int mcp4725_probe(struct i2c_client *client)
indio_dev->name = id->name;
indio_dev->info = &mcp4725_info;
- indio_dev->channels = &mcp472x_channel[id->driver_data];
+ indio_dev->channels = info->chan_spec;
indio_dev->num_channels = 1;
indio_dev->modes = INDIO_DIRECT_MODE;
/* read current DAC value and settings */
- err = i2c_master_recv(client, inbuf, data->id == MCP4725 ? 3 : 4);
+ err = i2c_master_recv(client, inbuf, info->dac_reg_offset);
if (err < 0) {
dev_err(&client->dev, "failed to read DAC value");
@@ -470,10 +473,10 @@ static int mcp4725_probe(struct i2c_client *client)
data->powerdown = pd > 0;
data->powerdown_mode = pd ? pd - 1 : 2; /* largest resistor to gnd */
data->dac_value = (inbuf[1] << 4) | (inbuf[2] >> 4);
- if (data->id == MCP4726)
+ if (!info->use_ext_ref_voltage)
ref = (inbuf[3] >> 3) & 0x3;
- if (data->id == MCP4726 && ref != data->ref_mode) {
+ if (!info->use_ext_ref_voltage && ref != data->ref_mode) {
dev_info(&client->dev,
"voltage reference mode differs (conf: %u, eeprom: %u), setting %u",
data->ref_mode, ref, data->ref_mode);
@@ -510,9 +513,20 @@ static void mcp4725_remove(struct i2c_client *client)
regulator_disable(data->vdd_reg);
}
+static const struct mcp4725_chip_info mcp4725 = {
+ .chan_spec = &mcp472x_channel[MCP4725],
+ .dac_reg_offset = 3,
+ .use_ext_ref_voltage = true,
+};
+
+static const struct mcp4725_chip_info mcp4726 = {
+ .chan_spec = &mcp472x_channel[MCP4726],
+ .dac_reg_offset = 4,
+};
+
static const struct i2c_device_id mcp4725_id[] = {
- { "mcp4725", MCP4725 },
- { "mcp4726", MCP4726 },
+ { "mcp4725", (kernel_ulong_t)&mcp4725 },
+ { "mcp4726", (kernel_ulong_t)&mcp4726 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mcp4725_id);
@@ -520,11 +534,11 @@ MODULE_DEVICE_TABLE(i2c, mcp4725_id);
static const struct of_device_id mcp4725_of_match[] = {
{
.compatible = "microchip,mcp4725",
- .data = (void *)MCP4725
+ .data = &mcp4725
},
{
.compatible = "microchip,mcp4726",
- .data = (void *)MCP4726
+ .data = &mcp4726
},
{ }
};
diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c
index 83bf184e3a..e150ac7291 100644
--- a/drivers/iio/dac/stm32-dac-core.c
+++ b/drivers/iio/dac/stm32-dac-core.c
@@ -9,9 +9,12 @@
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
@@ -94,16 +97,12 @@ static int stm32_dac_probe(struct platform_device *pdev)
struct reset_control *rst;
int ret;
- if (!dev->of_node)
- return -ENODEV;
-
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
platform_set_drvdata(pdev, &priv->common);
- cfg = (const struct stm32_dac_cfg *)
- of_match_device(dev->driver->of_match_table, dev)->data;
+ cfg = device_get_match_data(dev);
mmio = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(mmio))
@@ -183,7 +182,7 @@ err_pm_stop:
return ret;
}
-static int stm32_dac_remove(struct platform_device *pdev)
+static void stm32_dac_remove(struct platform_device *pdev)
{
pm_runtime_get_sync(&pdev->dev);
of_platform_depopulate(&pdev->dev);
@@ -191,8 +190,6 @@ static int stm32_dac_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
-
- return 0;
}
static int stm32_dac_core_resume(struct device *dev)
@@ -249,7 +246,7 @@ MODULE_DEVICE_TABLE(of, stm32_dac_of_match);
static struct platform_driver stm32_dac_driver = {
.probe = stm32_dac_probe,
- .remove = stm32_dac_remove,
+ .remove_new = stm32_dac_remove,
.driver = {
.name = "stm32-dac-core",
.of_match_table = stm32_dac_of_match,
diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c
index 15eb440751..5a722f307e 100644
--- a/drivers/iio/dac/stm32-dac.c
+++ b/drivers/iio/dac/stm32-dac.c
@@ -11,12 +11,13 @@
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/kernel.h>
+#include <linux/kstrtox.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
-#include <linux/string_helpers.h>
+#include <linux/string_choices.h>
#include "stm32-dac-core.h"
@@ -361,7 +362,7 @@ err_pm_put:
return ret;
}
-static int stm32_dac_remove(struct platform_device *pdev)
+static void stm32_dac_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -370,8 +371,6 @@ static int stm32_dac_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
-
- return 0;
}
static int stm32_dac_suspend(struct device *dev)
@@ -399,7 +398,7 @@ MODULE_DEVICE_TABLE(of, stm32_dac_of_match);
static struct platform_driver stm32_dac_driver = {
.probe = stm32_dac_probe,
- .remove = stm32_dac_remove,
+ .remove_new = stm32_dac_remove,
.driver = {
.name = "stm32-dac",
.of_match_table = stm32_dac_of_match,
diff --git a/drivers/iio/dac/ti-dac5571.c b/drivers/iio/dac/ti-dac5571.c
index bab11b9adc..efb1269a77 100644
--- a/drivers/iio/dac/ti-dac5571.c
+++ b/drivers/iio/dac/ti-dac5571.c
@@ -313,7 +313,6 @@ static int dac5571_probe(struct i2c_client *client)
const struct dac5571_spec *spec;
struct dac5571_data *data;
struct iio_dev *indio_dev;
- enum chip_id chip_id;
int ret, i;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
@@ -329,12 +328,7 @@ static int dac5571_probe(struct i2c_client *client)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = dac5571_channels;
- if (dev_fwnode(dev))
- chip_id = (uintptr_t)device_get_match_data(dev);
- else
- chip_id = id->driver_data;
-
- spec = &dac5571_spec[chip_id];
+ spec = i2c_get_match_data(client);
indio_dev->num_channels = spec->num_channels;
data->spec = spec;
@@ -392,31 +386,31 @@ static void dac5571_remove(struct i2c_client *i2c)
}
static const struct of_device_id dac5571_of_id[] = {
- {.compatible = "ti,dac5571", .data = (void *)single_8bit},
- {.compatible = "ti,dac6571", .data = (void *)single_10bit},
- {.compatible = "ti,dac7571", .data = (void *)single_12bit},
- {.compatible = "ti,dac5574", .data = (void *)quad_8bit},
- {.compatible = "ti,dac6574", .data = (void *)quad_10bit},
- {.compatible = "ti,dac7574", .data = (void *)quad_12bit},
- {.compatible = "ti,dac5573", .data = (void *)quad_8bit},
- {.compatible = "ti,dac6573", .data = (void *)quad_10bit},
- {.compatible = "ti,dac7573", .data = (void *)quad_12bit},
- {.compatible = "ti,dac121c081", .data = (void *)single_12bit},
+ {.compatible = "ti,dac121c081", .data = &dac5571_spec[single_12bit] },
+ {.compatible = "ti,dac5571", .data = &dac5571_spec[single_8bit] },
+ {.compatible = "ti,dac6571", .data = &dac5571_spec[single_10bit] },
+ {.compatible = "ti,dac7571", .data = &dac5571_spec[single_12bit] },
+ {.compatible = "ti,dac5574", .data = &dac5571_spec[quad_8bit] },
+ {.compatible = "ti,dac6574", .data = &dac5571_spec[quad_10bit] },
+ {.compatible = "ti,dac7574", .data = &dac5571_spec[quad_12bit] },
+ {.compatible = "ti,dac5573", .data = &dac5571_spec[quad_8bit] },
+ {.compatible = "ti,dac6573", .data = &dac5571_spec[quad_10bit] },
+ {.compatible = "ti,dac7573", .data = &dac5571_spec[quad_12bit] },
{}
};
MODULE_DEVICE_TABLE(of, dac5571_of_id);
static const struct i2c_device_id dac5571_id[] = {
- {"dac5571", single_8bit},
- {"dac6571", single_10bit},
- {"dac7571", single_12bit},
- {"dac5574", quad_8bit},
- {"dac6574", quad_10bit},
- {"dac7574", quad_12bit},
- {"dac5573", quad_8bit},
- {"dac6573", quad_10bit},
- {"dac7573", quad_12bit},
- {"dac121c081", single_12bit},
+ {"dac121c081", (kernel_ulong_t)&dac5571_spec[single_12bit] },
+ {"dac5571", (kernel_ulong_t)&dac5571_spec[single_8bit] },
+ {"dac6571", (kernel_ulong_t)&dac5571_spec[single_10bit] },
+ {"dac7571", (kernel_ulong_t)&dac5571_spec[single_12bit] },
+ {"dac5574", (kernel_ulong_t)&dac5571_spec[quad_8bit] },
+ {"dac6574", (kernel_ulong_t)&dac5571_spec[quad_10bit] },
+ {"dac7574", (kernel_ulong_t)&dac5571_spec[quad_12bit] },
+ {"dac5573", (kernel_ulong_t)&dac5571_spec[quad_8bit] },
+ {"dac6573", (kernel_ulong_t)&dac5571_spec[quad_10bit] },
+ {"dac7573", (kernel_ulong_t)&dac5571_spec[quad_12bit] },
{}
};
MODULE_DEVICE_TABLE(i2c, dac5571_id);
diff --git a/drivers/iio/dac/vf610_dac.c b/drivers/iio/dac/vf610_dac.c
index fc182250c6..de73bc5a1c 100644
--- a/drivers/iio/dac/vf610_dac.c
+++ b/drivers/iio/dac/vf610_dac.c
@@ -231,7 +231,7 @@ error_iio_device_register:
return ret;
}
-static int vf610_dac_remove(struct platform_device *pdev)
+static void vf610_dac_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct vf610_dac *info = iio_priv(indio_dev);
@@ -239,8 +239,6 @@ static int vf610_dac_remove(struct platform_device *pdev)
iio_device_unregister(indio_dev);
vf610_dac_exit(info);
clk_disable_unprepare(info->clk);
-
- return 0;
}
static int vf610_dac_suspend(struct device *dev)
@@ -274,7 +272,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(vf610_dac_pm_ops, vf610_dac_suspend,
static struct platform_driver vf610_dac_driver = {
.probe = vf610_dac_probe,
- .remove = vf610_dac_remove,
+ .remove_new = vf610_dac_remove,
.driver = {
.name = "vf610-dac",
.of_match_table = vf610_dac_match,
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
index 698c50da1f..59a38bf945 100644
--- a/drivers/iio/gyro/hid-sensor-gyro-3d.c
+++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
@@ -359,7 +359,7 @@ error_remove_trigger:
}
/* Function to deinitialize the processing for usage id */
-static int hid_gyro_3d_remove(struct platform_device *pdev)
+static void hid_gyro_3d_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -368,8 +368,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);
-
- return 0;
}
static const struct platform_device_id hid_gyro_3d_ids[] = {
@@ -388,7 +386,7 @@ static struct platform_driver hid_gyro_3d_platform_driver = {
.pm = &hid_sensor_pm_ops,
},
.probe = hid_gyro_3d_probe,
- .remove = hid_gyro_3d_remove,
+ .remove_new = hid_gyro_3d_remove,
};
module_platform_driver(hid_gyro_3d_platform_driver);
diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c
index fa0fe404a7..bf6d2636a8 100644
--- a/drivers/iio/humidity/hid-sensor-humidity.c
+++ b/drivers/iio/humidity/hid-sensor-humidity.c
@@ -260,7 +260,7 @@ error_remove_trigger:
}
/* Function to deinitialize the processing for usage id */
-static int hid_humidity_remove(struct platform_device *pdev)
+static void hid_humidity_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev);
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -269,8 +269,6 @@ static int hid_humidity_remove(struct platform_device *pdev)
iio_device_unregister(indio_dev);
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY);
hid_sensor_remove_trigger(indio_dev, &humid_st->common_attributes);
-
- return 0;
}
static const struct platform_device_id hid_humidity_ids[] = {
@@ -289,7 +287,7 @@ static struct platform_driver hid_humidity_platform_driver = {
.pm = &hid_sensor_pm_ops,
},
.probe = hid_humidity_probe,
- .remove = hid_humidity_remove,
+ .remove_new = hid_humidity_remove,
};
module_platform_driver(hid_humidity_platform_driver);
diff --git a/drivers/iio/humidity/si7005.c b/drivers/iio/humidity/si7005.c
index ebfb79bc9e..9465908cc6 100644
--- a/drivers/iio/humidity/si7005.c
+++ b/drivers/iio/humidity/si7005.c
@@ -169,9 +169,16 @@ static const struct i2c_device_id si7005_id[] = {
};
MODULE_DEVICE_TABLE(i2c, si7005_id);
+static const struct of_device_id si7005_dt_ids[] = {
+ { .compatible = "silabs,si7005" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, si7005_dt_ids);
+
static struct i2c_driver si7005_driver = {
.driver = {
.name = "si7005",
+ .of_match_table = si7005_dt_ids,
},
.probe = si7005_probe,
.id_table = si7005_id,
diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h
index 501e286702..1a38b1915e 100644
--- a/drivers/iio/iio_core.h
+++ b/drivers/iio/iio_core.h
@@ -30,9 +30,6 @@ struct iio_ioctl_handler {
unsigned int cmd, unsigned long arg);
};
-long iio_device_ioctl(struct iio_dev *indio_dev, struct file *filp,
- unsigned int cmd, unsigned long arg);
-
void iio_device_ioctl_handler_register(struct iio_dev *indio_dev,
struct iio_ioctl_handler *h);
void iio_device_ioctl_handler_unregister(struct iio_ioctl_handler *h);
diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c
index 6c81dc5bf2..64be656f0b 100644
--- a/drivers/iio/imu/adis16475.c
+++ b/drivers/iio/imu/adis16475.c
@@ -31,6 +31,12 @@
#define ADIS16475_REG_Y_ACCEL_L 0x14
#define ADIS16475_REG_Z_ACCEL_L 0x18
#define ADIS16475_REG_TEMP_OUT 0x1c
+#define ADIS16475_REG_X_DELTANG_L 0x24
+#define ADIS16475_REG_Y_DELTANG_L 0x28
+#define ADIS16475_REG_Z_DELTANG_L 0x2C
+#define ADIS16475_REG_X_DELTVEL_L 0x30
+#define ADIS16475_REG_Y_DELTVEL_L 0x34
+#define ADIS16475_REG_Z_DELTVEL_L 0x38
#define ADIS16475_REG_X_GYRO_BIAS_L 0x40
#define ADIS16475_REG_Y_GYRO_BIAS_L 0x44
#define ADIS16475_REG_Z_GYRO_BIAS_L 0x48
@@ -55,6 +61,7 @@
#define ADIS16475_REG_PROD_ID 0x72
#define ADIS16475_REG_SERIAL_NUM 0x74
#define ADIS16475_REG_FLASH_CNT 0x7c
+#define ADIS16500_BURST_DATA_SEL_MASK BIT(8)
#define ADIS16500_BURST32_MASK BIT(9)
#define ADIS16500_BURST32(x) FIELD_PREP(ADIS16500_BURST32_MASK, x)
/* number of data elements in burst mode */
@@ -65,6 +72,8 @@
#define ADIS16475_BURST_MAX_SPEED 1000000
#define ADIS16475_LSB_DEC_MASK 0
#define ADIS16475_LSB_FIR_MASK 1
+#define ADIS16500_BURST_DATA_SEL_0_CHN_MASK GENMASK(5, 0)
+#define ADIS16500_BURST_DATA_SEL_1_CHN_MASK GENMASK(12, 7)
enum {
ADIS16475_SYNC_DIRECT = 1,
@@ -84,16 +93,20 @@ struct adis16475_chip_info {
const struct adis16475_sync *sync;
const struct adis_data adis_data;
const char *name;
+#define ADIS16475_HAS_BURST32 BIT(0)
+#define ADIS16475_HAS_BURST_DELTA_DATA BIT(1)
+ const long flags;
u32 num_channels;
u32 gyro_max_val;
u32 gyro_max_scale;
u32 accel_max_val;
u32 accel_max_scale;
u32 temp_scale;
+ u32 deltang_max_val;
+ u32 deltvel_max_val;
u32 int_clk;
u16 max_dec;
u8 num_sync;
- bool has_burst32;
};
struct adis16475 {
@@ -115,6 +128,12 @@ enum {
ADIS16475_SCAN_ACCEL_Y,
ADIS16475_SCAN_ACCEL_Z,
ADIS16475_SCAN_TEMP,
+ ADIS16475_SCAN_DELTANG_X,
+ ADIS16475_SCAN_DELTANG_Y,
+ ADIS16475_SCAN_DELTANG_Z,
+ ADIS16475_SCAN_DELTVEL_X,
+ ADIS16475_SCAN_DELTVEL_Y,
+ ADIS16475_SCAN_DELTVEL_Z,
};
static bool low_rate_allow;
@@ -451,6 +470,14 @@ static int adis16475_read_raw(struct iio_dev *indio_dev,
case IIO_TEMP:
*val = st->info->temp_scale;
return IIO_VAL_INT;
+ case IIO_DELTA_ANGL:
+ *val = st->info->deltang_max_val;
+ *val2 = 31;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_DELTA_VELOCITY:
+ *val = st->info->deltvel_max_val;
+ *val2 = 31;
+ return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
@@ -551,6 +578,57 @@ static int adis16475_write_raw(struct iio_dev *indio_dev,
}, \
}
+#define ADIS16475_MOD_CHAN_DELTA(_type, _mod, _address, _si, _r_bits, _s_bits) { \
+ .type = (_type), \
+ .modified = 1, \
+ .channel2 = (_mod), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
+ .address = (_address), \
+ .scan_index = _si, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = (_r_bits), \
+ .storagebits = (_s_bits), \
+ .endianness = IIO_BE, \
+ }, \
+ }
+
+#define ADIS16475_DELTANG_CHAN(_mod) \
+ ADIS16475_MOD_CHAN_DELTA(IIO_DELTA_ANGL, IIO_MOD_ ## _mod, \
+ ADIS16475_REG_ ## _mod ## _DELTANG_L, ADIS16475_SCAN_DELTANG_ ## _mod, 32, 32)
+
+#define ADIS16475_DELTVEL_CHAN(_mod) \
+ ADIS16475_MOD_CHAN_DELTA(IIO_DELTA_VELOCITY, IIO_MOD_ ## _mod, \
+ ADIS16475_REG_ ## _mod ## _DELTVEL_L, ADIS16475_SCAN_DELTVEL_ ## _mod, 32, 32)
+
+#define ADIS16475_DELTANG_CHAN_NO_SCAN(_mod) \
+ ADIS16475_MOD_CHAN_DELTA(IIO_DELTA_ANGL, IIO_MOD_ ## _mod, \
+ ADIS16475_REG_ ## _mod ## _DELTANG_L, -1, 32, 32)
+
+#define ADIS16475_DELTVEL_CHAN_NO_SCAN(_mod) \
+ ADIS16475_MOD_CHAN_DELTA(IIO_DELTA_VELOCITY, IIO_MOD_ ## _mod, \
+ ADIS16475_REG_ ## _mod ## _DELTVEL_L, -1, 32, 32)
+
+static const struct iio_chan_spec adis16477_channels[] = {
+ ADIS16475_GYRO_CHANNEL(X),
+ ADIS16475_GYRO_CHANNEL(Y),
+ ADIS16475_GYRO_CHANNEL(Z),
+ ADIS16475_ACCEL_CHANNEL(X),
+ ADIS16475_ACCEL_CHANNEL(Y),
+ ADIS16475_ACCEL_CHANNEL(Z),
+ ADIS16475_TEMP_CHANNEL(),
+ ADIS16475_DELTANG_CHAN(X),
+ ADIS16475_DELTANG_CHAN(Y),
+ ADIS16475_DELTANG_CHAN(Z),
+ ADIS16475_DELTVEL_CHAN(X),
+ ADIS16475_DELTVEL_CHAN(Y),
+ ADIS16475_DELTVEL_CHAN(Z),
+ IIO_CHAN_SOFT_TIMESTAMP(13)
+};
+
static const struct iio_chan_spec adis16475_channels[] = {
ADIS16475_GYRO_CHANNEL(X),
ADIS16475_GYRO_CHANNEL(Y),
@@ -559,6 +637,12 @@ static const struct iio_chan_spec adis16475_channels[] = {
ADIS16475_ACCEL_CHANNEL(Y),
ADIS16475_ACCEL_CHANNEL(Z),
ADIS16475_TEMP_CHANNEL(),
+ ADIS16475_DELTANG_CHAN_NO_SCAN(X),
+ ADIS16475_DELTANG_CHAN_NO_SCAN(Y),
+ ADIS16475_DELTANG_CHAN_NO_SCAN(Z),
+ ADIS16475_DELTVEL_CHAN_NO_SCAN(X),
+ ADIS16475_DELTVEL_CHAN_NO_SCAN(Y),
+ ADIS16475_DELTVEL_CHAN_NO_SCAN(Z),
IIO_CHAN_SOFT_TIMESTAMP(7)
};
@@ -662,6 +746,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 400,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
@@ -677,6 +763,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(360),
+ .deltvel_max_val = 100,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
@@ -692,6 +780,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 100,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
@@ -707,6 +797,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 100,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
@@ -715,50 +807,56 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
},
[ADIS16477_1] = {
.name = "adis16477-1",
- .num_channels = ARRAY_SIZE(adis16475_channels),
- .channels = adis16475_channels,
+ .num_channels = ARRAY_SIZE(adis16477_channels),
+ .channels = adis16477_channels,
.gyro_max_val = 1,
.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(360),
+ .deltvel_max_val = 400,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
.num_sync = ARRAY_SIZE(adis16475_sync_mode),
- .has_burst32 = true,
+ .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
.adis_data = ADIS16475_DATA(16477, &adis16475_timeouts),
},
[ADIS16477_2] = {
.name = "adis16477-2",
- .num_channels = ARRAY_SIZE(adis16475_channels),
- .channels = adis16475_channels,
+ .num_channels = ARRAY_SIZE(adis16477_channels),
+ .channels = adis16477_channels,
.gyro_max_val = 1,
.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 400,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
.num_sync = ARRAY_SIZE(adis16475_sync_mode),
- .has_burst32 = true,
+ .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
.adis_data = ADIS16475_DATA(16477, &adis16475_timeouts),
},
[ADIS16477_3] = {
.name = "adis16477-3",
- .num_channels = ARRAY_SIZE(adis16475_channels),
- .channels = adis16475_channels,
+ .num_channels = ARRAY_SIZE(adis16477_channels),
+ .channels = adis16477_channels,
.gyro_max_val = 1,
.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 400,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
.num_sync = ARRAY_SIZE(adis16475_sync_mode),
- .has_burst32 = true,
+ .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
.adis_data = ADIS16475_DATA(16477, &adis16475_timeouts),
},
[ADIS16465_1] = {
@@ -770,6 +868,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(360),
+ .deltvel_max_val = 100,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
@@ -785,6 +885,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 100,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
@@ -800,6 +902,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(4000 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 100,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
@@ -815,6 +919,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(360),
+ .deltvel_max_val = 400,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
@@ -830,6 +936,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 400,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
@@ -845,6 +953,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.accel_max_val = 1,
.accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 400,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
@@ -853,129 +963,168 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
},
[ADIS16500] = {
.name = "adis16500",
- .num_channels = ARRAY_SIZE(adis16475_channels),
- .channels = adis16475_channels,
+ .num_channels = ARRAY_SIZE(adis16477_channels),
+ .channels = adis16477_channels,
.gyro_max_val = 1,
.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
.accel_max_val = 392,
.accel_max_scale = 32000 << 16,
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 400,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
/* pulse sync not supported */
.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
- .has_burst32 = true,
+ .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
.adis_data = ADIS16475_DATA(16500, &adis1650x_timeouts),
},
[ADIS16505_1] = {
.name = "adis16505-1",
- .num_channels = ARRAY_SIZE(adis16475_channels),
- .channels = adis16475_channels,
+ .num_channels = ARRAY_SIZE(adis16477_channels),
+ .channels = adis16477_channels,
.gyro_max_val = 1,
.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
.accel_max_val = 78,
.accel_max_scale = 32000 << 16,
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(360),
+ .deltvel_max_val = 100,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
/* pulse sync not supported */
.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
- .has_burst32 = true,
+ .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
.adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts),
},
[ADIS16505_2] = {
.name = "adis16505-2",
- .num_channels = ARRAY_SIZE(adis16475_channels),
- .channels = adis16475_channels,
+ .num_channels = ARRAY_SIZE(adis16477_channels),
+ .channels = adis16477_channels,
.gyro_max_val = 1,
.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
.accel_max_val = 78,
.accel_max_scale = 32000 << 16,
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 100,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
/* pulse sync not supported */
.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
- .has_burst32 = true,
+ .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
.adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts),
},
[ADIS16505_3] = {
.name = "adis16505-3",
- .num_channels = ARRAY_SIZE(adis16475_channels),
- .channels = adis16475_channels,
+ .num_channels = ARRAY_SIZE(adis16477_channels),
+ .channels = adis16477_channels,
.gyro_max_val = 1,
.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
.accel_max_val = 78,
.accel_max_scale = 32000 << 16,
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 100,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
/* pulse sync not supported */
.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
- .has_burst32 = true,
+ .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
.adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts),
},
[ADIS16507_1] = {
.name = "adis16507-1",
- .num_channels = ARRAY_SIZE(adis16475_channels),
- .channels = adis16475_channels,
+ .num_channels = ARRAY_SIZE(adis16477_channels),
+ .channels = adis16477_channels,
.gyro_max_val = 1,
.gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16),
.accel_max_val = 392,
.accel_max_scale = 32000 << 16,
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(360),
+ .deltvel_max_val = 400,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
/* pulse sync not supported */
.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
- .has_burst32 = true,
+ .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
.adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts),
},
[ADIS16507_2] = {
.name = "adis16507-2",
- .num_channels = ARRAY_SIZE(adis16475_channels),
- .channels = adis16475_channels,
+ .num_channels = ARRAY_SIZE(adis16477_channels),
+ .channels = adis16477_channels,
.gyro_max_val = 1,
.gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
.accel_max_val = 392,
.accel_max_scale = 32000 << 16,
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 400,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
/* pulse sync not supported */
.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
- .has_burst32 = true,
+ .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
.adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts),
},
[ADIS16507_3] = {
.name = "adis16507-3",
- .num_channels = ARRAY_SIZE(adis16475_channels),
- .channels = adis16475_channels,
+ .num_channels = ARRAY_SIZE(adis16477_channels),
+ .channels = adis16477_channels,
.gyro_max_val = 1,
.gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
.accel_max_val = 392,
.accel_max_scale = 32000 << 16,
.temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 400,
.int_clk = 2000,
.max_dec = 1999,
.sync = adis16475_sync_mode,
/* pulse sync not supported */
.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
- .has_burst32 = true,
+ .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
.adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts),
},
};
+static int adis16475_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ u16 en;
+ int ret;
+ struct adis16475 *st = iio_priv(indio_dev);
+
+ if (st->info->flags & ADIS16475_HAS_BURST_DELTA_DATA) {
+ if ((*scan_mask & ADIS16500_BURST_DATA_SEL_0_CHN_MASK) &&
+ (*scan_mask & ADIS16500_BURST_DATA_SEL_1_CHN_MASK))
+ return -EINVAL;
+ if (*scan_mask & ADIS16500_BURST_DATA_SEL_0_CHN_MASK)
+ en = FIELD_PREP(ADIS16500_BURST_DATA_SEL_MASK, 0);
+ else
+ en = FIELD_PREP(ADIS16500_BURST_DATA_SEL_MASK, 1);
+
+ ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL,
+ ADIS16500_BURST_DATA_SEL_MASK, en);
+ if (ret)
+ return ret;
+ }
+
+ return adis_update_scan_mode(indio_dev, scan_mask);
+}
+
static const struct iio_info adis16475_info = {
.read_raw = &adis16475_read_raw,
.write_raw = &adis16475_write_raw,
- .update_scan_mode = adis_update_scan_mode,
+ .update_scan_mode = adis16475_update_scan_mode,
.debugfs_reg_access = adis_debugfs_reg_access,
};
@@ -998,7 +1147,7 @@ static void adis16475_burst32_check(struct adis16475 *st)
int ret;
struct adis *adis = &st->adis;
- if (!st->info->has_burst32)
+ if (!(st->info->flags & ADIS16475_HAS_BURST32))
return;
if (st->lsb_flag && !st->burst32) {
@@ -1044,7 +1193,7 @@ static irqreturn_t adis16475_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16475 *st = iio_priv(indio_dev);
struct adis *adis = &st->adis;
- int ret, bit, i = 0;
+ int ret, bit, buff_offset = 0, i = 0;
__be16 *buffer;
u16 crc;
bool valid;
@@ -1073,7 +1222,20 @@ static irqreturn_t adis16475_trigger_handler(int irq, void *p)
switch (bit) {
case ADIS16475_SCAN_TEMP:
st->data[i++] = buffer[offset];
+ /*
+ * The temperature channel has 16-bit storage size.
+ * We need to perform the padding to have the buffer
+ * elements naturally aligned in case there are any
+ * 32-bit storage size channels enabled which have a
+ * scan index higher than the temperature channel scan
+ * index.
+ */
+ if (*indio_dev->active_scan_mask & GENMASK(ADIS16475_SCAN_DELTVEL_Z, ADIS16475_SCAN_DELTANG_X))
+ st->data[i++] = 0;
break;
+ case ADIS16475_SCAN_DELTANG_X ... ADIS16475_SCAN_DELTVEL_Z:
+ buff_offset = ADIS16475_SCAN_DELTANG_X;
+ fallthrough;
case ADIS16475_SCAN_GYRO_X ... ADIS16475_SCAN_ACCEL_Z:
/*
* The first 2 bytes on the received data are the
@@ -1081,18 +1243,18 @@ static irqreturn_t adis16475_trigger_handler(int irq, void *p)
*/
if (st->burst32) {
/* upper 16 */
- st->data[i++] = buffer[bit * 2 + 2];
+ st->data[i++] = buffer[(bit - buff_offset) * 2 + 2];
/* lower 16 */
- st->data[i++] = buffer[bit * 2 + 1];
+ st->data[i++] = buffer[(bit - buff_offset) * 2 + 1];
} else {
- st->data[i++] = buffer[bit + 1];
+ st->data[i++] = buffer[(bit - buff_offset) + 1];
/*
* Don't bother in doing the manual read if the
* device supports burst32. burst32 will be
* enabled in the next call to
* adis16475_burst32_check()...
*/
- if (st->lsb_flag && !st->info->has_burst32) {
+ if (st->lsb_flag && !(st->info->flags & ADIS16475_HAS_BURST32)) {
u16 val = 0;
const u32 reg = ADIS16475_REG_X_GYRO_L +
bit * 4;
diff --git a/drivers/iio/imu/bno055/Kconfig b/drivers/iio/imu/bno055/Kconfig
index 83e53acfbe..c7f5866a17 100644
--- a/drivers/iio/imu/bno055/Kconfig
+++ b/drivers/iio/imu/bno055/Kconfig
@@ -8,6 +8,7 @@ config BOSCH_BNO055
config BOSCH_BNO055_SERIAL
tristate "Bosch BNO055 attached via UART"
depends on SERIAL_DEV_BUS
+ select REGMAP
select BOSCH_BNO055
help
Enable this to support Bosch BNO055 IMUs attached via UART.
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c
index 7327e5723f..8a7f291190 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c
@@ -71,6 +71,19 @@ int inv_mpu_aux_init(const struct inv_mpu6050_state *st)
unsigned int val;
int ret;
+ /*
+ * Code based on the vendor Linux kernel v3.0,
+ * the exact meaning is unknown.
+ */
+ if (st->chip_type == INV_MPU9150) {
+ unsigned int mask = BIT(7);
+
+ val = st->level_shifter ? mask : 0;
+ ret = regmap_update_bits(st->map, 0x1, mask, val);
+ if (ret)
+ return ret;
+ }
+
/* configure i2c master */
val = INV_MPU6050_BITS_I2C_MST_CLK_400KHZ |
INV_MPU6050_BIT_WAIT_FOR_ES;
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index a9a5fb266e..6b034dccc3 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -17,6 +17,7 @@
#include <linux/regulator/consumer.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
+#include <linux/property.h>
#include <linux/iio/common/inv_sensors_timestamp.h>
#include <linux/iio/iio.h>
@@ -1495,6 +1496,8 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
st->irq = irq;
st->map = regmap;
+ st->level_shifter = device_property_read_bool(dev,
+ "invensense,level-shifter");
pdata = dev_get_platdata(dev);
if (!pdata) {
result = iio_read_mount_matrix(dev, &st->orientation);
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index ed5a96e78d..5950e2419e 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -203,6 +203,7 @@ struct inv_mpu6050_state {
s32 magn_raw_to_gauss[3];
struct iio_mount_matrix magn_orient;
unsigned int suspended_sensors;
+ bool level_shifter;
u8 *data;
};
@@ -464,7 +465,6 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev, int irq_type);
int inv_mpu6050_prepare_fifo(struct inv_mpu6050_state *st, bool enable);
int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en,
unsigned int mask);
-int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 val);
int inv_mpu_acpi_create_mux_client(struct i2c_client *client);
void inv_mpu_acpi_delete_mux_client(struct i2c_client *client);
int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index d752e9c049..e6d3d07a4c 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -90,6 +90,10 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_POSITIONRELATIVE] = "positionrelative",
[IIO_PHASE] = "phase",
[IIO_MASSCONCENTRATION] = "massconcentration",
+ [IIO_DELTA_ANGL] = "deltaangl",
+ [IIO_DELTA_VELOCITY] = "deltavelocity",
+ [IIO_COLORTEMP] = "colortemp",
+ [IIO_CHROMATICITY] = "chromaticity",
};
static const char * const iio_modifier_names[] = {
@@ -1577,10 +1581,13 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev)
ret = iio_device_register_sysfs_group(indio_dev,
&iio_dev_opaque->chan_attr_group);
if (ret)
- goto error_clear_attrs;
+ goto error_free_chan_attrs;
return 0;
+error_free_chan_attrs:
+ kfree(iio_dev_opaque->chan_attr_group.attrs);
+ iio_dev_opaque->chan_attr_group.attrs = NULL;
error_clear_attrs:
iio_free_chan_devattr_list(&iio_dev_opaque->channel_attr_list);
diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
index 19f7a91157..910c1f14ab 100644
--- a/drivers/iio/industrialio-event.c
+++ b/drivers/iio/industrialio-event.c
@@ -355,6 +355,21 @@ static ssize_t iio_ev_value_store(struct device *dev,
return len;
}
+static ssize_t iio_ev_label_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ 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_event_label)
+ return indio_dev->info->read_event_label(indio_dev,
+ this_attr->c, iio_ev_attr_type(this_attr),
+ iio_ev_attr_dir(this_attr), buf);
+
+ return -EINVAL;
+}
+
static int iio_device_add_event(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, unsigned int spec_index,
enum iio_event_type type, enum iio_event_direction dir,
@@ -411,6 +426,41 @@ static int iio_device_add_event(struct iio_dev *indio_dev,
return attrcount;
}
+static int iio_device_add_event_label(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ unsigned int spec_index,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+ char *postfix;
+ int ret;
+
+ if (!indio_dev->info->read_event_label)
+ return 0;
+
+ if (dir != IIO_EV_DIR_NONE)
+ postfix = kasprintf(GFP_KERNEL, "%s_%s_label",
+ iio_ev_type_text[type],
+ iio_ev_dir_text[dir]);
+ else
+ postfix = kasprintf(GFP_KERNEL, "%s_label",
+ iio_ev_type_text[type]);
+ if (postfix == NULL)
+ return -ENOMEM;
+
+ ret = __iio_add_chan_devattr(postfix, chan, &iio_ev_label_show, NULL,
+ spec_index, IIO_SEPARATE, &indio_dev->dev, NULL,
+ &iio_dev_opaque->event_interface->dev_attr_list);
+
+ kfree(postfix);
+
+ if (ret < 0)
+ return ret;
+
+ return 1;
+}
+
static int iio_device_add_event_sysfs(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan)
{
@@ -448,6 +498,11 @@ static int iio_device_add_event_sysfs(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
attrcount += ret;
+
+ ret = iio_device_add_event_label(indio_dev, chan, i, type, dir);
+ if (ret < 0)
+ return ret;
+ attrcount += ret;
}
ret = attrcount;
return ret;
diff --git a/drivers/iio/light/cm3605.c b/drivers/iio/light/cm3605.c
index e7f0b81b7f..22a63a89f2 100644
--- a/drivers/iio/light/cm3605.c
+++ b/drivers/iio/light/cm3605.c
@@ -266,7 +266,7 @@ out_disable_vdd:
return ret;
}
-static int cm3605_remove(struct platform_device *pdev)
+static void cm3605_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct cm3605 *cm3605 = iio_priv(indio_dev);
@@ -276,8 +276,6 @@ static int cm3605_remove(struct platform_device *pdev)
gpiod_set_value_cansleep(cm3605->aset, 0);
iio_device_unregister(indio_dev);
regulator_disable(cm3605->vdd);
-
- return 0;
}
static int cm3605_pm_suspend(struct device *dev)
@@ -320,7 +318,7 @@ static struct platform_driver cm3605_driver = {
.pm = pm_sleep_ptr(&cm3605_dev_pm_ops),
},
.probe = cm3605_probe,
- .remove = cm3605_remove,
+ .remove_new = cm3605_remove,
};
module_platform_driver(cm3605_driver);
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
index eb1aedad7e..b6c4bef2a7 100644
--- a/drivers/iio/light/hid-sensor-als.c
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -24,7 +24,7 @@ enum {
struct als_state {
struct hid_sensor_hub_callbacks callbacks;
struct hid_sensor_common common_attributes;
- struct hid_sensor_hub_attribute_info als_illum;
+ struct hid_sensor_hub_attribute_info als[CHANNEL_SCAN_INDEX_MAX];
struct {
u32 illum[CHANNEL_SCAN_INDEX_MAX];
u64 timestamp __aligned(8);
@@ -99,8 +99,8 @@ static int als_read_raw(struct iio_dev *indio_dev,
switch (chan->scan_index) {
case CHANNEL_SCAN_INDEX_INTENSITY:
case CHANNEL_SCAN_INDEX_ILLUM:
- report_id = als_state->als_illum.report_id;
- min = als_state->als_illum.logical_minimum;
+ report_id = als_state->als[chan->scan_index].report_id;
+ min = als_state->als[chan->scan_index].logical_minimum;
address = HID_USAGE_SENSOR_LIGHT_ILLUM;
break;
default:
@@ -226,6 +226,7 @@ static int als_capture_sample(struct hid_sensor_hub_device *hsdev,
case HID_USAGE_SENSOR_TIME_TIMESTAMP:
als_state->timestamp = hid_sensor_convert_timestamp(&als_state->common_attributes,
*(s64 *)raw_data);
+ ret = 0;
break;
default:
break;
@@ -242,22 +243,24 @@ static int als_parse_report(struct platform_device *pdev,
struct als_state *st)
{
int ret;
+ int i;
+
+ for (i = 0; i <= CHANNEL_SCAN_INDEX_ILLUM; ++i) {
+ ret = sensor_hub_input_get_attribute_info(hsdev,
+ HID_INPUT_REPORT,
+ usage_id,
+ HID_USAGE_SENSOR_LIGHT_ILLUM,
+ &st->als[i]);
+ if (ret < 0)
+ return ret;
+ als_adjust_channel_bit_mask(channels, i, st->als[i].size);
+
+ dev_dbg(&pdev->dev, "als %x:%x\n", st->als[i].index,
+ st->als[i].report_id);
+ }
- ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
- usage_id,
- HID_USAGE_SENSOR_LIGHT_ILLUM,
- &st->als_illum);
- if (ret < 0)
- return ret;
- als_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_INTENSITY,
- st->als_illum.size);
- als_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_ILLUM,
- st->als_illum.size);
-
- dev_dbg(&pdev->dev, "als %x:%x\n", st->als_illum.index,
- st->als_illum.report_id);
-
- st->scale_precision = hid_sensor_format_scale(usage_id, &st->als_illum,
+ st->scale_precision = hid_sensor_format_scale(usage_id,
+ &st->als[CHANNEL_SCAN_INDEX_INTENSITY],
&st->scale_pre_decml, &st->scale_post_decml);
return ret;
@@ -347,7 +350,7 @@ error_remove_trigger:
}
/* Function to deinitialize the processing for usage id */
-static int hid_als_remove(struct platform_device *pdev)
+static void hid_als_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -356,8 +359,6 @@ static int hid_als_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes);
-
- return 0;
}
static const struct platform_device_id hid_als_ids[] = {
@@ -380,7 +381,7 @@ static struct platform_driver hid_als_platform_driver = {
.pm = &hid_sensor_pm_ops,
},
.probe = hid_als_probe,
- .remove = hid_als_remove,
+ .remove_new = hid_als_remove,
};
module_platform_driver(hid_als_platform_driver);
diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c
index a47591e1ba..26c481d299 100644
--- a/drivers/iio/light/hid-sensor-prox.c
+++ b/drivers/iio/light/hid-sensor-prox.c
@@ -313,7 +313,7 @@ error_remove_trigger:
}
/* Function to deinitialize the processing for usage id */
-static int hid_prox_remove(struct platform_device *pdev)
+static void hid_prox_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -322,8 +322,6 @@ static int hid_prox_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes);
-
- return 0;
}
static const struct platform_device_id hid_prox_ids[] = {
@@ -346,7 +344,7 @@ static struct platform_driver hid_prox_platform_driver = {
.pm = &hid_sensor_pm_ops,
},
.probe = hid_prox_probe,
- .remove = hid_prox_remove,
+ .remove_new = hid_prox_remove,
};
module_platform_driver(hid_prox_platform_driver);
diff --git a/drivers/iio/light/lm3533-als.c b/drivers/iio/light/lm3533-als.c
index 827bc25269..7800f7fa51 100644
--- a/drivers/iio/light/lm3533-als.c
+++ b/drivers/iio/light/lm3533-als.c
@@ -895,7 +895,7 @@ err_free_irq:
return ret;
}
-static int lm3533_als_remove(struct platform_device *pdev)
+static void lm3533_als_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct lm3533_als *als = iio_priv(indio_dev);
@@ -905,8 +905,6 @@ static int lm3533_als_remove(struct platform_device *pdev)
lm3533_als_disable(als);
if (als->irq)
free_irq(als->irq, indio_dev);
-
- return 0;
}
static struct platform_driver lm3533_als_driver = {
@@ -914,7 +912,7 @@ static struct platform_driver lm3533_als_driver = {
.name = "lm3533-als",
},
.probe = lm3533_als_probe,
- .remove = lm3533_als_remove,
+ .remove_new = lm3533_als_remove,
};
module_platform_driver(lm3533_als_driver);
diff --git a/drivers/iio/light/opt4001.c b/drivers/iio/light/opt4001.c
index 502946bf9f..6cf60151b3 100644
--- a/drivers/iio/light/opt4001.c
+++ b/drivers/iio/light/opt4001.c
@@ -412,7 +412,7 @@ static int opt4001_probe(struct i2c_client *client)
if (dev_id != OPT4001_DEVICE_ID_VAL)
dev_warn(&client->dev, "Device ID: %#04x unknown\n", dev_id);
- chip->chip_info = device_get_match_data(&client->dev);
+ chip->chip_info = i2c_get_match_data(client);
indio_dev->channels = opt4001_channels;
indio_dev->num_channels = ARRAY_SIZE(opt4001_channels);
diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
index eb706d0bf7..dd466c5fa6 100644
--- a/drivers/iio/magnetometer/ak8975.c
+++ b/drivers/iio/magnetometer/ak8975.c
@@ -204,7 +204,6 @@ static long ak09912_raw_to_gauss(u16 data)
/* Compatible Asahi Kasei Compass parts */
enum asahi_compass_chipset {
- AKXXXX = 0,
AK8975,
AK8963,
AK09911,
@@ -248,7 +247,7 @@ struct ak_def {
};
static const struct ak_def ak_def_array[] = {
- {
+ [AK8975] = {
.type = AK8975,
.raw_to_gauss = ak8975_raw_to_gauss,
.range = 4096,
@@ -273,7 +272,7 @@ static const struct ak_def ak_def_array[] = {
AK8975_REG_HYL,
AK8975_REG_HZL},
},
- {
+ [AK8963] = {
.type = AK8963,
.raw_to_gauss = ak8963_09911_raw_to_gauss,
.range = 8190,
@@ -298,7 +297,7 @@ static const struct ak_def ak_def_array[] = {
AK8975_REG_HYL,
AK8975_REG_HZL},
},
- {
+ [AK09911] = {
.type = AK09911,
.raw_to_gauss = ak8963_09911_raw_to_gauss,
.range = 8192,
@@ -323,7 +322,7 @@ static const struct ak_def ak_def_array[] = {
AK09912_REG_HYL,
AK09912_REG_HZL},
},
- {
+ [AK09912] = {
.type = AK09912,
.raw_to_gauss = ak09912_raw_to_gauss,
.range = 32752,
@@ -348,7 +347,7 @@ static const struct ak_def ak_def_array[] = {
AK09912_REG_HYL,
AK09912_REG_HZL},
},
- {
+ [AK09916] = {
.type = AK09916,
.raw_to_gauss = ak09912_raw_to_gauss,
.range = 32752,
@@ -812,18 +811,6 @@ static const struct iio_info ak8975_info = {
.read_raw = &ak8975_read_raw,
};
-static const struct acpi_device_id ak_acpi_match[] = {
- {"AK8975", AK8975},
- {"AK8963", AK8963},
- {"INVN6500", AK8963},
- {"AK009911", AK09911},
- {"AK09911", AK09911},
- {"AKM9911", AK09911},
- {"AK09912", AK09912},
- { }
-};
-MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
-
static void ak8975_fill_buffer(struct iio_dev *indio_dev)
{
struct ak8975_data *data = iio_priv(indio_dev);
@@ -883,10 +870,7 @@ static int ak8975_probe(struct i2c_client *client)
struct iio_dev *indio_dev;
struct gpio_desc *eoc_gpiod;
struct gpio_desc *reset_gpiod;
- const void *match;
- unsigned int i;
int err;
- enum asahi_compass_chipset chipset;
const char *name = NULL;
/*
@@ -928,27 +912,15 @@ static int ak8975_probe(struct i2c_client *client)
return err;
/* id will be NULL when enumerated via ACPI */
- match = device_get_match_data(&client->dev);
- if (match) {
- chipset = (uintptr_t)match;
- name = dev_name(&client->dev);
- } else if (id) {
- chipset = (enum asahi_compass_chipset)(id->driver_data);
- name = id->name;
- } else
- return -ENOSYS;
-
- for (i = 0; i < ARRAY_SIZE(ak_def_array); i++)
- if (ak_def_array[i].type == chipset)
- break;
-
- if (i == ARRAY_SIZE(ak_def_array)) {
- dev_err(&client->dev, "AKM device type unsupported: %d\n",
- chipset);
+ data->def = i2c_get_match_data(client);
+ if (!data->def)
return -ENODEV;
- }
- data->def = &ak_def_array[i];
+ /* If enumerated via firmware node, fix the ABI */
+ if (dev_fwnode(&client->dev))
+ name = dev_name(&client->dev);
+ else
+ name = id->name;
/* Fetch the regulators */
data->vdd = devm_regulator_get(&client->dev, "vdd");
@@ -1076,29 +1048,40 @@ static int ak8975_runtime_resume(struct device *dev)
static DEFINE_RUNTIME_DEV_PM_OPS(ak8975_dev_pm_ops, ak8975_runtime_suspend,
ak8975_runtime_resume, NULL);
+static const struct acpi_device_id ak_acpi_match[] = {
+ {"AK8963", (kernel_ulong_t)&ak_def_array[AK8963] },
+ {"AK8975", (kernel_ulong_t)&ak_def_array[AK8975] },
+ {"AK009911", (kernel_ulong_t)&ak_def_array[AK09911] },
+ {"AK09911", (kernel_ulong_t)&ak_def_array[AK09911] },
+ {"AK09912", (kernel_ulong_t)&ak_def_array[AK09912] },
+ {"AKM9911", (kernel_ulong_t)&ak_def_array[AK09911] },
+ {"INVN6500", (kernel_ulong_t)&ak_def_array[AK8963] },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
+
static const struct i2c_device_id ak8975_id[] = {
- {"ak8975", AK8975},
- {"ak8963", AK8963},
- {"AK8963", AK8963},
- {"ak09911", AK09911},
- {"ak09912", AK09912},
- {"ak09916", AK09916},
+ {"AK8963", (kernel_ulong_t)&ak_def_array[AK8963] },
+ {"ak8963", (kernel_ulong_t)&ak_def_array[AK8963] },
+ {"ak8975", (kernel_ulong_t)&ak_def_array[AK8975] },
+ {"ak09911", (kernel_ulong_t)&ak_def_array[AK09911] },
+ {"ak09912", (kernel_ulong_t)&ak_def_array[AK09912] },
+ {"ak09916", (kernel_ulong_t)&ak_def_array[AK09916] },
{}
};
-
MODULE_DEVICE_TABLE(i2c, ak8975_id);
static const struct of_device_id ak8975_of_match[] = {
- { .compatible = "asahi-kasei,ak8975", },
- { .compatible = "ak8975", },
- { .compatible = "asahi-kasei,ak8963", },
- { .compatible = "ak8963", },
- { .compatible = "asahi-kasei,ak09911", },
- { .compatible = "ak09911", },
- { .compatible = "asahi-kasei,ak09912", },
- { .compatible = "ak09912", },
- { .compatible = "asahi-kasei,ak09916", },
- { .compatible = "ak09916", },
+ { .compatible = "asahi-kasei,ak8975", .data = &ak_def_array[AK8975] },
+ { .compatible = "ak8975", .data = &ak_def_array[AK8975] },
+ { .compatible = "asahi-kasei,ak8963", .data = &ak_def_array[AK8963] },
+ { .compatible = "ak8963", .data = &ak_def_array[AK8963] },
+ { .compatible = "asahi-kasei,ak09911", .data = &ak_def_array[AK09911] },
+ { .compatible = "ak09911", .data = &ak_def_array[AK09911] },
+ { .compatible = "asahi-kasei,ak09912", .data = &ak_def_array[AK09912] },
+ { .compatible = "ak09912", .data = &ak_def_array[AK09912] },
+ { .compatible = "asahi-kasei,ak09916", .data = &ak_def_array[AK09916] },
+ { .compatible = "ak09916", .data = &ak_def_array[AK09916] },
{}
};
MODULE_DEVICE_TABLE(of, ak8975_of_match);
diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
index e85a3a8eea..5c795a430d 100644
--- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c
+++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
@@ -547,7 +547,7 @@ error_remove_trigger:
}
/* Function to deinitialize the processing for usage id */
-static int hid_magn_3d_remove(struct platform_device *pdev)
+static void hid_magn_3d_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -556,8 +556,6 @@ static int hid_magn_3d_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(indio_dev, &magn_state->magn_flux_attributes);
-
- return 0;
}
static const struct platform_device_id hid_magn_3d_ids[] = {
@@ -576,7 +574,7 @@ static struct platform_driver hid_magn_3d_platform_driver = {
.pm = &hid_sensor_pm_ops,
},
.probe = hid_magn_3d_probe,
- .remove = hid_magn_3d_remove,
+ .remove_new = hid_magn_3d_remove,
};
module_platform_driver(hid_magn_3d_platform_driver);
diff --git a/drivers/iio/magnetometer/rm3100-core.c b/drivers/iio/magnetometer/rm3100-core.c
index 6993820445..42b70cd42b 100644
--- a/drivers/iio/magnetometer/rm3100-core.c
+++ b/drivers/iio/magnetometer/rm3100-core.c
@@ -530,6 +530,7 @@ int rm3100_common_probe(struct device *dev, struct regmap *regmap, int irq)
struct rm3100_data *data;
unsigned int tmp;
int ret;
+ int samp_rate_index;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
@@ -586,9 +587,14 @@ int rm3100_common_probe(struct device *dev, struct regmap *regmap, int irq)
ret = regmap_read(regmap, RM3100_REG_TMRC, &tmp);
if (ret < 0)
return ret;
+
+ samp_rate_index = tmp - RM3100_TMRC_OFFSET;
+ if (samp_rate_index < 0 || samp_rate_index >= RM3100_SAMP_NUM) {
+ dev_err(dev, "The value read from RM3100_REG_TMRC is invalid!\n");
+ return -EINVAL;
+ }
/* Initializing max wait time, which is double conversion time. */
- data->conversion_time = rm3100_samp_rates[tmp - RM3100_TMRC_OFFSET][2]
- * 2;
+ data->conversion_time = rm3100_samp_rates[samp_rate_index][2] * 2;
/* Cycle count values may not be what we want. */
if ((tmp - RM3100_TMRC_OFFSET) == 0)
diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c
index c5e485bfc6..7b041bb386 100644
--- a/drivers/iio/magnetometer/yamaha-yas530.c
+++ b/drivers/iio/magnetometer/yamaha-yas530.c
@@ -1434,9 +1434,7 @@ static int yas5xx_probe(struct i2c_client *i2c)
goto assert_reset;
}
- ci = device_get_match_data(dev);
- if (!ci)
- ci = (const struct yas5xx_chip_info *)id->driver_data;
+ ci = i2c_get_match_data(i2c);
yas5xx->chip_info = ci;
ret = regmap_read(yas5xx->map, YAS5XX_DEVICE_ID, &id_check);
diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c
index ba5b581d5b..8943d5c78b 100644
--- a/drivers/iio/orientation/hid-sensor-incl-3d.c
+++ b/drivers/iio/orientation/hid-sensor-incl-3d.c
@@ -383,7 +383,7 @@ error_remove_trigger:
}
/* Function to deinitialize the processing for usage id */
-static int hid_incl_3d_remove(struct platform_device *pdev)
+static void hid_incl_3d_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -392,8 +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);
-
- return 0;
}
static const struct platform_device_id hid_incl_3d_ids[] = {
@@ -412,7 +410,7 @@ static struct platform_driver hid_incl_3d_platform_driver = {
.pm = &hid_sensor_pm_ops,
},
.probe = hid_incl_3d_probe,
- .remove = hid_incl_3d_remove,
+ .remove_new = hid_incl_3d_remove,
};
module_platform_driver(hid_incl_3d_platform_driver);
diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c
index a033699910..5e8cadd517 100644
--- a/drivers/iio/orientation/hid-sensor-rotation.c
+++ b/drivers/iio/orientation/hid-sensor-rotation.c
@@ -327,7 +327,7 @@ error_remove_trigger:
}
/* Function to deinitialize the processing for usage id */
-static int hid_dev_rot_remove(struct platform_device *pdev)
+static void hid_dev_rot_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -336,8 +336,6 @@ static int hid_dev_rot_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(indio_dev, &rot_state->common_attributes);
-
- return 0;
}
static const struct platform_device_id hid_dev_rot_ids[] = {
@@ -364,7 +362,7 @@ static struct platform_driver hid_dev_rot_platform_driver = {
.pm = &hid_sensor_pm_ops,
},
.probe = hid_dev_rot_probe,
- .remove = hid_dev_rot_remove,
+ .remove_new = hid_dev_rot_remove,
};
module_platform_driver(hid_dev_rot_platform_driver);
diff --git a/drivers/iio/position/hid-sensor-custom-intel-hinge.c b/drivers/iio/position/hid-sensor-custom-intel-hinge.c
index 07c30d2172..76e173850a 100644
--- a/drivers/iio/position/hid-sensor-custom-intel-hinge.c
+++ b/drivers/iio/position/hid-sensor-custom-intel-hinge.c
@@ -342,7 +342,7 @@ error_remove_trigger:
}
/* Function to deinitialize the processing for usage id */
-static int hid_hinge_remove(struct platform_device *pdev)
+static void hid_hinge_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -351,8 +351,6 @@ static int hid_hinge_remove(struct platform_device *pdev)
iio_device_unregister(indio_dev);
sensor_hub_remove_callback(hsdev, hsdev->usage);
hid_sensor_remove_trigger(indio_dev, &st->common_attributes);
-
- return 0;
}
static const struct platform_device_id hid_hinge_ids[] = {
@@ -371,7 +369,7 @@ static struct platform_driver hid_hinge_platform_driver = {
.pm = &hid_sensor_pm_ops,
},
.probe = hid_hinge_probe,
- .remove = hid_hinge_remove,
+ .remove_new = hid_hinge_remove,
};
module_platform_driver(hid_hinge_platform_driver);
diff --git a/drivers/iio/potentiometer/ad5110.c b/drivers/iio/potentiometer/ad5110.c
index 991e745c4f..aaf02cc7ae 100644
--- a/drivers/iio/potentiometer/ad5110.c
+++ b/drivers/iio/potentiometer/ad5110.c
@@ -278,14 +278,19 @@ static const struct of_device_id ad5110_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ad5110_of_match);
+#define AD5110_ID_TABLE(_name, cfg) { \
+ .name = _name, \
+ .driver_data = (kernel_ulong_t)&ad5110_cfg[cfg], \
+}
+
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 },
+ AD5110_ID_TABLE("ad5110-10", AD5110_10),
+ AD5110_ID_TABLE("ad5110-80", AD5110_80),
+ AD5110_ID_TABLE("ad5112-05", AD5112_05),
+ AD5110_ID_TABLE("ad5112-10", AD5112_10),
+ AD5110_ID_TABLE("ad5112-80", AD5112_80),
+ AD5110_ID_TABLE("ad5114-10", AD5114_10),
+ AD5110_ID_TABLE("ad5114-80", AD5114_80),
{ }
};
MODULE_DEVICE_TABLE(i2c, ad5110_id);
@@ -305,7 +310,7 @@ static int ad5110_probe(struct i2c_client *client)
data->client = client;
mutex_init(&data->lock);
data->enable = 1;
- data->cfg = device_get_match_data(dev);
+ data->cfg = i2c_get_match_data(client);
/* refresh RDAC register with EEPROM */
ret = ad5110_write(data, AD5110_RESET, 0);
diff --git a/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c
index fc183e0790..e0526dd0e3 100644
--- a/drivers/iio/potentiometer/ds1803.c
+++ b/drivers/iio/potentiometer/ds1803.c
@@ -204,7 +204,6 @@ static const struct iio_info ds1803_info = {
static int ds1803_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device *dev = &client->dev;
struct ds1803_data *data;
struct iio_dev *indio_dev;
@@ -217,9 +216,7 @@ static int ds1803_probe(struct i2c_client *client)
data = iio_priv(indio_dev);
data->client = client;
- data->cfg = device_get_match_data(dev);
- if (!data->cfg)
- data->cfg = &ds1803_cfg[id->driver_data];
+ data->cfg = i2c_get_match_data(client);
indio_dev->info = &ds1803_info;
indio_dev->channels = data->cfg->channels;
@@ -239,10 +236,10 @@ static const struct of_device_id ds1803_dt_ids[] = {
MODULE_DEVICE_TABLE(of, ds1803_dt_ids);
static const struct i2c_device_id ds1803_id[] = {
- { "ds1803-010", DS1803_010 },
- { "ds1803-050", DS1803_050 },
- { "ds1803-100", DS1803_100 },
- { "ds3502", DS3502 },
+ { "ds1803-010", (kernel_ulong_t)&ds1803_cfg[DS1803_010] },
+ { "ds1803-050", (kernel_ulong_t)&ds1803_cfg[DS1803_050] },
+ { "ds1803-100", (kernel_ulong_t)&ds1803_cfg[DS1803_100] },
+ { "ds3502", (kernel_ulong_t)&ds1803_cfg[DS3502] },
{}
};
MODULE_DEVICE_TABLE(i2c, ds1803_id);
diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
index 7b4c2af328..95efa32e42 100644
--- a/drivers/iio/pressure/Kconfig
+++ b/drivers/iio/pressure/Kconfig
@@ -16,6 +16,15 @@ config ABP060MG
To compile this driver as a module, choose M here: the module
will be called abp060mg.
+config ROHM_BM1390
+ tristate "ROHM BM1390GLV-Z pressure sensor driver"
+ depends on I2C
+ help
+ Support for the ROHM BM1390 pressure sensor. The BM1390GLV-Z
+ can measure pressures ranging from 300 hPa to 1300 hPa with
+ configurable measurement averaging and internal FIFO. The
+ sensor does also provide temperature measurements.
+
config BMP280
tristate "Bosch Sensortec BMP180/BMP280/BMP380/BMP580 pressure sensor driver"
depends on (I2C || SPI_MASTER)
diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile
index c90f77210e..436aec7e65 100644
--- a/drivers/iio/pressure/Makefile
+++ b/drivers/iio/pressure/Makefile
@@ -5,6 +5,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_ABP060MG) += abp060mg.o
+obj-$(CONFIG_ROHM_BM1390) += rohm-bm1390.o
obj-$(CONFIG_BMP280) += bmp280.o
bmp280-objs := bmp280-core.o bmp280-regmap.o
obj-$(CONFIG_BMP280_I2C) += bmp280-i2c.o
diff --git a/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c
index 1dff9bb7c4..967de99c1b 100644
--- a/drivers/iio/pressure/bmp280-spi.c
+++ b/drivers/iio/pressure/bmp280-spi.c
@@ -91,6 +91,7 @@ static const struct of_device_id bmp280_of_spi_match[] = {
MODULE_DEVICE_TABLE(of, bmp280_of_spi_match);
static const struct spi_device_id bmp280_spi_id[] = {
+ { "bmp085", (kernel_ulong_t)&bmp180_chip_info },
{ "bmp180", (kernel_ulong_t)&bmp180_chip_info },
{ "bmp181", (kernel_ulong_t)&bmp180_chip_info },
{ "bmp280", (kernel_ulong_t)&bmp280_chip_info },
diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c
index a9215eb32d..956045e2db 100644
--- a/drivers/iio/pressure/hid-sensor-press.c
+++ b/drivers/iio/pressure/hid-sensor-press.c
@@ -323,7 +323,7 @@ error_remove_trigger:
}
/* Function to deinitialize the processing for usage id */
-static int hid_press_remove(struct platform_device *pdev)
+static void hid_press_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -332,8 +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);
-
- return 0;
}
static const struct platform_device_id hid_press_ids[] = {
@@ -352,7 +350,7 @@ static struct platform_driver hid_press_platform_driver = {
.pm = &hid_sensor_pm_ops,
},
.probe = hid_press_probe,
- .remove = hid_press_remove,
+ .remove_new = hid_press_remove,
};
module_platform_driver(hid_press_platform_driver);
diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c
index 9b3abffb72..ac30d76285 100644
--- a/drivers/iio/pressure/ms5637.c
+++ b/drivers/iio/pressure/ms5637.c
@@ -144,7 +144,6 @@ static const struct iio_info ms5637_info = {
static int ms5637_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
const struct ms_tp_data *data;
struct ms_tp_dev *dev_data;
struct iio_dev *indio_dev;
@@ -159,10 +158,7 @@ static int ms5637_probe(struct i2c_client *client)
return -EOPNOTSUPP;
}
- if (id)
- data = (const struct ms_tp_data *)id->driver_data;
- else
- data = device_get_match_data(&client->dev);
+ data = i2c_get_match_data(client);
if (!data)
return -EINVAL;
diff --git a/drivers/iio/pressure/rohm-bm1390.c b/drivers/iio/pressure/rohm-bm1390.c
new file mode 100644
index 0000000000..ccaa07a569
--- /dev/null
+++ b/drivers/iio/pressure/rohm-bm1390.c
@@ -0,0 +1,934 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * BM1390 ROHM pressure sensor
+ *
+ * Copyright (c) 2023, ROHM Semiconductor.
+ * https://fscdn.rohm.com/en/products/databook/datasheet/ic/sensor/pressure/bm1390glv-z-e.pdf
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define BM1390_REG_MANUFACT_ID 0x0f
+#define BM1390_REG_PART_ID 0x10
+#define BM1390_REG_POWER 0x12
+#define BM1390_MASK_POWER BIT(0)
+#define BM1390_POWER_ON BM1390_MASK_POWER
+#define BM1390_POWER_OFF 0x00
+#define BM1390_REG_RESET 0x13
+#define BM1390_MASK_RESET BIT(0)
+#define BM1390_RESET_RELEASE BM1390_MASK_RESET
+#define BM1390_RESET 0x00
+#define BM1390_REG_MODE_CTRL 0x14
+#define BM1390_MASK_MEAS_MODE GENMASK(1, 0)
+#define BM1390_MASK_DRDY_EN BIT(4)
+#define BM1390_MASK_WMI_EN BIT(2)
+#define BM1390_MASK_AVE_NUM GENMASK(7, 5)
+
+/*
+ * Data-sheet states that when the IIR is used, the AVE_NUM must be set to
+ * value 110b
+ */
+#define BM1390_IIR_AVE_NUM 0x06
+#define BM1390_REG_FIFO_CTRL 0x15
+#define BM1390_MASK_IIR_MODE GENMASK(1, 0)
+#define BM1390_IIR_MODE_OFF 0x0
+#define BM1390_IIR_MODE_WEAK 0x1
+#define BM1390_IIR_MODE_MID 0x2
+#define BM1390_IIR_MODE_STRONG 0x3
+
+#define BM1390_MASK_FIFO_LEN BIT(6)
+#define BM1390_MASK_FIFO_EN BIT(7)
+#define BM1390_WMI_MIN 2
+#define BM1390_WMI_MAX 3
+
+#define BM1390_REG_FIFO_LVL 0x18
+#define BM1390_MASK_FIFO_LVL GENMASK(2, 0)
+#define BM1390_REG_STATUS 0x19
+#define BM1390_REG_PRESSURE_BASE 0x1a
+#define BM1390_REG_TEMP_HI 0x1d
+#define BM1390_REG_TEMP_LO 0x1e
+#define BM1390_MAX_REGISTER BM1390_REG_TEMP_LO
+
+#define BM1390_ID 0x34
+
+/* Regmap configs */
+static const struct regmap_range bm1390_volatile_ranges[] = {
+ {
+ .range_min = BM1390_REG_STATUS,
+ .range_max = BM1390_REG_STATUS,
+ },
+ {
+ .range_min = BM1390_REG_FIFO_LVL,
+ .range_max = BM1390_REG_TEMP_LO,
+ },
+};
+
+static const struct regmap_access_table bm1390_volatile_regs = {
+ .yes_ranges = &bm1390_volatile_ranges[0],
+ .n_yes_ranges = ARRAY_SIZE(bm1390_volatile_ranges),
+};
+
+static const struct regmap_range bm1390_precious_ranges[] = {
+ {
+ .range_min = BM1390_REG_STATUS,
+ .range_max = BM1390_REG_STATUS,
+ },
+};
+
+static const struct regmap_access_table bm1390_precious_regs = {
+ .yes_ranges = &bm1390_precious_ranges[0],
+ .n_yes_ranges = ARRAY_SIZE(bm1390_precious_ranges),
+};
+
+static const struct regmap_range bm1390_read_only_ranges[] = {
+ {
+ .range_min = BM1390_REG_MANUFACT_ID,
+ .range_max = BM1390_REG_PART_ID,
+ }, {
+ .range_min = BM1390_REG_FIFO_LVL,
+ .range_max = BM1390_REG_TEMP_LO,
+ },
+};
+
+static const struct regmap_access_table bm1390_ro_regs = {
+ .no_ranges = &bm1390_read_only_ranges[0],
+ .n_no_ranges = ARRAY_SIZE(bm1390_read_only_ranges),
+};
+
+static const struct regmap_range bm1390_noinc_read_ranges[] = {
+ {
+ .range_min = BM1390_REG_PRESSURE_BASE,
+ .range_max = BM1390_REG_TEMP_LO,
+ },
+};
+
+static const struct regmap_access_table bm1390_nir_regs = {
+ .yes_ranges = &bm1390_noinc_read_ranges[0],
+ .n_yes_ranges = ARRAY_SIZE(bm1390_noinc_read_ranges),
+};
+
+static const struct regmap_config bm1390_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_table = &bm1390_volatile_regs,
+ .wr_table = &bm1390_ro_regs,
+ .rd_noinc_table = &bm1390_nir_regs,
+ .precious_table = &bm1390_precious_regs,
+ .max_register = BM1390_MAX_REGISTER,
+ .cache_type = REGCACHE_RBTREE,
+ .disable_locking = true,
+};
+
+enum {
+ BM1390_STATE_SAMPLE,
+ BM1390_STATE_FIFO,
+};
+
+struct bm1390_data_buf {
+ u32 pressure;
+ __be16 temp;
+ s64 ts __aligned(8);
+};
+
+/* BM1390 has FIFO for 4 pressure samples */
+#define BM1390_FIFO_LENGTH 4
+
+struct bm1390_data {
+ s64 timestamp, old_timestamp;
+ struct iio_trigger *trig;
+ struct regmap *regmap;
+ struct device *dev;
+ struct bm1390_data_buf buf;
+ int irq;
+ unsigned int state;
+ bool trigger_enabled;
+ u8 watermark;
+
+ /* Prevent accessing sensor during FIFO read sequence */
+ struct mutex mutex;
+};
+
+enum {
+ BM1390_CHAN_PRESSURE,
+ BM1390_CHAN_TEMP,
+};
+
+static const struct iio_chan_spec bm1390_channels[] = {
+ {
+ .type = IIO_PRESSURE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ /*
+ * When IIR is used, we must fix amount of averaged samples.
+ * Thus we don't allow setting oversampling ratio.
+ */
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = BM1390_CHAN_PRESSURE,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 22,
+ .storagebits = 32,
+ .endianness = IIO_LE,
+ },
+ },
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = BM1390_CHAN_TEMP,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_BE,
+ },
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(2),
+};
+
+/*
+ * We can't skip reading the pressure because the watermark IRQ is acked
+ * only when the pressure data is read from the FIFO.
+ */
+static const unsigned long bm1390_scan_masks[] = {
+ BIT(BM1390_CHAN_PRESSURE),
+ BIT(BM1390_CHAN_PRESSURE) | BIT(BM1390_CHAN_TEMP),
+ 0
+};
+
+static int bm1390_read_temp(struct bm1390_data *data, int *temp)
+{
+ __be16 temp_raw;
+ int ret;
+
+ ret = regmap_bulk_read(data->regmap, BM1390_REG_TEMP_HI, &temp_raw,
+ sizeof(temp_raw));
+ if (ret)
+ return ret;
+
+ *temp = be16_to_cpu(temp_raw);
+
+ return 0;
+}
+
+static int bm1390_pressure_read(struct bm1390_data *data, u32 *pressure)
+{
+ /* Pressure data is in 3 8-bit registers */
+ u8 raw[3];
+ int ret;
+
+ ret = regmap_bulk_read(data->regmap, BM1390_REG_PRESSURE_BASE,
+ raw, sizeof(raw));
+ if (ret < 0)
+ return ret;
+
+ *pressure = (u32)(raw[2] >> 2 | raw[1] << 6 | raw[0] << 14);
+
+ return 0;
+}
+
+ /* The enum values map directly to register bits */
+enum bm1390_meas_mode {
+ BM1390_MEAS_MODE_STOP = 0x0,
+ BM1390_MEAS_MODE_1SHOT = 0x1,
+ BM1390_MEAS_MODE_CONTINUOUS = 0x2,
+};
+
+static int bm1390_meas_set(struct bm1390_data *data, enum bm1390_meas_mode mode)
+{
+ return regmap_update_bits(data->regmap, BM1390_REG_MODE_CTRL,
+ BM1390_MASK_MEAS_MODE, mode);
+}
+
+/*
+ * If the trigger is not used we just wait until the measurement has
+ * completed. The data-sheet says maximum measurement cycle (regardless
+ * the AVE_NUM) is 200 mS so let's just sleep at least that long. If speed
+ * is needed the trigger should be used.
+ */
+#define BM1390_MAX_MEAS_TIME_MS 205
+
+static int bm1390_read_data(struct bm1390_data *data,
+ struct iio_chan_spec const *chan, int *val, int *val2)
+{
+ int ret, warn;
+
+ mutex_lock(&data->mutex);
+ /*
+ * We use 'continuous mode' even for raw read because according to the
+ * data-sheet an one-shot mode can't be used with IIR filter.
+ */
+ ret = bm1390_meas_set(data, BM1390_MEAS_MODE_CONTINUOUS);
+ if (ret)
+ goto unlock_out;
+
+ switch (chan->type) {
+ case IIO_PRESSURE:
+ msleep(BM1390_MAX_MEAS_TIME_MS);
+ ret = bm1390_pressure_read(data, val);
+ break;
+ case IIO_TEMP:
+ msleep(BM1390_MAX_MEAS_TIME_MS);
+ ret = bm1390_read_temp(data, val);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ warn = bm1390_meas_set(data, BM1390_MEAS_MODE_STOP);
+ if (warn)
+ dev_warn(data->dev, "Failed to stop measurement (%d)\n", warn);
+unlock_out:
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int bm1390_read_raw(struct iio_dev *idev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct bm1390_data *data = iio_priv(idev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ if (chan->type == IIO_TEMP) {
+ *val = 31;
+ *val2 = 250000;
+
+ return IIO_VAL_INT_PLUS_MICRO;
+ } else if (chan->type == IIO_PRESSURE) {
+ /*
+ * pressure in hPa is register value divided by 2048.
+ * This means kPa is 1/20480 times the register value,
+ */
+ *val = 1;
+ *val2 = 2048;
+
+ return IIO_VAL_FRACTIONAL;
+ }
+
+ return -EINVAL;
+ case IIO_CHAN_INFO_RAW:
+ ret = iio_device_claim_direct_mode(idev);
+ if (ret)
+ return ret;
+
+ ret = bm1390_read_data(data, chan, val, val2);
+ iio_device_release_direct_mode(idev);
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int __bm1390_fifo_flush(struct iio_dev *idev, unsigned int samples,
+ s64 timestamp)
+{
+ /* BM1390_FIFO_LENGTH is small so we shouldn't run out of stack */
+ struct bm1390_data_buf buffer[BM1390_FIFO_LENGTH];
+ struct bm1390_data *data = iio_priv(idev);
+ int smp_lvl, ret, i, warn, dummy;
+ u64 sample_period;
+ __be16 temp = 0;
+
+ ret = regmap_read(data->regmap, BM1390_REG_FIFO_LVL, &smp_lvl);
+ if (ret)
+ return ret;
+
+ smp_lvl = FIELD_GET(BM1390_MASK_FIFO_LVL, smp_lvl);
+ if (!smp_lvl)
+ return 0;
+
+ if (smp_lvl > BM1390_FIFO_LENGTH) {
+ /*
+ * The fifo holds maximum of 4 samples so valid values
+ * should be 0, 1, 2, 3, 4 - rest are probably bit errors
+ * in I2C line. Don't overflow if this happens.
+ */
+ dev_err(data->dev, "bad FIFO level %d\n", smp_lvl);
+ smp_lvl = BM1390_FIFO_LENGTH;
+ }
+
+ sample_period = timestamp - data->old_timestamp;
+ do_div(sample_period, smp_lvl);
+
+ if (samples && smp_lvl > samples)
+ smp_lvl = samples;
+
+
+ /*
+ * After some testing it appears that the temperature is not readable
+ * until the FIFO access has been done after the WMI. Thus, we need
+ * to read the all pressure values to memory and read the temperature
+ * only after that.
+ */
+ for (i = 0; i < smp_lvl; i++) {
+ /*
+ * When we start reading data from the FIFO the sensor goes to
+ * special FIFO reading mode. If any other register is accessed
+ * during the FIFO read, samples can be dropped. Prevent access
+ * until FIFO_LVL is read. We have mutex locked and we do also
+ * go performing reading of FIFO_LVL even if this read fails.
+ */
+ if (test_bit(BM1390_CHAN_PRESSURE, idev->active_scan_mask)) {
+ ret = bm1390_pressure_read(data, &buffer[i].pressure);
+ if (ret)
+ break;
+ }
+
+ /*
+ * Old timestamp is either the previous sample IRQ time,
+ * previous flush-time or, if this was first sample, the enable
+ * time. When we add a sample period to that we should get the
+ * best approximation of the time-stamp we are handling.
+ *
+ * Idea is to always keep the "old_timestamp" matching the
+ * timestamp which we are currently handling.
+ */
+ data->old_timestamp += sample_period;
+ buffer[i].ts = data->old_timestamp;
+ }
+ /* Reading the FIFO_LVL closes the FIFO access sequence */
+ warn = regmap_read(data->regmap, BM1390_REG_FIFO_LVL, &dummy);
+ if (warn)
+ dev_warn(data->dev, "Closing FIFO sequence failed\n");
+
+ if (ret)
+ return ret;
+
+ if (test_bit(BM1390_CHAN_TEMP, idev->active_scan_mask)) {
+ ret = regmap_bulk_read(data->regmap, BM1390_REG_TEMP_HI, &temp,
+ sizeof(temp));
+ if (ret)
+ return ret;
+ }
+
+ if (ret)
+ return ret;
+
+ for (i = 0; i < smp_lvl; i++) {
+ buffer[i].temp = temp;
+ iio_push_to_buffers(idev, &buffer[i]);
+ }
+
+ return smp_lvl;
+}
+
+static int bm1390_fifo_flush(struct iio_dev *idev, unsigned int samples)
+{
+ struct bm1390_data *data = iio_priv(idev);
+ s64 timestamp;
+ int ret;
+
+ /*
+ * If fifo_flush is being called from IRQ handler we know the stored
+ * timestamp is fairly accurate for the last stored sample. If we are
+ * called as a result of a read operation from userspace and hence
+ * before the watermark interrupt was triggered, take a timestamp
+ * now. We can fall anywhere in between two samples so the error in this
+ * case is at most one sample period.
+ * We need to have the IRQ disabled or we risk of messing-up
+ * the timestamps. If we are ran from IRQ, then the
+ * IRQF_ONESHOT has us covered - but if we are ran by the
+ * user-space read we need to disable the IRQ to be on a safe
+ * side. We do this usng synchronous disable so that if the
+ * IRQ thread is being ran on other CPU we wait for it to be
+ * finished.
+ */
+
+ timestamp = iio_get_time_ns(idev);
+ mutex_lock(&data->mutex);
+ ret = __bm1390_fifo_flush(idev, samples, timestamp);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int bm1390_set_watermark(struct iio_dev *idev, unsigned int val)
+{
+ struct bm1390_data *data = iio_priv(idev);
+
+ if (val < BM1390_WMI_MIN || val > BM1390_WMI_MAX)
+ return -EINVAL;
+
+ mutex_lock(&data->mutex);
+ data->watermark = val;
+ mutex_unlock(&data->mutex);
+
+ return 0;
+}
+
+static const struct iio_info bm1390_noirq_info = {
+ .read_raw = &bm1390_read_raw,
+};
+
+static const struct iio_info bm1390_info = {
+ .read_raw = &bm1390_read_raw,
+ .hwfifo_set_watermark = bm1390_set_watermark,
+ .hwfifo_flush_to_buffer = bm1390_fifo_flush,
+};
+
+static int bm1390_chip_init(struct bm1390_data *data)
+{
+ int ret;
+
+ ret = regmap_write_bits(data->regmap, BM1390_REG_POWER,
+ BM1390_MASK_POWER, BM1390_POWER_ON);
+ if (ret)
+ return ret;
+
+ msleep(1);
+
+ ret = regmap_write_bits(data->regmap, BM1390_REG_RESET,
+ BM1390_MASK_RESET, BM1390_RESET);
+ if (ret)
+ return ret;
+
+ msleep(1);
+
+ ret = regmap_write_bits(data->regmap, BM1390_REG_RESET,
+ BM1390_MASK_RESET, BM1390_RESET_RELEASE);
+ if (ret)
+ return ret;
+
+ msleep(1);
+
+ ret = regmap_reinit_cache(data->regmap, &bm1390_regmap);
+ if (ret) {
+ dev_err(data->dev, "Failed to reinit reg cache\n");
+ return ret;
+ }
+
+ /*
+ * Default to use IIR filter in "middle" mode. Also the AVE_NUM must
+ * be fixed when IIR is in use.
+ */
+ ret = regmap_update_bits(data->regmap, BM1390_REG_MODE_CTRL,
+ BM1390_MASK_AVE_NUM, BM1390_IIR_AVE_NUM);
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(data->regmap, BM1390_REG_FIFO_CTRL,
+ BM1390_MASK_IIR_MODE, BM1390_IIR_MODE_MID);
+}
+
+static int bm1390_fifo_set_wmi(struct bm1390_data *data)
+{
+ u8 regval;
+
+ regval = FIELD_PREP(BM1390_MASK_FIFO_LEN,
+ data->watermark - BM1390_WMI_MIN);
+
+ return regmap_update_bits(data->regmap, BM1390_REG_FIFO_CTRL,
+ BM1390_MASK_FIFO_LEN, regval);
+}
+
+static int bm1390_fifo_enable(struct iio_dev *idev)
+{
+ struct bm1390_data *data = iio_priv(idev);
+ int ret;
+
+ /* We can't do buffered stuff without IRQ as we never get WMI */
+ if (data->irq <= 0)
+ return -EINVAL;
+
+ mutex_lock(&data->mutex);
+ if (data->trigger_enabled) {
+ ret = -EBUSY;
+ goto unlock_out;
+ }
+
+ /* Update watermark to HW */
+ ret = bm1390_fifo_set_wmi(data);
+ if (ret)
+ goto unlock_out;
+
+ /* Enable WMI_IRQ */
+ ret = regmap_set_bits(data->regmap, BM1390_REG_MODE_CTRL,
+ BM1390_MASK_WMI_EN);
+ if (ret)
+ goto unlock_out;
+
+ /* Enable FIFO */
+ ret = regmap_set_bits(data->regmap, BM1390_REG_FIFO_CTRL,
+ BM1390_MASK_FIFO_EN);
+ if (ret)
+ goto unlock_out;
+
+ data->state = BM1390_STATE_FIFO;
+
+ data->old_timestamp = iio_get_time_ns(idev);
+ ret = bm1390_meas_set(data, BM1390_MEAS_MODE_CONTINUOUS);
+
+unlock_out:
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int bm1390_fifo_disable(struct iio_dev *idev)
+{
+ struct bm1390_data *data = iio_priv(idev);
+ int ret;
+
+ msleep(1);
+
+ mutex_lock(&data->mutex);
+ ret = bm1390_meas_set(data, BM1390_MEAS_MODE_STOP);
+ if (ret)
+ goto unlock_out;
+
+ /* Disable FIFO */
+ ret = regmap_clear_bits(data->regmap, BM1390_REG_FIFO_CTRL,
+ BM1390_MASK_FIFO_EN);
+ if (ret)
+ goto unlock_out;
+
+ data->state = BM1390_STATE_SAMPLE;
+
+ /* Disable WMI_IRQ */
+ ret = regmap_clear_bits(data->regmap, BM1390_REG_MODE_CTRL,
+ BM1390_MASK_WMI_EN);
+
+unlock_out:
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int bm1390_buffer_postenable(struct iio_dev *idev)
+{
+ /*
+ * If we use data-ready trigger, then the IRQ masks should be handled by
+ * trigger enable and the hardware buffer is not used but we just update
+ * results to the IIO FIFO when data-ready triggers.
+ */
+ if (iio_device_get_current_mode(idev) == INDIO_BUFFER_TRIGGERED)
+ return 0;
+
+ return bm1390_fifo_enable(idev);
+}
+
+static int bm1390_buffer_predisable(struct iio_dev *idev)
+{
+ if (iio_device_get_current_mode(idev) == INDIO_BUFFER_TRIGGERED)
+ return 0;
+
+ return bm1390_fifo_disable(idev);
+}
+
+static const struct iio_buffer_setup_ops bm1390_buffer_ops = {
+ .postenable = bm1390_buffer_postenable,
+ .predisable = bm1390_buffer_predisable,
+};
+
+static irqreturn_t bm1390_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *idev = pf->indio_dev;
+ struct bm1390_data *data = iio_priv(idev);
+ int ret, status;
+
+ /* DRDY is acked by reading status reg */
+ ret = regmap_read(data->regmap, BM1390_REG_STATUS, &status);
+ if (ret || !status)
+ return IRQ_NONE;
+
+ dev_dbg(data->dev, "DRDY trig status 0x%x\n", status);
+
+ if (test_bit(BM1390_CHAN_PRESSURE, idev->active_scan_mask)) {
+ ret = bm1390_pressure_read(data, &data->buf.pressure);
+ if (ret) {
+ dev_warn(data->dev, "sample read failed %d\n", ret);
+ return IRQ_NONE;
+ }
+ }
+
+ if (test_bit(BM1390_CHAN_TEMP, idev->active_scan_mask)) {
+ ret = regmap_bulk_read(data->regmap, BM1390_REG_TEMP_HI,
+ &data->buf.temp, sizeof(data->buf.temp));
+ if (ret) {
+ dev_warn(data->dev, "temp read failed %d\n", ret);
+ return IRQ_HANDLED;
+ }
+ }
+
+ iio_push_to_buffers_with_timestamp(idev, &data->buf, data->timestamp);
+ iio_trigger_notify_done(idev->trig);
+
+ return IRQ_HANDLED;
+}
+
+/* Get timestamps and wake the thread if we need to read data */
+static irqreturn_t bm1390_irq_handler(int irq, void *private)
+{
+ struct iio_dev *idev = private;
+ struct bm1390_data *data = iio_priv(idev);
+
+ data->timestamp = iio_get_time_ns(idev);
+
+ if (data->state == BM1390_STATE_FIFO || data->trigger_enabled)
+ return IRQ_WAKE_THREAD;
+
+ return IRQ_NONE;
+}
+
+static irqreturn_t bm1390_irq_thread_handler(int irq, void *private)
+{
+ struct iio_dev *idev = private;
+ struct bm1390_data *data = iio_priv(idev);
+ int ret = IRQ_NONE;
+
+ mutex_lock(&data->mutex);
+
+ if (data->trigger_enabled) {
+ iio_trigger_poll_nested(data->trig);
+ ret = IRQ_HANDLED;
+ } else if (data->state == BM1390_STATE_FIFO) {
+ int ok;
+
+ ok = __bm1390_fifo_flush(idev, BM1390_FIFO_LENGTH,
+ data->timestamp);
+ if (ok > 0)
+ ret = IRQ_HANDLED;
+ }
+
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int bm1390_set_drdy_irq(struct bm1390_data *data, bool en)
+{
+ if (en)
+ return regmap_set_bits(data->regmap, BM1390_REG_MODE_CTRL,
+ BM1390_MASK_DRDY_EN);
+ return regmap_clear_bits(data->regmap, BM1390_REG_MODE_CTRL,
+ BM1390_MASK_DRDY_EN);
+}
+
+static int bm1390_trigger_set_state(struct iio_trigger *trig,
+ bool state)
+{
+ struct bm1390_data *data = iio_trigger_get_drvdata(trig);
+ int ret = 0;
+
+ mutex_lock(&data->mutex);
+
+ if (data->trigger_enabled == state)
+ goto unlock_out;
+
+ if (data->state == BM1390_STATE_FIFO) {
+ dev_warn(data->dev, "Can't set trigger when FIFO enabled\n");
+ ret = -EBUSY;
+ goto unlock_out;
+ }
+
+ data->trigger_enabled = state;
+
+ if (state) {
+ ret = bm1390_meas_set(data, BM1390_MEAS_MODE_CONTINUOUS);
+ if (ret)
+ goto unlock_out;
+ } else {
+ int dummy;
+
+ ret = bm1390_meas_set(data, BM1390_MEAS_MODE_STOP);
+ if (ret)
+ goto unlock_out;
+
+ /*
+ * We need to read the status register in order to ACK the
+ * data-ready which may have been generated just before we
+ * disabled the measurement.
+ */
+ ret = regmap_read(data->regmap, BM1390_REG_STATUS, &dummy);
+ if (ret)
+ dev_warn(data->dev, "status read failed\n");
+ }
+
+ ret = bm1390_set_drdy_irq(data, state);
+
+unlock_out:
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static const struct iio_trigger_ops bm1390_trigger_ops = {
+ .set_trigger_state = bm1390_trigger_set_state,
+};
+
+static int bm1390_setup_buffer(struct bm1390_data *data, struct iio_dev *idev)
+{
+ int ret;
+
+ ret = devm_iio_triggered_buffer_setup(data->dev, idev,
+ &iio_pollfunc_store_time,
+ &bm1390_trigger_handler,
+ &bm1390_buffer_ops);
+
+ if (ret)
+ return dev_err_probe(data->dev, ret,
+ "iio_triggered_buffer_setup FAIL\n");
+
+ idev->available_scan_masks = bm1390_scan_masks;
+
+ return 0;
+}
+
+static int bm1390_setup_trigger(struct bm1390_data *data, struct iio_dev *idev,
+ int irq)
+{
+ struct iio_trigger *itrig;
+ char *name;
+ int ret;
+
+ itrig = devm_iio_trigger_alloc(data->dev, "%sdata-rdy-dev%d", idev->name,
+ iio_device_id(idev));
+ if (!itrig)
+ return -ENOMEM;
+
+ data->trig = itrig;
+
+ itrig->ops = &bm1390_trigger_ops;
+ iio_trigger_set_drvdata(itrig, data);
+
+ name = devm_kasprintf(data->dev, GFP_KERNEL, "%s-bm1390",
+ dev_name(data->dev));
+ if (name == NULL)
+ return -ENOMEM;
+
+ ret = devm_request_threaded_irq(data->dev, irq, bm1390_irq_handler,
+ &bm1390_irq_thread_handler,
+ IRQF_ONESHOT, name, idev);
+ if (ret)
+ return dev_err_probe(data->dev, ret, "Could not request IRQ\n");
+
+
+ ret = devm_iio_trigger_register(data->dev, itrig);
+ if (ret)
+ return dev_err_probe(data->dev, ret,
+ "Trigger registration failed\n");
+
+ return 0;
+}
+
+static int bm1390_probe(struct i2c_client *i2c)
+{
+ struct bm1390_data *data;
+ struct regmap *regmap;
+ struct iio_dev *idev;
+ struct device *dev;
+ unsigned int part_id;
+ int ret;
+
+ dev = &i2c->dev;
+
+ regmap = devm_regmap_init_i2c(i2c, &bm1390_regmap);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap),
+ "Failed to initialize Regmap\n");
+
+ ret = devm_regulator_get_enable(dev, "vdd");
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get regulator\n");
+
+ ret = regmap_read(regmap, BM1390_REG_PART_ID, &part_id);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to access sensor\n");
+
+ if (part_id != BM1390_ID)
+ dev_warn(dev, "unknown device 0x%x\n", part_id);
+
+ idev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!idev)
+ return -ENOMEM;
+
+ data = iio_priv(idev);
+ data->regmap = regmap;
+ data->dev = dev;
+ data->irq = i2c->irq;
+ /*
+ * For now we just allow BM1390_WMI_MIN to BM1390_WMI_MAX and
+ * discard every other configuration when triggered mode is not used.
+ */
+ data->watermark = BM1390_WMI_MAX;
+ mutex_init(&data->mutex);
+
+ idev->channels = bm1390_channels;
+ idev->num_channels = ARRAY_SIZE(bm1390_channels);
+ idev->name = "bm1390";
+ idev->modes = INDIO_DIRECT_MODE;
+
+ ret = bm1390_chip_init(data);
+ if (ret)
+ return dev_err_probe(dev, ret, "sensor init failed\n");
+
+ ret = bm1390_setup_buffer(data, idev);
+ if (ret)
+ return ret;
+
+ /* No trigger if we don't have IRQ for data-ready and WMI */
+ if (i2c->irq > 0) {
+ idev->info = &bm1390_info;
+ idev->modes |= INDIO_BUFFER_SOFTWARE;
+ ret = bm1390_setup_trigger(data, idev, i2c->irq);
+ if (ret)
+ return ret;
+ } else {
+ idev->info = &bm1390_noirq_info;
+ }
+
+ ret = devm_iio_device_register(dev, idev);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Unable to register iio device\n");
+
+ return 0;
+}
+
+static const struct of_device_id bm1390_of_match[] = {
+ { .compatible = "rohm,bm1390glv-z" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, bm1390_of_match);
+
+static const struct i2c_device_id bm1390_id[] = {
+ { "bm1390glv-z", },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, bm1390_id);
+
+static struct i2c_driver bm1390_driver = {
+ .driver = {
+ .name = "bm1390",
+ .of_match_table = bm1390_of_match,
+ /*
+ * Probing explicitly requires a few millisecond of sleep.
+ * Enabling the VDD regulator may include ramp up rates.
+ */
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
+ .probe = bm1390_probe,
+ .id_table = bm1390_id,
+};
+module_i2c_driver(bm1390_driver);
+
+MODULE_AUTHOR("Matti Vaittinen <mazziesaccount@gmail.com>");
+MODULE_DESCRIPTION("Driver for ROHM BM1390 pressure sensor");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/proximity/cros_ec_mkbp_proximity.c b/drivers/iio/proximity/cros_ec_mkbp_proximity.c
index 571ea18122..4df506bb8b 100644
--- a/drivers/iio/proximity/cros_ec_mkbp_proximity.c
+++ b/drivers/iio/proximity/cros_ec_mkbp_proximity.c
@@ -239,15 +239,13 @@ static int cros_ec_mkbp_proximity_probe(struct platform_device *pdev)
return 0;
}
-static int cros_ec_mkbp_proximity_remove(struct platform_device *pdev)
+static void cros_ec_mkbp_proximity_remove(struct platform_device *pdev)
{
struct cros_ec_mkbp_proximity_data *data = platform_get_drvdata(pdev);
struct cros_ec_device *ec = data->ec;
blocking_notifier_chain_unregister(&ec->event_notifier,
&data->notifier);
-
- return 0;
}
static const struct of_device_id cros_ec_mkbp_proximity_of_match[] = {
@@ -263,7 +261,7 @@ static struct platform_driver cros_ec_mkbp_proximity_driver = {
.pm = pm_sleep_ptr(&cros_ec_mkbp_proximity_pm_ops),
},
.probe = cros_ec_mkbp_proximity_probe,
- .remove = cros_ec_mkbp_proximity_remove,
+ .remove_new = cros_ec_mkbp_proximity_remove,
};
module_platform_driver(cros_ec_mkbp_proximity_driver);
diff --git a/drivers/iio/proximity/srf04.c b/drivers/iio/proximity/srf04.c
index faf2f806ce..86c57672fc 100644
--- a/drivers/iio/proximity/srf04.c
+++ b/drivers/iio/proximity/srf04.c
@@ -344,7 +344,7 @@ static int srf04_probe(struct platform_device *pdev)
return ret;
}
-static int srf04_remove(struct platform_device *pdev)
+static void srf04_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct srf04_data *data = iio_priv(indio_dev);
@@ -355,8 +355,6 @@ static int srf04_remove(struct platform_device *pdev)
pm_runtime_disable(data->dev);
pm_runtime_set_suspended(data->dev);
}
-
- return 0;
}
static int srf04_pm_runtime_suspend(struct device *dev)
@@ -391,7 +389,7 @@ static const struct dev_pm_ops srf04_pm_ops = {
static struct platform_driver srf04_driver = {
.probe = srf04_probe,
- .remove = srf04_remove,
+ .remove_new = srf04_remove,
.driver = {
.name = "srf04-gpio",
.of_match_table = of_srf04_match,
diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c
index d977aacb74..0d230a0dff 100644
--- a/drivers/iio/proximity/sx9310.c
+++ b/drivers/iio/proximity/sx9310.c
@@ -159,6 +159,11 @@ static_assert(SX9310_NUM_CHANNELS <= SX_COMMON_MAX_NUM_CHANNELS);
}
#define SX9310_CHANNEL(idx) SX9310_NAMED_CHANNEL(idx, NULL)
+struct sx931x_info {
+ const char *name;
+ unsigned int whoami;
+};
+
static const struct iio_chan_spec sx9310_channels[] = {
SX9310_CHANNEL(0), /* CS0 */
SX9310_CHANNEL(1), /* CS1 */
@@ -902,7 +907,7 @@ static int sx9310_check_whoami(struct device *dev,
struct iio_dev *indio_dev)
{
struct sx_common_data *data = iio_priv(indio_dev);
- unsigned int long ddata;
+ const struct sx931x_info *ddata;
unsigned int whoami;
int ret;
@@ -910,20 +915,11 @@ static int sx9310_check_whoami(struct device *dev,
if (ret)
return ret;
- ddata = (uintptr_t)device_get_match_data(dev);
- if (ddata != whoami)
- return -EINVAL;
-
- switch (whoami) {
- case SX9310_WHOAMI_VALUE:
- indio_dev->name = "sx9310";
- break;
- case SX9311_WHOAMI_VALUE:
- indio_dev->name = "sx9311";
- break;
- default:
+ ddata = device_get_match_data(dev);
+ if (ddata->whoami != whoami)
return -ENODEV;
- }
+
+ indio_dev->name = ddata->name;
return 0;
}
@@ -1015,23 +1011,33 @@ out:
static DEFINE_SIMPLE_DEV_PM_OPS(sx9310_pm_ops, sx9310_suspend, sx9310_resume);
+static const struct sx931x_info sx9310_info = {
+ .name = "sx9310",
+ .whoami = SX9310_WHOAMI_VALUE,
+};
+
+static const struct sx931x_info sx9311_info = {
+ .name = "sx9311",
+ .whoami = SX9311_WHOAMI_VALUE,
+};
+
static const struct acpi_device_id sx9310_acpi_match[] = {
- { "STH9310", SX9310_WHOAMI_VALUE },
- { "STH9311", SX9311_WHOAMI_VALUE },
+ { "STH9310", (kernel_ulong_t)&sx9310_info },
+ { "STH9311", (kernel_ulong_t)&sx9311_info },
{}
};
MODULE_DEVICE_TABLE(acpi, sx9310_acpi_match);
static const struct of_device_id sx9310_of_match[] = {
- { .compatible = "semtech,sx9310", (void *)SX9310_WHOAMI_VALUE },
- { .compatible = "semtech,sx9311", (void *)SX9311_WHOAMI_VALUE },
+ { .compatible = "semtech,sx9310", &sx9310_info },
+ { .compatible = "semtech,sx9311", &sx9311_info },
{}
};
MODULE_DEVICE_TABLE(of, sx9310_of_match);
static const struct i2c_device_id sx9310_id[] = {
- { "sx9310", SX9310_WHOAMI_VALUE },
- { "sx9311", SX9311_WHOAMI_VALUE },
+ { "sx9310", (kernel_ulong_t)&sx9310_info },
+ { "sx9311", (kernel_ulong_t)&sx9311_info },
{}
};
MODULE_DEVICE_TABLE(i2c, sx9310_id);
diff --git a/drivers/iio/resolver/Kconfig b/drivers/iio/resolver/Kconfig
index 47dbfead9b..424529d360 100644
--- a/drivers/iio/resolver/Kconfig
+++ b/drivers/iio/resolver/Kconfig
@@ -25,4 +25,17 @@ config AD2S1200
To compile this driver as a module, choose M here: the
module will be called ad2s1200.
+
+config AD2S1210
+ tristate "Analog Devices ad2s1210 driver"
+ depends on SPI
+ depends on COMMON_CLK
+ depends on GPIOLIB || COMPILE_TEST
+ help
+ Say yes here to build support for Analog Devices spi resolver
+ to digital converters, ad2s1210, provides direct access via sysfs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad2s1210.
+
endmenu
diff --git a/drivers/iio/resolver/Makefile b/drivers/iio/resolver/Makefile
index fa558138ce..7f6c876c35 100644
--- a/drivers/iio/resolver/Makefile
+++ b/drivers/iio/resolver/Makefile
@@ -5,3 +5,4 @@
obj-$(CONFIG_AD2S90) += ad2s90.o
obj-$(CONFIG_AD2S1200) += ad2s1200.o
+obj-$(CONFIG_AD2S1210) += ad2s1210.o
diff --git a/drivers/iio/resolver/ad2s1210.c b/drivers/iio/resolver/ad2s1210.c
new file mode 100644
index 0000000000..1bd1b950e7
--- /dev/null
+++ b/drivers/iio/resolver/ad2s1210.c
@@ -0,0 +1,1519 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ad2s1210.c support for the ADI Resolver to Digital Converters: AD2S1210
+ *
+ * Copyright (c) 2010-2010 Analog Devices Inc.
+ * Copyright (c) 2023 BayLibre, SAS
+ *
+ * Device register to IIO ABI mapping:
+ *
+ * Register | Addr | IIO ABI (sysfs)
+ * ----------------------------|------|-------------------------------------------
+ * DOS Overrange Threshold | 0x89 | events/in_altvoltage0_thresh_rising_value
+ * DOS Mismatch Threshold | 0x8A | events/in_altvoltage0_mag_rising_value
+ * DOS Reset Maximum Threshold | 0x8B | events/in_altvoltage0_mag_rising_reset_max
+ * DOS Reset Minimum Threshold | 0x8C | events/in_altvoltage0_mag_rising_reset_min
+ * LOT High Threshold | 0x8D | events/in_angl1_thresh_rising_value
+ * LOT Low Threshold [1] | 0x8E | events/in_angl1_thresh_rising_hysteresis
+ * Excitation Frequency | 0x91 | out_altvoltage0_frequency
+ * Control | 0x92 | *as bit fields*
+ * Phase lock range | D5 | events/in_phase0_mag_rising_value
+ * Hysteresis | D4 | in_angl0_hysteresis
+ * Encoder resolution | D3:2 | *not implemented*
+ * Resolution | D1:0 | *device tree: assigned-resolution-bits*
+ * Soft Reset | 0xF0 | [2]
+ * Fault | 0xFF | *not implemented*
+ *
+ * [1]: The value written to the LOT low register is high value minus the
+ * hysteresis.
+ * [2]: Soft reset is performed when `out_altvoltage0_frequency` is written.
+ *
+ * Fault to event mapping:
+ *
+ * Fault | | Channel | Type | Direction
+ * ----------------------------------------|----|---------------------------------
+ * Sine/cosine inputs clipped [3] | D7 | altvoltage1 | mag | either
+ * Sine/cosine inputs below LOS | D6 | altvoltage0 | thresh | falling
+ * Sine/cosine inputs exceed DOS overrange | D5 | altvoltage0 | thresh | rising
+ * Sine/cosine inputs exceed DOS mismatch | D4 | altvoltage0 | mag | rising
+ * Tracking error exceeds LOT | D3 | angl1 | thresh | rising
+ * Velocity exceeds maximum tracking rate | D2 | anglvel0 | mag | rising
+ * Phase error exceeds phase lock range | D1 | phase0 | mag | rising
+ * Configuration parity error | D0 | *writes to kernel log*
+ *
+ * [3]: The chip does not differentiate between fault on sine vs. cosine so
+ * there will also be an event on the altvoltage2 channel.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+/* control register flags */
+#define AD2S1210_ADDRESS_DATA BIT(7)
+#define AD2S1210_PHASE_LOCK_RANGE_44 BIT(5)
+#define AD2S1210_ENABLE_HYSTERESIS BIT(4)
+#define AD2S1210_SET_ENRES GENMASK(3, 2)
+#define AD2S1210_SET_RES GENMASK(1, 0)
+
+/* fault register flags */
+#define AD2S1210_FAULT_CLIP BIT(7)
+#define AD2S1210_FAULT_LOS BIT(6)
+#define AD2S1210_FAULT_DOS_OVR BIT(5)
+#define AD2S1210_FAULT_DOS_MIS BIT(4)
+#define AD2S1210_FAULT_LOT BIT(3)
+#define AD2S1210_FAULT_VELOCITY BIT(2)
+#define AD2S1210_FAULT_PHASE BIT(1)
+#define AD2S1210_FAULT_CONFIG_PARITY BIT(0)
+
+#define AD2S1210_REG_POSITION_MSB 0x80
+#define AD2S1210_REG_POSITION_LSB 0x81
+#define AD2S1210_REG_VELOCITY_MSB 0x82
+#define AD2S1210_REG_VELOCITY_LSB 0x83
+#define AD2S1210_REG_LOS_THRD 0x88
+#define AD2S1210_REG_DOS_OVR_THRD 0x89
+#define AD2S1210_REG_DOS_MIS_THRD 0x8A
+#define AD2S1210_REG_DOS_RST_MAX_THRD 0x8B
+#define AD2S1210_REG_DOS_RST_MIN_THRD 0x8C
+#define AD2S1210_REG_LOT_HIGH_THRD 0x8D
+#define AD2S1210_REG_LOT_LOW_THRD 0x8E
+#define AD2S1210_REG_EXCIT_FREQ 0x91
+#define AD2S1210_REG_CONTROL 0x92
+#define AD2S1210_REG_SOFT_RESET 0xF0
+#define AD2S1210_REG_FAULT 0xFF
+
+#define AD2S1210_MIN_CLKIN 6144000
+#define AD2S1210_MAX_CLKIN 10240000
+#define AD2S1210_MIN_EXCIT 2000
+#define AD2S1210_DEF_EXCIT 10000
+#define AD2S1210_MAX_EXCIT 20000
+#define AD2S1210_MIN_FCW 0x4
+#define AD2S1210_MAX_FCW 0x50
+
+/* 44 degrees ~= 0.767945 radians */
+#define PHASE_44_DEG_TO_RAD_INT 0
+#define PHASE_44_DEG_TO_RAD_MICRO 767945
+/* 360 degrees ~= 6.283185 radians */
+#define PHASE_360_DEG_TO_RAD_INT 6
+#define PHASE_360_DEG_TO_RAD_MICRO 283185
+
+/* Threshold voltage registers have 1 LSB == 38 mV */
+#define THRESHOLD_MILLIVOLT_PER_LSB 38
+/* max voltage for threshold registers is 0x7F * 38 mV */
+#define THRESHOLD_RANGE_STR "[0 38 4826]"
+
+#define FAULT_ONESHOT(bit, new, old) (new & bit && !(old & bit))
+
+enum ad2s1210_mode {
+ MOD_POS = 0b00,
+ MOD_VEL = 0b01,
+ MOD_RESERVED = 0b10,
+ MOD_CONFIG = 0b11,
+};
+
+enum ad2s1210_resolution {
+ AD2S1210_RES_10 = 0b00,
+ AD2S1210_RES_12 = 0b01,
+ AD2S1210_RES_14 = 0b10,
+ AD2S1210_RES_16 = 0b11,
+};
+
+struct ad2s1210_state {
+ struct mutex lock;
+ struct spi_device *sdev;
+ /** GPIO pin connected to SAMPLE line. */
+ struct gpio_desc *sample_gpio;
+ /** GPIO pins connected to A0 and A1 lines. */
+ struct gpio_descs *mode_gpios;
+ /** Used to access config registers. */
+ struct regmap *regmap;
+ /** The external oscillator frequency in Hz. */
+ unsigned long clkin_hz;
+ /** Available raw hysteresis values based on resolution. */
+ int hysteresis_available[2];
+ /** The selected resolution */
+ enum ad2s1210_resolution resolution;
+ /** Copy of fault register from the previous read. */
+ u8 prev_fault_flags;
+ /** For reading raw sample value via SPI. */
+ struct {
+ __be16 raw;
+ u8 fault;
+ } sample __aligned(IIO_DMA_MINALIGN);
+ /** Scan buffer */
+ struct {
+ __be16 chan[2];
+ /* Ensure timestamp is naturally aligned. */
+ s64 timestamp __aligned(8);
+ } scan;
+ /** SPI transmit buffer. */
+ u8 rx[2];
+ /** SPI receive buffer. */
+ u8 tx[2];
+};
+
+static int ad2s1210_set_mode(struct ad2s1210_state *st, enum ad2s1210_mode mode)
+{
+ struct gpio_descs *gpios = st->mode_gpios;
+ DECLARE_BITMAP(bitmap, 2);
+
+ bitmap[0] = mode;
+
+ return gpiod_set_array_value(gpios->ndescs, gpios->desc, gpios->info,
+ bitmap);
+}
+
+/*
+ * Writes the given data to the given register address.
+ *
+ * If the mode is configurable, the device will first be placed in
+ * configuration mode.
+ */
+static int ad2s1210_regmap_reg_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ struct ad2s1210_state *st = context;
+ struct spi_transfer xfers[] = {
+ {
+ .len = 1,
+ .rx_buf = &st->rx[0],
+ .tx_buf = &st->tx[0],
+ .cs_change = 1,
+ }, {
+ .len = 1,
+ .rx_buf = &st->rx[1],
+ .tx_buf = &st->tx[1],
+ },
+ };
+ int ret;
+
+ /* values can only be 7 bits, the MSB indicates an address */
+ if (val & ~0x7F)
+ return -EINVAL;
+
+ st->tx[0] = reg;
+ st->tx[1] = val;
+
+ ret = ad2s1210_set_mode(st, MOD_CONFIG);
+ if (ret < 0)
+ return ret;
+
+ ret = spi_sync_transfer(st->sdev, xfers, ARRAY_SIZE(xfers));
+ if (ret < 0)
+ return ret;
+
+ /* soft reset also clears the fault register */
+ if (reg == AD2S1210_REG_SOFT_RESET)
+ st->prev_fault_flags = 0;
+
+ return 0;
+}
+
+/*
+ * Reads value from one of the registers.
+ *
+ * If the mode is configurable, the device will first be placed in
+ * configuration mode.
+ */
+static int ad2s1210_regmap_reg_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ struct ad2s1210_state *st = context;
+ struct spi_transfer xfers[] = {
+ {
+ .len = 1,
+ .rx_buf = &st->rx[0],
+ .tx_buf = &st->tx[0],
+ .cs_change = 1,
+ }, {
+ .len = 1,
+ .rx_buf = &st->rx[1],
+ .tx_buf = &st->tx[1],
+ },
+ };
+ int ret;
+
+ ret = ad2s1210_set_mode(st, MOD_CONFIG);
+ if (ret < 0)
+ return ret;
+
+ st->tx[0] = reg;
+ /*
+ * Must be valid register address here otherwise this could write data.
+ * It doesn't matter which one as long as reading doesn't have side-
+ * effects.
+ */
+ st->tx[1] = AD2S1210_REG_CONTROL;
+
+ ret = spi_sync_transfer(st->sdev, xfers, ARRAY_SIZE(xfers));
+ if (ret < 0)
+ return ret;
+
+ /* reading the fault register also clears it */
+ if (reg == AD2S1210_REG_FAULT)
+ st->prev_fault_flags = 0;
+
+ /*
+ * If the D7 bit is set on any read/write register, it indicates a
+ * parity error. The fault register is read-only and the D7 bit means
+ * something else there.
+ */
+ if (reg != AD2S1210_REG_FAULT && st->rx[1] & AD2S1210_ADDRESS_DATA)
+ return -EBADMSG;
+
+ *val = st->rx[1];
+
+ return 0;
+}
+
+/*
+ * Toggles the SAMPLE line on the AD2S1210 to latch in the current position,
+ * velocity, and faults.
+ *
+ * Must be called with lock held.
+ */
+static void ad2s1210_toggle_sample_line(struct ad2s1210_state *st)
+{
+ /*
+ * Datasheet specifies minimum hold time t16 = 2 * tck + 20 ns. So the
+ * longest time needed is when CLKIN is 6.144 MHz, in which case t16
+ * ~= 350 ns. The same delay is also needed before re-asserting the
+ * SAMPLE line.
+ */
+ gpiod_set_value(st->sample_gpio, 1);
+ ndelay(350);
+ gpiod_set_value(st->sample_gpio, 0);
+ ndelay(350);
+}
+
+/*
+ * Sets the excitation frequency and performs software reset.
+ *
+ * Must be called with lock held.
+ */
+static int ad2s1210_reinit_excitation_frequency(struct ad2s1210_state *st,
+ u16 fexcit)
+{
+ /* Map resolution to settle time in milliseconds. */
+ static const int track_time_ms[] = { 10, 20, 25, 60 };
+ unsigned int ignored;
+ int ret;
+ u8 fcw;
+
+ fcw = fexcit * (1 << 15) / st->clkin_hz;
+ if (fcw < AD2S1210_MIN_FCW || fcw > AD2S1210_MAX_FCW)
+ return -ERANGE;
+
+ ret = regmap_write(st->regmap, AD2S1210_REG_EXCIT_FREQ, fcw);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Software reset reinitializes the excitation frequency output.
+ * It does not reset any of the configuration registers.
+ */
+ ret = regmap_write(st->regmap, AD2S1210_REG_SOFT_RESET, 0);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Soft reset always triggers some faults due the change in the output
+ * signal so clear the faults too. We need to delay for some time
+ * (what datasheet calls t[track]) to allow things to settle before
+ * clearing the faults.
+ */
+ msleep(track_time_ms[st->resolution] * 8192000 / st->clkin_hz);
+
+ /* Reading the fault register clears the faults. */
+ ret = regmap_read(st->regmap, AD2S1210_REG_FAULT, &ignored);
+ if (ret < 0)
+ return ret;
+
+ /* Have to toggle sample line to get fault output pins to reset. */
+ ad2s1210_toggle_sample_line(st);
+
+ return 0;
+}
+
+static void ad2s1210_push_events(struct iio_dev *indio_dev,
+ u8 flags, s64 timestamp)
+{
+ struct ad2s1210_state *st = iio_priv(indio_dev);
+
+ /* Sine/cosine inputs clipped */
+ if (FAULT_ONESHOT(AD2S1210_FAULT_CLIP, flags, st->prev_fault_flags)) {
+ /*
+ * The chip does not differentiate between fault on sine vs.
+ * cosine channel so we just send an event on both channels.
+ */
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 1,
+ IIO_EV_TYPE_MAG,
+ IIO_EV_DIR_EITHER),
+ timestamp);
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 2,
+ IIO_EV_TYPE_MAG,
+ IIO_EV_DIR_EITHER),
+ timestamp);
+ }
+
+ /* Sine/cosine inputs below LOS threshold */
+ if (FAULT_ONESHOT(AD2S1210_FAULT_LOS, flags, st->prev_fault_flags))
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_FALLING),
+ timestamp);
+
+ /* Sine/cosine inputs exceed DOS overrange threshold */
+ if (FAULT_ONESHOT(AD2S1210_FAULT_DOS_OVR, flags, st->prev_fault_flags))
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING),
+ timestamp);
+
+ /* Sine/cosine inputs exceed DOS mismatch threshold */
+ if (FAULT_ONESHOT(AD2S1210_FAULT_DOS_MIS, flags, st->prev_fault_flags))
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 0,
+ IIO_EV_TYPE_MAG,
+ IIO_EV_DIR_RISING),
+ timestamp);
+
+ /* Tracking error exceeds LOT threshold */
+ if (FAULT_ONESHOT(AD2S1210_FAULT_LOT, flags, st->prev_fault_flags))
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_ANGL, 1,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING),
+ timestamp);
+
+ /* Velocity exceeds maximum tracking rate */
+ if (FAULT_ONESHOT(AD2S1210_FAULT_VELOCITY, flags, st->prev_fault_flags))
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_ANGL_VEL, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING),
+ timestamp);
+
+ /* Phase error exceeds phase lock range */
+ if (FAULT_ONESHOT(AD2S1210_FAULT_PHASE, flags, st->prev_fault_flags))
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_PHASE, 0,
+ IIO_EV_TYPE_MAG,
+ IIO_EV_DIR_RISING),
+ timestamp);
+
+ /* Configuration parity error */
+ if (FAULT_ONESHOT(AD2S1210_FAULT_CONFIG_PARITY, flags,
+ st->prev_fault_flags))
+ /*
+ * Userspace should also get notified of this via error return
+ * when trying to write to any attribute that writes a register.
+ */
+ dev_err_ratelimited(&indio_dev->dev,
+ "Configuration parity error\n");
+
+ st->prev_fault_flags = flags;
+}
+
+static int ad2s1210_single_conversion(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val)
+{
+ struct ad2s1210_state *st = iio_priv(indio_dev);
+ s64 timestamp;
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ ad2s1210_toggle_sample_line(st);
+ timestamp = iio_get_time_ns(indio_dev);
+
+ switch (chan->type) {
+ case IIO_ANGL:
+ ret = ad2s1210_set_mode(st, MOD_POS);
+ break;
+ case IIO_ANGL_VEL:
+ ret = ad2s1210_set_mode(st, MOD_VEL);
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (ret < 0)
+ return ret;
+ ret = spi_read(st->sdev, &st->sample, 3);
+ if (ret < 0)
+ return ret;
+
+ switch (chan->type) {
+ case IIO_ANGL:
+ *val = be16_to_cpu(st->sample.raw);
+ ret = IIO_VAL_INT;
+ break;
+ case IIO_ANGL_VEL:
+ *val = (s16)be16_to_cpu(st->sample.raw);
+ ret = IIO_VAL_INT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ad2s1210_push_events(indio_dev, st->sample.fault, timestamp);
+
+ return ret;
+}
+
+static int ad2s1210_get_hysteresis(struct ad2s1210_state *st, int *val)
+{
+ int ret;
+
+ guard(mutex)(&st->lock);
+ ret = regmap_test_bits(st->regmap, AD2S1210_REG_CONTROL,
+ AD2S1210_ENABLE_HYSTERESIS);
+ if (ret < 0)
+ return ret;
+
+ *val = ret << (2 * (AD2S1210_RES_16 - st->resolution));
+ return IIO_VAL_INT;
+}
+
+static int ad2s1210_set_hysteresis(struct ad2s1210_state *st, int val)
+{
+ guard(mutex)(&st->lock);
+ return regmap_update_bits(st->regmap, AD2S1210_REG_CONTROL,
+ AD2S1210_ENABLE_HYSTERESIS,
+ val ? AD2S1210_ENABLE_HYSTERESIS : 0);
+}
+
+static int ad2s1210_get_phase_lock_range(struct ad2s1210_state *st,
+ int *val, int *val2)
+{
+ int ret;
+
+ guard(mutex)(&st->lock);
+ ret = regmap_test_bits(st->regmap, AD2S1210_REG_CONTROL,
+ AD2S1210_PHASE_LOCK_RANGE_44);
+ if (ret < 0)
+ return ret;
+
+ if (ret) {
+ /* 44 degrees as radians */
+ *val = PHASE_44_DEG_TO_RAD_INT;
+ *val2 = PHASE_44_DEG_TO_RAD_MICRO;
+ } else {
+ /* 360 degrees as radians */
+ *val = PHASE_360_DEG_TO_RAD_INT;
+ *val2 = PHASE_360_DEG_TO_RAD_MICRO;
+ }
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int ad2s1210_set_phase_lock_range(struct ad2s1210_state *st,
+ int val, int val2)
+{
+ int deg;
+
+ /* convert radians to degrees - only two allowable values */
+ if (val == PHASE_44_DEG_TO_RAD_INT && val2 == PHASE_44_DEG_TO_RAD_MICRO)
+ deg = 44;
+ else if (val == PHASE_360_DEG_TO_RAD_INT &&
+ val2 == PHASE_360_DEG_TO_RAD_MICRO)
+ deg = 360;
+ else
+ return -EINVAL;
+
+ guard(mutex)(&st->lock);
+ return regmap_update_bits(st->regmap, AD2S1210_REG_CONTROL,
+ AD2S1210_PHASE_LOCK_RANGE_44,
+ deg == 44 ? AD2S1210_PHASE_LOCK_RANGE_44 : 0);
+}
+
+/* map resolution to microradians/LSB for LOT registers */
+static const int ad2s1210_lot_threshold_urad_per_lsb[] = {
+ 6184, /* 10-bit: ~0.35 deg/LSB, 45 deg max */
+ 2473, /* 12-bit: ~0.14 deg/LSB, 18 deg max */
+ 1237, /* 14-bit: ~0.07 deg/LSB, 9 deg max */
+ 1237, /* 16-bit: same as 14-bit */
+};
+
+static int ad2s1210_get_voltage_threshold(struct ad2s1210_state *st,
+ unsigned int reg, int *val)
+{
+ unsigned int reg_val;
+ int ret;
+
+ guard(mutex)(&st->lock);
+ ret = regmap_read(st->regmap, reg, &reg_val);
+ if (ret < 0)
+ return ret;
+
+ *val = reg_val * THRESHOLD_MILLIVOLT_PER_LSB;
+ return IIO_VAL_INT;
+}
+
+static int ad2s1210_set_voltage_threshold(struct ad2s1210_state *st,
+ unsigned int reg, int val)
+{
+ unsigned int reg_val;
+
+ reg_val = val / THRESHOLD_MILLIVOLT_PER_LSB;
+
+ guard(mutex)(&st->lock);
+ return regmap_write(st->regmap, reg, reg_val);
+}
+
+static int ad2s1210_get_lot_high_threshold(struct ad2s1210_state *st,
+ int *val, int *val2)
+{
+ unsigned int reg_val;
+ int ret;
+
+ guard(mutex)(&st->lock);
+ ret = regmap_read(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, &reg_val);
+ if (ret < 0)
+ return ret;
+
+ *val = 0;
+ *val2 = reg_val * ad2s1210_lot_threshold_urad_per_lsb[st->resolution];
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int ad2s1210_set_lot_high_threshold(struct ad2s1210_state *st,
+ int val, int val2)
+{
+ unsigned int high_reg_val, low_reg_val, hysteresis;
+ int ret;
+
+ /* all valid values are between 0 and pi/4 radians */
+ if (val != 0)
+ return -EINVAL;
+
+ guard(mutex)(&st->lock);
+ /*
+ * We need to read both high and low registers first so we can preserve
+ * the hysteresis.
+ */
+ ret = regmap_read(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, &high_reg_val);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(st->regmap, AD2S1210_REG_LOT_LOW_THRD, &low_reg_val);
+ if (ret < 0)
+ return ret;
+
+ hysteresis = high_reg_val - low_reg_val;
+ high_reg_val = val2 / ad2s1210_lot_threshold_urad_per_lsb[st->resolution];
+ low_reg_val = high_reg_val - hysteresis;
+
+ ret = regmap_write(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, high_reg_val);
+ if (ret < 0)
+ return ret;
+
+ return regmap_write(st->regmap, AD2S1210_REG_LOT_LOW_THRD, low_reg_val);
+}
+
+static int ad2s1210_get_lot_low_threshold(struct ad2s1210_state *st,
+ int *val, int *val2)
+{
+ unsigned int high_reg_val, low_reg_val;
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ ret = regmap_read(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, &high_reg_val);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(st->regmap, AD2S1210_REG_LOT_LOW_THRD, &low_reg_val);
+ if (ret < 0)
+ return ret;
+
+ /* sysfs value is hysteresis rather than actual low value */
+ *val = 0;
+ *val2 = (high_reg_val - low_reg_val) *
+ ad2s1210_lot_threshold_urad_per_lsb[st->resolution];
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int ad2s1210_set_lot_low_threshold(struct ad2s1210_state *st,
+ int val, int val2)
+{
+ unsigned int reg_val, hysteresis;
+ int ret;
+
+ /* all valid values are between 0 and pi/4 radians */
+ if (val != 0)
+ return -EINVAL;
+
+ hysteresis = val2 / ad2s1210_lot_threshold_urad_per_lsb[st->resolution];
+
+ guard(mutex)(&st->lock);
+
+ ret = regmap_read(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, &reg_val);
+ if (ret < 0)
+ return ret;
+
+ return regmap_write(st->regmap, AD2S1210_REG_LOT_LOW_THRD,
+ reg_val - hysteresis);
+}
+
+static int ad2s1210_get_excitation_frequency(struct ad2s1210_state *st, int *val)
+{
+ unsigned int reg_val;
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ ret = regmap_read(st->regmap, AD2S1210_REG_EXCIT_FREQ, &reg_val);
+ if (ret < 0)
+ return ret;
+
+ *val = reg_val * st->clkin_hz / (1 << 15);
+ return IIO_VAL_INT;
+}
+
+static int ad2s1210_set_excitation_frequency(struct ad2s1210_state *st, int val)
+{
+ if (val < AD2S1210_MIN_EXCIT || val > AD2S1210_MAX_EXCIT)
+ return -EINVAL;
+
+ guard(mutex)(&st->lock);
+ return ad2s1210_reinit_excitation_frequency(st, val);
+}
+
+static const int ad2s1210_velocity_scale[] = {
+ 17089132, /* 8.192MHz / (2*pi * 2500 / 2^15) */
+ 42722830, /* 8.192MHz / (2*pi * 1000 / 2^15) */
+ 85445659, /* 8.192MHz / (2*pi * 500 / 2^15) */
+ 341782638, /* 8.192MHz / (2*pi * 125 / 2^15) */
+};
+
+static int ad2s1210_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long mask)
+{
+ struct ad2s1210_state *st = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ return ad2s1210_single_conversion(indio_dev, chan, val);
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_ANGL:
+ /* approx 0.3 arc min converted to radians */
+ *val = 0;
+ *val2 = 95874;
+ return IIO_VAL_INT_PLUS_NANO;
+ case IIO_ANGL_VEL:
+ *val = st->clkin_hz;
+ *val2 = ad2s1210_velocity_scale[st->resolution];
+ return IIO_VAL_FRACTIONAL;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_FREQUENCY:
+ switch (chan->type) {
+ case IIO_ALTVOLTAGE:
+ return ad2s1210_get_excitation_frequency(st, val);
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_HYSTERESIS:
+ switch (chan->type) {
+ case IIO_ANGL:
+ return ad2s1210_get_hysteresis(st, val);
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad2s1210_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type,
+ int *length, long mask)
+{
+ static const int excitation_frequency_available[] = {
+ AD2S1210_MIN_EXCIT,
+ 250, /* step */
+ AD2S1210_MAX_EXCIT,
+ };
+
+ struct ad2s1210_state *st = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_FREQUENCY:
+ switch (chan->type) {
+ case IIO_ALTVOLTAGE:
+ *type = IIO_VAL_INT;
+ *vals = excitation_frequency_available;
+ return IIO_AVAIL_RANGE;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_HYSTERESIS:
+ switch (chan->type) {
+ case IIO_ANGL:
+ *vals = st->hysteresis_available;
+ *type = IIO_VAL_INT;
+ *length = ARRAY_SIZE(st->hysteresis_available);
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad2s1210_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct ad2s1210_state *st = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_FREQUENCY:
+ switch (chan->type) {
+ case IIO_ALTVOLTAGE:
+ return ad2s1210_set_excitation_frequency(st, val);
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_HYSTERESIS:
+ switch (chan->type) {
+ case IIO_ANGL:
+ return ad2s1210_set_hysteresis(st, val);
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_event_spec ad2s1210_position_event_spec[] = {
+ {
+ /* Tracking error exceeds LOT threshold fault. */
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate =
+ /* Loss of tracking high threshold. */
+ BIT(IIO_EV_INFO_VALUE) |
+ /* Loss of tracking low threshold. */
+ BIT(IIO_EV_INFO_HYSTERESIS),
+ },
+};
+
+static const struct iio_event_spec ad2s1210_velocity_event_spec[] = {
+ {
+ /* Velocity exceeds maximum tracking rate fault. */
+ .type = IIO_EV_TYPE_MAG,
+ .dir = IIO_EV_DIR_RISING,
+ },
+};
+
+static const struct iio_event_spec ad2s1210_phase_event_spec[] = {
+ {
+ /* Phase error fault. */
+ .type = IIO_EV_TYPE_MAG,
+ .dir = IIO_EV_DIR_RISING,
+ /* Phase lock range. */
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ },
+};
+
+static const struct iio_event_spec ad2s1210_monitor_signal_event_spec[] = {
+ {
+ /* Sine/cosine below LOS threshold fault. */
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ /* Loss of signal threshold. */
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ },
+ {
+ /* Sine/cosine DOS overrange fault.*/
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ /* Degredation of signal overrange threshold. */
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ },
+ {
+ /* Sine/cosine DOS mismatch fault.*/
+ .type = IIO_EV_TYPE_MAG,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ },
+};
+
+static const struct iio_event_spec ad2s1210_sin_cos_event_spec[] = {
+ {
+ /* Sine/cosine clipping fault. */
+ .type = IIO_EV_TYPE_MAG,
+ .dir = IIO_EV_DIR_EITHER,
+ },
+};
+
+static const struct iio_chan_spec ad2s1210_channels[] = {
+ {
+ .type = IIO_ANGL,
+ .indexed = 1,
+ .channel = 0,
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_BE,
+ },
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS),
+ .info_mask_separate_available =
+ BIT(IIO_CHAN_INFO_HYSTERESIS),
+ }, {
+ .type = IIO_ANGL_VEL,
+ .indexed = 1,
+ .channel = 0,
+ .scan_index = 1,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_BE,
+ },
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .event_spec = ad2s1210_velocity_event_spec,
+ .num_event_specs = ARRAY_SIZE(ad2s1210_velocity_event_spec),
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(2),
+ {
+ /* used to configure LOT thresholds and get tracking error */
+ .type = IIO_ANGL,
+ .indexed = 1,
+ .channel = 1,
+ .scan_index = -1,
+ .event_spec = ad2s1210_position_event_spec,
+ .num_event_specs = ARRAY_SIZE(ad2s1210_position_event_spec),
+ },
+ {
+ /* used to configure phase lock range and get phase lock error */
+ .type = IIO_PHASE,
+ .indexed = 1,
+ .channel = 0,
+ .scan_index = -1,
+ .event_spec = ad2s1210_phase_event_spec,
+ .num_event_specs = ARRAY_SIZE(ad2s1210_phase_event_spec),
+ }, {
+ /* excitation frequency output */
+ .type = IIO_ALTVOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .output = 1,
+ .scan_index = -1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_FREQUENCY),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_FREQUENCY),
+ }, {
+ /* monitor signal */
+ .type = IIO_ALTVOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .scan_index = -1,
+ .event_spec = ad2s1210_monitor_signal_event_spec,
+ .num_event_specs = ARRAY_SIZE(ad2s1210_monitor_signal_event_spec),
+ }, {
+ /* sine input */
+ .type = IIO_ALTVOLTAGE,
+ .indexed = 1,
+ .channel = 1,
+ .scan_index = -1,
+ .event_spec = ad2s1210_sin_cos_event_spec,
+ .num_event_specs = ARRAY_SIZE(ad2s1210_sin_cos_event_spec),
+ }, {
+ /* cosine input */
+ .type = IIO_ALTVOLTAGE,
+ .indexed = 1,
+ .channel = 2,
+ .scan_index = -1,
+ .event_spec = ad2s1210_sin_cos_event_spec,
+ .num_event_specs = ARRAY_SIZE(ad2s1210_sin_cos_event_spec),
+ },
+};
+
+static ssize_t event_attr_voltage_reg_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
+ struct iio_dev_attr *iattr = to_iio_dev_attr(attr);
+ unsigned int value;
+ int ret;
+
+ guard(mutex)(&st->lock);
+ ret = regmap_read(st->regmap, iattr->address, &value);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", value * THRESHOLD_MILLIVOLT_PER_LSB);
+}
+
+static ssize_t event_attr_voltage_reg_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
+ struct iio_dev_attr *iattr = to_iio_dev_attr(attr);
+ u16 data;
+ int ret;
+
+ ret = kstrtou16(buf, 10, &data);
+ if (ret)
+ return -EINVAL;
+
+ guard(mutex)(&st->lock);
+ ret = regmap_write(st->regmap, iattr->address,
+ data / THRESHOLD_MILLIVOLT_PER_LSB);
+ if (ret < 0)
+ return ret;
+
+ return len;
+}
+
+static ssize_t
+in_angl1_thresh_rising_value_available_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
+ int step = ad2s1210_lot_threshold_urad_per_lsb[st->resolution];
+
+ return sysfs_emit(buf, "[0 0.%06d 0.%06d]\n", step, step * 0x7F);
+}
+
+static ssize_t
+in_angl1_thresh_rising_hysteresis_available_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
+ int step = ad2s1210_lot_threshold_urad_per_lsb[st->resolution];
+
+ return sysfs_emit(buf, "[0 0.%06d 0.%06d]\n", step, step * 0x7F);
+}
+
+static IIO_CONST_ATTR(in_phase0_mag_rising_value_available,
+ __stringify(PHASE_44_DEG_TO_RAD_INT) "."
+ __stringify(PHASE_44_DEG_TO_RAD_MICRO) " "
+ __stringify(PHASE_360_DEG_TO_RAD_INT) "."
+ __stringify(PHASE_360_DEG_TO_RAD_MICRO));
+static IIO_CONST_ATTR(in_altvoltage0_thresh_falling_value_available,
+ THRESHOLD_RANGE_STR);
+static IIO_CONST_ATTR(in_altvoltage0_thresh_rising_value_available,
+ THRESHOLD_RANGE_STR);
+static IIO_CONST_ATTR(in_altvoltage0_mag_rising_value_available,
+ THRESHOLD_RANGE_STR);
+static IIO_DEVICE_ATTR(in_altvoltage0_mag_rising_reset_max, 0644,
+ event_attr_voltage_reg_show, event_attr_voltage_reg_store,
+ AD2S1210_REG_DOS_RST_MAX_THRD);
+static IIO_CONST_ATTR(in_altvoltage0_mag_rising_reset_max_available, THRESHOLD_RANGE_STR);
+static IIO_DEVICE_ATTR(in_altvoltage0_mag_rising_reset_min, 0644,
+ event_attr_voltage_reg_show, event_attr_voltage_reg_store,
+ AD2S1210_REG_DOS_RST_MIN_THRD);
+static IIO_CONST_ATTR(in_altvoltage0_mag_rising_reset_min_available, THRESHOLD_RANGE_STR);
+static IIO_DEVICE_ATTR_RO(in_angl1_thresh_rising_value_available, 0);
+static IIO_DEVICE_ATTR_RO(in_angl1_thresh_rising_hysteresis_available, 0);
+
+static struct attribute *ad2s1210_event_attributes[] = {
+ &iio_const_attr_in_phase0_mag_rising_value_available.dev_attr.attr,
+ &iio_const_attr_in_altvoltage0_thresh_falling_value_available.dev_attr.attr,
+ &iio_const_attr_in_altvoltage0_thresh_rising_value_available.dev_attr.attr,
+ &iio_const_attr_in_altvoltage0_mag_rising_value_available.dev_attr.attr,
+ &iio_dev_attr_in_altvoltage0_mag_rising_reset_max.dev_attr.attr,
+ &iio_const_attr_in_altvoltage0_mag_rising_reset_max_available.dev_attr.attr,
+ &iio_dev_attr_in_altvoltage0_mag_rising_reset_min.dev_attr.attr,
+ &iio_const_attr_in_altvoltage0_mag_rising_reset_min_available.dev_attr.attr,
+ &iio_dev_attr_in_angl1_thresh_rising_value_available.dev_attr.attr,
+ &iio_dev_attr_in_angl1_thresh_rising_hysteresis_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad2s1210_event_attribute_group = {
+ .attrs = ad2s1210_event_attributes,
+};
+
+static int ad2s1210_initial(struct ad2s1210_state *st)
+{
+ unsigned int data;
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ /* Use default config register value plus resolution from devicetree. */
+ data = FIELD_PREP(AD2S1210_PHASE_LOCK_RANGE_44, 1);
+ data |= FIELD_PREP(AD2S1210_ENABLE_HYSTERESIS, 1);
+ data |= FIELD_PREP(AD2S1210_SET_ENRES, 0x3);
+ data |= FIELD_PREP(AD2S1210_SET_RES, st->resolution);
+
+ ret = regmap_write(st->regmap, AD2S1210_REG_CONTROL, data);
+ if (ret < 0)
+ return ret;
+
+ return ad2s1210_reinit_excitation_frequency(st, AD2S1210_DEF_EXCIT);
+}
+
+static int ad2s1210_read_label(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ char *label)
+{
+ if (chan->type == IIO_ANGL) {
+ if (chan->channel == 0)
+ return sprintf(label, "position\n");
+ if (chan->channel == 1)
+ return sprintf(label, "tracking error\n");
+ }
+ if (chan->type == IIO_ANGL_VEL)
+ return sprintf(label, "velocity\n");
+ if (chan->type == IIO_PHASE)
+ return sprintf(label, "synthetic reference\n");
+ if (chan->type == IIO_ALTVOLTAGE) {
+ if (chan->output)
+ return sprintf(label, "excitation\n");
+ if (chan->channel == 0)
+ return sprintf(label, "monitor signal\n");
+ if (chan->channel == 1)
+ return sprintf(label, "cosine\n");
+ if (chan->channel == 2)
+ return sprintf(label, "sine\n");
+ }
+
+ return -EINVAL;
+}
+
+static int ad2s1210_read_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
+{
+ struct ad2s1210_state *st = iio_priv(indio_dev);
+
+ switch (chan->type) {
+ case IIO_ANGL:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ return ad2s1210_get_lot_high_threshold(st, val, val2);
+ case IIO_EV_INFO_HYSTERESIS:
+ return ad2s1210_get_lot_low_threshold(st, val, val2);
+ default:
+ return -EINVAL;
+ }
+ case IIO_ALTVOLTAGE:
+ if (chan->output)
+ return -EINVAL;
+ if (type == IIO_EV_TYPE_THRESH && dir == IIO_EV_DIR_FALLING)
+ return ad2s1210_get_voltage_threshold(st,
+ AD2S1210_REG_LOS_THRD, val);
+ if (type == IIO_EV_TYPE_THRESH && dir == IIO_EV_DIR_RISING)
+ return ad2s1210_get_voltage_threshold(st,
+ AD2S1210_REG_DOS_OVR_THRD, val);
+ if (type == IIO_EV_TYPE_MAG)
+ return ad2s1210_get_voltage_threshold(st,
+ AD2S1210_REG_DOS_MIS_THRD, val);
+ return -EINVAL;
+ case IIO_PHASE:
+ return ad2s1210_get_phase_lock_range(st, val, val2);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad2s1210_write_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
+{
+ struct ad2s1210_state *st = iio_priv(indio_dev);
+
+ switch (chan->type) {
+ case IIO_ANGL:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ return ad2s1210_set_lot_high_threshold(st, val, val2);
+ case IIO_EV_INFO_HYSTERESIS:
+ return ad2s1210_set_lot_low_threshold(st, val, val2);
+ default:
+ return -EINVAL;
+ }
+ case IIO_ALTVOLTAGE:
+ if (chan->output)
+ return -EINVAL;
+ if (type == IIO_EV_TYPE_THRESH && dir == IIO_EV_DIR_FALLING)
+ return ad2s1210_set_voltage_threshold(st,
+ AD2S1210_REG_LOS_THRD, val);
+ if (type == IIO_EV_TYPE_THRESH && dir == IIO_EV_DIR_RISING)
+ return ad2s1210_set_voltage_threshold(st,
+ AD2S1210_REG_DOS_OVR_THRD, val);
+ if (type == IIO_EV_TYPE_MAG)
+ return ad2s1210_set_voltage_threshold(st,
+ AD2S1210_REG_DOS_MIS_THRD, val);
+ return -EINVAL;
+ case IIO_PHASE:
+ return ad2s1210_set_phase_lock_range(st, val, val2);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad2s1210_read_event_label(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ char *label)
+{
+ if (chan->type == IIO_ANGL)
+ return sprintf(label, "LOT\n");
+ if (chan->type == IIO_ANGL_VEL)
+ return sprintf(label, "max tracking rate\n");
+ if (chan->type == IIO_PHASE)
+ return sprintf(label, "phase lock\n");
+ if (chan->type == IIO_ALTVOLTAGE) {
+ if (chan->channel == 0) {
+ if (type == IIO_EV_TYPE_THRESH &&
+ dir == IIO_EV_DIR_FALLING)
+ return sprintf(label, "LOS\n");
+ if (type == IIO_EV_TYPE_THRESH &&
+ dir == IIO_EV_DIR_RISING)
+ return sprintf(label, "DOS overrange\n");
+ if (type == IIO_EV_TYPE_MAG)
+ return sprintf(label, "DOS mismatch\n");
+ }
+ if (chan->channel == 1 || chan->channel == 2)
+ return sprintf(label, "clipped\n");
+ }
+
+ return -EINVAL;
+}
+
+static int ad2s1210_debugfs_reg_access(struct iio_dev *indio_dev,
+ unsigned int reg, unsigned int writeval,
+ unsigned int *readval)
+{
+ struct ad2s1210_state *st = iio_priv(indio_dev);
+
+ guard(mutex)(&st->lock);
+
+ if (readval)
+ return regmap_read(st->regmap, reg, readval);
+
+ return regmap_write(st->regmap, reg, writeval);
+}
+
+static irqreturn_t ad2s1210_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ad2s1210_state *st = iio_priv(indio_dev);
+ size_t chan = 0;
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ memset(&st->scan, 0, sizeof(st->scan));
+ ad2s1210_toggle_sample_line(st);
+
+ if (test_bit(0, indio_dev->active_scan_mask)) {
+ ret = ad2s1210_set_mode(st, MOD_POS);
+ if (ret < 0)
+ goto error_ret;
+
+ ret = spi_read(st->sdev, &st->sample, 3);
+ if (ret < 0)
+ goto error_ret;
+
+ memcpy(&st->scan.chan[chan++], &st->sample.raw, 2);
+ }
+
+ if (test_bit(1, indio_dev->active_scan_mask)) {
+ ret = ad2s1210_set_mode(st, MOD_VEL);
+ if (ret < 0)
+ goto error_ret;
+
+ ret = spi_read(st->sdev, &st->sample, 3);
+ if (ret < 0)
+ goto error_ret;
+
+ memcpy(&st->scan.chan[chan++], &st->sample.raw, 2);
+ }
+
+ ad2s1210_push_events(indio_dev, st->sample.fault, pf->timestamp);
+ iio_push_to_buffers_with_timestamp(indio_dev, &st->scan, pf->timestamp);
+
+error_ret:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static const struct iio_info ad2s1210_info = {
+ .event_attrs = &ad2s1210_event_attribute_group,
+ .read_raw = ad2s1210_read_raw,
+ .read_avail = ad2s1210_read_avail,
+ .write_raw = ad2s1210_write_raw,
+ .read_label = ad2s1210_read_label,
+ .read_event_value = ad2s1210_read_event_value,
+ .write_event_value = ad2s1210_write_event_value,
+ .read_event_label = ad2s1210_read_event_label,
+ .debugfs_reg_access = &ad2s1210_debugfs_reg_access,
+};
+
+static int ad2s1210_setup_properties(struct ad2s1210_state *st)
+{
+ struct device *dev = &st->sdev->dev;
+ u32 val;
+ int ret;
+
+ ret = device_property_read_u32(dev, "assigned-resolution-bits", &val);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "failed to read assigned-resolution-bits property\n");
+
+ if (val < 10 || val > 16)
+ return dev_err_probe(dev, -EINVAL,
+ "resolution out of range: %u\n", val);
+
+ st->resolution = (val - 10) >> 1;
+ /*
+ * These are values that correlate to the hysteresis bit in the Control
+ * register. 0 = disabled, 1 = enabled. When enabled, the actual
+ * hysteresis is +/- 1 LSB of the raw position value. Which bit is the
+ * LSB depends on the specified resolution.
+ */
+ st->hysteresis_available[0] = 0;
+ st->hysteresis_available[1] = 1 << (2 * (AD2S1210_RES_16 -
+ st->resolution));
+
+ return 0;
+}
+
+static int ad2s1210_setup_clocks(struct ad2s1210_state *st)
+{
+ struct device *dev = &st->sdev->dev;
+ struct clk *clk;
+
+ clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk), "failed to get clock\n");
+
+ st->clkin_hz = clk_get_rate(clk);
+ if (st->clkin_hz < AD2S1210_MIN_CLKIN || st->clkin_hz > AD2S1210_MAX_CLKIN)
+ return dev_err_probe(dev, -EINVAL,
+ "clock frequency out of range: %lu\n",
+ st->clkin_hz);
+
+ return 0;
+}
+
+static int ad2s1210_setup_gpios(struct ad2s1210_state *st)
+{
+ struct device *dev = &st->sdev->dev;
+ struct gpio_descs *resolution_gpios;
+ DECLARE_BITMAP(bitmap, 2);
+ int ret;
+
+ /* should not be sampling on startup */
+ st->sample_gpio = devm_gpiod_get(dev, "sample", GPIOD_OUT_LOW);
+ if (IS_ERR(st->sample_gpio))
+ return dev_err_probe(dev, PTR_ERR(st->sample_gpio),
+ "failed to request sample GPIO\n");
+
+ /* both pins high means that we start in config mode */
+ st->mode_gpios = devm_gpiod_get_array(dev, "mode", GPIOD_OUT_HIGH);
+ if (IS_ERR(st->mode_gpios))
+ return dev_err_probe(dev, PTR_ERR(st->mode_gpios),
+ "failed to request mode GPIOs\n");
+
+ if (st->mode_gpios->ndescs != 2)
+ return dev_err_probe(dev, -EINVAL,
+ "requires exactly 2 mode-gpios\n");
+
+ /*
+ * If resolution gpios are provided, they get set to the required
+ * resolution, otherwise it is assumed the RES0 and RES1 pins are
+ * hard-wired to match the resolution indicated in the devicetree.
+ */
+ resolution_gpios = devm_gpiod_get_array_optional(dev, "resolution",
+ GPIOD_ASIS);
+ if (IS_ERR(resolution_gpios))
+ return dev_err_probe(dev, PTR_ERR(resolution_gpios),
+ "failed to request resolution GPIOs\n");
+
+ if (resolution_gpios) {
+ if (resolution_gpios->ndescs != 2)
+ return dev_err_probe(dev, -EINVAL,
+ "requires exactly 2 resolution-gpios\n");
+
+ bitmap[0] = st->resolution;
+
+ ret = gpiod_set_array_value(resolution_gpios->ndescs,
+ resolution_gpios->desc,
+ resolution_gpios->info,
+ bitmap);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "failed to set resolution gpios\n");
+ }
+
+ return 0;
+}
+
+static const struct regmap_range ad2s1210_regmap_readable_ranges[] = {
+ regmap_reg_range(AD2S1210_REG_POSITION_MSB, AD2S1210_REG_VELOCITY_LSB),
+ regmap_reg_range(AD2S1210_REG_LOS_THRD, AD2S1210_REG_LOT_LOW_THRD),
+ regmap_reg_range(AD2S1210_REG_EXCIT_FREQ, AD2S1210_REG_CONTROL),
+ regmap_reg_range(AD2S1210_REG_FAULT, AD2S1210_REG_FAULT),
+};
+
+static const struct regmap_access_table ad2s1210_regmap_rd_table = {
+ .yes_ranges = ad2s1210_regmap_readable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ad2s1210_regmap_readable_ranges),
+};
+
+static const struct regmap_range ad2s1210_regmap_writeable_ranges[] = {
+ regmap_reg_range(AD2S1210_REG_LOS_THRD, AD2S1210_REG_LOT_LOW_THRD),
+ regmap_reg_range(AD2S1210_REG_EXCIT_FREQ, AD2S1210_REG_CONTROL),
+ regmap_reg_range(AD2S1210_REG_SOFT_RESET, AD2S1210_REG_SOFT_RESET),
+ regmap_reg_range(AD2S1210_REG_FAULT, AD2S1210_REG_FAULT),
+};
+
+static const struct regmap_access_table ad2s1210_regmap_wr_table = {
+ .yes_ranges = ad2s1210_regmap_writeable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ad2s1210_regmap_writeable_ranges),
+};
+
+static int ad2s1210_setup_regmap(struct ad2s1210_state *st)
+{
+ struct device *dev = &st->sdev->dev;
+ const struct regmap_config config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .disable_locking = true,
+ .reg_read = ad2s1210_regmap_reg_read,
+ .reg_write = ad2s1210_regmap_reg_write,
+ .rd_table = &ad2s1210_regmap_rd_table,
+ .wr_table = &ad2s1210_regmap_wr_table,
+ .can_sleep = true,
+ };
+
+ st->regmap = devm_regmap_init(dev, NULL, st, &config);
+ if (IS_ERR(st->regmap))
+ return dev_err_probe(dev, PTR_ERR(st->regmap),
+ "failed to allocate register map\n");
+
+ return 0;
+}
+
+static int ad2s1210_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ struct ad2s1210_state *st;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+ st = iio_priv(indio_dev);
+
+ mutex_init(&st->lock);
+ st->sdev = spi;
+
+ ret = ad2s1210_setup_properties(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad2s1210_setup_clocks(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad2s1210_setup_gpios(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad2s1210_setup_regmap(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad2s1210_initial(st);
+ if (ret < 0)
+ return ret;
+
+ indio_dev->info = &ad2s1210_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = ad2s1210_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ad2s1210_channels);
+ indio_dev->name = spi_get_device_id(spi)->name;
+
+ ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
+ &iio_pollfunc_store_time,
+ &ad2s1210_trigger_handler, NULL);
+ if (ret < 0)
+ return dev_err_probe(&spi->dev, ret,
+ "iio triggered buffer setup failed\n");
+
+ return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct of_device_id ad2s1210_of_match[] = {
+ { .compatible = "adi,ad2s1210", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad2s1210_of_match);
+
+static const struct spi_device_id ad2s1210_id[] = {
+ { "ad2s1210" },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, ad2s1210_id);
+
+static struct spi_driver ad2s1210_driver = {
+ .driver = {
+ .name = "ad2s1210",
+ .of_match_table = ad2s1210_of_match,
+ },
+ .probe = ad2s1210_probe,
+ .id_table = ad2s1210_id,
+};
+module_spi_driver(ad2s1210_driver);
+
+MODULE_AUTHOR("Graff Yang <graff.yang@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices AD2S1210 Resolver to Digital SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/temperature/hid-sensor-temperature.c b/drivers/iio/temperature/hid-sensor-temperature.c
index d40f235af1..0143fd4789 100644
--- a/drivers/iio/temperature/hid-sensor-temperature.c
+++ b/drivers/iio/temperature/hid-sensor-temperature.c
@@ -257,7 +257,7 @@ error_remove_trigger:
}
/* Function to deinitialize the processing for usage id */
-static int hid_temperature_remove(struct platform_device *pdev)
+static void hid_temperature_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev);
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -265,8 +265,6 @@ static int hid_temperature_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TEMPERATURE);
hid_sensor_remove_trigger(indio_dev, &temp_st->common_attributes);
-
- return 0;
}
static const struct platform_device_id hid_temperature_ids[] = {
@@ -285,7 +283,7 @@ static struct platform_driver hid_temperature_platform_driver = {
.pm = &hid_sensor_pm_ops,
},
.probe = hid_temperature_probe,
- .remove = hid_temperature_remove,
+ .remove_new = hid_temperature_remove,
};
module_platform_driver(hid_temperature_platform_driver);
diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c
index 07bb5df24a..740018d4b3 100644
--- a/drivers/iio/temperature/mlx90614.c
+++ b/drivers/iio/temperature/mlx90614.c
@@ -600,7 +600,7 @@ static int mlx90614_probe(struct i2c_client *client)
data->client = client;
mutex_init(&data->lock);
data->wakeup_gpio = mlx90614_probe_wakeup(client);
- data->chip_info = device_get_match_data(&client->dev);
+ data->chip_info = i2c_get_match_data(client);
mlx90614_wakeup(data);
diff --git a/drivers/iio/temperature/tmp117.c b/drivers/iio/temperature/tmp117.c
index fc02f49168..059953015a 100644
--- a/drivers/iio/temperature/tmp117.c
+++ b/drivers/iio/temperature/tmp117.c
@@ -42,6 +42,12 @@ struct tmp117_data {
s16 calibbias;
};
+struct tmp11x_info {
+ const char *name;
+ struct iio_chan_spec const *channels;
+ int num_channels;
+};
+
static int tmp117_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int *val,
int *val2, long mask)
@@ -119,57 +125,54 @@ static const struct iio_chan_spec tmp116_channels[] = {
},
};
+static const struct tmp11x_info tmp116_channels_info = {
+ .name = "tmp116",
+ .channels = tmp116_channels,
+ .num_channels = ARRAY_SIZE(tmp116_channels)
+};
+
+static const struct tmp11x_info tmp117_channels_info = {
+ .name = "tmp117",
+ .channels = tmp117_channels,
+ .num_channels = ARRAY_SIZE(tmp117_channels)
+};
+
static const struct iio_info tmp117_info = {
.read_raw = tmp117_read_raw,
.write_raw = tmp117_write_raw,
};
-static int tmp117_identify(struct i2c_client *client)
+static int tmp117_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id;
- unsigned long match_data;
+ const struct tmp11x_info *match_data;
+ struct tmp117_data *data;
+ struct iio_dev *indio_dev;
int dev_id;
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
+ return -EOPNOTSUPP;
+
dev_id = i2c_smbus_read_word_swapped(client, TMP117_REG_DEVICE_ID);
if (dev_id < 0)
return dev_id;
switch (dev_id) {
case TMP116_DEVICE_ID:
+ match_data = &tmp116_channels_info;
+ break;
case TMP117_DEVICE_ID:
- return dev_id;
+ match_data = &tmp117_channels_info;
+ break;
+ default:
+ dev_info(&client->dev,
+ "Unknown device id (0x%x), use fallback compatible\n",
+ dev_id);
+ match_data = i2c_get_match_data(client);
}
- dev_info(&client->dev, "Unknown device id (0x%x), use fallback compatible\n",
- dev_id);
-
- match_data = (uintptr_t)device_get_match_data(&client->dev);
- if (match_data)
- return match_data;
-
- id = i2c_client_get_device_id(client);
- if (id)
- return id->driver_data;
-
- dev_err(&client->dev, "Failed to identify unsupported device\n");
-
- return -ENODEV;
-}
-
-static int tmp117_probe(struct i2c_client *client)
-{
- struct tmp117_data *data;
- struct iio_dev *indio_dev;
- int ret, dev_id;
-
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
- return -EOPNOTSUPP;
-
- ret = tmp117_identify(client);
- if (ret < 0)
- return ret;
-
- dev_id = ret;
+ if (!match_data)
+ return dev_err_probe(&client->dev, -ENODEV,
+ "Failed to identify unsupported device\n");
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
@@ -181,33 +184,24 @@ static int tmp117_probe(struct i2c_client *client)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &tmp117_info;
+ indio_dev->channels = match_data->channels;
+ indio_dev->num_channels = match_data->num_channels;
+ indio_dev->name = match_data->name;
- switch (dev_id) {
- case TMP116_DEVICE_ID:
- indio_dev->channels = tmp116_channels;
- indio_dev->num_channels = ARRAY_SIZE(tmp116_channels);
- indio_dev->name = "tmp116";
- break;
- case TMP117_DEVICE_ID:
- indio_dev->channels = tmp117_channels;
- indio_dev->num_channels = ARRAY_SIZE(tmp117_channels);
- indio_dev->name = "tmp117";
- break;
- }
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct of_device_id tmp117_of_match[] = {
- { .compatible = "ti,tmp116", .data = (void *)TMP116_DEVICE_ID },
- { .compatible = "ti,tmp117", .data = (void *)TMP117_DEVICE_ID },
+ { .compatible = "ti,tmp116", .data = &tmp116_channels_info },
+ { .compatible = "ti,tmp117", .data = &tmp117_channels_info },
{ }
};
MODULE_DEVICE_TABLE(of, tmp117_of_match);
static const struct i2c_device_id tmp117_id[] = {
- { "tmp116", TMP116_DEVICE_ID },
- { "tmp117", TMP117_DEVICE_ID },
+ { "tmp116", (kernel_ulong_t)&tmp116_channels_info },
+ { "tmp117", (kernel_ulong_t)&tmp117_channels_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, tmp117_id);
diff --git a/drivers/iio/trigger/iio-trig-interrupt.c b/drivers/iio/trigger/iio-trig-interrupt.c
index 5f49cd105f..dec256bfbd 100644
--- a/drivers/iio/trigger/iio-trig-interrupt.c
+++ b/drivers/iio/trigger/iio-trig-interrupt.c
@@ -81,7 +81,7 @@ error_ret:
return ret;
}
-static int iio_interrupt_trigger_remove(struct platform_device *pdev)
+static void iio_interrupt_trigger_remove(struct platform_device *pdev)
{
struct iio_trigger *trig;
struct iio_interrupt_trigger_info *trig_info;
@@ -92,13 +92,11 @@ static int iio_interrupt_trigger_remove(struct platform_device *pdev)
free_irq(trig_info->irq, trig);
kfree(trig_info);
iio_trigger_free(trig);
-
- return 0;
}
static struct platform_driver iio_interrupt_trigger_driver = {
.probe = iio_interrupt_trigger_probe,
- .remove = iio_interrupt_trigger_remove,
+ .remove_new = iio_interrupt_trigger_remove,
.driver = {
.name = "iio_interrupt_trigger",
},
diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
index 3643c4afae..d76444030a 100644
--- a/drivers/iio/trigger/stm32-timer-trigger.c
+++ b/drivers/iio/trigger/stm32-timer-trigger.c
@@ -809,7 +809,7 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev)
return 0;
}
-static int stm32_timer_trigger_remove(struct platform_device *pdev)
+static void stm32_timer_trigger_remove(struct platform_device *pdev)
{
struct stm32_timer_trigger *priv = platform_get_drvdata(pdev);
u32 val;
@@ -824,8 +824,6 @@ static int stm32_timer_trigger_remove(struct platform_device *pdev)
if (priv->enabled)
clk_disable(priv->clk);
-
- return 0;
}
static int stm32_timer_trigger_suspend(struct device *dev)
@@ -904,7 +902,7 @@ MODULE_DEVICE_TABLE(of, stm32_trig_of_match);
static struct platform_driver stm32_timer_trigger_driver = {
.probe = stm32_timer_trigger_probe,
- .remove = stm32_timer_trigger_remove,
+ .remove_new = stm32_timer_trigger_remove,
.driver = {
.name = "stm32-timer-trigger",
.of_match_table = stm32_trig_of_match,