blob: 7cf9735f60d087a8ee350dfd5163b98aa8922db8 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
David Wuf8d5bc72017-09-20 14:28:16 +08002/*
3 * (C) Copyright 2017, Fuzhou Rockchip Electronics Co., Ltd
4 *
David Wuf8d5bc72017-09-20 14:28:16 +08005 * Rockchip SARADC driver for U-Boot
6 */
7
David Wuf8d5bc72017-09-20 14:28:16 +08008#include <adc.h>
9#include <clk.h>
10#include <dm.h>
11#include <errno.h>
Quentin Schulz5df8ac42024-03-14 10:36:24 +010012#include <reset.h>
13#include <asm/arch-rockchip/hardware.h>
14#include <linux/bitfield.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060015#include <linux/bitops.h>
Quentin Schulz5df8ac42024-03-14 10:36:24 +010016#include <linux/delay.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070017#include <linux/err.h>
Simon Glassbdd5f812023-09-14 18:21:46 -060018#include <linux/printk.h>
Peter Cai14f3e382022-02-04 15:16:06 -050019#include <power/regulator.h>
David Wuf8d5bc72017-09-20 14:28:16 +080020
Quentin Schulz5df8ac42024-03-14 10:36:24 +010021#define usleep_range(a, b) udelay((b))
22
David Wuf8d5bc72017-09-20 14:28:16 +080023#define SARADC_CTRL_CHN_MASK GENMASK(2, 0)
24#define SARADC_CTRL_POWER_CTRL BIT(3)
25#define SARADC_CTRL_IRQ_ENABLE BIT(5)
26#define SARADC_CTRL_IRQ_STATUS BIT(6)
27
28#define SARADC_TIMEOUT (100 * 1000)
29
Quentin Schulzf1209562024-03-14 10:36:20 +010030struct rockchip_saradc_regs_v1 {
David Wuf8d5bc72017-09-20 14:28:16 +080031 unsigned int data;
32 unsigned int stas;
33 unsigned int ctrl;
34 unsigned int dly_pu_soc;
35};
36
Quentin Schulz5df8ac42024-03-14 10:36:24 +010037struct rockchip_saradc_regs_v2 {
38 unsigned int conv_con;
39#define SARADC2_SINGLE_MODE BIT(5)
40#define SARADC2_START BIT(4)
41#define SARADC2_CONV_CHANNELS GENMASK(3, 0)
42 unsigned int t_pd_soc;
43 unsigned int t_as_soc;
44 unsigned int t_das_soc;
45 unsigned int t_sel_soc;
46 unsigned int high_comp[16];
47 unsigned int low_comp[16];
48 unsigned int debounce;
49 unsigned int ht_int_en;
50 unsigned int lt_int_en;
51 unsigned int reserved[24];
52 unsigned int mt_int_en;
53 unsigned int end_int_en;
54#define SARADC2_EN_END_INT BIT(0)
55 unsigned int st_con;
56 unsigned int status;
57 unsigned int end_int_st;
58 unsigned int ht_int_st;
59 unsigned int lt_int_st;
60 unsigned int mt_int_st;
61 unsigned int data[16];
62 unsigned int auto_ch_en;
63};
64
Quentin Schulzf1209562024-03-14 10:36:20 +010065union rockchip_saradc_regs {
66 struct rockchip_saradc_regs_v1 *v1;
Quentin Schulz5df8ac42024-03-14 10:36:24 +010067 struct rockchip_saradc_regs_v2 *v2;
Quentin Schulzf1209562024-03-14 10:36:20 +010068};
David Wuf8d5bc72017-09-20 14:28:16 +080069struct rockchip_saradc_data {
70 int num_bits;
71 int num_channels;
72 unsigned long clk_rate;
Quentin Schulza07eeca2024-03-14 10:36:21 +010073 int (*channel_data)(struct udevice *dev, int channel, unsigned int *data);
Quentin Schulzd0aaaae2024-03-14 10:36:22 +010074 int (*start_channel)(struct udevice *dev, int channel);
Quentin Schulze8e0aae2024-03-14 10:36:23 +010075 int (*stop)(struct udevice *dev);
David Wuf8d5bc72017-09-20 14:28:16 +080076};
77
78struct rockchip_saradc_priv {
Quentin Schulzf1209562024-03-14 10:36:20 +010079 union rockchip_saradc_regs regs;
David Wuf8d5bc72017-09-20 14:28:16 +080080 int active_channel;
81 const struct rockchip_saradc_data *data;
Quentin Schulz5df8ac42024-03-14 10:36:24 +010082 struct reset_ctl *reset;
David Wuf8d5bc72017-09-20 14:28:16 +080083};
84
Quentin Schulza07eeca2024-03-14 10:36:21 +010085int rockchip_saradc_channel_data_v1(struct udevice *dev, int channel,
86 unsigned int *data)
87{
88 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
89
90 if ((readl(&priv->regs.v1->ctrl) & SARADC_CTRL_IRQ_STATUS) !=
91 SARADC_CTRL_IRQ_STATUS)
92 return -EBUSY;
93
94 /* Read value */
95 *data = readl(&priv->regs.v1->data);
96
97 /* Power down adc */
98 writel(0, &priv->regs.v1->ctrl);
99
100 return 0;
101}
102
Quentin Schulz5df8ac42024-03-14 10:36:24 +0100103int rockchip_saradc_channel_data_v2(struct udevice *dev, int channel,
104 unsigned int *data)
105{
106 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
107
108 if (!(readl(&priv->regs.v2->end_int_st) & SARADC2_EN_END_INT))
109 return -EBUSY;
110
111 /* Read value */
112 *data = readl(&priv->regs.v2->data[channel]);
113
114 /* Acknowledge the interrupt */
115 writel(SARADC2_EN_END_INT, &priv->regs.v2->end_int_st);
116
117 return 0;
118}
David Wuf8d5bc72017-09-20 14:28:16 +0800119int rockchip_saradc_channel_data(struct udevice *dev, int channel,
120 unsigned int *data)
121{
122 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
Simon Glass71fa5b42020-12-03 16:55:18 -0700123 struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
Quentin Schulza07eeca2024-03-14 10:36:21 +0100124 int ret;
David Wuf8d5bc72017-09-20 14:28:16 +0800125
126 if (channel != priv->active_channel) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900127 pr_err("Requested channel is not active!");
David Wuf8d5bc72017-09-20 14:28:16 +0800128 return -EINVAL;
129 }
130
Quentin Schulza07eeca2024-03-14 10:36:21 +0100131 ret = priv->data->channel_data(dev, channel, data);
132 if (ret) {
133 if (ret != -EBUSY)
134 pr_err("Error reading channel data, %d!", ret);
135 return ret;
136 }
David Wuf8d5bc72017-09-20 14:28:16 +0800137
David Wuf8d5bc72017-09-20 14:28:16 +0800138 *data &= uc_pdata->data_mask;
139
David Wuf8d5bc72017-09-20 14:28:16 +0800140 return 0;
141}
142
Quentin Schulzd0aaaae2024-03-14 10:36:22 +0100143int rockchip_saradc_start_channel_v1(struct udevice *dev, int channel)
David Wuf8d5bc72017-09-20 14:28:16 +0800144{
145 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
146
David Wuf8d5bc72017-09-20 14:28:16 +0800147 /* 8 clock periods as delay between power up and start cmd */
Quentin Schulzf1209562024-03-14 10:36:20 +0100148 writel(8, &priv->regs.v1->dly_pu_soc);
David Wuf8d5bc72017-09-20 14:28:16 +0800149
150 /* Select the channel to be used and trigger conversion */
151 writel(SARADC_CTRL_POWER_CTRL | (channel & SARADC_CTRL_CHN_MASK) |
Quentin Schulzf1209562024-03-14 10:36:20 +0100152 SARADC_CTRL_IRQ_ENABLE, &priv->regs.v1->ctrl);
David Wuf8d5bc72017-09-20 14:28:16 +0800153
Quentin Schulzd0aaaae2024-03-14 10:36:22 +0100154 return 0;
155}
156
Quentin Schulz5df8ac42024-03-14 10:36:24 +0100157static void rockchip_saradc_reset_controller(struct reset_ctl *reset)
158{
159 reset_assert(reset);
160 usleep_range(10, 20);
161 reset_deassert(reset);
162}
163
164int rockchip_saradc_start_channel_v2(struct udevice *dev, int channel)
165{
166 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
167
168 /*
169 * Downstream says
170 * """If read other chn at anytime, then chn1 will error, assert
171 * controller as a workaround."""
172 */
173 if (priv->reset)
174 rockchip_saradc_reset_controller(priv->reset);
175
176 writel(0xc, &priv->regs.v2->t_das_soc);
177 writel(0x20, &priv->regs.v2->t_pd_soc);
178
179 /* Acknowledge any previous interrupt */
180 writel(SARADC2_EN_END_INT, &priv->regs.v2->end_int_st);
181
182 rk_clrsetreg(&priv->regs.v2->conv_con,
183 SARADC2_CONV_CHANNELS | SARADC2_START | SARADC2_SINGLE_MODE,
184 FIELD_PREP(SARADC2_CONV_CHANNELS, channel) |
185 FIELD_PREP(SARADC2_START, 1) |
186 FIELD_PREP(SARADC2_SINGLE_MODE, 1));
187
188 return 0;
189}
190
Quentin Schulzd0aaaae2024-03-14 10:36:22 +0100191int rockchip_saradc_start_channel(struct udevice *dev, int channel)
192{
193 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
194 int ret;
195
196 if (channel < 0 || channel >= priv->data->num_channels) {
197 pr_err("Requested channel is invalid!");
198 return -EINVAL;
199 }
200
201 ret = priv->data->start_channel(dev, channel);
202 if (ret) {
203 pr_err("Error starting channel, %d!", ret);
204 return ret;
205 }
206
David Wuf8d5bc72017-09-20 14:28:16 +0800207 priv->active_channel = channel;
208
209 return 0;
210}
211
Quentin Schulze8e0aae2024-03-14 10:36:23 +0100212int rockchip_saradc_stop_v1(struct udevice *dev)
David Wuf8d5bc72017-09-20 14:28:16 +0800213{
214 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
215
216 /* Power down adc */
Quentin Schulzf1209562024-03-14 10:36:20 +0100217 writel(0, &priv->regs.v1->ctrl);
David Wuf8d5bc72017-09-20 14:28:16 +0800218
Quentin Schulze8e0aae2024-03-14 10:36:23 +0100219 return 0;
220}
221
222int rockchip_saradc_stop(struct udevice *dev)
223{
224 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
225
226 if (priv->data->stop) {
227 int ret = priv->data->stop(dev);
228
229 if (ret) {
230 pr_err("Error stopping channel, %d!", ret);
231 return ret;
232 }
233 }
234
David Wuf8d5bc72017-09-20 14:28:16 +0800235 priv->active_channel = -1;
236
237 return 0;
238}
239
240int rockchip_saradc_probe(struct udevice *dev)
241{
Peter Cai14f3e382022-02-04 15:16:06 -0500242 struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
David Wuf8d5bc72017-09-20 14:28:16 +0800243 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
Jonas Karlman2569c522024-10-17 20:00:26 +0000244 struct udevice *vref = NULL;
David Wuf8d5bc72017-09-20 14:28:16 +0800245 struct clk clk;
Peter Cai14f3e382022-02-04 15:16:06 -0500246 int vref_uv;
David Wuf8d5bc72017-09-20 14:28:16 +0800247 int ret;
248
Quentin Schulz5df8ac42024-03-14 10:36:24 +0100249 priv->reset = devm_reset_control_get_optional(dev, "saradc-apb");
250
David Wuf8d5bc72017-09-20 14:28:16 +0800251 ret = clk_get_by_index(dev, 0, &clk);
252 if (ret)
253 return ret;
254
255 ret = clk_set_rate(&clk, priv->data->clk_rate);
256 if (IS_ERR_VALUE(ret))
257 return ret;
258
259 priv->active_channel = -1;
260
Peter Cai14f3e382022-02-04 15:16:06 -0500261 ret = device_get_supply_regulator(dev, "vref-supply", &vref);
Jonas Karlman2569c522024-10-17 20:00:26 +0000262 if (ret && uc_pdata->vdd_microvolts <= 0) {
Peter Cai14f3e382022-02-04 15:16:06 -0500263 printf("can't get vref-supply: %d\n", ret);
264 return ret;
265 }
266
Quentin Schulz5df8ac42024-03-14 10:36:24 +0100267 if (priv->reset)
268 rockchip_saradc_reset_controller(priv->reset);
269
Jonas Karlman2569c522024-10-17 20:00:26 +0000270 if (vref)
271 vref_uv = regulator_get_value(vref);
272 else
273 vref_uv = uc_pdata->vdd_microvolts;
Peter Cai14f3e382022-02-04 15:16:06 -0500274 if (vref_uv < 0) {
275 printf("can't get vref-supply value: %d\n", vref_uv);
276 return vref_uv;
277 }
278
279 /* VDD supplied by common vref pin */
280 uc_pdata->vdd_supply = vref;
281 uc_pdata->vdd_microvolts = vref_uv;
282 uc_pdata->vss_microvolts = 0;
283
David Wuf8d5bc72017-09-20 14:28:16 +0800284 return 0;
285}
286
Simon Glassaad29ae2020-12-03 16:55:21 -0700287int rockchip_saradc_of_to_plat(struct udevice *dev)
David Wuf8d5bc72017-09-20 14:28:16 +0800288{
Simon Glass71fa5b42020-12-03 16:55:18 -0700289 struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
David Wuf8d5bc72017-09-20 14:28:16 +0800290 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
291 struct rockchip_saradc_data *data;
292
293 data = (struct rockchip_saradc_data *)dev_get_driver_data(dev);
Quentin Schulzf1209562024-03-14 10:36:20 +0100294 priv->regs.v1 = dev_read_addr_ptr(dev);
295 if (!priv->regs.v1) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900296 pr_err("Dev: %s - can't get address!", dev->name);
Johan Jonkerb415d0e2023-03-13 01:29:35 +0100297 return -EINVAL;
David Wuf8d5bc72017-09-20 14:28:16 +0800298 }
299
300 priv->data = data;
Giulio Benetti33ecda02022-03-14 10:09:43 +0100301 uc_pdata->data_mask = (1 << priv->data->num_bits) - 1;
David Wuf8d5bc72017-09-20 14:28:16 +0800302 uc_pdata->data_format = ADC_DATA_FORMAT_BIN;
303 uc_pdata->data_timeout_us = SARADC_TIMEOUT / 5;
304 uc_pdata->channel_mask = (1 << priv->data->num_channels) - 1;
305
306 return 0;
307}
308
309static const struct adc_ops rockchip_saradc_ops = {
310 .start_channel = rockchip_saradc_start_channel,
311 .channel_data = rockchip_saradc_channel_data,
312 .stop = rockchip_saradc_stop,
313};
314
315static const struct rockchip_saradc_data saradc_data = {
316 .num_bits = 10,
317 .num_channels = 3,
318 .clk_rate = 1000000,
Quentin Schulza07eeca2024-03-14 10:36:21 +0100319 .channel_data = rockchip_saradc_channel_data_v1,
Quentin Schulzd0aaaae2024-03-14 10:36:22 +0100320 .start_channel = rockchip_saradc_start_channel_v1,
Quentin Schulze8e0aae2024-03-14 10:36:23 +0100321 .stop = rockchip_saradc_stop_v1,
David Wuf8d5bc72017-09-20 14:28:16 +0800322};
323
324static const struct rockchip_saradc_data rk3066_tsadc_data = {
325 .num_bits = 12,
326 .num_channels = 2,
327 .clk_rate = 50000,
Quentin Schulza07eeca2024-03-14 10:36:21 +0100328 .channel_data = rockchip_saradc_channel_data_v1,
Quentin Schulzd0aaaae2024-03-14 10:36:22 +0100329 .start_channel = rockchip_saradc_start_channel_v1,
Quentin Schulze8e0aae2024-03-14 10:36:23 +0100330 .stop = rockchip_saradc_stop_v1,
David Wuf8d5bc72017-09-20 14:28:16 +0800331};
332
333static const struct rockchip_saradc_data rk3399_saradc_data = {
334 .num_bits = 10,
335 .num_channels = 6,
336 .clk_rate = 1000000,
Quentin Schulza07eeca2024-03-14 10:36:21 +0100337 .channel_data = rockchip_saradc_channel_data_v1,
Quentin Schulzd0aaaae2024-03-14 10:36:22 +0100338 .start_channel = rockchip_saradc_start_channel_v1,
Quentin Schulze8e0aae2024-03-14 10:36:23 +0100339 .stop = rockchip_saradc_stop_v1,
David Wuf8d5bc72017-09-20 14:28:16 +0800340};
341
Quentin Schulz5df8ac42024-03-14 10:36:24 +0100342static const struct rockchip_saradc_data rk3588_saradc_data = {
343 .num_bits = 12,
344 .num_channels = 8,
345 .clk_rate = 1000000,
346 .channel_data = rockchip_saradc_channel_data_v2,
347 .start_channel = rockchip_saradc_start_channel_v2,
348};
349
David Wuf8d5bc72017-09-20 14:28:16 +0800350static const struct udevice_id rockchip_saradc_ids[] = {
351 { .compatible = "rockchip,saradc",
352 .data = (ulong)&saradc_data },
353 { .compatible = "rockchip,rk3066-tsadc",
354 .data = (ulong)&rk3066_tsadc_data },
355 { .compatible = "rockchip,rk3399-saradc",
356 .data = (ulong)&rk3399_saradc_data },
Quentin Schulz5df8ac42024-03-14 10:36:24 +0100357 { .compatible = "rockchip,rk3588-saradc",
358 .data = (ulong)&rk3588_saradc_data },
David Wuf8d5bc72017-09-20 14:28:16 +0800359 { }
360};
361
362U_BOOT_DRIVER(rockchip_saradc) = {
363 .name = "rockchip_saradc",
364 .id = UCLASS_ADC,
365 .of_match = rockchip_saradc_ids,
366 .ops = &rockchip_saradc_ops,
367 .probe = rockchip_saradc_probe,
Simon Glassaad29ae2020-12-03 16:55:21 -0700368 .of_to_plat = rockchip_saradc_of_to_plat,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700369 .priv_auto = sizeof(struct rockchip_saradc_priv),
David Wuf8d5bc72017-09-20 14:28:16 +0800370};