]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
ae3ed042 DW |
2 | /* |
3 | * (C) Copyright 2017, Fuzhou Rockchip Electronics Co., Ltd | |
4 | * | |
ae3ed042 DW |
5 | * 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> | |
14 | ||
15 | #define SARADC_CTRL_CHN_MASK GENMASK(2, 0) | |
16 | #define SARADC_CTRL_POWER_CTRL BIT(3) | |
17 | #define SARADC_CTRL_IRQ_ENABLE BIT(5) | |
18 | #define SARADC_CTRL_IRQ_STATUS BIT(6) | |
19 | ||
20 | #define SARADC_TIMEOUT (100 * 1000) | |
21 | ||
22 | struct rockchip_saradc_regs { | |
23 | unsigned int data; | |
24 | unsigned int stas; | |
25 | unsigned int ctrl; | |
26 | unsigned int dly_pu_soc; | |
27 | }; | |
28 | ||
29 | struct rockchip_saradc_data { | |
30 | int num_bits; | |
31 | int num_channels; | |
32 | unsigned long clk_rate; | |
33 | }; | |
34 | ||
35 | struct rockchip_saradc_priv { | |
36 | struct rockchip_saradc_regs *regs; | |
37 | int active_channel; | |
38 | const struct rockchip_saradc_data *data; | |
39 | }; | |
40 | ||
41 | int rockchip_saradc_channel_data(struct udevice *dev, int channel, | |
42 | unsigned int *data) | |
43 | { | |
44 | struct rockchip_saradc_priv *priv = dev_get_priv(dev); | |
45 | struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); | |
46 | ||
47 | if (channel != priv->active_channel) { | |
9b643e31 | 48 | pr_err("Requested channel is not active!"); |
ae3ed042 DW |
49 | return -EINVAL; |
50 | } | |
51 | ||
52 | if ((readl(&priv->regs->ctrl) & SARADC_CTRL_IRQ_STATUS) != | |
53 | SARADC_CTRL_IRQ_STATUS) | |
54 | return -EBUSY; | |
55 | ||
56 | /* Read value */ | |
57 | *data = readl(&priv->regs->data); | |
58 | *data &= uc_pdata->data_mask; | |
59 | ||
60 | /* Power down adc */ | |
61 | writel(0, &priv->regs->ctrl); | |
62 | ||
63 | return 0; | |
64 | } | |
65 | ||
66 | int rockchip_saradc_start_channel(struct udevice *dev, int channel) | |
67 | { | |
68 | struct rockchip_saradc_priv *priv = dev_get_priv(dev); | |
69 | ||
70 | if (channel < 0 || channel >= priv->data->num_channels) { | |
9b643e31 | 71 | pr_err("Requested channel is invalid!"); |
ae3ed042 DW |
72 | return -EINVAL; |
73 | } | |
74 | ||
75 | /* 8 clock periods as delay between power up and start cmd */ | |
76 | writel(8, &priv->regs->dly_pu_soc); | |
77 | ||
78 | /* Select the channel to be used and trigger conversion */ | |
79 | writel(SARADC_CTRL_POWER_CTRL | (channel & SARADC_CTRL_CHN_MASK) | | |
80 | SARADC_CTRL_IRQ_ENABLE, &priv->regs->ctrl); | |
81 | ||
82 | priv->active_channel = channel; | |
83 | ||
84 | return 0; | |
85 | } | |
86 | ||
87 | int rockchip_saradc_stop(struct udevice *dev) | |
88 | { | |
89 | struct rockchip_saradc_priv *priv = dev_get_priv(dev); | |
90 | ||
91 | /* Power down adc */ | |
92 | writel(0, &priv->regs->ctrl); | |
93 | ||
94 | priv->active_channel = -1; | |
95 | ||
96 | return 0; | |
97 | } | |
98 | ||
99 | int rockchip_saradc_probe(struct udevice *dev) | |
100 | { | |
101 | struct rockchip_saradc_priv *priv = dev_get_priv(dev); | |
102 | struct clk clk; | |
103 | int ret; | |
104 | ||
105 | ret = clk_get_by_index(dev, 0, &clk); | |
106 | if (ret) | |
107 | return ret; | |
108 | ||
109 | ret = clk_set_rate(&clk, priv->data->clk_rate); | |
110 | if (IS_ERR_VALUE(ret)) | |
111 | return ret; | |
112 | ||
113 | priv->active_channel = -1; | |
114 | ||
115 | return 0; | |
116 | } | |
117 | ||
118 | int rockchip_saradc_ofdata_to_platdata(struct udevice *dev) | |
119 | { | |
120 | struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); | |
121 | struct rockchip_saradc_priv *priv = dev_get_priv(dev); | |
122 | struct rockchip_saradc_data *data; | |
123 | ||
124 | data = (struct rockchip_saradc_data *)dev_get_driver_data(dev); | |
125 | priv->regs = (struct rockchip_saradc_regs *)dev_read_addr(dev); | |
126 | if (priv->regs == (struct rockchip_saradc_regs *)FDT_ADDR_T_NONE) { | |
9b643e31 | 127 | pr_err("Dev: %s - can't get address!", dev->name); |
ae3ed042 DW |
128 | return -ENODATA; |
129 | } | |
130 | ||
131 | priv->data = data; | |
132 | uc_pdata->data_mask = (1 << priv->data->num_bits) - 1;; | |
133 | uc_pdata->data_format = ADC_DATA_FORMAT_BIN; | |
134 | uc_pdata->data_timeout_us = SARADC_TIMEOUT / 5; | |
135 | uc_pdata->channel_mask = (1 << priv->data->num_channels) - 1; | |
136 | ||
137 | return 0; | |
138 | } | |
139 | ||
140 | static const struct adc_ops rockchip_saradc_ops = { | |
141 | .start_channel = rockchip_saradc_start_channel, | |
142 | .channel_data = rockchip_saradc_channel_data, | |
143 | .stop = rockchip_saradc_stop, | |
144 | }; | |
145 | ||
146 | static const struct rockchip_saradc_data saradc_data = { | |
147 | .num_bits = 10, | |
148 | .num_channels = 3, | |
149 | .clk_rate = 1000000, | |
150 | }; | |
151 | ||
152 | static const struct rockchip_saradc_data rk3066_tsadc_data = { | |
153 | .num_bits = 12, | |
154 | .num_channels = 2, | |
155 | .clk_rate = 50000, | |
156 | }; | |
157 | ||
158 | static const struct rockchip_saradc_data rk3399_saradc_data = { | |
159 | .num_bits = 10, | |
160 | .num_channels = 6, | |
161 | .clk_rate = 1000000, | |
162 | }; | |
163 | ||
164 | static const struct udevice_id rockchip_saradc_ids[] = { | |
165 | { .compatible = "rockchip,saradc", | |
166 | .data = (ulong)&saradc_data }, | |
167 | { .compatible = "rockchip,rk3066-tsadc", | |
168 | .data = (ulong)&rk3066_tsadc_data }, | |
169 | { .compatible = "rockchip,rk3399-saradc", | |
170 | .data = (ulong)&rk3399_saradc_data }, | |
171 | { } | |
172 | }; | |
173 | ||
174 | U_BOOT_DRIVER(rockchip_saradc) = { | |
175 | .name = "rockchip_saradc", | |
176 | .id = UCLASS_ADC, | |
177 | .of_match = rockchip_saradc_ids, | |
178 | .ops = &rockchip_saradc_ops, | |
179 | .probe = rockchip_saradc_probe, | |
180 | .ofdata_to_platdata = rockchip_saradc_ofdata_to_platdata, | |
181 | .priv_auto_alloc_size = sizeof(struct rockchip_saradc_priv), | |
182 | }; |