blob: 4a842556a60cdf1fca9a9aa38a113565531077a0 [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;
40};
41
42struct rockchip_saradc_priv {
Quentin Schulz0707bfd2024-03-14 10:36:20 +010043 union rockchip_saradc_regs regs;
David Wuae3ed042017-09-20 14:28:16 +080044 int active_channel;
45 const struct rockchip_saradc_data *data;
46};
47
48int rockchip_saradc_channel_data(struct udevice *dev, int channel,
49 unsigned int *data)
50{
51 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
Simon Glasscaa4daa2020-12-03 16:55:18 -070052 struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
David Wuae3ed042017-09-20 14:28:16 +080053
54 if (channel != priv->active_channel) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +090055 pr_err("Requested channel is not active!");
David Wuae3ed042017-09-20 14:28:16 +080056 return -EINVAL;
57 }
58
Quentin Schulz0707bfd2024-03-14 10:36:20 +010059 if ((readl(&priv->regs.v1->ctrl) & SARADC_CTRL_IRQ_STATUS) !=
David Wuae3ed042017-09-20 14:28:16 +080060 SARADC_CTRL_IRQ_STATUS)
61 return -EBUSY;
62
63 /* Read value */
Quentin Schulz0707bfd2024-03-14 10:36:20 +010064 *data = readl(&priv->regs.v1->data);
David Wuae3ed042017-09-20 14:28:16 +080065 *data &= uc_pdata->data_mask;
66
67 /* Power down adc */
Quentin Schulz0707bfd2024-03-14 10:36:20 +010068 writel(0, &priv->regs.v1->ctrl);
David Wuae3ed042017-09-20 14:28:16 +080069
70 return 0;
71}
72
73int rockchip_saradc_start_channel(struct udevice *dev, int channel)
74{
75 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
76
77 if (channel < 0 || channel >= priv->data->num_channels) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +090078 pr_err("Requested channel is invalid!");
David Wuae3ed042017-09-20 14:28:16 +080079 return -EINVAL;
80 }
81
82 /* 8 clock periods as delay between power up and start cmd */
Quentin Schulz0707bfd2024-03-14 10:36:20 +010083 writel(8, &priv->regs.v1->dly_pu_soc);
David Wuae3ed042017-09-20 14:28:16 +080084
85 /* Select the channel to be used and trigger conversion */
86 writel(SARADC_CTRL_POWER_CTRL | (channel & SARADC_CTRL_CHN_MASK) |
Quentin Schulz0707bfd2024-03-14 10:36:20 +010087 SARADC_CTRL_IRQ_ENABLE, &priv->regs.v1->ctrl);
David Wuae3ed042017-09-20 14:28:16 +080088
89 priv->active_channel = channel;
90
91 return 0;
92}
93
94int rockchip_saradc_stop(struct udevice *dev)
95{
96 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
97
98 /* Power down adc */
Quentin Schulz0707bfd2024-03-14 10:36:20 +010099 writel(0, &priv->regs.v1->ctrl);
David Wuae3ed042017-09-20 14:28:16 +0800100
101 priv->active_channel = -1;
102
103 return 0;
104}
105
106int rockchip_saradc_probe(struct udevice *dev)
107{
Peter Caie9632282022-02-04 15:16:06 -0500108 struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
David Wuae3ed042017-09-20 14:28:16 +0800109 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
Peter Caie9632282022-02-04 15:16:06 -0500110 struct udevice *vref;
David Wuae3ed042017-09-20 14:28:16 +0800111 struct clk clk;
Peter Caie9632282022-02-04 15:16:06 -0500112 int vref_uv;
David Wuae3ed042017-09-20 14:28:16 +0800113 int ret;
114
115 ret = clk_get_by_index(dev, 0, &clk);
116 if (ret)
117 return ret;
118
119 ret = clk_set_rate(&clk, priv->data->clk_rate);
120 if (IS_ERR_VALUE(ret))
121 return ret;
122
123 priv->active_channel = -1;
124
Peter Caie9632282022-02-04 15:16:06 -0500125 ret = device_get_supply_regulator(dev, "vref-supply", &vref);
126 if (ret) {
127 printf("can't get vref-supply: %d\n", ret);
128 return ret;
129 }
130
131 vref_uv = regulator_get_value(vref);
132 if (vref_uv < 0) {
133 printf("can't get vref-supply value: %d\n", vref_uv);
134 return vref_uv;
135 }
136
137 /* VDD supplied by common vref pin */
138 uc_pdata->vdd_supply = vref;
139 uc_pdata->vdd_microvolts = vref_uv;
140 uc_pdata->vss_microvolts = 0;
141
David Wuae3ed042017-09-20 14:28:16 +0800142 return 0;
143}
144
Simon Glassd1998a92020-12-03 16:55:21 -0700145int rockchip_saradc_of_to_plat(struct udevice *dev)
David Wuae3ed042017-09-20 14:28:16 +0800146{
Simon Glasscaa4daa2020-12-03 16:55:18 -0700147 struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
David Wuae3ed042017-09-20 14:28:16 +0800148 struct rockchip_saradc_priv *priv = dev_get_priv(dev);
149 struct rockchip_saradc_data *data;
150
151 data = (struct rockchip_saradc_data *)dev_get_driver_data(dev);
Quentin Schulz0707bfd2024-03-14 10:36:20 +0100152 priv->regs.v1 = dev_read_addr_ptr(dev);
153 if (!priv->regs.v1) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900154 pr_err("Dev: %s - can't get address!", dev->name);
Johan Jonkerac9198d2023-03-13 01:29:35 +0100155 return -EINVAL;
David Wuae3ed042017-09-20 14:28:16 +0800156 }
157
158 priv->data = data;
Giulio Benetti9acae542022-03-14 10:09:43 +0100159 uc_pdata->data_mask = (1 << priv->data->num_bits) - 1;
David Wuae3ed042017-09-20 14:28:16 +0800160 uc_pdata->data_format = ADC_DATA_FORMAT_BIN;
161 uc_pdata->data_timeout_us = SARADC_TIMEOUT / 5;
162 uc_pdata->channel_mask = (1 << priv->data->num_channels) - 1;
163
164 return 0;
165}
166
167static const struct adc_ops rockchip_saradc_ops = {
168 .start_channel = rockchip_saradc_start_channel,
169 .channel_data = rockchip_saradc_channel_data,
170 .stop = rockchip_saradc_stop,
171};
172
173static const struct rockchip_saradc_data saradc_data = {
174 .num_bits = 10,
175 .num_channels = 3,
176 .clk_rate = 1000000,
177};
178
179static const struct rockchip_saradc_data rk3066_tsadc_data = {
180 .num_bits = 12,
181 .num_channels = 2,
182 .clk_rate = 50000,
183};
184
185static const struct rockchip_saradc_data rk3399_saradc_data = {
186 .num_bits = 10,
187 .num_channels = 6,
188 .clk_rate = 1000000,
189};
190
191static const struct udevice_id rockchip_saradc_ids[] = {
192 { .compatible = "rockchip,saradc",
193 .data = (ulong)&saradc_data },
194 { .compatible = "rockchip,rk3066-tsadc",
195 .data = (ulong)&rk3066_tsadc_data },
196 { .compatible = "rockchip,rk3399-saradc",
197 .data = (ulong)&rk3399_saradc_data },
198 { }
199};
200
201U_BOOT_DRIVER(rockchip_saradc) = {
202 .name = "rockchip_saradc",
203 .id = UCLASS_ADC,
204 .of_match = rockchip_saradc_ids,
205 .ops = &rockchip_saradc_ops,
206 .probe = rockchip_saradc_probe,
Simon Glassd1998a92020-12-03 16:55:21 -0700207 .of_to_plat = rockchip_saradc_of_to_plat,
Simon Glass41575d82020-12-03 16:55:17 -0700208 .priv_auto = sizeof(struct rockchip_saradc_priv),
David Wuae3ed042017-09-20 14:28:16 +0800209};