1 /* --COPYRIGHT--,BSD
2  * Copyright (c) 2017, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  * --/COPYRIGHT--*/
32 /* Standard Includes */
33 #include <stdint.h>
34 
35 /* DriverLib Includes */
36 #include <ti/devices/msp432p4xx/driverlib/pcm.h>
37 #include <ti/devices/msp432p4xx/driverlib/debug.h>
38 #include <ti/devices/msp432p4xx/driverlib/interrupt.h>
39 #include <ti/devices/msp432p4xx/driverlib/wdt_a.h>
40 #include <ti/devices/msp432p4xx/driverlib/rtc_c.h>
41 #include <ti/devices/msp432p4xx/driverlib/cpu.h>
42 
__PCM_setCoreVoltageLevelAdvanced(uint_fast8_t voltageLevel,uint32_t timeOut,bool blocking)43 static bool __PCM_setCoreVoltageLevelAdvanced(uint_fast8_t voltageLevel,
44         uint32_t timeOut, bool blocking)
45 {
46     uint8_t powerMode, bCurrentVoltageLevel;
47     uint32_t regValue;
48     bool boolTimeout;
49 
50     ASSERT(voltageLevel == PCM_VCORE0 || voltageLevel == PCM_VCORE1);
51 
52     /* Getting current power mode and level */
53     powerMode = PCM_getPowerMode();
54     bCurrentVoltageLevel = PCM_getCoreVoltageLevel();
55 
56     boolTimeout = timeOut > 0 ? true : false;
57 
58     /* If we are already at the power mode they requested, return */
59     if (bCurrentVoltageLevel == voltageLevel)
60         return true;
61 
62     while (bCurrentVoltageLevel != voltageLevel)
63     {
64         regValue = PCM->CTL0;
65 
66         switch (PCM_getPowerState())
67         {
68         case PCM_AM_LF_VCORE1:
69         case PCM_AM_DCDC_VCORE1:
70         case PCM_AM_LDO_VCORE0:
71             PCM->CTL0 = (PCM_KEY | (PCM_AM_LDO_VCORE1)
72                     | (regValue & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
73             break;
74         case PCM_AM_LF_VCORE0:
75         case PCM_AM_DCDC_VCORE0:
76         case PCM_AM_LDO_VCORE1:
77             PCM->CTL0 = (PCM_KEY | (PCM_AM_LDO_VCORE0)
78                     | (regValue & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
79             break;
80         default:
81             ASSERT(false);
82         }
83 
84         if(blocking)
85         {
86             while (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS))
87             {
88                 if (boolTimeout && !(--timeOut))
89                     return false;
90 
91             }
92         }
93         else
94         {
95             return true;
96         }
97 
98         bCurrentVoltageLevel = PCM_getCoreVoltageLevel();
99     }
100 
101     /* Changing the power mode if we are stuck in LDO mode */
102     if (powerMode != PCM_getPowerMode())
103     {
104         if (powerMode == PCM_DCDC_MODE)
105             return PCM_setPowerMode(PCM_DCDC_MODE);
106         else
107             return PCM_setPowerMode(PCM_LF_MODE);
108     }
109 
110     return true;
111 
112 }
113 
114 
PCM_setCoreVoltageLevel(uint_fast8_t voltageLevel)115 bool PCM_setCoreVoltageLevel(uint_fast8_t voltageLevel)
116 {
117     return __PCM_setCoreVoltageLevelAdvanced(voltageLevel, 0, true);
118 }
119 
PCM_setCoreVoltageLevelWithTimeout(uint_fast8_t voltageLevel,uint32_t timeOut)120 bool PCM_setCoreVoltageLevelWithTimeout(uint_fast8_t voltageLevel,
121         uint32_t timeOut)
122 {
123     return __PCM_setCoreVoltageLevelAdvanced(voltageLevel, timeOut, true);
124 }
125 
PCM_setCoreVoltageLevelNonBlocking(uint_fast8_t voltageLevel)126 bool PCM_setCoreVoltageLevelNonBlocking(uint_fast8_t voltageLevel)
127 {
128     return __PCM_setCoreVoltageLevelAdvanced(voltageLevel, 0, false);
129 }
130 
PCM_getPowerMode(void)131 uint8_t PCM_getPowerMode(void)
132 {
133     uint8_t currentPowerState;
134 
135     currentPowerState = PCM_getPowerState();
136 
137     switch (currentPowerState)
138     {
139     case PCM_AM_LDO_VCORE0:
140     case PCM_AM_LDO_VCORE1:
141     case PCM_LPM0_LDO_VCORE0:
142     case PCM_LPM0_LDO_VCORE1:
143         return PCM_LDO_MODE;
144     case PCM_AM_DCDC_VCORE0:
145     case PCM_AM_DCDC_VCORE1:
146     case PCM_LPM0_DCDC_VCORE0:
147     case PCM_LPM0_DCDC_VCORE1:
148         return PCM_DCDC_MODE;
149     case PCM_LPM0_LF_VCORE0:
150     case PCM_LPM0_LF_VCORE1:
151     case PCM_AM_LF_VCORE1:
152     case PCM_AM_LF_VCORE0:
153         return PCM_LF_MODE;
154     default:
155         ASSERT(false);
156         return false;
157 
158     }
159 }
160 
PCM_getCoreVoltageLevel(void)161 uint8_t PCM_getCoreVoltageLevel(void)
162 {
163     uint8_t currentPowerState = PCM_getPowerState();
164 
165     switch (currentPowerState)
166     {
167     case PCM_AM_LDO_VCORE0:
168     case PCM_AM_DCDC_VCORE0:
169     case PCM_AM_LF_VCORE0:
170     case PCM_LPM0_LDO_VCORE0:
171     case PCM_LPM0_DCDC_VCORE0:
172     case PCM_LPM0_LF_VCORE0:
173         return PCM_VCORE0;
174     case PCM_AM_LDO_VCORE1:
175     case PCM_AM_DCDC_VCORE1:
176     case PCM_AM_LF_VCORE1:
177     case PCM_LPM0_LDO_VCORE1:
178     case PCM_LPM0_DCDC_VCORE1:
179     case PCM_LPM0_LF_VCORE1:
180         return PCM_VCORE1;
181     case PCM_LPM3:
182         return PCM_VCORELPM3;
183     default:
184         ASSERT(false);
185         return false;
186 
187     }
188 }
189 
__PCM_setPowerModeAdvanced(uint_fast8_t powerMode,uint32_t timeOut,bool blocking)190 static bool __PCM_setPowerModeAdvanced(uint_fast8_t powerMode, uint32_t timeOut,
191 bool blocking)
192 {
193     uint8_t bCurrentPowerMode, bCurrentPowerState;
194     uint32_t regValue;
195     bool boolTimeout;
196 
197     ASSERT(
198             powerMode == PCM_LDO_MODE || powerMode == PCM_DCDC_MODE
199             || powerMode == PCM_LF_MODE);
200 
201     /* Getting Current Power Mode */
202     bCurrentPowerMode = PCM_getPowerMode();
203 
204     /* If the power mode being set it the same as the current mode, return */
205     if (powerMode == bCurrentPowerMode)
206         return true;
207 
208     bCurrentPowerState = PCM_getPowerState();
209 
210     boolTimeout = timeOut > 0 ? true : false;
211 
212     /* Go through the while loop while we haven't achieved the power mode */
213     while (bCurrentPowerMode != powerMode)
214     {
215         regValue = PCM->CTL0;
216 
217         switch (bCurrentPowerState)
218         {
219         case PCM_AM_DCDC_VCORE0:
220         case PCM_AM_LF_VCORE0:
221             PCM->CTL0 = (PCM_KEY | PCM_AM_LDO_VCORE0
222                     | (regValue & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
223             break;
224         case PCM_AM_LF_VCORE1:
225         case PCM_AM_DCDC_VCORE1:
226             PCM->CTL0 = (PCM_KEY | PCM_AM_LDO_VCORE1
227                     | (regValue & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
228             break;
229         case PCM_AM_LDO_VCORE1:
230         {
231             if (powerMode == PCM_DCDC_MODE)
232             {
233                 PCM->CTL0 = (PCM_KEY | PCM_AM_DCDC_VCORE1
234                         | (regValue & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
235             } else if (powerMode == PCM_LF_MODE)
236             {
237                 PCM->CTL0 = (PCM_KEY | PCM_AM_LF_VCORE1
238                         | (regValue & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
239             } else
240                 ASSERT(false);
241 
242             break;
243         }
244         case PCM_AM_LDO_VCORE0:
245         {
246             if (powerMode == PCM_DCDC_MODE)
247             {
248                 PCM->CTL0 = (PCM_KEY | PCM_AM_DCDC_VCORE0
249                         | (regValue & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
250             } else if (powerMode == PCM_LF_MODE)
251             {
252                 PCM->CTL0 = (PCM_KEY | PCM_AM_LF_VCORE0
253                         | (regValue & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
254             } else
255                 ASSERT(false);
256 
257             break;
258         }
259         default:
260             ASSERT(false);
261         }
262 
263         if (blocking)
264         {
265             while (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS))
266             {
267                 if (boolTimeout && !(--timeOut))
268                     return false;
269 
270             }
271         } else
272             return true;
273 
274         bCurrentPowerMode = PCM_getPowerMode();
275         bCurrentPowerState = PCM_getPowerState();
276     }
277 
278     return true;
279 
280 }
281 
PCM_setPowerMode(uint_fast8_t powerMode)282 bool PCM_setPowerMode(uint_fast8_t powerMode)
283 {
284     return __PCM_setPowerModeAdvanced(powerMode, 0, true);
285 }
286 
PCM_setPowerModeNonBlocking(uint_fast8_t powerMode)287 bool PCM_setPowerModeNonBlocking(uint_fast8_t powerMode)
288 {
289     return __PCM_setPowerModeAdvanced(powerMode, 0, false);
290 }
291 
PCM_setPowerModeWithTimeout(uint_fast8_t powerMode,uint32_t timeOut)292 bool PCM_setPowerModeWithTimeout(uint_fast8_t powerMode, uint32_t timeOut)
293 {
294     return __PCM_setPowerModeAdvanced(powerMode, timeOut, true);
295 }
296 
__PCM_setPowerStateAdvanced(uint_fast8_t powerState,uint32_t timeout,bool blocking)297 static bool __PCM_setPowerStateAdvanced(uint_fast8_t powerState,
298         uint32_t timeout,
299         bool blocking)
300 {
301     uint8_t bCurrentPowerState;
302     bCurrentPowerState = PCM_getPowerState();
303 
304     ASSERT(
305             powerState == PCM_AM_LDO_VCORE0 || powerState == PCM_AM_LDO_VCORE1
306             || powerState == PCM_AM_DCDC_VCORE0 || powerState == PCM_AM_DCDC_VCORE1
307             || powerState == PCM_AM_LF_VCORE0 || powerState == PCM_AM_LF_VCORE1
308             || powerState == PCM_LPM0_LDO_VCORE0 || powerState == PCM_LPM0_LDO_VCORE1
309             || powerState == PCM_LPM0_DCDC_VCORE0 || powerState == PCM_LPM0_DCDC_VCORE1
310             || powerState == PCM_LPM3 || powerState == PCM_LPM35_VCORE0
311             || powerState == PCM_LPM45 || powerState == PCM_LPM4);
312 
313     if (bCurrentPowerState == powerState)
314         return true;
315 
316     switch (powerState)
317     {
318     case PCM_AM_LDO_VCORE0:
319         return (__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE0, timeout, blocking)
320                 && __PCM_setPowerModeAdvanced(PCM_LDO_MODE, timeout, blocking));
321     case PCM_AM_LDO_VCORE1:
322         return (__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE1, timeout, blocking)
323                 && __PCM_setPowerModeAdvanced(PCM_LDO_MODE, timeout, blocking));
324     case PCM_AM_DCDC_VCORE0:
325         return (__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE0, timeout, blocking)
326                 && __PCM_setPowerModeAdvanced(PCM_DCDC_MODE, timeout, blocking));
327     case PCM_AM_DCDC_VCORE1:
328         return (__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE1, timeout, blocking)
329                 && __PCM_setPowerModeAdvanced(PCM_DCDC_MODE, timeout, blocking));
330     case PCM_AM_LF_VCORE0:
331         return (__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE0, timeout, blocking)
332                 && __PCM_setPowerModeAdvanced(PCM_LF_MODE, timeout, blocking));
333     case PCM_AM_LF_VCORE1:
334         return (__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE1, timeout, blocking)
335                 && __PCM_setPowerModeAdvanced(PCM_LF_MODE, timeout, blocking));
336     case PCM_LPM0_LDO_VCORE0:
337         if (!__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE0, timeout, blocking)
338                 || !__PCM_setPowerModeAdvanced(PCM_LDO_MODE, timeout, blocking))
339             break;
340         return PCM_gotoLPM0();
341     case PCM_LPM0_LDO_VCORE1:
342         if (!__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE1, timeout, blocking)
343                 || !__PCM_setPowerModeAdvanced(PCM_LDO_MODE, timeout, blocking))
344             break;
345         return PCM_gotoLPM0();
346     case PCM_LPM0_DCDC_VCORE0:
347         if (!__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE0, timeout, blocking)
348                 || !__PCM_setPowerModeAdvanced(PCM_DCDC_MODE, timeout,
349                         blocking))
350             break;
351         return PCM_gotoLPM0();
352     case PCM_LPM0_DCDC_VCORE1:
353         if (!__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE1, timeout, blocking)
354                 || !__PCM_setPowerModeAdvanced(PCM_DCDC_MODE, timeout,
355                         blocking))
356             break;
357         return PCM_gotoLPM0();
358     case PCM_LPM0_LF_VCORE0:
359         if (!__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE0, timeout, blocking)
360                 || !__PCM_setPowerModeAdvanced(PCM_LF_MODE, timeout, blocking))
361             break;
362         return PCM_gotoLPM0();
363     case PCM_LPM0_LF_VCORE1:
364         if (!__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE1, timeout, blocking)
365                 || !__PCM_setPowerModeAdvanced(PCM_LF_MODE, timeout, blocking))
366             break;
367         return PCM_gotoLPM0();
368     case PCM_LPM3:
369         return PCM_gotoLPM3();
370     case PCM_LPM4:
371         return PCM_gotoLPM4();
372     case PCM_LPM45:
373         return PCM_shutdownDevice(PCM_LPM45);
374     case PCM_LPM35_VCORE0:
375         return PCM_shutdownDevice(PCM_LPM35_VCORE0);
376     default:
377         ASSERT(false);
378         return false;
379     }
380 
381     return false;
382 
383 }
384 
PCM_setPowerState(uint_fast8_t powerState)385 bool PCM_setPowerState(uint_fast8_t powerState)
386 {
387     return __PCM_setPowerStateAdvanced(powerState, 0, true);
388 }
389 
PCM_setPowerStateWithTimeout(uint_fast8_t powerState,uint32_t timeout)390 bool PCM_setPowerStateWithTimeout(uint_fast8_t powerState, uint32_t timeout)
391 {
392     return __PCM_setPowerStateAdvanced(powerState, timeout, true);
393 }
394 
PCM_setPowerStateNonBlocking(uint_fast8_t powerState)395 bool PCM_setPowerStateNonBlocking(uint_fast8_t powerState)
396 {
397     return __PCM_setPowerStateAdvanced(powerState, 0, false);
398 }
399 
PCM_shutdownDevice(uint32_t shutdownMode)400 bool PCM_shutdownDevice(uint32_t shutdownMode)
401 {
402     uint32_t shutdownModeBits = (shutdownMode == PCM_LPM45) ?
403             PCM_CTL0_LPMR_12 : PCM_CTL0_LPMR_10;
404 
405     ASSERT(
406             shutdownMode == PCM_SHUTDOWN_PARTIAL
407             || shutdownMode == PCM_SHUTDOWN_COMPLETE);
408 
409     /* If a power transition is occuring, return false */
410     if (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS))
411         return false;
412 
413     /* Initiating the shutdown */
414     SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
415 
416     PCM->CTL0 = (PCM_KEY | shutdownModeBits
417             | (PCM->CTL0 & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_LPMR_MASK)));
418 
419     CPU_wfi();
420 
421     return true;
422 }
423 
PCM_gotoLPM4(void)424 bool PCM_gotoLPM4(void)
425 {
426     /* Disabling RTC_C and WDT_A */
427     WDT_A_holdTimer();
428     RTC_C_holdClock();
429 
430     /* LPM4 is just LPM3 with WDT_A/RTC_C disabled... */
431     return PCM_gotoLPM3();
432 }
433 
PCM_gotoLPM4InterruptSafe(void)434 bool PCM_gotoLPM4InterruptSafe(void)
435 {
436     bool slHappenedCorrect;
437 
438     /* Disabling master interrupts. In Cortex M, if an interrupt is enabled but
439      master interrupts are disabled and a WFI happens the WFI will
440      immediately exit. */
441     Interrupt_disableMaster();
442 
443     slHappenedCorrect = PCM_gotoLPM4();
444 
445     /* Enabling and Disabling Interrupts very quickly so that the
446      processor catches any pending interrupts */
447     Interrupt_enableMaster();
448     Interrupt_disableMaster();
449 
450     return slHappenedCorrect;
451 }
452 
PCM_gotoLPM0(void)453 bool PCM_gotoLPM0(void)
454 {
455     /* If we are in the middle of a state transition, return false */
456     if (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS))
457         return false;
458 
459     SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
460 
461     CPU_wfi();
462 
463     return true;
464 }
465 
PCM_gotoLPM0InterruptSafe(void)466 bool PCM_gotoLPM0InterruptSafe(void)
467 {
468     bool slHappenedCorrect;
469 
470     /* Disabling master interrupts. In Cortex M, if an interrupt is enabled but
471      master interrupts are disabled and a WFI happens the WFI will
472      immediately exit. */
473     Interrupt_disableMaster();
474 
475     slHappenedCorrect = PCM_gotoLPM0();
476 
477     /* Enabling and Disabling Interrupts very quickly so that the
478      processor catches any pending interrupts */
479     Interrupt_enableMaster();
480     Interrupt_disableMaster();
481 
482     return slHappenedCorrect;
483 }
484 
PCM_gotoLPM3(void)485 bool PCM_gotoLPM3(void)
486 {
487     uint_fast8_t bCurrentPowerState;
488     uint_fast8_t currentPowerMode;
489 
490     /* If we are in the middle of a state transition, return false */
491     if (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS))
492         return false;
493 
494     /* If we are in the middle of a shutdown, return false */
495     if ((PCM->CTL0 & PCM_CTL0_LPMR_MASK) == PCM_CTL0_LPMR_10
496             || (PCM->CTL0 & PCM_CTL0_LPMR_MASK) == PCM_CTL0_LPMR_12)
497         return false;
498 
499     currentPowerMode = PCM_getPowerMode();
500     bCurrentPowerState = PCM_getPowerState();
501 
502     if (currentPowerMode == PCM_DCDC_MODE)
503         PCM_setPowerMode(PCM_LDO_MODE);
504 
505     /* Clearing the SDR */
506     PCM->CTL0 = (PCM->CTL0 & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_LPMR_MASK)) | PCM_KEY;
507 
508     /* Setting the sleep deep bit */
509     SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
510 
511     CPU_wfi();
512 
513     SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
514 
515     return PCM_setPowerState(bCurrentPowerState);
516 }
517 
PCM_gotoLPM3InterruptSafe(void)518 bool PCM_gotoLPM3InterruptSafe(void)
519 {
520     bool lpmHappenedCorrect;
521 
522     /* Disabling master interrupts. In Cortex M, if an interrupt is enabled but
523      master interrupts are disabled and a WFI happens the WFI will
524      immediately exit. */
525     Interrupt_disableMaster();
526 
527     lpmHappenedCorrect = PCM_gotoLPM3();
528 
529     /* Enabling and Disabling Interrupts very quickly so that the
530      processor catches any pending interrupts */
531     Interrupt_enableMaster();
532     Interrupt_disableMaster();
533 
534     return lpmHappenedCorrect;
535 }
536 
PCM_getPowerState(void)537 uint8_t PCM_getPowerState(void)
538 {
539     return (PCM->CTL0 & PCM_CTL0_CPM_MASK) >> PCM_CTL0_CPM_OFS;
540 }
541 
PCM_enableRudeMode(void)542 void PCM_enableRudeMode(void)
543 {
544 
545     PCM->CTL1 = (PCM->CTL1 & ~(PCM_CTL0_KEY_MASK)) | PCM_KEY
546             | PCM_CTL1_FORCE_LPM_ENTRY;
547 }
548 
PCM_disableRudeMode(void)549 void PCM_disableRudeMode(void)
550 {
551     PCM->CTL1 = (PCM->CTL1 & ~(PCM_CTL0_KEY_MASK | PCM_CTL1_FORCE_LPM_ENTRY))
552             | PCM_KEY;
553 }
554 
PCM_enableInterrupt(uint32_t flags)555 void PCM_enableInterrupt(uint32_t flags)
556 {
557     PCM->IE |= flags;
558 }
559 
PCM_disableInterrupt(uint32_t flags)560 void PCM_disableInterrupt(uint32_t flags)
561 {
562     PCM->IE &= ~flags;
563 }
564 
PCM_getInterruptStatus(void)565 uint32_t PCM_getInterruptStatus(void)
566 {
567     return PCM->IFG;
568 }
569 
PCM_getEnabledInterruptStatus(void)570 uint32_t PCM_getEnabledInterruptStatus(void)
571 {
572     return PCM_getInterruptStatus() & PCM->IE;
573 }
574 
PCM_clearInterruptFlag(uint32_t flags)575 void PCM_clearInterruptFlag(uint32_t flags)
576 {
577     PCM->CLRIFG |= flags;
578 }
579 
PCM_registerInterrupt(void (* intHandler)(void))580 void PCM_registerInterrupt(void (*intHandler)(void))
581 {
582     //
583     // Register the interrupt handler, returning an error if an error occurs.
584     //
585     Interrupt_registerInterrupt(INT_PCM, intHandler);
586 
587     //
588     // Enable the system control interrupt.
589     //
590     Interrupt_enableInterrupt(INT_PCM);
591 }
592 
PCM_unregisterInterrupt(void)593 void PCM_unregisterInterrupt(void)
594 {
595     //
596     // Disable the interrupt.
597     //
598     Interrupt_disableInterrupt(INT_PCM);
599 
600     //
601     // Unregister the interrupt handler.
602     //
603     Interrupt_unregisterInterrupt(INT_PCM);
604 }
605