aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-12-15 14:18:40 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2020-12-15 14:18:40 -0800
commit3db1a3fa98808aa90f95ec3e0fa2fc7abf28f5c9 (patch)
tree53958546913e5c60c590109c141bf182f1795e86 /drivers/iio
parentMerge tag 'char-misc-5.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc (diff)
parentstaging: olpc_dcon: Do not call platform_device_unregister() in dcon_probe() (diff)
downloadlinux-dev-3db1a3fa98808aa90f95ec3e0fa2fc7abf28f5c9.tar.xz
linux-dev-3db1a3fa98808aa90f95ec3e0fa2fc7abf28f5c9.zip
Merge tag 'staging-5.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
Pull staging / IIO driver updates from Greg KH: "Here is the big staging and IIO driver pull request for 5.11-rc1 Lots of different things in here: - loads of driver updates - so many coding style cleanups - new IIO drivers - Android ION code is finally removed from the tree - wimax drivers are moved to staging on their way out of the kernel Nothing really exciting, just the constant grind of kernel development :) All have been in linux-next for a while with no reported issues" * tag 'staging-5.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (341 commits) staging: olpc_dcon: Do not call platform_device_unregister() in dcon_probe() staging: most: Fix spelling mistake "tranceiver" -> "transceiver" staging: qlge: remove duplicate word in comment staging: comedi: mf6x4: Fix AI end-of-conversion detection staging: greybus: Add TODO item about modernizing the pwm code pinctrl: ralink: add a pinctrl driver for the rt2880 family dt-bindings: pinctrl: rt2880: add binding document staging: rtl8723bs: remove ELEMENT_ID enum staging: rtl8723bs: remove unused macros staging: rtl8723bs: replace EID_EXTCapability staging: rtl8723bs: replace EID_BSSIntolerantChlReport staging: rtl8723bs: replace EID_BSSCoexistence staging: rtl8723bs: replace _MME_IE_ staging: rtl8723bs: replace _WAPI_IE_ staging: rtl8723bs: replace _EXT_SUPPORTEDRATES_IE_ staging: rtl8723bs: replace _ERPINFO_IE_ staging: rtl8723bs: replace _CHLGETXT_IE_ staging: rtl8723bs: replace _COUNTRY_IE_ staging: rtl8723bs: replace _IBSS_PARA_IE_ staging: rtl8723bs: replace _TIM_IE_ ...
Diffstat (limited to 'drivers/iio')
-rw-r--r--drivers/iio/accel/adis16201.c1
-rw-r--r--drivers/iio/accel/adis16209.c1
-rw-r--r--drivers/iio/accel/adxl372.c11
-rw-r--r--drivers/iio/accel/bma180.c9
-rw-r--r--drivers/iio/accel/bmc150-accel-core.c219
-rw-r--r--drivers/iio/accel/bmc150-accel-i2c.c45
-rw-r--r--drivers/iio/accel/bmc150-accel-spi.c2
-rw-r--r--drivers/iio/accel/bmc150-accel.h3
-rw-r--r--drivers/iio/accel/kxcjk-1013.c10
-rw-r--r--drivers/iio/accel/mma8452.c2
-rw-r--r--drivers/iio/accel/mxc4005.c16
-rw-r--r--drivers/iio/adc/Kconfig13
-rw-r--r--drivers/iio/adc/Makefile1
-rw-r--r--drivers/iio/adc/ad7292.c2
-rw-r--r--drivers/iio/adc/ad7298.c65
-rw-r--r--drivers/iio/adc/ad7768-1.c41
-rw-r--r--drivers/iio/adc/ad7887.c55
-rw-r--r--drivers/iio/adc/ad_sigma_delta.c18
-rw-r--r--drivers/iio/adc/at91-sama5d2_adc.c92
-rw-r--r--drivers/iio/adc/at91_adc.c353
-rw-r--r--drivers/iio/adc/cpcap-adc.c1
-rw-r--r--drivers/iio/adc/exynos_adc.c7
-rw-r--r--drivers/iio/adc/ingenic-adc.c2
-rw-r--r--drivers/iio/adc/meson_saradc.c2
-rw-r--r--drivers/iio/adc/mt6360-adc.c372
-rw-r--r--drivers/iio/adc/rockchip_saradc.c2
-rw-r--r--drivers/iio/adc/stm32-adc-core.c21
-rw-r--r--drivers/iio/adc/stm32-adc.c29
-rw-r--r--drivers/iio/adc/ti-adc084s021.c10
-rw-r--r--drivers/iio/adc/ti-ads124s08.c13
-rw-r--r--drivers/iio/buffer/industrialio-buffer-cb.c5
-rw-r--r--drivers/iio/buffer/industrialio-buffer-dmaengine.c3
-rw-r--r--drivers/iio/buffer/industrialio-triggered-buffer.c31
-rw-r--r--drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c15
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-trigger.c22
-rw-r--r--drivers/iio/dac/Kconfig7
-rw-r--r--drivers/iio/dac/ad5686.c13
-rw-r--r--drivers/iio/dac/ad5686.h1
-rw-r--r--drivers/iio/dac/ad5696-i2c.c20
-rw-r--r--drivers/iio/dac/ad7303.c2
-rw-r--r--drivers/iio/gyro/adxrs290.c6
-rw-r--r--drivers/iio/gyro/bmg160_core.c12
-rw-r--r--drivers/iio/gyro/mpu3050-core.c28
-rw-r--r--drivers/iio/humidity/hts221.h2
-rw-r--r--drivers/iio/humidity/hts221_core.c37
-rw-r--r--drivers/iio/iio_core.h15
-rw-r--r--drivers/iio/imu/bmi160/bmi160.h7
-rw-r--r--drivers/iio/imu/bmi160/bmi160_core.c7
-rw-r--r--drivers/iio/imu/kmx61.c10
-rw-r--r--drivers/iio/imu/st_lsm6dsx/Kconfig4
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h10
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c2
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c318
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c10
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c10
-rw-r--r--drivers/iio/industrialio-buffer.c18
-rw-r--r--drivers/iio/industrialio-core.c212
-rw-r--r--drivers/iio/industrialio-event.c28
-rw-r--r--drivers/iio/industrialio-trigger.c6
-rw-r--r--drivers/iio/inkern.c29
-rw-r--r--drivers/iio/light/apds9960.c2
-rw-r--r--drivers/iio/light/rpr0521.c17
-rw-r--r--drivers/iio/light/st_uvis25.h5
-rw-r--r--drivers/iio/light/st_uvis25_core.c8
-rw-r--r--drivers/iio/light/tsl2563.c16
-rw-r--r--drivers/iio/light/vcnl4035.c7
-rw-r--r--drivers/iio/magnetometer/bmc150_magn.c12
-rw-r--r--drivers/iio/magnetometer/mag3110.c13
-rw-r--r--drivers/iio/potentiometer/ad5272.c4
-rw-r--r--drivers/iio/pressure/bmp280-regmap.c4
-rw-r--r--drivers/iio/pressure/mpl3115.c9
-rw-r--r--drivers/iio/proximity/sx9310.c508
-rw-r--r--drivers/iio/proximity/vl53l0x-i2c.c7
-rw-r--r--drivers/iio/trigger/iio-trig-hrtimer.c4
-rw-r--r--drivers/iio/trigger/iio-trig-sysfs.c2
75 files changed, 2020 insertions, 906 deletions
diff --git a/drivers/iio/accel/adis16201.c b/drivers/iio/accel/adis16201.c
index f955cccb3e77..3633a4e302c6 100644
--- a/drivers/iio/accel/adis16201.c
+++ b/drivers/iio/accel/adis16201.c
@@ -268,7 +268,6 @@ static int adis16201_probe(struct spi_device *spi)
return -ENOMEM;
st = iio_priv(indio_dev);
- spi_set_drvdata(spi, indio_dev);
indio_dev->name = spi->dev.driver->name;
indio_dev->info = &adis16201_info;
diff --git a/drivers/iio/accel/adis16209.c b/drivers/iio/accel/adis16209.c
index 4a841aec6268..6c2d4a967de7 100644
--- a/drivers/iio/accel/adis16209.c
+++ b/drivers/iio/accel/adis16209.c
@@ -279,7 +279,6 @@ static int adis16209_probe(struct spi_device *spi)
return -ENOMEM;
st = iio_priv(indio_dev);
- spi_set_drvdata(spi, indio_dev);
indio_dev->name = spi->dev.driver->name;
indio_dev->info = &adis16209_info;
diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c
index aed2a4930fb0..8ba1453b8dbf 100644
--- a/drivers/iio/accel/adxl372.c
+++ b/drivers/iio/accel/adxl372.c
@@ -1211,15 +1211,14 @@ int adxl372_probe(struct device *dev, struct regmap *regmap,
return ret;
}
- ret = devm_iio_triggered_buffer_setup(dev,
- indio_dev, NULL,
- adxl372_trigger_handler,
- &adxl372_buffer_ops);
+ ret = devm_iio_triggered_buffer_setup_ext(dev,
+ indio_dev, NULL,
+ adxl372_trigger_handler,
+ &adxl372_buffer_ops,
+ adxl372_fifo_attributes);
if (ret < 0)
return ret;
- iio_buffer_set_attrs(indio_dev->buffer, adxl372_fifo_attributes);
-
if (st->irq) {
st->dready_trig = devm_iio_trigger_alloc(dev,
"%s-dev%d",
diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c
index 6b74c2b04c15..71f85a3e525b 100644
--- a/drivers/iio/accel/bma180.c
+++ b/drivers/iio/accel/bma180.c
@@ -959,17 +959,20 @@ static int bma180_data_rdy_trigger_set_state(struct iio_trigger *trig,
return bma180_set_new_data_intr_state(data, state);
}
-static int bma180_trig_try_reen(struct iio_trigger *trig)
+static void bma180_trig_reen(struct iio_trigger *trig)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct bma180_data *data = iio_priv(indio_dev);
+ int ret;
- return bma180_reset_intr(data);
+ ret = bma180_reset_intr(data);
+ if (ret)
+ dev_err(&data->client->dev, "failed to reset interrupt\n");
}
static const struct iio_trigger_ops bma180_trigger_ops = {
.set_trigger_state = bma180_data_rdy_trigger_set_state,
- .try_reenable = bma180_trig_try_reen,
+ .reenable = bma180_trig_reen,
};
static int bma180_probe(struct i2c_client *client,
diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c
index 48435865fdaf..7e425ebcd7ea 100644
--- a/drivers/iio/accel/bmc150-accel-core.c
+++ b/drivers/iio/accel/bmc150-accel-core.c
@@ -5,6 +5,7 @@
* - BMI055
* - BMA255
* - BMA250E
+ * - BMA222
* - BMA222E
* - BMA280
*
@@ -27,6 +28,7 @@
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
#include "bmc150-accel.h"
@@ -183,7 +185,7 @@ enum bmc150_accel_trigger_id {
struct bmc150_accel_data {
struct regmap *regmap;
- int irq;
+ struct regulator_bulk_data regulators[2];
struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
struct mutex mutex;
@@ -204,6 +206,7 @@ struct bmc150_accel_data {
int ev_enable_state;
int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */
const struct bmc150_accel_chip_info *chip_info;
+ struct i2c_client *second_device;
struct iio_mount_matrix orientation;
};
@@ -410,6 +413,103 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
}
#endif
+#ifdef CONFIG_ACPI
+/*
+ * Support for getting accelerometer information from BOSC0200 ACPI nodes.
+ *
+ * There are 2 variants of the BOSC0200 ACPI node. Some 2-in-1s with 360 degree
+ * hinges declare 2 I2C ACPI-resources for 2 accelerometers, 1 in the display
+ * and 1 in the base of the 2-in-1. On these 2-in-1s the ROMS ACPI object
+ * contains the mount-matrix for the sensor in the display and ROMK contains
+ * the mount-matrix for the sensor in the base. On devices using a single
+ * sensor there is a ROTM ACPI object which contains the mount-matrix.
+ *
+ * Here is an incomplete list of devices known to use 1 of these setups:
+ *
+ * Yoga devices with 2 accelerometers using ROMS + ROMK for the mount-matrices:
+ * Lenovo Thinkpad Yoga 11e 3th gen
+ * Lenovo Thinkpad Yoga 11e 4th gen
+ *
+ * Tablets using a single accelerometer using ROTM for the mount-matrix:
+ * Chuwi Hi8 Pro (CWI513)
+ * Chuwi Vi8 Plus (CWI519)
+ * Chuwi Hi13
+ * Irbis TW90
+ * Jumper EZpad mini 3
+ * Onda V80 plus
+ * Predia Basic Tablet
+ */
+static bool bmc150_apply_acpi_orientation(struct device *dev,
+ struct iio_mount_matrix *orientation)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_device *adev = ACPI_COMPANION(dev);
+ union acpi_object *obj, *elements;
+ char *name, *alt_name, *str;
+ acpi_status status;
+ int i, j, val[3];
+
+ if (!adev || !acpi_dev_hid_uid_match(adev, "BOSC0200", NULL))
+ return false;
+
+ if (strcmp(dev_name(dev), "i2c-BOSC0200:base") == 0)
+ alt_name = "ROMK";
+ else
+ alt_name = "ROMS";
+
+ if (acpi_has_method(adev->handle, "ROTM"))
+ name = "ROTM";
+ else if (acpi_has_method(adev->handle, alt_name))
+ name = alt_name;
+ else
+ return false;
+
+ status = acpi_evaluate_object(adev->handle, name, NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ dev_warn(dev, "Failed to get ACPI mount matrix: %d\n", status);
+ return false;
+ }
+
+ obj = buffer.pointer;
+ if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3)
+ goto unknown_format;
+
+ elements = obj->package.elements;
+ for (i = 0; i < 3; i++) {
+ if (elements[i].type != ACPI_TYPE_STRING)
+ goto unknown_format;
+
+ str = elements[i].string.pointer;
+ if (sscanf(str, "%d %d %d", &val[0], &val[1], &val[2]) != 3)
+ goto unknown_format;
+
+ for (j = 0; j < 3; j++) {
+ switch (val[j]) {
+ case -1: str = "-1"; break;
+ case 0: str = "0"; break;
+ case 1: str = "1"; break;
+ default: goto unknown_format;
+ }
+ orientation->rotation[i * 3 + j] = str;
+ }
+ }
+
+ kfree(buffer.pointer);
+ return true;
+
+unknown_format:
+ dev_warn(dev, "Unknown ACPI mount matrix format, ignoring\n");
+ kfree(buffer.pointer);
+ return false;
+}
+#else
+static bool bmc150_apply_acpi_orientation(struct device *dev,
+ struct iio_mount_matrix *orientation)
+{
+ return false;
+}
+#endif
+
static const struct bmc150_accel_interrupt_info {
u8 map_reg;
u8 map_bitmask;
@@ -1063,6 +1163,20 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
{153277, BMC150_ACCEL_DEF_RANGE_8G},
{306457, BMC150_ACCEL_DEF_RANGE_16G} },
},
+ [bma222] = {
+ .name = "BMA222",
+ .chip_id = 0x03,
+ .channels = bma222e_accel_channels,
+ .num_channels = ARRAY_SIZE(bma222e_accel_channels),
+ /*
+ * The datasheet page 17 says:
+ * 15.6, 31.3, 62.5 and 125 mg per LSB.
+ */
+ .scale_table = { {156000, BMC150_ACCEL_DEF_RANGE_2G},
+ {313000, BMC150_ACCEL_DEF_RANGE_4G},
+ {625000, BMC150_ACCEL_DEF_RANGE_8G},
+ {1250000, BMC150_ACCEL_DEF_RANGE_16G} },
+ },
[bma222e] = {
.name = "BMA222E",
.chip_id = 0xF8,
@@ -1134,7 +1248,7 @@ err_read:
return IRQ_HANDLED;
}
-static int bmc150_accel_trig_try_reen(struct iio_trigger *trig)
+static void bmc150_accel_trig_reen(struct iio_trigger *trig)
{
struct bmc150_accel_trigger *t = iio_trigger_get_drvdata(trig);
struct bmc150_accel_data *data = t->data;
@@ -1143,7 +1257,7 @@ static int bmc150_accel_trig_try_reen(struct iio_trigger *trig)
/* new data interrupts don't need ack */
if (t == &t->data->triggers[BMC150_ACCEL_TRIGGER_DATA_READY])
- return 0;
+ return;
mutex_lock(&data->mutex);
/* clear any latched interrupt */
@@ -1151,12 +1265,8 @@ static int bmc150_accel_trig_try_reen(struct iio_trigger *trig)
BMC150_ACCEL_INT_MODE_LATCH_INT |
BMC150_ACCEL_INT_MODE_LATCH_RESET);
mutex_unlock(&data->mutex);
- if (ret < 0) {
+ if (ret < 0)
dev_err(dev, "Error writing reg_int_rst_latch\n");
- return ret;
- }
-
- return 0;
}
static int bmc150_accel_trigger_set_state(struct iio_trigger *trig,
@@ -1196,7 +1306,7 @@ static int bmc150_accel_trigger_set_state(struct iio_trigger *trig,
static const struct iio_trigger_ops bmc150_accel_trigger_ops = {
.set_trigger_state = bmc150_accel_trigger_set_state,
- .try_reenable = bmc150_accel_trig_try_reen,
+ .reenable = bmc150_accel_trig_reen,
};
static int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev)
@@ -1558,6 +1668,7 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
const char *name, bool block_supported)
{
+ const struct attribute **fifo_attrs;
struct bmc150_accel_data *data;
struct iio_dev *indio_dev;
int ret;
@@ -1568,18 +1679,43 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
data = iio_priv(indio_dev);
dev_set_drvdata(dev, indio_dev);
- data->irq = irq;
data->regmap = regmap;
- ret = iio_read_mount_matrix(dev, "mount-matrix",
- &data->orientation);
+ if (!bmc150_apply_acpi_orientation(dev, &data->orientation)) {
+ ret = iio_read_mount_matrix(dev, "mount-matrix",
+ &data->orientation);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * VDD is the analog and digital domain voltage supply
+ * VDDIO is the digital I/O voltage supply
+ */
+ data->regulators[0].supply = "vdd";
+ data->regulators[1].supply = "vddio";
+ ret = devm_regulator_bulk_get(dev,
+ ARRAY_SIZE(data->regulators),
+ data->regulators);
if (ret)
+ return dev_err_probe(dev, ret, "failed to get regulators\n");
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
+ data->regulators);
+ if (ret) {
+ dev_err(dev, "failed to enable regulators: %d\n", ret);
return ret;
+ }
+ /*
+ * 2ms or 3ms power-on time according to datasheets, let's better
+ * be safe than sorry and set this delay to 5ms.
+ */
+ msleep(5);
ret = bmc150_accel_chip_init(data);
if (ret < 0)
- return ret;
+ goto err_disable_regulators;
mutex_init(&data->mutex);
@@ -1590,18 +1726,26 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &bmc150_accel_info;
- ret = iio_triggered_buffer_setup(indio_dev,
- &iio_pollfunc_store_time,
- bmc150_accel_trigger_handler,
- &bmc150_accel_buffer_ops);
+ if (block_supported) {
+ indio_dev->modes |= INDIO_BUFFER_SOFTWARE;
+ indio_dev->info = &bmc150_accel_info_fifo;
+ fifo_attrs = bmc150_accel_fifo_attributes;
+ } else {
+ fifo_attrs = NULL;
+ }
+
+ ret = iio_triggered_buffer_setup_ext(indio_dev,
+ &iio_pollfunc_store_time,
+ bmc150_accel_trigger_handler,
+ &bmc150_accel_buffer_ops,
+ fifo_attrs);
if (ret < 0) {
dev_err(dev, "Failed: iio triggered buffer setup\n");
- return ret;
+ goto err_disable_regulators;
}
- if (data->irq > 0) {
- ret = devm_request_threaded_irq(
- dev, data->irq,
+ if (irq > 0) {
+ ret = devm_request_threaded_irq(dev, irq,
bmc150_accel_irq_handler,
bmc150_accel_irq_thread_handler,
IRQF_TRIGGER_RISING,
@@ -1628,13 +1772,6 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
ret = bmc150_accel_triggers_setup(indio_dev, data);
if (ret)
goto err_buffer_cleanup;
-
- if (block_supported) {
- indio_dev->modes |= INDIO_BUFFER_SOFTWARE;
- indio_dev->info = &bmc150_accel_info_fifo;
- iio_buffer_set_attrs(indio_dev->buffer,
- bmc150_accel_fifo_attributes);
- }
}
ret = pm_runtime_set_active(dev);
@@ -1657,11 +1794,34 @@ err_trigger_unregister:
bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
err_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
+err_disable_regulators:
+ regulator_bulk_disable(ARRAY_SIZE(data->regulators),
+ data->regulators);
return ret;
}
EXPORT_SYMBOL_GPL(bmc150_accel_core_probe);
+struct i2c_client *bmc150_get_second_device(struct i2c_client *client)
+{
+ struct bmc150_accel_data *data = i2c_get_clientdata(client);
+
+ if (!data)
+ return NULL;
+
+ return data->second_device;
+}
+EXPORT_SYMBOL_GPL(bmc150_get_second_device);
+
+void bmc150_set_second_device(struct i2c_client *client)
+{
+ struct bmc150_accel_data *data = i2c_get_clientdata(client);
+
+ if (data)
+ data->second_device = client;
+}
+EXPORT_SYMBOL_GPL(bmc150_set_second_device);
+
int bmc150_accel_core_remove(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
@@ -1681,6 +1841,9 @@ int bmc150_accel_core_remove(struct device *dev)
bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_DEEP_SUSPEND, 0);
mutex_unlock(&data->mutex);
+ regulator_bulk_disable(ARRAY_SIZE(data->regulators),
+ data->regulators);
+
return 0;
}
EXPORT_SYMBOL_GPL(bmc150_accel_core_remove);
diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c
index 06021c8685a7..69f709319484 100644
--- a/drivers/iio/accel/bmc150-accel-i2c.c
+++ b/drivers/iio/accel/bmc150-accel-i2c.c
@@ -5,6 +5,7 @@
* - BMI055
* - BMA255
* - BMA250E
+ * - BMA222
* - BMA222E
* - BMA280
*
@@ -29,6 +30,8 @@ static int bmc150_accel_probe(struct i2c_client *client,
i2c_check_functionality(client->adapter, I2C_FUNC_I2C) ||
i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_I2C_BLOCK);
+ struct acpi_device __maybe_unused *adev;
+ int ret;
regmap = devm_regmap_init_i2c(client, &bmc150_regmap_conf);
if (IS_ERR(regmap)) {
@@ -39,12 +42,47 @@ static int bmc150_accel_probe(struct i2c_client *client,
if (id)
name = id->name;
- return bmc150_accel_core_probe(&client->dev, regmap, client->irq, name,
- block_supported);
+ ret = bmc150_accel_core_probe(&client->dev, regmap, client->irq, name, block_supported);
+ if (ret)
+ return ret;
+
+ /*
+ * Some BOSC0200 acpi_devices describe 2 accelerometers in a single ACPI
+ * device, try instantiating a second i2c_client for an I2cSerialBusV2
+ * ACPI resource with index 1. The !id check avoids recursion when
+ * bmc150_accel_probe() gets called for the second client.
+ */
+#ifdef CONFIG_ACPI
+ adev = ACPI_COMPANION(&client->dev);
+ if (!id && adev && strcmp(acpi_device_hid(adev), "BOSC0200") == 0) {
+ struct i2c_board_info board_info = {
+ .type = "bmc150_accel",
+ /*
+ * The 2nd accel sits in the base of 2-in-1s. Note this
+ * name is static, as there should never be more then 1
+ * BOSC0200 ACPI node with 2 accelerometers in it.
+ */
+ .dev_name = "BOSC0200:base",
+ .fwnode = client->dev.fwnode,
+ .irq = -ENOENT,
+ };
+ struct i2c_client *second_dev;
+
+ second_dev = i2c_acpi_new_device(&client->dev, 1, &board_info);
+ if (!IS_ERR(second_dev))
+ bmc150_set_second_device(second_dev);
+ }
+#endif
+
+ return 0;
}
static int bmc150_accel_remove(struct i2c_client *client)
{
+ struct i2c_client *second_dev = bmc150_get_second_device(client);
+
+ i2c_unregister_device(second_dev);
+
return bmc150_accel_core_remove(&client->dev);
}
@@ -54,6 +92,7 @@ static const struct acpi_device_id bmc150_accel_acpi_match[] = {
{"BMI055A", bmi055},
{"BMA0255", bma255},
{"BMA250E", bma250e},
+ {"BMA222", bma222},
{"BMA222E", bma222e},
{"BMA0280", bma280},
{"BOSC0200"},
@@ -66,6 +105,7 @@ static const struct i2c_device_id bmc150_accel_id[] = {
{"bmi055_accel", bmi055},
{"bma255", bma255},
{"bma250e", bma250e},
+ {"bma222", bma222},
{"bma222e", bma222e},
{"bma280", bma280},
{}
@@ -78,6 +118,7 @@ static const struct of_device_id bmc150_accel_of_match[] = {
{ .compatible = "bosch,bmi055_accel" },
{ .compatible = "bosch,bma255" },
{ .compatible = "bosch,bma250e" },
+ { .compatible = "bosch,bma222" },
{ .compatible = "bosch,bma222e" },
{ .compatible = "bosch,bma280" },
{ },
diff --git a/drivers/iio/accel/bmc150-accel-spi.c b/drivers/iio/accel/bmc150-accel-spi.c
index 2a8c311d6f5a..74a8aee4f612 100644
--- a/drivers/iio/accel/bmc150-accel-spi.c
+++ b/drivers/iio/accel/bmc150-accel-spi.c
@@ -39,6 +39,7 @@ static const struct acpi_device_id bmc150_accel_acpi_match[] = {
{"BMI055A", bmi055},
{"BMA0255", bma255},
{"BMA250E", bma250e},
+ {"BMA222", bma222},
{"BMA222E", bma222e},
{"BMA0280", bma280},
{ },
@@ -50,6 +51,7 @@ static const struct spi_device_id bmc150_accel_id[] = {
{"bmi055_accel", bmi055},
{"bma255", bma255},
{"bma250e", bma250e},
+ {"bma222", bma222},
{"bma222e", bma222e},
{"bma280", bma280},
{}
diff --git a/drivers/iio/accel/bmc150-accel.h b/drivers/iio/accel/bmc150-accel.h
index ae6118ae11b1..6024f15b9700 100644
--- a/drivers/iio/accel/bmc150-accel.h
+++ b/drivers/iio/accel/bmc150-accel.h
@@ -9,6 +9,7 @@ enum {
bmi055,
bma255,
bma250e,
+ bma222,
bma222e,
bma280,
};
@@ -16,6 +17,8 @@ enum {
int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
const char *name, bool block_supported);
int bmc150_accel_core_remove(struct device *dev);
+struct i2c_client *bmc150_get_second_device(struct i2c_client *second_device);
+void bmc150_set_second_device(struct i2c_client *second_device);
extern const struct dev_pm_ops bmc150_accel_pm_ops;
extern const struct regmap_config bmc150_regmap_conf;
diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c
index 560a3373ff20..e92c7e6766e1 100644
--- a/drivers/iio/accel/kxcjk-1013.c
+++ b/drivers/iio/accel/kxcjk-1013.c
@@ -1105,19 +1105,15 @@ err:
return IRQ_HANDLED;
}
-static int kxcjk1013_trig_try_reen(struct iio_trigger *trig)
+static void kxcjk1013_trig_reen(struct iio_trigger *trig)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct kxcjk1013_data *data = iio_priv(indio_dev);
int ret;
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_REL);
- if (ret < 0) {
+ if (ret < 0)
dev_err(&data->client->dev, "Error reading reg_int_rel\n");
- return ret;
- }
-
- return 0;
}
static int kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig,
@@ -1161,7 +1157,7 @@ static int kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig,
static const struct iio_trigger_ops kxcjk1013_trigger_ops = {
.set_trigger_state = kxcjk1013_data_rdy_trigger_set_state,
- .try_reenable = kxcjk1013_trig_try_reen,
+ .reenable = kxcjk1013_trig_reen,
};
static void kxcjk1013_report_motion_event(struct iio_dev *indio_dev)
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index bf1d2c8afdbd..b0176d936423 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -1187,7 +1187,7 @@ static struct attribute *mma8452_event_attributes[] = {
NULL,
};
-static struct attribute_group mma8452_event_attribute_group = {
+static const struct attribute_group mma8452_event_attribute_group = {
.attrs = mma8452_event_attributes,
};
diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c
index f877263dc6ef..0f8fd687866d 100644
--- a/drivers/iio/accel/mxc4005.c
+++ b/drivers/iio/accel/mxc4005.c
@@ -310,19 +310,15 @@ err:
return IRQ_HANDLED;
}
-static int mxc4005_clr_intr(struct mxc4005_data *data)
+static void mxc4005_clr_intr(struct mxc4005_data *data)
{
int ret;
/* clear interrupt */
ret = regmap_write(data->regmap, MXC4005_REG_INT_CLR1,
MXC4005_REG_INT_CLR1_BIT_DRDYC);
- if (ret < 0) {
+ if (ret < 0)
dev_err(data->dev, "failed to write to reg_int_clr1\n");
- return ret;
- }
-
- return 0;
}
static int mxc4005_set_trigger_state(struct iio_trigger *trig,
@@ -353,20 +349,20 @@ static int mxc4005_set_trigger_state(struct iio_trigger *trig,
return 0;
}
-static int mxc4005_trigger_try_reen(struct iio_trigger *trig)
+static void mxc4005_trigger_reen(struct iio_trigger *trig)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct mxc4005_data *data = iio_priv(indio_dev);
if (!data->dready_trig)
- return 0;
+ return;
- return mxc4005_clr_intr(data);
+ mxc4005_clr_intr(data);
}
static const struct iio_trigger_ops mxc4005_trigger_ops = {
.set_trigger_state = mxc4005_set_trigger_state,
- .try_reenable = mxc4005_trigger_try_reen,
+ .reenable = mxc4005_trigger_reen,
};
static int mxc4005_chip_init(struct mxc4005_data *data)
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 91ae90514aff..15587a1bc80d 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -295,7 +295,7 @@ config ASPEED_ADC
config AT91_ADC
tristate "Atmel AT91 ADC"
depends on ARCH_AT91 || COMPILE_TEST
- depends on INPUT && SYSFS
+ depends on INPUT && SYSFS && OF
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
@@ -703,6 +703,17 @@ config MCP3911
This driver can also be built as a module. If so, the module will be
called mcp3911.
+config MEDIATEK_MT6360_ADC
+ tristate "Mediatek MT6360 ADC driver"
+ depends on MFD_MT6360
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say Y here to enable MT6360 ADC support.
+ Integrated for System Monitoring includes
+ is used in smartphones and tablets and supports a 11 channel
+ general purpose ADC.
+
config MEDIATEK_MT6577_AUXADC
tristate "MediaTek AUXADC driver"
depends on ARCH_MEDIATEK || COMPILE_TEST
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 90f94ada7b30..5fca90ada0ec 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -65,6 +65,7 @@ obj-$(CONFIG_MAX9611) += max9611.o
obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
obj-$(CONFIG_MCP3911) += mcp3911.o
+obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o
obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
diff --git a/drivers/iio/adc/ad7292.c b/drivers/iio/adc/ad7292.c
index ab204e9199e9..70e33dd1c9f7 100644
--- a/drivers/iio/adc/ad7292.c
+++ b/drivers/iio/adc/ad7292.c
@@ -276,8 +276,6 @@ static int ad7292_probe(struct spi_device *spi)
return -EINVAL;
}
- spi_set_drvdata(spi, indio_dev);
-
st->reg = devm_regulator_get_optional(&spi->dev, "vref");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);
diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c
index 48d43cb0f932..689ecd5dd563 100644
--- a/drivers/iio/adc/ad7298.c
+++ b/drivers/iio/adc/ad7298.c
@@ -23,8 +23,6 @@
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
-#include <linux/platform_data/ad7298.h>
-
#define AD7298_WRITE BIT(15) /* write to the control register */
#define AD7298_REPEAT BIT(14) /* repeated conversion enable */
#define AD7298_CH(x) BIT(13 - (x)) /* channel select */
@@ -216,7 +214,7 @@ static int ad7298_get_ref_voltage(struct ad7298_state *st)
{
int vref;
- if (st->ext_ref) {
+ if (st->reg) {
vref = regulator_get_voltage(st->reg);
if (vref < 0)
return vref;
@@ -281,9 +279,15 @@ static const struct iio_info ad7298_info = {
.update_scan_mode = ad7298_update_scan_mode,
};
+static void ad7298_reg_disable(void *data)
+{
+ struct regulator *reg = data;
+
+ regulator_disable(reg);
+}
+
static int ad7298_probe(struct spi_device *spi)
{
- struct ad7298_platform_data *pdata = spi->dev.platform_data;
struct ad7298_state *st;
struct iio_dev *indio_dev;
int ret;
@@ -294,20 +298,27 @@ static int ad7298_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
- if (pdata && pdata->ext_ref)
+ st->reg = devm_regulator_get_optional(&spi->dev, "vref");
+ if (!IS_ERR(st->reg)) {
st->ext_ref = AD7298_EXTREF;
+ } else {
+ ret = PTR_ERR(st->reg);
+ if (ret != -ENODEV)
+ return ret;
- if (st->ext_ref) {
- st->reg = devm_regulator_get(&spi->dev, "vref");
- if (IS_ERR(st->reg))
- return PTR_ERR(st->reg);
+ st->reg = NULL;
+ }
+ if (st->reg) {
ret = regulator_enable(st->reg);
if (ret)
return ret;
- }
- spi_set_drvdata(spi, indio_dev);
+ ret = devm_add_action_or_reset(&spi->dev, ad7298_reg_disable,
+ st->reg);
+ if (ret)
+ return ret;
+ }
st->spi = spi;
@@ -333,37 +344,12 @@ static int ad7298_probe(struct spi_device *spi)
spi_message_add_tail(&st->scan_single_xfer[1], &st->scan_single_msg);
spi_message_add_tail(&st->scan_single_xfer[2], &st->scan_single_msg);
- ret = iio_triggered_buffer_setup(indio_dev, NULL,
+ ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL,
&ad7298_trigger_handler, NULL);
if (ret)
- goto error_disable_reg;
-
- ret = iio_device_register(indio_dev);
- if (ret)
- goto error_cleanup_ring;
-
- return 0;
-
-error_cleanup_ring:
- iio_triggered_buffer_cleanup(indio_dev);
-error_disable_reg:
- if (st->ext_ref)
- regulator_disable(st->reg);
-
- return ret;
-}
-
-static int ad7298_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct ad7298_state *st = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- iio_triggered_buffer_cleanup(indio_dev);
- if (st->ext_ref)
- regulator_disable(st->reg);
+ return ret;
- return 0;
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id ad7298_id[] = {
@@ -377,7 +363,6 @@ static struct spi_driver ad7298_driver = {
.name = "ad7298",
},
.probe = ad7298_probe,
- .remove = ad7298_remove,
.id_table = ad7298_id,
};
module_spi_driver(ad7298_driver);
diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
index 0e93b0766eb4..5c0cbee03230 100644
--- a/drivers/iio/adc/ad7768-1.c
+++ b/drivers/iio/adc/ad7768-1.c
@@ -161,6 +161,7 @@ struct ad7768_state {
struct completion completion;
struct iio_trigger *trig;
struct gpio_desc *gpio_sync_in;
+ const char *labels[ARRAY_SIZE(ad7768_channels)];
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
@@ -407,6 +408,14 @@ static int ad7768_write_raw(struct iio_dev *indio_dev,
}
}
+static int ad7768_read_label(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, char *label)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+
+ return sprintf(label, "%s\n", st->labels[chan->channel]);
+}
+
static struct attribute *ad7768_attributes[] = {
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
NULL
@@ -420,6 +429,7 @@ static const struct iio_info ad7768_info = {
.attrs = &ad7768_group,
.read_raw = &ad7768_read_raw,
.write_raw = &ad7768_write_raw,
+ .read_label = ad7768_read_label,
.debugfs_reg_access = &ad7768_reg_access,
};
@@ -532,6 +542,33 @@ static void ad7768_clk_disable(void *data)
clk_disable_unprepare(st->mclk);
}
+static int ad7768_set_channel_label(struct iio_dev *indio_dev,
+ int num_channels)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+ struct device *device = indio_dev->dev.parent;
+ struct fwnode_handle *fwnode;
+ struct fwnode_handle *child;
+ const char *label;
+ int crt_ch = 0;
+
+ fwnode = dev_fwnode(device);
+ fwnode_for_each_child_node(fwnode, child) {
+ if (fwnode_property_read_u32(child, "reg", &crt_ch))
+ continue;
+
+ if (crt_ch >= num_channels)
+ continue;
+
+ if (fwnode_property_read_string(child, "label", &label))
+ continue;
+
+ st->labels[crt_ch] = label;
+ }
+
+ return 0;
+}
+
static int ad7768_probe(struct spi_device *spi)
{
struct ad7768_state *st;
@@ -604,6 +641,10 @@ static int ad7768_probe(struct spi_device *spi)
init_completion(&st->completion);
+ ret = ad7768_set_channel_label(indio_dev, ARRAY_SIZE(ad7768_channels));
+ if (ret)
+ return ret;
+
ret = devm_request_irq(&spi->dev, spi->irq,
&ad7768_interrupt,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c
index 037bcb47693c..4f6f0e0e03ee 100644
--- a/drivers/iio/adc/ad7887.c
+++ b/drivers/iio/adc/ad7887.c
@@ -232,6 +232,13 @@ static const struct iio_info ad7887_info = {
.read_raw = &ad7887_read_raw,
};
+static void ad7887_reg_disable(void *data)
+{
+ struct regulator *reg = data;
+
+ regulator_disable(reg);
+}
+
static int ad7887_probe(struct spi_device *spi)
{
struct ad7887_platform_data *pdata = spi->dev.platform_data;
@@ -246,14 +253,22 @@ static int ad7887_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
- if (!pdata || !pdata->use_onchip_ref) {
- st->reg = devm_regulator_get(&spi->dev, "vref");
- if (IS_ERR(st->reg))
+ st->reg = devm_regulator_get_optional(&spi->dev, "vref");
+ if (IS_ERR(st->reg)) {
+ if (PTR_ERR(st->reg) != -ENODEV)
return PTR_ERR(st->reg);
+ st->reg = NULL;
+ }
+
+ if (st->reg) {
ret = regulator_enable(st->reg);
if (ret)
return ret;
+
+ ret = devm_add_action_or_reset(&spi->dev, ad7887_reg_disable, st->reg);
+ if (ret)
+ return ret;
}
st->chip_info =
@@ -269,7 +284,7 @@ static int ad7887_probe(struct spi_device *spi)
/* Setup default message */
mode = AD7887_PM_MODE4;
- if (!pdata || !pdata->use_onchip_ref)
+ if (!st->reg)
mode |= AD7887_REF_DIS;
if (pdata && pdata->en_dual)
mode |= AD7887_DUAL;
@@ -312,36 +327,13 @@ static int ad7887_probe(struct spi_device *spi)
indio_dev->num_channels = st->chip_info->num_channels;
}
- ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+ ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
+ &iio_pollfunc_store_time,
&ad7887_trigger_handler, &ad7887_ring_setup_ops);
if (ret)
- goto error_disable_reg;
-
- ret = iio_device_register(indio_dev);
- if (ret)
- goto error_unregister_ring;
-
- return 0;
-error_unregister_ring:
- iio_triggered_buffer_cleanup(indio_dev);
-error_disable_reg:
- if (st->reg)
- regulator_disable(st->reg);
-
- return ret;
-}
-
-static int ad7887_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct ad7887_state *st = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- iio_triggered_buffer_cleanup(indio_dev);
- if (st->reg)
- regulator_disable(st->reg);
+ return ret;
- return 0;
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id ad7887_id[] = {
@@ -355,7 +347,6 @@ static struct spi_driver ad7887_driver = {
.name = "ad7887",
},
.probe = ad7887_probe,
- .remove = ad7887_remove,
.id_table = ad7887_id,
};
module_spi_driver(ad7887_driver);
diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c
index 86039e9ecaca..3a6f239d4acc 100644
--- a/drivers/iio/adc/ad_sigma_delta.c
+++ b/drivers/iio/adc/ad_sigma_delta.c
@@ -57,7 +57,7 @@ EXPORT_SYMBOL_GPL(ad_sd_set_comm);
int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
unsigned int size, unsigned int val)
{
- uint8_t *data = sigma_delta->data;
+ uint8_t *data = sigma_delta->tx_buf;
struct spi_transfer t = {
.tx_buf = data,
.len = size + 1,
@@ -99,7 +99,7 @@ EXPORT_SYMBOL_GPL(ad_sd_write_reg);
static int ad_sd_read_reg_raw(struct ad_sigma_delta *sigma_delta,
unsigned int reg, unsigned int size, uint8_t *val)
{
- uint8_t *data = sigma_delta->data;
+ uint8_t *data = sigma_delta->tx_buf;
int ret;
struct spi_transfer t[] = {
{
@@ -146,22 +146,22 @@ int ad_sd_read_reg(struct ad_sigma_delta *sigma_delta,
{
int ret;
- ret = ad_sd_read_reg_raw(sigma_delta, reg, size, sigma_delta->data);
+ ret = ad_sd_read_reg_raw(sigma_delta, reg, size, sigma_delta->rx_buf);
if (ret < 0)
goto out;
switch (size) {
case 4:
- *val = get_unaligned_be32(sigma_delta->data);
+ *val = get_unaligned_be32(sigma_delta->rx_buf);
break;
case 3:
- *val = get_unaligned_be24(&sigma_delta->data[0]);
+ *val = get_unaligned_be24(sigma_delta->rx_buf);
break;
case 2:
- *val = get_unaligned_be16(sigma_delta->data);
+ *val = get_unaligned_be16(sigma_delta->rx_buf);
break;
case 1:
- *val = sigma_delta->data[0];
+ *val = sigma_delta->rx_buf[0];
break;
default:
ret = -EINVAL;
@@ -395,11 +395,9 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
+ uint8_t *data = sigma_delta->rx_buf;
unsigned int reg_size;
unsigned int data_reg;
- uint8_t data[16];
-
- memset(data, 0x00, 16);
reg_size = indio_dev->channels[0].scan_type.realbits +
indio_dev->channels[0].scan_type.shift;
diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
index b917a4714a9c..a7826f097b95 100644
--- a/drivers/iio/adc/at91-sama5d2_adc.c
+++ b/drivers/iio/adc/at91-sama5d2_adc.c
@@ -742,26 +742,24 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
return 0;
}
-static int at91_adc_reenable_trigger(struct iio_trigger *trig)
+static void at91_adc_reenable_trigger(struct iio_trigger *trig)
{
struct iio_dev *indio = iio_trigger_get_drvdata(trig);
struct at91_adc_state *st = iio_priv(indio);
/* if we are using DMA, we must not reenable irq after each trigger */
if (st->dma_st.dma_chan)
- return 0;
+ return;
enable_irq(st->irq);
/* Needed to ACK the DRDY interruption */
at91_adc_readl(st, AT91_SAMA5D2_LCDR);
-
- return 0;
}
static const struct iio_trigger_ops at91_adc_trigger_ops = {
.set_trigger_state = &at91_adc_configure_trigger,
- .try_reenable = &at91_adc_reenable_trigger,
+ .reenable = &at91_adc_reenable_trigger,
.validate_device = iio_trigger_validate_own_device,
};
@@ -1013,21 +1011,6 @@ static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *indio,
return trig;
}
-
-static int at91_adc_trigger_init(struct iio_dev *indio)
-{
- struct at91_adc_state *st = iio_priv(indio);
-
- st->trig = at91_adc_allocate_trigger(indio, st->selected_trig->name);
- if (IS_ERR(st->trig)) {
- dev_err(&indio->dev,
- "could not allocate trigger\n");
- return PTR_ERR(st->trig);
- }
-
- return 0;
-}
-
static void at91_adc_trigger_handler_nodma(struct iio_dev *indio_dev,
struct iio_poll_func *pf)
{
@@ -1155,13 +1138,6 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
return IRQ_HANDLED;
}
-static int at91_adc_buffer_init(struct iio_dev *indio)
-{
- return devm_iio_triggered_buffer_setup(&indio->dev, indio,
- &iio_pollfunc_store_time,
- &at91_adc_trigger_handler, &at91_buffer_setup_ops);
-}
-
static unsigned at91_adc_startup_time(unsigned startup_time_min,
unsigned adc_clk_khz)
{
@@ -1472,7 +1448,7 @@ static int at91_adc_write_raw(struct iio_dev *indio_dev,
return 0;
default:
return -EINVAL;
- };
+ }
}
static void at91_adc_dma_init(struct platform_device *pdev)
@@ -1691,6 +1667,44 @@ static const struct iio_info at91_adc_info = {
.hwfifo_set_watermark = &at91_adc_set_watermark,
};
+static int at91_adc_buffer_and_trigger_init(struct device *dev,
+ struct iio_dev *indio)
+{
+ struct at91_adc_state *st = iio_priv(indio);
+ const struct attribute **fifo_attrs;
+ int ret;
+
+ if (st->selected_trig->hw_trig)
+ fifo_attrs = at91_adc_fifo_attributes;
+ else
+ fifo_attrs = NULL;
+
+ ret = devm_iio_triggered_buffer_setup_ext(&indio->dev, indio,
+ &iio_pollfunc_store_time,
+ &at91_adc_trigger_handler, &at91_buffer_setup_ops, fifo_attrs);
+ if (ret < 0) {
+ dev_err(dev, "couldn't initialize the buffer.\n");
+ return ret;
+ }
+
+ if (!st->selected_trig->hw_trig)
+ return 0;
+
+ st->trig = at91_adc_allocate_trigger(indio, st->selected_trig->name);
+ if (IS_ERR(st->trig)) {
+ dev_err(dev, "could not allocate trigger\n");
+ return PTR_ERR(st->trig);
+ }
+
+ /*
+ * Initially the iio buffer has a length of 2 and
+ * a watermark of 1
+ */
+ st->dma_st.watermark = 1;
+
+ return 0;
+}
+
static int at91_adc_probe(struct platform_device *pdev)
{
struct iio_dev *indio_dev;
@@ -1826,27 +1840,9 @@ static int at91_adc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, indio_dev);
- ret = at91_adc_buffer_init(indio_dev);
- if (ret < 0) {
- dev_err(&pdev->dev, "couldn't initialize the buffer.\n");
+ ret = at91_adc_buffer_and_trigger_init(&pdev->dev, indio_dev);
+ if (ret < 0)
goto per_clk_disable_unprepare;
- }
-
- if (st->selected_trig->hw_trig) {
- ret = at91_adc_trigger_init(indio_dev);
- if (ret < 0) {
- dev_err(&pdev->dev, "couldn't setup the triggers.\n");
- goto per_clk_disable_unprepare;
- }
- /*
- * Initially the iio buffer has a length of 2 and
- * a watermark of 1
- */
- st->dma_st.watermark = 1;
-
- iio_buffer_set_attrs(indio_dev->buffer,
- at91_adc_fifo_attributes);
- }
if (dma_coerce_mask_and_coherent(&indio_dev->dev, DMA_BIT_MASK(32)))
dev_info(&pdev->dev, "cannot set DMA mask to 32-bit\n");
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 9b2c548fae95..70750abb5dea 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -22,8 +22,6 @@
#include <linux/slab.h>
#include <linux/wait.h>
-#include <linux/platform_data/at91_adc.h>
-
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger.h>
@@ -153,6 +151,25 @@
#define TOUCH_SHTIM 0xa
#define TOUCH_SCTIM_US 10 /* 10us for the Touchscreen Switches Closure Time */
+enum atmel_adc_ts_type {
+ ATMEL_ADC_TOUCHSCREEN_NONE = 0,
+ ATMEL_ADC_TOUCHSCREEN_4WIRE = 4,
+ ATMEL_ADC_TOUCHSCREEN_5WIRE = 5,
+};
+
+/**
+ * struct at91_adc_trigger - description of triggers
+ * @name: name of the trigger advertised to the user
+ * @value: value to set in the ADC's trigger setup register
+ * to enable the trigger
+ * @is_external: Does the trigger rely on an external pin?
+ */
+struct at91_adc_trigger {
+ const char *name;
+ u8 value;
+ bool is_external;
+};
+
/**
* struct at91_adc_reg_desc - Various informations relative to registers
* @channel_base: Base offset for the channel data registers
@@ -187,6 +204,11 @@ struct at91_adc_caps {
u32 (*calc_startup_ticks)(u32 startup_time, u32 adc_clk_khz);
u8 num_channels;
+
+ u8 low_res_bits;
+ u8 high_res_bits;
+ u32 trigger_number;
+ const struct at91_adc_trigger *triggers;
struct at91_adc_reg_desc registers;
};
@@ -202,19 +224,16 @@ struct at91_adc_state {
struct mutex lock;
u8 num_channels;
void __iomem *reg_base;
- struct at91_adc_reg_desc *registers;
+ const struct at91_adc_reg_desc *registers;
u32 startup_time;
u8 sample_hold_time;
bool sleep_mode;
struct iio_trigger **trig;
- struct at91_adc_trigger *trigger_list;
- u32 trigger_number;
bool use_external;
u32 vref_mv;
u32 res; /* resolution used for convertions */
- bool low_res; /* the resolution corresponds to the lowest one */
wait_queue_head_t wq_data_avail;
- struct at91_adc_caps *caps;
+ const struct at91_adc_caps *caps;
/*
* Following ADC channels are shared by touchscreen:
@@ -518,13 +537,13 @@ static int at91_adc_channel_init(struct iio_dev *idev)
}
static int at91_adc_get_trigger_value_by_name(struct iio_dev *idev,
- struct at91_adc_trigger *triggers,
+ const struct at91_adc_trigger *triggers,
const char *trigger_name)
{
struct at91_adc_state *st = iio_priv(idev);
int i;
- for (i = 0; i < st->trigger_number; i++) {
+ for (i = 0; i < st->caps->trigger_number; i++) {
char *name = kasprintf(GFP_KERNEL,
"%s-dev%d-%s",
idev->name,
@@ -550,13 +569,13 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
{
struct iio_dev *idev = iio_trigger_get_drvdata(trig);
struct at91_adc_state *st = iio_priv(idev);
- struct at91_adc_reg_desc *reg = st->registers;
+ const struct at91_adc_reg_desc *reg = st->registers;
u32 status = at91_adc_readl(st, reg->trigger_register);
int value;
u8 bit;
value = at91_adc_get_trigger_value_by_name(idev,
- st->trigger_list,
+ st->caps->triggers,
idev->trig->name);
if (value < 0)
return value;
@@ -601,7 +620,7 @@ static const struct iio_trigger_ops at91_adc_trigger_ops = {
};
static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *idev,
- struct at91_adc_trigger *trigger)
+ const struct at91_adc_trigger *trigger)
{
struct iio_trigger *trig;
int ret;
@@ -628,7 +647,7 @@ static int at91_adc_trigger_init(struct iio_dev *idev)
int i, ret;
st->trig = devm_kcalloc(&idev->dev,
- st->trigger_number, sizeof(*st->trig),
+ st->caps->trigger_number, sizeof(*st->trig),
GFP_KERNEL);
if (st->trig == NULL) {
@@ -636,12 +655,12 @@ static int at91_adc_trigger_init(struct iio_dev *idev)
goto error_ret;
}
- for (i = 0; i < st->trigger_number; i++) {
- if (st->trigger_list[i].is_external && !(st->use_external))
+ for (i = 0; i < st->caps->trigger_number; i++) {
+ if (st->caps->triggers[i].is_external && !(st->use_external))
continue;
st->trig[i] = at91_adc_allocate_trigger(idev,
- st->trigger_list + i);
+ st->caps->triggers + i);
if (st->trig[i] == NULL) {
dev_err(&idev->dev,
"Could not allocate trigger %d\n", i);
@@ -666,7 +685,7 @@ static void at91_adc_trigger_remove(struct iio_dev *idev)
struct at91_adc_state *st = iio_priv(idev);
int i;
- for (i = 0; i < st->trigger_number; i++) {
+ for (i = 0; i < st->caps->trigger_number; i++) {
iio_trigger_unregister(st->trig[i]);
iio_trigger_free(st->trig[i]);
}
@@ -737,58 +756,6 @@ static int at91_adc_read_raw(struct iio_dev *idev,
return -EINVAL;
}
-static int at91_adc_of_get_resolution(struct iio_dev *idev,
- struct platform_device *pdev)
-{
- struct at91_adc_state *st = iio_priv(idev);
- struct device_node *np = pdev->dev.of_node;
- int count, i, ret = 0;
- char *res_name, *s;
- u32 *resolutions;
-
- count = of_property_count_strings(np, "atmel,adc-res-names");
- if (count < 2) {
- dev_err(&idev->dev, "You must specified at least two resolution names for "
- "adc-res-names property in the DT\n");
- return count;
- }
-
- resolutions = kmalloc_array(count, sizeof(*resolutions), GFP_KERNEL);
- if (!resolutions)
- return -ENOMEM;
-
- if (of_property_read_u32_array(np, "atmel,adc-res", resolutions, count)) {
- dev_err(&idev->dev, "Missing adc-res property in the DT.\n");
- ret = -ENODEV;
- goto ret;
- }
-
- if (of_property_read_string(np, "atmel,adc-use-res", (const char **)&res_name))
- res_name = "highres";
-
- for (i = 0; i < count; i++) {
- if (of_property_read_string_index(np, "atmel,adc-res-names", i, (const char **)&s))
- continue;
-
- if (strcmp(res_name, s))
- continue;
-
- st->res = resolutions[i];
- if (!strcmp(res_name, "lowres"))
- st->low_res = true;
- else
- st->low_res = false;
-
- dev_info(&idev->dev, "Resolution used: %u bits\n", st->res);
- goto ret;
- }
-
- dev_err(&idev->dev, "There is no resolution for %s\n", res_name);
-
-ret:
- kfree(resolutions);
- return ret;
-}
static u32 calc_startup_ticks_9260(u32 startup_time, u32 adc_clk_khz)
{
@@ -829,8 +796,6 @@ static u32 calc_startup_ticks_9x5(u32 startup_time, u32 adc_clk_khz)
return ticks;
}
-static const struct of_device_id at91_adc_dt_ids[];
-
static int at91_adc_probe_dt_ts(struct device_node *node,
struct at91_adc_state *st, struct device *dev)
{
@@ -866,124 +831,6 @@ static int at91_adc_probe_dt_ts(struct device_node *node,
}
}
-static int at91_adc_probe_dt(struct iio_dev *idev,
- struct platform_device *pdev)
-{
- struct at91_adc_state *st = iio_priv(idev);
- struct device_node *node = pdev->dev.of_node;
- struct device_node *trig_node;
- int i = 0, ret;
- u32 prop;
-
- if (!node)
- return -EINVAL;
-
- st->caps = (struct at91_adc_caps *)
- of_match_device(at91_adc_dt_ids, &pdev->dev)->data;
-
- 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");
- ret = -EINVAL;
- goto error_ret;
- }
- 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");
- ret = -EINVAL;
- goto error_ret;
- }
- 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");
- ret = -EINVAL;
- goto error_ret;
- }
- st->vref_mv = prop;
-
- ret = at91_adc_of_get_resolution(idev, pdev);
- if (ret)
- goto error_ret;
-
- st->registers = &st->caps->registers;
- st->num_channels = st->caps->num_channels;
- st->trigger_number = of_get_child_count(node);
- st->trigger_list = devm_kcalloc(&idev->dev,
- st->trigger_number,
- sizeof(struct at91_adc_trigger),
- GFP_KERNEL);
- if (!st->trigger_list) {
- dev_err(&idev->dev, "Could not allocate trigger list memory.\n");
- ret = -ENOMEM;
- goto error_ret;
- }
-
- for_each_child_of_node(node, trig_node) {
- struct at91_adc_trigger *trig = st->trigger_list + i;
- const char *name;
-
- if (of_property_read_string(trig_node, "trigger-name", &name)) {
- dev_err(&idev->dev, "Missing trigger-name property in the DT.\n");
- ret = -EINVAL;
- goto error_ret;
- }
- trig->name = name;
-
- if (of_property_read_u32(trig_node, "trigger-value", &prop)) {
- dev_err(&idev->dev, "Missing trigger-value property in the DT.\n");
- ret = -EINVAL;
- goto error_ret;
- }
- trig->value = prop;
- trig->is_external = of_property_read_bool(trig_node, "trigger-external");
- i++;
- }
-
- /* Check if touchscreen is supported. */
- if (st->caps->has_ts)
- return at91_adc_probe_dt_ts(node, st, &idev->dev);
- else
- dev_info(&idev->dev, "not support touchscreen in the adc compatible string.\n");
-
- return 0;
-
-error_ret:
- return ret;
-}
-
-static int at91_adc_probe_pdata(struct at91_adc_state *st,
- struct platform_device *pdev)
-{
- struct at91_adc_data *pdata = pdev->dev.platform_data;
-
- if (!pdata)
- return -EINVAL;
-
- st->caps = (struct at91_adc_caps *)
- platform_get_device_id(pdev)->driver_data;
-
- st->use_external = pdata->use_external_triggers;
- st->vref_mv = pdata->vref;
- st->channels_mask = pdata->channels_used;
- st->num_channels = st->caps->num_channels;
- st->startup_time = pdata->startup_time;
- st->trigger_number = pdata->trigger_number;
- st->trigger_list = pdata->trigger_list;
- st->registers = &st->caps->registers;
- st->touchscreen_type = pdata->touchscreen_type;
-
- return 0;
-}
-
static const struct iio_info at91_adc_info = {
.read_raw = &at91_adc_read_raw,
};
@@ -1149,10 +996,12 @@ static void at91_ts_unregister(struct at91_adc_state *st)
static int at91_adc_probe(struct platform_device *pdev)
{
unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
+ struct device_node *node = pdev->dev.of_node;
int ret;
struct iio_dev *idev;
struct at91_adc_state *st;
- u32 reg;
+ u32 reg, prop;
+ char *s;
idev = devm_iio_device_alloc(&pdev->dev, sizeof(struct at91_adc_state));
if (!idev)
@@ -1160,15 +1009,51 @@ static int at91_adc_probe(struct platform_device *pdev)
st = iio_priv(idev);
- if (pdev->dev.of_node)
- ret = at91_adc_probe_dt(idev, pdev);
- else
- ret = at91_adc_probe_pdata(st, pdev);
+ st->caps = of_device_get_match_data(&pdev->dev);
- if (ret) {
- dev_err(&pdev->dev, "No platform data available.\n");
+ 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;
+ }
+ 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;
+ }
+ 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;
}
+ st->vref_mv = prop;
+
+ st->res = st->caps->high_res_bits;
+ if (st->caps->low_res_bits &&
+ !of_property_read_string(node, "atmel,adc-use-res", (const char **)&s)
+ && !strcmp(s, "lowres"))
+ st->res = st->caps->low_res_bits;
+
+ dev_info(&idev->dev, "Resolution used: %u bits\n", st->res);
+
+ st->registers = &st->caps->registers;
+ st->num_channels = st->caps->num_channels;
+
+ /* Check if touchscreen is supported. */
+ if (st->caps->has_ts) {
+ ret = at91_adc_probe_dt_ts(node, st, &idev->dev);
+ if (ret)
+ return ret;
+ }
platform_set_drvdata(pdev, idev);
@@ -1264,7 +1149,7 @@ static int at91_adc_probe(struct platform_device *pdev)
reg = AT91_ADC_PRESCAL_(prsc) & st->registers->mr_prescal_mask;
reg |= AT91_ADC_STARTUP_(ticks) & st->registers->mr_startup_mask;
- if (st->low_res)
+ if (st->res == st->caps->low_res_bits)
reg |= AT91_ADC_LOWRES;
if (st->sleep_mode)
reg |= AT91_ADC_SLEEP;
@@ -1376,9 +1261,18 @@ static int at91_adc_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(at91_adc_pm_ops, at91_adc_suspend, at91_adc_resume);
+static const struct at91_adc_trigger at91sam9260_triggers[] = {
+ { .name = "timer-counter-0", .value = 0x1 },
+ { .name = "timer-counter-1", .value = 0x3 },
+ { .name = "timer-counter-2", .value = 0x5 },
+ { .name = "external", .value = 0xd, .is_external = true },
+};
+
static struct at91_adc_caps at91sam9260_caps = {
.calc_startup_ticks = calc_startup_ticks_9260,
.num_channels = 4,
+ .low_res_bits = 8,
+ .high_res_bits = 10,
.registers = {
.channel_base = AT91_ADC_CHR(0),
.drdy_mask = AT91_ADC_DRDY,
@@ -1387,12 +1281,23 @@ static struct at91_adc_caps at91sam9260_caps = {
.mr_prescal_mask = AT91_ADC_PRESCAL_9260,
.mr_startup_mask = AT91_ADC_STARTUP_9260,
},
+ .triggers = at91sam9260_triggers,
+ .trigger_number = ARRAY_SIZE(at91sam9260_triggers),
+};
+
+static const struct at91_adc_trigger at91sam9x5_triggers[] = {
+ { .name = "external-rising", .value = 0x1, .is_external = true },
+ { .name = "external-falling", .value = 0x2, .is_external = true },
+ { .name = "external-any", .value = 0x3, .is_external = true },
+ { .name = "continuous", .value = 0x6 },
};
static struct at91_adc_caps at91sam9rl_caps = {
.has_ts = true,
.calc_startup_ticks = calc_startup_ticks_9260, /* same as 9260 */
.num_channels = 6,
+ .low_res_bits = 8,
+ .high_res_bits = 10,
.registers = {
.channel_base = AT91_ADC_CHR(0),
.drdy_mask = AT91_ADC_DRDY,
@@ -1401,12 +1306,16 @@ static struct at91_adc_caps at91sam9rl_caps = {
.mr_prescal_mask = AT91_ADC_PRESCAL_9260,
.mr_startup_mask = AT91_ADC_STARTUP_9G45,
},
+ .triggers = at91sam9x5_triggers,
+ .trigger_number = ARRAY_SIZE(at91sam9x5_triggers),
};
static struct at91_adc_caps at91sam9g45_caps = {
.has_ts = true,
.calc_startup_ticks = calc_startup_ticks_9260, /* same as 9260 */
.num_channels = 8,
+ .low_res_bits = 8,
+ .high_res_bits = 10,
.registers = {
.channel_base = AT91_ADC_CHR(0),
.drdy_mask = AT91_ADC_DRDY,
@@ -1415,6 +1324,8 @@ static struct at91_adc_caps at91sam9g45_caps = {
.mr_prescal_mask = AT91_ADC_PRESCAL_9G45,
.mr_startup_mask = AT91_ADC_STARTUP_9G45,
},
+ .triggers = at91sam9x5_triggers,
+ .trigger_number = ARRAY_SIZE(at91sam9x5_triggers),
};
static struct at91_adc_caps at91sam9x5_caps = {
@@ -1424,6 +1335,8 @@ static struct at91_adc_caps at91sam9x5_caps = {
.ts_pen_detect_sensitivity = 2,
.calc_startup_ticks = calc_startup_ticks_9x5,
.num_channels = 12,
+ .low_res_bits = 8,
+ .high_res_bits = 10,
.registers = {
.channel_base = AT91_ADC_CDR0_9X5,
.drdy_mask = AT91_ADC_SR_DRDY_9X5,
@@ -1433,6 +1346,29 @@ static struct at91_adc_caps at91sam9x5_caps = {
.mr_prescal_mask = AT91_ADC_PRESCAL_9G45,
.mr_startup_mask = AT91_ADC_STARTUP_9X5,
},
+ .triggers = at91sam9x5_triggers,
+ .trigger_number = ARRAY_SIZE(at91sam9x5_triggers),
+};
+
+static struct at91_adc_caps sama5d3_caps = {
+ .has_ts = true,
+ .has_tsmr = true,
+ .ts_filter_average = 3,
+ .ts_pen_detect_sensitivity = 2,
+ .calc_startup_ticks = calc_startup_ticks_9x5,
+ .num_channels = 12,
+ .low_res_bits = 0,
+ .high_res_bits = 12,
+ .registers = {
+ .channel_base = AT91_ADC_CDR0_9X5,
+ .drdy_mask = AT91_ADC_SR_DRDY_9X5,
+ .status_register = AT91_ADC_SR_9X5,
+ .trigger_register = AT91_ADC_TRGR_9X5,
+ .mr_prescal_mask = AT91_ADC_PRESCAL_9G45,
+ .mr_startup_mask = AT91_ADC_STARTUP_9X5,
+ },
+ .triggers = at91sam9x5_triggers,
+ .trigger_number = ARRAY_SIZE(at91sam9x5_triggers),
};
static const struct of_device_id at91_adc_dt_ids[] = {
@@ -1440,36 +1376,17 @@ static const struct of_device_id at91_adc_dt_ids[] = {
{ .compatible = "atmel,at91sam9rl-adc", .data = &at91sam9rl_caps },
{ .compatible = "atmel,at91sam9g45-adc", .data = &at91sam9g45_caps },
{ .compatible = "atmel,at91sam9x5-adc", .data = &at91sam9x5_caps },
+ { .compatible = "atmel,sama5d3-adc", .data = &sama5d3_caps },
{},
};
MODULE_DEVICE_TABLE(of, at91_adc_dt_ids);
-static const struct platform_device_id at91_adc_ids[] = {
- {
- .name = "at91sam9260-adc",
- .driver_data = (unsigned long)&at91sam9260_caps,
- }, {
- .name = "at91sam9rl-adc",
- .driver_data = (unsigned long)&at91sam9rl_caps,
- }, {
- .name = "at91sam9g45-adc",
- .driver_data = (unsigned long)&at91sam9g45_caps,
- }, {
- .name = "at91sam9x5-adc",
- .driver_data = (unsigned long)&at91sam9x5_caps,
- }, {
- /* terminator */
- }
-};
-MODULE_DEVICE_TABLE(platform, at91_adc_ids);
-
static struct platform_driver at91_adc_driver = {
.probe = at91_adc_probe,
.remove = at91_adc_remove,
- .id_table = at91_adc_ids,
.driver = {
.name = DRIVER_NAME,
- .of_match_table = of_match_ptr(at91_adc_dt_ids),
+ .of_match_table = at91_adc_dt_ids,
.pm = &at91_adc_pm_ops,
},
};
diff --git a/drivers/iio/adc/cpcap-adc.c b/drivers/iio/adc/cpcap-adc.c
index 64c3cc382311..f19c9aa93f17 100644
--- a/drivers/iio/adc/cpcap-adc.c
+++ b/drivers/iio/adc/cpcap-adc.c
@@ -557,6 +557,7 @@ static void cpcap_adc_setup_bank(struct cpcap_adc *ddata,
break;
case CPCAP_ADC_BATTP_PI16 ... CPCAP_ADC_BATTI_PI17:
value1 |= CPCAP_BIT_RAND1;
+ break;
default:
break;
}
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index 99f4404e9fd1..784c10deeb1a 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -7,6 +7,7 @@
* Copyright (C) 2013 Naveen Krishna Chatradhi <ch.naveen@samsung.com>
*/
+#include <linux/compiler.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
@@ -135,6 +136,8 @@ struct exynos_adc {
u32 value;
unsigned int version;
+ bool ts_enabled;
+
bool read_ts;
u32 ts_x;
u32 ts_y;
@@ -651,7 +654,7 @@ static irqreturn_t exynos_ts_isr(int irq, void *dev_id)
bool pressed;
int ret;
- while (info->input->users) {
+ while (READ_ONCE(info->ts_enabled)) {
ret = exynos_read_s3c64xx_ts(dev, &x, &y);
if (ret == -ETIMEDOUT)
break;
@@ -731,6 +734,7 @@ static int exynos_adc_ts_open(struct input_dev *dev)
{
struct exynos_adc *info = input_get_drvdata(dev);
+ WRITE_ONCE(info->ts_enabled, true);
enable_irq(info->tsirq);
return 0;
@@ -740,6 +744,7 @@ static void exynos_adc_ts_close(struct input_dev *dev)
{
struct exynos_adc *info = input_get_drvdata(dev);
+ WRITE_ONCE(info->ts_enabled, false);
disable_irq(info->tsirq);
}
diff --git a/drivers/iio/adc/ingenic-adc.c b/drivers/iio/adc/ingenic-adc.c
index 1aafbe2cfe67..34c03a264f74 100644
--- a/drivers/iio/adc/ingenic-adc.c
+++ b/drivers/iio/adc/ingenic-adc.c
@@ -562,7 +562,7 @@ static int ingenic_adc_read_avail(struct iio_dev *iio_dev,
return IIO_AVAIL_LIST;
default:
return -EINVAL;
- };
+ }
}
static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev,
diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
index e03988698755..66dc452d643a 100644
--- a/drivers/iio/adc/meson_saradc.c
+++ b/drivers/iio/adc/meson_saradc.c
@@ -593,13 +593,11 @@ static int meson_sar_adc_iio_info_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_RAW:
return meson_sar_adc_get_sample(indio_dev, chan, NO_AVERAGING,
ONE_SAMPLE, val);
- break;
case IIO_CHAN_INFO_AVERAGE_RAW:
return meson_sar_adc_get_sample(indio_dev, chan,
MEAN_AVERAGING, EIGHT_SAMPLES,
val);
- break;
case IIO_CHAN_INFO_SCALE:
if (chan->type == IIO_VOLTAGE) {
diff --git a/drivers/iio/adc/mt6360-adc.c b/drivers/iio/adc/mt6360-adc.c
new file mode 100644
index 000000000000..f57db3056fbe
--- /dev/null
+++ b/drivers/iio/adc/mt6360-adc.c
@@ -0,0 +1,372 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/ktime.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/unaligned/be_byteshift.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define MT6360_REG_PMUCHGCTRL3 0x313
+#define MT6360_REG_PMUADCCFG 0x356
+#define MT6360_REG_PMUADCIDLET 0x358
+#define MT6360_REG_PMUADCRPT1 0x35A
+
+/* PMUCHGCTRL3 0x313 */
+#define MT6360_AICR_MASK GENMASK(7, 2)
+#define MT6360_AICR_SHFT 2
+#define MT6360_AICR_400MA 0x6
+/* PMUADCCFG 0x356 */
+#define MT6360_ADCEN_MASK BIT(15)
+/* PMUADCRPT1 0x35A */
+#define MT6360_PREFERCH_MASK GENMASK(7, 4)
+#define MT6360_PREFERCH_SHFT 4
+#define MT6360_RPTCH_MASK GENMASK(3, 0)
+#define MT6360_NO_PREFER 15
+
+/* Time in ms */
+#define ADC_WAIT_TIME_MS 25
+#define ADC_CONV_TIMEOUT_MS 100
+#define ADC_LOOP_TIME_US 2000
+
+enum {
+ MT6360_CHAN_USBID = 0,
+ MT6360_CHAN_VBUSDIV5,
+ MT6360_CHAN_VBUSDIV2,
+ MT6360_CHAN_VSYS,
+ MT6360_CHAN_VBAT,
+ MT6360_CHAN_IBUS,
+ MT6360_CHAN_IBAT,
+ MT6360_CHAN_CHG_VDDP,
+ MT6360_CHAN_TEMP_JC,
+ MT6360_CHAN_VREF_TS,
+ MT6360_CHAN_TS,
+ MT6360_CHAN_MAX
+};
+
+struct mt6360_adc_data {
+ struct device *dev;
+ struct regmap *regmap;
+ /* Due to only one set of ADC control, this lock is used to prevent the race condition */
+ struct mutex adc_lock;
+ ktime_t last_off_timestamps[MT6360_CHAN_MAX];
+};
+
+static int mt6360_adc_read_channel(struct mt6360_adc_data *mad, int channel, int *val)
+{
+ __be16 adc_enable;
+ u8 rpt[3];
+ ktime_t predict_end_t, timeout;
+ unsigned int pre_wait_time;
+ int ret;
+
+ mutex_lock(&mad->adc_lock);
+
+ /* Select the preferred ADC channel */
+ ret = regmap_update_bits(mad->regmap, MT6360_REG_PMUADCRPT1, MT6360_PREFERCH_MASK,
+ channel << MT6360_PREFERCH_SHFT);
+ if (ret)
+ goto out_adc_lock;
+
+ adc_enable = cpu_to_be16(MT6360_ADCEN_MASK | BIT(channel));
+ ret = regmap_raw_write(mad->regmap, MT6360_REG_PMUADCCFG, &adc_enable, sizeof(adc_enable));
+ if (ret)
+ goto out_adc_lock;
+
+ predict_end_t = ktime_add_ms(mad->last_off_timestamps[channel], 2 * ADC_WAIT_TIME_MS);
+
+ if (ktime_after(ktime_get(), predict_end_t))
+ pre_wait_time = ADC_WAIT_TIME_MS;
+ else
+ pre_wait_time = 3 * ADC_WAIT_TIME_MS;
+
+ if (msleep_interruptible(pre_wait_time)) {
+ ret = -ERESTARTSYS;
+ goto out_adc_conv;
+ }
+
+ timeout = ktime_add_ms(ktime_get(), ADC_CONV_TIMEOUT_MS);
+ while (true) {
+ ret = regmap_raw_read(mad->regmap, MT6360_REG_PMUADCRPT1, rpt, sizeof(rpt));
+ if (ret)
+ goto out_adc_conv;
+
+ /*
+ * There are two functions, ZCV and TypeC OTP, running ADC VBAT and TS in
+ * background, and ADC samples are taken on a fixed frequency no matter read the
+ * previous one or not.
+ * To avoid conflict, We set minimum time threshold after enable ADC and
+ * check report channel is the same.
+ * The worst case is run the same ADC twice and background function is also running,
+ * ADC conversion sequence is desire channel before start ADC, background ADC,
+ * desire channel after start ADC.
+ * So the minimum correct data is three times of typical conversion time.
+ */
+ if ((rpt[0] & MT6360_RPTCH_MASK) == channel)
+ break;
+
+ if (ktime_compare(ktime_get(), timeout) > 0) {
+ ret = -ETIMEDOUT;
+ goto out_adc_conv;
+ }
+
+ usleep_range(ADC_LOOP_TIME_US / 2, ADC_LOOP_TIME_US);
+ }
+
+ *val = rpt[1] << 8 | rpt[2];
+ ret = IIO_VAL_INT;
+
+out_adc_conv:
+ /* Only keep ADC enable */
+ adc_enable = cpu_to_be16(MT6360_ADCEN_MASK);
+ regmap_raw_write(mad->regmap, MT6360_REG_PMUADCCFG, &adc_enable, sizeof(adc_enable));
+ mad->last_off_timestamps[channel] = ktime_get();
+ /* Config prefer channel to NO_PREFER */
+ regmap_update_bits(mad->regmap, MT6360_REG_PMUADCRPT1, MT6360_PREFERCH_MASK,
+ MT6360_NO_PREFER << MT6360_PREFERCH_SHFT);
+out_adc_lock:
+ mutex_unlock(&mad->adc_lock);
+
+ return ret;
+}
+
+static int mt6360_adc_read_scale(struct mt6360_adc_data *mad, int channel, int *val, int *val2)
+{
+ unsigned int regval;
+ int ret;
+
+ switch (channel) {
+ case MT6360_CHAN_USBID:
+ case MT6360_CHAN_VSYS:
+ case MT6360_CHAN_VBAT:
+ case MT6360_CHAN_CHG_VDDP:
+ case MT6360_CHAN_VREF_TS:
+ case MT6360_CHAN_TS:
+ *val = 1250;
+ return IIO_VAL_INT;
+ case MT6360_CHAN_VBUSDIV5:
+ *val = 6250;
+ return IIO_VAL_INT;
+ case MT6360_CHAN_VBUSDIV2:
+ case MT6360_CHAN_IBUS:
+ case MT6360_CHAN_IBAT:
+ *val = 2500;
+
+ if (channel == MT6360_CHAN_IBUS) {
+ /* IBUS will be affected by input current limit for the different Ron */
+ /* Check whether the config is <400mA or not */
+ ret = regmap_read(mad->regmap, MT6360_REG_PMUCHGCTRL3, &regval);
+ if (ret)
+ return ret;
+
+ regval = (regval & MT6360_AICR_MASK) >> MT6360_AICR_SHFT;
+ if (regval < MT6360_AICR_400MA)
+ *val = 1900;
+ }
+
+ return IIO_VAL_INT;
+ case MT6360_CHAN_TEMP_JC:
+ *val = 105;
+ *val2 = 100;
+ return IIO_VAL_FRACTIONAL;
+ }
+
+ return -EINVAL;
+}
+
+static int mt6360_adc_read_offset(struct mt6360_adc_data *mad, int channel, int *val)
+{
+ *val = (channel == MT6360_CHAN_TEMP_JC) ? -80 : 0;
+ return IIO_VAL_INT;
+}
+
+static int mt6360_adc_read_raw(struct iio_dev *iio_dev, const struct iio_chan_spec *chan,
+ int *val, int *val2, long mask)
+{
+ struct mt6360_adc_data *mad = iio_priv(iio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ return mt6360_adc_read_channel(mad, chan->channel, val);
+ case IIO_CHAN_INFO_SCALE:
+ return mt6360_adc_read_scale(mad, chan->channel, val, val2);
+ case IIO_CHAN_INFO_OFFSET:
+ return mt6360_adc_read_offset(mad, chan->channel, val);
+ }
+
+ return -EINVAL;
+}
+
+static const char *mt6360_channel_labels[MT6360_CHAN_MAX] = {
+ "usbid", "vbusdiv5", "vbusdiv2", "vsys", "vbat", "ibus", "ibat", "chg_vddp",
+ "temp_jc", "vref_ts", "ts",
+};
+
+static int mt6360_adc_read_label(struct iio_dev *iio_dev, const struct iio_chan_spec *chan,
+ char *label)
+{
+ return snprintf(label, PAGE_SIZE, "%s\n", mt6360_channel_labels[chan->channel]);
+}
+
+static const struct iio_info mt6360_adc_iio_info = {
+ .read_raw = mt6360_adc_read_raw,
+ .read_label = mt6360_adc_read_label,
+};
+
+#define MT6360_ADC_CHAN(_idx, _type) { \
+ .type = _type, \
+ .channel = MT6360_CHAN_##_idx, \
+ .scan_index = MT6360_CHAN_##_idx, \
+ .datasheet_name = #_idx, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_CPU, \
+ }, \
+ .indexed = 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OFFSET), \
+}
+
+static const struct iio_chan_spec mt6360_adc_channels[] = {
+ MT6360_ADC_CHAN(USBID, IIO_VOLTAGE),
+ MT6360_ADC_CHAN(VBUSDIV5, IIO_VOLTAGE),
+ MT6360_ADC_CHAN(VBUSDIV2, IIO_VOLTAGE),
+ MT6360_ADC_CHAN(VSYS, IIO_VOLTAGE),
+ MT6360_ADC_CHAN(VBAT, IIO_VOLTAGE),
+ MT6360_ADC_CHAN(IBUS, IIO_CURRENT),
+ MT6360_ADC_CHAN(IBAT, IIO_CURRENT),
+ MT6360_ADC_CHAN(CHG_VDDP, IIO_VOLTAGE),
+ MT6360_ADC_CHAN(TEMP_JC, IIO_TEMP),
+ MT6360_ADC_CHAN(VREF_TS, IIO_VOLTAGE),
+ MT6360_ADC_CHAN(TS, IIO_VOLTAGE),
+ IIO_CHAN_SOFT_TIMESTAMP(MT6360_CHAN_MAX),
+};
+
+static irqreturn_t mt6360_adc_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct mt6360_adc_data *mad = iio_priv(indio_dev);
+ struct {
+ u16 values[MT6360_CHAN_MAX];
+ int64_t timestamp;
+ } data __aligned(8);
+ int i = 0, bit, val, ret;
+
+ memset(&data, 0, sizeof(data));
+ for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) {
+ ret = mt6360_adc_read_channel(mad, bit, &val);
+ if (ret < 0) {
+ dev_warn(&indio_dev->dev, "Failed to get channel %d conversion val\n", bit);
+ goto out;
+ }
+
+ data.values[i++] = val;
+ }
+ iio_push_to_buffers_with_timestamp(indio_dev, &data, iio_get_time_ns(indio_dev));
+out:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static inline int mt6360_adc_reset(struct mt6360_adc_data *info)
+{
+ __be16 adc_enable;
+ ktime_t all_off_time;
+ int i, ret;
+
+ /* Clear ADC idle wait time to 0 */
+ ret = regmap_write(info->regmap, MT6360_REG_PMUADCIDLET, 0);
+ if (ret)
+ return ret;
+
+ /* Only keep ADC enable, but keep all channels off */
+ adc_enable = cpu_to_be16(MT6360_ADCEN_MASK);
+ ret = regmap_raw_write(info->regmap, MT6360_REG_PMUADCCFG, &adc_enable, sizeof(adc_enable));
+ if (ret)
+ return ret;
+
+ /* Reset all channel off time to the current one */
+ all_off_time = ktime_get();
+ for (i = 0; i < MT6360_CHAN_MAX; i++)
+ info->last_off_timestamps[i] = all_off_time;
+
+ return 0;
+}
+
+static int mt6360_adc_probe(struct platform_device *pdev)
+{
+ struct mt6360_adc_data *mad;
+ struct regmap *regmap;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!regmap) {
+ dev_err(&pdev->dev, "Failed to get parent regmap\n");
+ return -ENODEV;
+ }
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*mad));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ mad = iio_priv(indio_dev);
+ mad->dev = &pdev->dev;
+ mad->regmap = regmap;
+ mutex_init(&mad->adc_lock);
+
+ ret = mt6360_adc_reset(mad);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to reset adc\n");
+ return ret;
+ }
+
+ indio_dev->name = dev_name(&pdev->dev);
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->info = &mt6360_adc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = mt6360_adc_channels;
+ indio_dev->num_channels = ARRAY_SIZE(mt6360_adc_channels);
+
+ ret = devm_iio_triggered_buffer_setup(&pdev->dev, indio_dev, NULL,
+ mt6360_adc_trigger_handler, NULL);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to allocate iio trigger buffer\n");
+ return ret;
+ }
+
+ return devm_iio_device_register(&pdev->dev, indio_dev);
+}
+
+static const struct of_device_id __maybe_unused mt6360_adc_of_id[] = {
+ { .compatible = "mediatek,mt6360-adc", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mt6360_adc_of_id);
+
+static struct platform_driver mt6360_adc_driver = {
+ .driver = {
+ .name = "mt6360-adc",
+ .of_match_table = mt6360_adc_of_id,
+ },
+ .probe = mt6360_adc_probe,
+};
+module_platform_driver(mt6360_adc_driver);
+
+MODULE_AUTHOR("Gene Chen <gene_chen@richtek.com>");
+MODULE_DESCRIPTION("MT6360 ADC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c
index 1f3d7d639d37..12584f1631d8 100644
--- a/drivers/iio/adc/rockchip_saradc.c
+++ b/drivers/iio/adc/rockchip_saradc.c
@@ -462,7 +462,7 @@ static int rockchip_saradc_resume(struct device *dev)
ret = clk_prepare_enable(info->clk);
if (ret)
- return ret;
+ clk_disable_unprepare(info->pclk);
return ret;
}
diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index a83199b212a4..9d1ad6e38e85 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -200,7 +200,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev,
{
u32 ckmode, presc, val;
unsigned long rate;
- int i, div;
+ int i, div, duty;
/* stm32h7 bus clock is common for all ADC instances (mandatory) */
if (!priv->bclk) {
@@ -224,6 +224,11 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev,
return -EINVAL;
}
+ /* If duty is an error, kindly use at least /2 divider */
+ duty = clk_get_scaled_duty_cycle(priv->aclk, 100);
+ if (duty < 0)
+ dev_warn(&pdev->dev, "adc clock duty: %d\n", duty);
+
for (i = 0; i < ARRAY_SIZE(stm32h7_adc_ckmodes_spec); i++) {
ckmode = stm32h7_adc_ckmodes_spec[i].ckmode;
presc = stm32h7_adc_ckmodes_spec[i].presc;
@@ -232,6 +237,13 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev,
if (ckmode)
continue;
+ /*
+ * For proper operation, clock duty cycle range is 49%
+ * to 51%. Apply at least /2 prescaler otherwise.
+ */
+ if (div == 1 && (duty < 49 || duty > 51))
+ continue;
+
if ((rate / div) <= priv->max_clk_rate)
goto out;
}
@@ -244,6 +256,10 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev,
return -EINVAL;
}
+ duty = clk_get_scaled_duty_cycle(priv->bclk, 100);
+ if (duty < 0)
+ dev_warn(&pdev->dev, "bus clock duty: %d\n", duty);
+
for (i = 0; i < ARRAY_SIZE(stm32h7_adc_ckmodes_spec); i++) {
ckmode = stm32h7_adc_ckmodes_spec[i].ckmode;
presc = stm32h7_adc_ckmodes_spec[i].presc;
@@ -252,6 +268,9 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev,
if (!ckmode)
continue;
+ if (div == 1 && (duty < 49 || duty > 51))
+ continue;
+
if ((rate / div) <= priv->max_clk_rate)
goto out;
}
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index 16c02c30dec7..c067c994dae2 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -1353,7 +1353,7 @@ static int stm32_adc_set_watermark(struct iio_dev *indio_dev, unsigned int val)
* dma cyclic transfers are used, buffer is split into two periods.
* There should be :
* - always one buffer (period) dma is working on
- * - one buffer (period) driver can push with iio_trigger_poll().
+ * - one buffer (period) driver can push data.
*/
watermark = min(watermark, val * (unsigned)(sizeof(u16)));
adc->rx_buf_sz = min(rx_buf_sz, watermark * 2 * adc->num_conv);
@@ -1616,31 +1616,14 @@ static irqreturn_t stm32_adc_trigger_handler(int irq, void *p)
dev_dbg(&indio_dev->dev, "%s bufi=%d\n", __func__, adc->bufi);
- if (!adc->dma_chan) {
- /* reset buffer index */
- adc->bufi = 0;
- iio_push_to_buffers_with_timestamp(indio_dev, adc->buffer,
- pf->timestamp);
- } else {
- int residue = stm32_adc_dma_residue(adc);
-
- while (residue >= indio_dev->scan_bytes) {
- u16 *buffer = (u16 *)&adc->rx_buf[adc->bufi];
-
- iio_push_to_buffers_with_timestamp(indio_dev, buffer,
- pf->timestamp);
- residue -= indio_dev->scan_bytes;
- adc->bufi += indio_dev->scan_bytes;
- if (adc->bufi >= adc->rx_buf_sz)
- adc->bufi = 0;
- }
- }
-
+ /* reset buffer index */
+ adc->bufi = 0;
+ iio_push_to_buffers_with_timestamp(indio_dev, adc->buffer,
+ pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
/* re-enable eoc irq */
- if (!adc->dma_chan)
- stm32_adc_conv_irq_enable(adc);
+ stm32_adc_conv_irq_enable(adc);
return IRQ_HANDLED;
}
diff --git a/drivers/iio/adc/ti-adc084s021.c b/drivers/iio/adc/ti-adc084s021.c
index dfba34834a57..fb14b92fa6e7 100644
--- a/drivers/iio/adc/ti-adc084s021.c
+++ b/drivers/iio/adc/ti-adc084s021.c
@@ -70,11 +70,10 @@ static const struct iio_chan_spec adc084s021_channels[] = {
* @adc: The ADC SPI data.
* @data: Buffer for converted data.
*/
-static int adc084s021_adc_conversion(struct adc084s021 *adc, void *data)
+static int adc084s021_adc_conversion(struct adc084s021 *adc, __be16 *data)
{
int n_words = (adc->spi_trans.len >> 1) - 1; /* Discard first word */
int ret, i = 0;
- u16 *p = data;
/* Do the transfer */
ret = spi_sync(adc->spi, &adc->message);
@@ -82,7 +81,7 @@ static int adc084s021_adc_conversion(struct adc084s021 *adc, void *data)
return ret;
for (; i < n_words; i++)
- *(p + i) = adc->rx_buf[i + 1];
+ *(data + i) = adc->rx_buf[i + 1];
return ret;
}
@@ -93,6 +92,7 @@ static int adc084s021_read_raw(struct iio_dev *indio_dev,
{
struct adc084s021 *adc = iio_priv(indio_dev);
int ret;
+ __be16 be_val;
switch (mask) {
case IIO_CHAN_INFO_RAW:
@@ -107,13 +107,13 @@ static int adc084s021_read_raw(struct iio_dev *indio_dev,
}
adc->tx_buf[0] = channel->channel << 3;
- ret = adc084s021_adc_conversion(adc, val);
+ ret = adc084s021_adc_conversion(adc, &be_val);
iio_device_release_direct_mode(indio_dev);
regulator_disable(adc->reg);
if (ret < 0)
return ret;
- *val = be16_to_cpu(*val);
+ *val = be16_to_cpu(be_val);
*val = (*val >> channel->scan_type.shift) & 0xff;
return IIO_VAL_INT;
diff --git a/drivers/iio/adc/ti-ads124s08.c b/drivers/iio/adc/ti-ads124s08.c
index 4b4fbe33930c..b4a128b19188 100644
--- a/drivers/iio/adc/ti-ads124s08.c
+++ b/drivers/iio/adc/ti-ads124s08.c
@@ -99,6 +99,14 @@ struct ads124s_private {
struct gpio_desc *reset_gpio;
struct spi_device *spi;
struct mutex lock;
+ /*
+ * Used to correctly align data.
+ * Ensure timestamp is naturally aligned.
+ * Note that the full buffer length may not be needed if not
+ * all channels are enabled, as long as the alignment of the
+ * timestamp is maintained.
+ */
+ u32 buffer[ADS124S08_MAX_CHANNELS + sizeof(s64)/sizeof(u32)] __aligned(8);
u8 data[5] ____cacheline_aligned;
};
@@ -269,7 +277,6 @@ static irqreturn_t ads124s_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ads124s_private *priv = iio_priv(indio_dev);
- u32 buffer[ADS124S08_MAX_CHANNELS + sizeof(s64)/sizeof(u16)];
int scan_index, j = 0;
int ret;
@@ -284,7 +291,7 @@ static irqreturn_t ads124s_trigger_handler(int irq, void *p)
if (ret)
dev_err(&priv->spi->dev, "Start ADC conversions failed\n");
- buffer[j] = ads124s_read(indio_dev, scan_index);
+ priv->buffer[j] = ads124s_read(indio_dev, scan_index);
ret = ads124s_write_cmd(indio_dev, ADS124S08_STOP_CONV);
if (ret)
dev_err(&priv->spi->dev, "Stop ADC conversions failed\n");
@@ -292,7 +299,7 @@ static irqreturn_t ads124s_trigger_handler(int irq, void *p)
j++;
}
- iio_push_to_buffers_with_timestamp(indio_dev, buffer,
+ iio_push_to_buffers_with_timestamp(indio_dev, priv->buffer,
pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/buffer/industrialio-buffer-cb.c b/drivers/iio/buffer/industrialio-buffer-cb.c
index 47c96f7f4976..4c12b7a94af5 100644
--- a/drivers/iio/buffer/industrialio-buffer-cb.c
+++ b/drivers/iio/buffer/industrialio-buffer-cb.c
@@ -54,6 +54,11 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev,
struct iio_cb_buffer *cb_buff;
struct iio_channel *chan;
+ if (!cb) {
+ dev_err(dev, "Invalid arguments: A callback must be provided!\n");
+ return ERR_PTR(-EINVAL);
+ }
+
cb_buff = kzalloc(sizeof(*cb_buff), GFP_KERNEL);
if (cb_buff == NULL)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
index 93b4e9e6bb55..b0cb9a35f5cd 100644
--- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c
+++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
@@ -200,9 +200,8 @@ static struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev,
iio_dma_buffer_init(&dmaengine_buffer->queue, chan->device->dev,
&iio_dmaengine_default_ops);
- iio_buffer_set_attrs(&dmaengine_buffer->queue.buffer,
- iio_dmaengine_buffer_attrs);
+ dmaengine_buffer->queue.buffer.attrs = iio_dmaengine_buffer_attrs;
dmaengine_buffer->queue.buffer.access = &iio_dmaengine_buffer_ops;
return &dmaengine_buffer->queue.buffer;
diff --git a/drivers/iio/buffer/industrialio-triggered-buffer.c b/drivers/iio/buffer/industrialio-triggered-buffer.c
index 6c20a83f887e..92b8aea3e063 100644
--- a/drivers/iio/buffer/industrialio-triggered-buffer.c
+++ b/drivers/iio/buffer/industrialio-triggered-buffer.c
@@ -9,18 +9,20 @@
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
+#include <linux/iio/buffer_impl.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
/**
- * iio_triggered_buffer_setup() - Setup triggered buffer and pollfunc
+ * iio_triggered_buffer_setup_ext() - Setup triggered buffer and pollfunc
* @indio_dev: IIO device structure
* @h: Function which will be used as pollfunc top half
* @thread: Function which will be used as pollfunc bottom half
* @setup_ops: Buffer setup functions to use for this device.
* If NULL the default setup functions for triggered
* buffers will be used.
+ * @buffer_attrs: Extra sysfs buffer attributes for this IIO buffer
*
* This function combines some common tasks which will normally be performed
* when setting up a triggered buffer. It will allocate the buffer and the
@@ -33,10 +35,11 @@
* To free the resources allocated by this function call
* iio_triggered_buffer_cleanup().
*/
-int iio_triggered_buffer_setup(struct iio_dev *indio_dev,
+int iio_triggered_buffer_setup_ext(struct iio_dev *indio_dev,
irqreturn_t (*h)(int irq, void *p),
irqreturn_t (*thread)(int irq, void *p),
- const struct iio_buffer_setup_ops *setup_ops)
+ const struct iio_buffer_setup_ops *setup_ops,
+ const struct attribute **buffer_attrs)
{
struct iio_buffer *buffer;
int ret;
@@ -67,6 +70,8 @@ int iio_triggered_buffer_setup(struct iio_dev *indio_dev,
/* Flag that polled ring buffering is possible */
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
+ buffer->attrs = buffer_attrs;
+
return 0;
error_kfifo_free:
@@ -74,10 +79,10 @@ error_kfifo_free:
error_ret:
return ret;
}
-EXPORT_SYMBOL(iio_triggered_buffer_setup);
+EXPORT_SYMBOL(iio_triggered_buffer_setup_ext);
/**
- * iio_triggered_buffer_cleanup() - Free resources allocated by iio_triggered_buffer_setup()
+ * iio_triggered_buffer_cleanup() - Free resources allocated by iio_triggered_buffer_setup_ext()
* @indio_dev: IIO device structure
*/
void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev)
@@ -92,11 +97,12 @@ static void devm_iio_triggered_buffer_clean(struct device *dev, void *res)
iio_triggered_buffer_cleanup(*(struct iio_dev **)res);
}
-int devm_iio_triggered_buffer_setup(struct device *dev,
- struct iio_dev *indio_dev,
- irqreturn_t (*h)(int irq, void *p),
- irqreturn_t (*thread)(int irq, void *p),
- const struct iio_buffer_setup_ops *ops)
+int devm_iio_triggered_buffer_setup_ext(struct device *dev,
+ struct iio_dev *indio_dev,
+ irqreturn_t (*h)(int irq, void *p),
+ irqreturn_t (*thread)(int irq, void *p),
+ const struct iio_buffer_setup_ops *ops,
+ const struct attribute **buffer_attrs)
{
struct iio_dev **ptr;
int ret;
@@ -108,7 +114,8 @@ int devm_iio_triggered_buffer_setup(struct device *dev,
*ptr = indio_dev;
- ret = iio_triggered_buffer_setup(indio_dev, h, thread, ops);
+ ret = iio_triggered_buffer_setup_ext(indio_dev, h, thread, ops,
+ buffer_attrs);
if (!ret)
devres_add(dev, ptr);
else
@@ -116,7 +123,7 @@ int devm_iio_triggered_buffer_setup(struct device *dev,
return ret;
}
-EXPORT_SYMBOL_GPL(devm_iio_triggered_buffer_setup);
+EXPORT_SYMBOL_GPL(devm_iio_triggered_buffer_setup_ext);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("IIO helper functions for setting up triggered buffers");
diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
index e3f507771f17..c833ec0ef214 100644
--- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
+++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
@@ -359,19 +359,22 @@ int cros_ec_sensors_core_init(struct platform_device *pdev,
if (ret)
return ret;
} else {
+ const struct attribute **fifo_attrs;
+
+ if (has_hw_fifo)
+ fifo_attrs = cros_ec_sensor_fifo_attributes;
+ else
+ fifo_attrs = NULL;
+
/*
* The only way to get samples in buffer is to set a
* software trigger (systrig, hrtimer).
*/
- ret = devm_iio_triggered_buffer_setup(
+ ret = devm_iio_triggered_buffer_setup_ext(
dev, indio_dev, NULL, trigger_capture,
- NULL);
+ NULL, fifo_attrs);
if (ret)
return ret;
-
- if (has_hw_fifo)
- iio_buffer_set_attrs(indio_dev->buffer,
- cros_ec_sensor_fifo_attributes);
}
}
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index ff375790b7e8..064c32bec9c7 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -84,15 +84,6 @@ static const struct attribute *hid_sensor_fifo_attributes[] = {
NULL,
};
-static void hid_sensor_setup_batch_mode(struct iio_dev *indio_dev,
- struct hid_sensor_common *st)
-{
- if (!hid_sensor_batch_mode_supported(st))
- return;
-
- iio_buffer_set_attrs(indio_dev->buffer, hid_sensor_fifo_attributes);
-}
-
static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state)
{
int state_val;
@@ -247,11 +238,18 @@ static const struct iio_trigger_ops hid_sensor_trigger_ops = {
int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
struct hid_sensor_common *attrb)
{
+ const struct attribute **fifo_attrs;
int ret;
struct iio_trigger *trig;
- ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
- NULL, NULL);
+ if (hid_sensor_batch_mode_supported(attrb))
+ fifo_attrs = hid_sensor_fifo_attributes;
+ else
+ fifo_attrs = NULL;
+
+ ret = iio_triggered_buffer_setup_ext(indio_dev,
+ &iio_pollfunc_store_time,
+ NULL, NULL, fifo_attrs);
if (ret) {
dev_err(&indio_dev->dev, "Triggered Buffer Setup Failed\n");
return ret;
@@ -276,8 +274,6 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
attrb->trigger = trig;
indio_dev->trig = iio_trigger_get(trig);
- hid_sensor_setup_batch_mode(indio_dev, attrb);
-
ret = pm_runtime_set_active(&indio_dev->dev);
if (ret)
goto error_unreg_trigger;
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index dae8d27e772d..6f6074a5d3db 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -141,9 +141,10 @@ config AD5696_I2C
depends on I2C
select AD5686
help
- Say yes here to build support for Analog Devices AD5671R, AD5675R,
- AD5694, AD5694R, AD5695R, AD5696, AD5696R Voltage Output Digital to
- Analog Converter.
+ Say yes here to build support for Analog Devices AD5311R, AD5338R,
+ AD5671R, AD5675R, AD5691R, AD5692R, AD5693, AD5693R, AD5694, AD5694R,
+ AD5695R, AD5696, and AD5696R Digital to Analog converters.
+
To compile this driver as a module, choose M here: the module will be
called ad5696.
diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c
index 148d9541f517..7d6792ac1020 100644
--- a/drivers/iio/dac/ad5686.c
+++ b/drivers/iio/dac/ad5686.c
@@ -210,6 +210,12 @@ static const struct iio_chan_spec name[] = { \
AD5868_CHANNEL(0, 0, bits, _shift), \
}
+#define DECLARE_AD5338_CHANNELS(name, bits, _shift) \
+static const struct iio_chan_spec name[] = { \
+ AD5868_CHANNEL(0, 1, bits, _shift), \
+ AD5868_CHANNEL(1, 8, bits, _shift), \
+}
+
#define DECLARE_AD5686_CHANNELS(name, bits, _shift) \
static const struct iio_chan_spec name[] = { \
AD5868_CHANNEL(0, 1, bits, _shift), \
@@ -252,6 +258,7 @@ static const struct iio_chan_spec name[] = { \
DECLARE_AD5693_CHANNELS(ad5310r_channels, 10, 2);
DECLARE_AD5693_CHANNELS(ad5311r_channels, 10, 6);
+DECLARE_AD5338_CHANNELS(ad5338r_channels, 10, 6);
DECLARE_AD5676_CHANNELS(ad5672_channels, 12, 4);
DECLARE_AD5679_CHANNELS(ad5674r_channels, 12, 4);
DECLARE_AD5676_CHANNELS(ad5676_channels, 16, 0);
@@ -276,6 +283,12 @@ static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
.num_channels = 1,
.regmap_type = AD5693_REGMAP,
},
+ [ID_AD5338R] = {
+ .channels = ad5338r_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 2,
+ .regmap_type = AD5686_REGMAP,
+ },
[ID_AD5671R] = {
.channels = ad5672_channels,
.int_vref_mv = 2500,
diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h
index a15f2970577e..d9c8ba413fe9 100644
--- a/drivers/iio/dac/ad5686.h
+++ b/drivers/iio/dac/ad5686.h
@@ -52,6 +52,7 @@
enum ad5686_supported_device_ids {
ID_AD5310R,
ID_AD5311R,
+ ID_AD5338R,
ID_AD5671R,
ID_AD5672R,
ID_AD5674R,
diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c
index ccf794caef43..a39eda7c02d2 100644
--- a/drivers/iio/dac/ad5696-i2c.c
+++ b/drivers/iio/dac/ad5696-i2c.c
@@ -72,6 +72,7 @@ static int ad5686_i2c_remove(struct i2c_client *i2c)
static const struct i2c_device_id ad5686_i2c_id[] = {
{"ad5311r", ID_AD5311R},
+ {"ad5338r", ID_AD5338R},
{"ad5671r", ID_AD5671R},
{"ad5675r", ID_AD5675R},
{"ad5691r", ID_AD5691R},
@@ -87,9 +88,28 @@ static const struct i2c_device_id ad5686_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ad5686_i2c_id);
+static const struct of_device_id ad5686_of_match[] = {
+ { .compatible = "adi,ad5311r" },
+ { .compatible = "adi,ad5338r" },
+ { .compatible = "adi,ad5671r" },
+ { .compatible = "adi,ad5675r" },
+ { .compatible = "adi,ad5691r" },
+ { .compatible = "adi,ad5692r" },
+ { .compatible = "adi,ad5693" },
+ { .compatible = "adi,ad5693r" },
+ { .compatible = "adi,ad5694" },
+ { .compatible = "adi,ad5694r" },
+ { .compatible = "adi,ad5695r" },
+ { .compatible = "adi,ad5696" },
+ { .compatible = "adi,ad5696r" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, ad5686_of_match);
+
static struct i2c_driver ad5686_i2c_driver = {
.driver = {
.name = "ad5696",
+ .of_match_table = ad5686_of_match,
},
.probe = ad5686_i2c_probe,
.remove = ad5686_i2c_remove,
diff --git a/drivers/iio/dac/ad7303.c b/drivers/iio/dac/ad7303.c
index 2e46def9d8ee..dbb4645ab6b1 100644
--- a/drivers/iio/dac/ad7303.c
+++ b/drivers/iio/dac/ad7303.c
@@ -17,8 +17,6 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
-#include <linux/platform_data/ad7303.h>
-
#define AD7303_CFG_EXTERNAL_VREF BIT(15)
#define AD7303_CFG_POWER_DOWN(ch) BIT(11 + (ch))
#define AD7303_CFG_ADDR_OFFSET 10
diff --git a/drivers/iio/gyro/adxrs290.c b/drivers/iio/gyro/adxrs290.c
index ca6fc234076e..c45d8226cc2b 100644
--- a/drivers/iio/gyro/adxrs290.c
+++ b/drivers/iio/gyro/adxrs290.c
@@ -478,7 +478,7 @@ static int adxrs290_data_rdy_trigger_set_state(struct iio_trigger *trig,
return ret;
}
-static int adxrs290_reset_trig(struct iio_trigger *trig)
+static void adxrs290_reset_trig(struct iio_trigger *trig)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
int val;
@@ -491,14 +491,12 @@ static int adxrs290_reset_trig(struct iio_trigger *trig)
*/
adxrs290_get_rate_data(indio_dev,
ADXRS290_READ_REG(ADXRS290_REG_DATAY0), &val);
-
- return 0;
}
static const struct iio_trigger_ops adxrs290_trigger_ops = {
.set_trigger_state = &adxrs290_data_rdy_trigger_set_state,
.validate_device = &iio_trigger_validate_own_device,
- .try_reenable = &adxrs290_reset_trig,
+ .reenable = &adxrs290_reset_trig,
};
static irqreturn_t adxrs290_trigger_handler(int irq, void *p)
diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c
index 8ddda96455fc..2d5015801a75 100644
--- a/drivers/iio/gyro/bmg160_core.c
+++ b/drivers/iio/gyro/bmg160_core.c
@@ -893,7 +893,7 @@ err:
return IRQ_HANDLED;
}
-static int bmg160_trig_try_reen(struct iio_trigger *trig)
+static void bmg160_trig_reen(struct iio_trigger *trig)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct bmg160_data *data = iio_priv(indio_dev);
@@ -902,18 +902,14 @@ static int bmg160_trig_try_reen(struct iio_trigger *trig)
/* new data interrupts don't need ack */
if (data->dready_trigger_on)
- return 0;
+ return;
/* Set latched mode interrupt and clear any latched interrupt */
ret = regmap_write(data->regmap, BMG160_REG_INT_RST_LATCH,
BMG160_INT_MODE_LATCH_INT |
BMG160_INT_MODE_LATCH_RESET);
- if (ret < 0) {
+ if (ret < 0)
dev_err(dev, "Error writing reg_rst_latch\n");
- return ret;
- }
-
- return 0;
}
static int bmg160_data_rdy_trigger_set_state(struct iio_trigger *trig,
@@ -961,7 +957,7 @@ static int bmg160_data_rdy_trigger_set_state(struct iio_trigger *trig,
static const struct iio_trigger_ops bmg160_trigger_ops = {
.set_trigger_state = bmg160_data_rdy_trigger_set_state,
- .try_reenable = bmg160_trig_try_reen,
+ .reenable = bmg160_trig_reen,
};
static irqreturn_t bmg160_event_handler(int irq, void *private)
diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c
index 00e58060968c..dfa31a23500f 100644
--- a/drivers/iio/gyro/mpu3050-core.c
+++ b/drivers/iio/gyro/mpu3050-core.c
@@ -13,6 +13,7 @@
* TODO: add support for setting up the low pass 3dB frequency.
*/
+#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/err.h>
@@ -784,7 +785,8 @@ static int mpu3050_read_mem(struct mpu3050 *mpu3050,
static int mpu3050_hw_init(struct mpu3050 *mpu3050)
{
int ret;
- u8 otp[8];
+ __le64 otp_le;
+ u64 otp;
/* Reset */
ret = regmap_update_bits(mpu3050->map,
@@ -815,29 +817,31 @@ static int mpu3050_hw_init(struct mpu3050 *mpu3050)
MPU3050_MEM_USER_BANK |
MPU3050_MEM_OTP_BANK_0),
0,
- sizeof(otp),
- otp);
+ sizeof(otp_le),
+ (u8 *)&otp_le);
if (ret)
return ret;
/* This is device-unique data so it goes into the entropy pool */
- add_device_randomness(otp, sizeof(otp));
+ add_device_randomness(&otp_le, sizeof(otp_le));
+
+ otp = le64_to_cpu(otp_le);
dev_info(mpu3050->dev,
- "die ID: %04X, wafer ID: %02X, A lot ID: %04X, "
- "W lot ID: %03X, WP ID: %01X, rev ID: %02X\n",
+ "die ID: %04llX, wafer ID: %02llX, A lot ID: %04llX, "
+ "W lot ID: %03llX, WP ID: %01llX, rev ID: %02llX\n",
/* Die ID, bits 0-12 */
- (otp[1] << 8 | otp[0]) & 0x1fff,
+ FIELD_GET(GENMASK_ULL(12, 0), otp),
/* Wafer ID, bits 13-17 */
- ((otp[2] << 8 | otp[1]) & 0x03e0) >> 5,
+ FIELD_GET(GENMASK_ULL(17, 13), otp),
/* A lot ID, bits 18-33 */
- ((otp[4] << 16 | otp[3] << 8 | otp[2]) & 0x3fffc) >> 2,
+ FIELD_GET(GENMASK_ULL(33, 18), otp),
/* W lot ID, bits 34-45 */
- ((otp[5] << 8 | otp[4]) & 0x3ffc) >> 2,
+ FIELD_GET(GENMASK_ULL(45, 34), otp),
/* WP ID, bits 47-49 */
- ((otp[6] << 8 | otp[5]) & 0x0380) >> 7,
+ FIELD_GET(GENMASK_ULL(49, 47), otp),
/* rev ID, bits 50-55 */
- otp[6] >> 2);
+ FIELD_GET(GENMASK_ULL(55, 50), otp));
return 0;
}
diff --git a/drivers/iio/humidity/hts221.h b/drivers/iio/humidity/hts221.h
index 721359e226cb..cf3d8d2dccd6 100644
--- a/drivers/iio/humidity/hts221.h
+++ b/drivers/iio/humidity/hts221.h
@@ -13,6 +13,7 @@
#define HTS221_DEV_NAME "hts221"
#include <linux/iio/iio.h>
+#include <linux/regulator/consumer.h>
enum hts221_sensor_type {
HTS221_SENSOR_H,
@@ -29,6 +30,7 @@ struct hts221_hw {
const char *name;
struct device *dev;
struct regmap *regmap;
+ struct regulator *vdd;
struct iio_trigger *trig;
int irq;
diff --git a/drivers/iio/humidity/hts221_core.c b/drivers/iio/humidity/hts221_core.c
index 16657789dc45..6a39615b6961 100644
--- a/drivers/iio/humidity/hts221_core.c
+++ b/drivers/iio/humidity/hts221_core.c
@@ -547,6 +547,35 @@ static const struct iio_info hts221_info = {
static const unsigned long hts221_scan_masks[] = {0x3, 0x0};
+static int hts221_init_regulators(struct device *dev)
+{
+ struct iio_dev *iio_dev = dev_get_drvdata(dev);
+ struct hts221_hw *hw = iio_priv(iio_dev);
+ int err;
+
+ hw->vdd = devm_regulator_get(dev, "vdd");
+ if (IS_ERR(hw->vdd))
+ return dev_err_probe(dev, PTR_ERR(hw->vdd),
+ "failed to get vdd regulator\n");
+
+ err = regulator_enable(hw->vdd);
+ if (err) {
+ dev_err(dev, "failed to enable vdd regulator: %d\n", err);
+ return err;
+ }
+
+ msleep(50);
+
+ return 0;
+}
+
+static void hts221_chip_uninit(void *data)
+{
+ struct hts221_hw *hw = data;
+
+ regulator_disable(hw->vdd);
+}
+
int hts221_probe(struct device *dev, int irq, const char *name,
struct regmap *regmap)
{
@@ -567,6 +596,14 @@ int hts221_probe(struct device *dev, int irq, const char *name,
hw->irq = irq;
hw->regmap = regmap;
+ err = hts221_init_regulators(dev);
+ if (err)
+ return err;
+
+ err = devm_add_action_or_reset(dev, hts221_chip_uninit, hw);
+ if (err)
+ return err;
+
err = hts221_check_whoami(hw);
if (err < 0)
return err;
diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h
index fd9a5f1d5e51..fced02cadcc3 100644
--- a/drivers/iio/iio_core.h
+++ b/drivers/iio/iio_core.h
@@ -17,6 +17,20 @@ struct iio_dev;
extern struct device_type iio_device_type;
+#define IIO_IOCTL_UNHANDLED 1
+struct iio_ioctl_handler {
+ struct list_head entry;
+ long (*ioctl)(struct iio_dev *indio_dev, struct file *filp,
+ 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);
+
int __iio_add_chan_devattr(const char *postfix,
struct iio_chan_spec const *chan,
ssize_t (*func)(struct device *dev,
@@ -74,7 +88,6 @@ static inline void iio_buffer_wakeup_poll(struct iio_dev *indio_dev) {}
int iio_device_register_eventset(struct iio_dev *indio_dev);
void iio_device_unregister_eventset(struct iio_dev *indio_dev);
void iio_device_wakeup_eventset(struct iio_dev *indio_dev);
-int iio_event_getfd(struct iio_dev *indio_dev);
struct iio_event_interface;
bool iio_event_enabled(const struct iio_event_interface *ev_int);
diff --git a/drivers/iio/imu/bmi160/bmi160.h b/drivers/iio/imu/bmi160/bmi160.h
index a82e040bd109..32c2ea2d7112 100644
--- a/drivers/iio/imu/bmi160/bmi160.h
+++ b/drivers/iio/imu/bmi160/bmi160.h
@@ -10,6 +10,13 @@ struct bmi160_data {
struct iio_trigger *trig;
struct regulator_bulk_data supplies[2];
struct iio_mount_matrix orientation;
+ /*
+ * Ensure natural alignment for timestamp if present.
+ * Max length needed: 2 * 3 channels + 4 bytes padding + 8 byte ts.
+ * If fewer channels are enabled, less space may be needed, as
+ * long as the timestamp is still aligned to 8 bytes.
+ */
+ __le16 buf[12] __aligned(8);
};
extern const struct regmap_config bmi160_regmap_config;
diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c
index 222ebb26f013..290b5ef83f77 100644
--- a/drivers/iio/imu/bmi160/bmi160_core.c
+++ b/drivers/iio/imu/bmi160/bmi160_core.c
@@ -427,8 +427,6 @@ static irqreturn_t bmi160_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct bmi160_data *data = iio_priv(indio_dev);
- __le16 buf[16];
- /* 3 sens x 3 axis x __le16 + 3 x __le16 pad + 4 x __le16 tstamp */
int i, ret, j = 0, base = BMI160_REG_DATA_MAGN_XOUT_L;
__le16 sample;
@@ -438,10 +436,10 @@ static irqreturn_t bmi160_trigger_handler(int irq, void *p)
&sample, sizeof(sample));
if (ret)
goto done;
- buf[j++] = sample;
+ data->buf[j++] = sample;
}
- iio_push_to_buffers_with_timestamp(indio_dev, buf, pf->timestamp);
+ iio_push_to_buffers_with_timestamp(indio_dev, data->buf, pf->timestamp);
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
@@ -486,7 +484,6 @@ static int bmi160_write_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE:
return bmi160_set_scale(data,
bmi160_to_sensor(chan->type), val2);
- break;
case IIO_CHAN_INFO_SAMP_FREQ:
return bmi160_set_odr(data, bmi160_to_sensor(chan->type),
val, val2);
diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c
index 61885e99d3fc..4377047d503a 100644
--- a/drivers/iio/imu/kmx61.c
+++ b/drivers/iio/imu/kmx61.c
@@ -1063,24 +1063,20 @@ err_unlock:
return ret;
}
-static int kmx61_trig_try_reenable(struct iio_trigger *trig)
+static void kmx61_trig_reenable(struct iio_trigger *trig)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct kmx61_data *data = kmx61_get_data(indio_dev);
int ret;
ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_INL);
- if (ret < 0) {
+ if (ret < 0)
dev_err(&data->client->dev, "Error reading reg_inl\n");
- return ret;
- }
-
- return 0;
}
static const struct iio_trigger_ops kmx61_trigger_ops = {
.set_trigger_state = kmx61_data_rdy_trigger_set_state,
- .try_reenable = kmx61_trig_try_reenable,
+ .reenable = kmx61_trig_reenable,
};
static irqreturn_t kmx61_event_handler(int irq, void *private)
diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig
index 28f59d09208a..85860217aaf3 100644
--- a/drivers/iio/imu/st_lsm6dsx/Kconfig
+++ b/drivers/iio/imu/st_lsm6dsx/Kconfig
@@ -12,8 +12,8 @@ config IIO_ST_LSM6DSX
Say yes here to build support for STMicroelectronics LSM6DSx imu
sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm,
ism330dlc, lsm6dso, lsm6dsox, asm330lhh, lsm6dsr, lsm6ds3tr-c,
- ism330dhcx, lsm6dsrx, lsm6ds0 and the accelerometer/gyroscope
- of lsm9ds1.
+ ism330dhcx, lsm6dsrx, lsm6ds0, lsm6dsop, the accelerometer/gyroscope
+ of lsm9ds1 and lsm6dst.
To compile this driver as a module, choose M here: the module
will be called st_lsm6dsx.
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
index 9275346a9cc1..5ef55763a6cc 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
@@ -13,6 +13,7 @@
#include <linux/device.h>
#include <linux/iio/iio.h>
+#include <linux/regulator/consumer.h>
#define ST_LSM6DS3_DEV_NAME "lsm6ds3"
#define ST_LSM6DS3H_DEV_NAME "lsm6ds3h"
@@ -28,6 +29,8 @@
#define ST_LSM9DS1_DEV_NAME "lsm9ds1-imu"
#define ST_LSM6DS0_DEV_NAME "lsm6ds0"
#define ST_LSM6DSRX_DEV_NAME "lsm6dsrx"
+#define ST_LSM6DST_DEV_NAME "lsm6dst"
+#define ST_LSM6DSOP_DEV_NAME "lsm6dsop"
enum st_lsm6dsx_hw_id {
ST_LSM6DS3_ID,
@@ -44,6 +47,8 @@ enum st_lsm6dsx_hw_id {
ST_LSM9DS1_ID,
ST_LSM6DS0_ID,
ST_LSM6DSRX_ID,
+ ST_LSM6DST_ID,
+ ST_LSM6DSOP_ID,
ST_LSM6DSX_MAX_ID,
};
@@ -263,7 +268,6 @@ struct st_lsm6dsx_ext_dev_settings {
/**
* struct st_lsm6dsx_settings - ST IMU sensor settings
- * @wai: Sensor WhoAmI default value.
* @reset: register address for reset.
* @boot: register address for boot.
* @bdu: register address for Block Data Update.
@@ -281,7 +285,6 @@ struct st_lsm6dsx_ext_dev_settings {
* @shub_settings: i2c controller related settings.
*/
struct st_lsm6dsx_settings {
- u8 wai;
struct st_lsm6dsx_reg reset;
struct st_lsm6dsx_reg boot;
struct st_lsm6dsx_reg bdu;
@@ -289,6 +292,7 @@ struct st_lsm6dsx_settings {
struct {
enum st_lsm6dsx_hw_id hw_id;
const char *name;
+ u8 wai;
} id[ST_LSM6DSX_MAX_ID];
struct {
const struct iio_chan_spec *chan;
@@ -366,6 +370,7 @@ struct st_lsm6dsx_sensor {
* struct st_lsm6dsx_hw - ST IMU MEMS hw instance
* @dev: Pointer to instance of struct device (I2C or SPI).
* @regmap: Register map of the device.
+ * @regulators: VDD/VDDIO voltage regulators.
* @irq: Device interrupt line (I2C or SPI).
* @fifo_lock: Mutex to prevent concurrent access to the hw FIFO.
* @conf_lock: Mutex to prevent concurrent FIFO configuration update.
@@ -388,6 +393,7 @@ struct st_lsm6dsx_sensor {
struct st_lsm6dsx_hw {
struct device *dev;
struct regmap *regmap;
+ struct regulator_bulk_data regulators[2];
int irq;
struct mutex fifo_lock;
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
index 12ed0a2e55e4..f1103ecedd64 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
@@ -14,7 +14,7 @@
* (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the
* value of the decimation factor and ODR set for each FIFO data set.
*
- * LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR/LSM6DSRX/ISM330DHCX:
+ * LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR/LSM6DSRX/ISM330DHCX/LSM6DST/LSM6DSOP:
* The FIFO buffer can be configured to store data from gyroscope and
* accelerometer. Each sample is queued with a tag (1B) indicating data
* source (gyroscope, accelerometer, hw timer).
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
index 42f485634d04..7cedaab096a7 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
@@ -26,7 +26,7 @@
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
* - FIFO size: 4KB
*
- * - LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR/ISM330DHCX:
+ * - LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR/ISM330DHCX/LSM6DST/LSM6DSOP:
* - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416,
* 833
* - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
@@ -90,7 +90,6 @@ static const struct iio_chan_spec st_lsm6ds0_gyro_channels[] = {
static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
{
- .wai = 0x68,
.reset = {
.addr = 0x22,
.mask = BIT(0),
@@ -108,9 +107,11 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
{
.hw_id = ST_LSM9DS1_ID,
.name = ST_LSM9DS1_DEV_NAME,
+ .wai = 0x68,
}, {
.hw_id = ST_LSM6DS0_ID,
.name = ST_LSM6DS0_DEV_NAME,
+ .wai = 0x68,
},
},
.channels = {
@@ -195,7 +196,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
},
{
- .wai = 0x69,
.reset = {
.addr = 0x12,
.mask = BIT(0),
@@ -213,6 +213,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
{
.hw_id = ST_LSM6DS3_ID,
.name = ST_LSM6DS3_DEV_NAME,
+ .wai = 0x69,
},
},
.channels = {
@@ -361,7 +362,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
},
{
- .wai = 0x69,
.reset = {
.addr = 0x12,
.mask = BIT(0),
@@ -379,6 +379,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
{
.hw_id = ST_LSM6DS3H_ID,
.name = ST_LSM6DS3H_DEV_NAME,
+ .wai = 0x69,
},
},
.channels = {
@@ -527,7 +528,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
},
{
- .wai = 0x6a,
.reset = {
.addr = 0x12,
.mask = BIT(0),
@@ -545,15 +545,19 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
{
.hw_id = ST_LSM6DSL_ID,
.name = ST_LSM6DSL_DEV_NAME,
+ .wai = 0x6a,
}, {
.hw_id = ST_LSM6DSM_ID,
.name = ST_LSM6DSM_DEV_NAME,
+ .wai = 0x6a,
}, {
.hw_id = ST_ISM330DLC_ID,
.name = ST_ISM330DLC_DEV_NAME,
+ .wai = 0x6a,
}, {
.hw_id = ST_LSM6DS3TRC_ID,
.name = ST_LSM6DS3TRC_DEV_NAME,
+ .wai = 0x6a,
},
},
.channels = {
@@ -743,7 +747,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
},
{
- .wai = 0x6c,
.reset = {
.addr = 0x12,
.mask = BIT(0),
@@ -759,11 +762,29 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.max_fifo_size = 512,
.id = {
{
+ .hw_id = ST_LSM6DSR_ID,
+ .name = ST_LSM6DSR_DEV_NAME,
+ .wai = 0x6b,
+ }, {
+ .hw_id = ST_ISM330DHCX_ID,
+ .name = ST_ISM330DHCX_DEV_NAME,
+ .wai = 0x6b,
+ }, {
+ .hw_id = ST_LSM6DSRX_ID,
+ .name = ST_LSM6DSRX_DEV_NAME,
+ .wai = 0x6b,
+ }, {
.hw_id = ST_LSM6DSO_ID,
.name = ST_LSM6DSO_DEV_NAME,
+ .wai = 0x6c,
}, {
.hw_id = ST_LSM6DSOX_ID,
.name = ST_LSM6DSOX_DEV_NAME,
+ .wai = 0x6c,
+ }, {
+ .hw_id = ST_LSM6DST_ID,
+ .name = ST_LSM6DST_DEV_NAME,
+ .wai = 0x6d,
},
},
.channels = {
@@ -951,7 +972,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
},
{
- .wai = 0x6b,
.reset = {
.addr = 0x12,
.mask = BIT(0),
@@ -969,185 +989,11 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
{
.hw_id = ST_ASM330LHH_ID,
.name = ST_ASM330LHH_DEV_NAME,
- },
- },
- .channels = {
- [ST_LSM6DSX_ID_ACC] = {
- .chan = st_lsm6dsx_acc_channels,
- .len = ARRAY_SIZE(st_lsm6dsx_acc_channels),
- },
- [ST_LSM6DSX_ID_GYRO] = {
- .chan = st_lsm6dsx_gyro_channels,
- .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels),
- },
- },
- .drdy_mask = {
- .addr = 0x13,
- .mask = BIT(3),
- },
- .odr_table = {
- [ST_LSM6DSX_ID_ACC] = {
- .reg = {
- .addr = 0x10,
- .mask = GENMASK(7, 4),
- },
- .odr_avl[0] = { 12500, 0x01 },
- .odr_avl[1] = { 26000, 0x02 },
- .odr_avl[2] = { 52000, 0x03 },
- .odr_avl[3] = { 104000, 0x04 },
- .odr_avl[4] = { 208000, 0x05 },
- .odr_avl[5] = { 416000, 0x06 },
- .odr_avl[6] = { 833000, 0x07 },
- .odr_len = 7,
- },
- [ST_LSM6DSX_ID_GYRO] = {
- .reg = {
- .addr = 0x11,
- .mask = GENMASK(7, 4),
- },
- .odr_avl[0] = { 12500, 0x01 },
- .odr_avl[1] = { 26000, 0x02 },
- .odr_avl[2] = { 52000, 0x03 },
- .odr_avl[3] = { 104000, 0x04 },
- .odr_avl[4] = { 208000, 0x05 },
- .odr_avl[5] = { 416000, 0x06 },
- .odr_avl[6] = { 833000, 0x07 },
- .odr_len = 7,
- },
- },
- .fs_table = {
- [ST_LSM6DSX_ID_ACC] = {
- .reg = {
- .addr = 0x10,
- .mask = GENMASK(3, 2),
- },
- .fs_avl[0] = { IIO_G_TO_M_S_2(61000), 0x0 },
- .fs_avl[1] = { IIO_G_TO_M_S_2(122000), 0x2 },
- .fs_avl[2] = { IIO_G_TO_M_S_2(244000), 0x3 },
- .fs_avl[3] = { IIO_G_TO_M_S_2(488000), 0x1 },
- .fs_len = 4,
- },
- [ST_LSM6DSX_ID_GYRO] = {
- .reg = {
- .addr = 0x11,
- .mask = GENMASK(3, 2),
- },
- .fs_avl[0] = { IIO_DEGREE_TO_RAD(8750000), 0x0 },
- .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500000), 0x1 },
- .fs_avl[2] = { IIO_DEGREE_TO_RAD(35000000), 0x2 },
- .fs_avl[3] = { IIO_DEGREE_TO_RAD(70000000), 0x3 },
- .fs_len = 4,
- },
- },
- .irq_config = {
- .irq1 = {
- .addr = 0x0d,
- .mask = BIT(3),
- },
- .irq2 = {
- .addr = 0x0e,
- .mask = BIT(3),
- },
- .lir = {
- .addr = 0x56,
- .mask = BIT(0),
- },
- .clear_on_read = {
- .addr = 0x56,
- .mask = BIT(6),
- },
- .irq1_func = {
- .addr = 0x5e,
- .mask = BIT(5),
- },
- .irq2_func = {
- .addr = 0x5f,
- .mask = BIT(5),
- },
- .hla = {
- .addr = 0x12,
- .mask = BIT(5),
- },
- .od = {
- .addr = 0x12,
- .mask = BIT(4),
- },
- },
- .batch = {
- [ST_LSM6DSX_ID_ACC] = {
- .addr = 0x09,
- .mask = GENMASK(3, 0),
- },
- [ST_LSM6DSX_ID_GYRO] = {
- .addr = 0x09,
- .mask = GENMASK(7, 4),
- },
- },
- .fifo_ops = {
- .update_fifo = st_lsm6dsx_update_fifo,
- .read_fifo = st_lsm6dsx_read_tagged_fifo,
- .fifo_th = {
- .addr = 0x07,
- .mask = GENMASK(8, 0),
- },
- .fifo_diff = {
- .addr = 0x3a,
- .mask = GENMASK(9, 0),
- },
- .th_wl = 1,
- },
- .ts_settings = {
- .timer_en = {
- .addr = 0x19,
- .mask = BIT(5),
- },
- .decimator = {
- .addr = 0x0a,
- .mask = GENMASK(7, 6),
- },
- .freq_fine = 0x63,
- },
- .event_settings = {
- .enable_reg = {
- .addr = 0x58,
- .mask = BIT(7),
- },
- .wakeup_reg = {
- .addr = 0x5B,
- .mask = GENMASK(5, 0),
- },
- .wakeup_src_reg = 0x1b,
- .wakeup_src_status_mask = BIT(3),
- .wakeup_src_z_mask = BIT(0),
- .wakeup_src_y_mask = BIT(1),
- .wakeup_src_x_mask = BIT(2),
- },
- },
- {
- .wai = 0x6b,
- .reset = {
- .addr = 0x12,
- .mask = BIT(0),
- },
- .boot = {
- .addr = 0x12,
- .mask = BIT(7),
- },
- .bdu = {
- .addr = 0x12,
- .mask = BIT(6),
- },
- .max_fifo_size = 512,
- .id = {
- {
- .hw_id = ST_LSM6DSR_ID,
- .name = ST_LSM6DSR_DEV_NAME,
+ .wai = 0x6b,
}, {
- .hw_id = ST_ISM330DHCX_ID,
- .name = ST_ISM330DHCX_DEV_NAME,
- }, {
- .hw_id = ST_LSM6DSRX_ID,
- .name = ST_LSM6DSRX_DEV_NAME,
+ .hw_id = ST_LSM6DSOP_ID,
+ .name = ST_LSM6DSOP_DEV_NAME,
+ .wai = 0x6c,
},
},
.channels = {
@@ -1286,38 +1132,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
.freq_fine = 0x63,
},
- .shub_settings = {
- .page_mux = {
- .addr = 0x01,
- .mask = BIT(6),
- },
- .master_en = {
- .sec_page = true,
- .addr = 0x14,
- .mask = BIT(2),
- },
- .pullup_en = {
- .sec_page = true,
- .addr = 0x14,
- .mask = BIT(3),
- },
- .aux_sens = {
- .addr = 0x14,
- .mask = GENMASK(1, 0),
- },
- .wr_once = {
- .addr = 0x14,
- .mask = BIT(6),
- },
- .num_ext_dev = 3,
- .shub_out = {
- .sec_page = true,
- .addr = 0x02,
- },
- .slv0_addr = 0x15,
- .dw_slv0_addr = 0x21,
- .batch_en = BIT(3),
- },
.event_settings = {
.enable_reg = {
.addr = 0x58,
@@ -1332,7 +1146,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.wakeup_src_z_mask = BIT(0),
.wakeup_src_y_mask = BIT(1),
.wakeup_src_x_mask = BIT(2),
- }
+ },
},
};
@@ -1377,7 +1191,7 @@ static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id,
return err;
}
- if (data != st_lsm6dsx_sensor_settings[i].wai) {
+ if (data != st_lsm6dsx_sensor_settings[i].id[j].wai) {
dev_err(hw->dev, "unsupported whoami [%02x]\n", data);
return -ENODEV;
}
@@ -2255,19 +2069,35 @@ st_lsm6dsx_report_motion_event(struct st_lsm6dsx_hw *hw)
static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private)
{
struct st_lsm6dsx_hw *hw = private;
+ int fifo_len = 0, len;
bool event;
- int count;
event = st_lsm6dsx_report_motion_event(hw);
if (!hw->settings->fifo_ops.read_fifo)
return event ? IRQ_HANDLED : IRQ_NONE;
- mutex_lock(&hw->fifo_lock);
- count = hw->settings->fifo_ops.read_fifo(hw);
- mutex_unlock(&hw->fifo_lock);
+ /*
+ * If we are using edge IRQs, new samples can arrive while
+ * processing current interrupt since there are no hw
+ * guarantees the irq line stays "low" long enough to properly
+ * detect the new interrupt. In this case the new sample will
+ * be missed.
+ * Polling FIFO status register allow us to read new
+ * samples even if the interrupt arrives while processing
+ * previous data and the timeslot where the line is "low" is
+ * too short to be properly detected.
+ */
+ do {
+ mutex_lock(&hw->fifo_lock);
+ len = hw->settings->fifo_ops.read_fifo(hw);
+ mutex_unlock(&hw->fifo_lock);
+
+ if (len > 0)
+ fifo_len += len;
+ } while (len > 0);
- return count || event ? IRQ_HANDLED : IRQ_NONE;
+ return fifo_len || event ? IRQ_HANDLED : IRQ_NONE;
}
static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw)
@@ -2328,6 +2158,38 @@ static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw)
return 0;
}
+static int st_lsm6dsx_init_regulators(struct device *dev)
+{
+ struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev);
+ int err;
+
+ /* vdd-vddio power regulators */
+ hw->regulators[0].supply = "vdd";
+ hw->regulators[1].supply = "vddio";
+ err = devm_regulator_bulk_get(dev, ARRAY_SIZE(hw->regulators),
+ hw->regulators);
+ if (err)
+ return dev_err_probe(dev, err, "failed to get regulators\n");
+
+ err = regulator_bulk_enable(ARRAY_SIZE(hw->regulators),
+ hw->regulators);
+ if (err) {
+ dev_err(dev, "failed to enable regulators: %d\n", err);
+ return err;
+ }
+
+ msleep(50);
+
+ return 0;
+}
+
+static void st_lsm6dsx_chip_uninit(void *data)
+{
+ struct st_lsm6dsx_hw *hw = data;
+
+ regulator_bulk_disable(ARRAY_SIZE(hw->regulators), hw->regulators);
+}
+
int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
struct regmap *regmap)
{
@@ -2347,6 +2209,14 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
mutex_init(&hw->conf_lock);
mutex_init(&hw->page_lock);
+ err = st_lsm6dsx_init_regulators(dev);
+ if (err)
+ return err;
+
+ err = devm_add_action_or_reset(dev, st_lsm6dsx_chip_uninit, hw);
+ if (err)
+ return err;
+
hw->buff = devm_kzalloc(dev, ST_LSM6DSX_BUFF_SIZE, GFP_KERNEL);
if (!hw->buff)
return -ENOMEM;
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
index 0fb32131afce..ec8d4351390a 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
@@ -94,6 +94,14 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
.compatible = "st,lsm6dsrx",
.data = (void *)ST_LSM6DSRX_ID,
},
+ {
+ .compatible = "st,lsm6dst",
+ .data = (void *)ST_LSM6DST_ID,
+ },
+ {
+ .compatible = "st,lsm6dsop",
+ .data = (void *)ST_LSM6DSOP_ID,
+ },
{},
};
MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match);
@@ -113,6 +121,8 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = {
{ ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID },
{ ST_LSM6DS0_DEV_NAME, ST_LSM6DS0_ID },
{ ST_LSM6DSRX_DEV_NAME, ST_LSM6DSRX_ID },
+ { ST_LSM6DST_DEV_NAME, ST_LSM6DST_ID },
+ { ST_LSM6DSOP_DEV_NAME, ST_LSM6DSOP_ID },
{},
};
MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
index eb1086e4a951..349ec9c1890d 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
@@ -94,6 +94,14 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
.compatible = "st,lsm6dsrx",
.data = (void *)ST_LSM6DSRX_ID,
},
+ {
+ .compatible = "st,lsm6dst",
+ .data = (void *)ST_LSM6DST_ID,
+ },
+ {
+ .compatible = "st,lsm6dsop",
+ .data = (void *)ST_LSM6DSOP_ID,
+ },
{},
};
MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match);
@@ -113,6 +121,8 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = {
{ ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID },
{ ST_LSM6DS0_DEV_NAME, ST_LSM6DS0_ID },
{ ST_LSM6DSRX_DEV_NAME, ST_LSM6DSRX_ID },
+ { ST_LSM6DST_DEV_NAME, ST_LSM6DST_ID },
+ { ST_LSM6DSOP_DEV_NAME, ST_LSM6DSOP_ID },
{},
};
MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index a4f6bb96d4f4..2f7426a2f47c 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -210,18 +210,6 @@ void iio_buffer_init(struct iio_buffer *buffer)
}
EXPORT_SYMBOL(iio_buffer_init);
-/**
- * iio_buffer_set_attrs - Set buffer specific attributes
- * @buffer: The buffer for which we are setting attributes
- * @attrs: Pointer to a null terminated list of pointers to attributes
- */
-void iio_buffer_set_attrs(struct iio_buffer *buffer,
- const struct attribute **attrs)
-{
- buffer->attrs = attrs;
-}
-EXPORT_SYMBOL_GPL(iio_buffer_set_attrs);
-
static ssize_t iio_show_scan_index(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -865,12 +853,12 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev,
indio_dev->masklength,
in_ind + 1);
while (in_ind != out_ind) {
- in_ind = find_next_bit(indio_dev->active_scan_mask,
- indio_dev->masklength,
- in_ind + 1);
length = iio_storage_bytes_for_si(indio_dev, in_ind);
/* Make sure we are aligned */
in_loc = roundup(in_loc, length) + length;
+ in_ind = find_next_bit(indio_dev->active_scan_mask,
+ indio_dev->masklength,
+ in_ind + 1);
}
length = iio_storage_bytes_for_si(indio_dev, in_ind);
out_loc = roundup(out_loc, length);
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 261d3b17edc9..c2e4c267c36b 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -594,6 +594,7 @@ static ssize_t __iio_format_value(char *buf, size_t len, unsigned int type,
{
unsigned long long tmp;
int tmp0, tmp1;
+ s64 tmp2;
bool scale_db = false;
switch (type) {
@@ -616,10 +617,13 @@ static ssize_t __iio_format_value(char *buf, size_t len, unsigned int type,
else
return scnprintf(buf, len, "%d.%09u", vals[0], vals[1]);
case IIO_VAL_FRACTIONAL:
- tmp = div_s64((s64)vals[0] * 1000000000LL, vals[1]);
+ tmp2 = div_s64((s64)vals[0] * 1000000000LL, vals[1]);
tmp1 = vals[1];
- tmp0 = (int)div_s64_rem(tmp, 1000000000, &tmp1);
- return scnprintf(buf, len, "%d.%09u", tmp0, abs(tmp1));
+ tmp0 = (int)div_s64_rem(tmp2, 1000000000, &tmp1);
+ if ((tmp2 < 0) && (tmp0 == 0))
+ return snprintf(buf, len, "-0.%09u", abs(tmp1));
+ else
+ return snprintf(buf, len, "%d.%09u", tmp0, abs(tmp1));
case IIO_VAL_FRACTIONAL_LOG2:
tmp = shift_right((s64)vals[0] * 1000000000LL, vals[1]);
tmp0 = (int)div_s64_rem(tmp, 1000000000LL, &tmp1);
@@ -669,6 +673,19 @@ ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals)
}
EXPORT_SYMBOL_GPL(iio_format_value);
+static ssize_t iio_read_channel_label(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_label)
+ return -EINVAL;
+
+ return indio_dev->info->read_label(indio_dev, this_attr->c, buf);
+}
+
static ssize_t iio_read_channel_info(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -694,90 +711,52 @@ static ssize_t iio_read_channel_info(struct device *dev,
return iio_format_value(buf, ret, val_len, vals);
}
-static ssize_t iio_format_avail_list(char *buf, const int *vals,
- int type, int length)
+static ssize_t iio_format_list(char *buf, const int *vals, int type, int length,
+ const char *prefix, const char *suffix)
{
+ ssize_t len;
+ int stride;
int i;
- ssize_t len = 0;
switch (type) {
case IIO_VAL_INT:
- for (i = 0; i < length; i++) {
- len += __iio_format_value(buf + len, PAGE_SIZE - len,
- type, 1, &vals[i]);
- if (len >= PAGE_SIZE)
- return -EFBIG;
- if (i < length - 1)
- len += scnprintf(buf + len, PAGE_SIZE - len,
- " ");
- else
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "\n");
- if (len >= PAGE_SIZE)
- return -EFBIG;
- }
+ stride = 1;
break;
default:
- for (i = 0; i < length / 2; i++) {
- len += __iio_format_value(buf + len, PAGE_SIZE - len,
- type, 2, &vals[i * 2]);
- if (len >= PAGE_SIZE)
- return -EFBIG;
- if (i < length / 2 - 1)
- len += scnprintf(buf + len, PAGE_SIZE - len,
- " ");
- else
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "\n");
+ stride = 2;
+ break;
+ }
+
+ len = scnprintf(buf, PAGE_SIZE, prefix);
+
+ for (i = 0; i <= length - stride; i += stride) {
+ if (i != 0) {
+ len += scnprintf(buf + len, PAGE_SIZE - len, " ");
if (len >= PAGE_SIZE)
return -EFBIG;
}
+
+ len += __iio_format_value(buf + len, PAGE_SIZE - len, type,
+ stride, &vals[i]);
+ if (len >= PAGE_SIZE)
+ return -EFBIG;
}
+ len += scnprintf(buf + len, PAGE_SIZE - len, "%s\n", suffix);
+
return len;
}
-static ssize_t iio_format_avail_range(char *buf, const int *vals, int type)
+static ssize_t iio_format_avail_list(char *buf, const int *vals,
+ int type, int length)
{
- int i;
- ssize_t len;
- len = snprintf(buf, PAGE_SIZE, "[");
- switch (type) {
- case IIO_VAL_INT:
- for (i = 0; i < 3; i++) {
- len += __iio_format_value(buf + len, PAGE_SIZE - len,
- type, 1, &vals[i]);
- if (len >= PAGE_SIZE)
- return -EFBIG;
- if (i < 2)
- len += scnprintf(buf + len, PAGE_SIZE - len,
- " ");
- else
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "]\n");
- if (len >= PAGE_SIZE)
- return -EFBIG;
- }
- break;
- default:
- for (i = 0; i < 3; i++) {
- len += __iio_format_value(buf + len, PAGE_SIZE - len,
- type, 2, &vals[i * 2]);
- if (len >= PAGE_SIZE)
- return -EFBIG;
- if (i < 2)
- len += scnprintf(buf + len, PAGE_SIZE - len,
- " ");
- else
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "]\n");
- if (len >= PAGE_SIZE)
- return -EFBIG;
- }
- }
+ return iio_format_list(buf, vals, type, length, "", "");
+}
- return len;
+static ssize_t iio_format_avail_range(char *buf, const int *vals, int type)
+{
+ return iio_format_list(buf, vals, type, 3, "[", "]");
}
static ssize_t iio_read_channel_info_avail(struct device *dev,
@@ -1137,6 +1116,29 @@ error_iio_dev_attr_free:
return ret;
}
+static int iio_device_add_channel_label(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan)
+{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+ int ret;
+
+ if (!indio_dev->info->read_label)
+ return 0;
+
+ ret = __iio_add_chan_devattr("label",
+ chan,
+ &iio_read_channel_label,
+ NULL,
+ 0,
+ IIO_SEPARATE,
+ &indio_dev->dev,
+ &iio_dev_opaque->channel_attr_list);
+ if (ret < 0)
+ return ret;
+
+ return 1;
+}
+
static int iio_device_add_info_mask_type(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
enum iio_shared_by shared_by,
@@ -1270,6 +1272,11 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
return ret;
attrcount += ret;
+ ret = iio_device_add_channel_label(indio_dev, chan);
+ if (ret < 0)
+ return ret;
+ attrcount += ret;
+
if (chan->ext_info) {
unsigned int i = 0;
for (ext_info = chan->ext_info; ext_info->name; ext_info++) {
@@ -1567,6 +1574,7 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv)
}
dev_set_name(&dev->dev, "iio:device%d", dev->id);
INIT_LIST_HEAD(&iio_dev_opaque->buffer_list);
+ INIT_LIST_HEAD(&iio_dev_opaque->ioctl_handlers);
return dev;
}
@@ -1660,37 +1668,61 @@ static int iio_chrdev_release(struct inode *inode, struct file *filp)
return 0;
}
-/* Somewhat of a cross file organization violation - ioctls here are actually
- * event related */
+void iio_device_ioctl_handler_register(struct iio_dev *indio_dev,
+ struct iio_ioctl_handler *h)
+{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+
+ list_add_tail(&h->entry, &iio_dev_opaque->ioctl_handlers);
+}
+
+void iio_device_ioctl_handler_unregister(struct iio_ioctl_handler *h)
+{
+ list_del(&h->entry);
+}
+
static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct iio_dev *indio_dev = filp->private_data;
- int __user *ip = (int __user *)arg;
- int fd;
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+ struct iio_ioctl_handler *h;
+ int ret = -ENODEV;
+ mutex_lock(&indio_dev->info_exist_lock);
+
+ /**
+ * The NULL check here is required to prevent crashing when a device
+ * is being removed while userspace would still have open file handles
+ * to try to access this device.
+ */
if (!indio_dev->info)
- return -ENODEV;
-
- if (cmd == IIO_GET_EVENT_FD_IOCTL) {
- fd = iio_event_getfd(indio_dev);
- if (fd < 0)
- return fd;
- if (copy_to_user(ip, &fd, sizeof(fd)))
- return -EFAULT;
- return 0;
+ goto out_unlock;
+
+ ret = -EINVAL;
+ list_for_each_entry(h, &iio_dev_opaque->ioctl_handlers, entry) {
+ ret = h->ioctl(indio_dev, filp, cmd, arg);
+ if (ret != IIO_IOCTL_UNHANDLED)
+ break;
}
- return -EINVAL;
+
+ if (ret == IIO_IOCTL_UNHANDLED)
+ ret = -EINVAL;
+
+out_unlock:
+ mutex_unlock(&indio_dev->info_exist_lock);
+
+ return ret;
}
static const struct file_operations iio_buffer_fileops = {
- .read = iio_buffer_read_outer_addr,
- .release = iio_chrdev_release,
- .open = iio_chrdev_open,
- .poll = iio_buffer_poll_addr,
.owner = THIS_MODULE,
.llseek = noop_llseek,
+ .read = iio_buffer_read_outer_addr,
+ .poll = iio_buffer_poll_addr,
.unlocked_ioctl = iio_ioctl,
.compat_ioctl = compat_ptr_ioctl,
+ .open = iio_chrdev_open,
+ .release = iio_chrdev_release,
};
static int iio_check_unique_scan_index(struct iio_dev *indio_dev)
@@ -1796,6 +1828,9 @@ EXPORT_SYMBOL(__iio_device_register);
**/
void iio_device_unregister(struct iio_dev *indio_dev)
{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+ struct iio_ioctl_handler *h, *t;
+
cdev_device_del(&indio_dev->chrdev, &indio_dev->dev);
mutex_lock(&indio_dev->info_exist_lock);
@@ -1806,6 +1841,9 @@ void iio_device_unregister(struct iio_dev *indio_dev)
indio_dev->info = NULL;
+ list_for_each_entry_safe(h, t, &iio_dev_opaque->ioctl_handlers, entry)
+ list_del(&h->entry);
+
iio_device_wakeup_eventset(indio_dev);
iio_buffer_wakeup_poll(indio_dev);
diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
index 99ba657b8568..7e532117ac55 100644
--- a/drivers/iio/industrialio-event.c
+++ b/drivers/iio/industrialio-event.c
@@ -31,6 +31,7 @@
* @flags: file operations related flags including busy flag.
* @group: event interface sysfs attribute group
* @read_lock: lock to protect kfifo read operations
+ * @ioctl_handler: handler for event ioctl() calls
*/
struct iio_event_interface {
wait_queue_head_t wait;
@@ -40,6 +41,7 @@ struct iio_event_interface {
unsigned long flags;
struct attribute_group group;
struct mutex read_lock;
+ struct iio_ioctl_handler ioctl_handler;
};
bool iio_event_enabled(const struct iio_event_interface *ev_int)
@@ -187,7 +189,7 @@ static const struct file_operations iio_event_chrdev_fileops = {
.llseek = noop_llseek,
};
-int iio_event_getfd(struct iio_dev *indio_dev)
+static int iio_event_getfd(struct iio_dev *indio_dev)
{
struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
struct iio_event_interface *ev_int = iio_dev_opaque->event_interface;
@@ -473,6 +475,24 @@ static void iio_setup_ev_int(struct iio_event_interface *ev_int)
mutex_init(&ev_int->read_lock);
}
+static long iio_event_ioctl(struct iio_dev *indio_dev, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ int __user *ip = (int __user *)arg;
+ int fd;
+
+ if (cmd == IIO_GET_EVENT_FD_IOCTL) {
+ fd = iio_event_getfd(indio_dev);
+ if (fd < 0)
+ return fd;
+ if (copy_to_user(ip, &fd, sizeof(fd)))
+ return -EFAULT;
+ return 0;
+ }
+
+ return IIO_IOCTL_UNHANDLED;
+}
+
static const char *iio_event_group_name = "events";
int iio_device_register_eventset(struct iio_dev *indio_dev)
{
@@ -526,6 +546,10 @@ int iio_device_register_eventset(struct iio_dev *indio_dev)
ev_int->group.attrs[attrn++] = &p->dev_attr.attr;
indio_dev->groups[indio_dev->groupcounter++] = &ev_int->group;
+ ev_int->ioctl_handler.ioctl = iio_event_ioctl;
+ iio_device_ioctl_handler_register(&iio_dev_opaque->indio_dev,
+ &ev_int->ioctl_handler);
+
return 0;
error_free_setup_event_lines:
@@ -558,6 +582,8 @@ void iio_device_unregister_eventset(struct iio_dev *indio_dev)
if (ev_int == NULL)
return;
+
+ iio_device_ioctl_handler_unregister(&ev_int->ioctl_handler);
iio_free_chan_devattr_list(&ev_int->dev_attr_list);
kfree(ev_int->group.attrs);
kfree(ev_int);
diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
index 583bb51f65a7..ea3c9859b258 100644
--- a/drivers/iio/industrialio-trigger.c
+++ b/drivers/iio/industrialio-trigger.c
@@ -203,10 +203,8 @@ EXPORT_SYMBOL(iio_trigger_poll_chained);
void iio_trigger_notify_done(struct iio_trigger *trig)
{
if (atomic_dec_and_test(&trig->use_count) && trig->ops &&
- trig->ops->try_reenable)
- if (trig->ops->try_reenable(trig))
- /* Missed an interrupt so launch new poll now */
- iio_trigger_poll(trig);
+ trig->ops->reenable)
+ trig->ops->reenable(trig);
}
EXPORT_SYMBOL(iio_trigger_notify_done);
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index ede99e0d5371..fe30bcb6a57b 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -24,6 +24,21 @@ struct iio_map_internal {
static LIST_HEAD(iio_map_list);
static DEFINE_MUTEX(iio_map_list_lock);
+static int iio_map_array_unregister_locked(struct iio_dev *indio_dev)
+{
+ int ret = -ENODEV;
+ struct iio_map_internal *mapi, *next;
+
+ list_for_each_entry_safe(mapi, next, &iio_map_list, l) {
+ if (indio_dev == mapi->indio_dev) {
+ list_del(&mapi->l);
+ kfree(mapi);
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
int iio_map_array_register(struct iio_dev *indio_dev, struct iio_map *maps)
{
int i = 0, ret = 0;
@@ -45,6 +60,8 @@ int iio_map_array_register(struct iio_dev *indio_dev, struct iio_map *maps)
i++;
}
error_ret:
+ if (ret)
+ iio_map_array_unregister_locked(indio_dev);
mutex_unlock(&iio_map_list_lock);
return ret;
@@ -57,18 +74,12 @@ EXPORT_SYMBOL_GPL(iio_map_array_register);
*/
int iio_map_array_unregister(struct iio_dev *indio_dev)
{
- int ret = -ENODEV;
- struct iio_map_internal *mapi, *next;
+ int ret;
mutex_lock(&iio_map_list_lock);
- list_for_each_entry_safe(mapi, next, &iio_map_list, l) {
- if (indio_dev == mapi->indio_dev) {
- list_del(&mapi->l);
- kfree(mapi);
- ret = 0;
- }
- }
+ ret = iio_map_array_unregister_locked(indio_dev);
mutex_unlock(&iio_map_list_lock);
+
return ret;
}
EXPORT_SYMBOL_GPL(iio_map_array_unregister);
diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c
index 9afb3fcc74e6..547e7f9d6920 100644
--- a/drivers/iio/light/apds9960.c
+++ b/drivers/iio/light/apds9960.c
@@ -561,7 +561,7 @@ static int apds9960_write_raw(struct iio_dev *indio_dev,
}
default:
return -EINVAL;
- };
+ }
return 0;
}
diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c
index aa2972b04833..31224a33bade 100644
--- a/drivers/iio/light/rpr0521.c
+++ b/drivers/iio/light/rpr0521.c
@@ -194,6 +194,17 @@ struct rpr0521_data {
bool pxs_need_dis;
struct regmap *regmap;
+
+ /*
+ * Ensure correct naturally aligned timestamp.
+ * Note that the read will put garbage data into
+ * the padding but this should not be a problem
+ */
+ struct {
+ __le16 channels[3];
+ u8 garbage;
+ s64 ts __aligned(8);
+ } scan;
};
static IIO_CONST_ATTR(in_intensity_scale_available, RPR0521_ALS_SCALE_AVAIL);
@@ -449,8 +460,6 @@ static irqreturn_t rpr0521_trigger_consumer_handler(int irq, void *p)
struct rpr0521_data *data = iio_priv(indio_dev);
int err;
- u8 buffer[16]; /* 3 16-bit channels + padding + ts */
-
/* Use irq timestamp when reasonable. */
if (iio_trigger_using_own(indio_dev) && data->irq_timestamp) {
pf->timestamp = data->irq_timestamp;
@@ -461,11 +470,11 @@ static irqreturn_t rpr0521_trigger_consumer_handler(int irq, void *p)
pf->timestamp = iio_get_time_ns(indio_dev);
err = regmap_bulk_read(data->regmap, RPR0521_REG_PXS_DATA,
- &buffer,
+ data->scan.channels,
(3 * 2) + 1); /* 3 * 16-bit + (discarded) int clear reg. */
if (!err)
iio_push_to_buffers_with_timestamp(indio_dev,
- buffer, pf->timestamp);
+ &data->scan, pf->timestamp);
else
dev_err(&data->client->dev,
"Trigger consumer can't read from sensor.\n");
diff --git a/drivers/iio/light/st_uvis25.h b/drivers/iio/light/st_uvis25.h
index 78bc56aad129..283086887caf 100644
--- a/drivers/iio/light/st_uvis25.h
+++ b/drivers/iio/light/st_uvis25.h
@@ -27,6 +27,11 @@ struct st_uvis25_hw {
struct iio_trigger *trig;
bool enabled;
int irq;
+ /* Ensure timestamp is naturally aligned */
+ struct {
+ u8 chan;
+ s64 ts __aligned(8);
+ } scan;
};
extern const struct dev_pm_ops st_uvis25_pm_ops;
diff --git a/drivers/iio/light/st_uvis25_core.c b/drivers/iio/light/st_uvis25_core.c
index a18a82e6bbf5..1055594b2276 100644
--- a/drivers/iio/light/st_uvis25_core.c
+++ b/drivers/iio/light/st_uvis25_core.c
@@ -232,17 +232,19 @@ static const struct iio_buffer_setup_ops st_uvis25_buffer_ops = {
static irqreturn_t st_uvis25_buffer_handler_thread(int irq, void *p)
{
- u8 buffer[ALIGN(sizeof(u8), sizeof(s64)) + sizeof(s64)];
struct iio_poll_func *pf = p;
struct iio_dev *iio_dev = pf->indio_dev;
struct st_uvis25_hw *hw = iio_priv(iio_dev);
+ unsigned int val;
int err;
- err = regmap_read(hw->regmap, ST_UVIS25_REG_OUT_ADDR, (int *)buffer);
+ err = regmap_read(hw->regmap, ST_UVIS25_REG_OUT_ADDR, &val);
if (err < 0)
goto out;
- iio_push_to_buffers_with_timestamp(iio_dev, buffer,
+ hw->scan.chan = val;
+
+ iio_push_to_buffers_with_timestamp(iio_dev, &hw->scan,
iio_get_time_ns(iio_dev));
out:
diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c
index abc8d7db8dc1..5bf2bfbc5379 100644
--- a/drivers/iio/light/tsl2563.c
+++ b/drivers/iio/light/tsl2563.c
@@ -12,6 +12,8 @@
*/
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/property.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
@@ -703,7 +705,6 @@ static int tsl2563_probe(struct i2c_client *client,
struct iio_dev *indio_dev;
struct tsl2563_chip *chip;
struct tsl2563_platform_data *pdata = client->dev.platform_data;
- struct device_node *np = client->dev.of_node;
int err = 0;
u8 id = 0;
@@ -738,13 +739,14 @@ static int tsl2563_probe(struct i2c_client *client,
chip->calib0 = tsl2563_calib_from_sysfs(CALIB_BASE_SYSFS);
chip->calib1 = tsl2563_calib_from_sysfs(CALIB_BASE_SYSFS);
- if (pdata)
+ if (pdata) {
chip->cover_comp_gain = pdata->cover_comp_gain;
- else if (np)
- of_property_read_u32(np, "amstaos,cover-comp-gain",
- &chip->cover_comp_gain);
- else
- chip->cover_comp_gain = 1;
+ } else {
+ err = device_property_read_u32(&client->dev, "amstaos,cover-comp-gain",
+ &chip->cover_comp_gain);
+ if (err)
+ chip->cover_comp_gain = 1;
+ }
dev_info(&client->dev, "model %d, rev. %d\n", id >> 4, id & 0x0f);
indio_dev->name = client->name;
diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c
index 765c44adac57..73a28e30dddc 100644
--- a/drivers/iio/light/vcnl4035.c
+++ b/drivers/iio/light/vcnl4035.c
@@ -652,6 +652,12 @@ static const struct dev_pm_ops vcnl4035_pm_ops = {
vcnl4035_runtime_resume, NULL)
};
+static const struct i2c_device_id vcnl4035_id[] = {
+ { "vcnl4035", 0},
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, vcnl4035_id);
+
static const struct of_device_id vcnl4035_of_match[] = {
{ .compatible = "vishay,vcnl4035", },
{ }
@@ -666,6 +672,7 @@ static struct i2c_driver vcnl4035_driver = {
},
.probe = vcnl4035_probe,
.remove = vcnl4035_remove,
+ .id_table = vcnl4035_id,
};
module_i2c_driver(vcnl4035_driver);
diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c
index fc6840f9c1fa..fa09fcab620a 100644
--- a/drivers/iio/magnetometer/bmc150_magn.c
+++ b/drivers/iio/magnetometer/bmc150_magn.c
@@ -190,7 +190,7 @@ static bool bmc150_magn_is_writeable_reg(struct device *dev, unsigned int reg)
return true;
default:
return false;
- };
+ }
}
static bool bmc150_magn_is_volatile_reg(struct device *dev, unsigned int reg)
@@ -766,20 +766,20 @@ static int bmc150_magn_reset_intr(struct bmc150_magn_data *data)
return regmap_read(data->regmap, BMC150_MAGN_REG_X_L, &tmp);
}
-static int bmc150_magn_trig_try_reen(struct iio_trigger *trig)
+static void bmc150_magn_trig_reen(struct iio_trigger *trig)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct bmc150_magn_data *data = iio_priv(indio_dev);
int ret;
if (!data->dready_trigger_on)
- return 0;
+ return;
mutex_lock(&data->mutex);
ret = bmc150_magn_reset_intr(data);
mutex_unlock(&data->mutex);
-
- return ret;
+ if (ret)
+ dev_err(data->dev, "Failed to reset interrupt\n");
}
static int bmc150_magn_data_rdy_trigger_set_state(struct iio_trigger *trig,
@@ -817,7 +817,7 @@ err_unlock:
static const struct iio_trigger_ops bmc150_magn_trigger_ops = {
.set_trigger_state = bmc150_magn_data_rdy_trigger_set_state,
- .try_reenable = bmc150_magn_trig_try_reen,
+ .reenable = bmc150_magn_trig_reen,
};
static int bmc150_magn_buffer_preenable(struct iio_dev *indio_dev)
diff --git a/drivers/iio/magnetometer/mag3110.c b/drivers/iio/magnetometer/mag3110.c
index 838b13c8bb3d..c96415a1aead 100644
--- a/drivers/iio/magnetometer/mag3110.c
+++ b/drivers/iio/magnetometer/mag3110.c
@@ -56,6 +56,12 @@ struct mag3110_data {
int sleep_val;
struct regulator *vdd_reg;
struct regulator *vddio_reg;
+ /* Ensure natural alignment of timestamp */
+ struct {
+ __be16 channels[3];
+ u8 temperature;
+ s64 ts __aligned(8);
+ } scan;
};
static int mag3110_request(struct mag3110_data *data)
@@ -387,10 +393,9 @@ static irqreturn_t mag3110_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct mag3110_data *data = iio_priv(indio_dev);
- u8 buffer[16]; /* 3 16-bit channels + 1 byte temp + padding + ts */
int ret;
- ret = mag3110_read(data, (__be16 *) buffer);
+ ret = mag3110_read(data, data->scan.channels);
if (ret < 0)
goto done;
@@ -399,10 +404,10 @@ static irqreturn_t mag3110_trigger_handler(int irq, void *p)
MAG3110_DIE_TEMP);
if (ret < 0)
goto done;
- buffer[6] = ret;
+ data->scan.temperature = ret;
}
- iio_push_to_buffers_with_timestamp(indio_dev, buffer,
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
iio_get_time_ns(indio_dev));
done:
diff --git a/drivers/iio/potentiometer/ad5272.c b/drivers/iio/potentiometer/ad5272.c
index 70c45d346df0..d8cbd170262f 100644
--- a/drivers/iio/potentiometer/ad5272.c
+++ b/drivers/iio/potentiometer/ad5272.c
@@ -143,13 +143,13 @@ static int ad5272_reset(struct ad5272_data *data)
struct gpio_desc *reset_gpio;
reset_gpio = devm_gpiod_get_optional(&data->client->dev, "reset",
- GPIOD_OUT_LOW);
+ GPIOD_OUT_HIGH);
if (IS_ERR(reset_gpio))
return PTR_ERR(reset_gpio);
if (reset_gpio) {
udelay(1);
- gpiod_set_value(reset_gpio, 1);
+ gpiod_set_value(reset_gpio, 0);
} else {
ad5272_write(data, AD5272_RESET, 0);
}
diff --git a/drivers/iio/pressure/bmp280-regmap.c b/drivers/iio/pressure/bmp280-regmap.c
index 08c00ac32bda..da136dbadc8f 100644
--- a/drivers/iio/pressure/bmp280-regmap.c
+++ b/drivers/iio/pressure/bmp280-regmap.c
@@ -13,7 +13,7 @@ static bool bmp180_is_writeable_reg(struct device *dev, unsigned int reg)
return true;
default:
return false;
- };
+ }
}
static bool bmp180_is_volatile_reg(struct device *dev, unsigned int reg)
@@ -51,7 +51,7 @@ static bool bmp280_is_writeable_reg(struct device *dev, unsigned int reg)
return true;
default:
return false;
- };
+ }
}
static bool bmp280_is_volatile_reg(struct device *dev, unsigned int reg)
diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c
index ccdb0b70e48c..1eb9e7b29e05 100644
--- a/drivers/iio/pressure/mpl3115.c
+++ b/drivers/iio/pressure/mpl3115.c
@@ -144,7 +144,14 @@ static irqreturn_t mpl3115_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct mpl3115_data *data = iio_priv(indio_dev);
- u8 buffer[16]; /* 32-bit channel + 16-bit channel + padding + ts */
+ /*
+ * 32-bit channel + 16-bit channel + padding + ts
+ * Note that it is possible for only one of the first 2
+ * channels to be enabled. If that happens, the first element
+ * of the buffer may be either 16 or 32-bits. As such we cannot
+ * use a simple structure definition to express this data layout.
+ */
+ u8 buffer[16] __aligned(8);
int ret, pos = 0;
mutex_lock(&data->lock);
diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c
index 6d3f4ab8c6b2..a2f820997afc 100644
--- a/drivers/iio/proximity/sx9310.c
+++ b/drivers/iio/proximity/sx9310.c
@@ -16,6 +16,7 @@
#include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/kernel.h>
+#include <linux/log2.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/pm.h>
@@ -48,30 +49,55 @@
#define SX9310_REG_PROX_CTRL0_SCANPERIOD_15MS 0x01
#define SX9310_REG_PROX_CTRL1 0x11
#define SX9310_REG_PROX_CTRL2 0x12
+#define SX9310_REG_PROX_CTRL2_COMBMODE_MASK GENMASK(7, 6)
+#define SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1_CS2_CS3 (0x03 << 6)
#define SX9310_REG_PROX_CTRL2_COMBMODE_CS1_CS2 (0x02 << 6)
+#define SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1 (0x01 << 6)
+#define SX9310_REG_PROX_CTRL2_COMBMODE_CS3 (0x00 << 6)
+#define SX9310_REG_PROX_CTRL2_SHIELDEN_MASK GENMASK(3, 2)
#define SX9310_REG_PROX_CTRL2_SHIELDEN_DYNAMIC (0x01 << 2)
+#define SX9310_REG_PROX_CTRL2_SHIELDEN_GROUND (0x02 << 2)
#define SX9310_REG_PROX_CTRL3 0x13
+#define SX9310_REG_PROX_CTRL3_GAIN0_MASK GENMASK(3, 2)
#define SX9310_REG_PROX_CTRL3_GAIN0_X8 (0x03 << 2)
+#define SX9310_REG_PROX_CTRL3_GAIN12_MASK GENMASK(1, 0)
#define SX9310_REG_PROX_CTRL3_GAIN12_X4 0x02
#define SX9310_REG_PROX_CTRL4 0x14
+#define SX9310_REG_PROX_CTRL4_RESOLUTION_MASK GENMASK(2, 0)
#define SX9310_REG_PROX_CTRL4_RESOLUTION_FINEST 0x07
+#define SX9310_REG_PROX_CTRL4_RESOLUTION_VERY_FINE 0x06
+#define SX9310_REG_PROX_CTRL4_RESOLUTION_FINE 0x05
+#define SX9310_REG_PROX_CTRL4_RESOLUTION_MEDIUM 0x04
+#define SX9310_REG_PROX_CTRL4_RESOLUTION_MEDIUM_COARSE 0x03
+#define SX9310_REG_PROX_CTRL4_RESOLUTION_COARSE 0x02
+#define SX9310_REG_PROX_CTRL4_RESOLUTION_VERY_COARSE 0x01
+#define SX9310_REG_PROX_CTRL4_RESOLUTION_COARSEST 0x00
#define SX9310_REG_PROX_CTRL5 0x15
#define SX9310_REG_PROX_CTRL5_RANGE_SMALL (0x03 << 6)
+#define SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK GENMASK(3, 2)
#define SX9310_REG_PROX_CTRL5_STARTUPSENS_CS1 (0x01 << 2)
+#define SX9310_REG_PROX_CTRL5_RAWFILT_MASK GENMASK(1, 0)
+#define SX9310_REG_PROX_CTRL5_RAWFILT_SHIFT 0
#define SX9310_REG_PROX_CTRL5_RAWFILT_1P25 0x02
#define SX9310_REG_PROX_CTRL6 0x16
#define SX9310_REG_PROX_CTRL6_AVGTHRESH_DEFAULT 0x20
#define SX9310_REG_PROX_CTRL7 0x17
#define SX9310_REG_PROX_CTRL7_AVGNEGFILT_2 (0x01 << 3)
+#define SX9310_REG_PROX_CTRL7_AVGPOSFILT_MASK GENMASK(2, 0)
+#define SX9310_REG_PROX_CTRL7_AVGPOSFILT_SHIFT 0
#define SX9310_REG_PROX_CTRL7_AVGPOSFILT_512 0x05
#define SX9310_REG_PROX_CTRL8 0x18
+#define SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK GENMASK(7, 3)
#define SX9310_REG_PROX_CTRL9 0x19
#define SX9310_REG_PROX_CTRL8_9_PTHRESH_28 (0x08 << 3)
#define SX9310_REG_PROX_CTRL8_9_PTHRESH_96 (0x11 << 3)
#define SX9310_REG_PROX_CTRL8_9_BODYTHRESH_900 0x03
#define SX9310_REG_PROX_CTRL8_9_BODYTHRESH_1500 0x05
#define SX9310_REG_PROX_CTRL10 0x1a
+#define SX9310_REG_PROX_CTRL10_HYST_MASK GENMASK(5, 4)
#define SX9310_REG_PROX_CTRL10_HYST_6PCT (0x01 << 4)
+#define SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK GENMASK(3, 2)
+#define SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK GENMASK(1, 0)
#define SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_2 0x01
#define SX9310_REG_PROX_CTRL11 0x1b
#define SX9310_REG_PROX_CTRL12 0x1c
@@ -144,16 +170,31 @@ struct sx9310_data {
static const struct iio_event_spec sx9310_events[] = {
{
.type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_EITHER,
- .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE) |
+ BIT(IIO_EV_INFO_HYSTERESIS) |
+ BIT(IIO_EV_INFO_VALUE),
},
};
#define SX9310_NAMED_CHANNEL(idx, name) \
{ \
.type = IIO_PROXIMITY, \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_HARDWAREGAIN), \
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_separate_available = \
+ BIT(IIO_CHAN_INFO_HARDWAREGAIN), \
.indexed = 1, \
.channel = idx, \
.extend_name = name, \
@@ -426,6 +467,34 @@ out:
return ret;
}
+static int sx9310_read_gain(struct sx9310_data *data,
+ const struct iio_chan_spec *chan, int *val)
+{
+ unsigned int regval, gain;
+ int ret;
+
+ ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL3, &regval);
+ if (ret)
+ return ret;
+
+ switch (chan->channel) {
+ case 0:
+ case 3:
+ gain = FIELD_GET(SX9310_REG_PROX_CTRL3_GAIN0_MASK, regval);
+ break;
+ case 1:
+ case 2:
+ gain = FIELD_GET(SX9310_REG_PROX_CTRL3_GAIN12_MASK, regval);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *val = 1 << gain;
+
+ return IIO_VAL_INT;
+}
+
static int sx9310_read_samp_freq(struct sx9310_data *data, int *val, int *val2)
{
unsigned int regval;
@@ -461,6 +530,14 @@ static int sx9310_read_raw(struct iio_dev *indio_dev,
ret = sx9310_read_proximity(data, chan, val);
iio_device_release_direct_mode(indio_dev);
return ret;
+ case IIO_CHAN_INFO_HARDWAREGAIN:
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = sx9310_read_gain(data, chan, val);
+ iio_device_release_direct_mode(indio_dev);
+ return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
return sx9310_read_samp_freq(data, val, val2);
default:
@@ -468,6 +545,283 @@ static int sx9310_read_raw(struct iio_dev *indio_dev,
}
}
+static const int sx9310_gain_vals[] = { 1, 2, 4, 8 };
+
+static int sx9310_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ if (chan->type != IIO_PROXIMITY)
+ return -EINVAL;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_HARDWAREGAIN:
+ *type = IIO_VAL_INT;
+ *length = ARRAY_SIZE(sx9310_gain_vals);
+ *vals = sx9310_gain_vals;
+ return IIO_AVAIL_LIST;
+ }
+
+ return -EINVAL;
+}
+
+static const unsigned int sx9310_pthresh_codes[] = {
+ 2, 4, 6, 8, 12, 16, 20, 24, 28, 32, 40, 48, 56, 64, 72, 80, 88, 96, 112,
+ 128, 144, 160, 192, 224, 256, 320, 384, 512, 640, 768, 1024, 1536
+};
+
+static int sx9310_get_thresh_reg(unsigned int channel)
+{
+ switch (channel) {
+ case 0:
+ case 3:
+ return SX9310_REG_PROX_CTRL8;
+ case 1:
+ case 2:
+ return SX9310_REG_PROX_CTRL9;
+ }
+
+ return -EINVAL;
+}
+
+static int sx9310_read_thresh(struct sx9310_data *data,
+ const struct iio_chan_spec *chan, int *val)
+{
+ unsigned int reg;
+ unsigned int regval;
+ int ret;
+
+ reg = ret = sx9310_get_thresh_reg(chan->channel);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(data->regmap, reg, &regval);
+ if (ret)
+ return ret;
+
+ regval = FIELD_GET(SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval);
+ if (regval > ARRAY_SIZE(sx9310_pthresh_codes))
+ return -EINVAL;
+
+ *val = sx9310_pthresh_codes[regval];
+ return IIO_VAL_INT;
+}
+
+static int sx9310_read_hysteresis(struct sx9310_data *data,
+ const struct iio_chan_spec *chan, int *val)
+{
+ unsigned int regval, pthresh;
+ int ret;
+
+ ret = sx9310_read_thresh(data, chan, &pthresh);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL10, &regval);
+ if (ret)
+ return ret;
+
+ regval = FIELD_GET(SX9310_REG_PROX_CTRL10_HYST_MASK, regval);
+ if (!regval)
+ regval = 5;
+
+ /* regval is at most 5 */
+ *val = pthresh >> (5 - regval);
+
+ return IIO_VAL_INT;
+}
+
+static int sx9310_read_far_debounce(struct sx9310_data *data, int *val)
+{
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL10, &regval);
+ if (ret)
+ return ret;
+
+ regval = FIELD_GET(SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, regval);
+ if (regval)
+ *val = 1 << regval;
+ else
+ *val = 0;
+
+ return IIO_VAL_INT;
+}
+
+static int sx9310_read_close_debounce(struct sx9310_data *data, int *val)
+{
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL10, &regval);
+ if (ret)
+ return ret;
+
+ regval = FIELD_GET(SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, regval);
+ if (regval)
+ *val = 1 << regval;
+ else
+ *val = 0;
+
+ return IIO_VAL_INT;
+}
+
+static int sx9310_read_event_val(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 sx9310_data *data = iio_priv(indio_dev);
+
+ if (chan->type != IIO_PROXIMITY)
+ return -EINVAL;
+
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ return sx9310_read_thresh(data, chan, val);
+ case IIO_EV_INFO_PERIOD:
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ return sx9310_read_far_debounce(data, val);
+ case IIO_EV_DIR_FALLING:
+ return sx9310_read_close_debounce(data, val);
+ default:
+ return -EINVAL;
+ }
+ case IIO_EV_INFO_HYSTERESIS:
+ return sx9310_read_hysteresis(data, chan, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int sx9310_write_thresh(struct sx9310_data *data,
+ const struct iio_chan_spec *chan, int val)
+{
+ unsigned int reg;
+ unsigned int regval;
+ int ret, i;
+
+ reg = ret = sx9310_get_thresh_reg(chan->channel);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(sx9310_pthresh_codes); i++) {
+ if (sx9310_pthresh_codes[i] == val) {
+ regval = i;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(sx9310_pthresh_codes))
+ return -EINVAL;
+
+ regval = FIELD_PREP(SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval);
+ mutex_lock(&data->mutex);
+ ret = regmap_update_bits(data->regmap, reg,
+ SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int sx9310_write_hysteresis(struct sx9310_data *data,
+ const struct iio_chan_spec *chan, int _val)
+{
+ unsigned int hyst, val = _val;
+ int ret, pthresh;
+
+ ret = sx9310_read_thresh(data, chan, &pthresh);
+ if (ret < 0)
+ return ret;
+
+ if (val == 0)
+ hyst = 0;
+ else if (val == pthresh >> 2)
+ hyst = 3;
+ else if (val == pthresh >> 3)
+ hyst = 2;
+ else if (val == pthresh >> 4)
+ hyst = 1;
+ else
+ return -EINVAL;
+
+ hyst = FIELD_PREP(SX9310_REG_PROX_CTRL10_HYST_MASK, hyst);
+ mutex_lock(&data->mutex);
+ ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10,
+ SX9310_REG_PROX_CTRL10_HYST_MASK, hyst);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int sx9310_write_far_debounce(struct sx9310_data *data, int val)
+{
+ int ret;
+ unsigned int regval;
+
+ val = ilog2(val);
+ regval = FIELD_PREP(SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, val);
+
+ mutex_lock(&data->mutex);
+ ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10,
+ SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK,
+ regval);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int sx9310_write_close_debounce(struct sx9310_data *data, int val)
+{
+ int ret;
+ unsigned int regval;
+
+ val = ilog2(val);
+ regval = FIELD_PREP(SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, val);
+
+ mutex_lock(&data->mutex);
+ ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10,
+ SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK,
+ regval);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int sx9310_write_event_val(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 sx9310_data *data = iio_priv(indio_dev);
+
+ if (chan->type != IIO_PROXIMITY)
+ return -EINVAL;
+
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ return sx9310_write_thresh(data, chan, val);
+ case IIO_EV_INFO_PERIOD:
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ return sx9310_write_far_debounce(data, val);
+ case IIO_EV_DIR_FALLING:
+ return sx9310_write_close_debounce(data, val);
+ default:
+ return -EINVAL;
+ }
+ case IIO_EV_INFO_HYSTERESIS:
+ return sx9310_write_hysteresis(data, chan, val);
+ default:
+ return -EINVAL;
+ }
+}
+
static int sx9310_set_samp_freq(struct sx9310_data *data, int val, int val2)
{
int i, ret;
@@ -492,6 +846,37 @@ static int sx9310_set_samp_freq(struct sx9310_data *data, int val, int val2)
return ret;
}
+static int sx9310_write_gain(struct sx9310_data *data,
+ const struct iio_chan_spec *chan, int val)
+{
+ unsigned int gain, mask;
+ int ret;
+
+ gain = ilog2(val);
+
+ switch (chan->channel) {
+ case 0:
+ case 3:
+ mask = SX9310_REG_PROX_CTRL3_GAIN0_MASK;
+ gain = FIELD_PREP(SX9310_REG_PROX_CTRL3_GAIN0_MASK, gain);
+ break;
+ case 1:
+ case 2:
+ mask = SX9310_REG_PROX_CTRL3_GAIN12_MASK;
+ gain = FIELD_PREP(SX9310_REG_PROX_CTRL3_GAIN12_MASK, gain);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mutex_lock(&data->mutex);
+ ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL3, mask,
+ gain);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
static int sx9310_write_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int val, int val2,
long mask)
@@ -501,10 +886,14 @@ static int sx9310_write_raw(struct iio_dev *indio_dev,
if (chan->type != IIO_PROXIMITY)
return -EINVAL;
- if (mask != IIO_CHAN_INFO_SAMP_FREQ)
- return -EINVAL;
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return sx9310_set_samp_freq(data, val, val2);
+ case IIO_CHAN_INFO_HARDWAREGAIN:
+ return sx9310_write_gain(data, chan, val);
+ }
- return sx9310_set_samp_freq(data, val, val2);
+ return -EINVAL;
}
static irqreturn_t sx9310_irq_handler(int irq, void *private)
@@ -645,6 +1034,9 @@ static const struct attribute_group sx9310_attribute_group = {
static const struct iio_info sx9310_info = {
.attrs = &sx9310_attribute_group,
.read_raw = sx9310_read_raw,
+ .read_avail = sx9310_read_avail,
+ .read_event_value = sx9310_read_event_val,
+ .write_event_value = sx9310_write_event_val,
.write_raw = sx9310_write_raw,
.read_event_config = sx9310_read_event_config,
.write_event_config = sx9310_write_event_config,
@@ -820,9 +1212,113 @@ static int sx9310_init_compensation(struct iio_dev *indio_dev)
return ret;
}
+static const struct sx9310_reg_default *
+sx9310_get_default_reg(struct sx9310_data *data, int i,
+ struct sx9310_reg_default *reg_def)
+{
+ int ret;
+ const struct device_node *np = data->client->dev.of_node;
+ u32 combined[SX9310_NUM_CHANNELS] = { 4, 4, 4, 4 };
+ unsigned long comb_mask = 0;
+ const char *res;
+ u32 start = 0, raw = 0, pos = 0;
+
+ memcpy(reg_def, &sx9310_default_regs[i], sizeof(*reg_def));
+ if (!np)
+ return reg_def;
+
+ switch (reg_def->reg) {
+ case SX9310_REG_PROX_CTRL2:
+ if (of_property_read_bool(np, "semtech,cs0-ground")) {
+ reg_def->def &= ~SX9310_REG_PROX_CTRL2_SHIELDEN_MASK;
+ reg_def->def |= SX9310_REG_PROX_CTRL2_SHIELDEN_GROUND;
+ }
+
+ reg_def->def &= ~SX9310_REG_PROX_CTRL2_COMBMODE_MASK;
+ of_property_read_u32_array(np, "semtech,combined-sensors",
+ combined, ARRAY_SIZE(combined));
+ for (i = 0; i < ARRAY_SIZE(combined); i++) {
+ if (combined[i] <= SX9310_NUM_CHANNELS)
+ comb_mask |= BIT(combined[i]);
+ }
+
+ comb_mask &= 0xf;
+ if (comb_mask == (BIT(3) | BIT(2) | BIT(1) | BIT(0)))
+ reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1_CS2_CS3;
+ else if (comb_mask == (BIT(1) | BIT(2)))
+ reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS1_CS2;
+ else if (comb_mask == (BIT(0) | BIT(1)))
+ reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1;
+ else if (comb_mask == BIT(3))
+ reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS3;
+
+ break;
+ case SX9310_REG_PROX_CTRL4:
+ ret = of_property_read_string(np, "semtech,resolution", &res);
+ if (ret)
+ break;
+
+ reg_def->def &= ~SX9310_REG_PROX_CTRL4_RESOLUTION_MASK;
+ if (!strcmp(res, "coarsest"))
+ reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_COARSEST;
+ else if (!strcmp(res, "very-coarse"))
+ reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_VERY_COARSE;
+ else if (!strcmp(res, "coarse"))
+ reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_COARSE;
+ else if (!strcmp(res, "medium-coarse"))
+ reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_MEDIUM_COARSE;
+ else if (!strcmp(res, "medium"))
+ reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_MEDIUM;
+ else if (!strcmp(res, "fine"))
+ reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_FINE;
+ else if (!strcmp(res, "very-fine"))
+ reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_VERY_FINE;
+ else if (!strcmp(res, "finest"))
+ reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_FINEST;
+
+ break;
+ case SX9310_REG_PROX_CTRL5:
+ ret = of_property_read_u32(np, "semtech,startup-sensor", &start);
+ if (ret) {
+ start = FIELD_GET(SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK,
+ reg_def->def);
+ }
+
+ reg_def->def &= ~SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK;
+ reg_def->def |= FIELD_PREP(SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK,
+ start);
+
+ ret = of_property_read_u32(np, "semtech,proxraw-strength", &raw);
+ if (ret) {
+ raw = FIELD_GET(SX9310_REG_PROX_CTRL5_RAWFILT_MASK,
+ reg_def->def);
+ } else {
+ raw = ilog2(raw);
+ }
+
+ reg_def->def &= ~SX9310_REG_PROX_CTRL5_RAWFILT_MASK;
+ reg_def->def |= FIELD_PREP(SX9310_REG_PROX_CTRL5_RAWFILT_MASK,
+ raw);
+ break;
+ case SX9310_REG_PROX_CTRL7:
+ ret = of_property_read_u32(np, "semtech,avg-pos-strength", &pos);
+ if (ret)
+ break;
+
+ pos = min(max(ilog2(pos), 3), 10) - 3;
+ reg_def->def &= ~SX9310_REG_PROX_CTRL7_AVGPOSFILT_MASK;
+ reg_def->def |= FIELD_PREP(SX9310_REG_PROX_CTRL7_AVGPOSFILT_MASK,
+ pos);
+ break;
+ }
+
+ return reg_def;
+}
+
static int sx9310_init_device(struct iio_dev *indio_dev)
{
struct sx9310_data *data = iio_priv(indio_dev);
+ struct sx9310_reg_default tmp;
const struct sx9310_reg_default *initval;
int ret;
unsigned int i, val;
@@ -840,7 +1336,7 @@ static int sx9310_init_device(struct iio_dev *indio_dev)
/* Program some sane defaults. */
for (i = 0; i < ARRAY_SIZE(sx9310_default_regs); i++) {
- initval = &sx9310_default_regs[i];
+ initval = sx9310_get_default_reg(data, i, &tmp);
ret = regmap_write(data->regmap, initval->reg, initval->def);
if (ret)
return ret;
diff --git a/drivers/iio/proximity/vl53l0x-i2c.c b/drivers/iio/proximity/vl53l0x-i2c.c
index 235e125aeb3a..cf38144b6f95 100644
--- a/drivers/iio/proximity/vl53l0x-i2c.c
+++ b/drivers/iio/proximity/vl53l0x-i2c.c
@@ -225,6 +225,12 @@ static int vl53l0x_probe(struct i2c_client *client)
return devm_iio_device_register(&client->dev, indio_dev);
}
+static const struct i2c_device_id vl53l0x_id[] = {
+ { "vl53l0x", 0},
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, vl53l0x_id);
+
static const struct of_device_id st_vl53l0x_dt_match[] = {
{ .compatible = "st,vl53l0x", },
{ }
@@ -237,6 +243,7 @@ static struct i2c_driver vl53l0x_driver = {
.of_match_table = st_vl53l0x_dt_match,
},
.probe_new = vl53l0x_probe,
+ .id_table = vl53l0x_id,
};
module_i2c_driver(vl53l0x_driver);
diff --git a/drivers/iio/trigger/iio-trig-hrtimer.c b/drivers/iio/trigger/iio-trig-hrtimer.c
index f59bf8d58586..410de837d041 100644
--- a/drivers/iio/trigger/iio-trig-hrtimer.c
+++ b/drivers/iio/trigger/iio-trig-hrtimer.c
@@ -102,7 +102,7 @@ static int iio_trig_hrtimer_set_state(struct iio_trigger *trig, bool state)
if (state)
hrtimer_start(&trig_info->timer, trig_info->period,
- HRTIMER_MODE_REL);
+ HRTIMER_MODE_REL_HARD);
else
hrtimer_cancel(&trig_info->timer);
@@ -132,7 +132,7 @@ static struct iio_sw_trigger *iio_trig_hrtimer_probe(const char *name)
trig_info->swt.trigger->ops = &iio_hrtimer_trigger_ops;
trig_info->swt.trigger->dev.groups = iio_hrtimer_attr_groups;
- hrtimer_init(&trig_info->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ hrtimer_init(&trig_info->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
trig_info->timer.function = iio_hrtimer_trig_handler;
trig_info->sampling_frequency = HRTIMER_DEFAULT_SAMPLING_FREQUENCY;
diff --git a/drivers/iio/trigger/iio-trig-sysfs.c b/drivers/iio/trigger/iio-trig-sysfs.c
index e09e58072872..0f6b512a5c37 100644
--- a/drivers/iio/trigger/iio-trig-sysfs.c
+++ b/drivers/iio/trigger/iio-trig-sysfs.c
@@ -160,7 +160,7 @@ static int iio_sysfs_trigger_probe(int id)
t->trig->dev.parent = &iio_sysfs_trig_dev;
iio_trigger_set_drvdata(t->trig, t);
- init_irq_work(&t->work, iio_sysfs_trigger_work);
+ t->work = IRQ_WORK_INIT_HARD(iio_sysfs_trigger_work);
ret = iio_trigger_register(t->trig);
if (ret)