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