summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSheng-Liang Song <ssl@chromium.org>2014-12-17 10:58:11 -0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-03-21 00:29:14 +0000
commitc12181d9af8fbe0b61ac522e813bec463571dda5 (patch)
tree62e0288eee74af528acbc28f6aa24eacfab2c8b5
parent3f061f1864b59cd77d6c6d2fd6fdf8eb57393d51 (diff)
downloadchrome-ec-c12181d9af8fbe0b61ac522e813bec463571dda5.tar.gz
cr50: Added PMU driver
- Porting from cosmo code base. - Support clock initialization BRANCH=none BUG=chrome-os-partner:33813 TEST="make buildall -j; Verified on RevA1 Chip" Change-Id: I59e2bb133968d408acde44a3082e1b3b8f4bbbff Signed-off-by: Sheng-Liang Song <ssl@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/236394 Reviewed-by: Bill Richardson <wfrichar@chromium.org>
-rw-r--r--chip/g/build.mk1
-rw-r--r--chip/g/clock.c350
-rw-r--r--chip/g/pmu.c619
-rw-r--r--chip/g/pmu.h113
4 files changed, 767 insertions, 316 deletions
diff --git a/chip/g/build.mk b/chip/g/build.mk
index 5c5a9a1034..ac626e0381 100644
--- a/chip/g/build.mk
+++ b/chip/g/build.mk
@@ -17,4 +17,5 @@ CPPFLAGS+= -DGC_REVISION="$(ver_str)"
# Required chip modules
chip-y=clock.o gpio.o hwtimer.o jtag.o system.o uart.o
+chip-y+= pmu.o
chip-$(CONFIG_WATCHDOG)+=watchdog.o
diff --git a/chip/g/clock.c b/chip/g/clock.c
index 72ed2ca820..098c6a4aa7 100644
--- a/chip/g/clock.c
+++ b/chip/g/clock.c
@@ -5,327 +5,45 @@
#include "clock.h"
#include "registers.h"
-
-/* Clock initialization taken from some example code */
-
-#define RESOLUTION 12
-#define LOAD_VAL (0x1 << 11)
-#define MAX_TRIM (7*16)
-
-static void switch_osc_to_xtl(void);
-
-static void clock_on_xo0(void)
-{
- /* turn on xo0 clock */
- /* don't know which control word it might be in */
-#ifdef GC_PMU_PERICLKSET0_DXO0_MASK
- GR_PMU_PERICLKSET0 = GC_PMU_PERICLKSET0_DXO0_MASK;
-#endif
-
-#ifdef GC_PMU_PERICLKSET1_DXO0_MASK
- GR_PMU_PERICLKSET1 = GC_PMU_PERICLKSET1_DXO0_MASK;
-#endif
-}
-
-/* Converts an integer setting to the RC trim code format (7, 4-bit values) */
-static unsigned val_to_trim_code(unsigned val)
-{
- unsigned base = val / 7;
- unsigned mod = val % 7;
- unsigned code = 0x0;
- int digit;
-
- /* Increasing count from right to left */
- for (digit = 0; digit < 7; digit++) {
- /* Check for mod */
- if (digit <= mod)
- code |= ((base & 0xF) << 4 * digit);
- else
- code |= (((base - 1) & 0xF) << 4 * digit);
- }
-
- return code;
-}
-
-static unsigned calib_rc_trim(void)
-{
- unsigned size, iter;
- signed mid;
- signed diff;
-
- /* Switch to crystal for calibration. This should work since we are
- * technically on an uncalibrated RC trim clock. */
- switch_osc_to_xtl();
-
- clock_on_xo0();
-
- /* Clear the HOLD signal on dxo */
- GR_XO_OSC_CLRHOLD = GC_XO_OSC_CLRHOLD_RC_TRIM_MASK;
-
- /* Reset RC calibration counters */
- GR_XO_OSC_RC_CAL_RSTB = 0x0;
- GR_XO_OSC_RC_CAL_RSTB = 0x1;
-
- /* Write the LOAD val */
- GR_XO_OSC_RC_CAL_LOAD = LOAD_VAL;
-
- /* Begin binary search */
- mid = 0;
- size = MAX_TRIM / 2;
- for (iter = 0; iter <= 7; iter++) {
- /* Set the trim value */
- GR_XO_OSC_RC = val_to_trim_code(mid) << GC_XO_OSC_RC_TRIM_LSB;
-
- /* Do a calibration */
- GR_XO_OSC_RC_CAL_START = 0x1;
-
- /* NOTE: There is a small race condition because of the delay
- * in dregfile. The start doesn't actually appear for 2 clock
- * cycles after the write. So, poll until done goes low. */
- while (GR_XO_OSC_RC_CAL_DONE)
- ;
-
- /* Wait until it's done */
- while (!GR_XO_OSC_RC_CAL_DONE)
- ;
-
- /* Check the counter value */
- diff = LOAD_VAL - GR_XO_OSC_RC_CAL_COUNT;
-
- /* Test to see whether we are still outside of our desired
- * resolution */
- if ((diff < -RESOLUTION) || (diff > RESOLUTION))
- mid = (diff > 0) ? (mid - size / 2) : (mid + size / 2);
-
- size = (size + 1) >> 1; /* round up before division */
- }
-
- /* Set the final trim value */
- GR_XO_OSC_RC = (val_to_trim_code(mid) << GC_XO_OSC_RC_TRIM_LSB) |
- (0x1 << GC_XO_OSC_RC_EN_LSB);
-
- /* Set the HOLD signal on dxo */
- GR_XO_OSC_SETHOLD = GC_XO_OSC_SETHOLD_RC_TRIM_MASK;
-
- /* Switch back to the RC trim now that we are calibrated */
- GR_PMU_OSC_HOLD_CLR = 0x1; /* make sure the hold signal is clear */
- GR_PMU_OSC_SELECT = GC_PMU_OSC_SELECT_RC_TRIM;
- /* Make sure the hold signal is set for future power downs */
- GR_PMU_OSC_HOLD_SET = 0x1;
-
- return mid;
-}
-
-static void switch_osc_to_rc_trim(void)
-{
- unsigned trimmed;
- unsigned saved_trim, fuse_trim, default_trim;
- unsigned trim_code;
-
- /* check which clock we are running on */
- unsigned osc_sel = GR_PMU_OSC_SELECT_STAT;
-
- if (osc_sel == GC_PMU_OSC_SELECT_RC_TRIM) {
- /* already using the rc_trim so nothing to do here */
- /* make sure the hold signal is set for future power downs */
- GR_PMU_OSC_HOLD_SET = 0x1;
- return;
- }
-
- /* Turn on DXO clock so we can write in the trim code in */
- clock_on_xo0();
-
- /* disable the RC_TRIM Clock */
- REG_WRITE_MLV(GR_PMU_OSC_CTRL,
- GC_PMU_OSC_CTRL_RC_TRIM_READYB_MASK,
- GC_PMU_OSC_CTRL_RC_TRIM_READYB_LSB, 1);
-
- /* power up the clock if not already powered up */
- GR_PMU_CLRDIS = 1 << GC_PMU_SETDIS_RC_TRIM_LSB;
-
- /* Try to find the trim code */
- saved_trim = GR_XO_OSC_RC_STATUS;
- fuse_trim = GR_PMU_FUSE_RD_RC_OSC_26MHZ;
- default_trim = GR_XO_OSC_RC;
-
- /* Check for the trim code in the always-on domain before looking at
- * the fuse */
- if (saved_trim & GC_XO_OSC_RC_STATUS_EN_MASK) {
- trim_code = (saved_trim & GC_XO_OSC_RC_STATUS_TRIM_MASK)
- >> GC_XO_OSC_RC_STATUS_TRIM_LSB;
- trimmed = 1;
- } else if (fuse_trim & GC_PMU_FUSE_RD_RC_OSC_26MHZ_EN_MASK) {
- trim_code = (fuse_trim & GC_PMU_FUSE_RD_RC_OSC_26MHZ_TRIM_MASK)
- >> GC_PMU_FUSE_RD_RC_OSC_26MHZ_TRIM_LSB;
- trimmed = 1;
- } else {
- trim_code = (default_trim & GC_XO_OSC_RC_TRIM_MASK)
- >> GC_XO_OSC_RC_TRIM_LSB;
- trimmed = 0;
- }
-
- /* Write the trim code to dxo */
- if (trimmed) {
- /* clear the hold signal */
- GR_XO_OSC_CLRHOLD = 1 << GC_XO_OSC_CLRHOLD_RC_TRIM_LSB;
- GR_XO_OSC_RC = (trim_code << GC_XO_OSC_RC_TRIM_LSB) |
- ((trimmed & 0x1) << GC_XO_OSC_RC_EN_LSB);
- /* set the hold signal */
- GR_XO_OSC_SETHOLD = 1 << GC_XO_OSC_SETHOLD_RC_TRIM_LSB;
- }
-
- /* enable the RC_TRIM Clock */
- REG_WRITE_MLV(GR_PMU_OSC_CTRL, GC_PMU_OSC_CTRL_RC_TRIM_READYB_MASK,
- GC_PMU_OSC_CTRL_RC_TRIM_READYB_LSB, 0);
-
- /* Switch the select signal */
- GR_PMU_OSC_HOLD_CLR = 0x1; /* make sure the hold signal is clear */
- GR_PMU_OSC_SELECT = GC_PMU_OSC_SELECT_RC_TRIM;
- /* make sure the hold signal is set for future power downs */
- GR_PMU_OSC_HOLD_SET = 0x1;
-
- /* If we didn't find a valid trim code, then we need to calibrate */
- if (!trimmed)
- calib_rc_trim();
- /* We saved the trim code and went back to the RC trim inside
- * calib_rc_trim */
-}
-
-static void switch_osc_to_xtl(void)
-{
- unsigned int saved_trim, fuse_trim, trim_code, final_trim;
- unsigned int fsm_status, max_trim;
- unsigned int fsm_done;
- /* check which clock we are running on */
- unsigned int osc_sel = GR_PMU_OSC_SELECT_STAT;
-
- if (osc_sel == GC_PMU_OSC_SELECT_XTL) {
- /* already using the crystal so nothing to do here */
- /* make sure the hold signal is set for future power downs */
- GR_PMU_OSC_HOLD_SET = 0x1;
- return;
- }
-
- if (osc_sel == GC_PMU_OSC_SELECT_RC)
- /* RC untrimmed clock. We must go through the trimmed clock
- * first to avoid glitching */
- switch_osc_to_rc_trim();
-
- /* disable the XTL Clock */
- REG_WRITE_MLV(GR_PMU_OSC_CTRL, GC_PMU_OSC_CTRL_XTL_READYB_MASK,
- GC_PMU_OSC_CTRL_XTL_READYB_LSB, 1);
-
- /* power up the clock if not already powered up */
- GR_PMU_CLRDIS = 1 << GC_PMU_SETDIS_XTL_LSB;
-
- /* Try to find the trim code */
- trim_code = 0;
- saved_trim = GR_XO_OSC_XTL_TRIM_STAT;
- fuse_trim = GR_PMU_FUSE_RD_XTL_OSC_26MHZ;
-
- /* Check for the trim code in the always-on domain before looking at
- * the fuse */
- if (saved_trim & GC_XO_OSC_XTL_TRIM_STAT_EN_MASK) {
- /* nothing to do */
- /* trim_code = (saved_trim & GR_XO_OSC_XTL_TRIM_STAT_CODE_MASK)
- >> GR_XO_OSC_XTL_TRIM_STAT_CODE_LSB; */
- /* print_trickbox_message("XTL TRIM CODE FOUND IN 3P3"); */
- } else if (fuse_trim & GC_PMU_FUSE_RD_XTL_OSC_26MHZ_EN_MASK) {
- /* push the fuse trim code as the saved trim code */
- /* print_trickbox_message("XTL TRIM CODE FOUND IN FUSE"); */
- trim_code = (fuse_trim & GC_PMU_FUSE_RD_XTL_OSC_26MHZ_TRIM_MASK)
- >> GC_PMU_FUSE_RD_XTL_OSC_26MHZ_TRIM_LSB;
- /* make sure the hold signal is clear */
- GR_XO_OSC_CLRHOLD = 0x1 << GC_XO_OSC_CLRHOLD_XTL_LSB;
- GR_XO_OSC_XTL_TRIM =
- (trim_code << GC_XO_OSC_XTL_TRIM_CODE_LSB) |
- (0x1 << GC_XO_OSC_XTL_TRIM_EN_LSB);
- } else
- /* print_trickbox_message("XTL TRIM CODE NOT FOUND"); */
- ;
-
- /* Run the crystal FSM to calibrate the crystal trim */
- fsm_done = GR_XO_OSC_XTL_FSM;
- if (fsm_done & GC_XO_OSC_XTL_FSM_DONE_MASK) {
- /* If FSM done is high, it means we already ran it so let's not
- * run it again */
- /* DO NOTHING */
- } else {
- GR_XO_OSC_XTL_FSM_EN = 0x0; /* reset FSM */
- GR_XO_OSC_XTL_FSM_EN = GC_XO_OSC_XTL_FSM_EN_KEY;
- while (!(fsm_done & GC_XO_OSC_XTL_FSM_DONE_MASK))
- fsm_done = GR_XO_OSC_XTL_FSM;
- }
-
- /* Check the status and final trim value */
- max_trim = (GR_XO_OSC_XTL_FSM_CFG & GC_XO_OSC_XTL_FSM_CFG_TRIM_MAX_MASK)
- >> GC_XO_OSC_XTL_FSM_CFG_TRIM_MAX_LSB;
- final_trim = (fsm_done & GC_XO_OSC_XTL_FSM_TRIM_MASK)
- >> GC_XO_OSC_XTL_FSM_TRIM_LSB;
- fsm_status = (fsm_done & GC_XO_OSC_XTL_FSM_STATUS_MASK)
- >> GC_XO_OSC_XTL_FSM_STATUS_LSB;
-
- /* Check status bit and trim value */
- if (fsm_status) {
- if (final_trim >= max_trim)
- /* print_trickbox_error("ERROR: XTL FSM status was
- high, but final XTL trim is greater than or equal to
- max trim"); */
- ;
- } else {
- if (final_trim != max_trim)
- /* print_trickbox_error("ERROR: XTL FSM status was low,
- but final XTL trim does not equal max trim"); */
- ;
- }
-
- /* save the trim for future powerups */
- /* make sure the hold signal is clear (may have already been cleared) */
- GR_XO_OSC_CLRHOLD = 0x1 << GC_XO_OSC_CLRHOLD_XTL_LSB;
- GR_XO_OSC_XTL_TRIM =
- (final_trim << GC_XO_OSC_XTL_TRIM_CODE_LSB) |
- (0x1 << GC_XO_OSC_XTL_TRIM_EN_LSB);
- /* make sure the hold signal is set for future power downs */
- GR_XO_OSC_SETHOLD = 0x1 << GC_XO_OSC_SETHOLD_XTL_LSB;
-
- /* enable the XTL Clock */
- REG_WRITE_MLV(GR_PMU_OSC_CTRL, GC_PMU_OSC_CTRL_XTL_READYB_MASK,
- GC_PMU_OSC_CTRL_XTL_READYB_LSB, 0);
-
- /* Switch the select signal */
- GR_PMU_OSC_HOLD_CLR = 0x1; /* make sure the hold signal is clear */
- GR_PMU_OSC_SELECT = GC_PMU_OSC_SELECT_XTL;
- /* make sure the hold signal is set for future power downs */
- GR_PMU_OSC_HOLD_SET = 0x1;
-}
+#include "pmu.h"
void clock_init(void)
{
- /*
- * TODO(crosbug.com/p/33813): The following comment was in the example
- * code, but the function that's called doesn't match what it says.
- * Investigate further.
- */
-
- /* Switch to crystal clock since RC clock not accurate enough */
- switch_osc_to_rc_trim();
+ pmu_clock_en(PERIPH_PERI0);
+ pmu_clock_en(PERIPH_TIMEHS0);
+ pmu_clock_en(PERIPH_TIMEHS1);
+ pmu_clock_switch_xo();
}
void clock_enable_module(enum module_id module, int enable)
{
- if (module != MODULE_UART)
- return;
-
- /* don't know which control word it might be in */
-#ifdef GC_PMU_PERICLKSET0_DUART0_LSB
- REG_WRITE_MLV(GR_PMU_PERICLKSET0,
- GC_PMU_PERICLKSET0_DUART0_MASK,
- GC_PMU_PERICLKSET0_DUART0_LSB, enable);
-#endif
-
-#ifdef GR_PMU_PERICLKSET1_DUART0_LSB
- REG_WRITE_MLV(GR_PMU_PERICLKSET1,
- GC_PMU_PERICLKSET1_DUART0_MASK,
- GC_PMU_PERICLKSET0_DUART1_LSB, enable);
-#endif
+ pmu_clock_func clock_func;
+ clock_func = (enable) ? pmu_clock_en : pmu_clock_dis;
+
+ switch (module) {
+ case MODULE_UART:
+ clock_func(PERIPH_UART0);
+ break;
+ case MODULE_I2C:
+ clock_func(PERIPH_I2C0);
+ clock_func(PERIPH_I2C1);
+ break;
+ case MODULE_SPI_MASTER:
+ clock_func(PERIPH_SPI);
+ break;
+ case MODULE_SPI:
+ clock_func(PERIPH_SPS);
+ break;
+ case MODULE_USB:
+ clock_func(PERIPH_USB0);
+ clock_func(PERIPH_USB0_USB_PHY);
+ pmu_enable_clock_doubler();
+ break;
+ case MODULE_PMU:
+ clock_func(PERIPH_PMU);
+ break;
+ default:
+ break;
+ }
+ return;
}
diff --git a/chip/g/pmu.c b/chip/g/pmu.c
new file mode 100644
index 0000000000..b2841fe289
--- /dev/null
+++ b/chip/g/pmu.c
@@ -0,0 +1,619 @@
+/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "pmu.h"
+#include "task.h"
+
+/*
+ * RC Trim constants
+ */
+#define RCTRIM_RESOLUTION (12)
+#define RCTRIM_LOAD_VAL (1 << 11)
+#define RCTRIM_RANGE_MAX (7 * 7)
+#define RCTRIM_RANGE_MIN (-8 * 7)
+#define RCTRIM_RANGE (RCTRIM_RANGE_MAX - RCTRIM_RANGE_MIN + 1)
+
+/*
+ * Enable peripheral clock
+ * @param perih Peripheral from @ref uint32_t
+ */
+void pmu_clock_en(uint32_t periph)
+{
+ if (periph <= 31)
+ GR_PMU_PERICLKSET0 = (1 << periph);
+ else
+ GR_PMU_PERICLKSET1 = (1 << (periph - 32));
+}
+
+/*
+ * Disable peripheral clock
+ * @param perih Peripheral from @ref uint32_t
+ */
+void pmu_clock_dis(uint32_t periph)
+{
+ if (periph <= 31)
+ GR_PMU_PERICLKCLR0 = (1 << periph);
+ else
+ GR_PMU_PERICLKCLR1 = (1 << (periph - 32));
+}
+
+/*
+ * Peripheral reset
+ * @param periph Peripheral from @ref uint32_t
+ */
+void pmu_peripheral_rst(uint32_t periph)
+{
+ /* Reset high */
+ if (periph <= 31)
+ GR_PMU_RST0 = 1 << periph;
+ else
+ GR_PMU_RST1 = 1 << (periph - 32);
+}
+
+/*
+ * Internal helper to convert value to trim code
+ */
+static uint32_t _pmu_value_to_trim(uint32_t val)
+{
+ uint32_t base = val / 7;
+ uint32_t mod = val % 7;
+ uint32_t code = 0x0;
+ uint32_t digit;
+
+ /* Increasing count from right to left */
+ for (digit = 0; digit < 7; digit++) {
+ if (digit < mod)
+ code |= (((base + 1) & 0xF) << (4 * digit));
+ else
+ code |= ((base & 0xF) << (4 * digit));
+ }
+
+ return code;
+}
+
+/*
+ * Run the RC calibration counters
+ * This must be used otherwise the counters may get stuck
+ */
+static uint32_t _pmu_run_rc_counters(uint32_t load_val, uint32_t trim_val)
+{
+ uint32_t trim_code;
+
+ /* Convert value to trim code */
+ trim_code = _pmu_value_to_trim(trim_val);
+
+ /* Set the trim value */
+ GWRITE_FIELD(XO, OSC_RC, TRIM, trim_code);
+
+ /* Reset counters */
+ GR_XO_OSC_RC_CAL_RSTB = 0x0;
+ GR_XO_OSC_RC_CAL_RSTB = 0x1;
+
+ /* Load */
+ GR_XO_OSC_RC_CAL_LOAD = load_val;
+
+ /* Do calibration */
+ GR_XO_OSC_RC_CAL_START = 0x1;
+
+ /*
+ * There is a small race condition because of the delay in dregfile.
+ * The start doesn't actually appear for 2 clock cycles after the write.
+ * So, poll until done goes low.
+ */
+ while (GR_XO_OSC_RC_CAL_DONE)
+ ;
+
+ /* Wait until it's done */
+ while (!GR_XO_OSC_RC_CAL_DONE)
+ ;
+
+ /* Calculate the difference */
+ return GR_XO_OSC_RC_CAL_LOAD - GR_XO_OSC_RC_CAL_COUNT;
+}
+
+/*
+ * Calibrate RC trim
+ */
+uint32_t pmu_calibrate_rc_trim(void)
+{
+ uint32_t size, iter;
+ uint32_t mid;
+ uint32_t diff;
+
+ /*
+ * Switch to crystal for calibration
+ * This should work since we are on an uncalibrated RC trim clock
+ */
+ pmu_clock_switch_xo();
+
+ /* Clear the HOLD signal on dxo */
+ GR_XO_OSC_CLRHOLD = GC_XO_OSC_CLRHOLD_RC_TRIM_MASK;
+
+ /* Clear EN bit while iterating through codes */
+ GWRITE_FIELD(XO, OSC_RC, EN, 0);
+
+ /* Begin binary search */
+ mid = RCTRIM_RANGE_MAX - (RCTRIM_RANGE / 2);
+ size = RCTRIM_RANGE / 2;
+ for (iter = 0; iter < 8; iter++) {
+ /* Run the counters */
+ diff = _pmu_run_rc_counters(RCTRIM_LOAD_VAL, mid);
+
+ /*
+ * Test to see whether we are still outside of
+ * our desired resolution
+ */
+ if ((diff < -RCTRIM_RESOLUTION)
+ || (diff > RCTRIM_RESOLUTION)) {
+ if (diff > 0)
+ mid -= size / 2;
+ else
+ mid += size / 2;
+ }
+
+ /* Move to next range, round up */
+ size = (size + 1) >> 1;
+ }
+
+ /* Set the final trim value, set EN bit to lock in the code */
+ GR_XO_OSC_RC = (_pmu_value_to_trim(mid) << GC_XO_OSC_RC_TRIM_LSB)
+ | (0x1 << GC_XO_OSC_RC_EN_LSB);
+
+ /* Set EN bit to lock in this trim_code */
+ /* GWRITE_FIELD(XO, OSC_RC, EN, 1); */
+
+ /* Set the HOLD signal on dxo */
+ GR_XO_OSC_SETHOLD = GC_XO_OSC_SETHOLD_RC_TRIM_MASK;
+
+ /* Switch back to the RC trim now that we are calibrated */
+ /* pmu_clock_switch_rc_trim(); */
+
+ return _pmu_value_to_trim(mid);
+}
+
+/*
+ * Switch system clock to RC no trim
+ */
+uint32_t pmu_clock_switch_rc_notrim(void)
+{
+ uint32_t osc_sel;
+
+ /* check which clock we are running on */
+ osc_sel = GR_PMU_OSC_SELECT_STAT;
+
+ if (osc_sel == GC_PMU_OSC_SELECT_RC) {
+ /* Already on untrimmed RC */
+ return 0;
+ } else if (osc_sel == GC_PMU_OSC_SELECT_XTL) {
+ /* Need to switch to RC trimmed first */
+ pmu_clock_switch_rc_trim(1);
+ }
+
+ /* Turn on XO clock */
+ pmu_clock_en(PERIPH_XO);
+
+ /* Power up RC notrim clock if it's currently off */
+ GWRITE_FIELD(PMU, CLRDIS, RC_NOTRIM, 1);
+
+ /* Switch to the clock */
+ GR_PMU_OSC_HOLD_CLR = 0x1; /* make sure the hold signal is clear */
+ GR_PMU_OSC_SELECT = GC_PMU_OSC_SELECT_RC;
+ /* make sure the hold signal is set for future power downs */
+ GR_PMU_OSC_HOLD_SET = 0x1;
+
+ return 0;
+}
+
+/*
+ * enable clock doubler for USB purposes
+ */
+void pmu_enable_clock_doubler(void)
+{
+ /* enable stuff */
+ GREG32(XO, OSC_ADC_CAL_FREQ2X) =
+ (GC_XO_OSC_ADC_CAL_FREQ2X_CNTL_DEFAULT
+ << GC_XO_OSC_ADC_CAL_FREQ2X_CNTL_LSB) |
+ (1 << GC_XO_OSC_ADC_CAL_FREQ2X_EN_LSB);
+ /* enable more stuff */
+ GREG32(XO, OSC_CLKOUT) =
+ (1 << GC_XO_OSC_CLKOUT_ADC_EN_LSB) |
+ (1 << GC_XO_OSC_CLKOUT_PLL_EN_LSB) |
+ (1 << GC_XO_OSC_CLKOUT_BADC_EN_LSB) |
+ (1 << GC_XO_OSC_CLKOUT_USB_EN_LSB);
+
+ /* make sure doubled clock is selected */
+ GREG32(XO, OSC_24_48B_SEL) = GC_XO_OSC_24_48B_SEL_DEFAULT;
+}
+
+/*
+ * Switch system clock to RC trim
+ */
+uint32_t pmu_clock_switch_rc_trim(uint32_t skip_calibration)
+{
+ uint32_t trimmed;
+ uint32_t trim_code;
+ uint32_t osc_sel;
+
+ /* check which clock we are running on */
+ osc_sel = GREG32(PMU, OSC_SELECT_STAT);
+
+ if (osc_sel == GC_PMU_OSC_SELECT_RC_TRIM) {
+ /*
+ * already using the rc_trim so nothing to do here
+ * make sure the hold signal is set for future power downs
+ */
+ GREG32(PMU, OSC_HOLD_SET) = 0x1;
+ return 0;
+ }
+
+ /* Turn on DXO clock so we can write in the trim code in */
+ pmu_clock_en(PERIPH_XO);
+
+ /* Disable the RC Trim flops in the glitchless switch */
+ GWRITE_FIELD(PMU, OSC_CTRL, RC_TRIM_READYB, 0x1);
+
+ /* Power up the clock if not already powered up */
+ GREG32(PMU, CLRDIS) = 1 << GC_PMU_SETDIS_RC_TRIM_LSB;
+
+ /* Check for the trim code in the always-on domain
+ * before looking at the fuse
+ */
+ if (GREAD_FIELD(XO, OSC_RC_STATUS, EN)) {
+ trim_code = GREAD_FIELD(XO, OSC_RC_STATUS, TRIM);
+ trimmed = 1;
+ } else if (GREAD_FIELD(PMU, FUSE_RD_RC_OSC_26MHZ, EN)) {
+ trim_code = GREAD_FIELD(PMU, FUSE_RD_RC_OSC_26MHZ, TRIM);
+ trimmed = 1;
+ } else {
+ if (skip_calibration) {
+ trim_code = GREAD_FIELD(XO, OSC_RC, TRIM);
+ trimmed = 0;
+ } else {
+ trim_code = pmu_calibrate_rc_trim();
+ trimmed = 1;
+ }
+ }
+
+ /* Write the trim code to dxo */
+ if (trimmed) {
+ /* clear the hold signal */
+ GREG32(XO, OSC_CLRHOLD) = GC_XO_OSC_CLRHOLD_RC_TRIM_MASK;
+
+ /* Write the trim code and enable the trim code */
+ GREG32(XO, OSC_RC) = (trim_code << GC_XO_OSC_RC_TRIM_LSB) |
+ (1 << GC_XO_OSC_RC_EN_LSB);
+
+ /* set the hold signal */
+ GREG32(XO, OSC_SETHOLD) = 1 << GC_XO_OSC_SETHOLD_RC_TRIM_LSB;
+ }
+
+ /* Enable the flops for RC TRIM in the glitchless switch */
+ GWRITE_FIELD(PMU, OSC_CTRL, RC_TRIM_READYB, 0x0);
+
+ /*
+ * Switch the select signal
+ * make sure the hold signal is clear
+ */
+ GREG32(PMU, OSC_HOLD_CLR) = 0x1;
+ GREG32(PMU, OSC_SELECT) = GC_PMU_OSC_SELECT_RC_TRIM;
+
+ /* make sure the hold signal is set for future power downs */
+ GREG32(PMU, OSC_HOLD_SET) = 0x1;
+
+ return !trimmed;
+}
+
+/*
+ * Switch system clock to XO
+ * @returns The value of XO_OSC_XTL_FSM_STATUS. 0 = okay, 1 = error.
+ */
+uint32_t pmu_clock_switch_xo(void)
+{
+ uint32_t osc_sel;
+ uint32_t trim_code, final_trim, fsm_done, fsm_status;
+
+ /* check which clock we are running on */
+ osc_sel = GREG32(PMU, OSC_SELECT_STAT);
+
+ if (osc_sel == GC_PMU_OSC_SELECT_XTL) {
+ /*
+ * already using the crystal so nothing to do here
+ * make sure the hold signal is set for future power downs
+ */
+ GREG32(PMU, OSC_HOLD_SET) = 0x1;
+ return 0;
+ } else if (osc_sel == GC_PMU_OSC_SELECT_RC) {
+ /*
+ * RC untrimmed clock. We must go through
+ * the trimmed clock first to avoid glitching
+ */
+ pmu_clock_switch_rc_trim(1);
+ }
+
+ /* Turn on DXO clock so we can write in the trim code in */
+ pmu_clock_en(PERIPH_XO);
+
+ /* Disable the XTL Clock */
+ GWRITE_FIELD(PMU, OSC_CTRL, XTL_READYB, 0x1);
+
+ /* Power up the clock if not already powered up */
+ GREG32(PMU, CLRDIS) = 1 << GC_PMU_CLRDIS_XTL_LSB;
+
+ /* Try to find the trim code */
+ trim_code = 0;
+
+ /*
+ * Check for the trim code in the always-on domain
+ * before looking at the fuse
+ */
+ if (GREAD_FIELD(XO, OSC_XTL_TRIM_STAT, EN)) {
+ /* nothing to do */
+ trim_code = GREAD_FIELD(XO, OSC_XTL_TRIM_STAT, CODE);
+
+ } else if (GREAD_FIELD(PMU, FUSE_RD_XTL_OSC_26MHZ, EN)) {
+
+ /* push the fuse trim code as the saved trim code */
+ trim_code = GREAD_FIELD(PMU, FUSE_RD_XTL_OSC_26MHZ, TRIM);
+
+ /* make sure the hold signal is clear */
+ GREG32(XO, OSC_CLRHOLD) = 1 << GC_XO_OSC_CLRHOLD_XTL_LSB;
+ GREG32(XO, OSC_XTL_TRIM) =
+ (trim_code << GC_XO_OSC_XTL_TRIM_CODE_LSB)
+ | (0x1 << GC_XO_OSC_XTL_TRIM_EN_LSB);
+ } else {
+ /* Run the crystal FSM to calibrate the crystal trim */
+ fsm_done = GREG32(XO, OSC_XTL_FSM);
+ if (fsm_done & GC_XO_OSC_XTL_FSM_DONE_MASK) {
+ /*
+ * If FSM done is high, it means we already ran it
+ * so let's not run it again
+ * DO NOTHING
+ */
+ } else {
+ /* reset FSM */
+ GREG32(XO, OSC_XTL_FSM_EN) = 0x0;
+ GREG32(XO, OSC_XTL_FSM_EN) = GC_XO_OSC_XTL_FSM_EN_KEY;
+ while (!(fsm_done & GC_XO_OSC_XTL_FSM_DONE_MASK))
+ fsm_done = GREG32(XO, OSC_XTL_FSM);
+ }
+ }
+
+ /* Check the status and final trim value */
+ /* max_trim = GREAD_FIELD(XO, OSC_XTL_FSM_CFG, TRIM_MAX); */
+ final_trim = GREAD_FIELD(XO, OSC_XTL_FSM, TRIM);
+ fsm_status = GREAD_FIELD(XO, OSC_XTL_FSM, STATUS);
+
+ /*
+ * Save the trim for future powerups
+ * make sure the hold signal is clear (may have already been cleared)
+ */
+ GREG32(XO, OSC_CLRHOLD) = 1 << GC_XO_OSC_CLRHOLD_XTL_LSB;
+ GREG32(XO, OSC_XTL_TRIM) = (final_trim << GC_XO_OSC_XTL_TRIM_CODE_LSB) |
+ (1 << GC_XO_OSC_XTL_TRIM_EN_LSB);
+
+ /* make sure the hold signal is set for future power downs */
+ GREG32(XO, OSC_SETHOLD) = 1 << GC_XO_OSC_SETHOLD_XTL_LSB;
+
+ /* Enable the flops for XTL in the glitchless switch */
+ GWRITE_FIELD(PMU, OSC_CTRL, XTL_READYB, 0x0);
+
+ /*
+ * Switch the select signal
+ * make sure the hold signal is clear
+ */
+ GREG32(PMU, OSC_HOLD_CLR) = 0x1;
+ GREG32(PMU, OSC_SELECT) = GC_PMU_OSC_SELECT_XTL;
+
+ /* make sure the hold signal is set for future power downs */
+ GREG32(PMU, OSC_HOLD_SET) = 0x1;
+
+ return !fsm_status;
+}
+
+/*
+ * Enter sleep mode and handle exiting from sleep mode
+ * @warning The CPU must be in RC no trim mode before calling this function
+ */
+void pmu_sleep(void)
+{
+ uint32_t val;
+
+ /* Enable PMU sleep interrupts */
+ GREG32(PMU, ICTRL) = 1 << GC_PMU_ICTRL_SLEEP_LSB;
+
+ /* nvic_irq_en(GC_IRQNUM_PMU_PMUINT); */
+
+ /* Enable CPU SLEEPDEEP */
+ val = GREG32(M3, SCR);
+ GREG32(M3, SCR) = val | 0x4;
+
+ /* Enable WIC mode */
+ GREG32(PMU, SETWIC) = 1 << GC_PMU_SETWIC_PROC0_LSB;
+
+ /* Disable power domains for entering sleep mode */
+ GREG32(PMU, SETDIS) = (1 << GC_PMU_SETDIS_START_LSB) |
+ (1 << GC_PMU_SETDIS_VDDL_LSB) |
+ (1 << GC_PMU_SETDIS_VDDA_LSB) |
+ (1 << GC_PMU_SETDIS_VDDSRM_LSB) |
+ (1 << GC_PMU_SETDIS_BGAP_LSB) |
+ (1 << GC_PMU_SETDIS_VDDXO_LSB) |
+ (1 << GC_PMU_SETDIS_VDDXOLP_LSB) |
+ (1 << GC_PMU_SETDIS_XTL_LSB) |
+ (1 << GC_PMU_SETDIS_RC_TRIM_LSB) |
+ (1 << GC_PMU_SETDIS_RC_NOTRIM_LSB) |
+ (1 << GC_PMU_SETDIS_BATMON_LSB) |
+ (1 << GC_PMU_SETDIS_FST_BRNOUT_PWR_LSB) |
+ (1 << GC_PMU_SETDIS_FST_BRNOUT_LSB);
+
+ /* Wait for exit interrupt
+ * @todo Add code to disable all non-PMU interrupts.
+ */
+ __asm__("wfi");
+
+ /* Disable WIC mode */
+ GREG32(PMU, CLRWIC) = 1 << GC_PMU_CLRWIC_PROC0_LSB;
+
+ /* Disable CPU SLEEPDEEP */
+ val = GREG32(M3, SCR);
+ GREG32(M3, SCR) = val & (~0x4);
+
+ /* Re-enable power domains */
+ GREG32(PMU, CLRDIS) = (1 << GC_PMU_CLRDIS_START_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDL_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDA_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDSRM_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDIOF_LSB) |
+ (1 << GC_PMU_CLRDIS_BGAP_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDXO_LSB);
+
+#ifdef __FIX_ME__
+ GREG32(PMU, CLRDIS) = (1 << GC_PMU_CLRDIS_START_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDL_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDA_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDSRM_LSB) |
+ (1 << GC_PMU_CLRDIS_BGAP_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDXO_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDXOLP_LSB) |
+ (1 << GC_PMU_CLRDIS_XTL_LSB) |
+ (1 << GC_PMU_CLRDIS_RC_TRIM_LSB) |
+ (1 << GC_PMU_CLRDIS_RC_NOTRIM_LSB) |
+ (1 << GC_PMU_CLRDIS_BATMON_LSB) |
+ (1 << GC_PMU_CLRDIS_FST_BRNOUT_PWR_LSB) |
+ (1 << GC_PMU_CLRDIS_FST_BRNOUT_LSB);
+#endif
+}
+
+/*
+ * Enter hibernate mode
+ * This function does not return. The powerdown exit event will
+ * cause the CPU to begin executing the system / app bootloader.
+ * @warning The CPU must be in RC no trim mode
+ */
+void pmu_hibernate(void)
+{
+ /* Turn off power to everything except retention domains */
+ GREG32(PMU, SETDIS) = (1 << GC_PMU_SETDIS_START_LSB) |
+ (1 << GC_PMU_SETDIS_VDDL_LSB) |
+ (1 << GC_PMU_SETDIS_VDDA_LSB) |
+ (1 << GC_PMU_SETDIS_VDDSRM_LSB) |
+ (1 << GC_PMU_SETDIS_VDDIOF_LSB) |
+ (1 << GC_PMU_SETDIS_VDDLK_LSB) |
+ (1 << GC_PMU_SETDIS_VDDSK_LSB) |
+ (1 << GC_PMU_SETDIS_BIAS_LSB) |
+ (1 << GC_PMU_SETDIS_BGAP_LSB) |
+ (1 << GC_PMU_SETDIS_VDDXO_LSB) |
+ (1 << GC_PMU_SETDIS_VDDXOLP_LSB) |
+ (1 << GC_PMU_SETDIS_XTL_LSB) |
+ (1 << GC_PMU_SETDIS_RC_TRIM_LSB) |
+ (1 << GC_PMU_SETDIS_RC_NOTRIM_LSB) |
+ (1 << GC_PMU_SETDIS_BATMON_LSB) |
+ (1 << GC_PMU_SETDIS_FST_BRNOUT_PWR_LSB) |
+ (1 << GC_PMU_SETDIS_FST_BRNOUT_LSB);
+
+ /* Wait for powerdown */
+ for (;;)
+ __asm__("wfi");
+}
+
+/*
+ * Exit hibernate mode
+ * This function should be called after a powerdown exit event.
+ * It handles turning the power domains back on.
+ * Clocks will be left in RC no trim.
+ */
+void pmu_hibernate_exit(void)
+{
+ /* Turn on power to everything */
+ GREG32(PMU, CLRDIS) = (1 << GC_PMU_CLRDIS_START_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDL_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDA_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDSRM_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDIOF_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDLK_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDSK_LSB) |
+ (1 << GC_PMU_CLRDIS_BIAS_LSB) |
+ (1 << GC_PMU_CLRDIS_BGAP_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDXO_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDXOLP_LSB) |
+ (1 << GC_PMU_CLRDIS_XTL_LSB) |
+ (1 << GC_PMU_CLRDIS_RC_TRIM_LSB) |
+ (1 << GC_PMU_CLRDIS_RC_NOTRIM_LSB) |
+ (1 << GC_PMU_CLRDIS_BATMON_LSB) |
+ (1 << GC_PMU_CLRDIS_FST_BRNOUT_PWR_LSB) |
+ (1 << GC_PMU_CLRDIS_FST_BRNOUT_LSB);
+}
+
+/*
+ * Enter powerdown mode
+ * This function does not return. The powerdown exit event will
+ * cause the CPU to begin executing the system / app bootloader.
+ * @warning The CPU must be in RC no trim mode
+ */
+void pmu_powerdown(void)
+{
+ /* Turn off power to everything */
+ GREG32(PMU, SETDIS) = (1 << GC_PMU_SETDIS_START_LSB) |
+ (1 << GC_PMU_SETDIS_VDDL_LSB) |
+ (1 << GC_PMU_SETDIS_VDDA_LSB) |
+ (1 << GC_PMU_SETDIS_VDDSRM_LSB) |
+ (1 << GC_PMU_SETDIS_VDDIOF_LSB) |
+ (1 << GC_PMU_SETDIS_VDDLK_LSB) |
+ (1 << GC_PMU_SETDIS_VDDSK_LSB) |
+ (1 << GC_PMU_SETDIS_VDDSRK_LSB) |
+ (1 << GC_PMU_SETDIS_RETCOMPREF_LSB) |
+ (1 << GC_PMU_SETDIS_BIAS_LSB) |
+ (1 << GC_PMU_SETDIS_BGAP_LSB) |
+ (1 << GC_PMU_SETDIS_VDDXO_LSB) |
+ (1 << GC_PMU_SETDIS_VDDXOLP_LSB) |
+ (1 << GC_PMU_SETDIS_XTL_LSB) |
+ (1 << GC_PMU_SETDIS_RC_TRIM_LSB) |
+ (1 << GC_PMU_SETDIS_RC_NOTRIM_LSB) |
+ (1 << GC_PMU_SETDIS_BATMON_LSB) |
+ (1 << GC_PMU_SETDIS_FST_BRNOUT_PWR_LSB) |
+ (1 << GC_PMU_SETDIS_FST_BRNOUT_LSB);
+
+ /* Wait for powerdown */
+ for (;;)
+ __asm__("wfi");
+}
+
+/*
+ * Exit powerdown mode
+ * This function should be called after a powerdown exit event.
+ * It handles turning the power domains back on.
+ * Clocks will be left in RC no trim.
+ */
+void pmu_powerdown_exit(void)
+{
+ /* Turn on power to everything */
+ GREG32(PMU, CLRDIS) = (1 << GC_PMU_CLRDIS_START_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDL_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDA_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDSRM_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDIOF_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDLK_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDSK_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDSRK_LSB) |
+ (1 << GC_PMU_CLRDIS_RETCOMPREF_LSB) |
+ (1 << GC_PMU_CLRDIS_BIAS_LSB) |
+ (1 << GC_PMU_CLRDIS_BGAP_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDXO_LSB) |
+ (1 << GC_PMU_CLRDIS_VDDXOLP_LSB) |
+ (1 << GC_PMU_CLRDIS_XTL_LSB) |
+ (1 << GC_PMU_CLRDIS_RC_TRIM_LSB) |
+ (1 << GC_PMU_CLRDIS_RC_NOTRIM_LSB) |
+ (1 << GC_PMU_CLRDIS_BATMON_LSB) |
+ (1 << GC_PMU_CLRDIS_FST_BRNOUT_PWR_LSB) |
+ (1 << GC_PMU_CLRDIS_FST_BRNOUT_LSB);
+}
+
+/**
+ * Handle PMU interrupt
+ */
+void pmu_interrupt(void)
+{
+ /* TBD */
+}
+DECLARE_IRQ(GC_IRQNUM_PMU_PMUINT, pmu_interrupt, 1);
diff --git a/chip/g/pmu.h b/chip/g/pmu.h
new file mode 100644
index 0000000000..7411735850
--- /dev/null
+++ b/chip/g/pmu.h
@@ -0,0 +1,113 @@
+/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef INC_PMU_H_
+#define INC_PMU_H_
+
+#include "common.h"
+#include "registers.h"
+
+enum {
+ PERIPH_AES = 0x0,
+ PERIPH_AES0 = 0x0,
+ PERIPH_AES1 = 0x1,
+
+ PERIPH_CAMO = 0x2,
+ PERIPH_CAMO0 = 0x2,
+
+ PERIPH_FLASH = 0x3,
+ PERIPH_FLASH0 = 0x3,
+
+ GLOBALSEC = 0x4,
+ GLOBALSEC0 = 0x4,
+
+ PERIPH_GPIO = 0x5,
+ PERIPH_GPIO0 = 0x5,
+ PERIPH_GPIO1 = 0x6,
+
+ PERIPH_I2C = 0x7,
+ PERIPH_I2C0 = 0x7,
+ PERIPH_I2C1 = 0x8,
+
+ PERIPH_I2CS = 0x9,
+ PERIPH_I2CS0 = 0x9,
+
+ PERIPH_MAU = 0xa,
+ PERIPH_PAU = 0xb,
+ PERIPH_PINMUX = 0xc,
+ PERIPH_PMU = 0xd,
+
+ PERIPH_RBOX = 0xe,
+ PERIPH_RBOX0 = 0xe,
+
+ PERIPH_RTC = 0xf,
+ PERIPH_RTC0 = 0xf,
+
+ PERIPH_SHA = 0x10,
+ PERIPH_SHA0 = 0x10,
+
+ PERIPH_SPI = 0x11,
+ PERIPH_SPI0 = 0x11,
+
+ PERIPH_SPS = 0x12,
+ PERIPH_SPS0 = 0x12,
+
+ PERIPH_SWDP = 0x13,
+ PERIPH_SWDP0 = 0x13,
+
+ PERIPH_TEMP = 0x14,
+ PERIPH_TEMP0 = 0x14,
+
+ PERIPH_TIMEHS = 0x15,
+ PERIPH_TIMEHS0 = 0x15,
+ PERIPH_TIMEHS1 = 0x16,
+
+ PERIPH_TIMELS = 0x17,
+ PERIPH_TIMELS0 = 0x17,
+
+ PERIPH_TRNG = 0x18,
+ PERIPH_TRNG0 = 0x18,
+
+ PERIPH_UART = 0x19,
+ PERIPH_UART0 = 0x19,
+ PERIPH_UART1 = 0x1a,
+ PERIPH_UART2 = 0x1b,
+
+ PERIPH_USB = 0x1c,
+ PERIPH_USB0 = 0x1c,
+ PERIPH_USB0_USB_PHY = 0x1d,
+
+ PERIPH_WATCHDOG = 0x1e,
+ PERIPH_WATCHDOG0 = 0x1e,
+
+ PERIPH_XO = 0x1f,
+ PERIPH_XO0 = 0x1f,
+
+ PERIPH_PERI = 0x20,
+ PERIPH_PERI0 = 0x20,
+ PERIPH_PERI1 = 0x21,
+
+ PERIPH_PERI_MATRIX = 0x22,
+};
+
+typedef void (*pmu_clock_func)(uint32_t periph);
+extern void pmu_clock_en(uint32_t periph);
+extern void pmu_clock_dis(uint32_t periph);
+extern void pmu_peripheral_rst(uint32_t periph);
+extern uint32_t pmu_calibrate_rc_trim(void);
+extern uint32_t pmu_clock_switch_rc_notrim(void);
+extern uint32_t pmu_clock_switch_rc_trim(uint32_t skip_calibration);
+extern uint32_t pmu_clock_switch_xo(void);
+extern void pmu_sleep(void);
+extern void pmu_hibernate(void);
+extern void pmu_hibernate_exit(void);
+extern void pmu_powerdown(void);
+extern void pmu_powerdown_exit(void);
+
+/*
+ * enable clock doubler for USB purposes
+ */
+void pmu_enable_clock_doubler(void);
+#endif /* INC_PMU_H_ */