Commit ae3ed042ed31d1acbdd56938b45bd6c5076bebe3
Committed by
Philipp Tomsich
1 parent
6ca43a58db
Exists in
smarc_8mq_lf_v2020.04
and in
17 other branches
dm: adc: Add driver for Rockchip SARADC
The ADC can support some channels signal-ended some bits Successive Approximation Register (SAR) A/D Converter, like 6-channel and 10-bit. It converts the analog input signal into some bits binary digital codes. Signed-off-by: David Wu <david.wu@rock-chips.com> Acked-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com> Reviewed-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
Showing 3 changed files with 193 additions and 0 deletions Side-by-side Diff
drivers/adc/Kconfig
... | ... | @@ -28,4 +28,13 @@ |
28 | 28 | - 4 analog input channels |
29 | 29 | - 16-bit resolution |
30 | 30 | - single and multi-channel conversion mode |
31 | + | |
32 | +config SARADC_ROCKCHIP | |
33 | + bool "Enable Rockchip SARADC driver" | |
34 | + help | |
35 | + This enables driver for Rockchip SARADC. | |
36 | + It provides: | |
37 | + - 2~6 analog input channels | |
38 | + - 1O or 12 bits resolution | |
39 | + - Up to 1MSPS of sample rate |
drivers/adc/Makefile
drivers/adc/rockchip-saradc.c
1 | +/* | |
2 | + * (C) Copyright 2017, Fuzhou Rockchip Electronics Co., Ltd | |
3 | + * | |
4 | + * SPDX-License-Identifier: GPL-2.0+ | |
5 | + * | |
6 | + * Rockchip SARADC driver for U-Boot | |
7 | + */ | |
8 | + | |
9 | +#include <common.h> | |
10 | +#include <adc.h> | |
11 | +#include <clk.h> | |
12 | +#include <dm.h> | |
13 | +#include <errno.h> | |
14 | +#include <asm/io.h> | |
15 | + | |
16 | +#define SARADC_CTRL_CHN_MASK GENMASK(2, 0) | |
17 | +#define SARADC_CTRL_POWER_CTRL BIT(3) | |
18 | +#define SARADC_CTRL_IRQ_ENABLE BIT(5) | |
19 | +#define SARADC_CTRL_IRQ_STATUS BIT(6) | |
20 | + | |
21 | +#define SARADC_TIMEOUT (100 * 1000) | |
22 | + | |
23 | +struct rockchip_saradc_regs { | |
24 | + unsigned int data; | |
25 | + unsigned int stas; | |
26 | + unsigned int ctrl; | |
27 | + unsigned int dly_pu_soc; | |
28 | +}; | |
29 | + | |
30 | +struct rockchip_saradc_data { | |
31 | + int num_bits; | |
32 | + int num_channels; | |
33 | + unsigned long clk_rate; | |
34 | +}; | |
35 | + | |
36 | +struct rockchip_saradc_priv { | |
37 | + struct rockchip_saradc_regs *regs; | |
38 | + int active_channel; | |
39 | + const struct rockchip_saradc_data *data; | |
40 | +}; | |
41 | + | |
42 | +int rockchip_saradc_channel_data(struct udevice *dev, int channel, | |
43 | + unsigned int *data) | |
44 | +{ | |
45 | + struct rockchip_saradc_priv *priv = dev_get_priv(dev); | |
46 | + struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); | |
47 | + | |
48 | + if (channel != priv->active_channel) { | |
49 | + error("Requested channel is not active!"); | |
50 | + return -EINVAL; | |
51 | + } | |
52 | + | |
53 | + if ((readl(&priv->regs->ctrl) & SARADC_CTRL_IRQ_STATUS) != | |
54 | + SARADC_CTRL_IRQ_STATUS) | |
55 | + return -EBUSY; | |
56 | + | |
57 | + /* Read value */ | |
58 | + *data = readl(&priv->regs->data); | |
59 | + *data &= uc_pdata->data_mask; | |
60 | + | |
61 | + /* Power down adc */ | |
62 | + writel(0, &priv->regs->ctrl); | |
63 | + | |
64 | + return 0; | |
65 | +} | |
66 | + | |
67 | +int rockchip_saradc_start_channel(struct udevice *dev, int channel) | |
68 | +{ | |
69 | + struct rockchip_saradc_priv *priv = dev_get_priv(dev); | |
70 | + | |
71 | + if (channel < 0 || channel >= priv->data->num_channels) { | |
72 | + error("Requested channel is invalid!"); | |
73 | + return -EINVAL; | |
74 | + } | |
75 | + | |
76 | + /* 8 clock periods as delay between power up and start cmd */ | |
77 | + writel(8, &priv->regs->dly_pu_soc); | |
78 | + | |
79 | + /* Select the channel to be used and trigger conversion */ | |
80 | + writel(SARADC_CTRL_POWER_CTRL | (channel & SARADC_CTRL_CHN_MASK) | | |
81 | + SARADC_CTRL_IRQ_ENABLE, &priv->regs->ctrl); | |
82 | + | |
83 | + priv->active_channel = channel; | |
84 | + | |
85 | + return 0; | |
86 | +} | |
87 | + | |
88 | +int rockchip_saradc_stop(struct udevice *dev) | |
89 | +{ | |
90 | + struct rockchip_saradc_priv *priv = dev_get_priv(dev); | |
91 | + | |
92 | + /* Power down adc */ | |
93 | + writel(0, &priv->regs->ctrl); | |
94 | + | |
95 | + priv->active_channel = -1; | |
96 | + | |
97 | + return 0; | |
98 | +} | |
99 | + | |
100 | +int rockchip_saradc_probe(struct udevice *dev) | |
101 | +{ | |
102 | + struct rockchip_saradc_priv *priv = dev_get_priv(dev); | |
103 | + struct clk clk; | |
104 | + int ret; | |
105 | + | |
106 | + ret = clk_get_by_index(dev, 0, &clk); | |
107 | + if (ret) | |
108 | + return ret; | |
109 | + | |
110 | + ret = clk_set_rate(&clk, priv->data->clk_rate); | |
111 | + if (IS_ERR_VALUE(ret)) | |
112 | + return ret; | |
113 | + | |
114 | + priv->active_channel = -1; | |
115 | + | |
116 | + return 0; | |
117 | +} | |
118 | + | |
119 | +int rockchip_saradc_ofdata_to_platdata(struct udevice *dev) | |
120 | +{ | |
121 | + struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); | |
122 | + struct rockchip_saradc_priv *priv = dev_get_priv(dev); | |
123 | + struct rockchip_saradc_data *data; | |
124 | + | |
125 | + data = (struct rockchip_saradc_data *)dev_get_driver_data(dev); | |
126 | + priv->regs = (struct rockchip_saradc_regs *)dev_read_addr(dev); | |
127 | + if (priv->regs == (struct rockchip_saradc_regs *)FDT_ADDR_T_NONE) { | |
128 | + error("Dev: %s - can't get address!", dev->name); | |
129 | + return -ENODATA; | |
130 | + } | |
131 | + | |
132 | + priv->data = data; | |
133 | + uc_pdata->data_mask = (1 << priv->data->num_bits) - 1;; | |
134 | + uc_pdata->data_format = ADC_DATA_FORMAT_BIN; | |
135 | + uc_pdata->data_timeout_us = SARADC_TIMEOUT / 5; | |
136 | + uc_pdata->channel_mask = (1 << priv->data->num_channels) - 1; | |
137 | + | |
138 | + return 0; | |
139 | +} | |
140 | + | |
141 | +static const struct adc_ops rockchip_saradc_ops = { | |
142 | + .start_channel = rockchip_saradc_start_channel, | |
143 | + .channel_data = rockchip_saradc_channel_data, | |
144 | + .stop = rockchip_saradc_stop, | |
145 | +}; | |
146 | + | |
147 | +static const struct rockchip_saradc_data saradc_data = { | |
148 | + .num_bits = 10, | |
149 | + .num_channels = 3, | |
150 | + .clk_rate = 1000000, | |
151 | +}; | |
152 | + | |
153 | +static const struct rockchip_saradc_data rk3066_tsadc_data = { | |
154 | + .num_bits = 12, | |
155 | + .num_channels = 2, | |
156 | + .clk_rate = 50000, | |
157 | +}; | |
158 | + | |
159 | +static const struct rockchip_saradc_data rk3399_saradc_data = { | |
160 | + .num_bits = 10, | |
161 | + .num_channels = 6, | |
162 | + .clk_rate = 1000000, | |
163 | +}; | |
164 | + | |
165 | +static const struct udevice_id rockchip_saradc_ids[] = { | |
166 | + { .compatible = "rockchip,saradc", | |
167 | + .data = (ulong)&saradc_data }, | |
168 | + { .compatible = "rockchip,rk3066-tsadc", | |
169 | + .data = (ulong)&rk3066_tsadc_data }, | |
170 | + { .compatible = "rockchip,rk3399-saradc", | |
171 | + .data = (ulong)&rk3399_saradc_data }, | |
172 | + { } | |
173 | +}; | |
174 | + | |
175 | +U_BOOT_DRIVER(rockchip_saradc) = { | |
176 | + .name = "rockchip_saradc", | |
177 | + .id = UCLASS_ADC, | |
178 | + .of_match = rockchip_saradc_ids, | |
179 | + .ops = &rockchip_saradc_ops, | |
180 | + .probe = rockchip_saradc_probe, | |
181 | + .ofdata_to_platdata = rockchip_saradc_ofdata_to_platdata, | |
182 | + .priv_auto_alloc_size = sizeof(struct rockchip_saradc_priv), | |
183 | +}; |