blob: 029338e4af6093ad0fa4f9d70a6e2853bed5301d [file] [log] [blame]
Fabrice Gasnier5a1da382018-07-24 16:31:31 +02001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
4 * Author: Fabrice Gasnier <fabrice.gasnier@st.com>
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>
11#include <asm/io.h>
12#include <linux/iopoll.h>
13#include "stm32-adc-core.h"
14
15/* STM32H7 - Registers for each ADC instance */
16#define STM32H7_ADC_ISR 0x00
17#define STM32H7_ADC_CR 0x08
18#define STM32H7_ADC_CFGR 0x0C
19#define STM32H7_ADC_SMPR1 0x14
20#define STM32H7_ADC_SMPR2 0x18
21#define STM32H7_ADC_PCSEL 0x1C
22#define STM32H7_ADC_SQR1 0x30
23#define STM32H7_ADC_DR 0x40
24#define STM32H7_ADC_DIFSEL 0xC0
25
26/* STM32H7_ADC_ISR - bit fields */
27#define STM32MP1_VREGREADY BIT(12)
28#define STM32H7_EOC BIT(2)
29#define STM32H7_ADRDY BIT(0)
30
31/* STM32H7_ADC_CR - bit fields */
32#define STM32H7_DEEPPWD BIT(29)
33#define STM32H7_ADVREGEN BIT(28)
34#define STM32H7_BOOST BIT(8)
35#define STM32H7_ADSTART BIT(2)
36#define STM32H7_ADDIS BIT(1)
37#define STM32H7_ADEN BIT(0)
38
39/* STM32H7_ADC_CFGR bit fields */
40#define STM32H7_EXTEN GENMASK(11, 10)
41#define STM32H7_DMNGT GENMASK(1, 0)
42
43/* STM32H7_ADC_SQR1 - bit fields */
44#define STM32H7_SQ1_SHIFT 6
45
46/* BOOST bit must be set on STM32H7 when ADC clock is above 20MHz */
47#define STM32H7_BOOST_CLKRATE 20000000UL
48
49#define STM32_ADC_CH_MAX 20 /* max number of channels */
50#define STM32_ADC_TIMEOUT_US 100000
51
52struct stm32_adc_cfg {
53 unsigned int max_channels;
54 unsigned int num_bits;
55 bool has_vregready;
56};
57
58struct stm32_adc {
59 void __iomem *regs;
60 int active_channel;
61 const struct stm32_adc_cfg *cfg;
62};
63
64static int stm32_adc_stop(struct udevice *dev)
65{
66 struct stm32_adc *adc = dev_get_priv(dev);
67
68 setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADDIS);
69 clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST);
70 /* Setting DEEPPWD disables ADC vreg and clears ADVREGEN */
71 setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD);
72 adc->active_channel = -1;
73
74 return 0;
75}
76
77static int stm32_adc_start_channel(struct udevice *dev, int channel)
78{
79 struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
80 struct stm32_adc_common *common = dev_get_priv(dev_get_parent(dev));
81 struct stm32_adc *adc = dev_get_priv(dev);
82 int ret;
83 u32 val;
84
85 /* Exit deep power down, then enable ADC voltage regulator */
86 clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD);
87 setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADVREGEN);
88 if (common->rate > STM32H7_BOOST_CLKRATE)
89 setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST);
90
91 /* Wait for startup time */
92 if (!adc->cfg->has_vregready) {
93 udelay(20);
94 } else {
95 ret = readl_poll_timeout(adc->regs + STM32H7_ADC_ISR, val,
96 val & STM32MP1_VREGREADY,
97 STM32_ADC_TIMEOUT_US);
98 if (ret < 0) {
99 stm32_adc_stop(dev);
100 dev_err(dev, "Failed to enable vreg: %d\n", ret);
101 return ret;
102 }
103 }
104
105 /* Only use single ended channels */
106 writel(0, adc->regs + STM32H7_ADC_DIFSEL);
107
108 /* Enable ADC, Poll for ADRDY to be set (after adc startup time) */
109 setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADEN);
110 ret = readl_poll_timeout(adc->regs + STM32H7_ADC_ISR, val,
111 val & STM32H7_ADRDY, STM32_ADC_TIMEOUT_US);
112 if (ret < 0) {
113 stm32_adc_stop(dev);
114 dev_err(dev, "Failed to enable ADC: %d\n", ret);
115 return ret;
116 }
117
118 /* Preselect channels */
119 writel(uc_pdata->channel_mask, adc->regs + STM32H7_ADC_PCSEL);
120
121 /* Set sampling time to max value by default */
122 writel(0xffffffff, adc->regs + STM32H7_ADC_SMPR1);
123 writel(0xffffffff, adc->regs + STM32H7_ADC_SMPR2);
124
125 /* Program regular sequence: chan in SQ1 & len = 0 for one channel */
126 writel(channel << STM32H7_SQ1_SHIFT, adc->regs + STM32H7_ADC_SQR1);
127
128 /* Trigger detection disabled (conversion can be launched in SW) */
129 clrbits_le32(adc->regs + STM32H7_ADC_CFGR, STM32H7_EXTEN |
130 STM32H7_DMNGT);
131 adc->active_channel = channel;
132
133 return 0;
134}
135
136static int stm32_adc_channel_data(struct udevice *dev, int channel,
137 unsigned int *data)
138{
139 struct stm32_adc *adc = dev_get_priv(dev);
140 int ret;
141 u32 val;
142
143 if (channel != adc->active_channel) {
144 dev_err(dev, "Requested channel is not active!\n");
145 return -EINVAL;
146 }
147
148 setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADSTART);
149 ret = readl_poll_timeout(adc->regs + STM32H7_ADC_ISR, val,
150 val & STM32H7_EOC, STM32_ADC_TIMEOUT_US);
151 if (ret < 0) {
152 dev_err(dev, "conversion timed out: %d\n", ret);
153 return ret;
154 }
155
156 *data = readl(adc->regs + STM32H7_ADC_DR);
157
158 return 0;
159}
160
161static int stm32_adc_chan_of_init(struct udevice *dev)
162{
163 struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
164 struct stm32_adc *adc = dev_get_priv(dev);
165 u32 chans[STM32_ADC_CH_MAX];
Patrick Delaunay35fc48d2019-06-21 15:26:44 +0200166 unsigned int i, num_channels;
167 int ret;
Fabrice Gasnier5a1da382018-07-24 16:31:31 +0200168
169 /* Retrieve single ended channels listed in device tree */
Patrick Delaunay35fc48d2019-06-21 15:26:44 +0200170 ret = dev_read_size(dev, "st,adc-channels");
171 if (ret < 0) {
172 dev_err(dev, "can't get st,adc-channels: %d\n", ret);
173 return ret;
Fabrice Gasnier5a1da382018-07-24 16:31:31 +0200174 }
Patrick Delaunay35fc48d2019-06-21 15:26:44 +0200175 num_channels = ret / sizeof(u32);
Fabrice Gasnier5a1da382018-07-24 16:31:31 +0200176
177 if (num_channels > adc->cfg->max_channels) {
178 dev_err(dev, "too many st,adc-channels: %d\n", num_channels);
179 return -EINVAL;
180 }
181
182 ret = dev_read_u32_array(dev, "st,adc-channels", chans, num_channels);
183 if (ret < 0) {
184 dev_err(dev, "can't read st,adc-channels: %d\n", ret);
185 return ret;
186 }
187
188 for (i = 0; i < num_channels; i++) {
189 if (chans[i] >= adc->cfg->max_channels) {
190 dev_err(dev, "bad channel %u\n", chans[i]);
191 return -EINVAL;
192 }
193 uc_pdata->channel_mask |= 1 << chans[i];
194 }
195
196 uc_pdata->data_mask = (1 << adc->cfg->num_bits) - 1;
197 uc_pdata->data_format = ADC_DATA_FORMAT_BIN;
198 uc_pdata->data_timeout_us = 100000;
199
200 return 0;
201}
202
203static int stm32_adc_probe(struct udevice *dev)
204{
205 struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
206 struct stm32_adc_common *common = dev_get_priv(dev_get_parent(dev));
207 struct stm32_adc *adc = dev_get_priv(dev);
208 int offset;
209
210 offset = dev_read_u32_default(dev, "reg", -ENODATA);
211 if (offset < 0) {
212 dev_err(dev, "Can't read reg property\n");
213 return offset;
214 }
215 adc->regs = common->base + offset;
216 adc->cfg = (const struct stm32_adc_cfg *)dev_get_driver_data(dev);
217
218 /* VDD supplied by common vref pin */
219 uc_pdata->vdd_supply = common->vref;
220 uc_pdata->vdd_microvolts = common->vref_uv;
221 uc_pdata->vss_microvolts = 0;
222
223 return stm32_adc_chan_of_init(dev);
224}
225
226static const struct adc_ops stm32_adc_ops = {
227 .start_channel = stm32_adc_start_channel,
228 .channel_data = stm32_adc_channel_data,
229 .stop = stm32_adc_stop,
230};
231
232static const struct stm32_adc_cfg stm32h7_adc_cfg = {
233 .num_bits = 16,
234 .max_channels = STM32_ADC_CH_MAX,
235};
236
237static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
238 .num_bits = 16,
239 .max_channels = STM32_ADC_CH_MAX,
240 .has_vregready = true,
241};
242
243static const struct udevice_id stm32_adc_ids[] = {
244 { .compatible = "st,stm32h7-adc",
245 .data = (ulong)&stm32h7_adc_cfg },
246 { .compatible = "st,stm32mp1-adc",
247 .data = (ulong)&stm32mp1_adc_cfg },
248 {}
249};
250
251U_BOOT_DRIVER(stm32_adc) = {
252 .name = "stm32-adc",
253 .id = UCLASS_ADC,
254 .of_match = stm32_adc_ids,
255 .probe = stm32_adc_probe,
256 .ops = &stm32_adc_ops,
257 .priv_auto_alloc_size = sizeof(struct stm32_adc),
258};