1 /*
2 * Copyright (c) 2006-2024, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2024/02/22 flyingcys first version
9 */
10 #include <rtthread.h>
11 #include <rtdevice.h>
12 #include "drv_adc.h"
13 #include "drv_pinmux.h"
14 #include "drv_ioremap.h"
15
16 #define DBG_LEVEL DBG_LOG
17 #include <rtdbg.h>
18 #define LOG_TAG "DRV.ADC"
19
cvi_set_saradc_ctrl(unsigned long reg_base,rt_uint32_t value)20 rt_inline void cvi_set_saradc_ctrl(unsigned long reg_base, rt_uint32_t value)
21 {
22 value |= mmio_read_32(reg_base + SARADC_CTRL_OFFSET);
23 mmio_write_32(reg_base + SARADC_CTRL_OFFSET, value);
24 }
25
cvi_reset_saradc_ctrl(unsigned long reg_base,rt_uint32_t value)26 rt_inline void cvi_reset_saradc_ctrl(unsigned long reg_base, rt_uint32_t value)
27 {
28 value = mmio_read_32(reg_base + SARADC_CTRL_OFFSET) & ~value;
29 mmio_write_32(reg_base + SARADC_CTRL_OFFSET, value);
30 }
31
cvi_get_saradc_status(unsigned long reg_base)32 rt_inline rt_uint32_t cvi_get_saradc_status(unsigned long reg_base)
33 {
34 return((rt_uint32_t)mmio_read_32(reg_base + SARADC_STATUS_OFFSET));
35 }
36
cvi_set_cyc(unsigned long reg_base)37 rt_inline void cvi_set_cyc(unsigned long reg_base)
38 {
39 rt_uint32_t value;
40
41 value = mmio_read_32(reg_base + SARADC_CYC_SET_OFFSET);
42
43 value &= ~SARADC_CYC_CLKDIV_DIV_16;
44 mmio_write_32(reg_base + SARADC_CYC_SET_OFFSET, value);
45
46 value |= SARADC_CYC_CLKDIV_DIV_16; //set saradc clock cycle=840ns
47 mmio_write_32(reg_base + SARADC_CYC_SET_OFFSET, value);
48 }
49
cvi_do_calibration(unsigned long reg_base)50 rt_inline void cvi_do_calibration(unsigned long reg_base)
51 {
52 rt_uint32_t val;
53
54 val = mmio_read_32(reg_base + SARADC_TEST_OFFSET);
55 val |= 1 << SARADC_TEST_VREFSEL_BIT;
56 mmio_write_32(reg_base + SARADC_TEST_OFFSET, val);
57
58 val = mmio_read_32(reg_base + SARADC_TRIM_OFFSET);
59 val |= 0x4;
60 mmio_write_32(reg_base + SARADC_TRIM_OFFSET, val);
61 }
62
63 struct cvi_adc_dev
64 {
65 struct rt_adc_device device;
66 const char *name;
67 rt_ubase_t base;
68 };
69
70 static struct cvi_adc_dev adc_dev_config[] =
71 {
72 #ifdef BSP_USING_ADC_ACTIVE
73 {
74 .name = "adc1",
75 .base = SARADC_BASE
76 },
77 #endif /* BSP_USING_ADC_ACTIVE */
78 #ifdef BSP_USING_ADC_NODIE
79 {
80 .name = "adc2",
81 .base = RTC_ADC_BASE
82 },
83 #endif /* BSP_USING_ADC_NODIE */
84 };
85
_adc_enabled(struct rt_adc_device * device,rt_int8_t channel,rt_bool_t enabled)86 static rt_err_t _adc_enabled(struct rt_adc_device *device, rt_int8_t channel, rt_bool_t enabled)
87 {
88 struct cvi_adc_dev *adc_dev = (struct cvi_adc_dev *)device->parent.user_data;
89 uint32_t value;
90
91 RT_ASSERT(adc_dev != RT_NULL);
92
93 if (channel > SARADC_CH_MAX)
94 return -RT_EINVAL;
95
96 if (enabled)
97 {
98 //set channel
99 cvi_set_saradc_ctrl(adc_dev->base, (rt_uint32_t)channel << (SARADC_CTRL_SEL_POS + 1));
100
101 //set saradc clock cycle
102 cvi_set_cyc(adc_dev->base);
103
104 //start
105 cvi_set_saradc_ctrl(adc_dev->base, SARADC_CTRL_START);
106 LOG_D("enable saradc...");
107 }
108 else
109 {
110 cvi_reset_saradc_ctrl(adc_dev->base, (rt_uint32_t)channel << (SARADC_CTRL_SEL_POS + 1));
111 LOG_D("disable saradc...");
112 }
113 return RT_EOK;
114 }
115
_adc_convert(struct rt_adc_device * device,rt_int8_t channel,rt_uint32_t * value)116 static rt_err_t _adc_convert(struct rt_adc_device *device, rt_int8_t channel, rt_uint32_t *value)
117 {
118 struct cvi_adc_dev *adc_dev = (struct cvi_adc_dev *)device->parent.user_data;
119 rt_uint32_t result;
120 rt_uint32_t cnt = 0;
121
122 RT_ASSERT(adc_dev != RT_NULL);
123
124 if (channel > SARADC_CH_MAX)
125 return -RT_EINVAL;
126
127 while (cvi_get_saradc_status(adc_dev->base) & SARADC_STATUS_BUSY)
128 {
129 rt_thread_delay(10);
130 LOG_D("wait saradc ready");
131 cnt ++;
132 if (cnt > 100)
133 return -RT_ETIMEOUT;
134 }
135
136 result = mmio_read_32(adc_dev->base + SARADC_RESULT(channel - 1));
137 if (result & SARADC_RESULT_VALID)
138 {
139 *value = result & SARADC_RESULT_MASK;
140 LOG_D("saradc channel %d value: %04x", channel, *value);
141 }
142 else
143 {
144 LOG_E("saradc channel %d read failed. result:0x%04x", channel, result);
145 return -RT_ERROR;
146 }
147 return RT_EOK;
148 }
149
150 static const struct rt_adc_ops _adc_ops =
151 {
152 .enabled = _adc_enabled,
153 .convert = _adc_convert,
154 };
155
156
157 #if defined(BOARD_TYPE_MILKV_DUO)
158
159 /*
160 * cv180xb supports
161 * - adc1 & adc2 for active domain
162 * - adc3 for no-die domain
163 */
164 #ifdef BSP_USING_ADC_ACTIVE
165 static const char *pinname_whitelist_adc1_active[] = {
166 "ADC1",
167 NULL,
168 };
169 static const char *pinname_whitelist_adc2_active[] = {
170 NULL,
171 };
172 static const char *pinname_whitelist_adc3_active[] = {
173 NULL,
174 };
175 #endif
176
177 #ifdef BSP_USING_ADC_NODIE
178 static const char *pinname_whitelist_adc1_nodie[] = {
179 "PWR_GPIO2",
180 NULL,
181 };
182 static const char *pinname_whitelist_adc2_nodie[] = {
183 "PWR_GPIO1",
184 NULL,
185 };
186 static const char *pinname_whitelist_adc3_nodie[] = {
187 "PWR_VBAT_DET",
188 NULL,
189 };
190 #endif
191
192 #elif defined(BOARD_TYPE_MILKV_DUO256M)
193
194 /*
195 * sg2002 supports
196 * - adc1 for active domain
197 * - adc1/adc2/adc3 for no-die domain
198 */
199
200 #ifdef BSP_USING_ADC_ACTIVE
201 static const char *pinname_whitelist_adc1_active[] = {
202 "ADC1",
203 NULL,
204 };
205 static const char *pinname_whitelist_adc2_active[] = {
206 NULL,
207 };
208 static const char *pinname_whitelist_adc3_active[] = {
209 NULL,
210 };
211 #endif
212
213 #ifdef BSP_USING_ADC_NODIE
214 static const char *pinname_whitelist_adc1_nodie[] = {
215 "PWR_GPIO2",
216 NULL,
217 };
218 static const char *pinname_whitelist_adc2_nodie[] = {
219 "PWR_GPIO1",
220 NULL,
221 };
222 static const char *pinname_whitelist_adc3_nodie[] = {
223 "PWR_VBAT_DET",
224 NULL,
225 };
226 #endif
227
228 #else
229 #error "Unsupported board type!"
230 #endif
231
rt_hw_adc_pinmux_config()232 static void rt_hw_adc_pinmux_config()
233 {
234 #ifdef BSP_USING_ADC_ACTIVE
235 pinmux_config(BSP_ACTIVE_ADC1_PINNAME, XGPIOB_3, pinname_whitelist_adc1_active);
236 pinmux_config(BSP_ACTIVE_ADC2_PINNAME, XGPIOB_6, pinname_whitelist_adc2_active);
237 /* cv1800b & sg2002 don't support ADC3 either in active domain */
238 #endif
239
240 #ifdef BSP_USING_ADC_NODIE
241 pinmux_config(BSP_NODIE_ADC1_PINNAME, PWR_GPIO_2, pinname_whitelist_adc1_nodie);
242 pinmux_config(BSP_NODIE_ADC2_PINNAME, PWR_GPIO_1, pinname_whitelist_adc2_nodie);
243 pinmux_config(BSP_NODIE_ADC3_PINNAME, PWR_VBAT_DET, pinname_whitelist_adc3_nodie);
244 #endif
245 }
246
rt_hw_adc_init(void)247 int rt_hw_adc_init(void)
248 {
249 rt_uint8_t i;
250
251 for (i = 0; i < sizeof(adc_dev_config) / sizeof(adc_dev_config[0]); i++)
252 {
253 if (!rt_strcmp(adc_dev_config[i].name, "adc1"))
254 {
255 adc_dev_config[i].base = (rt_ubase_t)DRV_IOREMAP(SARADC_BASE, 0x10000);
256 }
257 else if (!rt_strcmp(adc_dev_config[i].name, "adc2"))
258 {
259 adc_dev_config[i].base = (rt_ubase_t)DRV_IOREMAP(RTC_ADC_BASE, 0x1000);
260 }
261 }
262
263 rt_hw_adc_pinmux_config();
264
265 for (i = 0; i < sizeof(adc_dev_config) / sizeof(adc_dev_config[0]); i++)
266 {
267 cvi_do_calibration(adc_dev_config[i].base);
268
269 if (rt_hw_adc_register(&adc_dev_config[i].device, adc_dev_config[i].name, &_adc_ops, &adc_dev_config[i]) != RT_EOK)
270 {
271 LOG_E("%s register failed!", adc_dev_config[i].name);
272 return -RT_ERROR;
273 }
274 }
275
276 return RT_EOK;
277 }
278 INIT_DEVICE_EXPORT(rt_hw_adc_init);
279