1 /*
2 * Copyright (c) 2023 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #ifndef HPM_MMC_DRV_H
9 #define HPM_MMC_DRV_H
10
11 #include "hpm_common.h"
12 #include "hpm_mmc_regs.h"
13 /**
14 * @brief MMC driver APIs
15 * @defgroup mmc_interface MMC driver APIs
16 * @ingroup mmc_interfaces
17 * @{
18 */
19
20 /* trigger source to update position parameter */
21 typedef enum {
22 mmc_pos_update_by_timestamp = 0,
23 mmc_pos_update_by_intrgr0_rise_edge = 1,
24 mmc_pos_update_by_intrgr1_rise_edge = 2,
25 mmc_pos_update_by_outtrgr0_rise_edge = 3,
26 mmc_pos_update_by_outtrgr1_rise_edge = 4,
27 mmc_pos_update_by_self_pos_thr = 5,
28 mmc_pos_update_by_self_speed_thr = 6,
29 } mmc_pos_update_trigger_t;
30
31
32 /* cmd mask to update position parameter */
33 typedef enum {
34 mmc_pos_update_none = 0,
35 mmc_pos_update_position = 1 << 0,
36 mmc_pos_update_revolution = 1 << 1,
37 mmc_pos_update_speed = 1 << 2,
38 mmc_pos_update_accel = 1 << 3,
39 mmc_pos_update_all = 0b1111,
40 } mmc_pos_update_cmd_mask_t;
41
42 typedef enum {
43 mmc_coef_not_update = 0,
44 mmc_coef_p_update = 1 << 0,
45 mmc_coef_i_update = 1 << 1,
46 mmc_coef_a_update = 1 << 2,
47 mmc_coef_update_all = 0b111,
48 } mmc_coef_update_cmd_mask_t;
49
50 typedef struct {
51 bool discrete_pos_mode;
52 uint32_t discrete_line;
53 uint32_t continuous_step_thr;
54 uint32_t continuous_circ_thr;
55 uint32_t oosync_theta_thr;
56 } mmc_track_pos_mode_t;
57
58 typedef struct {
59 bool force_accel_to_zero;
60 bool en_ms_coef;
61 bool open_loop_mode;
62 bool pos_16bit_type; /* true for output 16bit position, false for output 32bit position */
63 bool sync_new_pos; /* predictor base new track position data */
64 mmc_track_pos_mode_t pos_mode;
65 } mmc_track_mode_t;
66
67 typedef struct {
68 uint32_t pos_time;
69 uint32_t position;
70 int32_t revolution;
71 double speed;
72 double accel;
73 uint32_t cmd_mask; /*!< cmd to to select which parameters to update */
74 uint32_t trigger; /*!< trigger source for when to update parameters */
75 } mmc_pos_or_delta_pos_input_t;
76
77 typedef struct {
78 uint32_t coef_time;
79 double coef_p;
80 double coef_i;
81 double coef_a;
82 uint32_t cmd_mask; /* cmd to select change which parameter */
83 } mmc_coef_input_t;
84
85 typedef struct {
86 uint32_t err_thr;
87 uint32_t hold_time;
88 double coef_p;
89 double coef_i;
90 double coef_a;
91 } mmc_coef_trig_config_t;
92
93 typedef struct {
94 uint32_t time;
95 uint32_t position;
96 int32_t revolution;
97 double speed;
98 double accel;
99 } mmc_pos_out_t;
100
101 typedef struct {
102 double coef_p;
103 double coef_i;
104 double coef_a;
105 } mmc_coef_out_t;
106
107 /* track event, definition align with interrupt mask and status mask */
108 typedef enum {
109 mmc_track_shadow_read_done = 1 << 0,
110 mmc_track_init_coefs_done = 1 << 1,
111 mmc_track_init_pos_done = 1 << 2,
112 mmc_track_oosync = 1 << 4,
113 mmc_track_idle = 1 << 5, /*!< no corresponding interrupt */
114 mmc_pred1_init_pos_done = 1 << 6,
115 mmc_pred0_init_pos_done = 1 << 7,
116 mmc_track_init_delta_pos_done = 1 << 8,
117 mmc_track_pos_trig_valid = 1 << 9,
118 mmc_track_speed_trig_valid = 1 << 10,
119 } mmc_track_event_t;
120
121 typedef enum {
122 mmc_pred_idle = MMC_BR_BR_ST_IDLE_MASK,
123 mmc_pred_init_delta_pos_done = MMC_BR_BR_ST_INI_DELTA_POS_DONE_MASK,
124 mmc_pred_pos_trig_valid = MMC_BR_BR_ST_POS_TRG_VLD_MASK,
125 mmc_pred_speed_trig_valid = MMC_BR_BR_ST_SPEED_TRG_VLD_MASK,
126 mmc_pred_open_loop = MMC_BR_BR_ST_OPEN_LOOP_ST_MASK,
127 } mmc_pred_event_t;
128
129 typedef enum {
130 mmc_pred_pos_trig_valid_int = MMC_BR_BR_CTRL_POS_TRG_VALID_IE_MASK,
131 mmc_pred_speed_trig_valid_int = MMC_BR_BR_CTRL_SPEED_TRG_VALID_IE_MASK,
132 mmc_pred_init_delta_pos_done_int = MMC_BR_BR_CTRL_INI_DELTA_POS_DONE_IE_MASK
133 } mmc_pred_int_t;
134
135 typedef struct {
136 bool speed_trig_int;
137 bool position_trig_int;
138 bool delta_pos_done_trig_int;
139 bool open_loop_mode;
140 uint8_t pred_mode;
141 uint8_t not_first_pred_trig_type;
142 uint8_t first_pred_trig_type;
143 } mmc_pred_mode_t;
144
145 typedef enum {
146 mmc_pred_not_reload_pos_cmd = 0,
147 mmc_pred_0_reload_pos_cmd = 2,
148 mmc_pred_1_reload_pos_cmd = 1,
149 mmc_pred_both_reload_pos_cmd = 3,
150 } mmc_pred_reload_pos_cmd_t;
151
152 typedef enum {
153 mmc_pred_by_period = 0,
154 mmc_pred_continuously_repeat = 1,
155 mmc_pred_only_once = 2,
156 } mmc_pred_time_t;
157
158 /* using for mmc_pred_by_period mode */
159 typedef struct {
160 uint32_t offset_time;
161 uint32_t period_time;
162 uint32_t first_time;
163 } mmc_pred_period_time_t;
164
165 typedef struct {
166 bool less_than; /*!< true for less than, false for greater than */
167 bool enable;
168 uint32_t position_thr; /*!< position in a cycle */
169 int32_t revolution_thr; /*!< cycle */
170 } mmc_pos_trig_t;
171
172 typedef struct {
173 bool absolute_compare; /*!< true for absolute value compare, false for signed value compare */
174 bool less_than; /*!< true for less than, false for greater than */
175 bool enable;
176 int32_t speed_thr;
177 } mmc_speed_trig_t;
178
179
180 #ifdef __cplusplus
181 extern "C" {
182 #endif
183
184 /**
185 * @brief MMC set frequency
186 * @param [in] base MMC base address
187 * @param [in] freq the moto system freq
188 */
mmc_set_sysclk_freq(MMC_Type * base,uint32_t freq)189 static inline void mmc_set_sysclk_freq(MMC_Type *base, uint32_t freq)
190 {
191 uint32_t period;
192 base->SYSCLK_FREQ = freq;
193 /* 1/freq *(2^24)*(2^20) */
194 period = (uint32_t)((double)(1 << 20) * (1 << 24) / freq);
195 base->SYSCLK_PERIOD = period;
196 }
197
198 /**
199 * @brief MMC software reset
200 * @param [in] base MMC base address
201 */
mmc_software_reset(MMC_Type * base)202 static inline void mmc_software_reset(MMC_Type *base)
203 {
204 base->CR |= MMC_CR_SFTRST_MASK;
205 base->CR &= ~MMC_CR_SFTRST_MASK;
206 }
207
208 /**
209 * @brief MMC module enable
210 * @param [in] base MMC base address
211 */
mmc_enable_module(MMC_Type * base)212 static inline void mmc_enable_module(MMC_Type *base)
213 {
214 base->CR |= MMC_CR_MOD_EN_MASK;
215 }
216
217 /**
218 * @brief MMC module disable
219 * @param [in] base MMC base address
220 */
mmc_disable_module(MMC_Type * base)221 static inline void mmc_disable_module(MMC_Type *base)
222 {
223 base->CR &= ~MMC_CR_MOD_EN_MASK;
224 }
225
226 /**
227 * @brief MMC track set loop mode
228 * @param [in] base MMC base address
229 * @param [in] open_loop true for open loop, false for close loop
230 */
mmc_track_set_open_loop_mode(MMC_Type * base,bool open_loop)231 static inline void mmc_track_set_open_loop_mode(MMC_Type *base, bool open_loop)
232 {
233 if (open_loop) {
234 base->CR |= MMC_CR_OPEN_LOOP_MODE_MASK;
235 } else {
236 base->CR &= ~MMC_CR_OPEN_LOOP_MODE_MASK;
237 }
238 }
239
240 /**
241 * @brief MMC track set adjop mode
242 * @param [in] base MMC base address
243 * @param [in] adjop true for adjop mode, false for normal mode
244 */
mmc_track_set_adjop_mode(MMC_Type * base,bool adjop)245 static inline void mmc_track_set_adjop_mode(MMC_Type *base, bool adjop)
246 {
247 if (adjop) {
248 base->CR |= MMC_CR_ADJOP_MASK;
249 } else {
250 base->CR &= ~MMC_CR_ADJOP_MASK;
251 }
252 }
253
254 /**
255 * @brief MMC track request shadow read
256 * @param [in] base MMC base address
257 *
258 * @note request shadow before read mmc track resoult register
259 */
mmc_track_enable_shadow_read(MMC_Type * base)260 static inline void mmc_track_enable_shadow_read(MMC_Type *base)
261 {
262 base->CR |= MMC_CR_SHADOW_RD_REQ_MASK;
263 /* SHADOW_RD_REQ clear indicates that the shadow is complete */
264 while ((base->CR & MMC_CR_SHADOW_RD_REQ_MASK) == MMC_CR_SHADOW_RD_REQ_MASK) {
265 }
266 }
267
268 /**
269 * @brief MMC track enable interrupt
270 * @param [in] base MMC base address
271 * @param [in] int_mask interrupt_mask @ref mmc_track_event_t
272 */
mmc_track_enable_interrupt(MMC_Type * base,uint32_t int_mask)273 static inline void mmc_track_enable_interrupt(MMC_Type *base, uint32_t int_mask)
274 {
275 base->INT_EN = int_mask;
276 }
277
278 /**
279 * @brief MMC track disable interrupt
280 * @param [in] base MMC base address
281 * @param [in] int_mask interrupt_mask @ref mmc_track_event_t
282 */
mmc_track_disable_interrupt(MMC_Type * base,uint32_t int_mask)283 static inline void mmc_track_disable_interrupt(MMC_Type *base, uint32_t int_mask)
284 {
285 base->INT_EN &= ~int_mask;
286 }
287
288 /**
289 * @brief MMC track get status register value
290 * @param [in] base MMC base address
291 * @retval status register value
292 */
mmc_track_get_status(MMC_Type * base)293 static inline uint32_t mmc_track_get_status(MMC_Type *base)
294 {
295 return base->STA;
296 }
297
298 /**
299 * @brief MMC track clear status flag in status register
300 * @param [in] base MMC base address
301 * @param [in] clr_mask @ref mmc_track_event_t
302 */
mmc_track_clear_status(MMC_Type * base,uint32_t clr_mask)303 static inline void mmc_track_clear_status(MMC_Type *base, uint32_t clr_mask)
304 {
305 base->STA = clr_mask; /* W1C */
306 }
307
308 /**
309 * @brief MMC track set the threshold of theta for out-of-sync
310 * @param [in] base MMC base address
311 * @param [in] threshold threshold value
312 */
mmc_track_set_oosync_theta_threshold(MMC_Type * base,uint32_t threshold)313 static inline void mmc_track_set_oosync_theta_threshold(MMC_Type *base, uint32_t threshold)
314 {
315 base->OOSYNC_THETA_THR = MMC_OOSYNC_THETA_THR_VAL_SET(threshold);
316 }
317
318 /**
319 * @brief MMC track config position mode
320 * @param [in] base MMC base address
321 * @param [in] mode mmc_track_pos_mode_t
322 */
323 void mmc_track_config_pos_mode(MMC_Type *base, mmc_track_pos_mode_t *mode);
324
325 /**
326 * @brief MMC track get default mode config
327 * @param [in] base MMC base address
328 * @param [in] config mmc_track_mode_t
329 */
330 void mmc_track_get_default_mode_config(MMC_Type *base, mmc_track_mode_t *config);
331
332 /**
333 * @brief MMC track config mode
334 * @param [in] base MMC base address
335 * @param [in] config mmc_track_mode_t
336 */
337 void mmc_track_config_mode(MMC_Type *base, mmc_track_mode_t *config);
338
339 /**
340 * @brief MMC track config position parameter
341 * @param [in] base MMC base address
342 * @param [in] para mmc_pos_or_delta_pos_input_t
343 */
344 void mmc_track_config_pos_para(MMC_Type *base, mmc_pos_or_delta_pos_input_t *para);
345
346 /**
347 * @brief MMC track config delta parameter
348 * @param [in] base MMC base address
349 * @param [in] para mmc_pos_or_delta_pos_input_t
350 */
351 void mmc_track_config_delta_para(MMC_Type *base, mmc_pos_or_delta_pos_input_t *para);
352
353 /**
354 * @brief MMC track config coef parameter
355 * @param [in] base MMC base address
356 * @param [in] para mmc_coef_input_t
357 */
358 void mmc_track_config_coef_para(MMC_Type *base, mmc_coef_input_t *para);
359
360 /**
361 * @brief MMC track config position trigger
362 * @param [in] base MMC base address
363 * @param [in] trig mmc_pos_trig_t
364 */
365 void mmc_track_config_position_trig(MMC_Type *base, mmc_pos_trig_t *trig);
366
367 /**
368 * @brief MMC track config speed trigger
369 * @param [in] base MMC base address
370 * @param [in] trig mmc_speed_trig_t
371 */
372 void mmc_track_config_speed_trig(MMC_Type *base, mmc_speed_trig_t *trig);
373
374 /**
375 * @brief MMC track disable position trigger
376 * @param [in] base MMC base address
377 */
mmc_track_disable_position_trig(MMC_Type * base)378 static inline void mmc_track_disable_position_trig(MMC_Type *base)
379 {
380 base->POS_TRG_CFG &= ~MMC_POS_TRG_CFG_EN_MASK;
381 }
382
383 /**
384 * @brief MMC track disable speed trigger
385 * @param [in] base MMC base address
386 */
mmc_track_disable_speed_trig(MMC_Type * base)387 static inline void mmc_track_disable_speed_trig(MMC_Type *base)
388 {
389 base->SPEED_TRG_CFG &= ~MMC_SPEED_TRG_CFG_EN_MASK;
390 }
391
392 /**
393 * @brief MMC track config multiple coef trigger
394 * @param [in] base MMC base address
395 * @param [in] index coef trigger index(0/1/2)
396 * @param [in] config mmc_coef_trig_config_t
397 */
398 void mmc_track_config_coef_trig(MMC_Type *base, uint8_t index, mmc_coef_trig_config_t *config);
399
400 /**
401 * @brief MMC track get result
402 * @param [in] base MMC base address
403 * @param [out] pos_out mmc_pos_out_t
404 * @param [out] coef_out mmc_coef_out_t
405 */
406 void mmc_track_get_result(MMC_Type *base, mmc_pos_out_t *pos_out, mmc_coef_out_t *coef_out);
407
408 /* predictor */
409 /**
410 * @brief MMC enable predictor
411 * @param [in] base MMC base address
412 * @param [in] index predictor index(0/1)
413 */
mmc_enable_pred(MMC_Type * base,uint8_t index)414 static inline void mmc_enable_pred(MMC_Type *base, uint8_t index)
415 {
416 base->BR[index].BR_CTRL |= MMC_BR_BR_CTRL_BR_EN_MASK;
417 }
418
419 /**
420 * @brief MMC disable predictor
421 * @param [in] base MMC base address
422 * @param [in] index predictor index(0/1)
423 */
mmc_disable_pred(MMC_Type * base,uint8_t index)424 static inline void mmc_disable_pred(MMC_Type *base, uint8_t index)
425 {
426 base->BR[index].BR_CTRL &= ~MMC_BR_BR_CTRL_BR_EN_MASK;
427 }
428
429 /**
430 * @brief MMC predictor set loop mode
431 * @param [in] base MMC base address
432 * @param [in] index predictor index(0/1)
433 * @param [in] open_loop true for open loop, false for close loop
434 */
mmc_pred_set_open_loop_mode(MMC_Type * base,uint8_t index,bool open_loop)435 static inline void mmc_pred_set_open_loop_mode(MMC_Type *base, uint8_t index, bool open_loop)
436 {
437 if (open_loop) {
438 base->BR[index].BR_CTRL |= MMC_BR_BR_CTRL_OPEN_LOOP_MODE_MASK;
439 } else {
440 base->BR[index].BR_CTRL &= ~MMC_BR_BR_CTRL_OPEN_LOOP_MODE_MASK;
441 }
442 }
443
444 /**
445 * @brief MMC predictor set pred time
446 * @param [in] base MMC base address
447 * @param [in] index predictor index(0/1)
448 * @param [in] time mmc_pred_time_t
449 */
mmc_pred_set_pred_time(MMC_Type * base,uint8_t index,mmc_pred_time_t time)450 static inline void mmc_pred_set_pred_time(MMC_Type *base, uint8_t index, mmc_pred_time_t time)
451 {
452 base->BR[index].BR_CTRL &= ~MMC_BR_BR_CTRL_PRED_MODE_MASK;
453 base->BR[index].BR_CTRL |= MMC_BR_BR_CTRL_PRED_MODE_SET(time);
454 }
455
456 /**
457 * @brief MMC pred enable interrupt
458 * @param [in] base MMC base address
459 * @param [in] index predictor index(0/1)
460 * @param [in] int_mask interrupt_mask @ref mmc_pred_int_t
461 */
mmc_pred_enable_interrupt(MMC_Type * base,uint8_t index,uint32_t int_mask)462 static inline void mmc_pred_enable_interrupt(MMC_Type *base, uint8_t index, uint32_t int_mask)
463 {
464 base->BR[index].BR_CTRL |= int_mask;
465 }
466
467 /**
468 * @brief MMC pred disable interrupt
469 * @param [in] base MMC base address
470 * @param [in] index predictor index(0/1)
471 * @param [in] int_mask interrupt_mask @ref mmc_pred_int_t
472 */
mmc_pred_disable_interrupt(MMC_Type * base,uint8_t index,uint32_t int_mask)473 static inline void mmc_pred_disable_interrupt(MMC_Type *base, uint8_t index, uint32_t int_mask)
474 {
475 base->BR[index].BR_CTRL &= ~int_mask;
476 }
477
478 /**
479 * @brief MMC predictor get status register value
480 * @param [in] base MMC base address
481 * @param [in] index predictor index(0/1)
482 * @retval predictor status register value
483 */
mmc_pred_get_status(MMC_Type * base,uint8_t index)484 static inline uint32_t mmc_pred_get_status(MMC_Type *base, uint8_t index)
485 {
486 return base->BR[index].BR_ST;
487 }
488
489 /**
490 * @brief MMC predictor clear status bit in reigster
491 * @param [in] base MMC base address
492 * @param [in] index predictor index(0/1)
493 * @param [in] clr_mask bit mask @ref mmc_pred_event_t
494 */
mmc_pred_clear_status(MMC_Type * base,uint8_t index,uint32_t clr_mask)495 static inline void mmc_pred_clear_status(MMC_Type *base, uint8_t index, uint32_t clr_mask)
496 {
497 base->BR[index].BR_ST = clr_mask; /*!< W1C */
498 }
499
500 /**
501 * @brief MMC predictor get default mode config
502 * @param [in] base MMC base address
503 * @param [in] config mmc_pred_mode_t
504 */
505 void mmc_pred_get_default_mode_config(MMC_Type *base, mmc_pred_mode_t *config);
506
507 /**
508 * @brief MMC predictor config mode
509 * @param [in] base MMC base address
510 * @param [in] index predictor index(0/1)
511 * @param [in] config mmc_pred_mode_t
512 */
513 void mmc_pred_config_mode(MMC_Type *base, uint8_t index, mmc_pred_mode_t *config);
514
515 /**
516 * @brief MMC predictor config position parameter
517 * @param [in] base MMC base address
518 * @param [in] index predictor index(0/1)
519 * @param [in] para mmc_pos_or_delta_pos_input_t
520 * @param [in] req_reload request to update parameter cmd
521 *
522 * @note 2 predictors can be set simultaneously by call mmc_pred_reload_pos_cmd()
523 */
524 void mmc_pred_config_pos_para(MMC_Type *base, uint8_t index, mmc_pos_or_delta_pos_input_t *para, bool req_reload);
525
526 /**
527 * @brief MMC predictor reload position parameter cmd
528 * @param [in] base MMC base address
529 * @param [in] cmd mmc_pred_reload_pos_cmd_t
530 */
mmc_pred_reload_pos_cmd(MMC_Type * base,mmc_pred_reload_pos_cmd_t cmd)531 static inline void mmc_pred_reload_pos_cmd(MMC_Type *base, mmc_pred_reload_pos_cmd_t cmd)
532 {
533 base->CR &= ~(MMC_CR_INI_BR0_POS_REQ_MASK | MMC_CR_INI_BR0_POS_REQ_MASK);
534 base->CR |= cmd << MMC_CR_INI_BR1_POS_REQ_SHIFT;
535 }
536
537 /**
538 * @brief MMC predictor update delta parameter
539 * @param [in] base MMC base address
540 * @param [in] index predictor index(0/1)
541 * @param [in] para mmc_pos_or_delta_pos_input_t
542 */
543 void mmc_pred_config_delta_para(MMC_Type *base, uint8_t index, mmc_pos_or_delta_pos_input_t *para);
544
545 /**
546 * @brief MMC predictor config period time
547 * @param [in] base MMC base address
548 * @param [in] index predictor index(0/1)
549 * @param [in] time mmc_pred_period_time_t
550 */
551 void mmc_pred_config_period_time(MMC_Type *base, uint8_t index, mmc_pred_period_time_t *time);
552
553 /**
554 * @brief MMC predictor config position trigger
555 * @param [in] base MMC base address
556 * @param [in] index predictor index(0/1)
557 * @param [in] trig mmc_pos_trig_t
558 */
559 void mmc_pred_config_position_trig(MMC_Type *base, uint8_t index, mmc_pos_trig_t *trig);
560
561 /**
562 * @brief MMC predictor config speed trigger
563 * @param [in] base MMC base address
564 * @param [in] index predictor index(0/1)
565 * @param [in] trig mmc_speed_trig_t
566 */
567 void mmc_pred_config_speed_trig(MMC_Type *base, uint8_t index, mmc_speed_trig_t *trig);
568
569 /**
570 * @brief MMC predictor disable position trigger
571 * @param [in] base MMC base address
572 * @param [in] index predictor index(0/1)
573 */
mmc_pred_disable_position_trig(MMC_Type * base,uint8_t index)574 static inline void mmc_pred_disable_position_trig(MMC_Type *base, uint8_t index)
575 {
576 base->BR[index].BR_TRG_POS_CFG &= ~MMC_BR_BR_TRG_POS_CFG_EN_MASK;
577 }
578
579 /**
580 * @brief MMC predictor disable speed trigger
581 * @param [in] base MMC base address
582 * @param [in] index predictor index(0/1)
583 */
mmc_pred_disable_speed_trig(MMC_Type * base,uint8_t index)584 static inline void mmc_pred_disable_speed_trig(MMC_Type *base, uint8_t index)
585 {
586 base->BR[index].BR_TRG_SPEED_CFG &= ~MMC_BR_BR_TRG_SPEED_CFG_EN_MASK;
587 }
588
589 /**
590 * @brief MMC predictor get result
591 * @param [in] base MMC base address
592 * @param [in] index predictor index(0/1)
593 * @param [out] pos_out mmc_pos_out_t
594 */
595 void mmc_pred_get_result(MMC_Type *base, uint8_t index, mmc_pos_out_t *pos_out);
596
597 /**
598 * @brief MMC predictor get result
599 * @param [in] base MMC base address
600 * @param [out] para mmc_pos_or_delta_pos_input_t
601 */
602 void mmc_get_default_pos_or_delta_pos_para(MMC_Type *base, mmc_pos_or_delta_pos_input_t *para);
603
604
605 #ifdef __cplusplus
606 }
607 #endif
608 /**
609 * @}
610 */
611 #endif /* HPM_MMC_DRV_H */
612