| /**************************************************************************** |
| * arch/arm/src/max326xx/max32660/max32660_clockconfig.c |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <assert.h> |
| #include <debug.h> |
| |
| #include <nuttx/irq.h> |
| |
| #include "arm_internal.h" |
| #include "hardware/max326_gcr.h" |
| #include "hardware/max326_pwrseq.h" |
| #include "hardware/max326_flc.h" |
| #include "max326_periphclks.h" |
| #include "max326_clockconfig.h" |
| |
| #include <arch/board/board.h> |
| |
| /**************************************************************************** |
| * Public Data |
| ****************************************************************************/ |
| |
| /* This describes the initial clock configuration. It is needed by |
| * max326_start.c |
| */ |
| |
| const struct clock_setup_s g_initial_clock_setup = |
| { |
| .ovr = 2, /* Output voltage range for internal regulator */ |
| .clksrc = CLKSRC_HFIO, /* See enum clock_source_e. Determines Fsysosc */ |
| .psc = 0, /* System Oscillator Prescaler. Derives Fsysclk */ |
| .hfio = true, /* True: Enable the High frequency internal oscillator. */ |
| #ifdef BOARD_HAVE_X32K |
| .x32k = true, /* True: Enable the 32.768KHz ext crystal oscillator. */ |
| #endif |
| }; |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: max326_sysosc_frequency |
| * |
| * Description: |
| * Return the SYSOSC frequency. This is simply the frequency of the |
| * selected clock source. |
| * |
| ****************************************************************************/ |
| |
| static uint32_t max326_sysosc_frequency(void) |
| { |
| uint32_t regval; |
| |
| /* The clock source is in the GCR_CLKCTRL:CLKCTRL field */ |
| |
| regval = getreg32(MAX326_GCR_CLKCTRL); |
| switch ((regval & GCR_CLKCTRL_CLKSEL_MASK) >> GCR_CLKCTRL_CLKSEL_SHIFT) |
| { |
| default: |
| DEBUGPANIC(); |
| case CLKSRC_HFIO: |
| return max326_hfio_frequency(); |
| |
| case CLKSRC_8KHZ: |
| return 8000000; /* Nominally 8MHz */ |
| |
| case CLKSRC_32KHZ: |
| return 32768; |
| } |
| } |
| |
| /**************************************************************************** |
| * Name: max326_sysclk_frequency |
| * |
| * Description: |
| * Return the SYSCLK frequency. The SYSCLOCK is simply divided down from |
| * the SYSOSC. |
| * |
| ****************************************************************************/ |
| |
| static uint32_t max326_sysclk_frequency(void) |
| { |
| uint32_t regval; |
| uint32_t psc; |
| |
| /* The divider is in the GCR_CLKCTRL:PSC setting: |
| * |
| * Fsysclk = Fsysclk / (2^psc) |
| */ |
| |
| regval = getreg32(MAX326_GCR_CLKCTRL); |
| psc = (regval & GCR_CLKCTRL_PSC_MASK) >> GCR_CLKCTRL_PSC_SHIFT; |
| return max326_sysosc_frequency() >> psc; |
| } |
| |
| /**************************************************************************** |
| * Name: max326_enable_hfio |
| * |
| * Description: |
| * Enable High-Frequency Internal Oscillator (HFIO) if it is needed. |
| * |
| ****************************************************************************/ |
| |
| static void max326_enable_hfio(const struct clock_setup_s *clksetup) |
| { |
| uint32_t regval; |
| |
| /* Check if the HFIO is needed. */ |
| |
| if (clksetup->hfio) |
| { |
| /* Yes.. Enable the HFIO. */ |
| |
| regval = getreg32(MAX326_GCR_CLKCTRL); |
| regval |= GCR_CLKCTRL_HIRCEN; |
| putreg32(regval, MAX326_GCR_CLKCTRL); |
| |
| /* Wait for the oscillator to become ready */ |
| |
| while ((getreg32(MAX326_GCR_CLKCTRL) & GCR_CLKCTRL_HIRCRDY) == 0) |
| { |
| } |
| } |
| } |
| |
| /**************************************************************************** |
| * Name: max326_disable_hfio |
| * |
| * Description: |
| * Disable the High-Frequency Internal Oscillator (HFIO) if it is not used. |
| * |
| ****************************************************************************/ |
| |
| static void max326_disable_hfio(const struct clock_setup_s *clksetup) |
| { |
| uint32_t regval; |
| |
| /* Check if the HFIO is used. */ |
| |
| if (!clksetup->hfio) |
| { |
| /* No.. Disable the HFIO */ |
| |
| regval = getreg32(MAX326_GCR_CLKCTRL); |
| regval &= ~GCR_CLKCTRL_HIRCEN; |
| putreg32(regval, MAX326_GCR_CLKCTRL); |
| } |
| } |
| |
| /**************************************************************************** |
| * Name: max326_select_hfio |
| * |
| * Description: |
| * Select the High-Frequency Internal Oscillator (HFIO) as the SYSOSC |
| * clock source. |
| * |
| ****************************************************************************/ |
| |
| static void max326_select_hfio(void) |
| { |
| uint32_t regval; |
| |
| /* Select the HIFO as the SYSOSC clock source. */ |
| |
| regval = getreg32(MAX326_GCR_CLKCTRL); |
| regval &= ~GCR_CLKCTRL_CLKSEL_MASK; |
| regval |= GCR_CLKCTRL_CLKSEL_HIRC; |
| putreg32(regval, MAX326_GCR_CLKCTRL); |
| } |
| |
| /**************************************************************************** |
| * Name: max326_select_lirc8k |
| * |
| * Description: |
| * Select the 8kHz Internal Ultra-Low Power Nano-Ring Oscillator as the |
| * SYSOSC clock source. |
| * |
| ****************************************************************************/ |
| |
| static void max326_select_lirc8k(void) |
| { |
| uint32_t regval; |
| |
| /* The 8kHz nano-ring oscillator is "always-on": "This oscillator is |
| * enabled at device powerup by hardware and cannot be disabled by |
| * application firmware. |
| */ |
| |
| /* Make sure that the oscillator is ready */ |
| |
| while ((getreg32(MAX326_GCR_CLKCTRL) & GCR_CLKCTRL_LIRC8KRDY) == 0) |
| { |
| } |
| |
| /* Select the 8kHz nano-ring oscillator as the SYSOSC clock source. */ |
| |
| regval = getreg32(MAX326_GCR_CLKCTRL); |
| regval &= ~GCR_CLKCTRL_CLKSEL_MASK; |
| regval |= GCR_CLKCTRL_CLKSEL_LIRC8K; |
| putreg32(regval, MAX326_GCR_CLKCTRL); |
| } |
| |
| /**************************************************************************** |
| * Name: max326_enable_x32k |
| * |
| * Description: |
| * Enable the 32.768kHz External Crystal Oscillator if is it needed. |
| * |
| ****************************************************************************/ |
| |
| #ifdef BOARD_HAVE_X32K |
| static void max326_enable_x32k(const struct clock_setup_s *clksetup) |
| { |
| uint32_t regval; |
| |
| /* Check if the 2.768kHz External Crystal Oscillator is needed. */ |
| |
| regval = getreg32(MAX326_GCR_CLKCTRL); |
| if (clksetup->x32k) |
| { |
| /* Yes.. Enable the 32.768kHz external oscillator. */ |
| |
| regval |= GCR_CLKCTRL_X32KEN; |
| putreg32(regval, MAX326_GCR_CLKCTRL); |
| |
| /* Wait for the oscillator to become ready */ |
| |
| while ((getreg32(MAX326_GCR_CLKCTRL) & GCR_CLKCTRL_X32KRDY) == 0) |
| { |
| } |
| } |
| } |
| #endif |
| |
| /**************************************************************************** |
| * Name: max326_disable_x32k |
| * |
| * Description: |
| * Disable the 32.768 KHz crystal oscillator if it is not used |
| * |
| ****************************************************************************/ |
| |
| #ifdef BOARD_HAVE_X32K |
| static void max326_disable_x32k(const struct clock_setup_s *clksetup) |
| { |
| uint32_t regval; |
| |
| /* Check if the 32.768 KHz crystal oscillator is used */ |
| |
| if (!clksetup->x32k) |
| { |
| /* No.. Disable the 32.768kHz external oscillator. */ |
| |
| regval = getreg32(MAX326_GCR_CLKCTRL); |
| regval &= ~GCR_CLKCTRL_X32KEN; |
| putreg32(regval, MAX326_GCR_CLKCTRL); |
| } |
| } |
| #endif |
| |
| /**************************************************************************** |
| * Name: max326_select_x32k |
| * |
| * Description: |
| * Select the 32.768kHz External Crystal Oscillator as the SYSOSC clock |
| * source. |
| * |
| ****************************************************************************/ |
| |
| #ifdef BOARD_HAVE_X32K |
| static void max326_select_x32k(void) |
| { |
| uint32_t regval; |
| |
| /* Select the 32.768kHz external oscillator as the SYSOSC clock |
| * source. |
| */ |
| |
| regval = getreg32(MAX326_GCR_CLKCTRL); |
| regval &= ~GCR_CLKCTRL_CLKSEL_MASK; |
| regval |= GCR_CLKCTRL_CLKSEL_X32K; |
| putreg32(regval, MAX326_GCR_CLKCTRL); |
| } |
| #endif |
| |
| /**************************************************************************** |
| * Name: max326_set_ovr |
| * |
| * Description: |
| * Set the operating voltage range selection. If the OVR setting is |
| * different from the previous setting, then upon return, we will be |
| * running on either the 32.768kHz external oscillator or the 8kHz nano- |
| * ring oscillator with SYCLK prescaler == 0. |
| * |
| ****************************************************************************/ |
| |
| static void max326_set_ovr(const struct clock_setup_s *clksetup) |
| { |
| uint32_t ovr; |
| uint32_t regval; |
| |
| #ifndef BOARD_HAVE_X32K |
| DEBUGASSERT(clksetup->ovr != CLKSRC_32KHZ); |
| #endif |
| |
| /* First check of the OVR setting is being changed */ |
| |
| regval = getreg32(MAX326_PWRSEQ_LPCTRL); |
| ovr = (regval & PWRSEQ_LPCTRL_OVR_MASK) >> PWRSEQ_LPCTRL_OVR_SHIFT; |
| if (ovr != clksetup->ovr) |
| { |
| /* Switch to the internal LDO for VCORE |
| * |
| * NOTE: "If using an external supply for VCORE, ensure the external |
| * supply is set to the same voltage as the current OVR setting. The |
| * external supply must be equal to or greater than the set OVR |
| * voltage." |
| */ |
| |
| regval &= ~PWRSEQ_LPCTRL_LDODIS; |
| putreg32(regval, MAX326_PWRSEQ_LPCTRL); |
| |
| /* Disable any SYSCLK divider */ |
| |
| regval = getreg32(MAX326_GCR_CLKCTRL); |
| regval &= ~GCR_CLKCTRL_PSC_MASK; |
| putreg32(regval, MAX326_GCR_CLKCTRL); |
| |
| #ifdef BOARD_HAVE_X32K |
| /* Select the 32.768kHz External Crystal Oscillator as the SYSOSC |
| * clock source (if it was enabled) |
| */ |
| |
| if (clksetup->x32k) |
| { |
| max326_select_x32k(); |
| } |
| else |
| #endif |
| { |
| /* Select the 8kHz Internal Ultra-Low Power Nano-Ring Oscillator |
| * as the SYSOSC clock source. |
| */ |
| |
| max326_select_lirc8k(); |
| } |
| |
| /* Wait for SYSOSC to become ready */ |
| |
| while ((getreg32(MAX326_GCR_CLKCTRL) & GCR_CLKCTRL_CLKRDY) == 0) |
| { |
| } |
| |
| /* Change the OVR setting to the desired range */ |
| |
| regval = getreg32(MAX326_PWRSEQ_LPCTRL); |
| regval &= ~PWRSEQ_LPCTRL_OVR_MASK; |
| regval |= PWRSEQ_LPCTRL_OVR(clksetup->ovr); |
| putreg32(regval, MAX326_PWRSEQ_LPCTRL); |
| } |
| |
| /* Set the Flash Low Voltage Enable according to the OVR setting */ |
| |
| regval = getreg32(MAX326_FLC_CTRL); |
| if (clksetup->ovr < 2) |
| { |
| regval |= FLC_CTRL_LVE; |
| } |
| else |
| { |
| regval &= ~FLC_CTRL_LVE; |
| } |
| |
| putreg32(regval, MAX326_FLC_CTRL); |
| } |
| |
| /**************************************************************************** |
| * Name: max326_set_clksrc |
| * |
| * Description: |
| * Select the requested clock source. |
| * |
| ****************************************************************************/ |
| |
| static void max326_set_clksrc(const struct clock_setup_s *clksetup) |
| { |
| uint32_t regval; |
| uint32_t clksrc; |
| |
| /* Set the system clock source if it is different from the currently |
| * selected clock source. |
| */ |
| |
| regval = getreg32(MAX326_GCR_CLKCTRL); |
| clksrc = (regval & GCR_CLKCTRL_CLKSEL_MASK) >> GCR_CLKCTRL_CLKSEL_SHIFT; |
| |
| if (clksrc != clksetup->clksrc) |
| { |
| /* Set the selected clock source */ |
| |
| switch (clksetup->clksrc) |
| { |
| case CLKSRC_HFIO: /* High frequency internal oscillator */ |
| |
| /* Select the High-Frequency Internal Oscillator (HFIO) as the |
| * SYSOSC clock source. |
| */ |
| |
| DEBUGASSERT(clksetup->hfio); |
| max326_select_hfio(); |
| break; |
| |
| case CLKSRC_8KHZ: /* 8kHz Internal Ultra-Low Power Nano-Ring Oscillator */ |
| |
| /* Select the 8kHz Internal Ultra-Low Power Nano-Ring Oscillator |
| * as the SYSOSC clock source. |
| */ |
| |
| max326_select_lirc8k(); |
| break; |
| |
| case CLKSRC_32KHZ: /* 32.768kHz External Crystal Oscillator */ |
| #ifdef BOARD_HAVE_X32K |
| /* Select the 32.768kHz External Crystal Oscillator as the |
| * SYSOSC clock source. |
| */ |
| |
| DEBUGASSERT(clksetup->x32k); |
| max326_select_x32k(); |
| break; |
| #endif |
| |
| default: |
| DEBUGPANIC(); |
| return; |
| } |
| |
| /* Wait for SYSOSC to become ready */ |
| |
| while ((getreg32(MAX326_GCR_CLKCTRL) & GCR_CLKCTRL_CLKRDY) == 0) |
| { |
| } |
| } |
| |
| /* Set the SYSCLK prescaler */ |
| |
| regval = getreg32(MAX326_GCR_CLKCTRL); |
| regval &= ~GCR_CLKCTRL_PSC_MASK; |
| regval |= GCR_CLKCTRL_PSC(clksetup->psc); |
| putreg32(regval, MAX326_GCR_CLKCTRL); |
| } |
| |
| /**************************************************************************** |
| * Name: max326_set_fwsdefault |
| * |
| * Description: |
| * Set the the FLASH wait states to the default value (5) |
| * |
| ****************************************************************************/ |
| |
| static void max326_set_fwsdefault(void) |
| { |
| uint32_t regval; |
| |
| /* Set the number of Flash Wait States to the POR default value of 5. */ |
| |
| regval = getreg32(MAX326_GCR_MEMCTRL); |
| regval &= ~GCR_MEMCTRL_FWS_MASK; |
| regval |= GCR_MEMCTRL_FWS(5); |
| putreg32(regval, MAX326_GCR_MEMCTRL); |
| } |
| |
| /**************************************************************************** |
| * Name: max326_set_fws |
| * |
| * Description: |
| * Set an optimal value for the FLASH wait states. |
| * |
| ****************************************************************************/ |
| |
| static void max326_set_fws(void) |
| { |
| uint32_t regval; |
| uint32_t sysclk; |
| uint32_t fws; |
| |
| /* Get the SYSCLK frequency */ |
| |
| sysclk = max326_sysclk_frequency(); |
| |
| /* Set the FLASH states according to the SYSCLK frequency. |
| * |
| * This does not quite match the settings in Table 4.2 of the User Guide. |
| * that table has 1 or 2 wait states at 24MHz and 2 or 3 wait states at |
| * 48MH. Perhaps there is more to the wait state calculations than raw |
| * SYSCLK frequency? |
| */ |
| |
| if (sysclk < 24000000) |
| { |
| fws = 1; |
| } |
| else if (sysclk < 48000000) |
| { |
| fws = 2; |
| } |
| else if (sysclk < 72000000) |
| { |
| fws = 3; |
| } |
| else if (sysclk <= 96000000) |
| { |
| fws = 4; |
| } |
| else |
| { |
| fws = 5; |
| } |
| |
| regval = getreg32(MAX326_GCR_MEMCTRL); |
| regval &= ~GCR_MEMCTRL_FWS_MASK; |
| regval |= GCR_MEMCTRL_FWS(fws); |
| putreg32(regval, MAX326_GCR_MEMCTRL); |
| } |
| |
| /**************************************************************************** |
| * Name: max326_periph_reset |
| * |
| * Description: |
| * Set an optimal value for the FLASH wait states. |
| * |
| ****************************************************************************/ |
| |
| static void max326_periph_reset(void) |
| { |
| uint32_t regval; |
| |
| /* Initiate the peripheral reset */ |
| |
| regval = getreg32(MAX326_GCR_RST0); |
| regval |= GCR_RST0_PERIPH; |
| putreg32(regval, MAX326_GCR_RST0); |
| |
| /* Wait for the peripheral reset to complete */ |
| |
| while ((getreg32(MAX326_GCR_RST0) & GCR_RST0_PERIPH) != 0) |
| { |
| } |
| } |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: max326_clockconfig |
| * |
| * Description: |
| * Called to initialize the MAX3266xx. This does whatever setup is needed |
| * to put the MCU in a usable state. This includes the initialization of |
| * clocking using the settings in board.h. This function also performs |
| * other low-level chip as necessary. |
| * |
| ****************************************************************************/ |
| |
| void max326_clockconfig(const struct clock_setup_s *clksetup) |
| { |
| /* Set the the FLASH wait states to the default value (5) */ |
| |
| max326_set_fwsdefault(); |
| |
| #ifdef BOARD_HAVE_X32K |
| /* Enable the 32.768 KHz crystal oscillator if it is needed */ |
| |
| max326_enable_x32k(clksetup); |
| #endif |
| |
| /* Enable the High frequency internal oscillator if it is needed */ |
| |
| max326_enable_hfio(clksetup); |
| |
| /* Set the operating voltage range selection. If the OVR setting is |
| * different from the previous setting, then upon return, we will be |
| * running on either the 32.768kHz external oscillator or the 8kHz nano- |
| * ring oscillator with SYCLK prescaler == 0. |
| */ |
| |
| max326_set_ovr(clksetup); |
| |
| /* Select the requested clock source. */ |
| |
| max326_set_clksrc(clksetup); |
| |
| #ifdef BOARD_HAVE_X32K |
| /* Disable the 32.768 KHz crystal oscillator if it is not used */ |
| |
| max326_disable_x32k(clksetup); |
| #endif |
| |
| /* Disable the High frequency internal oscillator if it is not used. */ |
| |
| max326_disable_hfio(clksetup); |
| |
| /* Set an optimal value for the FLASH wait states */ |
| |
| max326_set_fws(); |
| |
| /* Perform a peripheral reset */ |
| |
| max326_periph_reset(); |
| |
| /* Disable most clocks to peripherals by default to reduce power */ |
| |
| #ifndef CONFIG_MAX326XX_DMA |
| max326_dma_disableclk(); |
| #endif |
| #if !defined(CONFIG_MAX326XX_SPIM0) && !defined(CONFIG_MAX326XX_SPIS0) |
| max326_spi0_disableclk(); |
| #endif |
| #if !defined(CONFIG_MAX326XX_SPIM1) && !defined(CONFIG_MAX326XX_SPIS1) |
| max326_spi1_disableclk(); |
| #endif |
| #ifndef CONFIG_MAX326XX_UART0 |
| max326_uart0_disableclk(); |
| #endif |
| #ifndef CONFIG_MAX326XX_UART1 |
| max326_uart1_disableclk(); |
| #endif |
| #if !defined(CONFIG_MAX326XX_I2CM0) && !defined(CONFIG_MAX326XX_I2CS0) |
| max326_i2c0_disableclk(); |
| #endif |
| #if !defined(CONFIG_MAX326XX_I2CM1) && !defined(CONFIG_MAX326XX_I2CS1) |
| max326_i2c1_disableclk(); |
| #endif |
| #ifndef CONFIG_MAX326XX_TMR32_0 |
| max326_tmr0_disableclk(); |
| #endif |
| #ifndef CONFIG_MAX326XX_TMR32_1 |
| max326_tmr1_disableclk(); |
| #endif |
| #ifndef CONFIG_MAX326XX_TMR32_0 |
| max326_tmr2_disableclk(); |
| #endif |
| } |
| |
| /**************************************************************************** |
| * Name: max326_hfio_frequency |
| * |
| * Description: |
| * Return the High-Frequency Internal Oscillator (HFIO) frequency. |
| * |
| ****************************************************************************/ |
| |
| uint32_t max326_hfio_frequency(void) |
| { |
| uint32_t regval; |
| |
| /* The HFIO frequency depends of the PWRSEQ_LP_CTRL:OVR setting */ |
| |
| regval = getreg32(MAX326_PWRSEQ_LPCTRL); |
| switch ((regval & PWRSEQ_LPCTRL_OVR_MASK) >> PWRSEQ_LPCTRL_OVR_SHIFT) |
| { |
| case 0: |
| return 24000000; /* Nominally 24MHz */ |
| |
| case 1: |
| return 48000000; /* Nominally 48MHz */ |
| |
| default: |
| DEBUGPANIC(); |
| case 2: |
| return 96000000; /* Nominally 96MHz */ |
| } |
| } |
| |
| /**************************************************************************** |
| * Name: max326_cpu_frequency |
| * |
| * Description: |
| * Return the current CPU frequency. |
| * |
| ****************************************************************************/ |
| |
| uint32_t max326_cpu_frequency(void) |
| { |
| return max326_sysclk_frequency(); |
| } |
| |
| /**************************************************************************** |
| * Name: max326_pclk_frequency |
| * |
| * Description: |
| * Return the current peripheral clock frequency. |
| * |
| ****************************************************************************/ |
| |
| uint32_t max326_pclk_frequency(void) |
| { |
| /* Fpclk = Fsysclk / 2 */ |
| |
| return max326_sysclk_frequency() >> 1; |
| } |