• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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