libmaple/libmaple/rcc.c
Marti Bolivar ef217b7434 libmaple/rcc.c: Fix typo.
Signed-off-by: Marti Bolivar <mbolivar@leaflabs.com>
2012-05-31 17:24:17 -04:00

170 lines
5.5 KiB
C

/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
* Copyright (c) 2011 LeafLabs, LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/
/**
* @file libmaple/rcc.c
* @brief Portable RCC routines.
*/
#include <libmaple/rcc.h>
#include "rcc_private.h"
/**
* @brief Get a peripheral's clock domain
* @param id Clock ID of the peripheral whose clock domain to return
* @return Clock source for the given clock ID
*/
rcc_clk_domain rcc_dev_clk(rcc_clk_id id) {
return rcc_dev_table[id].clk_domain;
}
/**
* @brief Switch the clock used as the source of the system clock.
*
* After switching the source, this function blocks until the new
* clock source is in use.
*
* @param sysclk_src New system clock source.
* @see rcc_sysclk_src
*/
void rcc_switch_sysclk(rcc_sysclk_src sysclk_src) {
uint32 cfgr = RCC_BASE->CFGR;
cfgr &= ~RCC_CFGR_SW;
cfgr |= sysclk_src;
/* Switch SYSCLK source. */
RCC_BASE->CFGR = cfgr;
/* Wait for new source to come into use. */
while ((RCC_BASE->CFGR & RCC_CFGR_SWS) != (sysclk_src << 2))
;
}
/*
* Turning clocks off and on, querying their status.
*/
/* IMPORTANT NOTE FOR IMPLEMENTORS:
*
* libmaple assumes that enum rcc_clk enumerators are two-byte
* values, stored in a uint16, in the following way:
*
* - The high-order byte is the byte offset (from RCC_BASE) of the register
* to touch when turning on or off the given clock.
*
* - The low-order byte is the bit in that register that turns the
* clock on or off.
*
* Example for STM32F1: Turning on the high-speed external clock (HSE)
* involves setting HSEON, bit 16, of RCC_CR. The high-order byte is
* then offsetof(struct rcc_reg_map, CR) = 0, and the low-order byte
* is 16.
*
* The corresponding value of RCC_CLK_HSE is thus (0 << 8) | 16 = 16.
*
* On all known STM32 series, this encoding has the property that
* adding one to the low byte also gives the bit to check to determine
* if the clock is ready. For example, on STM32F1, RCC_CR_HSERDY is
* bit 17. If that's not the case on your series, rcc_is_clk_ready()
* won't work for you. */
/* Returns the RCC register which controls the clock source. */
static inline __io uint32* rcc_clk_reg(rcc_clk clock) {
return (__io uint32*)((__io uint8*)RCC_BASE + (clock >> 8));
}
/* Returns a mask in rcc_clk_reg(clock) to be used for turning the
* clock on and off */
static inline uint32 rcc_clk_on_mask(rcc_clk clock) {
return 1 << (clock & 0xFF);
}
/* Returns a mask in rcc_clk_reg(clock) to be used when checking the
* readiness of the clock. */
static inline uint32 rcc_clk_ready_mask(rcc_clk clock) {
return rcc_clk_on_mask(clock) << 1;
}
/**
* @brief Turn on a clock source.
*
* After this routine exits, callers should ensure that the clock
* source is ready by waiting until rcc_is_clk_ready(clock) returns
* true.
*
* @param clock Clock to turn on.
* @see rcc_turn_off_clk()
* @see rcc_is_clk_ready()
*/
void rcc_turn_on_clk(rcc_clk clock) {
*rcc_clk_reg(clock) |= rcc_clk_on_mask(clock);
}
/**
* @brief Turn off a clock source.
*
* In certain configurations, certain clock sources cannot be safely
* turned off. (For example, the main PLL on STM32F1 devices cannot be
* turned off if it has been selected as the SYSCLK source). Consult
* the reference material for your MCU to ensure it is safe to call
* this function.
*
* @param clock Clock to turn off.
* @see rcc_turn_on_clk()
* @see rcc_is_clk_ready()
*/
void rcc_turn_off_clk(rcc_clk clock) {
*rcc_clk_reg(clock) &= ~rcc_clk_on_mask(clock);
}
/**
* @brief Check if a clock is on.
* @param clock Clock to check.
* @return 1 if the clock is on, 0 if the clock is off.
*/
int rcc_is_clk_on(rcc_clk clock) {
return !!(*rcc_clk_reg(clock) & rcc_clk_on_mask(clock));
}
/**
* @brief Check if a clock source is ready.
*
* In general, it is not safe to rely on a clock source unless this
* function returns nonzero. Also note that this function may return
* nonzero for a short period of time after a clock has been turned
* off. Consult the reference material for your MCU for more details.
*
* @param clock Clock whose readiness to check for.
* @return Nonzero if the clock is ready, zero otherwise.
* @see rcc_turn_on_clk()
* @see rcc_turn_off_clk()
*/
int rcc_is_clk_ready(rcc_clk clock) {
return (int)(*rcc_clk_reg(clock) & rcc_clk_ready_mask(clock));
}