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