- Main Page
- Related Pages
- Data Structures
- Files

- File List
- Globals

# drivers/pm/pm.c

Go to the documentation of this file.

    00001
    00041 #include <assert.h>
    00042 #include <interrupt.h>
    00043 #include <io.h>
    00044 #include <status-codes.h>
    00045 #include <timeout.h>
    00046 #include <chip/clk.h>
    00047
    00048 #ifndef CONFIG_PLL_STARTUP_CYCLES
    00049 # define CONFIG_PLL_STARTUP_CYCLES      63
    00050 #endif
    00051
    00052 #define PLL_TIMEOUT_MS                                          \
    00053         div_ceil(1000 * (CONFIG_PLL_STARTUP_CYCLES * 2),        \
    00054                         PM_RCOSC_MIN_RATE)
    00055
    00056 static int8_t osc_count[PM_NR_OSCS];
    00057 static int8_t pll_count[PM_NR_PLLS];
    00058
    00059 #if !defined(CONFIG_CLK_OSC0_MAIN)
    00060 unsigned long main_clock_rate = BOARD_OSC0_HZ;
    00061
    00066 void pm_priv_set_main_clock(enum pm_mainclk_src source,
    00067                 unsigned long rate)
    00068 {
    00069         uint32_t        mcctrl;
    00070         unsigned long   iflags;
    00071
    00072         assert(!(PM_MCCTRL_MCSEL(source) & ~PM_MCCTRL_MCSEL_MASK));
    00073
    00074         iflags = cpu_irq_save();
    00075         mcctrl = pm_read_reg(MCCTRL);
    00076         mcctrl &= ~PM_MCCTRL_MCSEL_MASK;
    00077         mcctrl |= PM_MCCTRL_MCSEL(source);
    00078         pm_write_reg(MCCTRL, mcctrl);
    00079         pm_read_reg(MCCTRL);
    00080
    00081         main_clock_rate = rate;
    00082         cpu_irq_restore(iflags);
    00083 }
    00084 #endif
    00085
    00086 int pm_enable_pll_sync(unsigned int id)
    00087 {
    00088         struct timeout  timeout;
    00089
    00090         assert(id < ARRAY_LEN(pll_count));
    00091         assert(cpu_irq_is_enabled());
    00092
    00093         /* Enable the PLL if it hasn't been enabled already */
    00094         cpu_irq_disable();
    00095         assert(pll_count[id] >= 0);
    00096         if (pll_count[id]++ == 0) {
    00097                 uint32_t        pllctrl;
    00098
    00099                 pllctrl = pm_read_reg(PLL(id));
    00100                 pllctrl |= PM_PLL_PLLEN;
    00101                 pm_write_reg(PLL(id), pllctrl);
    00102         }
    00103         cpu_irq_enable();
    00104
    00105         /* Return immediately if it's already running */
    00106         if (pm_read_reg(POSCSR) & PM_LOCK(id))
    00107                 return STATUS_OK;
    00108
    00109         /* Wait for it to lock */
    00110         timeout_init_ms(&timeout, PLL_TIMEOUT_MS);
    00111         do {
    00112                 if (pm_read_reg(POSCSR) & PM_LOCK(id))
    00113                         return STATUS_OK;
    00114         } while (!timeout_has_expired(&timeout));
    00115
    00116         return -STATUS_TIMEOUT;
    00117 }
    00118
    00119 unsigned long pm_init_pll(unsigned int id, enum pm_pll_src source,
    00120                 unsigned int div, unsigned int mul,
    00121                 unsigned long flags)
    00122 {
    00123         uint32_t        pllctrl;
    00124         unsigned long   rate;
    00125
    00126         /* Sanity checks */
    00127         assert(id < PM_NR_PLLS);
    00128         assert(source < 2);
    00129         assert(div > 0 && div < 256);
    00130         assert(mul > 1 && mul < 256);
    00131         assert(!(pm_read_reg(PLL(id)) & PM_PLL_PLLEN));
    00132
    00133         /* Calculate the target rate */
    00134         rate = (pm_priv_get_pll_src_rate(source) + div / 2) / div;
    00135         rate *= mul;
    00136
    00137         /* Configure the PLL */
    00138         pllctrl = PM_PLL_PLLOSC(source);
    00139         pllctrl |= flags;
    00140         if (PM_VERSION < PM_MKVERSION(3, 0, 0))
    00141                 mul--;
    00142         if (PM_VERSION < PM_MKVERSION(2, 0, 0))
    00143                 div--;
    00144
    00145         pllctrl |= PM_PLL_PLLDIV(div);
    00146         pllctrl |= PM_PLL_PLLMUL(mul);
    00147         pllctrl |= PM_PLL_PLLCOUNT(CONFIG_PLL_STARTUP_CYCLES);
    00148         pllctrl |= pm_priv_pll_rate_opt(rate);
    00149         pm_write_reg(PLL(id), pllctrl);
    00150
    00151         if (flags & PM_PLL_OUTPUT_DIV_BY_2)
    00152                 rate = (rate + 1) / 2;
    00153
    00154         return rate;
    00155 }
    00156
    00157 unsigned long pm_get_pll_rate(unsigned int id)
    00158 {
    00159         uint32_t        pllctrl;
    00160         unsigned long   rate;
    00161         unsigned int    source;
    00162         unsigned int    mul;
    00163         unsigned int    div;
    00164
    00165         pllctrl = pm_read_reg(PLL(id));
    00166         if (!(pllctrl & PM_PLL_PLLEN))
    00167                 return 0;
    00168
    00169         source = PM_PLL_GET_PLLOSC(pllctrl);
    00170         mul = PM_PLL_GET_PLLMUL(pllctrl);
    00171         div = PM_PLL_GET_PLLDIV(pllctrl);
    00172
    00173         if (PM_VERSION < PM_MKVERSION(2, 0, 0))
    00174                 div++;
    00175         if (PM_VERSION < PM_MKVERSION(3, 0, 0))
    00176                 mul++;
    00177
    00178         rate = (pm_priv_get_pll_src_rate(source) + div / 2) / div;
    00179         rate *= mul;
    00180         if (pllctrl & PM_PLL_OUTPUT_DIV_BY_2)
    00181                 rate = (rate + 1) / 2;
    00182
    00183         return rate;
    00184 }
    00185
    00186 int pm_priv_enable_osc_sync(unsigned int index, unsigned long startup_us)
    00187 {
    00188         struct timeout  timeout;
    00189
    00190         assert(index < ARRAY_LEN(osc_count));
    00191         assert(cpu_irq_is_enabled());
    00192
    00193         /* Enable the oscillator if it hasn't been enabled already */
    00194         cpu_irq_disable();
    00195         assert(osc_count[index] >= 0);
    00196         if (osc_count[index]++ == 0) {
    00197                 uint32_t        mcctrl;
    00198
    00199                 mcctrl = pm_read_reg(MCCTRL);
    00200                 mcctrl |= PM_MCCTRL_OSCEN(index);
    00201                 pm_write_reg(MCCTRL, mcctrl);
    00202         }
    00203         cpu_irq_enable();
    00204
    00205         /* Return immediately if it's already running */
    00206         if (pm_read_reg(POSCSR) & PM_OSCRDY(index))
    00207                 return STATUS_OK;
    00208
    00209         /* Otherwise, wait for it to start */
    00210         timeout_init_us(&timeout, startup_us * 2 + 100);
    00211         do {
    00212                 if (pm_read_reg(POSCSR) & PM_OSCRDY(index))
    00213                         return STATUS_OK;
    00214         } while (!timeout_has_expired(&timeout));
    00215
    00216         return -STATUS_TIMEOUT;
    00217 }