1 /*
2  * Copyright (C) 2015-2020 Alibaba Group Holding Limited
3  */
4 
5 #include <drv/adc.h>
6 #include <aos/adc_csi.h>
7 #include "objects.h"
8 #include "PinNames.h"
9 #include "pinmap.h"
10 
11 static const PinMap CSI_PinMap_ADC[] = {
12     { PB_4, ADC_CH0, 0 },
13     { PB_5, ADC_CH1, 0 },
14     { PB_6, ADC_CH2, 0 },
15     { PB_7, ADC_CH3, 0 },
16     { PB_1, ADC_CH4, 0 },
17     { PB_2, ADC_CH5, 0 },
18     { PB_3, ADC_CH6, 0 },
19     { VBAT_MEAS, ADC_CH7, 0 },
20     { NC, NC, 0 }
21 };
22 
23 static uint16_t rtl872xd_adc_offset;
24 static uint16_t rtl872xd_adc_gain;
25 
csi_adc_init(csi_adc_t * adc,uint32_t idx)26 csi_error_t csi_adc_init(csi_adc_t *adc, uint32_t idx)
27 {
28     if (!adc)
29         return CSI_ERROR;
30 
31     adc->priv = (ADC_InitTypeDef *)malloc(sizeof(ADC_InitTypeDef));
32     ADC_InitTypeDef *ADC_InitStruct = (ADC_InitTypeDef *)adc->priv;
33 
34     adc->dev.idx = idx;
35 
36     /* Initialize ADC */
37     ADC_StructInit(ADC_InitStruct);
38     ADC_Init(ADC_InitStruct);
39     return CSI_OK;
40 }
41 
csi_adc_uninit(csi_adc_t * adc)42 void csi_adc_uninit(csi_adc_t *adc)
43 {
44     /* Clear ADC Status */
45     ADC_INTClear();
46     /* Disable ADC  */
47     ADC_Cmd(DISABLE);
48 
49     if (adc->priv) {
50         free(adc->priv);
51         adc->priv = NULL;
52     }
53 }
54 
csi_adc_start(csi_adc_t * adc)55 csi_error_t csi_adc_start(csi_adc_t *adc)
56 {
57     ADC_Cmd(ENABLE);
58     return CSI_OK;
59 }
60 
csi_adc_stop(csi_adc_t * adc)61 csi_error_t csi_adc_stop(csi_adc_t *adc)
62 {
63     ADC_Cmd(DISABLE);
64     return CSI_OK;
65 }
66 
csi_adc_channel_enable(csi_adc_t * adc,uint8_t ch_id,bool is_enable)67 csi_error_t csi_adc_channel_enable(csi_adc_t *adc, uint8_t ch_id, bool is_enable)
68 {
69     ADC_InitTypeDef *ADC_InitStruct = (ADC_InitTypeDef *)adc->priv;
70     uint32_t adc_idx;
71 
72     if (ch_id != adc->dev.idx)
73         adc->dev.idx = ch_id;
74 
75     adc_idx = CSI_PinMap_ADC[ch_id].peripheral;
76 
77     ADC_InitStruct->ADC_CvlistLen = 0;
78     ADC_InitStruct->ADC_Cvlist[0] = adc_idx;
79     ADC_InitStruct->ADC_ChIDEn = is_enable; /* MSB 4bit is channel index*/
80     ADC_Init(ADC_InitStruct);
81     return CSI_OK;
82 }
83 
csi_adc_sampling_time(csi_adc_t * adc,uint16_t clock_num)84 csi_error_t csi_adc_sampling_time(csi_adc_t *adc, uint16_t clock_num)
85 {
86     /* no need to set sampling time */
87     return CSI_OK;
88 }
89 
csi_adc_channel_sampling_time(csi_adc_t * adc,uint8_t ch_id,uint16_t clock_num)90 csi_error_t csi_adc_channel_sampling_time(csi_adc_t *adc, uint8_t ch_id, uint16_t clock_num)
91 {
92     /* no need to set sampling time */
93     return CSI_OK;
94 }
95 
csi_adc_continue_mode(csi_adc_t * adc,bool is_enable)96 csi_error_t csi_adc_continue_mode(csi_adc_t *adc, bool is_enable)
97 {
98     ADC_InitTypeDef *ADC_InitStruct = (ADC_InitTypeDef *)adc->priv;
99 
100     if (is_enable) {
101         ADC_InitStruct->ADC_OpMode = ADC_AUTO_MODE;
102         ADC_Init(ADC_InitStruct);
103     }
104 
105     return CSI_OK;
106 }
107 
csi_adc_freq_div(csi_adc_t * adc,uint32_t div)108 uint32_t csi_adc_freq_div(csi_adc_t *adc, uint32_t div)
109 {
110     ADC_InitTypeDef *ADC_InitStruct = (ADC_InitTypeDef *)adc->priv;
111     uint32_t freq = 0;
112 
113     switch (div) {
114     case 12:
115         ADC_InitStruct->ADC_ClkDiv = ADC_CLK_DIV_12;
116         freq = (uint32_t)(2000000 / 12);
117         break;
118     case 16:
119         ADC_InitStruct->ADC_ClkDiv = ADC_CLK_DIV_16;
120         freq = (uint32_t)(2000000 / 16);
121         break;
122     case 32:
123         ADC_InitStruct->ADC_ClkDiv = ADC_CLK_DIV_32;
124         freq = (uint32_t)(2000000 / 32);
125         break;
126     case 64:
127         ADC_InitStruct->ADC_ClkDiv = ADC_CLK_DIV_64;
128         freq = (uint32_t)(2000000 / 64);
129         break;
130     default:
131         ADC_InitStruct->ADC_ClkDiv = ADC_CLK_DIV_12;
132         freq = (uint32_t)(2000000 / 12);
133         break;
134     }
135 
136     ADC_Init(ADC_InitStruct);
137     return freq;
138 }
139 
AD2MV(int32_t ad,uint16_t offset,uint16_t gain)140 static int32_t AD2MV(int32_t ad, uint16_t offset, uint16_t gain)
141 {
142     return (int32_t)(((10 * ad) - offset) * 1000 / gain);
143 }
144 
adc_get_offset_gain(uint16_t * offset,uint16_t * gain,uint8_t vbat)145 static void adc_get_offset_gain(uint16_t *offset, uint16_t *gain, uint8_t vbat)
146 {
147     uint8_t EfuseBuf[2];
148     uint32_t index;
149     uint32_t addressOffset;
150     uint32_t addressGain;
151 
152     if (vbat) {
153         addressOffset = 0x1D4;
154         addressGain = 0x1D6;
155     } else {
156         addressOffset = 0x1D0;
157         addressGain = 0x1D2;
158     }
159 
160     for (index = 0; index < 2; index++) {
161         EFUSERead8(0, addressOffset + index, EfuseBuf + index, L25EOUTVOLTAGE);
162     }
163     *offset = EfuseBuf[1] << 8 | EfuseBuf[0];
164 
165     for (index = 0; index < 2; index++) {
166         EFUSERead8(0, addressGain + index, EfuseBuf + index, L25EOUTVOLTAGE);
167     }
168     *gain = EfuseBuf[1] << 8 | EfuseBuf[0];
169 
170     if (*offset == 0xFFFF) {
171         if (vbat)
172             *offset = 0x9C4;
173         else
174             *offset = 0x9B0;
175     }
176 
177     if (*gain == 0xFFFF) {
178         if (vbat)
179             *gain = 7860;
180         else
181             *gain = 0x2F12;
182     }
183 }
184 
csi_adc_get_range(csi_adc_t * adc,uint8_t ch_id,uint32_t * range)185 csi_error_t csi_adc_get_range(csi_adc_t *adc, uint8_t ch_id, uint32_t *range)
186 {
187     if (ch_id < 4) {
188         *range = 3300;  /*CH0~CH3: 3.3V*/
189         return CSI_OK;
190     } else if (ch_id < 7) {
191         *range = 1800;  /*CH4~CH6: 1.8V*/
192         return CSI_OK;
193     } else if (ch_id == 7) {
194         *range = 5000;  /*CH7: 5V*/
195         return CSI_OK;
196     } else {
197         return CSI_ERROR;
198     }
199 }
200 
csi_adc_read(csi_adc_t * adc)201 int32_t csi_adc_read(csi_adc_t *adc)
202 {
203     int32_t value;
204     uint32_t data;
205 
206     /* Clear FIFO */
207     ADC_ClearFIFO();
208 
209     /* SW trigger to sample */
210     ADC_SWTrigCmd(ENABLE);
211     while (ADC_Readable() == 0)
212         ;
213     ADC_SWTrigCmd(DISABLE);
214 
215     data = ADC_Read();
216     value = (int32_t)(data & BIT_MASK_DAT_GLOBAL);
217     return value;
218 }
219 
csi_adc_read_voltage(csi_adc_t * adc)220 int32_t csi_adc_read_voltage(csi_adc_t *adc)
221 {
222     int32_t adc_data;
223 
224     adc_data = csi_adc_read(adc);
225     return AD2MV(adc_data, rtl872xd_adc_offset, rtl872xd_adc_gain);
226 }
227 
adc_csi_init(void)228 static int adc_csi_init(void)
229 {
230     csi_error_t ret;
231     static aos_adc_csi_t adc_csi_dev;
232 
233     adc_get_offset_gain(&rtl872xd_adc_offset, &rtl872xd_adc_gain, 0);
234     if (rtl872xd_adc_gain == 0) {
235         printf("%s:%d: rtl872xd_adc_gain is 0\r\n", __func__, __LINE__);
236         return -1;
237     }
238 
239     ret = csi_adc_init(&(adc_csi_dev.csi_adc), 0);
240     if (ret != CSI_OK) {
241         printf("%s:%d: csi_adc_init fail, ret:%d\r\n", __func__, __LINE__, ret);
242         return -1;
243     }
244 
245     adc_csi_dev.aos_adc.dev.id = 0;
246     adc_csi_dev.aos_adc.resolution = 12;
247     adc_csi_dev.aos_adc.freq = 2000000 / 12;
248     return aos_adc_csi_register(&adc_csi_dev);
249 }
250 
251 LEVEL1_DRIVER_ENTRY(adc_csi_init)
252