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