aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio/adc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/adc')
-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
19 files changed, 711 insertions, 388 deletions
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);