]>
Commit | Line | Data |
---|---|---|
a466ecec FG |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright (C) 2018, STMicroelectronics - All Rights Reserved | |
4 | * Author: Fabrice Gasnier <[email protected]> | |
5 | * | |
6 | * Originally based on the Linux kernel v4.18 drivers/iio/adc/stm32-adc.c. | |
7 | */ | |
8 | ||
9 | #include <common.h> | |
10 | #include <adc.h> | |
c273da07 | 11 | #include <dm.h> |
a466ecec | 12 | #include <asm/io.h> |
336d4615 | 13 | #include <dm/device_compat.h> |
cd93d625 | 14 | #include <linux/bitops.h> |
c05ed00a | 15 | #include <linux/delay.h> |
a466ecec FG |
16 | #include <linux/iopoll.h> |
17 | #include "stm32-adc-core.h" | |
18 | ||
19 | /* STM32H7 - Registers for each ADC instance */ | |
20 | #define STM32H7_ADC_ISR 0x00 | |
21 | #define STM32H7_ADC_CR 0x08 | |
22 | #define STM32H7_ADC_CFGR 0x0C | |
23 | #define STM32H7_ADC_SMPR1 0x14 | |
24 | #define STM32H7_ADC_SMPR2 0x18 | |
25 | #define STM32H7_ADC_PCSEL 0x1C | |
26 | #define STM32H7_ADC_SQR1 0x30 | |
27 | #define STM32H7_ADC_DR 0x40 | |
28 | #define STM32H7_ADC_DIFSEL 0xC0 | |
29 | ||
30 | /* STM32H7_ADC_ISR - bit fields */ | |
31 | #define STM32MP1_VREGREADY BIT(12) | |
32 | #define STM32H7_EOC BIT(2) | |
33 | #define STM32H7_ADRDY BIT(0) | |
34 | ||
35 | /* STM32H7_ADC_CR - bit fields */ | |
17bae776 OM |
36 | #define STM32H7_ADCAL BIT(31) |
37 | #define STM32H7_ADCALDIF BIT(30) | |
a466ecec FG |
38 | #define STM32H7_DEEPPWD BIT(29) |
39 | #define STM32H7_ADVREGEN BIT(28) | |
17bae776 | 40 | #define STM32H7_ADCALLIN BIT(16) |
a466ecec FG |
41 | #define STM32H7_BOOST BIT(8) |
42 | #define STM32H7_ADSTART BIT(2) | |
43 | #define STM32H7_ADDIS BIT(1) | |
44 | #define STM32H7_ADEN BIT(0) | |
45 | ||
46 | /* STM32H7_ADC_CFGR bit fields */ | |
47 | #define STM32H7_EXTEN GENMASK(11, 10) | |
48 | #define STM32H7_DMNGT GENMASK(1, 0) | |
49 | ||
50 | /* STM32H7_ADC_SQR1 - bit fields */ | |
51 | #define STM32H7_SQ1_SHIFT 6 | |
52 | ||
53 | /* BOOST bit must be set on STM32H7 when ADC clock is above 20MHz */ | |
54 | #define STM32H7_BOOST_CLKRATE 20000000UL | |
55 | ||
56 | #define STM32_ADC_CH_MAX 20 /* max number of channels */ | |
57 | #define STM32_ADC_TIMEOUT_US 100000 | |
58 | ||
59 | struct stm32_adc_cfg { | |
60 | unsigned int max_channels; | |
61 | unsigned int num_bits; | |
62 | bool has_vregready; | |
63 | }; | |
64 | ||
65 | struct stm32_adc { | |
66 | void __iomem *regs; | |
67 | int active_channel; | |
68 | const struct stm32_adc_cfg *cfg; | |
69 | }; | |
70 | ||
17bae776 | 71 | static void stm32_adc_enter_pwr_down(struct udevice *dev) |
a466ecec FG |
72 | { |
73 | struct stm32_adc *adc = dev_get_priv(dev); | |
74 | ||
a466ecec FG |
75 | clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST); |
76 | /* Setting DEEPPWD disables ADC vreg and clears ADVREGEN */ | |
77 | setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD); | |
a466ecec FG |
78 | } |
79 | ||
17bae776 | 80 | static int stm32_adc_exit_pwr_down(struct udevice *dev) |
a466ecec | 81 | { |
a466ecec FG |
82 | struct stm32_adc_common *common = dev_get_priv(dev_get_parent(dev)); |
83 | struct stm32_adc *adc = dev_get_priv(dev); | |
84 | int ret; | |
85 | u32 val; | |
86 | ||
17bae776 OM |
87 | /* return immediately if ADC is not in deep power down mode */ |
88 | if (!(readl(adc->regs + STM32H7_ADC_CR) & STM32H7_DEEPPWD)) | |
89 | return 0; | |
90 | ||
a466ecec FG |
91 | /* Exit deep power down, then enable ADC voltage regulator */ |
92 | clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD); | |
93 | setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADVREGEN); | |
17bae776 | 94 | |
a466ecec FG |
95 | if (common->rate > STM32H7_BOOST_CLKRATE) |
96 | setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST); | |
97 | ||
98 | /* Wait for startup time */ | |
99 | if (!adc->cfg->has_vregready) { | |
100 | udelay(20); | |
17bae776 OM |
101 | return 0; |
102 | } | |
103 | ||
104 | ret = readl_poll_timeout(adc->regs + STM32H7_ADC_ISR, val, | |
105 | val & STM32MP1_VREGREADY, | |
106 | STM32_ADC_TIMEOUT_US); | |
107 | if (ret < 0) { | |
108 | stm32_adc_enter_pwr_down(dev); | |
109 | dev_err(dev, "Failed to enable vreg: %d\n", ret); | |
a466ecec FG |
110 | } |
111 | ||
17bae776 OM |
112 | return ret; |
113 | } | |
114 | ||
115 | static int stm32_adc_stop(struct udevice *dev) | |
116 | { | |
117 | struct stm32_adc *adc = dev_get_priv(dev); | |
118 | ||
119 | setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADDIS); | |
120 | stm32_adc_enter_pwr_down(dev); | |
121 | adc->active_channel = -1; | |
122 | ||
123 | return 0; | |
124 | } | |
125 | ||
126 | static int stm32_adc_start_channel(struct udevice *dev, int channel) | |
127 | { | |
128 | struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev); | |
129 | struct stm32_adc *adc = dev_get_priv(dev); | |
130 | int ret; | |
131 | u32 val; | |
132 | ||
133 | ret = stm32_adc_exit_pwr_down(dev); | |
134 | if (ret < 0) | |
135 | return ret; | |
136 | ||
a466ecec FG |
137 | /* Only use single ended channels */ |
138 | writel(0, adc->regs + STM32H7_ADC_DIFSEL); | |
139 | ||
140 | /* Enable ADC, Poll for ADRDY to be set (after adc startup time) */ | |
141 | setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADEN); | |
142 | ret = readl_poll_timeout(adc->regs + STM32H7_ADC_ISR, val, | |
143 | val & STM32H7_ADRDY, STM32_ADC_TIMEOUT_US); | |
144 | if (ret < 0) { | |
145 | stm32_adc_stop(dev); | |
146 | dev_err(dev, "Failed to enable ADC: %d\n", ret); | |
147 | return ret; | |
148 | } | |
149 | ||
150 | /* Preselect channels */ | |
151 | writel(uc_pdata->channel_mask, adc->regs + STM32H7_ADC_PCSEL); | |
152 | ||
153 | /* Set sampling time to max value by default */ | |
154 | writel(0xffffffff, adc->regs + STM32H7_ADC_SMPR1); | |
155 | writel(0xffffffff, adc->regs + STM32H7_ADC_SMPR2); | |
156 | ||
157 | /* Program regular sequence: chan in SQ1 & len = 0 for one channel */ | |
158 | writel(channel << STM32H7_SQ1_SHIFT, adc->regs + STM32H7_ADC_SQR1); | |
159 | ||
160 | /* Trigger detection disabled (conversion can be launched in SW) */ | |
161 | clrbits_le32(adc->regs + STM32H7_ADC_CFGR, STM32H7_EXTEN | | |
162 | STM32H7_DMNGT); | |
163 | adc->active_channel = channel; | |
164 | ||
165 | return 0; | |
166 | } | |
167 | ||
168 | static int stm32_adc_channel_data(struct udevice *dev, int channel, | |
169 | unsigned int *data) | |
170 | { | |
171 | struct stm32_adc *adc = dev_get_priv(dev); | |
172 | int ret; | |
173 | u32 val; | |
174 | ||
175 | if (channel != adc->active_channel) { | |
176 | dev_err(dev, "Requested channel is not active!\n"); | |
177 | return -EINVAL; | |
178 | } | |
179 | ||
180 | setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADSTART); | |
181 | ret = readl_poll_timeout(adc->regs + STM32H7_ADC_ISR, val, | |
182 | val & STM32H7_EOC, STM32_ADC_TIMEOUT_US); | |
183 | if (ret < 0) { | |
184 | dev_err(dev, "conversion timed out: %d\n", ret); | |
185 | return ret; | |
186 | } | |
187 | ||
188 | *data = readl(adc->regs + STM32H7_ADC_DR); | |
189 | ||
190 | return 0; | |
191 | } | |
192 | ||
17bae776 OM |
193 | /** |
194 | * Fixed timeout value for ADC calibration. | |
195 | * worst cases: | |
196 | * - low clock frequency (0.12 MHz min) | |
197 | * - maximum prescalers | |
198 | * Calibration requires: | |
199 | * - 16384 ADC clock cycle for the linear calibration | |
200 | * - 20 ADC clock cycle for the offset calibration | |
201 | * | |
202 | * Set to 100ms for now | |
203 | */ | |
204 | #define STM32H7_ADC_CALIB_TIMEOUT_US 100000 | |
205 | ||
206 | static int stm32_adc_selfcalib(struct udevice *dev) | |
207 | { | |
208 | struct stm32_adc *adc = dev_get_priv(dev); | |
209 | int ret; | |
210 | u32 val; | |
211 | ||
212 | /* | |
213 | * Select calibration mode: | |
214 | * - Offset calibration for single ended inputs | |
215 | * - No linearity calibration. Done in next step. | |
216 | */ | |
217 | clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCALDIF | STM32H7_ADCALLIN); | |
218 | ||
219 | /* Start calibration, then wait for completion */ | |
220 | setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCAL); | |
221 | ret = readl_poll_sleep_timeout(adc->regs + STM32H7_ADC_CR, val, | |
222 | !(val & STM32H7_ADCAL), 100, | |
223 | STM32H7_ADC_CALIB_TIMEOUT_US); | |
224 | if (ret) { | |
225 | dev_err(dev, "calibration failed\n"); | |
226 | goto out; | |
227 | } | |
228 | ||
229 | /* | |
230 | * Select calibration mode, then start calibration: | |
231 | * - Offset calibration for differential input | |
232 | * - Linearity calibration (needs to be done only once for single/diff) | |
233 | * will run simultaneously with offset calibration. | |
234 | */ | |
235 | setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCALDIF | STM32H7_ADCALLIN); | |
236 | ||
237 | /* Start calibration, then wait for completion */ | |
238 | setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCAL); | |
239 | ret = readl_poll_sleep_timeout(adc->regs + STM32H7_ADC_CR, val, | |
240 | !(val & STM32H7_ADCAL), 100, | |
241 | STM32H7_ADC_CALIB_TIMEOUT_US); | |
242 | if (ret) | |
243 | dev_err(dev, "calibration failed\n"); | |
244 | ||
245 | out: | |
246 | clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCALDIF | STM32H7_ADCALLIN); | |
247 | ||
248 | return ret; | |
249 | } | |
250 | ||
1727d46b | 251 | static int stm32_adc_get_legacy_chan_count(struct udevice *dev) |
a466ecec | 252 | { |
0fb03656 | 253 | int ret; |
a466ecec FG |
254 | |
255 | /* Retrieve single ended channels listed in device tree */ | |
0fb03656 PD |
256 | ret = dev_read_size(dev, "st,adc-channels"); |
257 | if (ret < 0) { | |
258 | dev_err(dev, "can't get st,adc-channels: %d\n", ret); | |
259 | return ret; | |
a466ecec | 260 | } |
a466ecec | 261 | |
1727d46b OM |
262 | return (ret / sizeof(u32)); |
263 | } | |
264 | ||
265 | static int stm32_adc_legacy_chan_init(struct udevice *dev, unsigned int num_channels) | |
266 | { | |
267 | struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev); | |
268 | struct stm32_adc *adc = dev_get_priv(dev); | |
269 | u32 chans[STM32_ADC_CH_MAX]; | |
270 | int i, ret; | |
a466ecec FG |
271 | |
272 | ret = dev_read_u32_array(dev, "st,adc-channels", chans, num_channels); | |
273 | if (ret < 0) { | |
274 | dev_err(dev, "can't read st,adc-channels: %d\n", ret); | |
275 | return ret; | |
276 | } | |
277 | ||
278 | for (i = 0; i < num_channels; i++) { | |
279 | if (chans[i] >= adc->cfg->max_channels) { | |
280 | dev_err(dev, "bad channel %u\n", chans[i]); | |
281 | return -EINVAL; | |
282 | } | |
283 | uc_pdata->channel_mask |= 1 << chans[i]; | |
284 | } | |
285 | ||
1727d46b OM |
286 | return ret; |
287 | } | |
288 | ||
a9aa2aef OM |
289 | static int stm32_adc_generic_chan_init(struct udevice *dev, unsigned int num_channels) |
290 | { | |
291 | struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev); | |
292 | struct stm32_adc *adc = dev_get_priv(dev); | |
293 | ofnode child; | |
294 | int val, ret; | |
295 | ||
296 | ofnode_for_each_subnode(child, dev_ofnode(dev)) { | |
297 | ret = ofnode_read_u32(child, "reg", &val); | |
298 | if (ret) { | |
299 | dev_err(dev, "Missing channel index %d\n", ret); | |
300 | return ret; | |
301 | } | |
302 | ||
303 | if (val >= adc->cfg->max_channels) { | |
304 | dev_err(dev, "Invalid channel %d\n", val); | |
305 | return -EINVAL; | |
306 | } | |
307 | ||
308 | uc_pdata->channel_mask |= 1 << val; | |
309 | } | |
310 | ||
311 | return 0; | |
312 | } | |
313 | ||
1727d46b OM |
314 | static int stm32_adc_chan_of_init(struct udevice *dev) |
315 | { | |
316 | struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev); | |
317 | struct stm32_adc *adc = dev_get_priv(dev); | |
318 | unsigned int num_channels; | |
319 | int ret; | |
a9aa2aef OM |
320 | bool legacy = false; |
321 | ||
322 | num_channels = dev_get_child_count(dev); | |
323 | /* If no channels have been found, fallback to channels legacy properties. */ | |
324 | if (!num_channels) { | |
325 | legacy = true; | |
326 | ||
327 | ret = stm32_adc_get_legacy_chan_count(dev); | |
328 | if (!ret) { | |
329 | dev_err(dev, "No channel found\n"); | |
330 | return -ENODATA; | |
331 | } else if (ret < 0) { | |
332 | return ret; | |
333 | } | |
334 | num_channels = ret; | |
335 | } | |
1727d46b OM |
336 | |
337 | if (num_channels > adc->cfg->max_channels) { | |
338 | dev_err(dev, "too many st,adc-channels: %d\n", num_channels); | |
339 | return -EINVAL; | |
340 | } | |
341 | ||
a9aa2aef OM |
342 | if (legacy) |
343 | ret = stm32_adc_legacy_chan_init(dev, num_channels); | |
344 | else | |
345 | ret = stm32_adc_generic_chan_init(dev, num_channels); | |
1727d46b OM |
346 | if (ret < 0) |
347 | return ret; | |
348 | ||
a466ecec FG |
349 | uc_pdata->data_mask = (1 << adc->cfg->num_bits) - 1; |
350 | uc_pdata->data_format = ADC_DATA_FORMAT_BIN; | |
351 | uc_pdata->data_timeout_us = 100000; | |
352 | ||
353 | return 0; | |
354 | } | |
355 | ||
356 | static int stm32_adc_probe(struct udevice *dev) | |
357 | { | |
caa4daa2 | 358 | struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev); |
a466ecec FG |
359 | struct stm32_adc_common *common = dev_get_priv(dev_get_parent(dev)); |
360 | struct stm32_adc *adc = dev_get_priv(dev); | |
17bae776 | 361 | int offset, ret; |
a466ecec FG |
362 | |
363 | offset = dev_read_u32_default(dev, "reg", -ENODATA); | |
364 | if (offset < 0) { | |
365 | dev_err(dev, "Can't read reg property\n"); | |
366 | return offset; | |
367 | } | |
368 | adc->regs = common->base + offset; | |
369 | adc->cfg = (const struct stm32_adc_cfg *)dev_get_driver_data(dev); | |
370 | ||
371 | /* VDD supplied by common vref pin */ | |
372 | uc_pdata->vdd_supply = common->vref; | |
373 | uc_pdata->vdd_microvolts = common->vref_uv; | |
374 | uc_pdata->vss_microvolts = 0; | |
375 | ||
17bae776 OM |
376 | ret = stm32_adc_chan_of_init(dev); |
377 | if (ret < 0) | |
378 | return ret; | |
379 | ||
380 | ret = stm32_adc_exit_pwr_down(dev); | |
381 | if (ret < 0) | |
382 | return ret; | |
383 | ||
384 | ret = stm32_adc_selfcalib(dev); | |
385 | if (ret) | |
386 | stm32_adc_enter_pwr_down(dev); | |
387 | ||
388 | return ret; | |
a466ecec FG |
389 | } |
390 | ||
391 | static const struct adc_ops stm32_adc_ops = { | |
392 | .start_channel = stm32_adc_start_channel, | |
393 | .channel_data = stm32_adc_channel_data, | |
394 | .stop = stm32_adc_stop, | |
395 | }; | |
396 | ||
397 | static const struct stm32_adc_cfg stm32h7_adc_cfg = { | |
398 | .num_bits = 16, | |
399 | .max_channels = STM32_ADC_CH_MAX, | |
400 | }; | |
401 | ||
402 | static const struct stm32_adc_cfg stm32mp1_adc_cfg = { | |
403 | .num_bits = 16, | |
404 | .max_channels = STM32_ADC_CH_MAX, | |
405 | .has_vregready = true, | |
406 | }; | |
407 | ||
408 | static const struct udevice_id stm32_adc_ids[] = { | |
409 | { .compatible = "st,stm32h7-adc", | |
410 | .data = (ulong)&stm32h7_adc_cfg }, | |
411 | { .compatible = "st,stm32mp1-adc", | |
412 | .data = (ulong)&stm32mp1_adc_cfg }, | |
413 | {} | |
414 | }; | |
415 | ||
416 | U_BOOT_DRIVER(stm32_adc) = { | |
417 | .name = "stm32-adc", | |
418 | .id = UCLASS_ADC, | |
419 | .of_match = stm32_adc_ids, | |
420 | .probe = stm32_adc_probe, | |
421 | .ops = &stm32_adc_ops, | |
41575d8e | 422 | .priv_auto = sizeof(struct stm32_adc), |
a466ecec | 423 | }; |