1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * lpc32xx_adc.c - Support for ADC in LPC32XX |
4 | * |
5 | * 3-channel, 10-bit ADC |
6 | * |
7 | * Copyright (C) 2011, 2012 Roland Stigge <stigge@antcom.de> |
8 | */ |
9 | |
10 | #include <linux/clk.h> |
11 | #include <linux/completion.h> |
12 | #include <linux/err.h> |
13 | #include <linux/iio/iio.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/mutex.h> |
19 | #include <linux/platform_device.h> |
20 | #include <linux/regulator/consumer.h> |
21 | |
22 | /* |
23 | * LPC32XX registers definitions |
24 | */ |
25 | #define LPC32XXAD_SELECT(x) ((x) + 0x04) |
26 | #define LPC32XXAD_CTRL(x) ((x) + 0x08) |
27 | #define LPC32XXAD_VALUE(x) ((x) + 0x48) |
28 | |
29 | /* Bit definitions for LPC32XXAD_SELECT: */ |
30 | /* constant, always write this value! */ |
31 | #define LPC32XXAD_REFm 0x00000200 |
32 | /* constant, always write this value! */ |
33 | #define LPC32XXAD_REFp 0x00000080 |
34 | /* multiple of this is the channel number: 0, 1, 2 */ |
35 | #define LPC32XXAD_IN 0x00000010 |
36 | /* constant, always write this value! */ |
37 | #define LPC32XXAD_INTERNAL 0x00000004 |
38 | |
39 | /* Bit definitions for LPC32XXAD_CTRL: */ |
40 | #define LPC32XXAD_STROBE 0x00000002 |
41 | #define LPC32XXAD_PDN_CTRL 0x00000004 |
42 | |
43 | /* Bit definitions for LPC32XXAD_VALUE: */ |
44 | #define LPC32XXAD_VALUE_MASK 0x000003FF |
45 | |
46 | #define LPC32XXAD_NAME "lpc32xx-adc" |
47 | |
48 | struct lpc32xx_adc_state { |
49 | void __iomem *adc_base; |
50 | struct clk *clk; |
51 | struct completion completion; |
52 | struct regulator *vref; |
53 | /* lock to protect against multiple access to the device */ |
54 | struct mutex lock; |
55 | |
56 | u32 value; |
57 | }; |
58 | |
59 | static int lpc32xx_read_raw(struct iio_dev *indio_dev, |
60 | struct iio_chan_spec const *chan, |
61 | int *val, |
62 | int *val2, |
63 | long mask) |
64 | { |
65 | struct lpc32xx_adc_state *st = iio_priv(indio_dev); |
66 | int ret; |
67 | |
68 | switch (mask) { |
69 | case IIO_CHAN_INFO_RAW: |
70 | mutex_lock(&st->lock); |
71 | ret = clk_prepare_enable(clk: st->clk); |
72 | if (ret) { |
73 | mutex_unlock(lock: &st->lock); |
74 | return ret; |
75 | } |
76 | /* Measurement setup */ |
77 | __raw_writel(LPC32XXAD_INTERNAL | (chan->address) | |
78 | LPC32XXAD_REFp | LPC32XXAD_REFm, |
79 | LPC32XXAD_SELECT(st->adc_base)); |
80 | /* Trigger conversion */ |
81 | __raw_writel(LPC32XXAD_PDN_CTRL | LPC32XXAD_STROBE, |
82 | LPC32XXAD_CTRL(st->adc_base)); |
83 | wait_for_completion(&st->completion); /* set by ISR */ |
84 | clk_disable_unprepare(clk: st->clk); |
85 | *val = st->value; |
86 | mutex_unlock(lock: &st->lock); |
87 | |
88 | return IIO_VAL_INT; |
89 | |
90 | case IIO_CHAN_INFO_SCALE: |
91 | *val = regulator_get_voltage(regulator: st->vref) / 1000; |
92 | *val2 = 10; |
93 | |
94 | return IIO_VAL_FRACTIONAL_LOG2; |
95 | default: |
96 | return -EINVAL; |
97 | } |
98 | } |
99 | |
100 | static const struct iio_info lpc32xx_adc_iio_info = { |
101 | .read_raw = &lpc32xx_read_raw, |
102 | }; |
103 | |
104 | #define LPC32XX_ADC_CHANNEL_BASE(_index) \ |
105 | .type = IIO_VOLTAGE, \ |
106 | .indexed = 1, \ |
107 | .channel = _index, \ |
108 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
109 | .address = LPC32XXAD_IN * _index, \ |
110 | .scan_index = _index, |
111 | |
112 | #define LPC32XX_ADC_CHANNEL(_index) { \ |
113 | LPC32XX_ADC_CHANNEL_BASE(_index) \ |
114 | } |
115 | |
116 | #define LPC32XX_ADC_SCALE_CHANNEL(_index) { \ |
117 | LPC32XX_ADC_CHANNEL_BASE(_index) \ |
118 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ |
119 | } |
120 | |
121 | static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = { |
122 | LPC32XX_ADC_CHANNEL(0), |
123 | LPC32XX_ADC_CHANNEL(1), |
124 | LPC32XX_ADC_CHANNEL(2), |
125 | }; |
126 | |
127 | static const struct iio_chan_spec lpc32xx_adc_iio_scale_channels[] = { |
128 | LPC32XX_ADC_SCALE_CHANNEL(0), |
129 | LPC32XX_ADC_SCALE_CHANNEL(1), |
130 | LPC32XX_ADC_SCALE_CHANNEL(2), |
131 | }; |
132 | |
133 | static irqreturn_t lpc32xx_adc_isr(int irq, void *dev_id) |
134 | { |
135 | struct lpc32xx_adc_state *st = dev_id; |
136 | |
137 | /* Read value and clear irq */ |
138 | st->value = __raw_readl(LPC32XXAD_VALUE(st->adc_base)) & |
139 | LPC32XXAD_VALUE_MASK; |
140 | complete(&st->completion); |
141 | |
142 | return IRQ_HANDLED; |
143 | } |
144 | |
145 | static int lpc32xx_adc_probe(struct platform_device *pdev) |
146 | { |
147 | struct lpc32xx_adc_state *st = NULL; |
148 | struct resource *res; |
149 | int retval = -ENODEV; |
150 | struct iio_dev *iodev = NULL; |
151 | int irq; |
152 | |
153 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
154 | if (!res) { |
155 | dev_err(&pdev->dev, "failed to get platform I/O memory\n" ); |
156 | return -ENXIO; |
157 | } |
158 | |
159 | iodev = devm_iio_device_alloc(parent: &pdev->dev, sizeof_priv: sizeof(*st)); |
160 | if (!iodev) |
161 | return -ENOMEM; |
162 | |
163 | st = iio_priv(indio_dev: iodev); |
164 | |
165 | st->adc_base = devm_ioremap(dev: &pdev->dev, offset: res->start, |
166 | size: resource_size(res)); |
167 | if (!st->adc_base) { |
168 | dev_err(&pdev->dev, "failed mapping memory\n" ); |
169 | return -EBUSY; |
170 | } |
171 | |
172 | st->clk = devm_clk_get(dev: &pdev->dev, NULL); |
173 | if (IS_ERR(ptr: st->clk)) { |
174 | dev_err(&pdev->dev, "failed getting clock\n" ); |
175 | return PTR_ERR(ptr: st->clk); |
176 | } |
177 | |
178 | irq = platform_get_irq(pdev, 0); |
179 | if (irq < 0) |
180 | return irq; |
181 | |
182 | retval = devm_request_irq(dev: &pdev->dev, irq, handler: lpc32xx_adc_isr, irqflags: 0, |
183 | LPC32XXAD_NAME, dev_id: st); |
184 | if (retval < 0) { |
185 | dev_err(&pdev->dev, "failed requesting interrupt\n" ); |
186 | return retval; |
187 | } |
188 | |
189 | st->vref = devm_regulator_get(dev: &pdev->dev, id: "vref" ); |
190 | if (IS_ERR(ptr: st->vref)) { |
191 | iodev->channels = lpc32xx_adc_iio_channels; |
192 | dev_info(&pdev->dev, |
193 | "Missing vref regulator: No scaling available\n" ); |
194 | } else { |
195 | iodev->channels = lpc32xx_adc_iio_scale_channels; |
196 | } |
197 | |
198 | platform_set_drvdata(pdev, data: iodev); |
199 | |
200 | init_completion(x: &st->completion); |
201 | |
202 | iodev->name = LPC32XXAD_NAME; |
203 | iodev->info = &lpc32xx_adc_iio_info; |
204 | iodev->modes = INDIO_DIRECT_MODE; |
205 | iodev->num_channels = ARRAY_SIZE(lpc32xx_adc_iio_channels); |
206 | |
207 | mutex_init(&st->lock); |
208 | |
209 | retval = devm_iio_device_register(&pdev->dev, iodev); |
210 | if (retval) |
211 | return retval; |
212 | |
213 | dev_info(&pdev->dev, "LPC32XX ADC driver loaded, IRQ %d\n" , irq); |
214 | |
215 | return 0; |
216 | } |
217 | |
218 | static const struct of_device_id lpc32xx_adc_match[] = { |
219 | { .compatible = "nxp,lpc3220-adc" }, |
220 | {}, |
221 | }; |
222 | MODULE_DEVICE_TABLE(of, lpc32xx_adc_match); |
223 | |
224 | static struct platform_driver lpc32xx_adc_driver = { |
225 | .probe = lpc32xx_adc_probe, |
226 | .driver = { |
227 | .name = LPC32XXAD_NAME, |
228 | .of_match_table = lpc32xx_adc_match, |
229 | }, |
230 | }; |
231 | |
232 | module_platform_driver(lpc32xx_adc_driver); |
233 | |
234 | MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>" ); |
235 | MODULE_DESCRIPTION("LPC32XX ADC driver" ); |
236 | MODULE_LICENSE("GPL" ); |
237 | |