| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0+ |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * lpc32xx_adc.c - Support for ADC in LPC32XX |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * 3-channel, 10-bit ADC |
|---|
| 5 | 6 | * |
|---|
| 6 | 7 | * Copyright (C) 2011, 2012 Roland Stigge <stigge@antcom.de> |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 9 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 10 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 11 | | - * (at your option) any later version. |
|---|
| 12 | | - * |
|---|
| 13 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 14 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 15 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 16 | | - * GNU General Public License for more details. |
|---|
| 17 | | - * |
|---|
| 18 | | - * You should have received a copy of the GNU General Public License |
|---|
| 19 | | - * along with this program; if not, write to the Free Software |
|---|
| 20 | | - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|---|
| 21 | 8 | */ |
|---|
| 22 | 9 | |
|---|
| 23 | | -#include <linux/module.h> |
|---|
| 24 | | -#include <linux/platform_device.h> |
|---|
| 25 | | -#include <linux/interrupt.h> |
|---|
| 26 | | -#include <linux/device.h> |
|---|
| 27 | | -#include <linux/kernel.h> |
|---|
| 28 | | -#include <linux/slab.h> |
|---|
| 29 | | -#include <linux/io.h> |
|---|
| 30 | 10 | #include <linux/clk.h> |
|---|
| 31 | | -#include <linux/err.h> |
|---|
| 32 | 11 | #include <linux/completion.h> |
|---|
| 33 | | -#include <linux/of.h> |
|---|
| 34 | | - |
|---|
| 12 | +#include <linux/err.h> |
|---|
| 35 | 13 | #include <linux/iio/iio.h> |
|---|
| 36 | | -#include <linux/iio/sysfs.h> |
|---|
| 14 | +#include <linux/interrupt.h> |
|---|
| 15 | +#include <linux/io.h> |
|---|
| 16 | +#include <linux/module.h> |
|---|
| 17 | +#include <linux/mod_devicetable.h> |
|---|
| 18 | +#include <linux/platform_device.h> |
|---|
| 19 | +#include <linux/regulator/consumer.h> |
|---|
| 37 | 20 | |
|---|
| 38 | 21 | /* |
|---|
| 39 | 22 | * LPC32XX registers definitions |
|---|
| .. | .. |
|---|
| 65 | 48 | void __iomem *adc_base; |
|---|
| 66 | 49 | struct clk *clk; |
|---|
| 67 | 50 | struct completion completion; |
|---|
| 51 | + struct regulator *vref; |
|---|
| 68 | 52 | |
|---|
| 69 | 53 | u32 value; |
|---|
| 70 | 54 | }; |
|---|
| .. | .. |
|---|
| 77 | 61 | { |
|---|
| 78 | 62 | struct lpc32xx_adc_state *st = iio_priv(indio_dev); |
|---|
| 79 | 63 | int ret; |
|---|
| 80 | | - if (mask == IIO_CHAN_INFO_RAW) { |
|---|
| 64 | + |
|---|
| 65 | + switch (mask) { |
|---|
| 66 | + case IIO_CHAN_INFO_RAW: |
|---|
| 81 | 67 | mutex_lock(&indio_dev->mlock); |
|---|
| 82 | 68 | ret = clk_prepare_enable(st->clk); |
|---|
| 83 | 69 | if (ret) { |
|---|
| .. | .. |
|---|
| 97 | 83 | mutex_unlock(&indio_dev->mlock); |
|---|
| 98 | 84 | |
|---|
| 99 | 85 | return IIO_VAL_INT; |
|---|
| 100 | | - } |
|---|
| 101 | 86 | |
|---|
| 102 | | - return -EINVAL; |
|---|
| 87 | + case IIO_CHAN_INFO_SCALE: |
|---|
| 88 | + *val = regulator_get_voltage(st->vref) / 1000; |
|---|
| 89 | + *val2 = 10; |
|---|
| 90 | + |
|---|
| 91 | + return IIO_VAL_FRACTIONAL_LOG2; |
|---|
| 92 | + default: |
|---|
| 93 | + return -EINVAL; |
|---|
| 94 | + } |
|---|
| 103 | 95 | } |
|---|
| 104 | 96 | |
|---|
| 105 | 97 | static const struct iio_info lpc32xx_adc_iio_info = { |
|---|
| 106 | 98 | .read_raw = &lpc32xx_read_raw, |
|---|
| 107 | 99 | }; |
|---|
| 108 | 100 | |
|---|
| 109 | | -#define LPC32XX_ADC_CHANNEL(_index) { \ |
|---|
| 101 | +#define LPC32XX_ADC_CHANNEL_BASE(_index) \ |
|---|
| 110 | 102 | .type = IIO_VOLTAGE, \ |
|---|
| 111 | 103 | .indexed = 1, \ |
|---|
| 112 | 104 | .channel = _index, \ |
|---|
| 113 | 105 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
|---|
| 114 | 106 | .address = LPC32XXAD_IN * _index, \ |
|---|
| 115 | | - .scan_index = _index, \ |
|---|
| 107 | + .scan_index = _index, |
|---|
| 108 | + |
|---|
| 109 | +#define LPC32XX_ADC_CHANNEL(_index) { \ |
|---|
| 110 | + LPC32XX_ADC_CHANNEL_BASE(_index) \ |
|---|
| 111 | +} |
|---|
| 112 | + |
|---|
| 113 | +#define LPC32XX_ADC_SCALE_CHANNEL(_index) { \ |
|---|
| 114 | + LPC32XX_ADC_CHANNEL_BASE(_index) \ |
|---|
| 115 | + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ |
|---|
| 116 | 116 | } |
|---|
| 117 | 117 | |
|---|
| 118 | 118 | static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = { |
|---|
| 119 | 119 | LPC32XX_ADC_CHANNEL(0), |
|---|
| 120 | 120 | LPC32XX_ADC_CHANNEL(1), |
|---|
| 121 | 121 | LPC32XX_ADC_CHANNEL(2), |
|---|
| 122 | +}; |
|---|
| 123 | + |
|---|
| 124 | +static const struct iio_chan_spec lpc32xx_adc_iio_scale_channels[] = { |
|---|
| 125 | + LPC32XX_ADC_SCALE_CHANNEL(0), |
|---|
| 126 | + LPC32XX_ADC_SCALE_CHANNEL(1), |
|---|
| 127 | + LPC32XX_ADC_SCALE_CHANNEL(2), |
|---|
| 122 | 128 | }; |
|---|
| 123 | 129 | |
|---|
| 124 | 130 | static irqreturn_t lpc32xx_adc_isr(int irq, void *dev_id) |
|---|
| .. | .. |
|---|
| 167 | 173 | } |
|---|
| 168 | 174 | |
|---|
| 169 | 175 | irq = platform_get_irq(pdev, 0); |
|---|
| 170 | | - if (irq <= 0) { |
|---|
| 171 | | - dev_err(&pdev->dev, "failed getting interrupt resource\n"); |
|---|
| 176 | + if (irq <= 0) |
|---|
| 172 | 177 | return -ENXIO; |
|---|
| 173 | | - } |
|---|
| 174 | 178 | |
|---|
| 175 | 179 | retval = devm_request_irq(&pdev->dev, irq, lpc32xx_adc_isr, 0, |
|---|
| 176 | 180 | LPC32XXAD_NAME, st); |
|---|
| .. | .. |
|---|
| 179 | 183 | return retval; |
|---|
| 180 | 184 | } |
|---|
| 181 | 185 | |
|---|
| 186 | + st->vref = devm_regulator_get(&pdev->dev, "vref"); |
|---|
| 187 | + if (IS_ERR(st->vref)) { |
|---|
| 188 | + iodev->channels = lpc32xx_adc_iio_channels; |
|---|
| 189 | + dev_info(&pdev->dev, |
|---|
| 190 | + "Missing vref regulator: No scaling available\n"); |
|---|
| 191 | + } else { |
|---|
| 192 | + iodev->channels = lpc32xx_adc_iio_scale_channels; |
|---|
| 193 | + } |
|---|
| 194 | + |
|---|
| 182 | 195 | platform_set_drvdata(pdev, iodev); |
|---|
| 183 | 196 | |
|---|
| 184 | 197 | init_completion(&st->completion); |
|---|
| 185 | 198 | |
|---|
| 186 | 199 | iodev->name = LPC32XXAD_NAME; |
|---|
| 187 | | - iodev->dev.parent = &pdev->dev; |
|---|
| 188 | 200 | iodev->info = &lpc32xx_adc_iio_info; |
|---|
| 189 | 201 | iodev->modes = INDIO_DIRECT_MODE; |
|---|
| 190 | | - iodev->channels = lpc32xx_adc_iio_channels; |
|---|
| 191 | 202 | iodev->num_channels = ARRAY_SIZE(lpc32xx_adc_iio_channels); |
|---|
| 192 | 203 | |
|---|
| 193 | 204 | retval = devm_iio_device_register(&pdev->dev, iodev); |
|---|
| .. | .. |
|---|
| 199 | 210 | return 0; |
|---|
| 200 | 211 | } |
|---|
| 201 | 212 | |
|---|
| 202 | | -#ifdef CONFIG_OF |
|---|
| 203 | 213 | static const struct of_device_id lpc32xx_adc_match[] = { |
|---|
| 204 | 214 | { .compatible = "nxp,lpc3220-adc" }, |
|---|
| 205 | 215 | {}, |
|---|
| 206 | 216 | }; |
|---|
| 207 | 217 | MODULE_DEVICE_TABLE(of, lpc32xx_adc_match); |
|---|
| 208 | | -#endif |
|---|
| 209 | 218 | |
|---|
| 210 | 219 | static struct platform_driver lpc32xx_adc_driver = { |
|---|
| 211 | 220 | .probe = lpc32xx_adc_probe, |
|---|
| 212 | 221 | .driver = { |
|---|
| 213 | 222 | .name = LPC32XXAD_NAME, |
|---|
| 214 | | - .of_match_table = of_match_ptr(lpc32xx_adc_match), |
|---|
| 223 | + .of_match_table = lpc32xx_adc_match, |
|---|
| 215 | 224 | }, |
|---|
| 216 | 225 | }; |
|---|
| 217 | 226 | |
|---|