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