1 /*
2 * Copyright (c) 2023 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #ifndef HPM_OPAMP_DRV_H
9 #define HPM_OPAMP_DRV_H
10
11 #include "hpm_common.h"
12 #include "hpm_opamp_regs.h"
13 #include "hpm_soc_feature.h"
14
15 /**
16 * @brief OPMAP driver APIs
17 * @defgroup opamp_interface OPAMP driver APIs
18 * @ingroup io_interfaces
19 * @{
20 *
21 */
22 #define OPAMP_MODE_FOLLOW_KEY (0x06)
23 #define OPAMP_MODE_INVERT_INDEX0_KEY (0x08)
24 #define OPAMP_MODE_INVERT_INDEX1_KEY (0x18)
25 #define OPAMP_MODE_NON_INVERT_INDEX0_KEY (0x01)
26 #define OPAMP_MODE_NON_INVERT_INDEX1_KEY (0x09)
27 #define OPAMP_MODE_NON_INVERT_INDEX2_KEY (0x11)
28 #define OPAMP_MODE_NON_INVERT_INDEX3_KEY (0x19)
29 #define OPAMP_MODE_NON_INVERT_INDEX4_KEY (0x09)
30 #define OPAMP_MODE_USER_DEFINE_KEY (0x04)
31
32 /**
33 * @brief Reverse Input Pin Selection
34 *
35 */
36 typedef enum {
37 inm_pad_vim0 = 0, /**< Connect pad vim0 */
38 inm_pad_vim1 = 1, /**< Connect pad vim1 */
39 inm_pad_vim2 = 2, /**< Connect pad vim2 */
40 inm_pad_dac = 3, /**< Connect pad vim dac */
41 inm_pad_floating = 4 /**< Connect inm floating */
42 } opamp_inm_pad_t;
43
44 /**
45 * @brief Gain multiplier selection
46 *
47 */
48 typedef enum {
49 gain_x_2 = 0, /**< gain x2 */
50 gain_x_4 = 1,
51 gain_x_8 = 2,
52 gain_x_16 = 3,
53 gain_x_32 = 4,
54 gain_x_64 = 5,
55 gain_x_128 = 6, /**< gain x128 */
56 } opamp_gain_t;
57
58 /**
59 * @brief Miller Capacitor Selection
60 *
61 */
62 typedef enum {
63 miller_cap_x_7 = 0, /**< 7 unit cap */
64 miller_cap_x_8 = 1,
65 miller_cap_x_10 = 2,
66 miller_cap_x_13 = 3,
67 miller_cap_x_15 = 4, /**< 15 unit cap */
68 miller_cap_x_18 = 5,
69 miller_cap_x_5 = 6,
70 miller_cap_x_6 = 7, /**< 6 unit cap */
71 } opamp_miller_cap_t;
72
73 /**
74 * @brief Positive Input Pin Selection
75 *
76 */
77 typedef enum {
78 inp_pad_vip0 = 0, /**< Connect pad vip0 */
79 inp_pad_vip1 = 1, /**< Connect pad vip1 */
80 inp_pad_vip2 = 2, /**< Connect pad vip2 */
81 inp_pad_dac = 3, /**< Connect pad vip dac */
82 inp_pad_vsupply_x_0_25 = 4, /**< Connect reference = 0.25 * vsupply */
83 inp_pad_vsupply_x_0_5 = 5, /**< Connect reference = 0.5 * vsupply */
84 inp_pad_vsupply_x_0_75 = 6, /**< Connect reference = 0.75 * vsupply */
85 inp_pad_floating = 7 /**< Connect inp floating */
86 } opamp_inp_pad_t;
87
88 /**
89 * @brief opamp preset channel
90 *
91 */
92 typedef enum {
93 cfg_preset_0 = OPAMP_CFG_PRESET0,
94 cfg_preset_1 = OPAMP_CFG_PRESET1,
95 cfg_preset_2 = OPAMP_CFG_PRESET2,
96 cfg_preset_3 = OPAMP_CFG_PRESET3,
97 cfg_preset_4 = OPAMP_CFG_PRESET4,
98 cfg_preset_5 = OPAMP_CFG_PRESET5,
99 cfg_preset_6 = OPAMP_CFG_PRESET6,
100 cfg_preset_7 = OPAMP_CFG_PRESET7,
101 } opamp_cfg_preset_chn_t;
102
103 /**
104 * @brief operational amplifier
105 *
106 */
107 typedef enum {
108 mode_follow = 0, /**< opamp follow mode */
109 mode_invert_intern_vol = 1, /**< inverting opamp */
110 mode_invert_extern_vol = 2, /**< inverted amplification mode, external reference voltage */
111 mode_invert_dac_vol = 3, /**< inverted amplification mode, DAC output reference voltage */
112 mode_non_invert_gnd_vol = 4, /**< forward amplification mode, GND is the reference voltage */
113 mode_non_invert_extern_vol = 5, /**< forward amplification mode, external reference voltage */
114 mode_non_invert_dac_vol = 6, /**< forward amplification mode, DAC output reference voltage */
115 mode_user = 7, /**< custom Mode */
116 } opamp_mode_t;
117
118 /**
119 * @brief opamp configuration preset0
120 *
121 */
122 typedef union opamp_cfg_preset0 {
123 struct {
124 uint32_t vip_select: 3;
125 uint32_t vim_select: 3;
126 uint32_t vswitch_select: 3;
127 uint32_t cap_select: 4;
128 uint32_t reserve: 19;
129 };
130 uint32_t val;
131 } opamp_ctrl_cfg_preset0_t;
132
133 /**
134 * @brief opamp configuration preset1
135 *
136 */
137 typedef union opamp_cfg_preset1 {
138 struct {
139 uint32_t res_select: 3;
140 uint32_t function_mode: 5;
141 uint32_t iref_select: 2;
142 uint32_t opaout_select: 2;
143 uint32_t is_vssa_disconnect: 1;
144 uint32_t en_lv: 1;
145 uint32_t hw_trig_en: 1;
146 uint32_t reserve: 17;
147 };
148 uint32_t val;
149 } opamp_ctrl_cfg_preset1_t;
150
151 typedef struct opamp_cfg {
152 opamp_mode_t mode;
153 opamp_inm_pad_t negative_input_pin;
154 opamp_inp_pad_t positive_input_pin;
155 opamp_gain_t gain;
156 opamp_miller_cap_t miller_cap;
157 bool enable_extern_filter_cap;
158 bool enable_phase_margin_cap;
159 } opamp_cfg_t;
160
161 #ifdef __cplusplus
162 extern "C" {
163 #endif
164
165 /**
166 * @brief opamp initialisation functions
167 * Use this function to initialise the op-amp to different modes
168 * @param opamp @ref OPAMP_Type
169 * @param cfg @ref opamp_cfg_t
170 * @return @ref hpm_stat_t
171 */
172 hpm_stat_t opamp_init(OPAMP_Type *opamp, opamp_cfg_t *cfg);
173 /**
174 * @brief enable opamp function
175 *
176 * @param opamp @ref OPAMP_Type
177 */
opamp_enable(OPAMP_Type * opamp)178 static inline void opamp_enable(OPAMP_Type *opamp)
179 {
180 opamp->CTRL0 |= OPAMP_CTRL0_EN_LV_MASK;
181 }
182
183 /**
184 * @brief preset enable opamp function
185 *
186 * @param opamp @ref OPAMP_Type
187 * @param preset_chn preset channel
188 */
opamp_preset_opamp_enable(OPAMP_Type * opamp,uint8_t preset_chn)189 static inline void opamp_preset_opamp_enable(OPAMP_Type *opamp, uint8_t preset_chn)
190 {
191 opamp->CFG[preset_chn].CFG1 |= OPAMP_CFG_CFG1_EN_LV_MASK;
192 }
193
194 /**
195 * @brief disable opamp function
196 *
197 * @param opamp @ref OPAMP_Type
198 */
opamp_disable(OPAMP_Type * opamp)199 static inline void opamp_disable(OPAMP_Type *opamp)
200 {
201 opamp->CTRL0 &= ~OPAMP_CTRL0_EN_LV_MASK;
202 }
203
204 /**
205 * @brief preset disable opamp function
206 *
207 * @param opamp @ref OPAMP_Type
208 * @param preset_chn preset channel
209 */
opamp_preset_opamp_disable(OPAMP_Type * opamp,uint8_t preset_chn)210 static inline void opamp_preset_opamp_disable(OPAMP_Type *opamp, uint8_t preset_chn)
211 {
212 opamp->CFG[preset_chn].CFG1 &= ~OPAMP_CFG_CFG1_EN_LV_MASK;
213 }
214
215 /**
216 * @brief opamp miller cap selection
217 *
218 * @param opamp @ref OPAMP_Type
219 * @param select @ref opamp_iref_select_t
220 */
opamp_miller_cap_select(OPAMP_Type * opamp,opamp_miller_cap_t select)221 static inline void opamp_miller_cap_select(OPAMP_Type *opamp, opamp_miller_cap_t select)
222 {
223 opamp->CTRL0 = (opamp->CTRL0 & (~OPAMP_CTRL0_MILLER_SEL_MASK)) | OPAMP_CTRL0_MILLER_SEL_SET(select);
224 }
225
226 /**
227 * @brief opamp miller cap selection preset
228 *
229 * @param opamp @ref OPAMP_Type
230 * @param preset_chn preset channel
231 * @param select @ref opamp_iref_select_t
232 */
opamp_preset_miller_cap_select(OPAMP_Type * opamp,uint8_t preset_chn,opamp_miller_cap_t select)233 static inline void opamp_preset_miller_cap_select(OPAMP_Type *opamp, uint8_t preset_chn, opamp_miller_cap_t select)
234 {
235 opamp->CFG[preset_chn].CFG0 = (opamp->CFG[preset_chn].CFG0 & (~OPAMP_CFG_CFG0_MILLER_SEL_MASK)) | OPAMP_CFG_CFG0_MILLER_SEL_SET(select);
236 }
237
238 /**
239 * @brief enable phase margin compensation cap
240 *
241 * @param opamp @ref OPAMP_Type
242 */
opamp_phase_margin_cap_enable(OPAMP_Type * opamp)243 static inline void opamp_phase_margin_cap_enable(OPAMP_Type *opamp)
244 {
245 opamp->CTRL0 &= ~OPAMP_CTRL0_DISABLE_PM_CAP_MASK;
246 }
247
248 /**
249 * @brief enable phase margin compensation cap preset
250 *
251 * @param opamp @ref OPAMP_Type
252 * @param preset_chn preset channel
253 */
opamp_preset_phase_margin_cap_enable(OPAMP_Type * opamp,uint8_t preset_chn)254 static inline void opamp_preset_phase_margin_cap_enable(OPAMP_Type *opamp, uint8_t preset_chn)
255 {
256 opamp->CFG[preset_chn].CFG0 &= ~OPAMP_CFG_CFG0_DISABLE_PM_CAP_MASK;
257 }
258
259 /**
260 * @brief disable phase margin compensation cap
261 *
262 * @param opamp @ref OPAMP_Type
263 */
opamp_phase_margin_cap_disable(OPAMP_Type * opamp)264 static inline void opamp_phase_margin_cap_disable(OPAMP_Type *opamp)
265 {
266 opamp->CTRL0 |= OPAMP_CTRL0_DISABLE_PM_CAP_MASK;
267 }
268
269 /**
270 * @brief disable phase margin compensation cap preset
271 *
272 * @param opamp @ref OPAMP_Type
273 * @param preset_chn preset channel
274 */
opamp_preset_phase_margin_cap_disable(OPAMP_Type * opamp,uint8_t preset_chn)275 static inline void opamp_preset_phase_margin_cap_disable(OPAMP_Type *opamp, uint8_t preset_chn)
276 {
277 opamp->CFG[preset_chn].CFG0 |= OPAMP_CFG_CFG0_DISABLE_PM_CAP_MASK;
278 }
279
280 /**
281 * @brief opamp core inm connect pad
282 *
283 * @param opamp @ref OPAMP_Type
284 * @param select @ref opamp_inm_pad_t
285 */
opamp_inn_pad_select(OPAMP_Type * opamp,opamp_inm_pad_t select)286 static inline void opamp_inn_pad_select(OPAMP_Type *opamp, opamp_inm_pad_t select)
287 {
288 opamp->CTRL0 = (opamp->CTRL0 & (~OPAMP_CTRL0_VIM_SEL_MASK)) | OPAMP_CTRL0_VIM_SEL_SET(select);
289 }
290
291 /**
292 * @brief opamp core inm connect pad preset
293 *
294 * @param opamp @ref OPAMP_Type
295 * @param preset_chn preset channel
296 * @param select @ref opamp_inm_pad_t
297 */
opamp_preset_inn_pad_select(OPAMP_Type * opamp,uint8_t preset_chn,opamp_inm_pad_t select)298 static inline void opamp_preset_inn_pad_select(OPAMP_Type *opamp, uint8_t preset_chn, opamp_inm_pad_t select)
299 {
300 opamp->CFG[preset_chn].CFG0 = (opamp->CFG[preset_chn].CFG0 & (~OPAMP_CFG_CFG0_VIM_SEL_MASK)) | OPAMP_CFG_CFG0_VIM_SEL_SET(select);
301 }
302
303 /**
304 * @brief main string resistor selection
305 *
306 * @param opamp @ref OPAMP_Type
307 * @param select @ref opamp_gain_t
308 *
309 */
opamp_gain_select(OPAMP_Type * opamp,opamp_gain_t select)310 static inline void opamp_gain_select(OPAMP_Type *opamp, opamp_gain_t select)
311 {
312 opamp->CTRL0 = (opamp->CTRL0 & (~OPAMP_CTRL0_GAIN_SEL_MASK)) | OPAMP_CTRL0_GAIN_SEL_SET(select);
313 }
314
315 /**
316 * @brief main string resistor selection preset
317 *
318 * @param opamp @ref OPAMP_Type
319 * @param preset_chn preset channel
320 * @param select @ref opamp_gain_t
321 *
322 */
opamp_preset_gain_select(OPAMP_Type * opamp,uint8_t preset_chn,opamp_gain_t select)323 static inline void opamp_preset_gain_select(OPAMP_Type *opamp, uint8_t preset_chn, opamp_gain_t select)
324 {
325 opamp->CFG[preset_chn].CFG1 = (opamp->CFG[preset_chn].CFG1 & (~OPAMP_CFG_CFG1_GAIN_SEL_MASK)) | OPAMP_CFG_CFG1_GAIN_SEL_SET(select);
326 }
327
328 /**
329 * @brief disconnect the main series resistor and VSSA
330 *
331 * @param opamp @ref OPAMP_Type
332 */
opamp_disconnect_vssa(OPAMP_Type * opamp)333 static inline void opamp_disconnect_vssa(OPAMP_Type *opamp)
334 {
335 opamp->CTRL0 |= OPAMP_CTRL0_VBYPASS_MASK;
336 }
337
338 /**
339 * @brief disconnect the main series resistor and VSSA preset
340 *
341 * @param opamp @ref OPAMP_Type
342 * @param preset_chn preset channel
343 */
opamp_preset_disconnect_vssa(OPAMP_Type * opamp,uint8_t preset_chn)344 static inline void opamp_preset_disconnect_vssa(OPAMP_Type *opamp, uint8_t preset_chn)
345 {
346 opamp->CFG[preset_chn].CFG1 |= OPAMP_CFG_CFG1_VBYPASS_LV_MASK;
347 }
348
349 /**
350 * @brief connect the main series resistor and VSSA
351 *
352 * @param opamp @ref OPAMP_Type
353 */
opamp_connect_vssa(OPAMP_Type * opamp)354 static inline void opamp_connect_vssa(OPAMP_Type *opamp)
355 {
356 opamp->CTRL0 &= ~OPAMP_CTRL0_VBYPASS_MASK;
357 }
358
359 /**
360 * @brief connect the main series resistor and VSSA preset
361 *
362 * @param opamp @ref OPAMP_Type
363 * @param preset_chn preset channel
364 */
opamp_preset_connect_vssa(OPAMP_Type * opamp,uint8_t preset_chn)365 static inline void opamp_preset_connect_vssa(OPAMP_Type *opamp, uint8_t preset_chn)
366 {
367 opamp->CFG[preset_chn].CFG1 &= ~OPAMP_CFG_CFG1_VBYPASS_LV_MASK;
368 }
369
370 /**
371 * @brief opamp inp select
372 *
373 * @param opamp @ref OPAMP_Type
374 * @param select @ref opamp_inp_pad_t
375 */
opamp_inp_pad_select(OPAMP_Type * opamp,opamp_inp_pad_t select)376 static inline void opamp_inp_pad_select(OPAMP_Type *opamp, opamp_inp_pad_t select)
377 {
378 opamp->CTRL0 = (opamp->CTRL0 & (~OPAMP_CTRL0_VIP_SEL_MASK)) | OPAMP_CTRL0_VIP_SEL_SET(select);
379 }
380
381 /**
382 * @brief opamp inp select preset
383 *
384 * @param opamp @ref OPAMP_Type
385 * @param preset_chn preset channel
386 * @param select @ref opamp_inp_pad_t
387 */
opamp_preset_inp_pad_select(OPAMP_Type * opamp,uint8_t preset_chn,opamp_inp_pad_t select)388 static inline void opamp_preset_inp_pad_select(OPAMP_Type *opamp, uint8_t preset_chn, opamp_inp_pad_t select)
389 {
390 opamp->CFG[preset_chn].CFG0 = (opamp->CFG[preset_chn].CFG0 & (~OPAMP_CFG_CFG0_VIP_SEL_MASK)) | OPAMP_CFG_CFG0_VIP_SEL_SET(select);
391 }
392
393
394 /**
395 * @brief opamp get current preset
396 *
397 * @param opamp @ref OPAMP_Type
398 * @return value
399 */
opamp_get_cur_preset(OPAMP_Type * opamp)400 static inline uint8_t opamp_get_cur_preset(OPAMP_Type *opamp)
401 {
402 return OPAMP_STATUS_CUR_PRESET_GET(opamp->STATUS);
403 }
404
405 /**
406 * @brief get the current preset value
407 *
408 * @param opamp @ref OPAMP_Type
409 * @return true one of cur_preset is selected for opamp
410 * @return false opamp use cfg0 parameters
411 */
opamp_get_is_preset(OPAMP_Type * opamp)412 static inline bool opamp_get_is_preset(OPAMP_Type *opamp)
413 {
414 return OPAMP_STATUS_PRESET_ACT_GET(opamp->STATUS);
415 }
416
417 /**
418 * @brief Get the trigger conflict status
419 *
420 * @param opamp @ref OPAMP_Type
421 * @return if more than one hardware trigger is set, will put all trigger input there.
422 */
opamp_get_trig_conflict_status(OPAMP_Type * opamp)423 static inline uint8_t opamp_get_trig_conflict_status(OPAMP_Type *opamp)
424 {
425 return OPAMP_STATUS_TRIG_CONFLICT_GET(opamp->STATUS);
426 }
427
428 /**
429 * @brief Clear the trigger conflict status
430 *
431 * @param opamp @ref OPAMP_Type
432 */
opamp_clear_conflict_status(OPAMP_Type * opamp)433 static inline void opamp_clear_conflict_status(OPAMP_Type *opamp)
434 {
435 opamp->STATUS = OPAMP_STATUS_TRIG_CONFLICT_MASK;
436 }
437
438 /**
439 * @brief Set opamp preset value
440 *
441 * @param opamp @ref OPAMP_Type
442 * @param val @ref opamp_cfg_preset_chn_t
443 */
opamp_set_sw_preset_val(OPAMP_Type * opamp,opamp_cfg_preset_chn_t val)444 static inline void opamp_set_sw_preset_val(OPAMP_Type *opamp, opamp_cfg_preset_chn_t val)
445 {
446 opamp->CTRL1 = (opamp->CTRL1 & (~OPAMP_CTRL1_SW_SEL_MASK)) | OPAMP_CTRL1_SW_SEL_SET(val);
447 }
448
449 /**
450 * @brief Enable software preset
451 *
452 * @param opamp @ref OPAMP_Type
453 */
opamp_enable_sw_preset(OPAMP_Type * opamp)454 static inline void opamp_enable_sw_preset(OPAMP_Type *opamp)
455 {
456 opamp->CTRL1 |= OPAMP_CTRL1_SW_PRESET_MASK;
457 }
458
459 /**
460 * @brief Disable software preset
461 *
462 * @param opamp @ref OPAMP_Type
463 */
opamp_disable_sw_preset(OPAMP_Type * opamp)464 static inline void opamp_disable_sw_preset(OPAMP_Type *opamp)
465 {
466 opamp->CTRL1 &= ~OPAMP_CTRL1_SW_PRESET_MASK;
467 }
468
469
470 /**
471 * @brief Set preset x channel value
472 *
473 * @param opamp @ref OPAMP_Type
474 * @param preset_chn preset channel
475 * @param chn channel
476 */
opamp_set_preset_x_chn(OPAMP_Type * opamp,uint8_t preset_chn,uint8_t chn)477 static inline void opamp_set_preset_x_chn(OPAMP_Type *opamp, uint8_t preset_chn, uint8_t chn)
478 {
479 opamp->CFG[preset_chn].CFG2 = OPAMP_CFG_CFG2_CHANNEL_SET(chn);
480 }
481
482 /**
483 * @brief Set preset cfg
484 *
485 * @param opamp @ref OPAMP_Type
486 * @param preset_chn preset channel
487 * @param cfg @ref opamp_cfg_t
488 * @return hpm_stat_t
489 */
490 hpm_stat_t opamp_set_preset_cfg(OPAMP_Type *opamp, uint8_t preset_chn, opamp_cfg_t *cfg);
491
492 /**
493 * @brief opamp enable preset hardware trig
494 *
495 * @param opamp @ref OPAMP_Type
496 * @param preset_chn preset channel
497 */
opamp_preset_enable_hw_trig(OPAMP_Type * opamp,uint8_t preset_chn)498 static inline void opamp_preset_enable_hw_trig(OPAMP_Type *opamp, uint8_t preset_chn)
499 {
500 opamp->CFG[preset_chn].CFG1 |= OPAMP_CFG_CFG1_HW_TRIG_EN_MASK;
501 }
502
503 /**
504 * @brief opamp disable preset hardware trig
505 *
506 * @param opamp @ref OPAMP_Type
507 * @param preset_chn preset channel
508 */
opamp_preset_disable_hw_trig(OPAMP_Type * opamp,uint8_t preset_chn)509 static inline void opamp_preset_disable_hw_trig(OPAMP_Type *opamp, uint8_t preset_chn)
510 {
511 opamp->CFG[preset_chn].CFG1 &= ~OPAMP_CFG_CFG1_HW_TRIG_EN_MASK;
512 }
513
514 /**
515 * @brief opamp set mode
516 *
517 * @param opamp @ref OPAMP_Type
518 * @param mode @ref OPAMP_MODE_XX
519 */
opamp_mode_set(OPAMP_Type * opamp,uint8_t mode)520 static inline void opamp_mode_set(OPAMP_Type *opamp, uint8_t mode)
521 {
522 opamp->CTRL0 = (opamp->CTRL0 & (~OPAMP_CTRL0_MODE_MASK)) | OPAMP_CTRL0_MODE_SET(mode);
523 }
524
525 /**
526 * @brief opamp preset set mode
527 *
528 * @param opamp @ref OPAMP_Type
529 * @param preset_chn preset channel
530 * @param mode @ref OPAMP_MODE_XX
531 */
opamp_preset_mode_set(OPAMP_Type * opamp,uint8_t preset_chn,uint8_t mode)532 static inline void opamp_preset_mode_set(OPAMP_Type *opamp, uint8_t preset_chn, uint8_t mode)
533 {
534 opamp->CFG[preset_chn].CFG1 = (opamp->CFG[preset_chn].CFG1 & (~OPAMP_CFG_CFG1_MODE_MASK)) | OPAMP_CFG_CFG1_MODE_SET(mode);
535 }
536
537 /**
538 * @}
539 *
540 */
541
542 #ifdef __cplusplus
543 }
544 #endif
545
546 #endif /* HPM_ACMP_DRV_H */
547