blob: 2ca0fb4f108b3df3973f1cfe2a319e735e9a3903 [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-core.c.
7 */
8
9#include <common.h>
10#include <asm/io.h>
Simon Glass9bc15642020-02-03 07:36:16 -070011#include <dm/device_compat.h>
Fabrice Gasnier5a1da382018-07-24 16:31:31 +020012#include <power/regulator.h>
13#include "stm32-adc-core.h"
14
15/* STM32H7 - common registers for all ADC instances */
16#define STM32H7_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x08)
17
18/* STM32H7_ADC_CCR - bit fields */
19#define STM32H7_PRESC_SHIFT 18
20#define STM32H7_PRESC_MASK GENMASK(21, 18)
21#define STM32H7_CKMODE_SHIFT 16
22#define STM32H7_CKMODE_MASK GENMASK(17, 16)
23
24/* STM32 H7 maximum analog clock rate (from datasheet) */
25#define STM32H7_ADC_MAX_CLK_RATE 36000000
26
27/**
28 * struct stm32h7_adc_ck_spec - specification for stm32h7 adc clock
29 * @ckmode: ADC clock mode, Async or sync with prescaler.
30 * @presc: prescaler bitfield for async clock mode
31 * @div: prescaler division ratio
32 */
33struct stm32h7_adc_ck_spec {
34 u32 ckmode;
35 u32 presc;
36 int div;
37};
38
39static const struct stm32h7_adc_ck_spec stm32h7_adc_ckmodes_spec[] = {
40 /* 00: CK_ADC[1..3]: Asynchronous clock modes */
41 { 0, 0, 1 },
42 { 0, 1, 2 },
43 { 0, 2, 4 },
44 { 0, 3, 6 },
45 { 0, 4, 8 },
46 { 0, 5, 10 },
47 { 0, 6, 12 },
48 { 0, 7, 16 },
49 { 0, 8, 32 },
50 { 0, 9, 64 },
51 { 0, 10, 128 },
52 { 0, 11, 256 },
53 /* HCLK used: Synchronous clock modes (1, 2 or 4 prescaler) */
54 { 1, 0, 1 },
55 { 2, 0, 2 },
56 { 3, 0, 4 },
57};
58
59static int stm32h7_adc_clk_sel(struct udevice *dev,
60 struct stm32_adc_common *common)
61{
62 u32 ckmode, presc;
63 unsigned long rate;
Patrick Delaunay69c04e92019-06-21 15:26:45 +020064 unsigned int i;
65 int div;
Fabrice Gasnier5a1da382018-07-24 16:31:31 +020066
67 /* stm32h7 bus clock is common for all ADC instances (mandatory) */
68 if (!clk_valid(&common->bclk)) {
69 dev_err(dev, "No bclk clock found\n");
70 return -ENOENT;
71 }
72
73 /*
74 * stm32h7 can use either 'bus' or 'adc' clock for analog circuitry.
75 * So, choice is to have bus clock mandatory and adc clock optional.
76 * If optional 'adc' clock has been found, then try to use it first.
77 */
78 if (clk_valid(&common->aclk)) {
79 /*
80 * Asynchronous clock modes (e.g. ckmode == 0)
81 * From spec: PLL output musn't exceed max rate
82 */
83 rate = clk_get_rate(&common->aclk);
84 if (!rate) {
85 dev_err(dev, "Invalid aclk rate: 0\n");
86 return -EINVAL;
87 }
88
89 for (i = 0; i < ARRAY_SIZE(stm32h7_adc_ckmodes_spec); i++) {
90 ckmode = stm32h7_adc_ckmodes_spec[i].ckmode;
91 presc = stm32h7_adc_ckmodes_spec[i].presc;
92 div = stm32h7_adc_ckmodes_spec[i].div;
93
94 if (ckmode)
95 continue;
96
97 if ((rate / div) <= STM32H7_ADC_MAX_CLK_RATE)
98 goto out;
99 }
100 }
101
102 /* Synchronous clock modes (e.g. ckmode is 1, 2 or 3) */
103 rate = clk_get_rate(&common->bclk);
104 if (!rate) {
105 dev_err(dev, "Invalid bus clock rate: 0\n");
106 return -EINVAL;
107 }
108
109 for (i = 0; i < ARRAY_SIZE(stm32h7_adc_ckmodes_spec); i++) {
110 ckmode = stm32h7_adc_ckmodes_spec[i].ckmode;
111 presc = stm32h7_adc_ckmodes_spec[i].presc;
112 div = stm32h7_adc_ckmodes_spec[i].div;
113
114 if (!ckmode)
115 continue;
116
117 if ((rate / div) <= STM32H7_ADC_MAX_CLK_RATE)
118 goto out;
119 }
120
121 dev_err(dev, "clk selection failed\n");
122 return -EINVAL;
123
124out:
125 /* rate used later by each ADC instance to control BOOST mode */
126 common->rate = rate / div;
127
128 /* Set common clock mode and prescaler */
129 clrsetbits_le32(common->base + STM32H7_ADC_CCR,
130 STM32H7_CKMODE_MASK | STM32H7_PRESC_MASK,
131 ckmode << STM32H7_CKMODE_SHIFT |
132 presc << STM32H7_PRESC_SHIFT);
133
134 dev_dbg(dev, "Using %s clock/%d source at %ld kHz\n",
135 ckmode ? "bus" : "adc", div, common->rate / 1000);
136
137 return 0;
138}
139
140static int stm32_adc_core_probe(struct udevice *dev)
141{
142 struct stm32_adc_common *common = dev_get_priv(dev);
143 int ret;
144
145 common->base = dev_read_addr_ptr(dev);
146 if (!common->base) {
147 dev_err(dev, "can't get address\n");
148 return -ENOENT;
149 }
150
151 ret = device_get_supply_regulator(dev, "vref-supply", &common->vref);
152 if (ret) {
153 dev_err(dev, "can't get vref-supply: %d\n", ret);
154 return ret;
155 }
156
157 ret = regulator_get_value(common->vref);
158 if (ret < 0) {
159 dev_err(dev, "can't get vref-supply value: %d\n", ret);
160 return ret;
161 }
162 common->vref_uv = ret;
163
164 ret = clk_get_by_name(dev, "adc", &common->aclk);
165 if (!ret) {
166 ret = clk_enable(&common->aclk);
167 if (ret) {
168 dev_err(dev, "Can't enable aclk: %d\n", ret);
169 return ret;
170 }
171 }
172
173 ret = clk_get_by_name(dev, "bus", &common->bclk);
174 if (!ret) {
175 ret = clk_enable(&common->bclk);
176 if (ret) {
177 dev_err(dev, "Can't enable bclk: %d\n", ret);
178 goto err_aclk_disable;
179 }
180 }
181
182 ret = stm32h7_adc_clk_sel(dev, common);
183 if (ret)
184 goto err_bclk_disable;
185
186 return ret;
187
188err_bclk_disable:
189 if (clk_valid(&common->bclk))
190 clk_disable(&common->bclk);
191
192err_aclk_disable:
193 if (clk_valid(&common->aclk))
194 clk_disable(&common->aclk);
195
196 return ret;
197}
198
199static const struct udevice_id stm32_adc_core_ids[] = {
200 { .compatible = "st,stm32h7-adc-core" },
201 { .compatible = "st,stm32mp1-adc-core" },
202 {}
203};
204
205U_BOOT_DRIVER(stm32_adc_core) = {
206 .name = "stm32-adc-core",
207 .id = UCLASS_SIMPLE_BUS,
208 .of_match = stm32_adc_core_ids,
209 .probe = stm32_adc_core_probe,
210 .priv_auto_alloc_size = sizeof(struct stm32_adc_common),
211};