1 /*
2  * Copyright (c) 2024 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #ifndef HPM_CLC_DRV_H
9 #define HPM_CLC_DRV_H
10 
11 #include "hpm_common.h"
12 #include "hpm_clc_regs.h"
13 
14 /**
15  * @brief CLC driver APIs
16  * @defgroup clc_interface CLC driver APIs
17  * @ingroup motor_interfaces
18  * @{
19  */
20 
21 /**
22  * @brief clc channel
23  */
24 typedef enum {
25     clc_vd_chn = CLC_VDVQ_CHAN_VD,
26     clc_vq_chn = CLC_VDVQ_CHAN_VQ,
27 } clc_chn_t; /**< clc_chn_t */
28 
29 /**
30  * @brief clc coefficient zone
31  */
32 typedef enum {
33     clc_coeff_zone_0 = CLC_COEFF_0,
34     clc_coeff_zone_1 = CLC_COEFF_1,
35     clc_coeff_zone_2 = CLC_COEFF_2,
36 } clc_coeff_zone_t; /**< clc_coeff_zone_t */
37 
38 /**
39  * @brief clc irq mask bit
40  */
41 typedef enum {
42     clc_irq_calc_done = BIT0_MASK,
43     clc_irq_eadc_setting_err = BIT1_MASK,
44     clc_irq_2p2z_clamp_setting_err = BIT2_MASK,
45     clc_irq_2p2z_over_hi = BIT3_MASK,
46     clc_irq_2p2z_over_lo = BIT4_MASK,
47     clc_irq_2p2z_over_sf = BIT5_MASK,
48     clc_irq_3p3z_clamp_setting_err = BIT6_MASK,
49     clc_irq_3p3z_over_hi = BIT7_MASK,
50     clc_irq_3p3z_over_lo = BIT8_MASK,
51     clc_irq_forb_setting_err = BIT9_MASK,
52     clc_irq_data_in_forbid = BIT10_MASK
53 } clc_irq_mask_t;
54 
55 /**
56  * @brief clc parameter configuration
57  */
58 typedef struct {
59     int32_t eadc_lowth;
60     int32_t eadc_mid_lowth;
61     int32_t eadc_mid_highth;
62     int32_t eadc_highth;
63     int32_t _2p2z_clamp_lowth;
64     int32_t _2p2z_clamp_highth;
65     int32_t _3p3z_clamp_lowth;
66     int32_t _3p3z_clamp_highth;
67     int32_t output_forbid_lowth;
68     int32_t output_forbid_mid;
69     int32_t output_forbid_highth;
70 } clc_param_config_t;   /**< clc_param_config_t */
71 
72 /**
73  * @brief clc coefficient configuration
74  */
75 typedef struct {
76     float b0;
77     float b1;
78     float b2;
79     float b3;
80     float a0;
81     float a1;
82     float a2;
83 } clc_coeff_config_t;   /**< clc_coeff_config_t */
84 
85 #ifdef __cplusplus
86 extern "C" {
87 #endif
88 
89 /**
90  * @brief CLC enable or disable
91  *
92  * @param[in] clc CLC base address
93  * @param[in] chn CLC channel, @ref clc_chn_t
94  * @param[in] enable true-enable, false-disable
95  */
clc_set_enable(CLC_Type * clc,clc_chn_t chn,bool enable)96 static inline void clc_set_enable(CLC_Type *clc, clc_chn_t chn, bool enable)
97 {
98     if (enable) {
99         clc->VDVQ_CHAN[chn].MODE |= CLC_VDVQ_CHAN_MODE_ENABLE_CLC_MASK;
100     } else {
101         clc->VDVQ_CHAN[chn].MODE &= ~CLC_VDVQ_CHAN_MODE_ENABLE_CLC_MASK;
102     }
103 }
104 
105 /**
106  * @brief CLC keep working even if bad irq status ocurred
107  *
108  * @param[in] clc CLC base address
109  * @param[in] chn CLC channel, @ref clc_chn_t
110  * @param[in] enable true-enable, false-disable
111  */
clc_set_mask_mode_enable(CLC_Type * clc,clc_chn_t chn,bool enable)112 static inline void clc_set_mask_mode_enable(CLC_Type *clc, clc_chn_t chn, bool enable)
113 {
114     if (enable) {
115         clc->VDVQ_CHAN[chn].MODE |= CLC_VDVQ_CHAN_MODE_MASK_MODE_MASK;
116     } else {
117         clc->VDVQ_CHAN[chn].MODE &= ~CLC_VDVQ_CHAN_MODE_MASK_MODE_MASK;
118     }
119 }
120 
121 /**
122  * @brief CLC set software inject dq work mode
123  *
124  * @param[in] clc CLC base address
125  * @param[in] chn CLC channel, @ref clc_chn_t
126  * @param[in] enable true-if the ADC value comes from software injection and the VD/VQ channel is required for joint use.
127  */
clc_set_sw_inject_dq_mode_enable(CLC_Type * clc,clc_chn_t chn,bool enable)128 static inline void clc_set_sw_inject_dq_mode_enable(CLC_Type *clc, clc_chn_t chn, bool enable)
129 {
130     if (enable) {
131         clc->VDVQ_CHAN[chn].MODE |= CLC_VDVQ_CHAN_MODE_DQ_MODE_MASK;
132     } else {
133         clc->VDVQ_CHAN[chn].MODE &= ~CLC_VDVQ_CHAN_MODE_DQ_MODE_MASK;
134     }
135 }
136 
137 /**
138  * @brief CLC set irq enable or disable
139  * @param[in] clc CLC base address
140  * @param[in] chn CLC channel, @ref clc_chn_t
141  * @param[in] irq_mask irq mask, @ref clc_irq_mask_t
142  * @param[in] enable enable or disable
143  *  @arg true enable
144  *  @arg false disable
145  */
clc_set_irq_enable(CLC_Type * clc,clc_chn_t chn,uint32_t irq_mask,bool enable)146 static inline void clc_set_irq_enable(CLC_Type *clc, clc_chn_t chn, uint32_t irq_mask, bool enable)
147 {
148     if (enable) {
149         clc->VDVQ_CHAN[chn].MODE |= CLC_VDVQ_CHAN_MODE_ENABLE_IRQ_SET(irq_mask);
150     } else {
151         clc->VDVQ_CHAN[chn].MODE &= ~CLC_VDVQ_CHAN_MODE_ENABLE_IRQ_SET(irq_mask);
152     }
153 }
154 
155 /**
156  * @brief CLC get irq status
157  * @param[in] clc CLC base address
158  * @param[in] chn CLC channel, @ref clc_chn_t
159 
160  * @retval irq status.
161  */
clc_get_irq_status(CLC_Type * clc,clc_chn_t chn)162 static inline uint32_t clc_get_irq_status(CLC_Type *clc, clc_chn_t chn)
163 {
164     return CLC_VDVQ_CHAN_STATUS_STATUS_GET(clc->VDVQ_CHAN[chn].STATUS);
165 }
166 
167 /**
168  * @brief CLC clear irq status
169  * @param[in] clc CLC base address
170  * @param[in] chn CLC channel, @ref clc_chn_t
171  * @param[in] irq_mask irq mask, @ref clc_irq_mask_t
172  */
clc_clear_irq_status(CLC_Type * clc,clc_chn_t chn,uint32_t irq_mask)173 static inline void clc_clear_irq_status(CLC_Type *clc, clc_chn_t chn, uint32_t irq_mask)
174 {
175     clc->VDVQ_CHAN[chn].STATUS = CLC_VDVQ_CHAN_STATUS_STATUS_SET(irq_mask);
176 }
177 
178 /**
179  * @brief CLC check irq request flag
180  * @param[in] clc CLC base address
181  * @param[in] chn CLC channel, @ref clc_chn_t
182  * @param[in] irq_mask irq mask, @ref clc_irq_mask_t
183 
184  * @retval true-has irq req, false-no irq req.
185  */
clc_get_irq_flag(CLC_Type * clc,clc_chn_t chn,uint32_t irq_mask)186 static inline bool clc_get_irq_flag(CLC_Type *clc, clc_chn_t chn, uint32_t irq_mask)
187 {
188     return ((clc->VDVQ_CHAN[chn].STATUS & irq_mask) == irq_mask) ? true : false;
189 }
190 
191 /**
192  * @brief CLC set adc channel
193  * @param[in] clc CLC base address
194  * @param[in] chn CLC channel, @ref clc_chn_t
195  * @param[in] adc_chn adc channel for ADC0~3 or SDM_ADC0~7, adc from VSC must be set to 0.
196  * @param[in] adc_offset adc offset for ADC0~3 or SDM_ADC0~7, adc from VSC must be set to 0.
197  */
clc_set_adc_chn_offset(CLC_Type * clc,clc_chn_t chn,uint32_t adc_chn,uint32_t adc_offset)198 static inline void clc_set_adc_chn_offset(CLC_Type *clc, clc_chn_t chn, uint32_t adc_chn, uint32_t adc_offset)
199 {
200     clc->VDVQ_CHAN[chn].ADC_CHAN = adc_chn;
201     clc->VDVQ_CHAN[chn].ADC_OFFSET = adc_offset;
202 }
203 
204 /**
205  * @brief CLC set pwm period
206  * @param[in] clc CLC base address
207  * @param[in] chn CLC channel, @ref clc_chn_t
208  * @param[in] pwm_period 0-clc dac output pwm duty ratio, else-clc dac output pwm period, number of clock cycles.
209  */
clc_set_pwm_period(CLC_Type * clc,clc_chn_t chn,uint32_t pwm_period)210 static inline void clc_set_pwm_period(CLC_Type *clc, clc_chn_t chn, uint32_t pwm_period)
211 {
212     clc->VDVQ_CHAN[chn].PWM_PERIOD = pwm_period;
213 }
214 
215 /**
216  * @brief CLC set pwm period
217  * @param[in] clc CLC base address
218  * @param[in] chn CLC channel, @ref clc_chn_t
219  * @retval pwm period
220  */
clc_get_pwm_period(CLC_Type * clc,clc_chn_t chn)221 static inline uint32_t clc_get_pwm_period(CLC_Type *clc, clc_chn_t chn)
222 {
223     return clc->VDVQ_CHAN[chn].PWM_PERIOD;
224 }
225 
226 /**
227  * @brief CLC get output caculated value
228  * @param[in] clc CLC base address
229  * @param[in] chn CLC channel, @ref clc_chn_t
230  * @retval CLC output caculated value
231  */
clc_get_output_value(CLC_Type * clc,clc_chn_t chn)232 static inline uint32_t clc_get_output_value(CLC_Type *clc, clc_chn_t chn)
233 {
234     return clc->VDVQ_CHAN[chn].OUTPUT_VALUE;
235 }
236 
237 /**
238  * @brief CLC get timestamp
239  * @param[in] clc CLC base address
240  * @param[in] chn CLC channel, @ref clc_chn_t
241  * @retval CLC adc timestamp
242  */
clc_get_timestamp(CLC_Type * clc,clc_chn_t chn)243 static inline uint32_t clc_get_timestamp(CLC_Type *clc, clc_chn_t chn)
244 {
245     return clc->VDVQ_CHAN[chn].TIMESTAMP;
246 }
247 
248 /**
249  * @brief CLC get error adc latest value
250  * @param[in] clc CLC base address
251  * @param[in] chn CLC channel, @ref clc_chn_t
252  * @retval CLC error adc latest value
253  */
clc_get_eadc_current_value(CLC_Type * clc,clc_chn_t chn)254 static inline int32_t clc_get_eadc_current_value(CLC_Type *clc, clc_chn_t chn)
255 {
256     return (int32_t)clc->VDVQ_CHAN[chn].EADC_CURR;
257 }
258 
259 /**
260  * @brief CLC get error adc previous0 value
261  * @param[in] clc CLC base address
262  * @param[in] chn CLC channel, @ref clc_chn_t
263  * @retval CLC error adc previous0 value
264  */
clc_get_eadc_previous0_value(CLC_Type * clc,clc_chn_t chn)265 static inline int32_t clc_get_eadc_previous0_value(CLC_Type *clc, clc_chn_t chn)
266 {
267     return (int32_t)clc->VDVQ_CHAN[chn].EADC_PRE0;
268 }
269 
270 /**
271  * @brief CLC software inject error adc previous0 value
272  * @param[in] clc CLC base address
273  * @param[in] chn CLC channel, @ref clc_chn_t
274  * @param[in] value CLC error adc previous0 value
275  */
clc_sw_inject_eadc_previous0_value(CLC_Type * clc,clc_chn_t chn,int32_t value)276 static inline void clc_sw_inject_eadc_previous0_value(CLC_Type *clc, clc_chn_t chn, int32_t value)
277 {
278     clc->VDVQ_CHAN[chn].EADC_PRE0 = (uint32_t)value;
279 }
280 
281 /**
282  * @brief CLC get error adc previous1 value
283  * @param[in] clc CLC base address
284  * @param[in] chn CLC channel, @ref clc_chn_t
285  * @retval CLC error adc previous1 value
286  */
clc_get_eadc_previous1_value(CLC_Type * clc,clc_chn_t chn)287 static inline int32_t clc_get_eadc_previous1_value(CLC_Type *clc, clc_chn_t chn)
288 {
289     return (int32_t)clc->VDVQ_CHAN[chn].EADC_PRE1;
290 }
291 
292 /**
293  * @brief CLC software inject error adc previous1 value
294  * @param[in] clc CLC base address
295  * @param[in] chn CLC channel, @ref clc_chn_t
296  * @param[in] value CLC error adc previous1 value
297  */
clc_sw_inject_eadc_previous1_value(CLC_Type * clc,clc_chn_t chn,int32_t value)298 static inline void clc_sw_inject_eadc_previous1_value(CLC_Type *clc, clc_chn_t chn, int32_t value)
299 {
300     clc->VDVQ_CHAN[chn].EADC_PRE1 = (uint32_t)value;
301 }
302 
303 /**
304  * @brief CLC get 2p2z last value
305  * @param[in] clc CLC base address
306  * @param[in] chn CLC channel, @ref clc_chn_t
307  * @retval CLC 2p2z last value
308  */
clc_get_2p2z_current_value(CLC_Type * clc,clc_chn_t chn)309 static inline int32_t clc_get_2p2z_current_value(CLC_Type *clc, clc_chn_t chn)
310 {
311     return (int32_t)clc->VDVQ_CHAN[chn].P2Z2_CURR;
312 }
313 
314 /**
315  * @brief CLC software inject 2p2z last value
316  * @param[in] clc CLC base address
317  * @param[in] chn CLC channel, @ref clc_chn_t
318  * @param[in] value CLC 2p2z last value
319  */
clc_sw_inject_2p2z_current_value(CLC_Type * clc,clc_chn_t chn,int32_t value)320 static inline void clc_sw_inject_2p2z_current_value(CLC_Type *clc, clc_chn_t chn, int32_t value)
321 {
322     clc->VDVQ_CHAN[chn].P2Z2_CURR = (uint32_t)value;
323 }
324 
325 /**
326  * @brief CLC get 2p2z previous0 value
327  * @param[in] clc CLC base address
328  * @param[in] chn CLC channel, @ref clc_chn_t
329  * @retval CLC 2p2z previous0 value
330  */
clc_get_2p2z_previous0_value(CLC_Type * clc,clc_chn_t chn)331 static inline int32_t clc_get_2p2z_previous0_value(CLC_Type *clc, clc_chn_t chn)
332 {
333     return (int32_t)clc->VDVQ_CHAN[chn].P2Z2_PRE0;
334 }
335 
336 /**
337  * @brief CLC software inject 2p2z previous0 value
338  * @param[in] clc CLC base address
339  * @param[in] chn CLC channel, @ref clc_chn_t
340  * @param[in] value CLC 2p2z previous0 value
341  */
clc_sw_inject_2p2z_previous0_value(CLC_Type * clc,clc_chn_t chn,int32_t value)342 static inline void clc_sw_inject_2p2z_previous0_value(CLC_Type *clc, clc_chn_t chn, int32_t value)
343 {
344     clc->VDVQ_CHAN[chn].P2Z2_PRE0 = (uint32_t)value;
345 }
346 
347 /**
348  * @brief CLC get 3p3z last value
349  * @param[in] clc CLC base address
350  * @param[in] chn CLC channel, @ref clc_chn_t
351  * @retval CLC 3p3z last value
352  */
clc_get_3p3z_current_value(CLC_Type * clc,clc_chn_t chn)353 static inline int32_t clc_get_3p3z_current_value(CLC_Type *clc, clc_chn_t chn)
354 {
355     return (int32_t)clc->VDVQ_CHAN[chn].P3Z3_CURR;
356 }
357 
358 /**
359  * @brief CLC software inject 3p3z last value
360  * @param[in] clc CLC base address
361  * @param[in] chn CLC channel, @ref clc_chn_t
362  * @param[in] value CLC 3p3z last value
363  */
clc_sw_inject_3p3z_current_value(CLC_Type * clc,clc_chn_t chn,int32_t value)364 static inline void clc_sw_inject_3p3z_current_value(CLC_Type *clc, clc_chn_t chn, int32_t value)
365 {
366     clc->VDVQ_CHAN[chn].P3Z3_CURR = (uint32_t)value;
367 }
368 
369 /**
370  * @brief CLC set expected adc value
371  * @param[in] clc CLC base address
372  * @param[in] chn CLC channel, @ref clc_chn_t
373  * @param[in] expect expected adc value
374  */
clc_set_expect_adc_value(CLC_Type * clc,clc_chn_t chn,int32_t expect)375 static inline void clc_set_expect_adc_value(CLC_Type *clc, clc_chn_t chn, int32_t expect)
376 {
377     clc->VDVQ_CHAN[chn].ADC_EXPECT = (uint32_t)expect;
378 }
379 
380 /**
381  * @brief CLC software inject adc value. If it's not dq mode, this will trig clc calculation.
382  * @param[in] clc CLC base address
383  * @param[in] chn CLC channel, @ref clc_chn_t
384  * @param[in] value CLC adc value
385  */
clc_sw_inject_adc_value(CLC_Type * clc,clc_chn_t chn,uint32_t value)386 static inline void clc_sw_inject_adc_value(CLC_Type *clc, clc_chn_t chn, uint32_t value)
387 {
388     clc->VDVQ_CHAN[chn].ADC_SW = value;
389 }
390 
391 /**
392  * @brief CLC set software inject dq adc value ready, this will trig clc calculation.
393  * @param[in] clc CLC base address
394  */
clc_set_sw_inject_dq_adc_value_ready(CLC_Type * clc)395 static inline void clc_set_sw_inject_dq_adc_value_ready(CLC_Type *clc)
396 {
397     clc->DQ_ADC_SW_READY = CLC_DQ_ADC_SW_READY_DQ_ADC_SW_READY_MASK;
398 }
399 
400 /**
401  * @brief CLC parameter configuration
402  * @param[in] clc CLC base address
403  * @param[in] chn CLC channel, @ref clc_chn_t
404  * @param[in] param @ref clc_param_config_t.
405  */
406 void clc_config_param(CLC_Type *clc, clc_chn_t chn, clc_param_config_t *param);
407 
408 /**
409  * @brief CLC coefficient configuration
410  * @param[in] clc CLC base address
411  * @param[in] chn CLC channel, @ref clc_chn_t
412  * @param[in] zone CLC coefficient zone, @ref clc_coeff_zone_t
413  * @param[in] coeff @ref clc_param_config_t.
414  *
415  * @retval status_invalid_argument some parameters are invalid
416  * @retval status_success operation is successful
417  */
418 hpm_stat_t clc_config_coeff(CLC_Type *clc, clc_chn_t chn, clc_coeff_zone_t zone, clc_coeff_config_t *coeff);
419 
420 /**
421  * @brief CLC software inject dq adc value
422  * @param[in] clc CLC base address
423  * @param[in] d_value CLC d adc value
424  * @param[in] q_value CLC q adc value
425  */
426 void clc_sw_inject_dq_adc_value(CLC_Type *clc, uint32_t d_value, uint32_t q_value);
427 
428 
429 #ifdef __cplusplus
430 }
431 #endif
432 /**
433  * @}
434  */
435 #endif /* HPM_CLC_DRV_H */
436