1 /*
2  * Copyright (c) 2021-2024 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "hpm_adc12_drv.h"
9 #include "hpm_soc_feature.h"
10 
adc12_get_default_config(adc12_config_t * config)11 void adc12_get_default_config(adc12_config_t *config)
12 {
13     config->res                = adc12_res_12_bits;
14     config->conv_mode          = adc12_conv_mode_oneshot;
15     config->adc_clk_div        = adc12_clock_divider_1;
16     config->wait_dis           = true;
17     config->sel_sync_ahb       = true;
18     config->adc_ahb_en         = false;
19 }
20 
adc12_get_channel_default_config(adc12_channel_config_t * config)21 void adc12_get_channel_default_config(adc12_channel_config_t *config)
22 {
23     config->ch                 = 0;
24     config->diff_sel           = adc12_sample_signal_single_ended;
25     config->sample_cycle       = 10;
26     config->sample_cycle_shift = 0;
27     config->thshdh             = 0xfff;
28     config->thshdl             = 0x000;
29     config->wdog_int_en        = false;
30 }
31 
adc12_do_calibration(ADC12_Type * ptr,adc12_sample_signal_t diff_sel)32 static hpm_stat_t adc12_do_calibration(ADC12_Type *ptr, adc12_sample_signal_t diff_sel)
33 {
34     uint8_t cal_out;
35     uint32_t loop_cnt = ADC12_SOC_CALIBRATION_WAITING_LOOP_CNT;
36 
37     if (ADC12_IS_SIGNAL_TYPE_INVALID(diff_sel)) {
38         return status_invalid_argument;
39     }
40 
41     /*Set diff_sel temporarily */
42     ptr->SAMPLE_CFG[0] &= ~ADC12_SAMPLE_CFG_DIFF_SEL_MASK;
43     ptr->SAMPLE_CFG[0] |= ADC12_SAMPLE_CFG_DIFF_SEL_SET(diff_sel);
44 
45     /* Set resetcal and resetadc */
46     ptr->ANA_CTRL0 |= ADC12_ANA_CTRL0_RESETCAL_MASK | ADC12_ANA_CTRL0_RESETADC_MASK;
47 
48     /* Clear resetcal and resetadc */
49     ptr->ANA_CTRL0 &= ~(ADC12_ANA_CTRL0_RESETCAL_MASK | ADC12_ANA_CTRL0_RESETADC_MASK);
50 
51     /* Set startcal */
52     ptr->ANA_CTRL0 |= ADC12_ANA_CTRL0_STARTCAL_MASK;
53 
54     /* Clear startcal */
55     ptr->ANA_CTRL0 &= ~ADC12_ANA_CTRL0_STARTCAL_MASK;
56 
57     /* Set HW rearm_en */
58     ptr->ANA_CTRL0 |= ADC12_ANA_CTRL0_REARM_EN_MASK;
59 
60     /* Polling calibration status */
61     while (ADC12_ANA_STATUS_CALON_GET(ptr->ANA_STATUS) && loop_cnt--) {
62         /* TODO: Call a common delay function */
63     }
64 
65     /* Check if the calibration is timeout */
66     if (loop_cnt == 0) {
67         return status_timeout;
68     }
69 
70     /* Read calculation result */
71     cal_out = ADC12_ANA_STATUS_CAL_OUT_GET(ptr->ANA_STATUS);
72 
73     /* Update cal_out */
74     if (diff_sel == adc12_sample_signal_single_ended) {
75         ptr->ANA_CTRL0 = (ptr->ANA_CTRL0 & ~ADC12_ANA_CTRL0_CAL_VAL_SE_MASK)
76                        | ADC12_ANA_CTRL0_CAL_VAL_SE_SET(cal_out);
77     } else {
78         ptr->ANA_CTRL0 = (ptr->ANA_CTRL0 & ~ADC12_ANA_CTRL0_CAL_VAL_DIFF_MASK)
79                        | ADC12_ANA_CTRL0_CAL_VAL_DIFF_SET(cal_out);
80     }
81 
82     return status_success;
83 }
84 
adc12_deinit(ADC12_Type * ptr)85 hpm_stat_t adc12_deinit(ADC12_Type *ptr)
86 {
87     /* disable all interrupts */
88     ptr->INT_EN = 0;
89 
90     return status_success;
91 }
92 
adc12_init(ADC12_Type * ptr,adc12_config_t * config)93 hpm_stat_t adc12_init(ADC12_Type *ptr, adc12_config_t *config)
94 {
95     uint32_t adc_clk_div;
96 
97     /**
98      * disable adc
99      * When the adc is processing data, it will generate an error to initialize the adc again,
100      * so you need to shut down the adc before initializing it.
101      */
102 
103     ptr->ANA_CTRL0 &= ~(ADC12_ANA_CTRL0_ENADC_MASK);
104 
105     /* Check the resolution */
106     if (config->res > adc12_res_12_bits) {
107         return status_invalid_argument;
108     }
109 
110     /* Set resolution */
111     ptr->ANA_CTRL1 = (ptr->ANA_CTRL1 & ~ADC12_ANA_CTRL1_SELRES_MASK)
112                    | ADC12_ANA_CTRL1_SELRES_SET(config->res);
113 
114     /* Set convert clock number and clock period */
115     if ((config->adc_clk_div - 1) > ADC12_CONV_CFG1_CLOCK_DIVIDER_MASK)  {
116         return status_invalid_argument;
117     }
118 
119     /* Set ADC minimum conversion cycle and ADC clock divider */
120     ptr->CONV_CFG1 = ADC12_CONV_CFG1_CONVERT_CLOCK_NUMBER_SET(2 * config->res + 7)
121                    | ADC12_CONV_CFG1_CLOCK_DIVIDER_SET(config->adc_clk_div - 1);
122 
123     /* Set ADC Config0 */
124     ptr->ADC_CFG0 = ADC12_ADC_CFG0_SEL_SYNC_AHB_SET(config->sel_sync_ahb)
125                   | ADC12_ADC_CFG0_ADC_AHB_EN_SET(config->adc_ahb_en);
126 
127     /* Set wait_dis */
128     ptr->BUF_CFG0 = ADC12_BUF_CFG0_WAIT_DIS_SET(config->wait_dis);
129 
130     /*-------------------------------------------------------------------------------
131      *                                 Calibration
132      *------------------------------------------------------------------------------
133      */
134     /* Set enldo */
135     ptr->ANA_CTRL0 |= ADC12_ANA_CTRL0_ENLDO_MASK;
136 
137     /* TODO: wait 20us after setting enlado for adc0~adc2 */
138 
139     adc_clk_div = config->adc_clk_div;
140 
141     if (adc_clk_div == ADC12_SOC_CLOCK_CLK_DIV) {
142         ptr->CONV_CFG1 = (ptr->CONV_CFG1 & ~ADC12_CONV_CFG1_CLOCK_DIVIDER_MASK)
143                          | ADC12_CONV_CFG1_CLOCK_DIVIDER_SET(config->adc_clk_div + 1);
144     }
145 
146     /* Set enadc */
147     ptr->ANA_CTRL0 |= ADC12_ANA_CTRL0_ENADC_MASK;
148 
149     /* Do a calibration for single-ended mode */
150     adc12_do_calibration(ptr, adc12_sample_signal_single_ended);
151 
152     /* Do a calibration for differential mode */
153     adc12_do_calibration(ptr, adc12_sample_signal_differential);
154 
155     /* Set ADC clock divider */
156     if (adc_clk_div == ADC12_SOC_CLOCK_CLK_DIV) {
157         ptr->CONV_CFG1 = (ptr->CONV_CFG1 & ~ADC12_CONV_CFG1_CLOCK_DIVIDER_MASK)
158                        | ADC12_CONV_CFG1_CLOCK_DIVIDER_SET(config->adc_clk_div);
159     }
160 
161     /*-------------------------------------------------------------------------------
162      *                                 End of calibration
163      *------------------------------------------------------------------------------
164      */
165 
166     return status_success;
167 }
168 
adc12_init_channel(ADC12_Type * ptr,adc12_channel_config_t * config)169 hpm_stat_t adc12_init_channel(ADC12_Type *ptr, adc12_channel_config_t *config)
170 {
171     /* Check the specified channel number */
172     if (ADC12_IS_CHANNEL_INVALID(config->ch)) {
173         return status_invalid_argument;
174     }
175 
176     /* Check sample cycle */
177     if (ADC12_IS_CHANNEL_SAMPLE_CYCLE_INVALID(config->sample_cycle)) {
178         return status_invalid_argument;
179     }
180 
181     /* Set warning threshold */
182     ptr->PRD_CFG[config->ch].PRD_THSHD_CFG = ADC12_PRD_CFG_PRD_THSHD_CFG_THSHDH_SET(config->thshdh)
183                                            | ADC12_PRD_CFG_PRD_THSHD_CFG_THSHDL_SET(config->thshdl);
184 
185     /* Select single-ended mode or differential mode */
186     /* Set ADC sample cycles multiple */
187     /* Set ADC sample cycles */
188     ptr->SAMPLE_CFG[config->ch] = ADC12_SAMPLE_CFG_DIFF_SEL_SET(config->diff_sel)
189                                 | ADC12_SAMPLE_CFG_SAMPLE_CLOCK_NUMBER_SHIFT_SET(config->sample_cycle_shift)
190                                 | ADC12_SAMPLE_CFG_SAMPLE_CLOCK_NUMBER_SET(config->sample_cycle);
191 
192     /* Enable watchdog interrupt */
193     if (config->wdog_int_en) {
194         ptr->INT_EN |= 1 << config->ch;
195     }
196 
197     return status_success;
198 }
199 
adc12_get_channel_threshold(ADC12_Type * ptr,uint8_t ch,adc12_channel_threshold_t * config)200 hpm_stat_t adc12_get_channel_threshold(ADC12_Type *ptr, uint8_t ch, adc12_channel_threshold_t *config)
201 {
202     /* Check the specified channel number */
203     if (ADC12_IS_CHANNEL_INVALID(ch)) {
204         return status_invalid_argument;
205     }
206 
207     config->ch     = ch;
208     config->thshdh = ADC12_PRD_CFG_PRD_THSHD_CFG_THSHDH_GET(ptr->PRD_CFG[ch].PRD_THSHD_CFG);
209     config->thshdl = ADC12_PRD_CFG_PRD_THSHD_CFG_THSHDL_GET(ptr->PRD_CFG[ch].PRD_THSHD_CFG);
210 
211     return status_success;
212 }
213 
adc12_init_seq_dma(ADC12_Type * ptr,adc12_dma_config_t * dma_config)214 hpm_stat_t adc12_init_seq_dma(ADC12_Type *ptr, adc12_dma_config_t *dma_config)
215 {
216     /* Check the DMA buffer length  */
217     if (ADC12_IS_SEQ_DMA_BUFF_LEN_INVLAID(dma_config->buff_len_in_4bytes)) {
218         return status_invalid_argument;
219     }
220 
221     /* Reset ADC DMA  */
222     ptr->SEQ_DMA_CFG |= ADC12_SEQ_DMA_CFG_DMA_RST_MASK;
223 
224     /* Reset memory to clear all of cycle bits */
225     memset(dma_config->start_addr, 0x00, dma_config->buff_len_in_4bytes * sizeof(uint32_t));
226 
227     /* De-reset ADC DMA */
228     ptr->SEQ_DMA_CFG &= ~ADC12_SEQ_DMA_CFG_DMA_RST_MASK;
229 
230     /* Set ADC DMA target address which should be 4-byte aligned */
231     ptr->SEQ_DMA_ADDR = (uint32_t)dma_config->start_addr & ADC12_SEQ_DMA_ADDR_TAR_ADDR_MASK;
232 
233     /* Set ADC DMA memory dword length */
234     ptr->SEQ_DMA_CFG = (ptr->SEQ_DMA_CFG & ~ADC12_SEQ_DMA_CFG_BUF_LEN_MASK)
235                      | ADC12_SEQ_DMA_CFG_BUF_LEN_SET(dma_config->buff_len_in_4bytes - 1);
236 
237     /* Set stop_en and stop_pos */
238     if (dma_config->stop_en) {
239         ptr->SEQ_DMA_CFG = (ptr->SEQ_DMA_CFG & ~ADC12_SEQ_DMA_CFG_STOP_POS_MASK)
240                          | ADC12_SEQ_DMA_CFG_STOP_EN_MASK
241                          | ADC12_SEQ_DMA_CFG_STOP_POS_SET(dma_config->stop_pos);
242     }
243 
244     return status_success;
245 }
246 
adc12_set_prd_config(ADC12_Type * ptr,adc12_prd_config_t * config)247 hpm_stat_t adc12_set_prd_config(ADC12_Type *ptr, adc12_prd_config_t *config)
248 {
249     /* Check the specified channel number */
250     if (ADC12_IS_CHANNEL_INVALID(config->ch)) {
251         return status_invalid_argument;
252     }
253 
254     /* Check the prescale */
255     if (config->prescale > (ADC12_PRD_CFG_PRD_CFG_PRESCALE_MASK >> ADC12_PRD_CFG_PRD_CFG_PRESCALE_SHIFT)) {
256         return status_invalid_argument;
257     }
258 
259     /* Set periodic prescale */
260     ptr->PRD_CFG[config->ch].PRD_CFG = (ptr->PRD_CFG[config->ch].PRD_CFG & ~ADC12_PRD_CFG_PRD_CFG_PRESCALE_MASK)
261                                      | ADC12_PRD_CFG_PRD_CFG_PRESCALE_SET(config->prescale);
262 
263     /* Set period count */
264     ptr->PRD_CFG[config->ch].PRD_CFG = (ptr->PRD_CFG[config->ch].PRD_CFG & ~ADC12_PRD_CFG_PRD_CFG_PRD_MASK)
265                                      | ADC12_PRD_CFG_PRD_CFG_PRD_SET(config->period_count);
266 
267     return status_success;
268 }
269 
adc12_trigger_seq_by_sw(ADC12_Type * ptr)270 hpm_stat_t adc12_trigger_seq_by_sw(ADC12_Type *ptr)
271 {
272     if (ADC12_INT_STS_SEQ_SW_CFLCT_GET(ptr->INT_STS)) {
273         return status_fail;
274     }
275     ptr->SEQ_CFG0 |= ADC12_SEQ_CFG0_SW_TRIG_MASK;
276 
277     return status_success;
278 }
279 
280 /* Note: the sequence length can not be larger or equal than 2 in HPM6750EVK Revision A0 */
adc12_set_seq_config(ADC12_Type * ptr,adc12_seq_config_t * config)281 hpm_stat_t adc12_set_seq_config(ADC12_Type *ptr, adc12_seq_config_t *config)
282 {
283     /* Check sequence length */
284     if (ADC12_IS_SEQ_LEN_INVLAID(config->seq_len)) {
285         return status_invalid_argument;
286     }
287 
288     ptr->SEQ_CFG0 = ADC12_SEQ_CFG0_SEQ_LEN_SET(config->seq_len - 1)
289                   | ADC12_SEQ_CFG0_RESTART_EN_SET(config->restart_en)
290                   | ADC12_SEQ_CFG0_CONT_EN_SET(config->cont_en)
291                   | ADC12_SEQ_CFG0_SW_TRIG_EN_SET(config->sw_trig_en)
292                   | ADC12_SEQ_CFG0_HW_TRIG_EN_SET(config->hw_trig_en);
293 
294     /* Set sequence queue */
295     for (int i = 0; i < config->seq_len; i++) {
296         /* Check the specified channel number */
297         if (ADC12_IS_CHANNEL_INVALID(config->queue[i].ch)) {
298             return status_invalid_argument;
299         }
300 
301         ptr->SEQ_QUE[i] = ADC12_SEQ_QUE_SEQ_INT_EN_SET(config->queue[i].seq_int_en)
302                         | ADC12_SEQ_QUE_CHAN_NUM_4_0_SET(config->queue[i].ch);
303     }
304 
305     return status_success;
306 }
307 
adc12_trigger_pmt_by_sw(ADC12_Type * ptr,uint8_t trig_ch)308 hpm_stat_t adc12_trigger_pmt_by_sw(ADC12_Type *ptr, uint8_t trig_ch)
309 {
310     ptr->TRG_SW_STA = ADC12_TRG_SW_STA_TRG_SW_STA_MASK | ADC12_TRG_SW_STA_TRIG_SW_INDEX_SET(trig_ch);
311 
312     return status_success;
313 }
314 
adc12_set_pmt_config(ADC12_Type * ptr,adc12_pmt_config_t * config)315 hpm_stat_t adc12_set_pmt_config(ADC12_Type *ptr, adc12_pmt_config_t *config)
316 {
317     uint32_t temp = 0;
318 
319     /* Check the specified trigger length */
320     if (ADC12_IS_TRIG_LEN_INVLAID(config->trig_len)) {
321         return status_invalid_argument;
322     }
323 
324 	/* Check the triggier channel */
325     if (ADC12_IS_TRIG_CH_INVLAID(config->trig_ch)) {
326         return status_invalid_argument;
327     }
328 
329     temp |= ADC12_CONFIG_TRIG_LEN_SET(config->trig_len - 1);
330 
331     for (int i = 0; i < config->trig_len; i++) {
332         if (ADC12_IS_CHANNEL_INVALID(config->adc_ch[i])) {
333             return status_invalid_argument;
334         }
335 
336         temp |= config->inten[i] << (ADC12_CONFIG_INTEN0_SHIFT + i * ADC_SOC_CONFIG_INTEN_CHAN_BIT_SIZE)
337              |  config->adc_ch[i] << (ADC12_CONFIG_CHAN0_SHIFT + i * ADC_SOC_CONFIG_INTEN_CHAN_BIT_SIZE);
338     }
339 
340     ptr->CONFIG[config->trig_ch] = temp;
341 
342     return status_success;
343 }
344 
adc12_get_oneshot_result(ADC12_Type * ptr,uint8_t ch,uint16_t * result)345 hpm_stat_t adc12_get_oneshot_result(ADC12_Type *ptr, uint8_t ch, uint16_t *result)
346 {
347     uint32_t bus_res;
348 
349     /* Check the specified channel number */
350     if (ADC12_IS_CHANNEL_INVALID(ch)) {
351         return status_invalid_argument;
352     }
353 
354     bus_res = ptr->BUS_RESULT[ch];
355     *result = ADC12_BUS_RESULT_CHAN_RESULT_GET(bus_res);
356 
357     if (ADC12_BUF_CFG0_WAIT_DIS_GET(ptr->BUF_CFG0)) {
358         if (!ADC12_BUS_RESULT_VALID_GET(bus_res)) {
359             return status_fail;
360         }
361     }
362 
363     return status_success;
364 }
365 
adc12_get_prd_result(ADC12_Type * ptr,uint8_t ch,uint16_t * result)366 hpm_stat_t adc12_get_prd_result(ADC12_Type *ptr, uint8_t ch, uint16_t *result)
367 {
368     /* Check the specified channel number */
369     if (ADC12_IS_CHANNEL_INVALID(ch)) {
370         return status_invalid_argument;
371     }
372 
373     *result = ADC12_PRD_CFG_PRD_RESULT_CHAN_RESULT_GET(ptr->PRD_CFG[ch].PRD_RESULT);
374 
375     return status_success;
376 }
377