static void use_hfrosc(int div, int trim) { // Make sure the HFROSC is running at its default setting PRCI_REG(PRCI_HFROSCCFG) = (ROSC_DIV(div) | ROSC_TRIM(trim) | ROSC_EN(1)); while ((PRCI_REG(PRCI_HFROSCCFG) & ROSC_RDY(1)) == 0) ; PRCI_REG(PRCI_PLLCFG) &= ~PLL_SEL(1); }
void select_clock(const clock_config_t *cfg) { uint32_t new_qspi_div = 0; uint32_t old_qspi_div = SPI0_REG(SPI_REG_SCKDIV); /* Clock based on external escilator */ if (!cfg->xosc || cfg->pll) { /* Turn on internal oscillator */ PRCI_REG(PRCI_HFROSCCFG) = ROSC_DIV(cfg->osc_div) | ROSC_TRIM(MYNEWT_VAL(HFROSC_DEFAULT_TRIM_VAL)) | ROSC_EN(1); while ((PRCI_REG(PRCI_HFROSCCFG) & ROSC_RDY(1)) == 0) { } /* Compute CPU frequency on demand */ cpu_freq = 0; } if (cfg->xosc) { /* Turn on external oscillator if not ready yet */ if ((PRCI_REG(PRCI_HFXOSCCFG) & XOSC_RDY(1)) == 0) { PRCI_REG(PRCI_HFXOSCCFG) = XOSC_EN(1); while ((PRCI_REG(PRCI_HFXOSCCFG) & XOSC_RDY(1)) == 0) { } } cpu_freq = cfg->frq; } /* * If reqested closk is higher then FLASH_MAX_CLOCK change divider so QSPI * clock is in rage. */ if (cfg->frq >= MYNEWT_VAL(FLASH_MAX_CLOCK) * 2) { new_qspi_div = (cfg->frq + MYNEWT_VAL(FLASH_MAX_CLOCK) - 1) / (2 * MYNEWT_VAL(FLASH_MAX_CLOCK)) - 1; } /* New qspi divider is higher, reduce qspi clock before switching to higher clock */ if (new_qspi_div > old_qspi_div) { SPI0_REG(SPI_REG_SCKDIV) = new_qspi_div; } PRCI_REG(PRCI_PLLDIV) = PLL_FINAL_DIV_BY_1(cfg->pll_outdiv1) | PLL_FINAL_DIV(cfg->pll_out_div); if (cfg->pll) { uint32_t now; uint32_t pllcfg = PLL_REFSEL(cfg->xosc) | PLL_R(cfg->pll_div_r) | PLL_F(cfg->pll_mul_f) | PLL_Q(cfg->pll_div_q); PRCI_REG(PRCI_PLLCFG) = PLL_BYPASS(1) | pllcfg; PRCI_REG(PRCI_PLLCFG) ^= PLL_BYPASS(1); /* 100us lock grace period */ now = mtime_lo(); while (mtime_lo() - now < 4) { } /* Now it is safe to check for PLL Lock */ while ((PRCI_REG(PRCI_PLLCFG) & PLL_LOCK(1)) == 0) { } /* Select PLL as clock source */ PRCI_REG(PRCI_PLLCFG) |= PLL_SEL(1) | pllcfg; } else { /* Select bypassed PLL as source signal, it allows to use HFXOSC */ PRCI_REG(PRCI_PLLCFG) = PLL_BYPASS(1) | PLL_REFSEL(cfg->xosc) | PLL_SEL(1); } /* * Old qspi divider was higher, now it's safe to reduce divider, increasing * qspi clock for better performance */ if (new_qspi_div < old_qspi_div) { SPI0_REG(SPI_REG_SCKDIV) = new_qspi_div; } }