summaryrefslogtreecommitdiffstats
path: root/drivers/iio/adc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/adc')
-rw-r--r--drivers/iio/adc/Kconfig32
-rw-r--r--drivers/iio/adc/Makefile3
-rw-r--r--drivers/iio/adc/ad7766.c6
-rw-r--r--drivers/iio/adc/at91-sama5d2_adc.c329
-rw-r--r--drivers/iio/adc/at91_adc.c2
-rw-r--r--drivers/iio/adc/dln2-adc.c722
-rw-r--r--drivers/iio/adc/ep93xx_adc.c255
-rw-r--r--drivers/iio/adc/ina2xx-adc.c36
-rw-r--r--drivers/iio/adc/ltc2471.c160
-rw-r--r--drivers/iio/adc/ltc2497.c54
-rw-r--r--drivers/iio/adc/max9611.c4
-rw-r--r--drivers/iio/adc/mcp3422.c6
-rw-r--r--drivers/iio/adc/meson_saradc.c13
-rw-r--r--drivers/iio/adc/mt6577_auxadc.c37
-rw-r--r--drivers/iio/adc/rockchip_saradc.c5
-rw-r--r--drivers/iio/adc/stm32-adc-core.c2
-rw-r--r--drivers/iio/adc/ti-ads1015.c16
17 files changed, 1617 insertions, 65 deletions
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 614fa41559b1..e4eeebac5297 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -239,6 +239,15 @@ config DA9150_GPADC
To compile this driver as a module, choose M here: the module will be
called berlin2-adc.
+config DLN2_ADC
+ tristate "Diolan DLN-2 ADC driver support"
+ depends on MFD_DLN2
+ help
+ Say yes here to build support for Diolan DLN-2 ADC.
+
+ This driver can also be built as a module. If so, the module will be
+ called adc_dln2.
+
config ENVELOPE_DETECTOR
tristate "Envelope detector using a DAC and a comparator"
depends on OF
@@ -249,6 +258,17 @@ config ENVELOPE_DETECTOR
To compile this driver as a module, choose M here: the module will be
called envelope-detector.
+config EP93XX_ADC
+ tristate "Cirrus Logic EP93XX ADC driver"
+ depends on ARCH_EP93XX
+ help
+ Driver for the ADC module on the EP93XX series of SoC from Cirrus Logic.
+ It's recommended to switch on CONFIG_HIGH_RES_TIMERS option, in this
+ case driver will reduce its CPU usage by 90% in some use cases.
+
+ To compile this driver as a module, choose M here: the module will be
+ called ep93xx_adc.
+
config EXYNOS_ADC
tristate "Exynos ADC driver support"
depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
@@ -322,7 +342,7 @@ config INA2XX_ADC
This driver is mutually exclusive with the HWMON version.
config IMX7D_ADC
- tristate "IMX7D ADC driver"
+ tristate "Freescale IMX7D ADC driver"
depends on ARCH_MXC || COMPILE_TEST
depends on HAS_IOMEM
help
@@ -362,6 +382,16 @@ config LPC32XX_ADC
activate only one via device tree selection. Provides direct access
via sysfs.
+config LTC2471
+ tristate "Linear Technology LTC2471 and LTC2473 ADC driver"
+ depends on I2C
+ help
+ Say yes here to build support for Linear Technology LTC2471 and
+ LTC2473 16-bit I2C ADC.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc2471.
+
config LTC2485
tristate "Linear Technology LTC2485 ADC driver"
depends on I2C
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index b546736a5541..9874e05f52d7 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -24,7 +24,9 @@ obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o
obj-$(CONFIG_CPCAP_ADC) += cpcap-adc.o
obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
+obj-$(CONFIG_DLN2_ADC) += dln2-adc.o
obj-$(CONFIG_ENVELOPE_DETECTOR) += envelope-detector.o
+obj-$(CONFIG_EP93XX_ADC) += ep93xx_adc.o
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
obj-$(CONFIG_FSL_MX25_ADC) += fsl-imx25-gcq.o
obj-$(CONFIG_HI8435) += hi8435.o
@@ -34,6 +36,7 @@ obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
+obj-$(CONFIG_LTC2471) += ltc2471.o
obj-$(CONFIG_LTC2485) += ltc2485.o
obj-$(CONFIG_LTC2497) += ltc2497.o
obj-$(CONFIG_MAX1027) += max1027.o
diff --git a/drivers/iio/adc/ad7766.c b/drivers/iio/adc/ad7766.c
index 75cca42b6e70..ce45037295d8 100644
--- a/drivers/iio/adc/ad7766.c
+++ b/drivers/iio/adc/ad7766.c
@@ -103,8 +103,7 @@ static int ad7766_preenable(struct iio_dev *indio_dev)
return ret;
}
- if (ad7766->pd_gpio)
- gpiod_set_value(ad7766->pd_gpio, 0);
+ gpiod_set_value(ad7766->pd_gpio, 0);
return 0;
}
@@ -113,8 +112,7 @@ static int ad7766_postdisable(struct iio_dev *indio_dev)
{
struct ad7766 *ad7766 = iio_priv(indio_dev);
- if (ad7766->pd_gpio)
- gpiod_set_value(ad7766->pd_gpio, 1);
+ gpiod_set_value(ad7766->pd_gpio, 1);
/*
* The PD pin is synchronous to the clock, so give it some time to
diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
index e10dca3ed74b..bc5b38e3a147 100644
--- a/drivers/iio/adc/at91-sama5d2_adc.c
+++ b/drivers/iio/adc/at91-sama5d2_adc.c
@@ -25,6 +25,11 @@
#include <linux/wait.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/regulator/consumer.h>
/* Control Register */
@@ -132,6 +137,17 @@
#define AT91_SAMA5D2_PRESSR 0xbc
/* Trigger Register */
#define AT91_SAMA5D2_TRGR 0xc0
+/* Mask for TRGMOD field of TRGR register */
+#define AT91_SAMA5D2_TRGR_TRGMOD_MASK GENMASK(2, 0)
+/* No trigger, only software trigger can start conversions */
+#define AT91_SAMA5D2_TRGR_TRGMOD_NO_TRIGGER 0
+/* Trigger Mode external trigger rising edge */
+#define AT91_SAMA5D2_TRGR_TRGMOD_EXT_TRIG_RISE 1
+/* Trigger Mode external trigger falling edge */
+#define AT91_SAMA5D2_TRGR_TRGMOD_EXT_TRIG_FALL 2
+/* Trigger Mode external trigger any edge */
+#define AT91_SAMA5D2_TRGR_TRGMOD_EXT_TRIG_ANY 3
+
/* Correction Select Register */
#define AT91_SAMA5D2_COSR 0xd0
/* Correction Value Register */
@@ -145,14 +161,29 @@
/* Version Register */
#define AT91_SAMA5D2_VERSION 0xfc
+#define AT91_SAMA5D2_HW_TRIG_CNT 3
+#define AT91_SAMA5D2_SINGLE_CHAN_CNT 12
+#define AT91_SAMA5D2_DIFF_CHAN_CNT 6
+
+/*
+ * Maximum number of bytes to hold conversion from all channels
+ * plus the timestamp
+ */
+#define AT91_BUFFER_MAX_BYTES ((AT91_SAMA5D2_SINGLE_CHAN_CNT + \
+ AT91_SAMA5D2_DIFF_CHAN_CNT) * 2 + 8)
+
+#define AT91_BUFFER_MAX_HWORDS (AT91_BUFFER_MAX_BYTES / 2)
+
#define AT91_SAMA5D2_CHAN_SINGLE(num, addr) \
{ \
.type = IIO_VOLTAGE, \
.channel = num, \
.address = addr, \
+ .scan_index = num, \
.scan_type = { \
.sign = 'u', \
.realbits = 12, \
+ .storagebits = 16, \
}, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
@@ -168,9 +199,11 @@
.channel = num, \
.channel2 = num2, \
.address = addr, \
+ .scan_index = num + AT91_SAMA5D2_SINGLE_CHAN_CNT, \
.scan_type = { \
.sign = 's', \
.realbits = 12, \
+ .storagebits = 16, \
}, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
@@ -188,6 +221,12 @@ struct at91_adc_soc_info {
unsigned max_sample_rate;
};
+struct at91_adc_trigger {
+ char *name;
+ unsigned int trgmod_value;
+ unsigned int edge_type;
+};
+
struct at91_adc_state {
void __iomem *base;
int irq;
@@ -195,11 +234,14 @@ struct at91_adc_state {
struct regulator *reg;
struct regulator *vref;
int vref_uv;
+ struct iio_trigger *trig;
+ const struct at91_adc_trigger *selected_trig;
const struct iio_chan_spec *chan;
bool conversion_done;
u32 conversion_value;
struct at91_adc_soc_info soc_info;
wait_queue_head_t wq_data_available;
+ u16 buffer[AT91_BUFFER_MAX_HWORDS];
/*
* lock to prevent concurrent 'single conversion' requests through
* sysfs.
@@ -207,6 +249,24 @@ struct at91_adc_state {
struct mutex lock;
};
+static const struct at91_adc_trigger at91_adc_trigger_list[] = {
+ {
+ .name = "external_rising",
+ .trgmod_value = AT91_SAMA5D2_TRGR_TRGMOD_EXT_TRIG_RISE,
+ .edge_type = IRQ_TYPE_EDGE_RISING,
+ },
+ {
+ .name = "external_falling",
+ .trgmod_value = AT91_SAMA5D2_TRGR_TRGMOD_EXT_TRIG_FALL,
+ .edge_type = IRQ_TYPE_EDGE_FALLING,
+ },
+ {
+ .name = "external_any",
+ .trgmod_value = AT91_SAMA5D2_TRGR_TRGMOD_EXT_TRIG_ANY,
+ .edge_type = IRQ_TYPE_EDGE_BOTH,
+ },
+};
+
static const struct iio_chan_spec at91_adc_channels[] = {
AT91_SAMA5D2_CHAN_SINGLE(0, 0x50),
AT91_SAMA5D2_CHAN_SINGLE(1, 0x54),
@@ -226,12 +286,132 @@ static const struct iio_chan_spec at91_adc_channels[] = {
AT91_SAMA5D2_CHAN_DIFF(6, 7, 0x68),
AT91_SAMA5D2_CHAN_DIFF(8, 9, 0x70),
AT91_SAMA5D2_CHAN_DIFF(10, 11, 0x78),
+ IIO_CHAN_SOFT_TIMESTAMP(AT91_SAMA5D2_SINGLE_CHAN_CNT
+ + AT91_SAMA5D2_DIFF_CHAN_CNT + 1),
+};
+
+static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
+{
+ struct iio_dev *indio = iio_trigger_get_drvdata(trig);
+ struct at91_adc_state *st = iio_priv(indio);
+ u32 status = at91_adc_readl(st, AT91_SAMA5D2_TRGR);
+ u8 bit;
+
+ /* clear TRGMOD */
+ status &= ~AT91_SAMA5D2_TRGR_TRGMOD_MASK;
+
+ if (state)
+ status |= st->selected_trig->trgmod_value;
+
+ /* set/unset hw trigger */
+ at91_adc_writel(st, AT91_SAMA5D2_TRGR, status);
+
+ for_each_set_bit(bit, indio->active_scan_mask, indio->num_channels) {
+ struct iio_chan_spec const *chan = indio->channels + bit;
+
+ if (state) {
+ at91_adc_writel(st, AT91_SAMA5D2_CHER,
+ BIT(chan->channel));
+ at91_adc_writel(st, AT91_SAMA5D2_IER,
+ BIT(chan->channel));
+ } else {
+ at91_adc_writel(st, AT91_SAMA5D2_IDR,
+ BIT(chan->channel));
+ at91_adc_writel(st, AT91_SAMA5D2_CHDR,
+ BIT(chan->channel));
+ }
+ }
+
+ return 0;
+}
+
+static int 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);
+
+ 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 = {
+ .owner = THIS_MODULE,
+ .set_trigger_state = &at91_adc_configure_trigger,
+ .try_reenable = &at91_adc_reenable_trigger,
};
+static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *indio,
+ char *trigger_name)
+{
+ struct iio_trigger *trig;
+ int ret;
+
+ trig = devm_iio_trigger_alloc(&indio->dev, "%s-dev%d-%s", indio->name,
+ indio->id, trigger_name);
+ if (!trig)
+ return NULL;
+
+ trig->dev.parent = indio->dev.parent;
+ iio_trigger_set_drvdata(trig, indio);
+ trig->ops = &at91_adc_trigger_ops;
+
+ ret = devm_iio_trigger_register(&indio->dev, trig);
+ if (ret)
+ return ERR_PTR(ret);
+
+ 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 irqreturn_t at91_adc_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio = pf->indio_dev;
+ struct at91_adc_state *st = iio_priv(indio);
+ int i = 0;
+ u8 bit;
+
+ for_each_set_bit(bit, indio->active_scan_mask, indio->num_channels) {
+ struct iio_chan_spec const *chan = indio->channels + bit;
+
+ st->buffer[i] = at91_adc_readl(st, chan->address);
+ i++;
+ }
+
+ iio_push_to_buffers_with_timestamp(indio, st->buffer, pf->timestamp);
+
+ iio_trigger_notify_done(indio->trig);
+
+ 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, NULL);
+}
+
static unsigned at91_adc_startup_time(unsigned startup_time_min,
unsigned adc_clk_khz)
{
- const unsigned startup_lookup[] = {
+ static const unsigned int startup_lookup[] = {
0, 8, 16, 24,
64, 80, 96, 112,
512, 576, 640, 704,
@@ -293,14 +473,18 @@ static irqreturn_t at91_adc_interrupt(int irq, void *private)
u32 status = at91_adc_readl(st, AT91_SAMA5D2_ISR);
u32 imr = at91_adc_readl(st, AT91_SAMA5D2_IMR);
- if (status & imr) {
+ if (!(status & imr))
+ return IRQ_NONE;
+
+ if (iio_buffer_enabled(indio)) {
+ disable_irq_nosync(irq);
+ iio_trigger_poll(indio->trig);
+ } else {
st->conversion_value = at91_adc_readl(st, st->chan->address);
st->conversion_done = true;
wake_up_interruptible(&st->wq_data_available);
- return IRQ_HANDLED;
}
-
- return IRQ_NONE;
+ return IRQ_HANDLED;
}
static int at91_adc_read_raw(struct iio_dev *indio_dev,
@@ -313,6 +497,11 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
+ /* we cannot use software trigger if hw trigger enabled */
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
mutex_lock(&st->lock);
st->chan = chan;
@@ -344,6 +533,8 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,
at91_adc_writel(st, AT91_SAMA5D2_CHDR, BIT(chan->channel));
mutex_unlock(&st->lock);
+
+ iio_device_release_direct_mode(indio_dev);
return ret;
case IIO_CHAN_INFO_SCALE:
@@ -386,12 +577,27 @@ static const struct iio_info at91_adc_info = {
.driver_module = THIS_MODULE,
};
+static void at91_adc_hw_init(struct at91_adc_state *st)
+{
+ at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_SWRST);
+ at91_adc_writel(st, AT91_SAMA5D2_IDR, 0xffffffff);
+ /*
+ * Transfer field must be set to 2 according to the datasheet and
+ * allows different analog settings for each channel.
+ */
+ at91_adc_writel(st, AT91_SAMA5D2_MR,
+ AT91_SAMA5D2_MR_TRANSFER(2) | AT91_SAMA5D2_MR_ANACH);
+
+ at91_adc_setup_samp_freq(st, st->soc_info.min_sample_rate);
+}
+
static int at91_adc_probe(struct platform_device *pdev)
{
struct iio_dev *indio_dev;
struct at91_adc_state *st;
struct resource *res;
- int ret;
+ int ret, i;
+ u32 edge_type;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*st));
if (!indio_dev)
@@ -432,6 +638,27 @@ static int at91_adc_probe(struct platform_device *pdev)
return ret;
}
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "atmel,trigger-edge-type", &edge_type);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "invalid or missing value for atmel,trigger-edge-type\n");
+ return ret;
+ }
+
+ st->selected_trig = NULL;
+
+ for (i = 0; i < AT91_SAMA5D2_HW_TRIG_CNT; i++)
+ if (at91_adc_trigger_list[i].edge_type == edge_type) {
+ st->selected_trig = &at91_adc_trigger_list[i];
+ break;
+ }
+
+ if (!st->selected_trig) {
+ dev_err(&pdev->dev, "invalid external trigger edge value\n");
+ return -EINVAL;
+ }
+
init_waitqueue_head(&st->wq_data_available);
mutex_init(&st->lock);
@@ -482,16 +709,7 @@ static int at91_adc_probe(struct platform_device *pdev)
goto vref_disable;
}
- at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_SWRST);
- at91_adc_writel(st, AT91_SAMA5D2_IDR, 0xffffffff);
- /*
- * Transfer field must be set to 2 according to the datasheet and
- * allows different analog settings for each channel.
- */
- at91_adc_writel(st, AT91_SAMA5D2_MR,
- AT91_SAMA5D2_MR_TRANSFER(2) | AT91_SAMA5D2_MR_ANACH);
-
- at91_adc_setup_samp_freq(st, st->soc_info.min_sample_rate);
+ at91_adc_hw_init(st);
ret = clk_prepare_enable(st->per_clk);
if (ret)
@@ -499,10 +717,25 @@ 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");
+ goto per_clk_disable_unprepare;
+ }
+
+ 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;
+ }
+
ret = iio_device_register(indio_dev);
if (ret < 0)
goto per_clk_disable_unprepare;
+ dev_info(&pdev->dev, "setting up trigger as %s\n",
+ st->selected_trig->name);
+
dev_info(&pdev->dev, "version: %x\n",
readl_relaxed(st->base + AT91_SAMA5D2_VERSION));
@@ -532,6 +765,69 @@ static int at91_adc_remove(struct platform_device *pdev)
return 0;
}
+static __maybe_unused int at91_adc_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev =
+ platform_get_drvdata(to_platform_device(dev));
+ struct at91_adc_state *st = iio_priv(indio_dev);
+
+ /*
+ * Do a sofware reset of the ADC before we go to suspend.
+ * this will ensure that all pins are free from being muxed by the ADC
+ * and can be used by for other devices.
+ * Otherwise, ADC will hog them and we can't go to suspend mode.
+ */
+ at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_SWRST);
+
+ clk_disable_unprepare(st->per_clk);
+ regulator_disable(st->vref);
+ regulator_disable(st->reg);
+
+ return pinctrl_pm_select_sleep_state(dev);
+}
+
+static __maybe_unused int at91_adc_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev =
+ platform_get_drvdata(to_platform_device(dev));
+ struct at91_adc_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = pinctrl_pm_select_default_state(dev);
+ if (ret)
+ goto resume_failed;
+
+ ret = regulator_enable(st->reg);
+ if (ret)
+ goto resume_failed;
+
+ ret = regulator_enable(st->vref);
+ if (ret)
+ goto reg_disable_resume;
+
+ ret = clk_prepare_enable(st->per_clk);
+ if (ret)
+ goto vref_disable_resume;
+
+ at91_adc_hw_init(st);
+
+ /* reconfiguring trigger hardware state */
+ if (iio_buffer_enabled(indio_dev))
+ at91_adc_configure_trigger(st->trig, true);
+
+ return 0;
+
+vref_disable_resume:
+ regulator_disable(st->vref);
+reg_disable_resume:
+ regulator_disable(st->reg);
+resume_failed:
+ dev_err(&indio_dev->dev, "failed to resume\n");
+ return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(at91_adc_pm_ops, at91_adc_suspend, at91_adc_resume);
+
static const struct of_device_id at91_adc_dt_match[] = {
{
.compatible = "atmel,sama5d2-adc",
@@ -547,6 +843,7 @@ static struct platform_driver at91_adc_driver = {
.driver = {
.name = "at91-sama5d2_adc",
.of_match_table = at91_adc_dt_match,
+ .pm = &at91_adc_pm_ops,
},
};
module_platform_driver(at91_adc_driver)
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 34b928cefeed..15109728cae7 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -799,7 +799,7 @@ static u32 calc_startup_ticks_9x5(u32 startup_time, u32 adc_clk_khz)
* For sama5d3x and at91sam9x5, the formula changes to:
* Startup Time = <lookup_table_value> / ADC Clock
*/
- const int startup_lookup[] = {
+ static const int startup_lookup[] = {
0, 8, 16, 24,
64, 80, 96, 112,
512, 576, 640, 704,
diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c
new file mode 100644
index 000000000000..ab8d6aed5085
--- /dev/null
+++ b/drivers/iio/adc/dln2-adc.c
@@ -0,0 +1,722 @@
+/*
+ * Driver for the Diolan DLN-2 USB-ADC adapter
+ *
+ * Copyright (c) 2017 Jack Andersen
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/dln2.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+
+#define DLN2_ADC_MOD_NAME "dln2-adc"
+
+#define DLN2_ADC_ID 0x06
+
+#define DLN2_ADC_GET_CHANNEL_COUNT DLN2_CMD(0x01, DLN2_ADC_ID)
+#define DLN2_ADC_ENABLE DLN2_CMD(0x02, DLN2_ADC_ID)
+#define DLN2_ADC_DISABLE DLN2_CMD(0x03, DLN2_ADC_ID)
+#define DLN2_ADC_CHANNEL_ENABLE DLN2_CMD(0x05, DLN2_ADC_ID)
+#define DLN2_ADC_CHANNEL_DISABLE DLN2_CMD(0x06, DLN2_ADC_ID)
+#define DLN2_ADC_SET_RESOLUTION DLN2_CMD(0x08, DLN2_ADC_ID)
+#define DLN2_ADC_CHANNEL_GET_VAL DLN2_CMD(0x0A, DLN2_ADC_ID)
+#define DLN2_ADC_CHANNEL_GET_ALL_VAL DLN2_CMD(0x0B, DLN2_ADC_ID)
+#define DLN2_ADC_CHANNEL_SET_CFG DLN2_CMD(0x0C, DLN2_ADC_ID)
+#define DLN2_ADC_CHANNEL_GET_CFG DLN2_CMD(0x0D, DLN2_ADC_ID)
+#define DLN2_ADC_CONDITION_MET_EV DLN2_CMD(0x10, DLN2_ADC_ID)
+
+#define DLN2_ADC_EVENT_NONE 0
+#define DLN2_ADC_EVENT_BELOW 1
+#define DLN2_ADC_EVENT_LEVEL_ABOVE 2
+#define DLN2_ADC_EVENT_OUTSIDE 3
+#define DLN2_ADC_EVENT_INSIDE 4
+#define DLN2_ADC_EVENT_ALWAYS 5
+
+#define DLN2_ADC_MAX_CHANNELS 8
+#define DLN2_ADC_DATA_BITS 10
+
+/*
+ * Plays similar role to iio_demux_table in subsystem core; except allocated
+ * in a fixed 8-element array.
+ */
+struct dln2_adc_demux_table {
+ unsigned int from;
+ unsigned int to;
+ unsigned int length;
+};
+
+struct dln2_adc {
+ struct platform_device *pdev;
+ struct iio_chan_spec iio_channels[DLN2_ADC_MAX_CHANNELS + 1];
+ int port, trigger_chan;
+ struct iio_trigger *trig;
+ struct mutex mutex;
+ /* Cached sample period in milliseconds */
+ unsigned int sample_period;
+ /* Demux table */
+ unsigned int demux_count;
+ struct dln2_adc_demux_table demux[DLN2_ADC_MAX_CHANNELS];
+ /* Precomputed timestamp padding offset and length */
+ unsigned int ts_pad_offset, ts_pad_length;
+};
+
+struct dln2_adc_port_chan {
+ u8 port;
+ u8 chan;
+};
+
+struct dln2_adc_get_all_vals {
+ __le16 channel_mask;
+ __le16 values[DLN2_ADC_MAX_CHANNELS];
+};
+
+static void dln2_adc_add_demux(struct dln2_adc *dln2,
+ unsigned int in_loc, unsigned int out_loc,
+ unsigned int length)
+{
+ struct dln2_adc_demux_table *p = dln2->demux_count ?
+ &dln2->demux[dln2->demux_count - 1] : NULL;
+
+ if (p && p->from + p->length == in_loc &&
+ p->to + p->length == out_loc) {
+ p->length += length;
+ } else if (dln2->demux_count < DLN2_ADC_MAX_CHANNELS) {
+ p = &dln2->demux[dln2->demux_count++];
+ p->from = in_loc;
+ p->to = out_loc;
+ p->length = length;
+ }
+}
+
+static void dln2_adc_update_demux(struct dln2_adc *dln2)
+{
+ int in_ind = -1, out_ind;
+ unsigned int in_loc = 0, out_loc = 0;
+ struct iio_dev *indio_dev = platform_get_drvdata(dln2->pdev);
+
+ /* Clear out any old demux */
+ dln2->demux_count = 0;
+
+ /* Optimize all 8-channels case */
+ if (indio_dev->masklength &&
+ (*indio_dev->active_scan_mask & 0xff) == 0xff) {
+ dln2_adc_add_demux(dln2, 0, 0, 16);
+ dln2->ts_pad_offset = 0;
+ dln2->ts_pad_length = 0;
+ return;
+ }
+
+ /* Build demux table from fixed 8-channels to active_scan_mask */
+ for_each_set_bit(out_ind,
+ indio_dev->active_scan_mask,
+ indio_dev->masklength) {
+ /* Handle timestamp separately */
+ if (out_ind == DLN2_ADC_MAX_CHANNELS)
+ break;
+ for (++in_ind; in_ind != out_ind; ++in_ind)
+ in_loc += 2;
+ dln2_adc_add_demux(dln2, in_loc, out_loc, 2);
+ out_loc += 2;
+ in_loc += 2;
+ }
+
+ if (indio_dev->scan_timestamp) {
+ size_t ts_offset = indio_dev->scan_bytes / sizeof(int64_t) - 1;
+
+ dln2->ts_pad_offset = out_loc;
+ dln2->ts_pad_length = ts_offset * sizeof(int64_t) - out_loc;
+ } else {
+ dln2->ts_pad_offset = 0;
+ dln2->ts_pad_length = 0;
+ }
+}
+
+static int dln2_adc_get_chan_count(struct dln2_adc *dln2)
+{
+ int ret;
+ u8 port = dln2->port;
+ u8 count;
+ int olen = sizeof(count);
+
+ ret = dln2_transfer(dln2->pdev, DLN2_ADC_GET_CHANNEL_COUNT,
+ &port, sizeof(port), &count, &olen);
+ if (ret < 0) {
+ dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
+ return ret;
+ }
+ if (olen < sizeof(count))
+ return -EPROTO;
+
+ return count;
+}
+
+static int dln2_adc_set_port_resolution(struct dln2_adc *dln2)
+{
+ int ret;
+ struct dln2_adc_port_chan port_chan = {
+ .port = dln2->port,
+ .chan = DLN2_ADC_DATA_BITS,
+ };
+
+ ret = dln2_transfer_tx(dln2->pdev, DLN2_ADC_SET_RESOLUTION,
+ &port_chan, sizeof(port_chan));
+ if (ret < 0)
+ dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
+
+ return ret;
+}
+
+static int dln2_adc_set_chan_enabled(struct dln2_adc *dln2,
+ int channel, bool enable)
+{
+ int ret;
+ struct dln2_adc_port_chan port_chan = {
+ .port = dln2->port,
+ .chan = channel,
+ };
+ u16 cmd = enable ? DLN2_ADC_CHANNEL_ENABLE : DLN2_ADC_CHANNEL_DISABLE;
+
+ ret = dln2_transfer_tx(dln2->pdev, cmd, &port_chan, sizeof(port_chan));
+ if (ret < 0)
+ dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
+
+ return ret;
+}
+
+static int dln2_adc_set_port_enabled(struct dln2_adc *dln2, bool enable,
+ u16 *conflict_out)
+{
+ int ret;
+ u8 port = dln2->port;
+ __le16 conflict;
+ int olen = sizeof(conflict);
+ u16 cmd = enable ? DLN2_ADC_ENABLE : DLN2_ADC_DISABLE;
+
+ if (conflict_out)
+ *conflict_out = 0;
+
+ ret = dln2_transfer(dln2->pdev, cmd, &port, sizeof(port),
+ &conflict, &olen);
+ if (ret < 0) {
+ dev_dbg(&dln2->pdev->dev, "Problem in %s(%d)\n",
+ __func__, (int)enable);
+ if (conflict_out && enable && olen >= sizeof(conflict))
+ *conflict_out = le16_to_cpu(conflict);
+ return ret;
+ }
+ if (enable && olen < sizeof(conflict))
+ return -EPROTO;
+
+ return ret;
+}
+
+static int dln2_adc_set_chan_period(struct dln2_adc *dln2,
+ unsigned int channel, unsigned int period)
+{
+ int ret;
+ struct {
+ struct dln2_adc_port_chan port_chan;
+ __u8 type;
+ __le16 period;
+ __le16 low;
+ __le16 high;
+ } __packed set_cfg = {
+ .port_chan.port = dln2->port,
+ .port_chan.chan = channel,
+ .type = period ? DLN2_ADC_EVENT_ALWAYS : DLN2_ADC_EVENT_NONE,
+ .period = cpu_to_le16(period)
+ };
+
+ ret = dln2_transfer_tx(dln2->pdev, DLN2_ADC_CHANNEL_SET_CFG,
+ &set_cfg, sizeof(set_cfg));
+ if (ret < 0)
+ dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
+
+ return ret;
+}
+
+static int dln2_adc_read(struct dln2_adc *dln2, unsigned int channel)
+{
+ int ret, i;
+ struct iio_dev *indio_dev = platform_get_drvdata(dln2->pdev);
+ u16 conflict;
+ __le16 value;
+ int olen = sizeof(value);
+ struct dln2_adc_port_chan port_chan = {
+ .port = dln2->port,
+ .chan = channel,
+ };
+
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret < 0)
+ return ret;
+
+ ret = dln2_adc_set_chan_enabled(dln2, channel, true);
+ if (ret < 0)
+ goto release_direct;
+
+ ret = dln2_adc_set_port_enabled(dln2, true, &conflict);
+ if (ret < 0) {
+ if (conflict) {
+ dev_err(&dln2->pdev->dev,
+ "ADC pins conflict with mask %04X\n",
+ (int)conflict);
+ ret = -EBUSY;
+ }
+ goto disable_chan;
+ }
+
+ /*
+ * Call GET_VAL twice due to initial zero-return immediately after
+ * enabling channel.
+ */
+ for (i = 0; i < 2; ++i) {
+ ret = dln2_transfer(dln2->pdev, DLN2_ADC_CHANNEL_GET_VAL,
+ &port_chan, sizeof(port_chan),
+ &value, &olen);
+ if (ret < 0) {
+ dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
+ goto disable_port;
+ }
+ if (olen < sizeof(value)) {
+ ret = -EPROTO;
+ goto disable_port;
+ }
+ }
+
+ ret = le16_to_cpu(value);
+
+disable_port:
+ dln2_adc_set_port_enabled(dln2, false, NULL);
+disable_chan:
+ dln2_adc_set_chan_enabled(dln2, channel, false);
+release_direct:
+ iio_device_release_direct_mode(indio_dev);
+
+ return ret;
+}
+
+static int dln2_adc_read_all(struct dln2_adc *dln2,
+ struct dln2_adc_get_all_vals *get_all_vals)
+{
+ int ret;
+ __u8 port = dln2->port;
+ int olen = sizeof(*get_all_vals);
+
+ ret = dln2_transfer(dln2->pdev, DLN2_ADC_CHANNEL_GET_ALL_VAL,
+ &port, sizeof(port), get_all_vals, &olen);
+ if (ret < 0) {
+ dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
+ return ret;
+ }
+ if (olen < sizeof(*get_all_vals))
+ return -EPROTO;
+
+ return ret;
+}
+
+static int dln2_adc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long mask)
+{
+ int ret;
+ unsigned int microhertz;
+ struct dln2_adc *dln2 = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&dln2->mutex);
+ ret = dln2_adc_read(dln2, chan->channel);
+ mutex_unlock(&dln2->mutex);
+
+ if (ret < 0)
+ return ret;
+
+ *val = ret;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ /*
+ * Voltage reference is fixed at 3.3v
+ * 3.3 / (1 << 10) * 1000000000
+ */
+ *val = 0;
+ *val2 = 3222656;
+ return IIO_VAL_INT_PLUS_NANO;
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ if (dln2->sample_period) {
+ microhertz = 1000000000 / dln2->sample_period;
+ *val = microhertz / 1000000;
+ *val2 = microhertz % 1000000;
+ } else {
+ *val = 0;
+ *val2 = 0;
+ }
+
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int dln2_adc_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
+{
+ int ret;
+ unsigned int microhertz;
+ struct dln2_adc *dln2 = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ microhertz = 1000000 * val + val2;
+
+ mutex_lock(&dln2->mutex);
+
+ dln2->sample_period =
+ microhertz ? 1000000000 / microhertz : UINT_MAX;
+ if (dln2->sample_period > 65535) {
+ dln2->sample_period = 65535;
+ dev_warn(&dln2->pdev->dev,
+ "clamping period to 65535ms\n");
+ }
+
+ /*
+ * The first requested channel is arbitrated as a shared
+ * trigger source, so only one event is registered with the
+ * DLN. The event handler will then read all enabled channel
+ * values using DLN2_ADC_CHANNEL_GET_ALL_VAL to maintain
+ * synchronization between ADC readings.
+ */
+ if (dln2->trigger_chan != -1)
+ ret = dln2_adc_set_chan_period(dln2,
+ dln2->trigger_chan, dln2->sample_period);
+ else
+ ret = 0;
+
+ mutex_unlock(&dln2->mutex);
+
+ return ret;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int dln2_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct dln2_adc *dln2 = iio_priv(indio_dev);
+ int chan_count = indio_dev->num_channels - 1;
+ int ret, i, j;
+
+ mutex_lock(&dln2->mutex);
+
+ for (i = 0; i < chan_count; ++i) {
+ ret = dln2_adc_set_chan_enabled(dln2, i,
+ test_bit(i, scan_mask));
+ if (ret < 0) {
+ for (j = 0; j < i; ++j)
+ dln2_adc_set_chan_enabled(dln2, j, false);
+ mutex_unlock(&dln2->mutex);
+ dev_err(&dln2->pdev->dev,
+ "Unable to enable ADC channel %d\n", i);
+ return -EBUSY;
+ }
+ }
+
+ dln2_adc_update_demux(dln2);
+
+ mutex_unlock(&dln2->mutex);
+
+ return 0;
+}
+
+#define DLN2_ADC_CHAN(lval, idx) { \
+ lval.type = IIO_VOLTAGE; \
+ lval.channel = idx; \
+ lval.indexed = 1; \
+ lval.info_mask_separate = BIT(IIO_CHAN_INFO_RAW); \
+ lval.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ); \
+ lval.scan_index = idx; \
+ lval.scan_type.sign = 'u'; \
+ lval.scan_type.realbits = DLN2_ADC_DATA_BITS; \
+ lval.scan_type.storagebits = 16; \
+ lval.scan_type.endianness = IIO_LE; \
+}
+
+/* Assignment version of IIO_CHAN_SOFT_TIMESTAMP */
+#define IIO_CHAN_SOFT_TIMESTAMP_ASSIGN(lval, _si) { \
+ lval.type = IIO_TIMESTAMP; \
+ lval.channel = -1; \
+ lval.scan_index = _si; \
+ lval.scan_type.sign = 's'; \
+ lval.scan_type.realbits = 64; \
+ lval.scan_type.storagebits = 64; \
+}
+
+static const struct iio_info dln2_adc_info = {
+ .read_raw = dln2_adc_read_raw,
+ .write_raw = dln2_adc_write_raw,
+ .update_scan_mode = dln2_update_scan_mode,
+ .driver_module = THIS_MODULE,
+};
+
+static irqreturn_t dln2_adc_trigger_h(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct {
+ __le16 values[DLN2_ADC_MAX_CHANNELS];
+ int64_t timestamp_space;
+ } data;
+ struct dln2_adc_get_all_vals dev_data;
+ struct dln2_adc *dln2 = iio_priv(indio_dev);
+ const struct dln2_adc_demux_table *t;
+ int ret, i;
+
+ mutex_lock(&dln2->mutex);
+ ret = dln2_adc_read_all(dln2, &dev_data);
+ mutex_unlock(&dln2->mutex);
+ if (ret < 0)
+ goto done;
+
+ /* Demux operation */
+ for (i = 0; i < dln2->demux_count; ++i) {
+ t = &dln2->demux[i];
+ memcpy((void *)data.values + t->to,
+ (void *)dev_data.values + t->from, t->length);
+ }
+
+ /* Zero padding space between values and timestamp */
+ if (dln2->ts_pad_length)
+ memset((void *)data.values + dln2->ts_pad_offset,
+ 0, dln2->ts_pad_length);
+
+ iio_push_to_buffers_with_timestamp(indio_dev, &data,
+ iio_get_time_ns(indio_dev));
+
+done:
+ iio_trigger_notify_done(indio_dev->trig);
+ return IRQ_HANDLED;
+}
+
+static int dln2_adc_triggered_buffer_postenable(struct iio_dev *indio_dev)
+{
+ int ret;
+ struct dln2_adc *dln2 = iio_priv(indio_dev);
+ u16 conflict;
+ unsigned int trigger_chan;
+
+ mutex_lock(&dln2->mutex);
+
+ /* Enable ADC */
+ ret = dln2_adc_set_port_enabled(dln2, true, &conflict);
+ if (ret < 0) {
+ mutex_unlock(&dln2->mutex);
+ dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
+ if (conflict) {
+ dev_err(&dln2->pdev->dev,
+ "ADC pins conflict with mask %04X\n",
+ (int)conflict);
+ ret = -EBUSY;
+ }
+ return ret;
+ }
+
+ /* Assign trigger channel based on first enabled channel */
+ trigger_chan = find_first_bit(indio_dev->active_scan_mask,
+ indio_dev->masklength);
+ if (trigger_chan < DLN2_ADC_MAX_CHANNELS) {
+ dln2->trigger_chan = trigger_chan;
+ ret = dln2_adc_set_chan_period(dln2, dln2->trigger_chan,
+ dln2->sample_period);
+ mutex_unlock(&dln2->mutex);
+ if (ret < 0) {
+ dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
+ return ret;
+ }
+ } else {
+ dln2->trigger_chan = -1;
+ mutex_unlock(&dln2->mutex);
+ }
+
+ return iio_triggered_buffer_postenable(indio_dev);
+}
+
+static int dln2_adc_triggered_buffer_predisable(struct iio_dev *indio_dev)
+{
+ int ret;
+ struct dln2_adc *dln2 = iio_priv(indio_dev);
+
+ mutex_lock(&dln2->mutex);
+
+ /* Disable trigger channel */
+ if (dln2->trigger_chan != -1) {
+ dln2_adc_set_chan_period(dln2, dln2->trigger_chan, 0);
+ dln2->trigger_chan = -1;
+ }
+
+ /* Disable ADC */
+ ret = dln2_adc_set_port_enabled(dln2, false, NULL);
+
+ mutex_unlock(&dln2->mutex);
+ if (ret < 0) {
+ dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
+ return ret;
+ }
+
+ return iio_triggered_buffer_predisable(indio_dev);
+}
+
+static const struct iio_buffer_setup_ops dln2_adc_buffer_setup_ops = {
+ .postenable = dln2_adc_triggered_buffer_postenable,
+ .predisable = dln2_adc_triggered_buffer_predisable,
+};
+
+static void dln2_adc_event(struct platform_device *pdev, u16 echo,
+ const void *data, int len)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct dln2_adc *dln2 = iio_priv(indio_dev);
+
+ /* Called via URB completion handler */
+ iio_trigger_poll(dln2->trig);
+}
+
+static const struct iio_trigger_ops dln2_adc_trigger_ops = {
+ .owner = THIS_MODULE,
+};
+
+static int dln2_adc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct dln2_adc *dln2;
+ struct dln2_platform_data *pdata = dev_get_platdata(&pdev->dev);
+ struct iio_dev *indio_dev;
+ int i, ret, chans;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*dln2));
+ if (!indio_dev) {
+ dev_err(dev, "failed allocating iio device\n");
+ return -ENOMEM;
+ }
+
+ dln2 = iio_priv(indio_dev);
+ dln2->pdev = pdev;
+ dln2->port = pdata->port;
+ dln2->trigger_chan = -1;
+ mutex_init(&dln2->mutex);
+
+ platform_set_drvdata(pdev, indio_dev);
+
+ ret = dln2_adc_set_port_resolution(dln2);
+ if (ret < 0) {
+ dev_err(dev, "failed to set ADC resolution to 10 bits\n");
+ return ret;
+ }
+
+ chans = dln2_adc_get_chan_count(dln2);
+ if (chans < 0) {
+ dev_err(dev, "failed to get channel count: %d\n", chans);
+ return chans;
+ }
+ if (chans > DLN2_ADC_MAX_CHANNELS) {
+ chans = DLN2_ADC_MAX_CHANNELS;
+ dev_warn(dev, "clamping channels to %d\n",
+ DLN2_ADC_MAX_CHANNELS);
+ }
+
+ for (i = 0; i < chans; ++i)
+ DLN2_ADC_CHAN(dln2->iio_channels[i], i)
+ IIO_CHAN_SOFT_TIMESTAMP_ASSIGN(dln2->iio_channels[i], i);
+
+ indio_dev->name = DLN2_ADC_MOD_NAME;
+ indio_dev->dev.parent = dev;
+ indio_dev->info = &dln2_adc_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = dln2->iio_channels;
+ indio_dev->num_channels = chans + 1;
+ indio_dev->setup_ops = &dln2_adc_buffer_setup_ops;
+
+ dln2->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
+ indio_dev->name, indio_dev->id);
+ if (!dln2->trig) {
+ dev_err(dev, "failed to allocate trigger\n");
+ return -ENOMEM;
+ }
+ dln2->trig->ops = &dln2_adc_trigger_ops;
+ iio_trigger_set_drvdata(dln2->trig, dln2);
+ devm_iio_trigger_register(dev, dln2->trig);
+ iio_trigger_set_immutable(indio_dev, dln2->trig);
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+ dln2_adc_trigger_h,
+ &dln2_adc_buffer_setup_ops);
+ if (ret) {
+ dev_err(dev, "failed to allocate triggered buffer: %d\n", ret);
+ return ret;
+ }
+
+ ret = dln2_register_event_cb(pdev, DLN2_ADC_CONDITION_MET_EV,
+ dln2_adc_event);
+ if (ret) {
+ dev_err(dev, "failed to setup DLN2 periodic event: %d\n", ret);
+ return ret;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(dev, "failed to register iio device: %d\n", ret);
+ goto unregister_event;
+ }
+
+ return ret;
+
+unregister_event:
+ dln2_unregister_event_cb(pdev, DLN2_ADC_CONDITION_MET_EV);
+
+ return ret;
+}
+
+static int dln2_adc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+
+ iio_device_unregister(indio_dev);
+ dln2_unregister_event_cb(pdev, DLN2_ADC_CONDITION_MET_EV);
+ return 0;
+}
+
+static struct platform_driver dln2_adc_driver = {
+ .driver.name = DLN2_ADC_MOD_NAME,
+ .probe = dln2_adc_probe,
+ .remove = dln2_adc_remove,
+};
+
+module_platform_driver(dln2_adc_driver);
+
+MODULE_AUTHOR("Jack Andersen <jackoalan@gmail.com");
+MODULE_DESCRIPTION("Driver for the Diolan DLN2 ADC interface");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:dln2-adc");
diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c
new file mode 100644
index 000000000000..a179ac476c6d
--- /dev/null
+++ b/drivers/iio/adc/ep93xx_adc.c
@@ -0,0 +1,255 @@
+/*
+ * Driver for ADC module on the Cirrus Logic EP93xx series of SoCs
+ *
+ * Copyright (C) 2015 Alexander Sverdlin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The driver uses polling to get the conversion status. According to EP93xx
+ * datasheets, reading ADCResult register starts the conversion, but user is also
+ * responsible for ensuring that delay between adjacent conversion triggers is
+ * long enough so that maximum allowed conversion rate is not exceeded. This
+ * basically renders IRQ mode unusable.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/io.h>
+#include <linux/irqflags.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+
+/*
+ * This code could benefit from real HR Timers, but jiffy granularity would
+ * lower ADC conversion rate down to CONFIG_HZ, so we fallback to busy wait
+ * in such case.
+ *
+ * HR Timers-based version loads CPU only up to 10% during back to back ADC
+ * conversion, while busy wait-based version consumes whole CPU power.
+ */
+#ifdef CONFIG_HIGH_RES_TIMERS
+#define ep93xx_adc_delay(usmin, usmax) usleep_range(usmin, usmax)
+#else
+#define ep93xx_adc_delay(usmin, usmax) udelay(usmin)
+#endif
+
+#define EP93XX_ADC_RESULT 0x08
+#define EP93XX_ADC_SDR BIT(31)
+#define EP93XX_ADC_SWITCH 0x18
+#define EP93XX_ADC_SW_LOCK 0x20
+
+struct ep93xx_adc_priv {
+ struct clk *clk;
+ void __iomem *base;
+ int lastch;
+ struct mutex lock;
+};
+
+#define EP93XX_ADC_CH(index, dname, swcfg) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = index, \
+ .address = swcfg, \
+ .datasheet_name = dname, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OFFSET), \
+}
+
+/*
+ * Numbering scheme for channels 0..4 is defined in EP9301 and EP9302 datasheets.
+ * EP9307, EP9312 and EP9312 have 3 channels more (total 8), but the numbering is
+ * not defined. So the last three are numbered randomly, let's say.
+ */
+static const struct iio_chan_spec ep93xx_adc_channels[8] = {
+ EP93XX_ADC_CH(0, "YM", 0x608),
+ EP93XX_ADC_CH(1, "SXP", 0x680),
+ EP93XX_ADC_CH(2, "SXM", 0x640),
+ EP93XX_ADC_CH(3, "SYP", 0x620),
+ EP93XX_ADC_CH(4, "SYM", 0x610),
+ EP93XX_ADC_CH(5, "XP", 0x601),
+ EP93XX_ADC_CH(6, "XM", 0x602),
+ EP93XX_ADC_CH(7, "YP", 0x604),
+};
+
+static int ep93xx_read_raw(struct iio_dev *iiodev,
+ struct iio_chan_spec const *channel, int *value,
+ int *shift, long mask)
+{
+ struct ep93xx_adc_priv *priv = iio_priv(iiodev);
+ unsigned long timeout;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&priv->lock);
+ if (priv->lastch != channel->channel) {
+ priv->lastch = channel->channel;
+ /*
+ * Switch register is software-locked, unlocking must be
+ * immediately followed by write
+ */
+ local_irq_disable();
+ writel_relaxed(0xAA, priv->base + EP93XX_ADC_SW_LOCK);
+ writel_relaxed(channel->address,
+ priv->base + EP93XX_ADC_SWITCH);
+ local_irq_enable();
+ /*
+ * Settling delay depends on module clock and could be
+ * 2ms or 500us
+ */
+ ep93xx_adc_delay(2000, 2000);
+ }
+ /* Start the conversion, eventually discarding old result */
+ readl_relaxed(priv->base + EP93XX_ADC_RESULT);
+ /* Ensure maximum conversion rate is not exceeded */
+ ep93xx_adc_delay(DIV_ROUND_UP(1000000, 925),
+ DIV_ROUND_UP(1000000, 925));
+ /* At this point conversion must be completed, but anyway... */
+ ret = IIO_VAL_INT;
+ timeout = jiffies + msecs_to_jiffies(1) + 1;
+ while (1) {
+ u32 t;
+
+ t = readl_relaxed(priv->base + EP93XX_ADC_RESULT);
+ if (t & EP93XX_ADC_SDR) {
+ *value = sign_extend32(t, 15);
+ break;
+ }
+
+ if (time_after(jiffies, timeout)) {
+ dev_err(&iiodev->dev, "Conversion timeout\n");
+ ret = -ETIMEDOUT;
+ break;
+ }
+
+ cpu_relax();
+ }
+ mutex_unlock(&priv->lock);
+ return ret;
+
+ case IIO_CHAN_INFO_OFFSET:
+ /* According to datasheet, range is -25000..25000 */
+ *value = 25000;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ /* Typical supply voltage is 3.3v */
+ *value = (1ULL << 32) * 3300 / 50000;
+ *shift = 32;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ }
+
+ return -EINVAL;
+}
+
+static const struct iio_info ep93xx_adc_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = ep93xx_read_raw,
+};
+
+static int ep93xx_adc_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct iio_dev *iiodev;
+ struct ep93xx_adc_priv *priv;
+ struct clk *pclk;
+ struct resource *res;
+
+ iiodev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
+ if (!iiodev)
+ return -ENOMEM;
+ priv = iio_priv(iiodev);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Cannot obtain memory resource\n");
+ return -ENXIO;
+ }
+ priv->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->base)) {
+ dev_err(&pdev->dev, "Cannot map memory resource\n");
+ return PTR_ERR(priv->base);
+ }
+
+ iiodev->dev.parent = &pdev->dev;
+ iiodev->name = dev_name(&pdev->dev);
+ iiodev->modes = INDIO_DIRECT_MODE;
+ iiodev->info = &ep93xx_adc_info;
+ iiodev->num_channels = ARRAY_SIZE(ep93xx_adc_channels);
+ iiodev->channels = ep93xx_adc_channels;
+
+ priv->lastch = -1;
+ mutex_init(&priv->lock);
+
+ platform_set_drvdata(pdev, iiodev);
+
+ priv->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ dev_err(&pdev->dev, "Cannot obtain clock\n");
+ return PTR_ERR(priv->clk);
+ }
+
+ pclk = clk_get_parent(priv->clk);
+ if (!pclk) {
+ dev_warn(&pdev->dev, "Cannot obtain parent clock\n");
+ } else {
+ /*
+ * This is actually a place for improvement:
+ * EP93xx ADC supports two clock divisors -- 4 and 16,
+ * resulting in conversion rates 3750 and 925 samples per second
+ * with 500us or 2ms settling time respectively.
+ * One might find this interesting enough to be configurable.
+ */
+ ret = clk_set_rate(priv->clk, clk_get_rate(pclk) / 16);
+ if (ret)
+ dev_warn(&pdev->dev, "Cannot set clock rate\n");
+ /*
+ * We can tolerate rate setting failure because the module should
+ * work in any case.
+ */
+ }
+
+ ret = clk_enable(priv->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot enable clock\n");
+ return ret;
+ }
+
+ ret = iio_device_register(iiodev);
+ if (ret)
+ clk_disable(priv->clk);
+
+ return ret;
+}
+
+static int ep93xx_adc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *iiodev = platform_get_drvdata(pdev);
+ struct ep93xx_adc_priv *priv = iio_priv(iiodev);
+
+ iio_device_unregister(iiodev);
+ clk_disable(priv->clk);
+
+ return 0;
+}
+
+static struct platform_driver ep93xx_adc_driver = {
+ .driver = {
+ .name = "ep93xx-adc",
+ },
+ .probe = ep93xx_adc_probe,
+ .remove = ep93xx_adc_remove,
+};
+module_platform_driver(ep93xx_adc_driver);
+
+MODULE_AUTHOR("Alexander Sverdlin <alexander.sverdlin@gmail.com>");
+MODULE_DESCRIPTION("Cirrus Logic EP93XX ADC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ep93xx-adc");
diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c
index 232c0b80d658..68884d26b50c 100644
--- a/drivers/iio/adc/ina2xx-adc.c
+++ b/drivers/iio/adc/ina2xx-adc.c
@@ -44,6 +44,7 @@
#define INA226_MASK_ENABLE 0x06
#define INA226_CVRF BIT(3)
+#define INA219_CNVR BIT(1)
#define INA2XX_MAX_REGISTERS 8
@@ -592,6 +593,7 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev)
int bit, ret, i = 0;
s64 time_a, time_b;
unsigned int alert;
+ int cnvr_need_clear = 0;
time_a = iio_get_time_ns(indio_dev);
@@ -603,22 +605,30 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev)
* we check the ConVersionReadyFlag.
* On hardware that supports using the ALERT pin to toggle a
* GPIO a triggered buffer could be used instead.
- * For now, we pay for that extra read of the ALERT register
+ * For now, we do an extra read of the MASK_ENABLE register (INA226)
+ * resp. the BUS_VOLTAGE register (INA219).
*/
if (!chip->allow_async_readout)
do {
- ret = regmap_read(chip->regmap, INA226_MASK_ENABLE,
- &alert);
+ if (chip->config->chip_id == ina226) {
+ ret = regmap_read(chip->regmap,
+ INA226_MASK_ENABLE, &alert);
+ alert &= INA226_CVRF;
+ } else {
+ ret = regmap_read(chip->regmap,
+ INA2XX_BUS_VOLTAGE, &alert);
+ alert &= INA219_CNVR;
+ cnvr_need_clear = alert;
+ }
+
if (ret < 0)
return ret;
- alert &= INA226_CVRF;
} while (!alert);
/*
- * Single register reads: bulk_read will not work with ina226
- * as there is no auto-increment of the address register for
- * data length longer than 16bits.
+ * Single register reads: bulk_read will not work with ina226/219
+ * as there is no auto-increment of the register pointer.
*/
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->masklength) {
@@ -630,6 +640,18 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev)
return ret;
data[i++] = val;
+
+ if (INA2XX_SHUNT_VOLTAGE + bit == INA2XX_POWER)
+ cnvr_need_clear = 0;
+ }
+
+ /* Dummy read on INA219 power register to clear CNVR flag */
+ if (cnvr_need_clear && chip->config->chip_id == ina219) {
+ unsigned int val;
+
+ ret = regmap_read(chip->regmap, INA2XX_POWER, &val);
+ if (ret < 0)
+ return ret;
}
time_b = iio_get_time_ns(indio_dev);
diff --git a/drivers/iio/adc/ltc2471.c b/drivers/iio/adc/ltc2471.c
new file mode 100644
index 000000000000..29b7ed60cdb0
--- /dev/null
+++ b/drivers/iio/adc/ltc2471.c
@@ -0,0 +1,160 @@
+/*
+ * Driver for Linear Technology LTC2471 and LTC2473 voltage monitors
+ * The LTC2473 is identical to the 2471, but reports a differential signal.
+ *
+ * Copyright (C) 2017 Topic Embedded Products
+ * Author: Mike Looijmans <mike.looijmans@topic.nl>
+ *
+ * License: GPLv2
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+enum ltc2471_chips {
+ ltc2471,
+ ltc2473,
+};
+
+struct ltc2471_data {
+ struct i2c_client *client;
+};
+
+/* Reference voltage is 1.25V */
+#define LTC2471_VREF 1250
+
+/* Read two bytes from the I2C bus to obtain the ADC result */
+static int ltc2471_get_value(struct i2c_client *client)
+{
+ int ret;
+ __be16 buf;
+
+ ret = i2c_master_recv(client, (char *)&buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(buf))
+ return -EIO;
+
+ /* MSB first */
+ return be16_to_cpu(buf);
+}
+
+static int ltc2471_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long info)
+{
+ struct ltc2471_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ ret = ltc2471_get_value(data->client);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ if (chan->differential)
+ /* Output ranges from -VREF to +VREF */
+ *val = 2 * LTC2471_VREF;
+ else
+ /* Output ranges from 0 to VREF */
+ *val = LTC2471_VREF;
+ *val2 = 16; /* 16 data bits */
+ return IIO_VAL_FRACTIONAL_LOG2;
+
+ case IIO_CHAN_INFO_OFFSET:
+ /* Only differential chip has this property */
+ *val = -LTC2471_VREF;
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_chan_spec ltc2471_channel[] = {
+ {
+ .type = IIO_VOLTAGE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+ },
+};
+
+static const struct iio_chan_spec ltc2473_channel[] = {
+ {
+ .type = IIO_VOLTAGE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET),
+ .differential = 1,
+ },
+};
+
+static const struct iio_info ltc2471_info = {
+ .read_raw = ltc2471_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static int ltc2471_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct iio_dev *indio_dev;
+ struct ltc2471_data *data;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -EOPNOTSUPP;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ data->client = client;
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->name = id->name;
+ indio_dev->info = &ltc2471_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ if (id->driver_data == ltc2473)
+ indio_dev->channels = ltc2473_channel;
+ else
+ indio_dev->channels = ltc2471_channel;
+ indio_dev->num_channels = 1;
+
+ /* Trigger once to start conversion and check if chip is there */
+ ret = ltc2471_get_value(client);
+ if (ret < 0) {
+ dev_err(&client->dev, "Cannot read from device.\n");
+ return ret;
+ }
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id ltc2471_i2c_id[] = {
+ { "ltc2471", ltc2471 },
+ { "ltc2473", ltc2473 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, ltc2471_i2c_id);
+
+static struct i2c_driver ltc2471_i2c_driver = {
+ .driver = {
+ .name = "ltc2471",
+ },
+ .probe = ltc2471_i2c_probe,
+ .id_table = ltc2471_i2c_id,
+};
+
+module_i2c_driver(ltc2471_i2c_driver);
+
+MODULE_DESCRIPTION("LTC2471/LTC2473 ADC driver");
+MODULE_AUTHOR("Topic Embedded Products");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c
index 2691b10023f5..5bf8011dcde9 100644
--- a/drivers/iio/adc/ltc2497.c
+++ b/drivers/iio/adc/ltc2497.c
@@ -11,6 +11,7 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
+#include <linux/iio/driver.h>
#include <linux/iio/sysfs.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -127,13 +128,14 @@ static int ltc2497_read_raw(struct iio_dev *indio_dev,
}
}
-#define LTC2497_CHAN(_chan, _addr) { \
+#define LTC2497_CHAN(_chan, _addr, _ds_name) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (_chan), \
.address = (_addr | (_chan / 2) | ((_chan & 1) ? LTC2497_SIGN : 0)), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .datasheet_name = (_ds_name), \
}
#define LTC2497_CHAN_DIFF(_chan, _addr) { \
@@ -148,22 +150,22 @@ static int ltc2497_read_raw(struct iio_dev *indio_dev,
}
static const struct iio_chan_spec ltc2497_channel[] = {
- LTC2497_CHAN(0, LTC2497_SGL),
- LTC2497_CHAN(1, LTC2497_SGL),
- LTC2497_CHAN(2, LTC2497_SGL),
- LTC2497_CHAN(3, LTC2497_SGL),
- LTC2497_CHAN(4, LTC2497_SGL),
- LTC2497_CHAN(5, LTC2497_SGL),
- LTC2497_CHAN(6, LTC2497_SGL),
- LTC2497_CHAN(7, LTC2497_SGL),
- LTC2497_CHAN(8, LTC2497_SGL),
- LTC2497_CHAN(9, LTC2497_SGL),
- LTC2497_CHAN(10, LTC2497_SGL),
- LTC2497_CHAN(11, LTC2497_SGL),
- LTC2497_CHAN(12, LTC2497_SGL),
- LTC2497_CHAN(13, LTC2497_SGL),
- LTC2497_CHAN(14, LTC2497_SGL),
- LTC2497_CHAN(15, LTC2497_SGL),
+ LTC2497_CHAN(0, LTC2497_SGL, "CH0"),
+ LTC2497_CHAN(1, LTC2497_SGL, "CH1"),
+ LTC2497_CHAN(2, LTC2497_SGL, "CH2"),
+ LTC2497_CHAN(3, LTC2497_SGL, "CH3"),
+ LTC2497_CHAN(4, LTC2497_SGL, "CH4"),
+ LTC2497_CHAN(5, LTC2497_SGL, "CH5"),
+ LTC2497_CHAN(6, LTC2497_SGL, "CH6"),
+ LTC2497_CHAN(7, LTC2497_SGL, "CH7"),
+ LTC2497_CHAN(8, LTC2497_SGL, "CH8"),
+ LTC2497_CHAN(9, LTC2497_SGL, "CH9"),
+ LTC2497_CHAN(10, LTC2497_SGL, "CH10"),
+ LTC2497_CHAN(11, LTC2497_SGL, "CH11"),
+ LTC2497_CHAN(12, LTC2497_SGL, "CH12"),
+ LTC2497_CHAN(13, LTC2497_SGL, "CH13"),
+ LTC2497_CHAN(14, LTC2497_SGL, "CH14"),
+ LTC2497_CHAN(15, LTC2497_SGL, "CH15"),
LTC2497_CHAN_DIFF(0, LTC2497_DIFF),
LTC2497_CHAN_DIFF(1, LTC2497_DIFF),
LTC2497_CHAN_DIFF(2, LTC2497_DIFF),
@@ -192,6 +194,7 @@ static int ltc2497_probe(struct i2c_client *client,
{
struct iio_dev *indio_dev;
struct ltc2497_st *st;
+ struct iio_map *plat_data;
int ret;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
@@ -221,19 +224,31 @@ static int ltc2497_probe(struct i2c_client *client,
if (ret < 0)
return ret;
+ if (client->dev.platform_data) {
+ plat_data = ((struct iio_map *)client->dev.platform_data);
+ ret = iio_map_array_register(indio_dev, plat_data);
+ if (ret) {
+ dev_err(&indio_dev->dev, "iio map err: %d\n", ret);
+ goto err_regulator_disable;
+ }
+ }
+
ret = i2c_smbus_write_byte(st->client, LTC2497_CONFIG_DEFAULT);
if (ret < 0)
- goto err_regulator_disable;
+ goto err_array_unregister;
st->addr_prev = LTC2497_CONFIG_DEFAULT;
st->time_prev = ktime_get();
ret = iio_device_register(indio_dev);
if (ret < 0)
- goto err_regulator_disable;
+ goto err_array_unregister;
return 0;
+err_array_unregister:
+ iio_map_array_unregister(indio_dev);
+
err_regulator_disable:
regulator_disable(st->ref);
@@ -245,6 +260,7 @@ static int ltc2497_remove(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ltc2497_st *st = iio_priv(indio_dev);
+ iio_map_array_unregister(indio_dev);
iio_device_unregister(indio_dev);
regulator_disable(st->ref);
diff --git a/drivers/iio/adc/max9611.c b/drivers/iio/adc/max9611.c
index b0526e4b9530..b1dd17cbce58 100644
--- a/drivers/iio/adc/max9611.c
+++ b/drivers/iio/adc/max9611.c
@@ -549,8 +549,8 @@ static int max9611_probe(struct i2c_client *client,
ret = of_property_read_u32(of_node, shunt_res_prop, &of_shunt);
if (ret) {
dev_err(&client->dev,
- "Missing %s property for %s node\n",
- shunt_res_prop, of_node->full_name);
+ "Missing %s property for %pOF node\n",
+ shunt_res_prop, of_node);
return ret;
}
max9611->shunt_resistor_uohm = of_shunt;
diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c
index 254135e07792..63de705086ed 100644
--- a/drivers/iio/adc/mcp3422.c
+++ b/drivers/iio/adc/mcp3422.c
@@ -379,10 +379,12 @@ static int mcp3422_probe(struct i2c_client *client,
/* meaningful default configuration */
config = (MCP3422_CONT_SAMPLING
- | MCP3422_CHANNEL_VALUE(1)
+ | MCP3422_CHANNEL_VALUE(0)
| MCP3422_PGA_VALUE(MCP3422_PGA_1)
| MCP3422_SAMPLE_RATE_VALUE(MCP3422_SRATE_240));
- mcp3422_update_config(adc, config);
+ err = mcp3422_update_config(adc, config);
+ if (err < 0)
+ return err;
err = devm_iio_device_register(&client->dev, indio_dev);
if (err < 0)
diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
index 83da50ed73ab..2e8dbb89c8c9 100644
--- a/drivers/iio/adc/meson_saradc.c
+++ b/drivers/iio/adc/meson_saradc.c
@@ -572,8 +572,8 @@ static int meson_sar_adc_clk_init(struct iio_dev *indio_dev,
struct clk_init_data init;
const char *clk_parents[1];
- init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%s#adc_div",
- of_node_full_name(indio_dev->dev.of_node));
+ init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%pOF#adc_div",
+ indio_dev->dev.of_node);
init.flags = 0;
init.ops = &clk_divider_ops;
clk_parents[0] = __clk_get_name(priv->clkin);
@@ -591,8 +591,8 @@ static int meson_sar_adc_clk_init(struct iio_dev *indio_dev,
if (WARN_ON(IS_ERR(priv->adc_div_clk)))
return PTR_ERR(priv->adc_div_clk);
- init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%s#adc_en",
- of_node_full_name(indio_dev->dev.of_node));
+ init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%pOF#adc_en",
+ indio_dev->dev.of_node);
init.flags = CLK_SET_RATE_PARENT;
init.ops = &clk_gate_ops;
clk_parents[0] = __clk_get_name(priv->adc_div_clk);
@@ -915,6 +915,11 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
init_completion(&priv->done);
match = of_match_device(meson_sar_adc_of_match, &pdev->dev);
+ if (!match) {
+ dev_err(&pdev->dev, "failed to match device\n");
+ return -ENODEV;
+ }
+
priv->data = match->data;
indio_dev->name = priv->data->name;
diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c
index 2d104c828041..414cf44bf19d 100644
--- a/drivers/iio/adc/mt6577_auxadc.c
+++ b/drivers/iio/adc/mt6577_auxadc.c
@@ -184,6 +184,37 @@ static const struct iio_info mt6577_auxadc_info = {
.read_raw = &mt6577_auxadc_read_raw,
};
+static int __maybe_unused mt6577_auxadc_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
+ int ret;
+
+ ret = clk_prepare_enable(adc_dev->adc_clk);
+ if (ret) {
+ pr_err("failed to enable auxadc clock\n");
+ return ret;
+ }
+
+ mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
+ MT6577_AUXADC_PDN_EN, 0);
+ mdelay(MT6577_AUXADC_POWER_READY_MS);
+
+ return 0;
+}
+
+static int __maybe_unused mt6577_auxadc_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
+
+ mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
+ 0, MT6577_AUXADC_PDN_EN);
+ clk_disable_unprepare(adc_dev->adc_clk);
+
+ return 0;
+}
+
static int mt6577_auxadc_probe(struct platform_device *pdev)
{
struct mt6577_auxadc_device *adc_dev;
@@ -269,8 +300,13 @@ static int mt6577_auxadc_remove(struct platform_device *pdev)
return 0;
}
+static SIMPLE_DEV_PM_OPS(mt6577_auxadc_pm_ops,
+ mt6577_auxadc_suspend,
+ mt6577_auxadc_resume);
+
static const struct of_device_id mt6577_auxadc_of_match[] = {
{ .compatible = "mediatek,mt2701-auxadc", },
+ { .compatible = "mediatek,mt7622-auxadc", },
{ .compatible = "mediatek,mt8173-auxadc", },
{ }
};
@@ -280,6 +316,7 @@ static struct platform_driver mt6577_auxadc_driver = {
.driver = {
.name = "mt6577-auxadc",
.of_match_table = mt6577_auxadc_of_match,
+ .pm = &mt6577_auxadc_pm_ops,
},
.probe = mt6577_auxadc_probe,
.remove = mt6577_auxadc_remove,
diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c
index ae6d3324f518..2bf2ed15a870 100644
--- a/drivers/iio/adc/rockchip_saradc.c
+++ b/drivers/iio/adc/rockchip_saradc.c
@@ -224,6 +224,11 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
info = iio_priv(indio_dev);
match = of_match_device(rockchip_saradc_match, &pdev->dev);
+ if (!match) {
+ dev_err(&pdev->dev, "failed to match device\n");
+ return -ENODEV;
+ }
+
info->data = match->data;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index e09233b03c05..9d083c2338f9 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -172,7 +172,7 @@ struct stm32h7_adc_ck_spec {
int div;
};
-const struct stm32h7_adc_ck_spec stm32h7_adc_ckmodes_spec[] = {
+static const struct stm32h7_adc_ck_spec stm32h7_adc_ckmodes_spec[] = {
/* 00: CK_ADC[1..3]: Asynchronous clock modes */
{ 0, 0, 1 },
{ 0, 1, 2 },
diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c
index 884b8e461b17..7972845b3823 100644
--- a/drivers/iio/adc/ti-ads1015.c
+++ b/drivers/iio/adc/ti-ads1015.c
@@ -505,24 +505,24 @@ static int ads1015_get_channels_config_of(struct i2c_client *client)
unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE;
if (of_property_read_u32(node, "reg", &pval)) {
- dev_err(&client->dev, "invalid reg on %s\n",
- node->full_name);
+ dev_err(&client->dev, "invalid reg on %pOF\n",
+ node);
continue;
}
channel = pval;
if (channel >= ADS1015_CHANNELS) {
dev_err(&client->dev,
- "invalid channel index %d on %s\n",
- channel, node->full_name);
+ "invalid channel index %d on %pOF\n",
+ channel, node);
continue;
}
if (!of_property_read_u32(node, "ti,gain", &pval)) {
pga = pval;
if (pga > 6) {
- dev_err(&client->dev, "invalid gain on %s\n",
- node->full_name);
+ dev_err(&client->dev, "invalid gain on %pOF\n",
+ node);
of_node_put(node);
return -EINVAL;
}
@@ -532,8 +532,8 @@ static int ads1015_get_channels_config_of(struct i2c_client *client)
data_rate = pval;
if (data_rate > 7) {
dev_err(&client->dev,
- "invalid data_rate on %s\n",
- node->full_name);
+ "invalid data_rate on %pOF\n",
+ node);
of_node_put(node);
return -EINVAL;
}