1 /*
2 * Copyright (c) 2021 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "hpm_adc16_drv.h"
9 #include "hpm_soc_feature.h"
10
adc16_get_default_config(adc16_config_t * config)11 void adc16_get_default_config(adc16_config_t *config)
12 {
13 config->conv_mode = adc16_conv_mode_oneshot;
14 config->adc_clk_div = 1;
15 config->wait_dis = 0;
16 config->conv_duration = 0;
17 config->sel_sync_ahb = true;
18 config->port3_rela_time = false;
19 config->adc_ahb_en = false;
20 }
21
adc16_get_channel_default_config(adc16_channel_config_t * config)22 void adc16_get_channel_default_config(adc16_channel_config_t *config)
23 {
24 config->ch = 0;
25 config->sample_cycle = 10;
26 config->sample_cycle_shift = 0;
27 config->thshdh = 0;
28 config->thshdl = 0;
29 }
30
adc16_do_calibration(ADC16_Type * ptr)31 static hpm_stat_t adc16_do_calibration(ADC16_Type *ptr)
32 {
33 int i, j;
34 uint32_t clk_div_temp;
35 uint32_t adc16_params[ADC16_SOC_PARAMS_LEN];
36 int32_t param01;
37 uint32_t param02;
38 uint64_t param64;
39 uint32_t param32;
40 uint32_t temp;
41
42 /* Get input clock divider */
43 clk_div_temp = ADC16_CONV_CFG1_CLOCK_DIVIDER_GET(ptr->CONV_CFG1);
44
45 /* Set input clock divider temporarily */
46 ptr->CONV_CFG1 = (ptr->CONV_CFG1 & ~ADC16_CONV_CFG1_CLOCK_DIVIDER_MASK)
47 | ADC16_CONV_CFG1_CLOCK_DIVIDER_SET(1);
48
49 /* Enable ADC clock */
50 ptr->ANA_CTRL0 |= ADC16_ANA_CTRL0_ADC_CLK_ON_MASK;
51
52 for (i = 0; i < ADC16_SOC_PARAMS_LEN; i++) {
53 adc16_params[i] = 0;
54 }
55
56 /* Enable reg_en */
57 /* Enable bandgap_en */
58 ptr->ADC16_CONFIG0 |= ADC16_ADC16_CONFIG0_REG_EN_MASK
59 | ADC16_ADC16_CONFIG0_BANDGAP_EN_MASK;
60
61 /* Set cal_avg_cfg for 5 loops */
62 ptr->ADC16_CONFIG0 = (ptr->ADC16_CONFIG0 & ~ADC16_ADC16_CONFIG0_CAL_AVG_CFG_MASK)
63 | ADC16_ADC16_CONFIG0_CAL_AVG_CFG_SET(5);
64
65 /* Enable ahb_en */
66 ptr->ADC_CFG0 |= ADC16_ADC_CFG0_ADC_AHB_EN_MASK;
67
68 /* Disable ADC clock */
69 ptr->ANA_CTRL0 &= ~ADC16_ANA_CTRL0_ADC_CLK_ON_MASK;
70
71 /* Recover input clock divider */
72 ptr->CONV_CFG1 = (ptr->CONV_CFG1 & ~ADC16_CONV_CFG1_CLOCK_DIVIDER_MASK)
73 | ADC16_CONV_CFG1_CLOCK_DIVIDER_SET(clk_div_temp);
74
75 for (j = 0; j < 4; j++) {
76 /* Set startcal */
77 ptr->ANA_CTRL0 |= ADC16_ANA_CTRL0_STARTCAL_MASK;
78
79 /* Clear startcal */
80 ptr->ANA_CTRL0 &= ~ADC16_ANA_CTRL0_STARTCAL_MASK;
81
82 /* Polling calibration status */
83 while (ADC16_ANA_STATUS_CALON_GET(ptr->ANA_STATUS)) {
84 }
85
86 /* Read parameters */
87 for (i = 0; i < ADC16_SOC_PARAMS_LEN; i++) {
88 adc16_params[i] += ADC16_ADC16_PARAMS_PARAM_VAL_GET(ptr->ADC16_PARAMS[i]);
89 }
90 }
91
92 adc16_params[ADC16_ADC16_PARAMS_ADC16_PARA33] -= 0x800;
93 param01 = adc16_params[ADC16_ADC16_PARAMS_ADC16_PARA32] - adc16_params[ADC16_ADC16_PARAMS_ADC16_PARA33];
94 adc16_params[ADC16_ADC16_PARAMS_ADC16_PARA32] = adc16_params[ADC16_ADC16_PARAMS_ADC16_PARA00] -
95 adc16_params[ADC16_ADC16_PARAMS_ADC16_PARA33];
96 adc16_params[ADC16_ADC16_PARAMS_ADC16_PARA00] = 0;
97
98 for (i = 1; i < ADC16_SOC_PARAMS_LEN - 2; i++) {
99 adc16_params[i] = adc16_params[ADC16_ADC16_PARAMS_ADC16_PARA32] + adc16_params[i] -
100 adc16_params[ADC16_ADC16_PARAMS_ADC16_PARA33] + adc16_params[i - 1];
101 }
102
103 param02 = (param01 + adc16_params[ADC16_ADC16_PARAMS_ADC16_PARA31] + adc16_params[ADC16_ADC16_PARAMS_ADC16_PARA32]) >> 6;
104 param64 = 0x10000ll * param02;
105 param64 = param64 / (0x20000 - param02 / 2);
106 param32 = (uint32_t)param64;
107
108 for (i = 0; i < ADC16_SOC_PARAMS_LEN; i++) {
109 adc16_params[i] >>= 6;
110 }
111
112 /* Enable ADC clock */
113 ptr->ANA_CTRL0 |= ADC16_ANA_CTRL0_ADC_CLK_ON_MASK;
114
115 ptr->CONV_CFG1 = (ptr->CONV_CFG1 & ~ADC16_CONV_CFG1_CLOCK_DIVIDER_MASK)
116 | ADC16_CONV_CFG1_CLOCK_DIVIDER_SET(1);
117
118 /* Write parameters */
119 for (i = 0; i < ADC16_SOC_PARAMS_LEN ; i++) {
120 ptr->ADC16_PARAMS[i] = (uint16_t)(adc16_params[i]);
121 }
122
123 /* Set ADC16 Config0 */
124 temp = ptr->ADC16_CONFIG0;
125
126 temp &= ~(ADC16_ADC16_CONFIG0_CAL_AVG_CFG_MASK | ADC16_ADC16_CONFIG0_CONV_PARAM_MASK);
127
128 temp |= ADC16_ADC16_CONFIG0_REG_EN_MASK
129 | ADC16_ADC16_CONFIG0_BANDGAP_EN_MASK
130 | ADC16_ADC16_CONFIG0_CAL_AVG_CFG_MASK
131 | ADC16_ADC16_CONFIG0_CONV_PARAM_SET(param32);
132
133 ptr->ADC16_CONFIG0 = temp;
134
135 /* Recover input clock divider */
136 ptr->CONV_CFG1 = (ptr->CONV_CFG1 & ~ADC16_CONV_CFG1_CLOCK_DIVIDER_MASK)
137 | ADC16_CONV_CFG1_CLOCK_DIVIDER_SET(clk_div_temp);
138
139 /* Disable ADC clock */
140 ptr->ANA_CTRL0 &= ~ADC16_ANA_CTRL0_ADC_CLK_ON_MASK;
141
142 return status_success;
143 }
144
adc16_init(ADC16_Type * ptr,adc16_config_t * config)145 hpm_stat_t adc16_init(ADC16_Type *ptr, adc16_config_t *config)
146 {
147 /* Set convert clock number and clock period */
148 if (config->adc_clk_div > ADC16_CONV_CFG1_CLOCK_DIVIDER_MASK) {
149 return status_invalid_argument;
150 }
151
152 /* Set ADC minimum conversion cycle and ADC clock divider */
153 ptr->CONV_CFG1 = ADC16_CONV_CFG1_CONVERT_CLOCK_NUMBER_SET(21)
154 | ADC16_CONV_CFG1_CLOCK_DIVIDER_SET(config->adc_clk_div);
155
156 /* Set ahb_en */
157 /* Set convert duration */
158 ptr->ADC_CFG0 = ADC16_ADC_CFG0_ADC_AHB_EN_SET(config->sel_sync_ahb)
159 | ADC16_ADC_CFG0_CONVERT_DURATION_SET(config->conv_duration);
160
161 /* Set wait_dis */
162 if (config->conv_mode == adc16_conv_mode_oneshot) {
163 /* Set wait_dis */
164 ptr->BUF_CFG0 = ADC16_BUF_CFG0_WAIT_DIS_SET(config->wait_dis);
165 }
166
167 /* Do a calibration */
168 adc16_do_calibration(ptr);
169
170 return status_success;
171 }
172
adc16_init_channel(ADC16_Type * ptr,adc16_channel_config_t * config)173 hpm_stat_t adc16_init_channel(ADC16_Type *ptr, adc16_channel_config_t *config)
174 {
175 /* Check the specified channel number */
176 if (ADC16_IS_CHANNEL_INVALID(config->ch)) {
177 return status_invalid_argument;
178 }
179
180 /* Set warning threshold */
181 ptr->PRD_CFG[config->ch].PRD_THSHD_CFG = ADC16_PRD_CFG_PRD_THSHD_CFG_THSHDH_SET(config->thshdh)
182 | ADC16_PRD_CFG_PRD_THSHD_CFG_THSHDL_SET(config->thshdl);
183
184 /* Set ADC sample cycles multiple */
185 /* Set ADC sample cycles */
186 ptr->SAMPLE_CFG[config->ch] = ADC16_SAMPLE_CFG_SAMPLE_CLOCK_NUMBER_SHIFT_SET(config->sample_cycle_shift)
187 | ADC16_SAMPLE_CFG_SAMPLE_CLOCK_NUMBER_SET(config->sample_cycle);
188
189 return status_success;
190 }
191
adc16_init_seq_dma(ADC16_Type * ptr,adc16_dma_config_t * dma_config)192 void adc16_init_seq_dma(ADC16_Type *ptr, adc16_dma_config_t *dma_config)
193 {
194 /* Reset ADC DMA */
195 ptr->SEQ_DMA_CFG |= ADC16_SEQ_DMA_CFG_DMA_RST_MASK;
196
197 /* Reset memory to clear all of cycle bits */
198 memset(dma_config->start_addr, 0x00, dma_config->buff_len_in_4bytes * sizeof(uint32_t));
199
200 /* De-reset ADC DMA */
201 ptr->SEQ_DMA_CFG &= ~ADC16_SEQ_DMA_CFG_DMA_RST_MASK;
202
203 /* Set ADC DMA target address which should be 4-byte aligned */
204 ptr->SEQ_DMA_ADDR = (uint32_t)dma_config->start_addr & ADC16_SEQ_DMA_ADDR_TAR_ADDR_MASK;
205
206 /* Set ADC DMA memory dword length */
207 ptr->SEQ_DMA_CFG = (ptr->SEQ_DMA_CFG & ~ADC16_SEQ_DMA_CFG_BUF_LEN_MASK)
208 | ADC16_SEQ_DMA_CFG_BUF_LEN_SET(dma_config->buff_len_in_4bytes);
209
210 /* Set stop_en and stop_pos */
211 if (dma_config->stop_en) {
212 ptr->SEQ_DMA_CFG = (ptr->SEQ_DMA_CFG & ~ADC16_SEQ_DMA_CFG_STOP_POS_MASK)
213 | ADC16_SEQ_DMA_CFG_STOP_EN_MASK
214 | ADC16_SEQ_DMA_CFG_STOP_POS_SET(dma_config->stop_pos);
215 }
216 }
217
adc16_set_prd_config(ADC16_Type * ptr,adc16_prd_config_t * config)218 hpm_stat_t adc16_set_prd_config(ADC16_Type *ptr, adc16_prd_config_t *config)
219 {
220 /* Check the specified channel number */
221 if (ADC16_IS_CHANNEL_INVALID(config->ch)) {
222 return status_invalid_argument;
223 }
224
225 if (config->prescale > (ADC16_PRD_CFG_PRD_CFG_PRESCALE_MASK >> ADC16_PRD_CFG_PRD_CFG_PRESCALE_SHIFT)) {
226 return status_invalid_argument;
227 }
228
229 /* periodic prescale */
230 ptr->PRD_CFG[config->ch].PRD_CFG = (ptr->PRD_CFG[config->ch].PRD_CFG & ~ADC16_PRD_CFG_PRD_CFG_PRESCALE_MASK)
231 | ADC16_PRD_CFG_PRD_CFG_PRESCALE_SET(config->prescale);
232
233
234 /* Set period count */
235 ptr->PRD_CFG[config->ch].PRD_CFG = (ptr->PRD_CFG[config->ch].PRD_CFG & ~ADC16_PRD_CFG_PRD_CFG_PRD_MASK)
236 | ADC16_PRD_CFG_PRD_CFG_PRD_SET(config->period_count);
237
238 return status_success;
239 }
240
adc16_trigger_seq_by_sw(ADC16_Type * ptr)241 void adc16_trigger_seq_by_sw(ADC16_Type *ptr)
242 {
243 ptr->SEQ_CFG0 |= ADC16_SEQ_CFG0_SW_TRIG_MASK;
244 }
245
246 /* Note: the sequence length can not be larger or equal than 2 in HPM6750EVK Revision A0 */
adc16_set_seq_config(ADC16_Type * ptr,adc16_seq_config_t * config)247 hpm_stat_t adc16_set_seq_config(ADC16_Type *ptr, adc16_seq_config_t *config)
248 {
249 if (config->seq_len > ADC_SOC_SEQ_MAX_LEN) {
250 return status_invalid_argument;
251 }
252
253 ptr->SEQ_CFG0 = ADC16_SEQ_CFG0_SEQ_LEN_SET(config->seq_len - 1)
254 | ADC16_SEQ_CFG0_RESTART_EN_SET(config->restart_en)
255 | ADC16_SEQ_CFG0_CONT_EN_SET(config->cont_en)
256 | ADC16_SEQ_CFG0_SW_TRIG_EN_SET(config->sw_trig_en)
257 | ADC16_SEQ_CFG0_HW_TRIG_EN_SET(config->hw_trig_en);
258
259 /* Set sequence queue */
260 for (int i = 0; i < config->seq_len; i++) {
261 /* Check the specified channel number */
262 if (ADC16_IS_CHANNEL_INVALID(config->queue[i].ch)) {
263 return status_invalid_argument;
264 }
265
266 ptr->SEQ_QUE[i] = ADC16_SEQ_QUE_SEQ_INT_EN_SET(config->queue[i].seq_int_en)
267 | ADC16_SEQ_QUE_CHAN_NUM_4_0_SET(config->queue[i].ch);
268 }
269
270 return status_success;
271 }
272
adc16_set_pmt_config(ADC16_Type * ptr,adc16_pmt_config_t * config)273 hpm_stat_t adc16_set_pmt_config(ADC16_Type *ptr, adc16_pmt_config_t *config)
274 {
275 uint32_t temp = 0;
276
277 /* Check the specified trigger length */
278 if (ADC16_IS_TRIG_LEN_INVLAID(config->trig_len)) {
279 return status_invalid_argument;
280 }
281
282 temp |= ADC16_CONFIG_TRIG_LEN_SET(config->trig_len - 1);
283
284 for (int i = 0; i < config->trig_len; i++) {
285 if (ADC16_IS_CHANNEL_INVALID(config->trig_ch)) {
286 return status_invalid_argument;
287 }
288
289 temp |= config->inten[i] << (ADC16_CONFIG_INTEN0_SHIFT + i * ADC_SOC_CONFIG_INTEN_CHAN_BIT_SIZE)
290 | config->adc_ch[i] << (ADC16_CONFIG_CHAN0_SHIFT + i * ADC_SOC_CONFIG_INTEN_CHAN_BIT_SIZE);
291 }
292
293 ptr->CONFIG[config->trig_ch] = temp;
294
295 return status_success;
296 }
297
adc16_set_pmt_queue_enable(ADC16_Type * ptr,uint8_t trig_ch,bool enable)298 hpm_stat_t adc16_set_pmt_queue_enable(ADC16_Type *ptr, uint8_t trig_ch, bool enable)
299 {
300 #if ADC_SOC_PREEMPT_ENABLE_CTRL_SUPPORT == 1
301 /* Check the specified trigger channel */
302 if (ADC16_IS_TRIG_CH_INVLAID(trig_ch)) {
303 return status_invalid_argument;
304 }
305
306 /* Set queue enable control */
307 ptr->CONFIG[trig_ch] |= ADC16_CONFIG_QUEUE_EN_SET(enable);
308 return status_success;
309 #else
310 return status_success;
311 #endif
312 }
313
314 /* one shot mode */
adc16_get_oneshot_result(ADC16_Type * ptr,uint8_t ch,uint16_t * result)315 hpm_stat_t adc16_get_oneshot_result(ADC16_Type *ptr, uint8_t ch, uint16_t *result)
316 {
317 if (ADC16_IS_CHANNEL_INVALID(ch)) {
318 return status_invalid_argument;
319 }
320
321 *result = ADC16_BUS_RESULT_CHAN_RESULT_GET(ptr->BUS_RESULT[ch]);
322
323 return status_success;
324 }
325
326 /* period mode */
adc16_get_prd_result(ADC16_Type * ptr,uint8_t ch,uint16_t * result)327 hpm_stat_t adc16_get_prd_result(ADC16_Type *ptr, uint8_t ch, uint16_t *result)
328 {
329 if (ADC16_IS_CHANNEL_INVALID(ch)) {
330 return status_invalid_argument;
331 }
332
333 *result = ptr->PRD_CFG[ch].PRD_RESULT;
334
335 return status_success;
336 }
337