text: /** @defgroup rcc_defines RCC Defines
  @brief <b>Defined Constants and Types for the STM32H7xx Reset and Clock
  Control</b>
  @ingroup STM32H7xx_defines
  @version 1.0.0
  LGPL License Terms @ref lgpl_license
   */
  /*
   * This file is part of the libopencm3 project.
   *
   * Copyright (C) 2019 Brian Viele <vielster@allocor.tech>
   *
   * This library is free software: you can redistribute it and/or modify
   * it under the terms of the GNU Lesser General Public License as published by
   * the Free Software Foundation, either version 3 of the License, or
   * (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public License
   * along with this library.  If not, see <http://www.gnu.org/licenses/>.
   */
  
  #ifndef LIBOPENCM3_RCC_H
  #define LIBOPENCM3_RCC_H
  
  #include <libopencm3/cm3/common.h>
  #include <libopencm3/stm32/h7/pwr.h>
  
  /**@{*/
  
  /** @defgroup rcc_registers RCC Registers
  @{*/
  #define RCC_CR                    MMIO32(RCC_BASE + 0x000)
  #define RCC_ICSCR                 MMIO32(RCC_BASE + 0x004)  /* Y-devices only */
  #define RCC_HSICFGR               MMIO32(RCC_BASE + 0x004)  /* V-devices only */
  #define RCC_CRRCR                 MMIO32(RCC_BASE + 0x008)
  #define RCC_CSICFGR               MMIO32(RCC_BASE + 0x00C)  /* V-devices only */
  #define RCC_CFGR                  MMIO32(RCC_BASE + 0x010)
  #define RCC_D1CFGR                MMIO32(RCC_BASE + 0x018)
  #define RCC_D2CFGR                MMIO32(RCC_BASE + 0x01C)
  #define RCC_D3CFGR                MMIO32(RCC_BASE + 0x020)
  #define RCC_PLLCKSELR             MMIO32(RCC_BASE + 0x028)
  #define RCC_PLLCFGR               MMIO32(RCC_BASE + 0x02C)
  /* PLLs are 1-based, so reference macros to 1..3, using index 0 will give undefined behavior. */
  #define RCC_PLLDIVR(n)            MMIO32(RCC_BASE + 0x030 + (0x08 * ((n) - 1)))
  #define RCC_PLLFRACR(n)           MMIO32(RCC_BASE + 0x030 + (0x08 * ((n) - 1)))
  #define RCC_PLL1DIVR              RCC_PLLDIVR(1)
  #define RCC_PLL1FRACR             RCC_PLLFRACR(1)
  #define RCC_PLL2DIVR              RCC_PLLDIVR(2)
  #define RCC_PLL2FRACR             RCC_PLLFRACR(2)
  #define RCC_PLL3DIVR              RCC_PLLDIVR(3)
  #define RCC_PLL3FRACR             RCC_PLLFRACR(3)
  #define RCC_D1CCIPR               MMIO32(RCC_BASE + 0x04C)
  #define RCC_D2CCIP1R              MMIO32(RCC_BASE + 0x050)
  #define RCC_D2CCIP2R              MMIO32(RCC_BASE + 0x054)
  #define RCC_D3CCIPR               MMIO32(RCC_BASE + 0x058)
  #define RCC_AHB1RSTR              MMIO32(RCC_BASE + 0x080)
  #define RCC_AHB2RSTR              MMIO32(RCC_BASE + 0x084)
  #define RCC_AHB3RSTR              MMIO32(RCC_BASE + 0x07C)
  #define RCC_AHB4RSTR              MMIO32(RCC_BASE + 0x088)
  #define RCC_APB1LRSTR             MMIO32(RCC_BASE + 0x090)
  #define RCC_APB1HRSTR             MMIO32(RCC_BASE + 0x094)
  #define RCC_APB2RSTR              MMIO32(RCC_BASE + 0x098)
  #define RCC_APB3RSTR              MMIO32(RCC_BASE + 0x08C)
  #define RCC_APB4RSTR              MMIO32(RCC_BASE + 0x09C)
  #define RCC_AHB1ENR               MMIO32(RCC_BASE + 0x0D8)
  #define RCC_AHB2ENR               MMIO32(RCC_BASE + 0x0DC)
  #define RCC_AHB3ENR               MMIO32(RCC_BASE + 0x0D4)
  #define RCC_AHB4ENR               MMIO32(RCC_BASE + 0x0E0)
  #define RCC_APB1LENR              MMIO32(RCC_BASE + 0x0E8)
  #define RCC_APB1HENR              MMIO32(RCC_BASE + 0x0EC)
  #define RCC_APB2ENR               MMIO32(RCC_BASE + 0x0F0)
  #define RCC_APB3ENR               MMIO32(RCC_BASE + 0x0E4)
  #define RCC_APB4ENR               MMIO32(RCC_BASE + 0x0F4)
  #define RCC_AHB1LPENR             MMIO32(RCC_BASE + 0x100)
  #define RCC_AHB2LPENR             MMIO32(RCC_BASE + 0x104)
  #define RCC_AHB4LPENR             MMIO32(RCC_BASE + 0x108)
  #define RCC_APB1LLPENR            MMIO32(RCC_BASE + 0x110)
  #define RCC_APB1HLPENR            MMIO32(RCC_BASE + 0x114)
  #define RCC_APB2LPENR             MMIO32(RCC_BASE + 0x118)
  #define RCC_APB3LPENR             MMIO32(RCC_BASE + 0x10C)
  #define RCC_APB4LPENR             MMIO32(RCC_BASE + 0x11C)
  #define RCC_BDCR                  MMIO32(RCC_BASE + 0x70)
  #define RCC_CSR                   MMIO32(RCC_BASE + 0x74)
  #define RCC_SSCGR                 MMIO32(RCC_BASE + 0x80)
  #define RCC_PLLI2SCFGR            MMIO32(RCC_BASE + 0x84)
  #define RCC_PLLSAICFGR            MMIO32(RCC_BASE + 0x88)
  #define RCC_DCKCFGR1              MMIO32(RCC_BASE + 0x8C)
  #define RCC_DCKCFGR2              MMIO32(RCC_BASE + 0x90)
  /**@}*/
  
  /** @defgroup rcc_cr_values RCC_CR Values
   * @ingroup rcc_registers
  @{*/
  #define RCC_CR_PLL3RDY            BIT29
  #define RCC_CR_PLL3ON             BIT28
  #define RCC_CR_PLL2RDY            BIT27
  #define RCC_CR_PLL2ON             BIT26
  #define RCC_CR_PLL1RDY            BIT25
  #define RCC_CR_PLL1ON             BIT24
  #define RCC_CR_HSECSSON           BIT19
  #define RCC_CR_HSEBYP             BIT18
  #define RCC_CR_HSERDY             BIT17
  #define RCC_CR_HSEON              BIT16
  #define RCC_CR_D2CKRDY            BIT15
  #define RCC_CR_D1CKRDY            BIT14
  #define RCC_CR_HSI48RDY           BIT13
  #define RCC_CR_HSI48ON            BIT12
  #define RCC_CR_CSIKERON           BIT9
  #define RCC_CR_CSIRDY             BIT8
  #define RCC_CR_CSION              BIT7
  #define RCC_CR_HSIDIVF            BIT5
  #define RCC_CR_HSIDIV_MASK        (0x03)
  #define RCC_CR_HSIDIV_SHIFT       3
  #define RCC_CR_HSIDIV(n)          (((n) & RCC_CR_HSIDIV_MASK) << RCC_CR_HSIDIV_MASK)
  #define RCC_CR_HSIRDY             BIT2
  #define RCC_CR_HSIKERON           BIT1
  #define RCC_CR_HSION              BIT0
  /**@}*/
  
  
  /** @defgroup rcc_cfgr_values RCC_CFGR Values
   * @ingroup rcc_registers
  @{*/
  /* MCO2: Microcontroller clock output 2 */
  #define RCC_CFGR_MCO2_MASK        0x7
  #define RCC_CFGR_MCO2_SHIFT       29
  #define RCC_CFGR_MCO2_SYSCLK      0x0
  #define RCC_CFGR_MCO2_PLL2        0x1
  #define RCC_CFGR_MCO2_HSE         0x2
  #define RCC_CFGR_MCO2_PLL1        0x3
  #define RCC_CFGR_MCO2_CSI         0x4
  #define RCC_CFGR_MCO2_LSI         0x5
  
  /* MCO1/2PRE: MCO Prescalers */
  #define RCC_CFGR_MCOPRE_MASK      0xf
  #define RCC_CFGR_MCO2PRE_SHIFT    25
  #define RCC_CFGR_MCO1PRE_SHIFT    18
  #define RCC_CFGR_MCOPRE_DIV_NONE  0x0
  #define RCC_CFGR_MCOPRE_DIV_BYP   0x1
  #define RCC_CFGR_MCOPRE_DIV_2     0x2
  #define RCC_CFGR_MCOPRE_DIV_3     0x3
  #define RCC_CFGR_MCOPRE_DIV_4     0x4
  /* Note: MCOPRE_DIV can go from 1 - 15  */
  
  /* MCO1: Microcontroller clock output 1 */
  #define RCC_CFGR_MCO1_MASK        0x7
  #define RCC_CFGR_MCO1_SHIFT       22
  #define RCC_CFGR_MCO1_HSI         0x0
  #define RCC_CFGR_MCO1_LSE         0x1
  #define RCC_CFGR_MCO1_HSE         0x2
  #define RCC_CFGR_MCO1_PLL1        0x3
  #define RCC_CFGR_MCO1_HSI48       0x4
  #define RCC_CFGR_MCO_SHIFT        RCC_CFGR_MCO1_SHIFT
  #define RCC_CFGR_MCO_MASK         RCC_CFGR_MCO1_MASK
  
  /* RTCPRE: HSE division factor for RTC clock */
  #define RCC_CFGR_RTCPRE_SHIFT     8
  #define RCC_CFGR_RTCPRE_MASK      0x3f
  
  /* SWS: System clock switch status */
  #define RCC_CFGR_SWS_SHIFT        3
  #define RCC_CFGR_SWS_MASK         0x7
  #define RCC_CFGR_SWS_HSI          0x0
  #define RCC_CFGR_SWS_CSI          0x1
  #define RCC_CFGR_SWS_HSE          0x2
  #define RCC_CFGR_SWS_PLL1         0x3
  
  /* SW: System clock switch */
  #define RCC_CFGR_SW_SHIFT         0
  #define RCC_CFGR_SW_MASK          0x7
  #define RCC_CFGR_SW_HSI           0x0
  #define RCC_CFGR_SW_CSI           0x1
  #define RCC_CFGR_SW_HSE           0x2
  #define RCC_CFGR_SW_PLL1          0x3
  /**@}*/
  
  /** @defgroup rcc_d1cfgr_values RCC_D1CFGR Values
   * @ingroup rcc_registers
   * @{*/
  #define RCC_D1CFGR_D1CPRE_BYP       0x0
  #define RCC_D1CFGR_D1CPRE_DIV2      0x8
  #define RCC_D1CFGR_D1CPRE_DIV4      0x9
  #define RCC_D1CFGR_D1CPRE_DIV8      0xA
  #define RCC_D1CFGR_D1CPRE_DIV16     0xB
  #define RCC_D1CFGR_D1CPRE_DIV64     0xC
  #define RCC_D1CFGR_D1CPRE_DIV128    0xD
  #define RCC_D1CFGR_D1CPRE_DIV256    0xE
  #define RCC_D1CFGR_D1CPRE_DIV512    0xF
  #define RCC_D1CFGR_D1PPRE_BYP       0x0
  #define RCC_D1CFGR_D1PPRE_DIV2      0x4
  #define RCC_D1CFGR_D1PPRE_DIV4      0x5
  #define RCC_D1CFGR_D1PPRE_DIV8      0x6
  #define RCC_D1CFGR_D1PPRE_DIV16     0x7
  #define RCC_D1CFGR_D1HPRE_BYP       0x0
  #define RCC_D1CFGR_D1HPRE_DIV2      0x8
  #define RCC_D1CFGR_D1HPRE_DIV4      0x9
  #define RCC_D1CFGR_D1HPRE_DIV8      0xA
  #define RCC_D1CFGR_D1HPRE_DIV16     0xB
  #define RCC_D1CFGR_D1HPRE_DIV64     0xC
  #define RCC_D1CFGR_D1HPRE_DIV128    0xD
  #define RCC_D1CFGR_D1HPRE_DIV256    0xE
  #define RCC_D1CFGR_D1HPRE_DIV512    0xF
  
  #define RCC_D1CFGR_D1CPRE_SHIFT     8
  #define RCC_D1CFGR_D1PPRE_SHIFT     4
  #define RCC_D1CFGR_D1CPRE(cpre)     (cpre << RCC_D1CFGR_D1CPRE_SHIFT)
  #define RCC_D1CFGR_D1PPRE(ppre)     (ppre << RCC_D1CFGR_D1PPRE_SHIFT)
  #define RCC_D1CFGR_D1HPRE(hpre)     (hpre)
  /**@}*/
  
  /** @defgroup rcc_d2cfgr_values RCC_D2CFGR Values
   * @ingroup rcc_registers
   * @{*/
  #define RCC_D2CFGR_D2PPRE_BYP       0x0
  #define RCC_D2CFGR_D2PPRE_DIV2      0x4
  #define RCC_D2CFGR_D2PPRE_DIV4      0x5
  #define RCC_D2CFGR_D2PPRE_DIV8      0x6
  #define RCC_D2CFGR_D2PPRE_DIV16     0x7
  
  #define RCC_D2CFGR_D2PPRE2_SHIFT    8
  #define RCC_D2CFGR_D2PPRE1_SHIFT    4
  #define RCC_D2CFGR_D2PPRE2(ppre)    (ppre << RCC_D2CFGR_D2PPRE2_SHIFT)
  #define RCC_D2CFGR_D2PPRE1(ppre)    (ppre << RCC_D2CFGR_D2PPRE1_SHIFT)
  /**@}*/
  
  /** @defgroup rcc_d3cfgr_values RCC_D3CFGR Values
   * @ingroup rcc_registers
   * @{*/
  #define RCC_D3CFGR_D3PPRE_BYP       0x0
  #define RCC_D3CFGR_D3PPRE_DIV2      0x4
  #define RCC_D3CFGR_D3PPRE_DIV4      0x5
  #define RCC_D3CFGR_D3PPRE_DIV8      0x6
  #define RCC_D3CFGR_D3PPRE_DIV16     0x7
  #define RCC_D3CFGR_D3PPRE_SHIFT     4
  #define RCC_D3CFGR_D3PPRE(ppre)     (ppre << RCC_D3CFGR_D3PPRE_SHIFT)
  /**@}*/
  
  /** @defgroup rcc_pllckselr_values RCC_PLLCKSELR Values
   * @ingroup rcc_registers
   * @{*/
  #define RCC_PLLCKSELR_PLLSRC_HSI    0x0
  #define RCC_PLLCKSELR_PLLSRC_CSI    0x1
  #define RCC_PLLCKSELR_PLLSRC_HSE    0x2
  #define RCC_PLLCKSELR_PLLSRC_NONE   0x3
  #define RCC_PLLCKSELR_DIVM_DIS      0
  #define RCC_PLLCKSELR_DIVM_BYP      1
  #define RCC_PLLCKSELR_DIVM_MASK     0x3f
  
  #define RCC_PLLCKSELR_DIVM3_SHIFT   20
  #define RCC_PLLCKSELR_DIVM2_SHIFT   12
  #define RCC_PLLCKSELR_DIVM1_SHIFT   4
  
  #define RCC_PLLCKSELR_DIVM3(n)      ((n) << RCC_PLLCKSELR_DIVM3_SHIFT)
  #define RCC_PLLCKSELR_DIVM2(n)      ((n) << RCC_PLLCKSELR_DIVM2_SHIFT)
  #define RCC_PLLCKSELR_DIVM1(n)      ((n) << RCC_PLLCKSELR_DIVM1_SHIFT)
  /**@}*/
  
  /** @defgroup rcc_pllcfgr_values RCC_PLLCFGR Values
   * @ingroup rcc_registers
   * @{*/
  #define RCC_PLLCFGR_PLLRGE_1_2MHZ   0
  #define RCC_PLLCFGR_PLLRGE_2_4MHZ   1
  #define RCC_PLLCFGR_PLLRGE_4_8MHZ   2
  #define RCC_PLLCFGR_PLLRGE_8_16MHZ  3
  
  #define RCC_PLLCFGR_DIVR3EN         BIT24
  #define RCC_PLLCFGR_DIVQ3EN         BIT23
  #define RCC_PLLCFGR_DIVP3EN         BIT22
  #define RCC_PLLCFGR_DIVR2EN         BIT21
  #define RCC_PLLCFGR_DIVQ2EN         BIT20
  #define RCC_PLLCFGR_DIVP2EN         BIT19
  #define RCC_PLLCFGR_DIVR1EN         BIT18
  #define RCC_PLLCFGR_DIVQ1EN         BIT17
  #define RCC_PLLCFGR_DIVP1EN         BIT16
  #define RCC_PLLCFGR_PLL3RGE_SHIFT   10
  #define RCC_PLLCFGR_PLL3VCO_WIDE    0       /* 192 - 836MHz base output. */
  #define RCC_PLLCFGR_PLL3VCO_MED     BIT9    /* 150 - 420MHz base output. */
  #define RCC_PLLCFGR_PLL3FRACEN      BIT8
  #define RCC_PLLCFGR_PLL2RGE_SHIFT   6
  #define RCC_PLLCFGR_PLL2VCO_WIDE    0       /* 192 - 836MHz base output. */
  #define RCC_PLLCFGR_PLL2VCO_MED     BIT5    /* 150 - 420MHz base output. */
  #define RCC_PLLCFGR_PLL2FRACEN      BIT4
  #define RCC_PLLCFGR_PLL1RGE_SHIFT   2
  #define RCC_PLLCFGR_PLL1VCO_WIDE    0       /* 192 - 836MHz base output. */
  #define RCC_PLLCFGR_PLL1VCO_MED     BIT1    /* 150 - 420MHz base output. */
  #define RCC_PLLCFGR_PLL1FRACEN      BIT0
  /**@}*/
  
  /** @defgroup rcc_plldivr_values RCC_PLLnDIVR Values
   * @ingroup rcc_registers
   * @{*/
  #define RCC_PLLNDIVR_DIVR_SHIFT     24
  #define RCC_PLLNDIVR_DIVQ_SHIFT     16
  #define RCC_PLLNDIVR_DIVP_SHIFT     9
  #define RCC_PLLNDIVR_DIVN_SHIFT     0
  
  /* Need to preserve reserved bits, so give easy mask shortcut. */
  #define RCC_PLLNDIVR_DIVR(n)        (((n) - 1) << RCC_PLLNDIVR_DIVR_SHIFT)
  #define RCC_PLLNDIVR_DIVQ(n)        (((n) - 1) << RCC_PLLNDIVR_DIVQ_SHIFT)
  #define RCC_PLLNDIVR_DIVP(n)        (((n) - 1) << RCC_PLLNDIVR_DIVP_SHIFT)
  #define RCC_PLLNDIVR_DIVN(n)        (((n) - 1) << RCC_PLLNDIVR_DIVN_SHIFT)
  /**@}*/
  
  /** @defgroup rcc_bdcr_values RCC_BDCR Values
   * @ingroup rcc_registers
  @{*/
  #define RCC_BDCR_BDRST            (1 << 16)
  #define RCC_BDCR_RTCEN            (1 << 15)
  #define RCC_BDCR_RTCSEL_MASK      0x3
  #define RCC_BDCR_RTCSEL_SHIFT     8
  #define RCC_BDCR_RTCSEL_NONE      0
  #define RCC_BDCR_RTCSEL_LSE       1
  #define RCC_BDCR_RTCSEL_LSI       2
  #define RCC_BDCR_RTCSEL_HSE       3
  #define RCC_BDCR_LSEDRV_MASK      0x3
  #define RCC_BDCR_LSEDRV_SHIFT     3
  #define RCC_BDCR_LSEDRV_LOW       0
  #define RCC_BDCR_LSEDRV_MEDH      1 /* good job st */
  #define RCC_BDCR_LSEDRV_MEDL      2
  #define RCC_BDCR_LSEDRV_HIGH      3
  #define RCC_BDCR_LSEBYP           (1 << 2)
  #define RCC_BDCR_LSERDY           (1 << 1)
  #define RCC_BDCR_LSEON            (1 << 0)
  /**@}*/
  
  /** @defgroup rcc_csr_values RCC_CSR Values.
   * @ingroup rcc_registers
  @{*/
  #define RCC_CSR_LSIRDY            (1 << 1)
  #define RCC_CSR_LSION             (1 << 0)
  /**@}*/
  
  /** @defgroup rcc_d1ccipr_values RCC_D1CCIP1R Values
   * @ingroup rcc_registers
   * @{*/
  #define RCC_D1CCIPR_CKPERSEL_HSI       0
  #define RCC_D1CCIPR_CKPERSEL_CSI       1
  #define RCC_D1CCIPR_CKPERSEL_HSE       2
  #define RCC_D1CCIPR_CKPERSEL_DISABLE   3
  /**@}*/
  #define RCC_D1CCIPR_CKPERSEL_SHIFT     28
  #define RCC_D1CCIPR_CKPERSEL_MASK      3
  
  #define RCC_D2CCIP1R_SWPSEL_SHIFT       31
  #define RCC_D2CCIP1R_FDCANSEL_SHIFT     28
  #define RCC_D2CCIP1R_FDCANSEL_MASK      0x3
  #define RCC_D2CCIP1R_DFSDM1SEL_SHIFT    24
  #define RCC_D2CCIP1R_SPDIFSEL_SHIFT     20
  #define RCC_D2CCIP1R_SPI45SEL_SHIFT     16
  #define RCC_D2CCIP1R_SPI45SEL_MASK      0x7
  #define RCC_D2CCIP1R_SPI123SEL_SHIFT    12
  #define RCC_D2CCIP1R_SPI123SEL_MASK     0x7
  #define RCC_D2CCIP1R_SAI23SEL_SHIFT     6
  #define RCC_D2CCIP1R_SAISEL_MASK        0x7
  
  /** @defgroup rcc_d2ccip1r_values RCC_D2CCIP1R Values
   * @ingroup rcc_registers
   * @{*/
  #define RCC_D2CCIP1R_SWPSEL_PCLK        0x0
  #define RCC_D2CCIP1R_SWPSEL_HSI         0x1
  #define RCC_D2CCIP1R_FDCANSEL_HSE       0x0
  #define RCC_D2CCIP1R_FDCANSEL_PLL1Q     0x1
  #define RCC_D2CCIP1R_FDCANSEL_PLL2Q     0x2
  #define RCC_D2CCIP1R_DFSDM1SEL_PCLK2    0x0
  #define RCC_D2CCIP1R_DFSDM1SEL_SYSCLK   0x1
  #define RCC_D2CCIP1R_SPDIFSEL_PLL1Q     0x0
  #define RCC_D2CCIP1R_SPDIFSEL_PLL2R     0x1
  #define RCC_D2CCIP1R_SPDIFSEL_PLL3R     0x2
  #define RCC_D2CCIP1R_SPDIFSEL_HSI       0x3
  #define RCC_D2CCIP1R_SPI45SEL_APB4      0x0
  #define RCC_D2CCIP1R_SPI45SEL_PLL2Q     0x1
  #define RCC_D2CCIP1R_SPI45SEL_PLL3Q     0x2
  #define RCC_D2CCIP1R_SPI45SEL_HSI       0x3
  #define RCC_D2CCIP1R_SPI45SEL_CSI       0x4
  #define RCC_D2CCIP1R_SPI45SEL_HSE       0x5
  #define RCC_D2CCIP1R_SPI123SEL_PLL1Q    0x0
  #define RCC_D2CCIP1R_SPI123SEL_PLL2P    0x1
  #define RCC_D2CCIP1R_SPI123SEL_PLL3P    0x2
  #define RCC_D2CCIP1R_SPI123SEL_I2SCKIN  0x3
  #define RCC_D2CCIP1R_SPI123SEL_PERCK    0x4
  #define RCC_D2CCIP1R_SAISEL_PLL1Q       0x0
  #define RCC_D2CCIP1R_SAISEL_PLL2P       0x1
  #define RCC_D2CCIP1R_SAISEL_PLL3P       0x2
  #define RCC_D2CCIP1R_SAISEL_I2SCKIN     0x3
  #define RCC_D2CCIP1R_SAISEL_PERCK       0x4
  /**@}*/
  
  #define RCC_D2CCIP2R_LPTIM1SEL_SHIFT        28
  #define RCC_D2CCIP2R_CECSEL_SHIFT           22
  #define RCC_D2CCIP2R_USBSEL_SHIFT           20
  #define RCC_D2CCIP2R_I2C123SEL_SHIFT        12
  #define RCC_D2CCIP2R_RNGSEL_SHIFT           8
  #define RCC_D2CCIP2R_USART16SEL_SHIFT       3
  #define RCC_D2CCIP2R_USART234578SEL_SHIFT   0
  #define RCC_D2CCIP2R_USARTSEL_MASK          7
  
  /** @defgroup rcc_d2ccip2r_values RCC_D2CCIP2R Values
   * @ingroup rcc_registers
   * @{*/
  #define RCC_D2CCIP2R_USART16SEL_PCLK2       0
  #define RCC_D2CCIP2R_USART234578SEL_PCLK1   0
  #define RCC_D2CCIP2R_USARTSEL_PLL2Q         1
  #define RCC_D2CCIP2R_USARTSEL_PLL3Q         2
  #define RCC_D2CCIP2R_USARTSEL_HSI           3
  #define RCC_D2CCIP2R_USARTSEL_CSI           4
  #define RCC_D2CCIP2R_USARTSEL_LSE           5
  /**@}*/
  
  
  #define RCC_HSI_BASE_FREQUENCY              64000000UL
  
  /** Enumerations for core system/bus clocks for user/driver/system access to base bus clocks
    * not directly associated with a peripheral. */
  enum rcc_clock_source {
    RCC_CPUCLK,
    RCC_SYSCLK,
    RCC_PERCLK,
    RCC_SYSTICKCLK,
    RCC_HCLK3,
    RCC_AHBCLK,           /* AHB1,2,4 all share base HCLK. */
    RCC_APB1CLK,          /* Note: APB1 and PCLK1 in manual */
    RCC_APB2CLK,          /* Note: APB2 and PCLK2 in manual */
    RCC_APB3CLK,          /* Note: APB3 and PCLK3 in manual */
    RCC_APB4CLK,          /* Note: APB4 and PCLK4 in manual */
  };
  
  enum rcc_osc {
    RCC_PLL,
    RCC_HSE,
    RCC_HSI,
    RCC_LSE,
    RCC_LSI
  };
  
  /** PLL Configuration structure. */
  struct rcc_pll_config {
    enum rcc_osc sysclock_source;     /**< SYSCLK source input selection. */
    uint8_t pll_source;               /**< RCC_PLLCKSELR_PLLSRC_xxx value. */
    uint32_t hse_frequency;           /**< User specified HSE frequency, 0 if none. */
    struct pll_config {
      uint8_t divm;                   /**< Pre-divider value for each PLL. 0-64 integers. */
      uint16_t divn;                  /**< Multiplier, 0-512 integer. */
      uint8_t divp;                   /**< Post divider for PLLP clock. */
      uint8_t divq;                   /**< Post divider for PLLQ clock. */
      uint8_t divr;                   /**< Post divider for PLLR clock. */
    } pll1, pll2, pll3;               /**< PLL1-PLL3 configurations. */
    uint8_t core_pre;                 /**< Core prescaler  note: domain 1. */
    uint8_t hpre;                     /**< HCLK3 prescaler note: domain 1. */
    uint8_t ppre1;                    /**< APB1 Peripheral prescaler note: domain 2. */
    uint8_t ppre2;                    /**< APB2 Peripheral prescaler note: domain 2. */
    uint8_t ppre3;                    /**< APB3 Peripheral prescaler note: domain 1. */
    uint8_t ppre4;                    /**< APB4 Peripheral prescaler note: domain 3. */
    uint8_t flash_waitstates;         /**< Latency Value to set for flahs. */
    enum pwr_vos_scale voltage_scale; /**< LDO Voltage scale used for this frequency. */
  };
  
  #define _REG_BIT(base, bit)       (((base) << 5) + (bit))
  
  enum rcc_periph_clken {
     /* AHB1 peripherals */
    RCC_DMA1        = _REG_BIT(0xD8, 0),
    RCC_DMA2        = _REG_BIT(0xD8, 1),
    RCC_ADC12       = _REG_BIT(0xD8, 5),
    RCC_ETH1MAC     = _REG_BIT(0xD8, 15),
    RCC_ETH1TX      = _REG_BIT(0xD8, 16),
    RCC_ETH1RX      = _REG_BIT(0xD8, 17),
    RCC_USB2OTGHSULPIEN = _REG_BIT(0xD8, 18),
    RCC_USB1OTGHSEN = _REG_BIT(0xD8, 25),
    RCC_USB1OTGHSULPIEN = _REG_BIT(0xD8, 26),
    RCC_USB2OTGHSEN = _REG_BIT(0xD8, 27),
  
    /* AHB2 peripherals */
    RCC_DCMI        = _REG_BIT(0xDC, 0),
    RCC_CRYP        = _REG_BIT(0xDC, 4),
    RCC_HASH        = _REG_BIT(0xDC, 5),
    RCC_RNG         = _REG_BIT(0xDC, 6),
    RCC_SDMMC2      = _REG_BIT(0xDC, 9),
    RCC_SRAM1       = _REG_BIT(0xDC, 29),
    RCC_SRAM2       = _REG_BIT(0xDC, 30),
    RCC_SRAM3       = _REG_BIT(0xDC, 31),
  
    /* AHB3 peripherals */
    RCC_MDMA        = _REG_BIT(0xD4, 0),
    RCC_DMA2D       = _REG_BIT(0xD4, 4),
    RCC_JPGDEC      = _REG_BIT(0xD4, 5),
    RCC_FMC         = _REG_BIT(0xD4, 12),
    RCC_QSPI        = _REG_BIT(0xD4, 14),
    RCC_SDMMC1      = _REG_BIT(0xD4, 16),
  
    /* AHB4 peripherals*/
    RCC_GPIOA       = _REG_BIT(0xE0, 0),
    RCC_GPIOB       = _REG_BIT(0xE0, 1),
    RCC_GPIOC       = _REG_BIT(0xE0, 2),
    RCC_GPIOD       = _REG_BIT(0xE0, 3),
    RCC_GPIOE       = _REG_BIT(0xE0, 4),
    RCC_GPIOF       = _REG_BIT(0xE0, 5),
    RCC_GPIOG       = _REG_BIT(0xE0, 6),
    RCC_GPIOH       = _REG_BIT(0xE0, 7),
    RCC_GPIOI       = _REG_BIT(0xE0, 8),
    RCC_GPIOJ       = _REG_BIT(0xE0, 9),
    RCC_GPIOK       = _REG_BIT(0xE0, 10),
    RCC_CRC         = _REG_BIT(0xE0, 19),
    RCC_BDMA        = _REG_BIT(0xE0, 21),
    RCC_ADC3        = _REG_BIT(0xE0, 24),
    RCC_HSEM        = _REG_BIT(0xE0, 25),
    RCC_BKPSRAM     = _REG_BIT(0xE0, 28),
  
    /* APB1L peripherals*/
    RCC_TIM2        = _REG_BIT(0xE8, 0),
    RCC_TIM3        = _REG_BIT(0xE8, 1),
    RCC_TIM4        = _REG_BIT(0xE8, 2),
    RCC_TIM5        = _REG_BIT(0xE8, 3),
    RCC_TIM6        = _REG_BIT(0xE8, 4),
    RCC_TIM7        = _REG_BIT(0xE8, 5),
    RCC_TIM12       = _REG_BIT(0xE8, 6),
    RCC_TIM13       = _REG_BIT(0xE8, 7),
    RCC_TIM14       = _REG_BIT(0xE8, 8),
    RCC_LPTIM1      = _REG_BIT(0xE8, 9),
    RCC_SPI2        = _REG_BIT(0xE8, 14),
    RCC_SPI3        = _REG_BIT(0xE8, 15),
    RCC_SPDIFRX     = _REG_BIT(0xE8, 16),
    RCC_USART2      = _REG_BIT(0xE8, 17),
    RCC_USART3      = _REG_BIT(0xE8, 18),
    RCC_UART4       = _REG_BIT(0xE8, 19),
    RCC_UART5       = _REG_BIT(0xE8, 20),
    RCC_I2C1        = _REG_BIT(0xE8, 21),
    RCC_I2C2        = _REG_BIT(0xE8, 22),
    RCC_I2C3        = _REG_BIT(0xE8, 23),
    RCC_CEC         = _REG_BIT(0xE8, 27),
    RCC_DAC         = _REG_BIT(0xE8, 29),
    RCC_UART7       = _REG_BIT(0xE8, 30),
    RCC_UART8       = _REG_BIT(0xE8, 31),
  
    /* APB1H peripherals*/
    RCC_CRS         = _REG_BIT(0xEC, 1),
    RCC_SWP         = _REG_BIT(0xEC, 2),
    RCC_OPAMP       = _REG_BIT(0xEC, 4),
    RCC_MDIO        = _REG_BIT(0xEC, 5),
    RCC_FDCAN       = _REG_BIT(0xEC, 8),
  
    /* APB2 peripherals */
    RCC_TIM1        = _REG_BIT(0xF0, 0),
    RCC_TIM8        = _REG_BIT(0xF0, 1),
    RCC_USART1      = _REG_BIT(0xF0, 4),
    RCC_USART6      = _REG_BIT(0xF0, 5),
    RCC_SPI1        = _REG_BIT(0xF0, 12),
    RCC_SPI4        = _REG_BIT(0xF0, 13),
    RCC_TIM15       = _REG_BIT(0xF0, 16),
    RCC_TIM16       = _REG_BIT(0xF0, 17),
    RCC_TIM17       = _REG_BIT(0xF0, 18),
    RCC_SPI5        = _REG_BIT(0xF0, 20),
    RCC_SAI1        = _REG_BIT(0xF0, 22),
    RCC_SAI2        = _REG_BIT(0xF0, 23),
    RCC_SAI3        = _REG_BIT(0xF0, 24),
    RCC_DFSDM       = _REG_BIT(0xF0, 28),
    RCC_HRTIM       = _REG_BIT(0xF0, 29),
  
    /* APB3 peripherals */
    RCC_LTDCEN      = _REG_BIT(0xE4, 3),
    RCC_WWDG1EN     = _REG_BIT(0xE4, 6),
  
    /* APB4 peripherals */
    RCC_SYSCFG      = _REG_BIT(0xF4, 1),
    RCC_LPUART1     = _REG_BIT(0xF4, 3),
    RCC_SPI6        = _REG_BIT(0xF4, 5),
    RCC_I2C4        = _REG_BIT(0xF4, 7),
    RCC_LPTIM2      = _REG_BIT(0xF4, 9),
    RCC_LPTIM3      = _REG_BIT(0xF4, 10),
    RCC_LPTIM4      = _REG_BIT(0xF4, 11),
    RCC_LPTIM5      = _REG_BIT(0xF4, 12),
    RCC_COMP12      = _REG_BIT(0xF4, 14),
    RCC_VREF        = _REG_BIT(0xF4, 15),
    RCC_RTCAPB      = _REG_BIT(0xF4, 16),
    RCC_SAI4        = _REG_BIT(0xF4, 21),
  };
  
  enum rcc_periph_rst {
     /* AHB1 peripherals */
    RST_DMA1        = _REG_BIT(0x80, 0),
    RST_DMA2        = _REG_BIT(0x80, 1),
    RST_ADC12       = _REG_BIT(0x80, 5),
    RST_ETH1MAC     = _REG_BIT(0x80, 15),
    RST_USB1OTGRST  = _REG_BIT(0x80, 25),
    RST_USB2OTGRST  = _REG_BIT(0x80, 27),
  
    /* AHB2 peripherals */
    RST_DCMI        = _REG_BIT(0xDC, 0),
    RST_CRYP        = _REG_BIT(0xDC, 4),
    RST_HASH        = _REG_BIT(0xDC, 5),
    RST_RNG         = _REG_BIT(0xDC, 6),
    RST_SDMMC2      = _REG_BIT(0xDC, 9),
  
    /* AHB3 peripherals */
    RST_MDMA        = _REG_BIT(0x7C, 0),
    RST_DMA2D       = _REG_BIT(0x7C, 4),
    RST_JPGDEC      = _REG_BIT(0x7C, 5),
    RST_FMC         = _REG_BIT(0x7C, 12),
    RST_QSPI        = _REG_BIT(0x7C, 14),
    RST_SDMMC1      = _REG_BIT(0x7C, 16),
  
    /* AHB4 peripherals*/
    RST_GPIOA       = _REG_BIT(0x88, 0),
    RST_GPIOB       = _REG_BIT(0x88, 1),
    RST_GPIOC       = _REG_BIT(0x88, 2),
    RST_GPIOD       = _REG_BIT(0x88, 3),
    RST_GPIOE       = _REG_BIT(0x88, 4),
    RST_GPIOF       = _REG_BIT(0x88, 5),
    RST_GPIOG       = _REG_BIT(0x88, 6),
    RST_GPIOH       = _REG_BIT(0x88, 7),
    RST_GPIOI       = _REG_BIT(0x88, 8),
    RST_GPIOJ       = _REG_BIT(0x88, 9),
    RST_GPIOK       = _REG_BIT(0x88, 10),
    RST_CRC         = _REG_BIT(0x88, 19),
    RST_BDMA        = _REG_BIT(0x88, 21),
    RST_ADC3        = _REG_BIT(0x88, 24),
    RST_HSEM        = _REG_BIT(0x88, 25),
  
    /* APB1L peripherals*/
    RST_TIM2        = _REG_BIT(0x90, 0),
    RST_TIM3        = _REG_BIT(0x90, 1),
    RST_TIM4        = _REG_BIT(0x90, 2),
    RST_TIM5        = _REG_BIT(0x90, 3),
    RST_TIM6        = _REG_BIT(0x90, 4),
    RST_TIM7        = _REG_BIT(0x90, 5),
    RST_TIM12       = _REG_BIT(0x90, 6),
    RST_TIM13       = _REG_BIT(0x90, 7),
    RST_TIM14       = _REG_BIT(0x90, 8),
    RST_LPTIM1      = _REG_BIT(0x90, 9),
    RST_SPI2        = _REG_BIT(0x90, 14),
    RST_SPI3        = _REG_BIT(0x90, 15),
    RST_SPDIFRX     = _REG_BIT(0x90, 16),
    RST_USART2      = _REG_BIT(0x90, 17),
    RST_USART3      = _REG_BIT(0x90, 18),
    RST_UART4       = _REG_BIT(0x90, 19),
    RST_UART5       = _REG_BIT(0x90, 20),
    RST_I2C1        = _REG_BIT(0x90, 21),
    RST_I2C2        = _REG_BIT(0x90, 22),
    RST_I2C3        = _REG_BIT(0x90, 23),
    RST_CEC         = _REG_BIT(0x90, 27),
    RST_DAC         = _REG_BIT(0x90, 29),
    RST_UART7       = _REG_BIT(0x90, 30),
    RST_UART8       = _REG_BIT(0x90, 31),
  
    /* APB1H peripherals*/
    RST_CRS         = _REG_BIT(0x94, 1),
    RST_SWP         = _REG_BIT(0x94, 2),
    RST_OPAMP       = _REG_BIT(0x94, 4),
    RST_MDIO        = _REG_BIT(0x94, 5),
    RST_FDCAN       = _REG_BIT(0x94, 8),
  
    /* APB2 peripherals */
    RST_TIM1        = _REG_BIT(0x98, 0),
    RST_TIM8        = _REG_BIT(0x98, 1),
    RST_USART1      = _REG_BIT(0x98, 4),
    RST_USART6      = _REG_BIT(0x98, 5),
    RST_SPI1        = _REG_BIT(0x98, 12),
    RST_SPI4        = _REG_BIT(0x98, 13),
    RST_TIM15       = _REG_BIT(0x98, 16),
    RST_TIM16       = _REG_BIT(0x98, 17),
    RST_TIM17       = _REG_BIT(0x98, 18),
    RST_SPI5        = _REG_BIT(0x98, 20),
    RST_SAI1        = _REG_BIT(0x98, 22),
    RST_SAI2        = _REG_BIT(0x98, 23),
    RST_SAI3        = _REG_BIT(0x98, 24),
    RST_DFSDM       = _REG_BIT(0x98, 28),
    RST_HRTIM       = _REG_BIT(0x98, 29),
  
    /* APB3 peripherals */
    RST_LTDCRST     = _REG_BIT(0x8C, 3),
  
    /* APB4 peripherals */
    RST_SYSCFG      = _REG_BIT(0x9C, 1),
    RST_LPUART1     = _REG_BIT(0x9C, 3),
    RST_SPI6        = _REG_BIT(0x9C, 5),
    RST_I2C4        = _REG_BIT(0x9C, 7),
    RST_LPTIM2      = _REG_BIT(0x9C, 9),
    RST_LPTIM3      = _REG_BIT(0x9C, 10),
    RST_LPTIM4      = _REG_BIT(0x9C, 11),
    RST_LPTIM5      = _REG_BIT(0x9C, 12),
    RST_COMP12      = _REG_BIT(0x9C, 14),
    RST_VREF        = _REG_BIT(0x9C, 15),
    RST_SAI4        = _REG_BIT(0x9C, 21),
  };
  
  #undef _REG_BIT
  /**@}*/
  
  
  /** @defgroup rcc_file RCC peripheral API
   *
   * @ingroup peripheral_apis
   * @{
   */
  #include <libopencm3/stm32/common/rcc_common_all.h>
  
  BEGIN_DECLS
  
  /**
   * Setup the base PLLs and clock domains for the STM32H7. This function will
   * utilize the users input parameters to configure all 3 PLLs, as well as the
   * core clock domains (namely SYSCLK, CPU, HCLK, AHB, PCLK1-4) with the
   * specified dividers. Given the dividers, the RCC module will track the
   * the configured frequency for each of these clock domains.
   *
   *   Note: If clock sources, configs, divider, etc. are modified outside of
   *         this module, the frequency tracking may be undefined.
   *   Note: Clock tree is fairly complex, see RM0433 Section 7
   *         for details.
   * @param[in] config  Input config structure defining desired setup.
   */
  void rcc_clock_setup_pll(const struct rcc_pll_config *config);
  
  /**
   * Get the clock rate (in Hz) of the specified clock source. There are
   * numerous clock sources and configurations on the H7, so rates for each
   * configured peripheral clock are aimed to be discoverd/calculated by this
   * module such that the user does not need to know how the MCU is configured
   * in order to utilize a peripheral clock.
   * @param[in] source  Clock source desired to be fetched.
   * @return Clock rate in Hz for the specified clock. 0 if undefined or error.
   */
  uint32_t rcc_get_bus_clk_freq(enum rcc_clock_source source);
  
  /**
   * Get the clock rate (in Hz) of the specified peripheral. This will pull the
   * proper sources out of the clock tree and calculate the clock for the
   * peripheral for return to the user, based on current settings.
   * @param[in] periph  Peripheral base address to get the clock rate for.
   * @return Clock rate in Hz for the specified peripheral. 0 if undefined or error.
   */
  uint32_t rcc_get_peripheral_clk_freq(uint32_t periph);
  
  /**
   * Set the clksel value for the specified peripheral. This code will determine
   * the appropriate register, shift and mask values to apply to the selection to
   * and set the values appropriately.
   *
   * Peripheral specific clksels functions are also available,
   * eg rcc_set_<periph>_clksel. These provide the same functionality, you only
   * need one of them. for instance @ref rcc_set_fdcan_clksel or
   * @ref rcc_set_spi123_clksel
   * @param[in] periph Base address of the peripheral to set the clock sel for
   * @param[in] clksel Raw, unshifted selection value for the clock, depending
   * on peripheral, see @ref rcc_d1ccipr_values or @ref rcc_d2ccip1r_values or
   * @ref rcc_d2ccip2r_values
   */
  void rcc_set_peripheral_clk_sel(uint32_t periph, uint32_t clksel);
  
  /**
   * Set the clock select for the FDCAN devices.
   * @param[in] clksel  Clock source to configure for, @ref rcc_d2ccip1r_values
   * appropriate for the FDCAN peripherals, eg RCC_D2CCIP1R_FDCANSEL_XXX
   * @sa rcc_set_peripheral_clk_sel for equivalent generic functionality
   */
  void rcc_set_fdcan_clksel(uint8_t clksel);
  
  /**
   * Set the clock select for the SPI 1/2/3 devices.
   * @param[in] clksel  Clock source to configure for, @ref rcc_d2ccip1r_values
   * appropriate for the SPI1/2/3 peripherals, eg RCC_D2CCIP1R_SPI123_XXX
   * @sa rcc_set_peripheral_clk_sel for equivalent generic functionality
   */
  void rcc_set_spi123_clksel(uint8_t clksel);
  
  /**
   * Set the clock select for the SPI 4/5 devices.
   * @param[in] clksel  Clock source to configure for. @ref rcc_d2ccip1r_values
   * @sa rcc_set_peripheral_clk_sel for equivalent generic functionality
   */
  void rcc_set_spi45_clksel(uint8_t clksel);
  
  
  END_DECLS
  /**@}*/
  /**@}*/
  
  #endif
  