From 9a0ebbc93547d88f422905c34dcceebe928f3e9e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 13 Nov 2017 11:29:55 +0100 Subject: iio: adc/accel: Fix up module licenses The module license checker complains about these two so just fix it up. They are both GPLv2, both written by me or using code I extracted while refactoring from the GPLv2 drivers. Cc: Randy Dunlap Reported-by: Randy Dunlap Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron --- drivers/iio/adc/qcom-vadc-common.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/qcom-vadc-common.c b/drivers/iio/adc/qcom-vadc-common.c index 47d24ae5462f..fe3d7826783c 100644 --- a/drivers/iio/adc/qcom-vadc-common.c +++ b/drivers/iio/adc/qcom-vadc-common.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "qcom-vadc-common.h" @@ -229,3 +230,6 @@ int qcom_vadc_decimation_from_dt(u32 value) return __ffs64(value / VADC_DECIMATION_MIN); } EXPORT_SYMBOL(qcom_vadc_decimation_from_dt); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Qualcomm ADC common functionality"); -- cgit v1.2.3 From 073c662017f2f3ea693bb31e4f5d2332265f1de0 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Wed, 15 Nov 2017 14:56:47 +0200 Subject: iio: adc: at91-sama5d2_adc: add support for DMA Added support for DMA transfers. The implementation uses the user watermark to decide whether DMA will be used or not. For watermark 1, DMA will not be used. If watermark is bigger, DMA will be used. Sysfs attributes are created to indicate whether the DMA is used, with hwfifo_enabled, and the current DMA watermark is readable in hwfifo_watermark. Minimum and maximum values are in hwfifo_watermark_min and hwfifo_watermark_max. Signed-off-by: Eugen Hristev Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 1 + drivers/iio/adc/at91-sama5d2_adc.c | 453 +++++++++++++++++++++++++++++++++++-- 2 files changed, 434 insertions(+), 20 deletions(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index ef86296b8b0d..486793691de0 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -158,6 +158,7 @@ config AT91_SAMA5D2_ADC tristate "Atmel AT91 SAMA5D2 ADC" depends on ARCH_AT91 || COMPILE_TEST depends on HAS_IOMEM + depends on HAS_DMA select IIO_TRIGGERED_BUFFER help Say yes here to build support for Atmel SAMA5D2 ADC which is diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c index 755a493c2a2c..99f3c2c89768 100644 --- a/drivers/iio/adc/at91-sama5d2_adc.c +++ b/drivers/iio/adc/at91-sama5d2_adc.c @@ -16,6 +16,8 @@ #include #include +#include +#include #include #include #include @@ -100,6 +102,8 @@ #define AT91_SAMA5D2_LCDR 0x20 /* Interrupt Enable Register */ #define AT91_SAMA5D2_IER 0x24 +/* Interrupt Enable Register - general overrun error */ +#define AT91_SAMA5D2_IER_GOVRE BIT(25) /* Interrupt Disable Register */ #define AT91_SAMA5D2_IDR 0x28 /* Interrupt Mask Register */ @@ -167,13 +171,19 @@ /* * Maximum number of bytes to hold conversion from all channels - * plus the timestamp + * without the timestamp. */ -#define AT91_BUFFER_MAX_BYTES ((AT91_SAMA5D2_SINGLE_CHAN_CNT + \ - AT91_SAMA5D2_DIFF_CHAN_CNT) * 2 + 8) +#define AT91_BUFFER_MAX_CONVERSION_BYTES ((AT91_SAMA5D2_SINGLE_CHAN_CNT + \ + AT91_SAMA5D2_DIFF_CHAN_CNT) * 2) + +/* This total must also include the timestamp */ +#define AT91_BUFFER_MAX_BYTES (AT91_BUFFER_MAX_CONVERSION_BYTES + 8) #define AT91_BUFFER_MAX_HWORDS (AT91_BUFFER_MAX_BYTES / 2) +#define AT91_HWFIFO_MAX_SIZE_STR "128" +#define AT91_HWFIFO_MAX_SIZE 128 + #define AT91_SAMA5D2_CHAN_SINGLE(num, addr) \ { \ .type = IIO_VOLTAGE, \ @@ -228,6 +238,28 @@ struct at91_adc_trigger { bool hw_trig; }; +/** + * at91_adc_dma - at91-sama5d2 dma information struct + * @dma_chan: the dma channel acquired + * @rx_buf: dma coherent allocated area + * @rx_dma_buf: dma handler for the buffer + * @phys_addr: physical address of the ADC base register + * @buf_idx: index inside the dma buffer where reading was last done + * @rx_buf_sz: size of buffer used by DMA operation + * @watermark: number of conversions to copy before DMA triggers irq + * @dma_ts: hold the start timestamp of dma operation + */ +struct at91_adc_dma { + struct dma_chan *dma_chan; + u8 *rx_buf; + dma_addr_t rx_dma_buf; + phys_addr_t phys_addr; + int buf_idx; + int rx_buf_sz; + int watermark; + s64 dma_ts; +}; + struct at91_adc_state { void __iomem *base; int irq; @@ -242,6 +274,7 @@ struct at91_adc_state { u32 conversion_value; struct at91_adc_soc_info soc_info; wait_queue_head_t wq_data_available; + struct at91_adc_dma dma_st; u16 buffer[AT91_BUFFER_MAX_HWORDS]; /* * lock to prevent concurrent 'single conversion' requests through @@ -322,11 +355,17 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state) if (state) { at91_adc_writel(st, AT91_SAMA5D2_CHER, BIT(chan->channel)); - at91_adc_writel(st, AT91_SAMA5D2_IER, - BIT(chan->channel)); + /* enable irq only if not using DMA */ + if (!st->dma_st.dma_chan) { + at91_adc_writel(st, AT91_SAMA5D2_IER, + BIT(chan->channel)); + } } else { - at91_adc_writel(st, AT91_SAMA5D2_IDR, - BIT(chan->channel)); + /* disable irq only if not using DMA */ + if (!st->dma_st.dma_chan) { + at91_adc_writel(st, AT91_SAMA5D2_IDR, + BIT(chan->channel)); + } at91_adc_writel(st, AT91_SAMA5D2_CHDR, BIT(chan->channel)); } @@ -340,6 +379,10 @@ 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); + /* if we are using DMA, we must not reenable irq after each trigger */ + if (st->dma_st.dma_chan) + return 0; + enable_irq(st->irq); /* Needed to ACK the DRDY interruption */ @@ -350,6 +393,153 @@ static int at91_adc_reenable_trigger(struct iio_trigger *trig) static const struct iio_trigger_ops at91_adc_trigger_ops = { .set_trigger_state = &at91_adc_configure_trigger, .try_reenable = &at91_adc_reenable_trigger, + .validate_device = iio_trigger_validate_own_device, +}; + +static int at91_adc_dma_size_done(struct at91_adc_state *st) +{ + struct dma_tx_state state; + enum dma_status status; + int i, size; + + status = dmaengine_tx_status(st->dma_st.dma_chan, + st->dma_st.dma_chan->cookie, + &state); + if (status != DMA_IN_PROGRESS) + return 0; + + /* Transferred length is size in bytes from end of buffer */ + i = st->dma_st.rx_buf_sz - state.residue; + + /* Return available bytes */ + if (i >= st->dma_st.buf_idx) + size = i - st->dma_st.buf_idx; + else + size = st->dma_st.rx_buf_sz + i - st->dma_st.buf_idx; + return size; +} + +static void at91_dma_buffer_done(void *data) +{ + struct iio_dev *indio_dev = data; + + iio_trigger_poll_chained(indio_dev->trig); +} + +static int at91_adc_dma_start(struct iio_dev *indio_dev) +{ + struct at91_adc_state *st = iio_priv(indio_dev); + struct dma_async_tx_descriptor *desc; + dma_cookie_t cookie; + int ret; + u8 bit; + + if (!st->dma_st.dma_chan) + return 0; + + /* we start a new DMA, so set buffer index to start */ + st->dma_st.buf_idx = 0; + + /* + * compute buffer size w.r.t. watermark and enabled channels. + * scan_bytes is aligned so we need an exact size for DMA + */ + st->dma_st.rx_buf_sz = 0; + + for_each_set_bit(bit, indio_dev->active_scan_mask, + indio_dev->num_channels) { + struct iio_chan_spec const *chan = indio_dev->channels + bit; + + st->dma_st.rx_buf_sz += chan->scan_type.storagebits / 8; + } + st->dma_st.rx_buf_sz *= st->dma_st.watermark; + + /* Prepare a DMA cyclic transaction */ + desc = dmaengine_prep_dma_cyclic(st->dma_st.dma_chan, + st->dma_st.rx_dma_buf, + st->dma_st.rx_buf_sz, + st->dma_st.rx_buf_sz / 2, + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); + + if (!desc) { + dev_err(&indio_dev->dev, "cannot prepare DMA cyclic\n"); + return -EBUSY; + } + + desc->callback = at91_dma_buffer_done; + desc->callback_param = indio_dev; + + cookie = dmaengine_submit(desc); + ret = dma_submit_error(cookie); + if (ret) { + dev_err(&indio_dev->dev, "cannot submit DMA cyclic\n"); + dmaengine_terminate_async(st->dma_st.dma_chan); + return ret; + } + + /* enable general overrun error signaling */ + at91_adc_writel(st, AT91_SAMA5D2_IER, AT91_SAMA5D2_IER_GOVRE); + /* Issue pending DMA requests */ + dma_async_issue_pending(st->dma_st.dma_chan); + + /* consider current time as DMA start time for timestamps */ + st->dma_st.dma_ts = iio_get_time_ns(indio_dev); + + dev_dbg(&indio_dev->dev, "DMA cyclic started\n"); + + return 0; +} + +static int at91_adc_buffer_postenable(struct iio_dev *indio_dev) +{ + int ret; + + ret = at91_adc_dma_start(indio_dev); + if (ret) { + dev_err(&indio_dev->dev, "buffer postenable failed\n"); + return ret; + } + + return iio_triggered_buffer_postenable(indio_dev); +} + +static int at91_adc_buffer_predisable(struct iio_dev *indio_dev) +{ + struct at91_adc_state *st = iio_priv(indio_dev); + int ret; + u8 bit; + + ret = iio_triggered_buffer_predisable(indio_dev); + if (ret < 0) + dev_err(&indio_dev->dev, "buffer predisable failed\n"); + + if (!st->dma_st.dma_chan) + return ret; + + /* if we are using DMA we must clear registers and end DMA */ + dmaengine_terminate_sync(st->dma_st.dma_chan); + + /* + * For each enabled channel we must read the last converted value + * to clear EOC status and not get a possible interrupt later. + * This value is being read by DMA from LCDR anyway + */ + for_each_set_bit(bit, indio_dev->active_scan_mask, + indio_dev->num_channels) { + struct iio_chan_spec const *chan = indio_dev->channels + bit; + + if (st->dma_st.dma_chan) + at91_adc_readl(st, chan->address); + } + + /* read overflow register to clear possible overflow status */ + at91_adc_readl(st, AT91_SAMA5D2_OVER); + return ret; +} + +static const struct iio_buffer_setup_ops at91_buffer_setup_ops = { + .postenable = &at91_adc_buffer_postenable, + .predisable = &at91_adc_buffer_predisable, }; static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *indio, @@ -388,24 +578,77 @@ static int at91_adc_trigger_init(struct iio_dev *indio) return 0; } -static irqreturn_t at91_adc_trigger_handler(int irq, void *p) +static void at91_adc_trigger_handler_nodma(struct iio_dev *indio_dev, + struct iio_poll_func *pf) { - struct iio_poll_func *pf = p; - struct iio_dev *indio = pf->indio_dev; - struct at91_adc_state *st = iio_priv(indio); + struct at91_adc_state *st = iio_priv(indio_dev); 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; + for_each_set_bit(bit, indio_dev->active_scan_mask, + indio_dev->num_channels) { + struct iio_chan_spec const *chan = indio_dev->channels + bit; st->buffer[i] = at91_adc_readl(st, chan->address); i++; } + iio_push_to_buffers_with_timestamp(indio_dev, st->buffer, + pf->timestamp); +} + +static void at91_adc_trigger_handler_dma(struct iio_dev *indio_dev) +{ + struct at91_adc_state *st = iio_priv(indio_dev); + int transferred_len = at91_adc_dma_size_done(st); + s64 ns = iio_get_time_ns(indio_dev); + s64 interval; + int sample_index = 0, sample_count, sample_size; + + u32 status = at91_adc_readl(st, AT91_SAMA5D2_ISR); + /* if we reached this point, we cannot sample faster */ + if (status & AT91_SAMA5D2_IER_GOVRE) + pr_info_ratelimited("%s: conversion overrun detected\n", + indio_dev->name); + + sample_size = div_s64(st->dma_st.rx_buf_sz, st->dma_st.watermark); + + sample_count = div_s64(transferred_len, sample_size); + + /* + * interval between samples is total time since last transfer handling + * divided by the number of samples (total size divided by sample size) + */ + interval = div_s64((ns - st->dma_st.dma_ts), sample_count); + + while (transferred_len >= sample_size) { + iio_push_to_buffers_with_timestamp(indio_dev, + (st->dma_st.rx_buf + st->dma_st.buf_idx), + (st->dma_st.dma_ts + interval * sample_index)); + /* adjust remaining length */ + transferred_len -= sample_size; + /* adjust buffer index */ + st->dma_st.buf_idx += sample_size; + /* in case of reaching end of buffer, reset index */ + if (st->dma_st.buf_idx >= st->dma_st.rx_buf_sz) + st->dma_st.buf_idx = 0; + sample_index++; + } + /* adjust saved time for next transfer handling */ + st->dma_st.dma_ts = iio_get_time_ns(indio_dev); +} + +static irqreturn_t at91_adc_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct at91_adc_state *st = iio_priv(indio_dev); - iio_push_to_buffers_with_timestamp(indio, st->buffer, pf->timestamp); + if (st->dma_st.dma_chan) + at91_adc_trigger_handler_dma(indio_dev); + else + at91_adc_trigger_handler_nodma(indio_dev, pf); - iio_trigger_notify_done(indio->trig); + iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; } @@ -414,7 +657,7 @@ 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); + &at91_adc_trigger_handler, &at91_buffer_setup_ops); } static unsigned at91_adc_startup_time(unsigned startup_time_min, @@ -485,10 +728,13 @@ static irqreturn_t at91_adc_interrupt(int irq, void *private) if (!(status & imr)) return IRQ_NONE; - if (iio_buffer_enabled(indio)) { + if (iio_buffer_enabled(indio) && !st->dma_st.dma_chan) { disable_irq_nosync(irq); iio_trigger_poll(indio->trig); - } else { + } else if (iio_buffer_enabled(indio) && st->dma_st.dma_chan) { + disable_irq_nosync(irq); + WARN(true, "Unexpected irq occurred\n"); + } else if (!iio_buffer_enabled(indio)) { st->conversion_value = at91_adc_readl(st, st->chan->address); st->conversion_done = true; wake_up_interruptible(&st->wq_data_available); @@ -510,7 +756,6 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev, ret = iio_device_claim_direct_mode(indio_dev); if (ret) return ret; - mutex_lock(&st->lock); st->chan = chan; @@ -580,9 +825,123 @@ static int at91_adc_write_raw(struct iio_dev *indio_dev, return 0; } +static void at91_adc_dma_init(struct platform_device *pdev) +{ + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct at91_adc_state *st = iio_priv(indio_dev); + struct dma_slave_config config = {0}; + /* + * We make the buffer double the size of the fifo, + * such that DMA uses one half of the buffer (full fifo size) + * and the software uses the other half to read/write. + */ + unsigned int pages = DIV_ROUND_UP(AT91_HWFIFO_MAX_SIZE * + AT91_BUFFER_MAX_CONVERSION_BYTES * 2, + PAGE_SIZE); + + if (st->dma_st.dma_chan) + return; + + st->dma_st.dma_chan = dma_request_slave_channel(&pdev->dev, "rx"); + + if (!st->dma_st.dma_chan) { + dev_info(&pdev->dev, "can't get DMA channel\n"); + goto dma_exit; + } + + st->dma_st.rx_buf = dma_alloc_coherent(st->dma_st.dma_chan->device->dev, + pages * PAGE_SIZE, + &st->dma_st.rx_dma_buf, + GFP_KERNEL); + if (!st->dma_st.rx_buf) { + dev_info(&pdev->dev, "can't allocate coherent DMA area\n"); + goto dma_chan_disable; + } + + /* Configure DMA channel to read data register */ + config.direction = DMA_DEV_TO_MEM; + config.src_addr = (phys_addr_t)(st->dma_st.phys_addr + + AT91_SAMA5D2_LCDR); + config.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + config.src_maxburst = 1; + config.dst_maxburst = 1; + + if (dmaengine_slave_config(st->dma_st.dma_chan, &config)) { + dev_info(&pdev->dev, "can't configure DMA slave\n"); + goto dma_free_area; + } + + dev_info(&pdev->dev, "using %s for rx DMA transfers\n", + dma_chan_name(st->dma_st.dma_chan)); + + return; + +dma_free_area: + dma_free_coherent(st->dma_st.dma_chan->device->dev, pages * PAGE_SIZE, + st->dma_st.rx_buf, st->dma_st.rx_dma_buf); +dma_chan_disable: + dma_release_channel(st->dma_st.dma_chan); + st->dma_st.dma_chan = 0; +dma_exit: + dev_info(&pdev->dev, "continuing without DMA support\n"); +} + +static void at91_adc_dma_disable(struct platform_device *pdev) +{ + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct at91_adc_state *st = iio_priv(indio_dev); + unsigned int pages = DIV_ROUND_UP(AT91_HWFIFO_MAX_SIZE * + AT91_BUFFER_MAX_CONVERSION_BYTES * 2, + PAGE_SIZE); + + /* if we are not using DMA, just return */ + if (!st->dma_st.dma_chan) + return; + + /* wait for all transactions to be terminated first*/ + dmaengine_terminate_sync(st->dma_st.dma_chan); + + dma_free_coherent(st->dma_st.dma_chan->device->dev, pages * PAGE_SIZE, + st->dma_st.rx_buf, st->dma_st.rx_dma_buf); + dma_release_channel(st->dma_st.dma_chan); + st->dma_st.dma_chan = 0; + + dev_info(&pdev->dev, "continuing without DMA support\n"); +} + +static int at91_adc_set_watermark(struct iio_dev *indio_dev, unsigned int val) +{ + struct at91_adc_state *st = iio_priv(indio_dev); + + if (val > AT91_HWFIFO_MAX_SIZE) + return -EINVAL; + + if (!st->selected_trig->hw_trig) { + dev_dbg(&indio_dev->dev, "we need hw trigger for DMA\n"); + return 0; + } + + dev_dbg(&indio_dev->dev, "new watermark is %u\n", val); + st->dma_st.watermark = val; + + /* + * The logic here is: if we have watermark 1, it means we do + * each conversion with it's own IRQ, thus we don't need DMA. + * If the watermark is higher, we do DMA to do all the transfers in bulk + */ + + if (val == 1) + at91_adc_dma_disable(to_platform_device(&indio_dev->dev)); + else if (val > 1) + at91_adc_dma_init(to_platform_device(&indio_dev->dev)); + + return 0; +} + static const struct iio_info at91_adc_info = { .read_raw = &at91_adc_read_raw, .write_raw = &at91_adc_write_raw, + .hwfifo_set_watermark = &at91_adc_set_watermark, }; static void at91_adc_hw_init(struct at91_adc_state *st) @@ -599,6 +958,42 @@ static void at91_adc_hw_init(struct at91_adc_state *st) at91_adc_setup_samp_freq(st, st->soc_info.min_sample_rate); } +static ssize_t at91_adc_get_fifo_state(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = + platform_get_drvdata(to_platform_device(dev)); + struct at91_adc_state *st = iio_priv(indio_dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", !!st->dma_st.dma_chan); +} + +static ssize_t at91_adc_get_watermark(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = + platform_get_drvdata(to_platform_device(dev)); + struct at91_adc_state *st = iio_priv(indio_dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", st->dma_st.watermark); +} + +static IIO_DEVICE_ATTR(hwfifo_enabled, 0444, + at91_adc_get_fifo_state, NULL, 0); +static IIO_DEVICE_ATTR(hwfifo_watermark, 0444, + at91_adc_get_watermark, NULL, 0); + +static IIO_CONST_ATTR(hwfifo_watermark_min, "2"); +static IIO_CONST_ATTR(hwfifo_watermark_max, AT91_HWFIFO_MAX_SIZE_STR); + +static const struct attribute *at91_adc_fifo_attributes[] = { + &iio_const_attr_hwfifo_watermark_min.dev_attr.attr, + &iio_const_attr_hwfifo_watermark_max.dev_attr.attr, + &iio_dev_attr_hwfifo_watermark.dev_attr.attr, + &iio_dev_attr_hwfifo_enabled.dev_attr.attr, + NULL, +}; + static int at91_adc_probe(struct platform_device *pdev) { struct iio_dev *indio_dev; @@ -674,6 +1069,9 @@ static int at91_adc_probe(struct platform_device *pdev) if (!res) return -EINVAL; + /* if we plan to use DMA, we need the physical address of the regs */ + st->dma_st.phys_addr = res->start; + st->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(st->base)) return PTR_ERR(st->base); @@ -737,11 +1135,22 @@ static int at91_adc_probe(struct platform_device *pdev) 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"); + ret = iio_device_register(indio_dev); if (ret < 0) - goto per_clk_disable_unprepare; + goto dma_disable; if (st->selected_trig->hw_trig) dev_info(&pdev->dev, "setting up trigger as %s\n", @@ -752,6 +1161,8 @@ static int at91_adc_probe(struct platform_device *pdev) return 0; +dma_disable: + at91_adc_dma_disable(pdev); per_clk_disable_unprepare: clk_disable_unprepare(st->per_clk); vref_disable: @@ -768,6 +1179,8 @@ static int at91_adc_remove(struct platform_device *pdev) iio_device_unregister(indio_dev); + at91_adc_dma_disable(pdev); + clk_disable_unprepare(st->per_clk); regulator_disable(st->vref); -- cgit v1.2.3 From 10c7a314c9fde2342407c1bd2d71d0c0f7ff9662 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Wed, 15 Nov 2017 14:56:48 +0200 Subject: iio: adc: at91-sama5d2_adc: ack DRDY irq in direct mode Need to acknowledge DRDY irq in direct mode/ software triggered mode. Otherwise, on the next conversion, overrun flag will be raised, which is not a correct state. This doesn't affect the functionality, but will generate possible incorrect overrun reports. Signed-off-by: Eugen Hristev Signed-off-by: Jonathan Cameron --- drivers/iio/adc/at91-sama5d2_adc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c index 99f3c2c89768..4eff8351ce29 100644 --- a/drivers/iio/adc/at91-sama5d2_adc.c +++ b/drivers/iio/adc/at91-sama5d2_adc.c @@ -786,6 +786,9 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev, at91_adc_writel(st, AT91_SAMA5D2_IDR, BIT(chan->channel)); at91_adc_writel(st, AT91_SAMA5D2_CHDR, BIT(chan->channel)); + /* Needed to ACK the DRDY interruption */ + at91_adc_readl(st, AT91_SAMA5D2_LCDR); + mutex_unlock(&st->lock); iio_device_release_direct_mode(indio_dev); -- cgit v1.2.3 From 2e64438487697f3f099946edc8acd4ceea6b1ab2 Mon Sep 17 00:00:00 2001 From: Stefan Brüns Date: Sat, 28 Oct 2017 23:12:46 +0200 Subject: iio: adc: ina2xx: Shift bus voltage register to mask flag bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lower bits of the INA219/220 bus voltage register are conversion status flags, properly shift the value. When reading via IIO buffer, the value is passed on unaltered, shifting is the responsibility of the user. Signed-off-by: Stefan Brüns Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ina2xx-adc.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 84a43871f7dc..651dc9df2a7b 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -44,7 +44,6 @@ #define INA226_MASK_ENABLE 0x06 #define INA226_CVRF BIT(3) -#define INA219_CNVR BIT(1) #define INA2XX_MAX_REGISTERS 8 @@ -79,6 +78,11 @@ #define INA226_ITS_MASK GENMASK(5, 3) #define INA226_SHIFT_ITS(val) ((val) << 3) +/* INA219 Bus voltage register, low bits are flags */ +#define INA219_OVF BIT(0) +#define INA219_CNVR BIT(1) +#define INA219_BUS_VOLTAGE_SHIFT 3 + /* Cosmetic macro giving the sampling period for a full P=UxI cycle */ #define SAMPLING_PERIOD(c) ((c->int_time_vbus + c->int_time_vshunt) \ * c->avg) @@ -112,7 +116,7 @@ struct ina2xx_config { u16 config_default; int calibration_factor; int shunt_div; - int bus_voltage_shift; + int bus_voltage_shift; /* position of lsb */ int bus_voltage_lsb; /* uV */ int power_lsb; /* uW */ enum ina2xx_ids chip_id; @@ -135,7 +139,7 @@ static const struct ina2xx_config ina2xx_config[] = { .config_default = INA219_CONFIG_DEFAULT, .calibration_factor = 40960000, .shunt_div = 100, - .bus_voltage_shift = 3, + .bus_voltage_shift = INA219_BUS_VOLTAGE_SHIFT, .bus_voltage_lsb = 4000, .power_lsb = 20000, .chip_id = ina219, @@ -170,6 +174,9 @@ static int ina2xx_read_raw(struct iio_dev *indio_dev, else *val = regval; + if (chan->address == INA2XX_BUS_VOLTAGE) + *val >>= chip->config->bus_voltage_shift; + return IIO_VAL_INT; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: @@ -203,9 +210,9 @@ static int ina2xx_read_raw(struct iio_dev *indio_dev, return IIO_VAL_FRACTIONAL; case INA2XX_BUS_VOLTAGE: - /* processed (mV) = raw*lsb (uV) / (1000 << shift) */ + /* processed (mV) = raw * lsb (uV) / 1000 */ *val = chip->config->bus_voltage_lsb; - *val2 = 1000 << chip->config->bus_voltage_shift; + *val2 = 1000; return IIO_VAL_FRACTIONAL; case INA2XX_POWER: @@ -532,7 +539,7 @@ static ssize_t ina2xx_shunt_resistor_store(struct device *dev, * Sampling Freq is a consequence of the integration times of * the Voltage channels. */ -#define INA219_CHAN_VOLTAGE(_index, _address) { \ +#define INA219_CHAN_VOLTAGE(_index, _address, _shift) { \ .type = IIO_VOLTAGE, \ .address = (_address), \ .indexed = 1, \ @@ -544,7 +551,8 @@ static ssize_t ina2xx_shunt_resistor_store(struct device *dev, .scan_index = (_index), \ .scan_type = { \ .sign = 'u', \ - .realbits = 16, \ + .shift = _shift, \ + .realbits = 16 - _shift, \ .storagebits = 16, \ .endianness = IIO_LE, \ } \ @@ -579,8 +587,8 @@ static const struct iio_chan_spec ina226_channels[] = { }; static const struct iio_chan_spec ina219_channels[] = { - INA219_CHAN_VOLTAGE(0, INA2XX_SHUNT_VOLTAGE), - INA219_CHAN_VOLTAGE(1, INA2XX_BUS_VOLTAGE), + INA219_CHAN_VOLTAGE(0, INA2XX_SHUNT_VOLTAGE, 0), + INA219_CHAN_VOLTAGE(1, INA2XX_BUS_VOLTAGE, INA219_BUS_VOLTAGE_SHIFT), INA219_CHAN(IIO_POWER, 2, INA2XX_POWER), INA219_CHAN(IIO_CURRENT, 3, INA2XX_CURRENT), IIO_CHAN_SOFT_TIMESTAMP(4), -- cgit v1.2.3 From 2d8119d752d4fe794d768b0c42cdf6cf14b37bcc Mon Sep 17 00:00:00 2001 From: Stefan Brüns Date: Sat, 28 Oct 2017 23:12:47 +0200 Subject: iio: adc: ina2xx: Use LSB specifier instead of divider in config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While the config uses the physical value corresponding to the LSB for both the power and the bus voltage register, the shunt voltage is specified as parts of 1 mV. Use the LSB physical value for all registers. No functional change. Signed-off-by: Stefan Brüns Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ina2xx-adc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 651dc9df2a7b..ada98ee4b80a 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -115,7 +115,7 @@ enum ina2xx_ids { ina219, ina226 }; struct ina2xx_config { u16 config_default; int calibration_factor; - int shunt_div; + int shunt_voltage_lsb; /* nV */ int bus_voltage_shift; /* position of lsb */ int bus_voltage_lsb; /* uV */ int power_lsb; /* uW */ @@ -138,7 +138,7 @@ static const struct ina2xx_config ina2xx_config[] = { [ina219] = { .config_default = INA219_CONFIG_DEFAULT, .calibration_factor = 40960000, - .shunt_div = 100, + .shunt_voltage_lsb = 10000, .bus_voltage_shift = INA219_BUS_VOLTAGE_SHIFT, .bus_voltage_lsb = 4000, .power_lsb = 20000, @@ -147,7 +147,7 @@ static const struct ina2xx_config ina2xx_config[] = { [ina226] = { .config_default = INA226_CONFIG_DEFAULT, .calibration_factor = 5120000, - .shunt_div = 400, + .shunt_voltage_lsb = 2500, .bus_voltage_shift = 0, .bus_voltage_lsb = 1250, .power_lsb = 25000, @@ -204,9 +204,9 @@ static int ina2xx_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: switch (chan->address) { case INA2XX_SHUNT_VOLTAGE: - /* processed (mV) = raw/shunt_div */ - *val2 = chip->config->shunt_div; - *val = 1; + /* processed (mV) = raw * lsb(nV) / 1000000 */ + *val = chip->config->shunt_voltage_lsb; + *val2 = 1000000; return IIO_VAL_FRACTIONAL; case INA2XX_BUS_VOLTAGE: -- cgit v1.2.3 From ca6a2d86acaebd7a7e871fbb361a75101cf9f4cb Mon Sep 17 00:00:00 2001 From: Stefan Brüns Date: Sat, 28 Oct 2017 23:12:48 +0200 Subject: iio: adc: ina2xx: Allow setting Shunt Voltage PGA gain and Bus Voltage range MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reducing shunt and bus voltage range improves the accuracy, so allow altering the default settings. Both settings are exposed as gain values. While for the shunt voltage this is straightforward, the bus range settings of 32V (default) and 16V are mapped to gain values of 1 resp. 2, to provide a uniform API to userspace. As the gain settings are incorporated into the raw values by the sensor itself, adjusting of the scale attributes is not necessary. Signed-off-by: Stefan Brüns Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ina2xx-adc.c | 111 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 108 insertions(+), 3 deletions(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index ada98ee4b80a..ddf878163bf9 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -48,8 +48,10 @@ #define INA2XX_MAX_REGISTERS 8 /* settings - depend on use case */ -#define INA219_CONFIG_DEFAULT 0x399F /* PGA=8 */ +#define INA219_CONFIG_DEFAULT 0x399F /* PGA=1/8, BRNG=32V */ #define INA219_DEFAULT_IT 532 +#define INA219_DEFAULT_BRNG 1 /* 32V */ +#define INA219_DEFAULT_PGA 125 /* 1000/8 */ #define INA226_CONFIG_DEFAULT 0x4327 #define INA226_DEFAULT_AVG 4 #define INA226_DEFAULT_IT 1110 @@ -62,6 +64,14 @@ */ #define INA2XX_MODE_MASK GENMASK(3, 0) +/* Gain for VShunt: 1/8 (default), 1/4, 1/2, 1 */ +#define INA219_PGA_MASK GENMASK(12, 11) +#define INA219_SHIFT_PGA(val) ((val) << 11) + +/* VBus range: 32V (default), 16V */ +#define INA219_BRNG_MASK BIT(13) +#define INA219_SHIFT_BRNG(val) ((val) << 13) + /* Averaging for VBus/VShunt/Power */ #define INA226_AVG_MASK GENMASK(11, 9) #define INA226_SHIFT_AVG(val) ((val) << 9) @@ -131,6 +141,8 @@ struct ina2xx_chip_info { int avg; int int_time_vbus; /* Bus voltage integration time uS */ int int_time_vshunt; /* Shunt voltage integration time uS */ + int range_vbus; /* Bus voltage maximum in V */ + int pga_gain_vshunt; /* Shunt voltage PGA gain */ bool allow_async_readout; }; @@ -226,6 +238,18 @@ static int ina2xx_read_raw(struct iio_dev *indio_dev, *val = 1; return IIO_VAL_INT; } + + case IIO_CHAN_INFO_HARDWAREGAIN: + switch (chan->address) { + case INA2XX_SHUNT_VOLTAGE: + *val = chip->pga_gain_vshunt; + *val2 = 1000; + return IIO_VAL_FRACTIONAL; + + case INA2XX_BUS_VOLTAGE: + *val = chip->range_vbus == 32 ? 1 : 2; + return IIO_VAL_INT; + } } return -EINVAL; @@ -360,6 +384,74 @@ static int ina219_set_int_time_vshunt(struct ina2xx_chip_info *chip, return 0; } +static const int ina219_vbus_range_tab[] = { 1, 2 }; +static int ina219_set_vbus_range_denom(struct ina2xx_chip_info *chip, + unsigned int range, + unsigned int *config) +{ + if (range == 1) + chip->range_vbus = 32; + else if (range == 2) + chip->range_vbus = 16; + else + return -EINVAL; + + *config &= ~INA219_BRNG_MASK; + *config |= INA219_SHIFT_BRNG(range == 1 ? 1 : 0) & INA219_BRNG_MASK; + + return 0; +} + +static const int ina219_vshunt_gain_tab[] = { 125, 250, 500, 1000 }; +static const int ina219_vshunt_gain_frac[] = { + 125, 1000, 250, 1000, 500, 1000, 1000, 1000 }; + +static int ina219_set_vshunt_pga_gain(struct ina2xx_chip_info *chip, + unsigned int gain, + unsigned int *config) +{ + int bits; + + if (gain < 125 || gain > 1000) + return -EINVAL; + + bits = find_closest(gain, ina219_vshunt_gain_tab, + ARRAY_SIZE(ina219_vshunt_gain_tab)); + + chip->pga_gain_vshunt = ina219_vshunt_gain_tab[bits]; + bits = 3 - bits; + + *config &= ~INA219_PGA_MASK; + *config |= INA219_SHIFT_PGA(bits) & INA219_PGA_MASK; + + return 0; +} + +static int ina2xx_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_HARDWAREGAIN: + switch (chan->address) { + case INA2XX_SHUNT_VOLTAGE: + *type = IIO_VAL_FRACTIONAL; + *length = sizeof(ina219_vshunt_gain_frac) / sizeof(int); + *vals = ina219_vshunt_gain_frac; + return IIO_AVAIL_LIST; + + case INA2XX_BUS_VOLTAGE: + *type = IIO_VAL_INT; + *length = sizeof(ina219_vbus_range_tab) / sizeof(int); + *vals = ina219_vbus_range_tab; + return IIO_AVAIL_LIST; + } + } + + return -EINVAL; +} + static int ina2xx_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) @@ -402,6 +494,14 @@ static int ina2xx_write_raw(struct iio_dev *indio_dev, } break; + case IIO_CHAN_INFO_HARDWAREGAIN: + if (chan->address == INA2XX_SHUNT_VOLTAGE) + ret = ina219_set_vshunt_pga_gain(chip, val * 1000 + + val2 / 1000, &tmp); + else + ret = ina219_set_vbus_range_denom(chip, val, &tmp); + break; + default: ret = -EINVAL; } @@ -546,7 +646,10 @@ static ssize_t ina2xx_shunt_resistor_store(struct device *dev, .channel = (_index), \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_INT_TIME), \ + BIT(IIO_CHAN_INFO_INT_TIME) | \ + BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ + .info_mask_separate_available = \ + BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ .info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .scan_index = (_index), \ .scan_type = { \ @@ -754,7 +857,6 @@ static IIO_CONST_ATTR_NAMED(ina226_integration_time_available, integration_time_available, "0.000140 0.000204 0.000332 0.000588 0.001100 0.002116 0.004156 0.008244"); - static IIO_DEVICE_ATTR(in_allow_async_readout, S_IRUGO | S_IWUSR, ina2xx_allow_async_readout_show, ina2xx_allow_async_readout_store, 0); @@ -788,6 +890,7 @@ static const struct attribute_group ina226_attribute_group = { static const struct iio_info ina219_info = { .attrs = &ina219_attribute_group, .read_raw = ina2xx_read_raw, + .read_avail = ina2xx_read_avail, .write_raw = ina2xx_write_raw, .debugfs_reg_access = ina2xx_debug_reg, }; @@ -868,6 +971,8 @@ static int ina2xx_probe(struct i2c_client *client, chip->avg = 1; ina219_set_int_time_vbus(chip, INA219_DEFAULT_IT, &val); ina219_set_int_time_vshunt(chip, INA219_DEFAULT_IT, &val); + ina219_set_vbus_range_denom(chip, INA219_DEFAULT_BRNG, &val); + ina219_set_vshunt_pga_gain(chip, INA219_DEFAULT_PGA, &val); } ret = ina2xx_init(chip, val); -- cgit v1.2.3 From 0bae72aa8a89fd2b6a8ae4b21ff9141fc1f3b496 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Wed, 25 Oct 2017 11:27:44 +0200 Subject: iio: adc: stm32: remove const channel names definition Remove const array that defines channels. Build channels definition at probe time, when initializing channels (only for requested ones). This will ease adding differential channels support. Signed-off-by: Fabrice Gasnier Signed-off-by: Jonathan Cameron --- drivers/iio/adc/stm32-adc.c | 66 ++++++++++----------------------------------- 1 file changed, 14 insertions(+), 52 deletions(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index c9d96f935dba..99981de41e0d 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -153,6 +153,8 @@ enum stm32h7_adc_dmngt { /* BOOST bit must be set on STM32H7 when ADC clock is above 20MHz */ #define STM32H7_BOOST_CLKRATE 20000000UL +#define STM32_ADC_CH_MAX 20 /* max number of channels */ +#define STM32_ADC_CH_SZ 5 /* max channel name size */ #define STM32_ADC_MAX_SQ 16 /* SQ1..SQ16 */ #define STM32_ADC_MAX_SMP 7 /* SMPx range is [0..7] */ #define STM32_ADC_TIMEOUT_US 100000 @@ -300,6 +302,7 @@ struct stm32_adc_cfg { * @pcsel bitmask to preselect channels on some devices * @smpr_val: sampling time settings (e.g. smpr1 / smpr2) * @cal: optional calibration data on some devices + * @chan_name: channel name array */ struct stm32_adc { struct stm32_adc_common *common; @@ -321,69 +324,28 @@ struct stm32_adc { u32 pcsel; u32 smpr_val[2]; struct stm32_adc_calib cal; -}; - -/** - * struct stm32_adc_chan_spec - specification of stm32 adc channel - * @type: IIO channel type - * @channel: channel number (single ended) - * @name: channel name (single ended) - */ -struct stm32_adc_chan_spec { - enum iio_chan_type type; - int channel; - const char *name; + char chan_name[STM32_ADC_CH_MAX][STM32_ADC_CH_SZ]; }; /** * struct stm32_adc_info - stm32 ADC, per instance config data - * @channels: Reference to stm32 channels spec * @max_channels: Number of channels * @resolutions: available resolutions * @num_res: number of available resolutions */ struct stm32_adc_info { - const struct stm32_adc_chan_spec *channels; int max_channels; const unsigned int *resolutions; const unsigned int num_res; }; -/* - * Input definitions common for all instances: - * stm32f4 can have up to 16 channels - * stm32h7 can have up to 20 channels - */ -static const struct stm32_adc_chan_spec stm32_adc_channels[] = { - { IIO_VOLTAGE, 0, "in0" }, - { IIO_VOLTAGE, 1, "in1" }, - { IIO_VOLTAGE, 2, "in2" }, - { IIO_VOLTAGE, 3, "in3" }, - { IIO_VOLTAGE, 4, "in4" }, - { IIO_VOLTAGE, 5, "in5" }, - { IIO_VOLTAGE, 6, "in6" }, - { IIO_VOLTAGE, 7, "in7" }, - { IIO_VOLTAGE, 8, "in8" }, - { IIO_VOLTAGE, 9, "in9" }, - { IIO_VOLTAGE, 10, "in10" }, - { IIO_VOLTAGE, 11, "in11" }, - { IIO_VOLTAGE, 12, "in12" }, - { IIO_VOLTAGE, 13, "in13" }, - { IIO_VOLTAGE, 14, "in14" }, - { IIO_VOLTAGE, 15, "in15" }, - { IIO_VOLTAGE, 16, "in16" }, - { IIO_VOLTAGE, 17, "in17" }, - { IIO_VOLTAGE, 18, "in18" }, - { IIO_VOLTAGE, 19, "in19" }, -}; - static const unsigned int stm32f4_adc_resolutions[] = { /* sorted values so the index matches RES[1:0] in STM32F4_ADC_CR1 */ 12, 10, 8, 6, }; +/* stm32f4 can have up to 16 channels */ static const struct stm32_adc_info stm32f4_adc_info = { - .channels = stm32_adc_channels, .max_channels = 16, .resolutions = stm32f4_adc_resolutions, .num_res = ARRAY_SIZE(stm32f4_adc_resolutions), @@ -394,9 +356,9 @@ static const unsigned int stm32h7_adc_resolutions[] = { 16, 14, 12, 10, 8, }; +/* stm32h7 can have up to 20 channels */ static const struct stm32_adc_info stm32h7_adc_info = { - .channels = stm32_adc_channels, - .max_channels = 20, + .max_channels = STM32_ADC_CH_MAX, .resolutions = stm32h7_adc_resolutions, .num_res = ARRAY_SIZE(stm32h7_adc_resolutions), }; @@ -1628,15 +1590,16 @@ static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns) } static void stm32_adc_chan_init_one(struct iio_dev *indio_dev, - struct iio_chan_spec *chan, - const struct stm32_adc_chan_spec *channel, + struct iio_chan_spec *chan, u32 vinp, int scan_index, u32 smp) { struct stm32_adc *adc = iio_priv(indio_dev); + char *name = adc->chan_name[vinp]; - chan->type = channel->type; - chan->channel = channel->channel; - chan->datasheet_name = channel->name; + chan->type = IIO_VOLTAGE; + chan->channel = vinp; + snprintf(name, STM32_ADC_CH_SZ, "in%d", vinp); + chan->datasheet_name = name; chan->scan_index = scan_index; chan->indexed = 1; chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); @@ -1699,8 +1662,7 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) scan_index, &smp); stm32_adc_chan_init_one(indio_dev, &channels[scan_index], - &adc_info->channels[val], - scan_index, smp); + val, scan_index, smp); scan_index++; } -- cgit v1.2.3 From 3fb2e24ed7b713bd6c1a03ab9f9849f76629f26f Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Wed, 25 Oct 2017 11:27:45 +0200 Subject: iio: adc: stm32: add support for differential channels STM32H7 ADC channels can be configured either as single ended or differential with 'st,adc-channels' or 'st,adc-diff-channels' (positive and negative input pair: , ...). Differential channels have different offset and scale, from spec: raw value = (full_scale / 2) * (1 + (vinp - vinn) / vref). Add offset attribute. Differential channels are selected by DIFSEL register. Negative inputs must be added to pre-selected channels as well (PCSEL). Signed-off-by: Fabrice Gasnier Signed-off-by: Jonathan Cameron --- drivers/iio/adc/stm32-adc.c | 123 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 103 insertions(+), 20 deletions(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 99981de41e0d..da7fef376ed8 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -92,6 +92,7 @@ #define STM32H7_ADC_SQR3 0x38 #define STM32H7_ADC_SQR4 0x3C #define STM32H7_ADC_DR 0x40 +#define STM32H7_ADC_DIFSEL 0xC0 #define STM32H7_ADC_CALFACT 0xC4 #define STM32H7_ADC_CALFACT2 0xC8 @@ -154,7 +155,7 @@ enum stm32h7_adc_dmngt { #define STM32H7_BOOST_CLKRATE 20000000UL #define STM32_ADC_CH_MAX 20 /* max number of channels */ -#define STM32_ADC_CH_SZ 5 /* max channel name size */ +#define STM32_ADC_CH_SZ 10 /* max channel name size */ #define STM32_ADC_MAX_SQ 16 /* SQ1..SQ16 */ #define STM32_ADC_MAX_SMP 7 /* SMPx range is [0..7] */ #define STM32_ADC_TIMEOUT_US 100000 @@ -299,6 +300,7 @@ struct stm32_adc_cfg { * @rx_buf: dma rx buffer cpu address * @rx_dma_buf: dma rx buffer bus address * @rx_buf_sz: dma rx buffer size + * @difsel bitmask to set single-ended/differential channel * @pcsel bitmask to preselect channels on some devices * @smpr_val: sampling time settings (e.g. smpr1 / smpr2) * @cal: optional calibration data on some devices @@ -321,12 +323,18 @@ struct stm32_adc { u8 *rx_buf; dma_addr_t rx_dma_buf; unsigned int rx_buf_sz; + u32 difsel; u32 pcsel; u32 smpr_val[2]; struct stm32_adc_calib cal; char chan_name[STM32_ADC_CH_MAX][STM32_ADC_CH_SZ]; }; +struct stm32_adc_diff_channel { + u32 vinp; + u32 vinn; +}; + /** * struct stm32_adc_info - stm32 ADC, per instance config data * @max_channels: Number of channels @@ -945,15 +953,19 @@ pwr_dwn: * stm32h7_adc_prepare() - Leave power down mode to enable ADC. * @adc: stm32 adc instance * Leave power down mode. + * Configure channels as single ended or differential before enabling ADC. * Enable ADC. * Restore calibration data. - * Pre-select channels that may be used in PCSEL (required by input MUX / IO). + * Pre-select channels that may be used in PCSEL (required by input MUX / IO): + * - Only one input is selected for single ended (e.g. 'vinp') + * - Two inputs are selected for differential channels (e.g. 'vinp' & 'vinn') */ static int stm32h7_adc_prepare(struct stm32_adc *adc) { int ret; stm32h7_adc_exit_pwr_down(adc); + stm32_adc_writel(adc, STM32H7_ADC_DIFSEL, adc->difsel); ret = stm32h7_adc_enable(adc); if (ret) @@ -1225,10 +1237,23 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev, return ret; case IIO_CHAN_INFO_SCALE: - *val = adc->common->vref_mv; - *val2 = chan->scan_type.realbits; + if (chan->differential) { + *val = adc->common->vref_mv * 2; + *val2 = chan->scan_type.realbits; + } else { + *val = adc->common->vref_mv; + *val2 = chan->scan_type.realbits; + } return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_OFFSET: + if (chan->differential) + /* ADC_full_scale / 2 */ + *val = -((1 << chan->scan_type.realbits) / 2); + else + *val = 0; + return IIO_VAL_INT; + default: return -EINVAL; } @@ -1591,29 +1616,39 @@ static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns) static void stm32_adc_chan_init_one(struct iio_dev *indio_dev, struct iio_chan_spec *chan, u32 vinp, - int scan_index, u32 smp) + u32 vinn, int scan_index, bool differential) { struct stm32_adc *adc = iio_priv(indio_dev); char *name = adc->chan_name[vinp]; chan->type = IIO_VOLTAGE; chan->channel = vinp; - snprintf(name, STM32_ADC_CH_SZ, "in%d", vinp); + if (differential) { + chan->differential = 1; + chan->channel2 = vinn; + snprintf(name, STM32_ADC_CH_SZ, "in%d-in%d", vinp, vinn); + } else { + snprintf(name, STM32_ADC_CH_SZ, "in%d", vinp); + } chan->datasheet_name = name; chan->scan_index = scan_index; chan->indexed = 1; chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); - chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); + chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET); chan->scan_type.sign = 'u'; chan->scan_type.realbits = adc->cfg->adc_info->resolutions[adc->res]; chan->scan_type.storagebits = 16; chan->ext_info = stm32_adc_ext_info; - /* Prepare sampling time settings */ - stm32_adc_smpr_init(adc, chan->channel, smp); - /* pre-build selected channels mask */ adc->pcsel |= BIT(chan->channel); + if (differential) { + /* pre-build diff channels mask */ + adc->difsel |= BIT(chan->channel); + /* Also add negative input to pre-selected channels */ + adc->pcsel |= BIT(chan->channel2); + } } static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) @@ -1621,17 +1656,40 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) struct device_node *node = indio_dev->dev.of_node; struct stm32_adc *adc = iio_priv(indio_dev); const struct stm32_adc_info *adc_info = adc->cfg->adc_info; + struct stm32_adc_diff_channel diff[STM32_ADC_CH_MAX]; struct property *prop; const __be32 *cur; struct iio_chan_spec *channels; - int scan_index = 0, num_channels, ret; + int scan_index = 0, num_channels = 0, num_diff = 0, ret, i; u32 val, smp = 0; - num_channels = of_property_count_u32_elems(node, "st,adc-channels"); - if (num_channels < 0 || - num_channels > adc_info->max_channels) { + ret = of_property_count_u32_elems(node, "st,adc-channels"); + if (ret > adc_info->max_channels) { dev_err(&indio_dev->dev, "Bad st,adc-channels?\n"); - return num_channels < 0 ? num_channels : -EINVAL; + return -EINVAL; + } else if (ret > 0) { + num_channels += ret; + } + + ret = of_property_count_elems_of_size(node, "st,adc-diff-channels", + sizeof(*diff)); + if (ret > adc_info->max_channels) { + dev_err(&indio_dev->dev, "Bad st,adc-diff-channels?\n"); + return -EINVAL; + } else if (ret > 0) { + int size = ret * sizeof(*diff) / sizeof(u32); + + num_diff = ret; + num_channels += ret; + ret = of_property_read_u32_array(node, "st,adc-diff-channels", + (u32 *)diff, size); + if (ret) + return ret; + } + + if (!num_channels) { + dev_err(&indio_dev->dev, "No channels configured\n"); + return -ENODATA; } /* Optional sample time is provided either for each, or all channels */ @@ -1652,6 +1710,33 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) return -EINVAL; } + /* Channel can't be configured both as single-ended & diff */ + for (i = 0; i < num_diff; i++) { + if (val == diff[i].vinp) { + dev_err(&indio_dev->dev, + "channel %d miss-configured\n", val); + return -EINVAL; + } + } + stm32_adc_chan_init_one(indio_dev, &channels[scan_index], val, + 0, scan_index, false); + scan_index++; + } + + for (i = 0; i < num_diff; i++) { + if (diff[i].vinp >= adc_info->max_channels || + diff[i].vinn >= adc_info->max_channels) { + dev_err(&indio_dev->dev, "Invalid channel in%d-in%d\n", + diff[i].vinp, diff[i].vinn); + return -EINVAL; + } + stm32_adc_chan_init_one(indio_dev, &channels[scan_index], + diff[i].vinp, diff[i].vinn, scan_index, + true); + scan_index++; + } + + for (i = 0; i < scan_index; i++) { /* * Using of_property_read_u32_index(), smp value will only be * modified if valid u32 value can be decoded. This allows to @@ -1659,11 +1744,9 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) * value per channel. */ of_property_read_u32_index(node, "st,min-sample-time-nsecs", - scan_index, &smp); - - stm32_adc_chan_init_one(indio_dev, &channels[scan_index], - val, scan_index, smp); - scan_index++; + i, &smp); + /* Prepare sampling time settings */ + stm32_adc_smpr_init(adc, channels[i].channel, smp); } indio_dev->num_channels = scan_index; -- cgit v1.2.3 From edf7550a1f93a88be2bf743b5d352b278d1b789c Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Tue, 31 Oct 2017 12:42:03 +1030 Subject: iio: adc: aspeed: Deassert reset in probe The ASPEED SoC must deassert a reset in order to use the ADC peripheral. The device tree bindings are updated to document the resets phandle, and the example is updated to match what is expected for both the reset and clock phandle. Note that the bindings should have always had the reset controller, as the hardware is unusable without it. Signed-off-by: Joel Stanley Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/aspeed_adc.txt | 4 +++- drivers/iio/adc/aspeed_adc.c | 25 ++++++++++++++++------ 2 files changed, 22 insertions(+), 7 deletions(-) (limited to 'drivers/iio/adc') diff --git a/Documentation/devicetree/bindings/iio/adc/aspeed_adc.txt b/Documentation/devicetree/bindings/iio/adc/aspeed_adc.txt index 674e133b7cd7..034fc2ba100e 100644 --- a/Documentation/devicetree/bindings/iio/adc/aspeed_adc.txt +++ b/Documentation/devicetree/bindings/iio/adc/aspeed_adc.txt @@ -8,6 +8,7 @@ Required properties: - reg: memory window mapping address and length - clocks: Input clock used to derive the sample clock. Expected to be the SoC's APB clock. +- resets: Reset controller phandle - #io-channel-cells: Must be set to <1> to indicate channels are selected by index. @@ -15,6 +16,7 @@ Example: adc@1e6e9000 { compatible = "aspeed,ast2400-adc"; reg = <0x1e6e9000 0xb0>; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_ADC>; #io-channel-cells = <1>; }; diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c index 8a958d5f1905..327a49ba1991 100644 --- a/drivers/iio/adc/aspeed_adc.c +++ b/drivers/iio/adc/aspeed_adc.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -53,11 +54,12 @@ struct aspeed_adc_model_data { }; struct aspeed_adc_data { - struct device *dev; - void __iomem *base; - spinlock_t clk_lock; - struct clk_hw *clk_prescaler; - struct clk_hw *clk_scaler; + struct device *dev; + void __iomem *base; + spinlock_t clk_lock; + struct clk_hw *clk_prescaler; + struct clk_hw *clk_scaler; + struct reset_control *rst; }; #define ASPEED_CHAN(_idx, _data_reg_addr) { \ @@ -217,6 +219,15 @@ static int aspeed_adc_probe(struct platform_device *pdev) goto scaler_error; } + data->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); + if (IS_ERR(data->rst)) { + dev_err(&pdev->dev, + "invalid or missing reset controller device tree entry"); + ret = PTR_ERR(data->rst); + goto reset_error; + } + reset_control_deassert(data->rst); + model_data = of_device_get_match_data(&pdev->dev); if (model_data->wait_init_sequence) { @@ -263,9 +274,10 @@ iio_register_error: writel(ASPEED_OPERATION_MODE_POWER_DOWN, data->base + ASPEED_REG_ENGINE_CONTROL); clk_disable_unprepare(data->clk_scaler->clk); +reset_error: + reset_control_assert(data->rst); clk_enable_error: clk_hw_unregister_divider(data->clk_scaler); - scaler_error: clk_hw_unregister_divider(data->clk_prescaler); return ret; @@ -280,6 +292,7 @@ static int aspeed_adc_remove(struct platform_device *pdev) writel(ASPEED_OPERATION_MODE_POWER_DOWN, data->base + ASPEED_REG_ENGINE_CONTROL); clk_disable_unprepare(data->clk_scaler->clk); + reset_control_assert(data->rst); clk_hw_unregister_divider(data->clk_scaler); clk_hw_unregister_divider(data->clk_prescaler); -- cgit v1.2.3 From 930df4d853a8493f6e203d14a944c226c64750c3 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Tue, 7 Nov 2017 22:10:06 +0800 Subject: iio: adc: meson-saradc: remove irrelevant clock "sana" The "sana" clock is not used at SAR ADC module in Amlogic Meson SoC, it is irrelevant for the SAR ADC. Signed-off-by: Xingyu Chen Signed-off-by: Yixun Lan Reviewed-by: Martin Blumenstingl Signed-off-by: Jonathan Cameron --- drivers/iio/adc/meson_saradc.c | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index 9c6932ffc0af..f0b6502a8904 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -231,7 +231,6 @@ struct meson_sar_adc_priv { const struct meson_sar_adc_data *data; struct clk *clkin; struct clk *core_clk; - struct clk *sana_clk; struct clk *adc_sel_clk; struct clk *adc_clk; struct clk_gate clk_gate; @@ -708,12 +707,6 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev) goto err_core_clk; } - ret = clk_prepare_enable(priv->sana_clk); - if (ret) { - dev_err(indio_dev->dev.parent, "failed to enable sana clk\n"); - goto err_sana_clk; - } - regval = FIELD_PREP(MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, 1); regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, regval); @@ -741,8 +734,6 @@ err_adc_clk: MESON_SAR_ADC_REG3_ADC_EN, 0); regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11, MESON_SAR_ADC_REG11_BANDGAP_EN, 0); - clk_disable_unprepare(priv->sana_clk); -err_sana_clk: clk_disable_unprepare(priv->core_clk); err_core_clk: regulator_disable(priv->vref); @@ -768,7 +759,6 @@ static int meson_sar_adc_hw_disable(struct iio_dev *indio_dev) regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11, MESON_SAR_ADC_REG11_BANDGAP_EN, 0); - clk_disable_unprepare(priv->sana_clk); clk_disable_unprepare(priv->core_clk); regulator_disable(priv->vref); @@ -961,16 +951,6 @@ static int meson_sar_adc_probe(struct platform_device *pdev) return PTR_ERR(priv->core_clk); } - priv->sana_clk = devm_clk_get(&pdev->dev, "sana"); - if (IS_ERR(priv->sana_clk)) { - if (PTR_ERR(priv->sana_clk) == -ENOENT) { - priv->sana_clk = NULL; - } else { - dev_err(&pdev->dev, "failed to get sana clk\n"); - return PTR_ERR(priv->sana_clk); - } - } - priv->adc_clk = devm_clk_get(&pdev->dev, "adc_clk"); if (IS_ERR(priv->adc_clk)) { if (PTR_ERR(priv->adc_clk) == -ENOENT) { -- cgit v1.2.3 From 8d05ffd2b8a08668cfea9e64a2991ab8ec9b494e Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sat, 25 Nov 2017 09:38:17 +0100 Subject: iio: Add macro to populate struct iio_map array The GPIO core provides a handy GPIO_LOOKUP() macro to populate a struct gpiod_lookup array without having to spell out attribute names (but still avoid breakage when attributes within the struct are rearranged or added). The axp288_adc.c driver uses a similar macro to populate a struct iio_map array. Make it available to others. Cc: Jacob Pan Signed-off-by: Lukas Wunner Acked-by: Chen-Yu Tsai Signed-off-by: Jonathan Cameron --- drivers/iio/adc/axp288_adc.c | 20 ++++++-------------- include/linux/iio/machine.h | 7 +++++++ 2 files changed, 13 insertions(+), 14 deletions(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/axp288_adc.c b/drivers/iio/adc/axp288_adc.c index 60c9e853dd81..031d568b4972 100644 --- a/drivers/iio/adc/axp288_adc.c +++ b/drivers/iio/adc/axp288_adc.c @@ -92,22 +92,14 @@ static const struct iio_chan_spec axp288_adc_channels[] = { }, }; -#define AXP288_ADC_MAP(_adc_channel_label, _consumer_dev_name, \ - _consumer_channel) \ - { \ - .adc_channel_label = _adc_channel_label, \ - .consumer_dev_name = _consumer_dev_name, \ - .consumer_channel = _consumer_channel, \ - } - /* for consumer drivers */ static struct iio_map axp288_adc_default_maps[] = { - AXP288_ADC_MAP("TS_PIN", "axp288-batt", "axp288-batt-temp"), - AXP288_ADC_MAP("PMIC_TEMP", "axp288-pmic", "axp288-pmic-temp"), - AXP288_ADC_MAP("GPADC", "axp288-gpadc", "axp288-system-temp"), - AXP288_ADC_MAP("BATT_CHG_I", "axp288-chrg", "axp288-chrg-curr"), - AXP288_ADC_MAP("BATT_DISCHRG_I", "axp288-chrg", "axp288-chrg-d-curr"), - AXP288_ADC_MAP("BATT_V", "axp288-batt", "axp288-batt-volt"), + IIO_MAP("TS_PIN", "axp288-batt", "axp288-batt-temp"), + IIO_MAP("PMIC_TEMP", "axp288-pmic", "axp288-pmic-temp"), + IIO_MAP("GPADC", "axp288-gpadc", "axp288-system-temp"), + IIO_MAP("BATT_CHG_I", "axp288-chrg", "axp288-chrg-curr"), + IIO_MAP("BATT_DISCHRG_I", "axp288-chrg", "axp288-chrg-d-curr"), + IIO_MAP("BATT_V", "axp288-batt", "axp288-batt-volt"), {}, }; diff --git a/include/linux/iio/machine.h b/include/linux/iio/machine.h index 1601a2a63a72..5e1cfa75f652 100644 --- a/include/linux/iio/machine.h +++ b/include/linux/iio/machine.h @@ -28,4 +28,11 @@ struct iio_map { void *consumer_data; }; +#define IIO_MAP(_provider_channel, _consumer_dev_name, _consumer_channel) \ +{ \ + .adc_channel_label = _provider_channel, \ + .consumer_dev_name = _consumer_dev_name, \ + .consumer_channel = _consumer_channel, \ +} + #endif -- cgit v1.2.3 From 6e93e26193c83b29eb397190aff449f53618a552 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Tue, 5 Dec 2017 15:55:59 +0100 Subject: iio: stm32: Adopt SPDX identifier Add SPDX identifier in stm32's files in IIO directory Signed-off-by: Benjamin Gaignard Acked-by: Fabrice Gasnier Acked-by: Philippe Ombredanne Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/stm32-adc-core.c | 14 +------------- drivers/iio/adc/stm32-adc-core.h | 14 +------------- drivers/iio/adc/stm32-adc.c | 15 +-------------- drivers/iio/counter/stm32-lptimer-cnt.c | 2 +- drivers/iio/dac/stm32-dac-core.c | 14 +------------- drivers/iio/dac/stm32-dac-core.h | 15 +-------------- drivers/iio/dac/stm32-dac.c | 15 +-------------- drivers/iio/trigger/stm32-lptimer-trigger.c | 3 +-- drivers/iio/trigger/stm32-timer-trigger.c | 2 +- 9 files changed, 9 insertions(+), 85 deletions(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c index 6aefef99f935..40be7d9fadbf 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * This file is part of STM32 ADC driver * @@ -6,19 +7,6 @@ * * Inspired from: fsl-imx25-tsadc * - * License type: GPLv2 - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . */ #include diff --git a/drivers/iio/adc/stm32-adc-core.h b/drivers/iio/adc/stm32-adc-core.h index 250ee958a669..8af507b3f32d 100644 --- a/drivers/iio/adc/stm32-adc-core.h +++ b/drivers/iio/adc/stm32-adc-core.h @@ -1,22 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * This file is part of STM32 ADC driver * * Copyright (C) 2016, STMicroelectronics - All Rights Reserved * Author: Fabrice Gasnier . * - * License type: GPLv2 - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . */ #ifndef __STM32_ADC_H diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index da7fef376ed8..6dbf9549cdc9 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -1,22 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * This file is part of STM32 ADC driver * * Copyright (C) 2016, STMicroelectronics - All Rights Reserved * Author: Fabrice Gasnier . - * - * License type: GPLv2 - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . */ #include diff --git a/drivers/iio/counter/stm32-lptimer-cnt.c b/drivers/iio/counter/stm32-lptimer-cnt.c index 81ae5f74216d..42fb8ba67090 100644 --- a/drivers/iio/counter/stm32-lptimer-cnt.c +++ b/drivers/iio/counter/stm32-lptimer-cnt.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * STM32 Low-Power Timer Encoder and Counter driver * @@ -7,7 +8,6 @@ * * Inspired by 104-quad-8 and stm32-timer-trigger drivers. * - * License terms: GNU General Public License (GPL), version 2 */ #include diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c index 55026fe1c610..d0fb3124de07 100644 --- a/drivers/iio/dac/stm32-dac-core.c +++ b/drivers/iio/dac/stm32-dac-core.c @@ -1,22 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * This file is part of STM32 DAC driver * * Copyright (C) 2017, STMicroelectronics - All Rights Reserved * Author: Fabrice Gasnier . * - * License type: GPLv2 - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . */ #include diff --git a/drivers/iio/dac/stm32-dac-core.h b/drivers/iio/dac/stm32-dac-core.h index daf09931857c..d3b415fb9575 100644 --- a/drivers/iio/dac/stm32-dac-core.h +++ b/drivers/iio/dac/stm32-dac-core.h @@ -1,22 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * This file is part of STM32 DAC driver * * Copyright (C) 2017, STMicroelectronics - All Rights Reserved * Author: Fabrice Gasnier . - * - * License type: GPLv2 - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . */ #ifndef __STM32_DAC_CORE_H diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c index 9ffab02bf9f9..cce26a3a6627 100644 --- a/drivers/iio/dac/stm32-dac.c +++ b/drivers/iio/dac/stm32-dac.c @@ -1,23 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * This file is part of STM32 DAC driver * * Copyright (C) 2017, STMicroelectronics - All Rights Reserved * Authors: Amelie Delaunay * Fabrice Gasnier - * - * License type: GPLv2 - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . */ #include diff --git a/drivers/iio/trigger/stm32-lptimer-trigger.c b/drivers/iio/trigger/stm32-lptimer-trigger.c index de361d879929..98cdc7e47f3d 100644 --- a/drivers/iio/trigger/stm32-lptimer-trigger.c +++ b/drivers/iio/trigger/stm32-lptimer-trigger.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * STM32 Low-Power Timer Trigger driver * @@ -5,8 +6,6 @@ * * Author: Fabrice Gasnier . * - * License terms: GNU General Public License (GPL), version 2 - * * Inspired by Benjamin Gaignard's stm32-timer-trigger driver */ diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c index b542dc484969..ccf1ce653b25 100644 --- a/drivers/iio/trigger/stm32-timer-trigger.c +++ b/drivers/iio/trigger/stm32-timer-trigger.c @@ -1,9 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) STMicroelectronics 2016 * * Author: Benjamin Gaignard * - * License terms: GNU General Public License (GPL), version 2 */ #include -- cgit v1.2.3 From fda29dbac9e6604f8eeb660953a2bef360514dc7 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Tue, 31 Oct 2017 21:01:46 +0100 Subject: iio: adc: meson-saradc: fix the clock frequency on Meson8 and Meson8b GX SoCs use a 1.2 MHz ADC clock, while the older SoCs use a 1.14 MHz clock. A comment in the driver from Amlogic's GPL kernel says that it's running at 1.28 MHz. However, it's actually programming a divider of 20 + 1. With a XTAL clock of 24 MHz this results in a frequency of 1.14 MHz. (their calculation might be based on a 27 MHz XTAL clock, but this is not what we have on the Meson8 and Meson8b SoCs). The ADC was still working with the 1.2MHz clock. In my own tests I did not see a difference between 1.2 and 1.14 MHz (regardless of the clock frequency used, the ADC results were identical). Signed-off-by: Martin Blumenstingl Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/meson_saradc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index 48fdbb3a061b..24025f179621 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -221,6 +221,7 @@ enum meson_sar_adc_chan7_mux_sel { struct meson_sar_adc_data { bool has_bl30_integration; + unsigned long clock_rate; u32 bandgap_reg; unsigned int resolution; const char *name; @@ -683,7 +684,7 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) return ret; } - ret = clk_set_rate(priv->adc_clk, 1200000); + ret = clk_set_rate(priv->adc_clk, priv->data->clock_rate); if (ret) { dev_err(indio_dev->dev.parent, "failed to set adc clock rate\n"); @@ -856,6 +857,7 @@ static const struct iio_info meson_sar_adc_iio_info = { static const struct meson_sar_adc_data meson_sar_adc_meson8_data = { .has_bl30_integration = false, + .clock_rate = 1150000, .bandgap_reg = MESON_SAR_ADC_DELTA_10, .regmap_config = &meson_sar_adc_regmap_config_meson8, .resolution = 10, @@ -864,6 +866,7 @@ static const struct meson_sar_adc_data meson_sar_adc_meson8_data = { static const struct meson_sar_adc_data meson_sar_adc_meson8b_data = { .has_bl30_integration = false, + .clock_rate = 1150000, .bandgap_reg = MESON_SAR_ADC_DELTA_10, .regmap_config = &meson_sar_adc_regmap_config_meson8, .resolution = 10, @@ -872,6 +875,7 @@ static const struct meson_sar_adc_data meson_sar_adc_meson8b_data = { static const struct meson_sar_adc_data meson_sar_adc_gxbb_data = { .has_bl30_integration = true, + .clock_rate = 1200000, .bandgap_reg = MESON_SAR_ADC_REG11, .regmap_config = &meson_sar_adc_regmap_config_gxbb, .resolution = 10, @@ -880,6 +884,7 @@ static const struct meson_sar_adc_data meson_sar_adc_gxbb_data = { static const struct meson_sar_adc_data meson_sar_adc_gxl_data = { .has_bl30_integration = true, + .clock_rate = 1200000, .bandgap_reg = MESON_SAR_ADC_REG11, .regmap_config = &meson_sar_adc_regmap_config_gxbb, .resolution = 12, @@ -888,6 +893,7 @@ static const struct meson_sar_adc_data meson_sar_adc_gxl_data = { static const struct meson_sar_adc_data meson_sar_adc_gxm_data = { .has_bl30_integration = true, + .clock_rate = 1200000, .bandgap_reg = MESON_SAR_ADC_REG11, .regmap_config = &meson_sar_adc_regmap_config_gxbb, .resolution = 12, -- cgit v1.2.3 From ab569a4c55422c9fb123e9ce8bffd44198724c51 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Tue, 31 Oct 2017 21:01:47 +0100 Subject: iio: adc: meson-saradc: program the channel muxes during initialization On some Meson8 devices the channel muxes are not programmed. This results in garbage values when trying to read channels that are not set up. Fix this by initializing the channel 0 and 1 muxes in MESON_SAR_ADC_CHAN_10_SW as well as the muxes for all other channels in MESON_SAR_ADC_AUX_SW based on what the vendor driver does (which is simply a 1:1 mapping of channel number and channel mux). This only showed up on Meson8 devices, because for GXBB and newer BL30 is taking care of initializing the channel muxes. This additionally fixes a typo in the MESON_SAR_ADC_AUX_SW_MUX_SEL_CHAN_MASK macro because the old definition assumed that the register fields were 2 bit wide, while they are actually 3 bit wide. Signed-off-by: Martin Blumenstingl Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/meson_saradc.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index 24025f179621..29fa7736d80c 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -96,8 +96,8 @@ #define MESON_SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK GENMASK(11, 0) #define MESON_SAR_ADC_AUX_SW 0x1c - #define MESON_SAR_ADC_AUX_SW_MUX_SEL_CHAN_MASK(_chan) \ - (GENMASK(10, 8) << (((_chan) - 2) * 2)) + #define MESON_SAR_ADC_AUX_SW_MUX_SEL_CHAN_SHIFT(_chan) \ + (8 + (((_chan) - 2) * 3)) #define MESON_SAR_ADC_AUX_SW_VREF_P_MUX BIT(6) #define MESON_SAR_ADC_AUX_SW_VREF_N_MUX BIT(5) #define MESON_SAR_ADC_AUX_SW_MODE_SEL BIT(4) @@ -622,7 +622,7 @@ static int meson_sar_adc_clk_init(struct iio_dev *indio_dev, static int meson_sar_adc_init(struct iio_dev *indio_dev) { struct meson_sar_adc_priv *priv = iio_priv(indio_dev); - int regval, ret; + int regval, i, ret; /* * make sure we start at CH7 input since the other muxes are only used @@ -677,6 +677,32 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) FIELD_PREP(MESON_SAR_ADC_DELAY_INPUT_DLY_SEL_MASK, 1)); + /* + * set up the input channel muxes in MESON_SAR_ADC_CHAN_10_SW + * (0 = SAR_ADC_CH0, 1 = SAR_ADC_CH1) + */ + regval = FIELD_PREP(MESON_SAR_ADC_CHAN_10_SW_CHAN0_MUX_SEL_MASK, 0); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW, + MESON_SAR_ADC_CHAN_10_SW_CHAN0_MUX_SEL_MASK, + regval); + regval = FIELD_PREP(MESON_SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK, 1); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW, + MESON_SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK, + regval); + + /* + * set up the input channel muxes in MESON_SAR_ADC_AUX_SW + * (2 = SAR_ADC_CH2, 3 = SAR_ADC_CH3, ...) and enable + * MESON_SAR_ADC_AUX_SW_YP_DRIVE_SW and + * MESON_SAR_ADC_AUX_SW_XP_DRIVE_SW like the vendor driver. + */ + regval = 0; + for (i = 2; i <= 7; i++) + regval |= i << MESON_SAR_ADC_AUX_SW_MUX_SEL_CHAN_SHIFT(i); + regval |= MESON_SAR_ADC_AUX_SW_YP_DRIVE_SW; + regval |= MESON_SAR_ADC_AUX_SW_XP_DRIVE_SW; + regmap_write(priv->regmap, MESON_SAR_ADC_AUX_SW, regval); + ret = clk_set_parent(priv->adc_sel_clk, priv->clkin); if (ret) { dev_err(indio_dev->dev.parent, -- cgit v1.2.3 From 17b3453f5c69758e851a37776798e64795897a7d Mon Sep 17 00:00:00 2001 From: Stefan Brüns Date: Fri, 8 Dec 2017 18:41:46 +0100 Subject: iio: adc: ina2xx: Remove bogus cast for data argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit iio_push_to_buffers_with_timestamp expects a void pointer, so the cast is both unnecessary and misleading. Signed-off-by: Stefan Brüns Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/ina2xx-adc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index ddf878163bf9..3195f8754c3b 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -767,8 +767,7 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev) time_b = iio_get_time_ns(indio_dev); - iio_push_to_buffers_with_timestamp(indio_dev, - (unsigned int *)data, time_a); + iio_push_to_buffers_with_timestamp(indio_dev, data, time_a); return (unsigned long)(time_b - time_a) / 1000; }; -- cgit v1.2.3 From d456d61f53ece55ae17599bf004bb071c0a618e4 Mon Sep 17 00:00:00 2001 From: Stefan Brüns Date: Fri, 8 Dec 2017 18:41:47 +0100 Subject: iio: adc: ina2xx: Clarify size requirement for data buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The timestamp is inserted into the buffer after the sample data by iio_push_to_buffers_with_timestamp, document the space requirement for the timestamp. Signed-off-by: Stefan Brüns Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/ina2xx-adc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 3195f8754c3b..8c8120406f52 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -700,7 +700,8 @@ static const struct iio_chan_spec ina219_channels[] = { static int ina2xx_work_buffer(struct iio_dev *indio_dev) { struct ina2xx_chip_info *chip = iio_priv(indio_dev); - unsigned short data[8]; + /* data buffer needs space for channel data and timestap */ + unsigned short data[4 + sizeof(s64)/sizeof(short)]; int bit, ret, i = 0; s64 time_a, time_b; unsigned int alert; -- cgit v1.2.3 From c68013f3a9a7c901a9a7935a973a0ab1cc884c4a Mon Sep 17 00:00:00 2001 From: Stefan Brüns Date: Fri, 8 Dec 2017 18:41:48 +0100 Subject: iio: adc: ina2xx: Remove unneeded dummy read to clear CNVR flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Although the datasheet states the CNVR flag is cleared by reading the BUS_VOLTAGE register, it is actually cleared by reading any of the voltage/current/power registers. The behaviour has been confirmed by TI support: http://e2e.ti.com/support/amplifiers/current-shunt-monitors/f/931/p/647053/2378282 Signed-off-by: Stefan Brüns Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/ina2xx-adc.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 8c8120406f52..b027d485398b 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -705,7 +705,6 @@ 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); @@ -730,7 +729,6 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev) ret = regmap_read(chip->regmap, INA2XX_BUS_VOLTAGE, &alert); alert &= INA219_CNVR; - cnvr_need_clear = alert; } if (ret < 0) @@ -752,18 +750,6 @@ 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); -- cgit v1.2.3 From 8bcf024f06f11c0c9597ecbbfbe291a9a5092204 Mon Sep 17 00:00:00 2001 From: Stefan Brüns Date: Fri, 8 Dec 2017 18:41:49 +0100 Subject: iio: adc: ina2xx: Do not udelay for several seconds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The conversion time can be up to 16 seconds (8 ms per channel, 2 channels, 1024 times averaging). Signed-off-by: Stefan Brüns Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/ina2xx-adc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index b027d485398b..2621a34ee5c6 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -764,7 +764,7 @@ static int ina2xx_capture_thread(void *data) struct iio_dev *indio_dev = data; struct ina2xx_chip_info *chip = iio_priv(indio_dev); int sampling_us = SAMPLING_PERIOD(chip); - int buffer_us; + int buffer_us, delay_us; /* * Poll a bit faster than the chip internal Fs, in case @@ -778,8 +778,10 @@ static int ina2xx_capture_thread(void *data) if (buffer_us < 0) return buffer_us; - if (sampling_us > buffer_us) - udelay(sampling_us - buffer_us); + if (sampling_us > buffer_us) { + delay_us = sampling_us - buffer_us; + usleep_range(delay_us, (delay_us * 3) >> 1); + } } while (!kthread_should_stop()); -- cgit v1.2.3 From d3bf60450d47c180d6588ae0d0bb9ea7147718df Mon Sep 17 00:00:00 2001 From: Andreas Klinger Date: Wed, 13 Dec 2017 18:10:11 +0100 Subject: iio: hx711: add triggered buffer support Add buffer to device data struct and add trigger function Data format is quite simple: voltage - channel 0 32 Bit voltage - channel 1 32 Bit timestamp 64 Bit Using both channels at the same time is working quite slow because of changing the channel which needs a dummy read. Signed-off-by: Andreas Klinger Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/Kconfig | 2 + drivers/iio/adc/hx711.c | 121 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 100 insertions(+), 23 deletions(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 486793691de0..47492c936747 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -319,6 +319,8 @@ config HI8435 config HX711 tristate "AVIA HX711 ADC for weight cells" depends on GPIOLIB + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help If you say yes here you get support for AVIA HX711 ADC which is used for weigh cells diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c index d10b9f13d557..a38162ee7dcb 100644 --- a/drivers/iio/adc/hx711.c +++ b/drivers/iio/adc/hx711.c @@ -24,6 +24,9 @@ #include #include #include +#include +#include +#include #include #include @@ -89,6 +92,11 @@ struct hx711_data { int gain_set; /* gain set on device */ int gain_chan_a; /* gain for channel A */ struct mutex lock; + /* + * triggered buffer + * 2x32-bit channel + 64-bit timestamp + */ + u32 buffer[4]; }; static int hx711_cycle(struct hx711_data *hx711_data) @@ -236,34 +244,40 @@ static int hx711_set_gain_for_channel(struct hx711_data *hx711_data, int chan) return 0; } +static int hx711_reset_read(struct hx711_data *hx711_data, int chan) +{ + int ret; + int val; + + /* + * hx711_reset() must be called from here + * because it could be calling hx711_read() by itself + */ + if (hx711_reset(hx711_data)) { + dev_err(hx711_data->dev, "reset failed!"); + return -EIO; + } + + ret = hx711_set_gain_for_channel(hx711_data, chan); + if (ret < 0) + return ret; + + val = hx711_read(hx711_data); + + return val; +} + static int hx711_read_raw(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, int *val, int *val2, long mask) { struct hx711_data *hx711_data = iio_priv(indio_dev); - int ret; switch (mask) { case IIO_CHAN_INFO_RAW: mutex_lock(&hx711_data->lock); - /* - * hx711_reset() must be called from here - * because it could be calling hx711_read() by itself - */ - if (hx711_reset(hx711_data)) { - mutex_unlock(&hx711_data->lock); - dev_err(hx711_data->dev, "reset failed!"); - return -EIO; - } - - ret = hx711_set_gain_for_channel(hx711_data, chan->channel); - if (ret < 0) { - mutex_unlock(&hx711_data->lock); - return ret; - } - - *val = hx711_read(hx711_data); + *val = hx711_reset_read(hx711_data, chan->channel); mutex_unlock(&hx711_data->lock); @@ -339,6 +353,36 @@ static int hx711_write_raw_get_fmt(struct iio_dev *indio_dev, return IIO_VAL_INT_PLUS_NANO; } +static irqreturn_t hx711_trigger(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct hx711_data *hx711_data = iio_priv(indio_dev); + int i, j = 0; + + mutex_lock(&hx711_data->lock); + + memset(hx711_data->buffer, 0, sizeof(hx711_data->buffer)); + + for (i = 0; i < indio_dev->masklength; i++) { + if (!test_bit(i, indio_dev->active_scan_mask)) + continue; + + hx711_data->buffer[j] = hx711_reset_read(hx711_data, + indio_dev->channels[i].channel); + j++; + } + + iio_push_to_buffers_with_timestamp(indio_dev, hx711_data->buffer, + pf->timestamp); + + mutex_unlock(&hx711_data->lock); + + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + static ssize_t hx711_scale_available_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -387,6 +431,13 @@ static const struct iio_chan_spec hx711_chan_spec[] = { .indexed = 1, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .scan_index = 0, + .scan_type = { + .sign = 'u', + .realbits = 24, + .storagebits = 32, + .endianness = IIO_CPU, + }, }, { .type = IIO_VOLTAGE, @@ -394,7 +445,15 @@ static const struct iio_chan_spec hx711_chan_spec[] = { .indexed = 1, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .scan_index = 1, + .scan_type = { + .sign = 'u', + .realbits = 24, + .storagebits = 32, + .endianness = IIO_CPU, + }, }, + IIO_CHAN_SOFT_TIMESTAMP(2), }; static int hx711_probe(struct platform_device *pdev) @@ -459,10 +518,9 @@ static int hx711_probe(struct platform_device *pdev) * 1 LSB = (AVDD * 100) / GAIN / 1678 [10^-9 mV] */ ret = regulator_get_voltage(hx711_data->reg_avdd); - if (ret < 0) { - regulator_disable(hx711_data->reg_avdd); - return ret; - } + if (ret < 0) + goto error_regulator; + /* we need 10^-9 mV */ ret *= 100; @@ -482,12 +540,27 @@ static int hx711_probe(struct platform_device *pdev) indio_dev->channels = hx711_chan_spec; indio_dev->num_channels = ARRAY_SIZE(hx711_chan_spec); + ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time, + hx711_trigger, NULL); + if (ret < 0) { + dev_err(dev, "setup of iio triggered buffer failed\n"); + goto error_regulator; + } + ret = iio_device_register(indio_dev); if (ret < 0) { dev_err(dev, "Couldn't register the device\n"); - regulator_disable(hx711_data->reg_avdd); + goto error_buffer; } + return 0; + +error_buffer: + iio_triggered_buffer_cleanup(indio_dev); + +error_regulator: + regulator_disable(hx711_data->reg_avdd); + return ret; } @@ -501,6 +574,8 @@ static int hx711_remove(struct platform_device *pdev) iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + regulator_disable(hx711_data->reg_avdd); return 0; -- cgit v1.2.3 From 1fe899e3ed504b3c982157ba44a3d66970dac6e4 Mon Sep 17 00:00:00 2001 From: Andreas Klinger Date: Wed, 13 Dec 2017 18:10:34 +0100 Subject: iio: hx711: fix bug in reset functionality Return value in hx711_reset() should indicate status of dout otherwise the calling function is reporting an error as false positive If there are two reads too close to each other, then the second one will never succeed. This happens especially when using buffered mode with both channels enabled. When changing the channel on every trigger event the former 100 ms are not enough for waiting until the device indicates normal mode. Wait up to 1 second until the device turns into normal mode. Signed-off-by: Andreas Klinger Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/hx711.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c index a38162ee7dcb..9430b54121e0 100644 --- a/drivers/iio/adc/hx711.c +++ b/drivers/iio/adc/hx711.c @@ -153,15 +153,16 @@ static int hx711_wait_for_ready(struct hx711_data *hx711_data) int i, val; /* - * a maximum reset cycle time of 56 ms was measured. - * we round it up to 100 ms + * in some rare cases the reset takes quite a long time + * especially when the channel is changed. + * Allow up to one second for it */ for (i = 0; i < 100; i++) { val = gpiod_get_value(hx711_data->gpiod_dout); if (!val) break; - /* sleep at least 1 ms */ - msleep(1); + /* sleep at least 10 ms */ + msleep(10); } if (val) return -EIO; @@ -203,9 +204,7 @@ static int hx711_reset(struct hx711_data *hx711_data) * after a dummy read we need to wait vor readiness * for not mixing gain pulses with the clock */ - ret = hx711_wait_for_ready(hx711_data); - if (ret) - return ret; + val = hx711_wait_for_ready(hx711_data); } return val; -- cgit v1.2.3 From c34812e490b583fab63287249b3cf47326556e2d Mon Sep 17 00:00:00 2001 From: Venkat Prashanth B U Date: Sun, 17 Dec 2017 14:37:48 +0530 Subject: Drivers: iio:adc: fix brace coding style issue in at91_adc.c This is a patch to the at91_adc.c file that fixes up a brace warning found by the checkpatch.pl tool Signed-off-by: Venkat Prashanth B U Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/at91_adc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 3836d4222a3e..71a5ee652b79 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -1177,9 +1177,9 @@ static int at91_adc_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); st->reg_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(st->reg_base)) { + if (IS_ERR(st->reg_base)) return PTR_ERR(st->reg_base); - } + /* * Disable all IRQs before setting up the handler -- cgit v1.2.3 From a28caa7b8fe19ac2c31b7630772107e0d50ce18e Mon Sep 17 00:00:00 2001 From: Maciej Purski Date: Mon, 18 Dec 2017 09:43:58 +0100 Subject: iio: adc: ina2xx: Make calibration register value fixed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calibration register is used for calculating current register in hardware according to datasheet: current = shunt_volt * calib_register / 2048 (ina 226) current = shunt_volt * calib_register / 4096 (ina 219) Fix calib_register value to 2048 for ina226 and 4096 for ina 219 in order to avoid truncation error and provide best precision allowed by shunt_voltage measurement. Make current scale value follow changes of shunt_resistor from sysfs as calib_register value is now fixed. Power_lsb value should also follow shunt_resistor changes as stated in datasheet: power_lsb = 25 * current_lsb (ina 226) power_lsb = 20 * current_lsb (ina 219) This is a part of the patchset: https://lkml.org/lkml/2017/11/22/394 Signed-off-by: Maciej Purski Reviewed-by: Stefan Brüns Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/ina2xx-adc.c | 64 +++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 31 deletions(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 2621a34ee5c6..94d506f0f404 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -124,11 +124,12 @@ enum ina2xx_ids { ina219, ina226 }; struct ina2xx_config { u16 config_default; - int calibration_factor; + int calibration_value; int shunt_voltage_lsb; /* nV */ int bus_voltage_shift; /* position of lsb */ int bus_voltage_lsb; /* uV */ - int power_lsb; /* uW */ + /* fixed relation between current and power lsb, uW/uA */ + int power_lsb_factor; enum ina2xx_ids chip_id; }; @@ -149,20 +150,20 @@ struct ina2xx_chip_info { static const struct ina2xx_config ina2xx_config[] = { [ina219] = { .config_default = INA219_CONFIG_DEFAULT, - .calibration_factor = 40960000, + .calibration_value = 4096, .shunt_voltage_lsb = 10000, .bus_voltage_shift = INA219_BUS_VOLTAGE_SHIFT, .bus_voltage_lsb = 4000, - .power_lsb = 20000, + .power_lsb_factor = 20, .chip_id = ina219, }, [ina226] = { .config_default = INA226_CONFIG_DEFAULT, - .calibration_factor = 5120000, + .calibration_value = 2048, .shunt_voltage_lsb = 2500, .bus_voltage_shift = 0, .bus_voltage_lsb = 1250, - .power_lsb = 25000, + .power_lsb_factor = 25, .chip_id = ina226, }, }; @@ -227,16 +228,26 @@ static int ina2xx_read_raw(struct iio_dev *indio_dev, *val2 = 1000; return IIO_VAL_FRACTIONAL; - case INA2XX_POWER: - /* processed (mW) = raw*lsb (uW) / 1000 */ - *val = chip->config->power_lsb; - *val2 = 1000; + case INA2XX_CURRENT: + /* + * processed (mA) = raw * current_lsb (mA) + * current_lsb (mA) = shunt_voltage_lsb (nV) / + * shunt_resistor (uOhm) + */ + *val = chip->config->shunt_voltage_lsb; + *val2 = chip->shunt_resistor_uohm; return IIO_VAL_FRACTIONAL; - case INA2XX_CURRENT: - /* processed (mA) = raw (mA) */ - *val = 1; - return IIO_VAL_INT; + case INA2XX_POWER: + /* + * processed (mW) = raw * power_lsb (mW) + * power_lsb (mW) = power_lsb_factor (mW/mA) * + * current_lsb (mA) + */ + *val = chip->config->power_lsb_factor * + chip->config->shunt_voltage_lsb; + *val2 = chip->shunt_resistor_uohm; + return IIO_VAL_FRACTIONAL; } case IIO_CHAN_INFO_HARDWAREGAIN: @@ -541,25 +552,21 @@ static ssize_t ina2xx_allow_async_readout_store(struct device *dev, } /* - * Set current LSB to 1mA, shunt is in uOhms - * (equation 13 in datasheet). We hardcode a Current_LSB - * of 1.0 x10-3. The only remaining parameter is RShunt. - * There is no need to expose the CALIBRATION register - * to the user for now. But we need to reset this register - * if the user updates RShunt after driver init, e.g upon - * reading an EEPROM/Probe-type value. + * Calibration register is set to the best value, which eliminates + * truncation errors on calculating current register in hardware. + * According to datasheet (INA 226: eq. 3, INA219: eq. 4) the best values + * are 2048 for ina226 and 4096 for ina219. They are hardcoded as + * calibration_value. */ static int ina2xx_set_calibration(struct ina2xx_chip_info *chip) { - u16 regval = DIV_ROUND_CLOSEST(chip->config->calibration_factor, - chip->shunt_resistor_uohm); - - return regmap_write(chip->regmap, INA2XX_CALIBRATION, regval); + return regmap_write(chip->regmap, INA2XX_CALIBRATION, + chip->config->calibration_value); } static int set_shunt_resistor(struct ina2xx_chip_info *chip, unsigned int val) { - if (val <= 0 || val > chip->config->calibration_factor) + if (val == 0 || val > INT_MAX) return -EINVAL; chip->shunt_resistor_uohm = val; @@ -592,11 +599,6 @@ static ssize_t ina2xx_shunt_resistor_store(struct device *dev, if (ret) return ret; - /* Update the Calibration register */ - ret = ina2xx_set_calibration(chip); - if (ret) - return ret; - return len; } -- cgit v1.2.3 From 8ea2a63869517271f7356241015a3edf3efb77a5 Mon Sep 17 00:00:00 2001 From: Stefan Brüns Date: Mon, 1 Jan 2018 02:24:42 +0100 Subject: iio: adc: ina2xx: Use a monotonic clock for delay calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The iio timestamp clock is user selectable and may be non-monotonic. Also, only part of the acquisition time is measured, thus the delay was longer than intended. Use a monotonic timestamp to track the time for the next poll iteration. The timestamp is advanced by the sampling interval each iteration. In case the conversion overrruns the register readout (i.e. fast sampling combined with a slow bus), one or multiple samples will be dropped. Signed-off-by: Stefan Brüns Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/ina2xx-adc.c | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 94d506f0f404..144d5c950f2b 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -705,10 +705,10 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev) /* data buffer needs space for channel data and timestap */ unsigned short data[4 + sizeof(s64)/sizeof(short)]; int bit, ret, i = 0; - s64 time_a, time_b; + s64 time; unsigned int alert; - time_a = iio_get_time_ns(indio_dev); + time = iio_get_time_ns(indio_dev); /* * Because the timer thread and the chip conversion clock @@ -754,11 +754,9 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev) data[i++] = val; } - time_b = iio_get_time_ns(indio_dev); + iio_push_to_buffers_with_timestamp(indio_dev, data, time); - iio_push_to_buffers_with_timestamp(indio_dev, data, time_a); - - return (unsigned long)(time_b - time_a) / 1000; + return 0; }; static int ina2xx_capture_thread(void *data) @@ -766,7 +764,9 @@ static int ina2xx_capture_thread(void *data) struct iio_dev *indio_dev = data; struct ina2xx_chip_info *chip = iio_priv(indio_dev); int sampling_us = SAMPLING_PERIOD(chip); - int buffer_us, delay_us; + int ret; + struct timespec64 next, now, delta; + s64 delay_us; /* * Poll a bit faster than the chip internal Fs, in case @@ -775,15 +775,28 @@ static int ina2xx_capture_thread(void *data) if (!chip->allow_async_readout) sampling_us -= 200; + ktime_get_ts64(&next); + do { - buffer_us = ina2xx_work_buffer(indio_dev); - if (buffer_us < 0) - return buffer_us; + ret = ina2xx_work_buffer(indio_dev); + if (ret < 0) + return ret; - if (sampling_us > buffer_us) { - delay_us = sampling_us - buffer_us; - usleep_range(delay_us, (delay_us * 3) >> 1); - } + ktime_get_ts64(&now); + + /* + * Advance the timestamp for the next poll by one sampling + * interval, and sleep for the remainder (next - now) + * In case "next" has already passed, the interval is added + * multiple times, i.e. samples are dropped. + */ + do { + timespec64_add_ns(&next, 1000 * sampling_us); + delta = timespec64_sub(next, now); + delay_us = div_s64(timespec64_to_ns(&delta), 1000); + } while (delay_us <= 0); + + usleep_range(delay_us, (delay_us * 3) >> 1); } while (!kthread_should_stop()); -- cgit v1.2.3 From 8c3a7b0a6c3538ab459d89691dbd379235efd170 Mon Sep 17 00:00:00 2001 From: Stefan Brüns Date: Thu, 21 Dec 2017 19:31:37 +0100 Subject: iio: adc: ina2xx: Align timestamp with conversion ready flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As the timestamp is no longer (ab-)used to measure the function run time, it can be taken at the correct time, i.e. when the conversion has finished. Signed-off-by: Stefan Brüns Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/ina2xx-adc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 144d5c950f2b..0845acaeaa8a 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -708,8 +708,6 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev) s64 time; unsigned int alert; - time = iio_get_time_ns(indio_dev); - /* * Because the timer thread and the chip conversion clock * are asynchronous, the period difference will eventually @@ -738,6 +736,8 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev) } while (!alert); + time = iio_get_time_ns(indio_dev); + /* * Single register reads: bulk_read will not work with ina226/219 * as there is no auto-increment of the register pointer. -- cgit v1.2.3 From 9273aa16b3847d31206d24b435f2bdd01c226cd4 Mon Sep 17 00:00:00 2001 From: Stefan Brüns Date: Thu, 21 Dec 2017 19:31:38 +0100 Subject: iio: adc: ina2xx: Actually align the loop with the conversion ready flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, the registers are read out once per conversion interval. If the reading is delayed as the conversion has not yet finished, this extra time is treated as being part of the readout, although it should delay the start of the poll interval. This results in the interval starting slightly earlier in each iteration, until all time between reads is spent polling the status registers instead of sleeping. To fix this, the delay has to account for the state of the conversion ready flag. Whenever the conversion is already finished, schedule the next read on the regular interval, otherwise schedule it one interval after the flag bit has been set. Split the work function in two functions, one for the status poll and one for reading the values, to be able to note down the time when the flag bit is raised. Signed-off-by: Stefan Brüns Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/ina2xx-adc.c | 57 +++++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 19 deletions(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 0845acaeaa8a..0635a79864bf 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -699,13 +699,10 @@ static const struct iio_chan_spec ina219_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(4), }; -static int ina2xx_work_buffer(struct iio_dev *indio_dev) +static int ina2xx_conversion_ready(struct iio_dev *indio_dev) { struct ina2xx_chip_info *chip = iio_priv(indio_dev); - /* data buffer needs space for channel data and timestap */ - unsigned short data[4 + sizeof(s64)/sizeof(short)]; - int bit, ret, i = 0; - s64 time; + int ret; unsigned int alert; /* @@ -719,22 +716,29 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev) * 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 { - 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; - } + 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; + } - if (ret < 0) - return ret; + if (ret < 0) + return ret; + + return !!alert; +} - } while (!alert); +static int ina2xx_work_buffer(struct iio_dev *indio_dev) +{ + struct ina2xx_chip_info *chip = iio_priv(indio_dev); + /* data buffer needs space for channel data and timestap */ + unsigned short data[4 + sizeof(s64)/sizeof(short)]; + int bit, ret, i = 0; + s64 time; time = iio_get_time_ns(indio_dev); @@ -778,6 +782,21 @@ static int ina2xx_capture_thread(void *data) ktime_get_ts64(&next); do { + while (!chip->allow_async_readout) { + ret = ina2xx_conversion_ready(indio_dev); + if (ret < 0) + return ret; + + /* + * If the conversion was not yet finished, + * reset the reference timestamp. + */ + if (ret == 0) + ktime_get_ts64(&next); + else + break; + } + ret = ina2xx_work_buffer(indio_dev); if (ret < 0) return ret; -- cgit v1.2.3 From a540243f4dabddeaec937a859683c539e1571d9d Mon Sep 17 00:00:00 2001 From: Venkat Prashanth B U Date: Fri, 5 Jan 2018 09:13:57 +0530 Subject: Drivers:iio:adc:ti_am335x_adc remove comparison to bool This is the patch to the file ti_am335x_adc.c which fixes the following coccinelle warning: WARNING: Comparison to bool Signed-off-by: Venkat Prashanth B U Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/ti_am335x_adc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index b3e573cc6f5f..80df5a377d30 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -523,7 +523,7 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, } am335x_tsc_se_adc_done(adc_dev->mfd_tscadc); - if (found == false) + if (!found) ret = -EBUSY; err_unlock: -- cgit v1.2.3 From 04e491ca9df60ffe8637d00d68e5ab8bc73b30d5 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Fri, 5 Jan 2018 15:34:54 +0100 Subject: iio: adc: stm32: fix scan of multiple channels with DMA By default, watermark is set to '1'. Watermark is used to fine tune cyclic dma buffer period. In case watermark is left untouched (e.g. 1) and several channels are being scanned, buffer period is wrongly set (e.g. to 1 sample). As a consequence, data is never pushed to upper layer. Fix buffer period size, by taking scan channels number into account. Fixes: 2763ea0585c9 ("iio: adc: stm32: add optional dma support") Signed-off-by: Fabrice Gasnier Cc: Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/stm32-adc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/iio/adc') diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 6dbf9549cdc9..7f5def465340 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -1289,6 +1289,7 @@ static int stm32_adc_set_watermark(struct iio_dev *indio_dev, unsigned int val) { struct stm32_adc *adc = iio_priv(indio_dev); unsigned int watermark = STM32_DMA_BUFFER_SIZE / 2; + unsigned int rx_buf_sz = STM32_DMA_BUFFER_SIZE; /* * dma cyclic transfers are used, buffer is split into two periods. @@ -1297,7 +1298,7 @@ static int stm32_adc_set_watermark(struct iio_dev *indio_dev, unsigned int val) * - one buffer (period) driver can push with iio_trigger_poll(). */ watermark = min(watermark, val * (unsigned)(sizeof(u16))); - adc->rx_buf_sz = watermark * 2; + adc->rx_buf_sz = min(rx_buf_sz, watermark * 2 * adc->num_conv); return 0; } -- cgit v1.2.3