.. | .. |
---|
| 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 | |
---|