/* This source file is part of the ATMEL AVR32-SoftwareFramework-AT32AP7000-1.0.0 Release */

/*This file has been prepared for Doxygen automatic documentation generation.*/
/*! \file *********************************************************************
 *
 * \brief Power Manager Example
 *
 *
 * - Compiler:           IAR EWAVR32 and GNU GCC for AVR32
 * - Supported devices:  All AVR32 devices with a Power Manager.
 * - AppNote:
 *
 * \author               Atmel Corporation: http://www.atmel.com \n
 *                       Support and FAQ: http://support.atmel.no/
 *
 *****************************************************************************/

/*! \page License
 * Copyright (C) 2006-2008, Atmel Corporation All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. The name of ATMEL may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND
 * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*! \mainpage
 * \section intro Introduction
 * This is the documentation for the data structures, functions, variables, defines, enums, and
 * typedefs for the power manager driver. <BR>It also gives an example of the usage of the
 * PM on AVR32 products.
 * <BR>This example shows:
 * - how to configure a PLL and switch the main clock to PLL output,
 * - configure a Generic Clock and output it to a GPIO pin,
 * - LED0 blinks endlessly.
 *
 * \section files Main Files
 * - pm_at32ap7000.c: power manager driver
 * - pm_at32ap7000.h: power manager driver header file
 * - pm_example2.c: power manager example application
 *
 * \section compinfo Compilation Info
 * This software was written for the GNU GCC for AVR32 and IAR Systems compiler
 * for AVR32. Other compilers may or may not work.
 *
 * \section deviceinfo Device Info
 * All AVR32 devices with a PM module can be used. This example has been tested
 * with the following setup:<BR>
 * <ul><li>STK1000 starter kit</ul>
 *
 * \section setupinfo Setup Information
 * CPU speed: <i> 100 MHz </i>
 * - On \b STK1000, check GCLK0 pin with an oscilloscope, the frequency should be 100MHz.
 * On STK1000, GCLK_0 is found on PCI style connector (J18) pin number A21.
 * - Check that LED0 blinks.
 *
 * \section contactinfo Contact Info
 * For more info about Atmel AVR32 visit<BR>
 * <A href="http://www.atmel.com/products/AVR32/" >Atmel AVR32</A><BR>
 * Support and FAQ: http://support.atmel.no/
 */


#include "gpio.h"
#include "pm_at32ap7000.h"
#include "board.h"


/*! \name Generic Clock Configuration
 */
//! @{
#if BOARD == EVK1100
#  define EXAMPLE_GCLK_ID             0
#  define EXAMPLE_GCLK_PIN            AVR32_PM_GCLK_0_1_PIN
#  define EXAMPLE_GCLK_FUNCTION       AVR32_PM_GCLK_0_1_FUNCTION
// Note that gclk0_1 is pin 51 pb19 on AT32UC3A0512 QFP144.
#elif BOARD == EVK1101
#  define EXAMPLE_GCLK_ID             2
#  define EXAMPLE_GCLK_PIN            AVR32_PM_GCLK_2_PIN
#  define EXAMPLE_GCLK_FUNCTION       AVR32_PM_GCLK_2_FUNCTION
// Note that gclk_2 is pin 30 pa30 on AT32UC3B0256 QFP64.
#elif BOARD == STK1000
#  define EXAMPLE_GCLK_ID             0
#  define EXAMPLE_GCLK_PIN            AVR32_PM_GCLK_0_PIN
#  define EXAMPLE_GCLK_FUNCTION       AVR32_PM_GCLK_0_FUNCTION
#endif

#if !defined(EXAMPLE_GCLK_ID)  || \
    !defined(EXAMPLE_GCLK_PIN) || \
    !defined(EXAMPLE_GCLK_FUNCTION)
#  error The generic clock configuration to use in this example is missing.
#endif
//! @}


/* Start PLL0, enable a generic clock with PLL0 output then switch main clock to PLL0 output.
   All calculations in this function suppose that the Osc0 frequency is 12MHz. */
void local_start_pll0()
{
  // Reset PM. Makes sure we get the expected clocking after a soft reset (e.g.: JTAG reset)
  pm_reset();

  // Start PLL0 giving 100 MHz clock
  pm_pll_opt_t pm_pll_opt = {
    .pll_id = 0,
    .mul = 5,
    .div = 1,
    .osc_id = 0,
    .count = 16,
    .wait_for_lock = 1,
  };
  pm_start_pll(&pm_pll_opt);

  // Divide HSB by 2, PBA by 4 and PBB by 2 to keep them below maximum ratings
  pm_set_clock_domain_scaler(PM_HSB_DOMAIN, 2);
  pm_set_clock_domain_scaler(PM_PBB_DOMAIN, 2);
  pm_set_clock_domain_scaler(PM_PBA_DOMAIN, 4);

  /* Setup generic clock on PLL0, with Osc0/PLL0, no divisor */
  pm_gen_clk_opt_t pm_gen_clk_opt = {
    .clock_source = PM_PLL0,
    .divider = 0,
  };
  pm_start_generic_clock(EXAMPLE_GCLK_ID, &pm_gen_clk_opt);

  /* Set the GCLOCK function to the GPIO pin */
  gpio_enable_module_pin(EXAMPLE_GCLK_PIN, EXAMPLE_GCLK_FUNCTION);

  // Use PLL0 as clock source
  pm_set_mclk_source(PM_PLL0);
}


/* \brief Software Delay
 *
 */
static void software_delay(void)
{
  volatile int i;
  for (i=0; i<1000000; i++);
}


/* \brief This is an example of how to configure and start a PLL from Osc0
 * then configure the GCLK output to GLCK_0_1, and switch the main clock to
 * PLL0 output.
 *
 */
int main(void)
{
  /* start PLL0 and switch main clock to PLL0 output */
  /* Also set-up a generic clock from PLL0 and output it to a gpio pin. */
  local_start_pll0();

  LED_Off(0xff);

  /* Now toggle LED0 using a GPIO */
  while(1)
  {
    LED_Toggle(LED0);
    software_delay();
  }
}
