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