diff options
Diffstat (limited to 'drivers/iio/adc/ti_am335x_adc.c')
| -rw-r--r-- | drivers/iio/adc/ti_am335x_adc.c | 258 |
1 files changed, 146 insertions, 112 deletions
diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index 855cc2d64ac8..a1a28584de93 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI ADC MFD driver * * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/kernel.h> @@ -22,9 +14,9 @@ #include <linux/io.h> #include <linux/iio/iio.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/iio/machine.h> #include <linux/iio/driver.h> +#include <linux/iopoll.h> #include <linux/mfd/ti_am335x_tscadc.h> #include <linux/iio/buffer.h> @@ -65,7 +57,7 @@ static unsigned int tiadc_readl(struct tiadc_device *adc, unsigned int reg) } static void tiadc_writel(struct tiadc_device *adc, unsigned int reg, - unsigned int val) + unsigned int val) { writel(val, adc->mfd_tscadc->tscadc_base + reg); } @@ -80,7 +72,7 @@ static u32 get_adc_step_mask(struct tiadc_device *adc_dev) } static u32 get_adc_chan_step_mask(struct tiadc_device *adc_dev, - struct iio_chan_spec const *chan) + struct iio_chan_spec const *chan) { int i; @@ -102,10 +94,18 @@ static u32 get_adc_step_bit(struct tiadc_device *adc_dev, int chan) return 1 << adc_dev->channel_step[chan]; } +static int tiadc_wait_idle(struct tiadc_device *adc_dev) +{ + u32 val; + + return readl_poll_timeout(adc_dev->mfd_tscadc->tscadc_base + REG_ADCFSM, + val, !(val & SEQ_STATUS), 10, + IDLE_TIMEOUT_MS * 1000 * adc_dev->channels); +} + static void tiadc_step_config(struct iio_dev *indio_dev) { struct tiadc_device *adc_dev = iio_priv(indio_dev); - struct device *dev = adc_dev->mfd_tscadc->dev; unsigned int stepconfig; int i, steps = 0; @@ -118,23 +118,14 @@ static void tiadc_step_config(struct iio_dev *indio_dev) * Channel would represent which analog input * needs to be given to ADC to digitalize data. */ - - for (i = 0; i < adc_dev->channels; i++) { int chan; chan = adc_dev->channel_line[i]; - if (adc_dev->step_avg[i] > STEPCONFIG_AVG_16) { - dev_warn(dev, "chan %d step_avg truncating to %d\n", - chan, STEPCONFIG_AVG_16); - adc_dev->step_avg[i] = STEPCONFIG_AVG_16; - } - - if (adc_dev->step_avg[i]) - stepconfig = - STEPCONFIG_AVG(ffs(adc_dev->step_avg[i]) - 1) | - STEPCONFIG_FIFO1; + if (adc_dev->step_avg[i] && adc_dev->step_avg[i] <= STEPCONFIG_AVG_16) + stepconfig = STEPCONFIG_AVG(ffs(adc_dev->step_avg[i]) - 1) | + STEPCONFIG_FIFO1; else stepconfig = STEPCONFIG_FIFO1; @@ -142,26 +133,13 @@ static void tiadc_step_config(struct iio_dev *indio_dev) stepconfig |= STEPCONFIG_MODE_SWCNT; tiadc_writel(adc_dev, REG_STEPCONFIG(steps), - stepconfig | STEPCONFIG_INP(chan) | - STEPCONFIG_INM_ADCREFM | - STEPCONFIG_RFP_VREFP | - STEPCONFIG_RFM_VREFN); - - if (adc_dev->open_delay[i] > STEPDELAY_OPEN_MASK) { - dev_warn(dev, "chan %d open delay truncating to 0x3FFFF\n", - chan); - adc_dev->open_delay[i] = STEPDELAY_OPEN_MASK; - } - - if (adc_dev->sample_delay[i] > 0xFF) { - dev_warn(dev, "chan %d sample delay truncating to 0xFF\n", - chan); - adc_dev->sample_delay[i] = 0xFF; - } + stepconfig | STEPCONFIG_INP(chan) | + STEPCONFIG_INM_ADCREFM | STEPCONFIG_RFP_VREFP | + STEPCONFIG_RFM_VREFN); tiadc_writel(adc_dev, REG_STEPDELAY(steps), - STEPDELAY_OPEN(adc_dev->open_delay[i]) | - STEPDELAY_SAMPLE(adc_dev->sample_delay[i])); + STEPDELAY_OPEN(adc_dev->open_delay[i]) | + STEPDELAY_SAMPLE(adc_dev->sample_delay[i])); adc_dev->channel_step[i] = steps; steps++; @@ -184,12 +162,14 @@ static irqreturn_t tiadc_irq_h(int irq, void *private) if (status & IRQENB_FIFO1OVRRUN) { /* FIFO Overrun. Clear flag. Disable/Enable ADC to recover */ config = tiadc_readl(adc_dev, REG_CTRL); - config &= ~(CNTRLREG_TSCSSENB); + config &= ~(CNTRLREG_SSENB); tiadc_writel(adc_dev, REG_CTRL, config); - tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1OVRRUN - | IRQENB_FIFO1UNDRFLW | IRQENB_FIFO1THRES); + tiadc_writel(adc_dev, REG_IRQSTATUS, + IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW | + IRQENB_FIFO1THRES); - /* wait for idle state. + /* + * Wait for the idle state. * ADC needs to finish the current conversion * before disabling the module */ @@ -197,7 +177,7 @@ static irqreturn_t tiadc_irq_h(int irq, void *private) adc_fsm = tiadc_readl(adc_dev, REG_ADCFSM); } while (adc_fsm != 0x10 && count++ < 100); - tiadc_writel(adc_dev, REG_CTRL, (config | CNTRLREG_TSCSSENB)); + tiadc_writel(adc_dev, REG_CTRL, (config | CNTRLREG_SSENB)); return IRQ_HANDLED; } else if (status & IRQENB_FIFO1THRES) { /* Disable irq and wake worker thread */ @@ -217,11 +197,11 @@ static irqreturn_t tiadc_worker_h(int irq, void *private) fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); for (k = 0; k < fifo1count; k = k + i) { - for (i = 0; i < (indio_dev->scan_bytes)/2; i++) { + for (i = 0; i < indio_dev->scan_bytes / 2; i++) { read = tiadc_readl(adc_dev, REG_FIFO1); data[i] = read & FIFOREAD_DATA_MASK; } - iio_push_to_buffers(indio_dev, (u8 *) data); + iio_push_to_buffers(indio_dev, (u8 *)data); } tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1THRES); @@ -254,6 +234,7 @@ static int tiadc_start_dma(struct iio_dev *indio_dev) struct dma_async_tx_descriptor *desc; dma->current_period = 0; /* We start to fill period 0 */ + /* * Make the fifo thresh as the multiple of total number of * channels enabled, so make sure that cyclic DMA period @@ -263,9 +244,10 @@ static int tiadc_start_dma(struct iio_dev *indio_dev) */ dma->fifo_thresh = rounddown(FIFO1_THRESHOLD + 1, adc_dev->total_ch_enabled) - 1; + /* Make sure that period length is multiple of fifo thresh level */ dma->period_size = rounddown(DMA_BUFFER_SIZE / 2, - (dma->fifo_thresh + 1) * sizeof(u16)); + (dma->fifo_thresh + 1) * sizeof(u16)); dma->conf.src_maxburst = dma->fifo_thresh + 1; dmaengine_slave_config(dma->chan, &dma->conf); @@ -295,10 +277,15 @@ static int tiadc_buffer_preenable(struct iio_dev *indio_dev) { struct tiadc_device *adc_dev = iio_priv(indio_dev); int i, fifo1count; + int ret; - tiadc_writel(adc_dev, REG_IRQCLR, (IRQENB_FIFO1THRES | - IRQENB_FIFO1OVRRUN | - IRQENB_FIFO1UNDRFLW)); + ret = tiadc_wait_idle(adc_dev); + if (ret) + return ret; + + tiadc_writel(adc_dev, REG_IRQCLR, + IRQENB_FIFO1THRES | IRQENB_FIFO1OVRRUN | + IRQENB_FIFO1UNDRFLW); /* Flush FIFO. Needed in corner cases in simultaneous tsc/adc use */ fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); @@ -328,8 +315,9 @@ static int tiadc_buffer_postenable(struct iio_dev *indio_dev) am335x_tsc_se_set_cache(adc_dev->mfd_tscadc, enb); - tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1THRES - | IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW); + tiadc_writel(adc_dev, REG_IRQSTATUS, + IRQENB_FIFO1THRES | IRQENB_FIFO1OVRRUN | + IRQENB_FIFO1UNDRFLW); irq_enable = IRQENB_FIFO1OVRRUN; if (!dma->chan) @@ -345,8 +333,9 @@ static int tiadc_buffer_predisable(struct iio_dev *indio_dev) struct tiadc_dma *dma = &adc_dev->dma; int fifo1count, i; - tiadc_writel(adc_dev, REG_IRQCLR, (IRQENB_FIFO1THRES | - IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW)); + tiadc_writel(adc_dev, REG_IRQCLR, + IRQENB_FIFO1THRES | IRQENB_FIFO1OVRRUN | + IRQENB_FIFO1UNDRFLW); am335x_tsc_se_clr(adc_dev->mfd_tscadc, adc_dev->buffer_en_ch_steps); adc_dev->buffer_en_ch_steps = 0; adc_dev->total_ch_enabled = 0; @@ -378,23 +367,20 @@ static const struct iio_buffer_setup_ops tiadc_buffer_setup_ops = { }; static int tiadc_iio_buffered_hardware_setup(struct device *dev, - struct iio_dev *indio_dev, - irqreturn_t (*pollfunc_bh)(int irq, void *p), - irqreturn_t (*pollfunc_th)(int irq, void *p), - int irq, - unsigned long flags, - const struct iio_buffer_setup_ops *setup_ops) + struct iio_dev *indio_dev, + irqreturn_t (*pollfunc_bh)(int irq, void *p), + irqreturn_t (*pollfunc_th)(int irq, void *p), + int irq, unsigned long flags, + const struct iio_buffer_setup_ops *setup_ops) { int ret; - ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, - INDIO_BUFFER_SOFTWARE, - setup_ops); + ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, setup_ops); if (ret) return ret; return devm_request_threaded_irq(dev, irq, pollfunc_th, pollfunc_bh, - flags, indio_dev->name, indio_dev); + flags, indio_dev->name, indio_dev); } static const char * const chan_name_ain[] = { @@ -419,16 +405,16 @@ static int tiadc_channel_init(struct device *dev, struct iio_dev *indio_dev, indio_dev->num_channels = channels; chan_array = devm_kcalloc(dev, channels, sizeof(*chan_array), GFP_KERNEL); - if (chan_array == NULL) + if (!chan_array) return -ENOMEM; chan = chan_array; for (i = 0; i < channels; i++, chan++) { - chan->type = IIO_VOLTAGE; chan->indexed = 1; chan->channel = adc_dev->channel_line[i]; chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); + chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); chan->datasheet_name = chan_name_ain[chan->channel]; chan->scan_index = i; chan->scan_type.sign = 'u'; @@ -442,16 +428,33 @@ static int tiadc_channel_init(struct device *dev, struct iio_dev *indio_dev, } static int tiadc_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, long mask) + struct iio_chan_spec const *chan, int *val, int *val2, + long mask) { struct tiadc_device *adc_dev = iio_priv(indio_dev); - int ret = IIO_VAL_INT; int i, map_val; unsigned int fifo1count, read, stepid; bool found = false; u32 step_en; unsigned long timeout; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + break; + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_VOLTAGE: + *val = 1800; + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } if (iio_buffer_enabled(indio_dev)) return -EBUSY; @@ -461,15 +464,19 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, return -EINVAL; mutex_lock(&adc_dev->fifo1_lock); + + ret = tiadc_wait_idle(adc_dev); + if (ret) + goto err_unlock; + fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); while (fifo1count--) tiadc_readl(adc_dev, REG_FIFO1); am335x_tsc_se_set_once(adc_dev->mfd_tscadc, step_en); - timeout = jiffies + msecs_to_jiffies - (IDLE_TIMEOUT * adc_dev->channels); /* Wait for Fifo threshold interrupt */ + timeout = jiffies + msecs_to_jiffies(IDLE_TIMEOUT_MS * adc_dev->channels); while (1) { fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); if (fifo1count) @@ -481,12 +488,13 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, goto err_unlock; } } + map_val = adc_dev->channel_step[chan->scan_index]; /* * We check the complete FIFO. We programmed just one entry but in case * something went wrong we left empty handed (-EAGAIN previously) and - * then the value apeared somehow in the FIFO we would have two entries. + * then the value appeared somehow in the FIFO we would have two entries. * Therefore we read every item and keep only the latest version of the * requested channel. */ @@ -498,17 +506,18 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, if (stepid == map_val) { read = read & FIFOREAD_DATA_MASK; found = true; - *val = (u16) read; + *val = (u16)read; } } + am335x_tsc_se_adc_done(adc_dev->mfd_tscadc); if (!found) - ret = -EBUSY; + ret = -EBUSY; err_unlock: mutex_unlock(&adc_dev->fifo1_lock); - return ret; + return ret ? ret : IIO_VAL_INT; } static const struct iio_info tiadc_info = { @@ -545,6 +554,7 @@ static int tiadc_request_dma(struct platform_device *pdev, goto err; return 0; + err: dma_release_channel(dma->chan); return -ENOMEM; @@ -554,12 +564,11 @@ static int tiadc_parse_dt(struct platform_device *pdev, struct tiadc_device *adc_dev) { struct device_node *node = pdev->dev.of_node; - struct property *prop; - const __be32 *cur; int channels = 0; u32 val; + int i; - of_property_for_each_u32(node, "ti,adc-channels", prop, cur, val) { + of_property_for_each_u32(node, "ti,adc-channels", val) { adc_dev->channel_line[channels] = val; /* Set Default values for optional DT parameters */ @@ -570,6 +579,8 @@ static int tiadc_parse_dt(struct platform_device *pdev, channels++; } + adc_dev->channels = channels; + of_property_read_u32_array(node, "ti,chan-step-avg", adc_dev->step_avg, channels); of_property_read_u32_array(node, "ti,chan-step-opendelay", @@ -577,7 +588,33 @@ static int tiadc_parse_dt(struct platform_device *pdev, of_property_read_u32_array(node, "ti,chan-step-sampledelay", adc_dev->sample_delay, channels); - adc_dev->channels = channels; + for (i = 0; i < adc_dev->channels; i++) { + int chan; + + chan = adc_dev->channel_line[i]; + + if (adc_dev->step_avg[i] > STEPCONFIG_AVG_16) { + dev_warn(&pdev->dev, + "chan %d: wrong step avg, truncated to %ld\n", + chan, STEPCONFIG_AVG_16); + adc_dev->step_avg[i] = STEPCONFIG_AVG_16; + } + + if (adc_dev->open_delay[i] > STEPCONFIG_MAX_OPENDLY) { + dev_warn(&pdev->dev, + "chan %d: wrong open delay, truncated to 0x%lX\n", + chan, STEPCONFIG_MAX_OPENDLY); + adc_dev->open_delay[i] = STEPCONFIG_MAX_OPENDLY; + } + + if (adc_dev->sample_delay[i] > STEPCONFIG_MAX_SAMPLE) { + dev_warn(&pdev->dev, + "chan %d: wrong sample delay, truncated to 0x%lX\n", + chan, STEPCONFIG_MAX_SAMPLE); + adc_dev->sample_delay[i] = STEPCONFIG_MAX_SAMPLE; + } + } + return 0; } @@ -594,10 +631,9 @@ static int tiadc_probe(struct platform_device *pdev) } indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev)); - if (indio_dev == NULL) { - dev_err(&pdev->dev, "failed to allocate iio device\n"); + if (!indio_dev) return -ENOMEM; - } + adc_dev = iio_priv(indio_dev); adc_dev->mfd_tscadc = ti_tscadc_dev_get(pdev); @@ -616,35 +652,35 @@ static int tiadc_probe(struct platform_device *pdev) return err; err = tiadc_iio_buffered_hardware_setup(&pdev->dev, indio_dev, - &tiadc_worker_h, - &tiadc_irq_h, - adc_dev->mfd_tscadc->irq, - IRQF_SHARED, - &tiadc_buffer_setup_ops); - + &tiadc_worker_h, + &tiadc_irq_h, + adc_dev->mfd_tscadc->irq, + IRQF_SHARED, + &tiadc_buffer_setup_ops); if (err) - goto err_free_channels; + return err; err = iio_device_register(indio_dev); if (err) - goto err_buffer_unregister; + return err; platform_set_drvdata(pdev, indio_dev); err = tiadc_request_dma(pdev, adc_dev); - if (err && err == -EPROBE_DEFER) + if (err && err != -ENODEV) { + dev_err_probe(&pdev->dev, err, "DMA request failed\n"); goto err_dma; + } return 0; err_dma: iio_device_unregister(indio_dev); -err_buffer_unregister: -err_free_channels: + return err; } -static int tiadc_remove(struct platform_device *pdev) +static void tiadc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct tiadc_device *adc_dev = iio_priv(indio_dev); @@ -660,25 +696,22 @@ static int tiadc_remove(struct platform_device *pdev) step_en = get_adc_step_mask(adc_dev); am335x_tsc_se_clr(adc_dev->mfd_tscadc, step_en); - - return 0; } -static int __maybe_unused tiadc_suspend(struct device *dev) +static int tiadc_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct tiadc_device *adc_dev = iio_priv(indio_dev); unsigned int idle; idle = tiadc_readl(adc_dev, REG_CTRL); - idle &= ~(CNTRLREG_TSCSSENB); - tiadc_writel(adc_dev, REG_CTRL, (idle | - CNTRLREG_POWERDOWN)); + idle &= ~(CNTRLREG_SSENB); + tiadc_writel(adc_dev, REG_CTRL, idle | CNTRLREG_POWERDOWN); return 0; } -static int __maybe_unused tiadc_resume(struct device *dev) +static int tiadc_resume(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct tiadc_device *adc_dev = iio_priv(indio_dev); @@ -686,31 +719,32 @@ static int __maybe_unused tiadc_resume(struct device *dev) /* Make sure ADC is powered up */ restore = tiadc_readl(adc_dev, REG_CTRL); - restore &= ~(CNTRLREG_POWERDOWN); + restore &= ~CNTRLREG_POWERDOWN; tiadc_writel(adc_dev, REG_CTRL, restore); tiadc_step_config(indio_dev); am335x_tsc_se_set_cache(adc_dev->mfd_tscadc, - adc_dev->buffer_en_ch_steps); + adc_dev->buffer_en_ch_steps); return 0; } -static SIMPLE_DEV_PM_OPS(tiadc_pm_ops, tiadc_suspend, tiadc_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(tiadc_pm_ops, tiadc_suspend, tiadc_resume); static const struct of_device_id ti_adc_dt_ids[] = { { .compatible = "ti,am3359-adc", }, + { .compatible = "ti,am4372-adc", }, { } }; MODULE_DEVICE_TABLE(of, ti_adc_dt_ids); static struct platform_driver tiadc_driver = { .driver = { - .name = "TI-am335x-adc", - .pm = &tiadc_pm_ops, + .name = "TI-am335x-adc", + .pm = pm_sleep_ptr(&tiadc_pm_ops), .of_match_table = ti_adc_dt_ids, }, - .probe = tiadc_probe, - .remove = tiadc_remove, + .probe = tiadc_probe, + .remove = tiadc_remove, }; module_platform_driver(tiadc_driver); |
