/*                                             -*- mode:C++; fill-column:100  -*-
  clock.h Support for changing/setting the system clock speed
  Copyright (C) 2010 The Regents of the University of New Mexico.  All rights reserved.

  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 2.1 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 General Public License
  along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  USA
*/
/**
  \file clock.h  Support for changing/setting the system clock speed
  \author David H. Ackley.  
  \date (C) 2009 All rights reserved.
  \lgpl
 */

#ifndef CLOCK_H_
#define CLOCK_H_

#include "SFBTypes.h"

#ifdef __cplusplus
extern "C"{
#endif

enum ClockSpeedCode {
  CSC_UNSET = 0,
  CSC_12MHZ = 1,                /**< Code representing 12MHz processor speed*/
  CSC_24MHZ = 2,                /**< Code representing 24MHz processor speed*/
  CSC_36MHZ = 3,                /**< Code representing 36MHz processor speed*/
  CSC_48MHZ = 4,                /**< Code representing 48MHz processor speed*/
  CSC_60MHZ = 5,                /**< Code representing 60MHz processor speed*/
  CSC_72MHZ = 6,                /**< Code representing 72MHz processor speed*/

  CSC_MAX = 7, 

  CSC_MIN_MHZ = CSC_12MHZ,      /**< Code representing the slowest supported processor speed */ 
  CSC_MAX_MHZ = CSC_72MHZ,      /**< Code representing the fastest supported processor speed */ 

  CSC_AUTO = 8
};

/** The internal hardware parameters associated with a given CPU clock speed.  Primarily intended
    for internal use. */
typedef struct clockConfiguration {
  u8 pllMulM;                   /**< PLL multiplier: 6-512, prefer small */
  u8 pllDivN;                   /**< PLL predivider: 1-32, prefer small */
  u8 clkDiv;                    /**< Clock divider: Even values 2-254 */
  u8 mamtim;                    /**< MAM clocks: 1+ */
  u8 pclkDiv;                   /**< Default PCLKDIV: 1,2,4,8 */
  u8 pclkMHz;                   /**< Default PCLK MHz: Derived value */
} ClockConfiguration;

/** Access the parameters of the current clock configuration.  Primarily intended for internal
    use. */
extern const ClockConfiguration * getCurrentClockConfiguration() ;

/** Access the parameters of the clock configuration associated with \a code.  Primarily intended
    for internal use. */
extern const ClockConfiguration * getClockConfigurationForCode(u32 code) ;

/** Return the current clock speed in Hz. */
extern u32 getCCLK() ;

/** Return the current clock speed code. */
extern u8 getCCLKCode() ;

/** Set the clock speed to \a code. */
extern void setClockSpeed(u32 code) ;

/** Declaration for a handler function to be called after a clock speed change has occurred. */
typedef void (*ClockSpeedChangeCallback)(u32 newClockSpeed);
 
/** Set the handler function to be called after a clock speed change has occurred to \a callback.

    \e Avoid \e using \e this \e callback \e mechanism \e if \e possible!  It is \b dangerous!

    Would-be users of this mechanism be aware of the following:
    -# The supplied \a callback function will be called with \e interrupts \e disabled, and for
       successful use the \a callback function should not reenable them, should not perform any
       operations depending on interrupts, and should not take very much time to execute.
    -# The supplied \a callback function may be called \b multiple times as the result of a \b single
       #setClockSpeed call, due to intermediate speed changes on the way to the final value.

    \param callback Pointer to handler function, or 0 to specify no function should be called back

    \returns The previous values of the handler.
*/
extern ClockSpeedChangeCallback setClockSpeedChangeCallback(ClockSpeedChangeCallback callback) ;

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /*CLOCK_H_*/
