blob: b5df58fe3ebe2172012e50b446b69ca85d48c1de [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
David Wuae3ed042017-09-20 14:28:16 +08002/*
3 * (C) Copyright 2017, Fuzhou Rockchip Electronics Co., Ltd
4 *
David Wuae3ed042017-09-20 14:28:16 +08005 * Rockchip SARADC driver for U-Boot
6 */
7
8#include <common.h>
9#include <adc.h>
10#include <clk.h>
11#include <dm.h>
12#include <errno.h>
13#include <asm/io.h>
Simon Glasscd93d622020-05-10 11:40:13 -060014#include <linux/bitops.h>
Simon Glass61b29b82020-02-03 07:36:15 -070015#include <linux/err.h>
Simon Glass1e94b462023-09-14 18:21:46 -060016#include <linux/printk.h>
Peter Caie9632282022-02-04 15:16:06 -050017#include <power/regulator.h>
David Wuae3ed042017-09-20 14:28:16 +080018
19#define SARADC_CTRL_CHN_MASK GENMASK(2, 0)
20#define SARADC_CTRL_POWER_CTRL BIT(3)
21#define SARADC_CTRL_IRQ_ENABLE BIT(5)
22#define SARADC_CTRL_IRQ_STATUS BIT(6)
23
24#define SARADC_TIMEOUT (100 * 1000)
25
Quentin Schulz0707bfd2024-03-14 10:36:20 +010026struct rockchip_saradc_regs_v1 {
David Wuae3ed042017-09-20 14:28:16 +080027 unsigned int data;
28 unsigned int stas;
29 unsigned int ctrl;
30 unsigned int dly_pu_soc;
31};
32
Quentin Schulz0707bfd2024-03-14 10:36:20 +010033union rockchip_saradc_regs {
34 struct rockchip_saradc_regs_v1 *v1;
35};
David Wuae3ed042017-09-20 14:28:16 +080036struct rockchip_saradc_data {
37 int num_bits;
38 int num_channels;
39 unsigned long clk_rate;
Quentin Schulz7da30652024-03-14 10:36:21 +010040 int (*channel_data)(struct udevice *dev, int channel, unsigned int *data);
Quentin Schulz25775252024-03-14 10:36:22 +010041 int (*start_channel)(struct udevice *dev, int channel);
Quentin Schulzd63c57e2024-03-14 10:36:23 +010042 int (*stop)(struct udevice *dev);
David Wuae3ed042017-09-20 14:28:16 +080043};
44
45struct rockchip_saradc_priv {
Quentin Schulz0707bfd2024-03-14 10:36:20 +010046 union rockchip_saradc_regs regs;
David Wuae3ed042017-09-20 14:28:16 +080047 int active_channel;
48 const struct rockchip_saradc_data *data;
49};
50
Quentin Schulz7da30652024-03-14 10:36:21 +010051int rockchip_saradc_channel_data_v1(struct udevice *dev, int channel,
52 unsigned int *data)
David Wuae3ed042017-09-20 14:28:16 +080053{
54 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
David Wuae3ed042017-09-20 14:28:16 +080055
Quentin Schulz0707bfd2024-03-14 10:36:20 +010056 if ((readl(&priv->regs.v1->ctrl) & SARADC_CTRL_IRQ_STATUS) !=
David Wuae3ed042017-09-20 14:28:16 +080057 SARADC_CTRL_IRQ_STATUS)
58 return -EBUSY;
59
60 /* Read value */
Quentin Schulz0707bfd2024-03-14 10:36:20 +010061 *data = readl(&priv->regs.v1->data);
David Wuae3ed042017-09-20 14:28:16 +080062
63 /* Power down adc */
Quentin Schulz0707bfd2024-03-14 10:36:20 +010064 writel(0, &priv->regs.v1->ctrl);
David Wuae3ed042017-09-20 14:28:16 +080065
66 return 0;
67}
68
Quentin Schulz7da30652024-03-14 10:36:21 +010069int rockchip_saradc_channel_data(struct udevice *dev, int channel,
70 unsigned int *data)
71{
72 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
73 struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
74 int ret;
75
76 if (channel != priv->active_channel) {
77 pr_err("Requested channel is not active!");
78 return -EINVAL;
79 }
80
81 ret = priv->data->channel_data(dev, channel, data);
82 if (ret) {
83 if (ret != -EBUSY)
84 pr_err("Error reading channel data, %d!", ret);
85 return ret;
86 }
87
88 *data &= uc_pdata->data_mask;
89
90 return 0;
91}
92
Quentin Schulz25775252024-03-14 10:36:22 +010093int rockchip_saradc_start_channel_v1(struct udevice *dev, int channel)
David Wuae3ed042017-09-20 14:28:16 +080094{
95 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
96
David Wuae3ed042017-09-20 14:28:16 +080097 /* 8 clock periods as delay between power up and start cmd */
Quentin Schulz0707bfd2024-03-14 10:36:20 +010098 writel(8, &priv->regs.v1->dly_pu_soc);
David Wuae3ed042017-09-20 14:28:16 +080099
100 /* Select the channel to be used and trigger conversion */
101 writel(SARADC_CTRL_POWER_CTRL | (channel & SARADC_CTRL_CHN_MASK) |
Quentin Schulz0707bfd2024-03-14 10:36:20 +0100102 SARADC_CTRL_IRQ_ENABLE, &priv->regs.v1->ctrl);
David Wuae3ed042017-09-20 14:28:16 +0800103
Quentin Schulz25775252024-03-14 10:36:22 +0100104 return 0;
105}
106
107int rockchip_saradc_start_channel(struct udevice *dev, int channel)
108{
109 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
110 int ret;
111
112 if (channel < 0 || channel >= priv->data->num_channels) {
113 pr_err("Requested channel is invalid!");
114 return -EINVAL;
115 }
116
117 ret = priv->data->start_channel(dev, channel);
118 if (ret) {
119 pr_err("Error starting channel, %d!", ret);
120 return ret;
121 }
122
David Wuae3ed042017-09-20 14:28:16 +0800123 priv->active_channel = channel;
124
125 return 0;
126}
127
Quentin Schulzd63c57e2024-03-14 10:36:23 +0100128int rockchip_saradc_stop_v1(struct udevice *dev)
David Wuae3ed042017-09-20 14:28:16 +0800129{
130 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
131
132 /* Power down adc */
Quentin Schulz0707bfd2024-03-14 10:36:20 +0100133 writel(0, &priv->regs.v1->ctrl);
David Wuae3ed042017-09-20 14:28:16 +0800134
Quentin Schulzd63c57e2024-03-14 10:36:23 +0100135 return 0;
136}
137
138int rockchip_saradc_stop(struct udevice *dev)
139{
140 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
141
142 if (priv->data->stop) {
143 int ret = priv->data->stop(dev);
144
145 if (ret) {
146 pr_err("Error stopping channel, %d!", ret);
147 return ret;
148 }
149 }
150
David Wuae3ed042017-09-20 14:28:16 +0800151 priv->active_channel = -1;
152
153 return 0;
154}
155
156int rockchip_saradc_probe(struct udevice *dev)
157{
Peter Caie9632282022-02-04 15:16:06 -0500158 struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
David Wuae3ed042017-09-20 14:28:16 +0800159 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
Peter Caie9632282022-02-04 15:16:06 -0500160 struct udevice *vref;
David Wuae3ed042017-09-20 14:28:16 +0800161 struct clk clk;
Peter Caie9632282022-02-04 15:16:06 -0500162 int vref_uv;
David Wuae3ed042017-09-20 14:28:16 +0800163 int ret;
164
165 ret = clk_get_by_index(dev, 0, &clk);
166 if (ret)
167 return ret;
168
169 ret = clk_set_rate(&clk, priv->data->clk_rate);
170 if (IS_ERR_VALUE(ret))
171 return ret;
172
173 priv->active_channel = -1;
174
Peter Caie9632282022-02-04 15:16:06 -0500175 ret = device_get_supply_regulator(dev, "vref-supply", &vref);
176 if (ret) {
177 printf("can't get vref-supply: %d\n", ret);
178 return ret;
179 }
180
181 vref_uv = regulator_get_value(vref);
182 if (vref_uv < 0) {
183 printf("can't get vref-supply value: %d\n", vref_uv);
184 return vref_uv;
185 }
186
187 /* VDD supplied by common vref pin */
188 uc_pdata->vdd_supply = vref;
189 uc_pdata->vdd_microvolts = vref_uv;
190 uc_pdata->vss_microvolts = 0;
191
David Wuae3ed042017-09-20 14:28:16 +0800192 return 0;
193}
194
Simon Glassd1998a92020-12-03 16:55:21 -0700195int rockchip_saradc_of_to_plat(struct udevice *dev)
David Wuae3ed042017-09-20 14:28:16 +0800196{
Simon Glasscaa4daa2020-12-03 16:55:18 -0700197 struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
David Wuae3ed042017-09-20 14:28:16 +0800198 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
199 struct rockchip_saradc_data *data;
200
201 data = (struct rockchip_saradc_data *)dev_get_driver_data(dev);
Quentin Schulz0707bfd2024-03-14 10:36:20 +0100202 priv->regs.v1 = dev_read_addr_ptr(dev);
203 if (!priv->regs.v1) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900204 pr_err("Dev: %s - can't get address!", dev->name);
Johan Jonkerac9198d2023-03-13 01:29:35 +0100205 return -EINVAL;
David Wuae3ed042017-09-20 14:28:16 +0800206 }
207
208 priv->data = data;
Giulio Benetti9acae542022-03-14 10:09:43 +0100209 uc_pdata->data_mask = (1 << priv->data->num_bits) - 1;
David Wuae3ed042017-09-20 14:28:16 +0800210 uc_pdata->data_format = ADC_DATA_FORMAT_BIN;
211 uc_pdata->data_timeout_us = SARADC_TIMEOUT / 5;
212 uc_pdata->channel_mask = (1 << priv->data->num_channels) - 1;
213
214 return 0;
215}
216
217static const struct adc_ops rockchip_saradc_ops = {
218 .start_channel = rockchip_saradc_start_channel,
219 .channel_data = rockchip_saradc_channel_data,
220 .stop = rockchip_saradc_stop,
221};
222
223static const struct rockchip_saradc_data saradc_data = {
224 .num_bits = 10,
225 .num_channels = 3,
226 .clk_rate = 1000000,
Quentin Schulz7da30652024-03-14 10:36:21 +0100227 .channel_data = rockchip_saradc_channel_data_v1,
Quentin Schulz25775252024-03-14 10:36:22 +0100228 .start_channel = rockchip_saradc_start_channel_v1,
Quentin Schulzd63c57e2024-03-14 10:36:23 +0100229 .stop = rockchip_saradc_stop_v1,
David Wuae3ed042017-09-20 14:28:16 +0800230};
231
232static const struct rockchip_saradc_data rk3066_tsadc_data = {
233 .num_bits = 12,
234 .num_channels = 2,
235 .clk_rate = 50000,
Quentin Schulz7da30652024-03-14 10:36:21 +0100236 .channel_data = rockchip_saradc_channel_data_v1,
Quentin Schulz25775252024-03-14 10:36:22 +0100237 .start_channel = rockchip_saradc_start_channel_v1,
Quentin Schulzd63c57e2024-03-14 10:36:23 +0100238 .stop = rockchip_saradc_stop_v1,
David Wuae3ed042017-09-20 14:28:16 +0800239};
240
241static const struct rockchip_saradc_data rk3399_saradc_data = {
242 .num_bits = 10,
243 .num_channels = 6,
244 .clk_rate = 1000000,
Quentin Schulz7da30652024-03-14 10:36:21 +0100245 .channel_data = rockchip_saradc_channel_data_v1,
Quentin Schulz25775252024-03-14 10:36:22 +0100246 .start_channel = rockchip_saradc_start_channel_v1,
Quentin Schulzd63c57e2024-03-14 10:36:23 +0100247 .stop = rockchip_saradc_stop_v1,
David Wuae3ed042017-09-20 14:28:16 +0800248};
249
250static const struct udevice_id rockchip_saradc_ids[] = {
251 { .compatible = "rockchip,saradc",
252 .data = (ulong)&saradc_data },
253 { .compatible = "rockchip,rk3066-tsadc",
254 .data = (ulong)&rk3066_tsadc_data },
255 { .compatible = "rockchip,rk3399-saradc",
256 .data = (ulong)&rk3399_saradc_data },
257 { }
258};
259
260U_BOOT_DRIVER(rockchip_saradc) = {
261 .name = "rockchip_saradc",
262 .id = UCLASS_ADC,
263 .of_match = rockchip_saradc_ids,
264 .ops = &rockchip_saradc_ops,
265 .probe = rockchip_saradc_probe,
Simon Glassd1998a92020-12-03 16:55:21 -0700266 .of_to_plat = rockchip_saradc_of_to_plat,
Simon Glass41575d82020-12-03 16:55:17 -0700267 .priv_auto = sizeof(struct rockchip_saradc_priv),
David Wuae3ed042017-09-20 14:28:16 +0800268};