void at91_spi0_hw_init(void)
{
	/* Configure the spi0 pins */
	/* {"MISO",	AT91C_PIN_PA(0),	0, PIO_DEFAULT, PIO_PERIPH_A}
	   {"MOSI",	AT91C_PIN_PA(1),	0, PIO_DEFAULT, PIO_PERIPH_A}
	   {"SPCK",	AT91C_PIN_PA(2),	0, PIO_DEFAULT, PIO_PERIPH_A}*/
	writel(((0x01 << 0) | (0x01 << 1) | (0x01 << 2)), AT91C_BASE_PIOA + PIO_ASR(0));
	writel(((0x01 << 0) | (0x01 << 1) | (0x01 << 2)), AT91C_BASE_PIOA + PIO_PDR(0));

#if (AT91C_SPI_PCS_DATAFLASH == AT91C_SPI_PCS0_DATAFLASH)
	/* {"NPCS",        AT91C_PIN_PA(3),     1, PIO_PULLUP, PIO_OUTPUT}, */
	writel((0x01 << 3), AT91C_BASE_PIOA + PIO_IDR(0));
	writel((0x01 << 3), AT91C_BASE_PIOA + PIO_PPUDR(0));
	writel((0x01 << 3), AT91C_BASE_PIOA + PIO_SODR(0));
	writel((0x01 << 3), AT91C_BASE_PIOA + PIO_OER(0));
	writel((0x01 << 3), AT91C_BASE_PIOA + PIO_PER(0));

	writel((1 << AT91C_ID_PIOA), (PMC_PCER + AT91C_BASE_PMC));
#endif

#if (AT91C_SPI_PCS_DATAFLASH == AT91C_SPI_PCS1_DATAFLASH)
	/* {"NPCS",        AT91C_PIN_PC(11),     1, PIO_PULLUP, PIO_OUTPUT}, */
	writel((0x01 << 11), AT91C_BASE_PIOC + PIO_IDR(0));
	writel((0x01 << 11), AT91C_BASE_PIOC + PIO_PPUDR(0));
	writel((0x01 << 11), AT91C_BASE_PIOC + PIO_SODR(0));
	writel((0x01 << 11), AT91C_BASE_PIOC + PIO_OER(0));
	writel((0x01 << 11), AT91C_BASE_PIOC + PIO_PER(0));

	writel(((1 << AT91C_ID_PIOA) | (1 << AT91C_ID_PIOC)), (PMC_PCER + AT91C_BASE_PMC));
#endif

	/* Enable the spi0 clock */
	writel((1 << AT91C_ID_SPI0), (PMC_PCER + AT91C_BASE_PMC));
}
void nandflash_hw_init(void)
{
	unsigned int reg;

	/* Setup Smart Media, first enable the address range of
	 * CS3 in HMATRIX user interface  */
	reg = readl(AT91C_BASE_CCFG + CCFG_EBICSA);
	reg |= AT91C_EBI_CS3A_SM;
	writel(reg, AT91C_BASE_CCFG + CCFG_EBICSA);

	/* Configure SMC CS3 */
	writel((AT91C_SMC_NWESETUP_(1)
		| AT91C_SMC_NCS_WRSETUP_(0)
		| AT91C_SMC_NRDSETUP_(1)
		| AT91C_SMC_NCS_RDSETUP_(0)),
		AT91C_BASE_SMC + SMC_SETUP3);

	writel((AT91C_SMC_NWEPULSE_(3)
		| AT91C_SMC_NCS_WRPULSE_(3)
		| AT91C_SMC_NRDPULSE_(3)
		| AT91C_SMC_NCS_RDPULSE_(3)),
		AT91C_BASE_SMC + SMC_PULSE3);

	writel((AT91C_SMC_NWECYCLE_(5)
		| AT91C_SMC_NRDCYCLE_(5)),
		AT91C_BASE_SMC + SMC_CYCLE3);

	writel((AT91C_SMC_READMODE
		| AT91C_SMC_WRITEMODE
		/* AT91C_SMC_NWAITM_NWAIT_DISABLE */
		| (0x0 << 5)
		| AT91C_SMC_DBW_WIDTH_BITS_16
		| AT91_SMC_TDF_(2)),
		AT91C_BASE_SMC + SMC_CTRL3);

	/* configure NAND pins */

	/* {"NANDCS", AT91C_PIN_PC(14), 1, PIO_PULLUP, PIO_OUTPUT} */
	writel((0x01 << 14), AT91C_BASE_PIOC + PIO_IDR(0));
	writel((0x01 << 14), AT91C_BASE_PIOC + PIO_PPUDR(0));
	writel((0x01 << 14), AT91C_BASE_PIOC + PIO_SODR(0));
	writel((0x01 << 14), AT91C_BASE_PIOC + PIO_OER(0));
	writel((0x01 << 14), AT91C_BASE_PIOC + PIO_PER(0));

	/* enable PIOC clock  */
	writel((1 << AT91C_ID_PIOC), PMC_PCER + AT91C_BASE_PMC);
}
/** @brief Toggle output
 *
 * @param[in] gpioport uint32_t: GPIO Port base address
 * @param[in] gpios uint32_t
 */
void gpio_toggle(uint32_t gpioport, uint32_t gpios)
{
	uint32_t odsr = PIO_ODSR(gpioport);
	PIO_CODR(gpioport) = odsr & gpios;
	PIO_SODR(gpioport) = ~odsr & gpios;
}
/** @brief Atomic set output
 *
 * @param[in] gpioport uint32_t: GPIO Port base address
 * @param[in] gpios uint32_t
 */
void gpio_set(uint32_t gpioport, uint32_t gpios)
{
	PIO_SODR(gpioport) = gpios;
}
void reset_handler() {
    // Disable Exceptions and Interrupts
    asm volatile ("cpsid f");
    asm volatile ("cpsid i");

    // Initialize the RTT and Event Timer
    timer_init();

    // Reset and Disable the Watchdog Timer
    WDT_CR = WDT_CR_WDRSTT | WDT_CR_KEY;
    WDT_MR = WDT_MR_WDDIS;

    // Enable Peripheral Clocks for the PIOs
    PMC_PCER = (1 << PMC_ID_PIOA);
    PMC_PCER = (1 << PMC_ID_PIOB);
    PMC_PCER = (1 << PMC_ID_PIOC);

    // Clear the PIO Interrupt Status Registers
    PIO_ISR(PIOA);
    PIO_ISR(PIOB);
    PIO_ISR(PIOC);

    // Configure the High-Voltage Pin and Disable the PSU (HV Off)
    PIO_PER(PIN_HV5530_HVEN_PIO)  = (1 << PIN_HV5530_HVEN_IDX); // Enable PIO on Pin
    PIO_OER(PIN_HV5530_HVEN_PIO)  = (1 << PIN_HV5530_HVEN_IDX); // Enable Output
    PIO_PUDR(PIN_HV5530_HVEN_PIO) = (1 << PIN_HV5530_HVEN_IDX); // Disable Pull-Up
    PIO_CODR(PIN_HV5530_HVEN_PIO) = (1 << PIN_HV5530_HVEN_IDX); // Clear Output Data Register

    // Configure the initial state of the 5v PSU (5v On)
    PIO_PER(PIN_5VPSU_EN_PIO)  = (1 << PIN_5VPSU_EN_IDX);    // Enable PIO on Pin
    PIO_OER(PIN_5VPSU_EN_PIO)  = (1 << PIN_5VPSU_EN_IDX);    // Enable Output
    PIO_PUER(PIN_5VPSU_EN_PIO) = (1 << PIN_5VPSU_EN_IDX);    // Enable Pull-Up
    PIO_CODR(PIN_5VPSU_EN_PIO) = (1 << PIN_5VPSU_EN_IDX);    // Clear Output Data Register

    // Configure the ZigBee Shutdown Pin (ZigBee On)
    PIO_PER(PIN_ZIGBEE_SHDN_PIO)  = (1 << PIN_ZIGBEE_SHDN_IDX); // Enable PIO on Pin
    PIO_OER(PIN_ZIGBEE_SHDN_PIO)  = (1 << PIN_ZIGBEE_SHDN_IDX); // Enable Output
    PIO_PUER(PIN_ZIGBEE_SHDN_PIO) = (1 << PIN_ZIGBEE_SHDN_IDX); // Enable Pull-Up
    PIO_SODR(PIN_ZIGBEE_SHDN_PIO) = (1 << PIN_ZIGBEE_SHDN_IDX); // Set Output Data Register

    // Enable User Resets by Asserting the NRST Pin
    // Assert NRST for 2^(11+1) Slow Clock Cycles (32 kHz * 4096 = 128ms)
    RSTC_MR = RSTC_MR_URSTEN | (11 << RSTC_MR_ERSTL_Off) | RSTC_MR_KEY;

    // Set the Flash Read/Write Cycles to 4 (for stable operation at 96MHz)
    EEFC_FMR(EEFC0) = ((EEFC_FMR(EEFC0) & ~EEFC_FMR_FWS_Msk) | (4 << (EEFC_FMR_FWS_Off)));
    EEFC_FMR(EEFC1) = ((EEFC_FMR(EEFC1) & ~EEFC_FMR_FWS_Msk) | (4 << (EEFC_FMR_FWS_Off)));

    // Configure Clock Generator Main Clock (External 12MHz Xtal)
    // Startup time 15625uS for Xtal (65 for 65*8 cycles at slow clock, ~32000Hz)
    CKGR_MOR = CKGR_MOR_KEY | (CKGR_MOR & ~(CKGR_MOR_MOSCXTBY)) |
        CKGR_MOR_MOSCXTEN | (65 << CKGR_MOR_MOSCXTST_Off);
    // Wait the main Xtal to stabilize
    while ((PMC_SR & PMC_SR_MOSCXTS) == 0);
    // Select Xtal as the Main Clock Source
    CKGR_MOR |= CKGR_MOR_KEY | CKGR_MOR_MOSCSEL;
    // Wait for the selection to complete
    while (!(PMC_SR & PMC_SR_MOSCSELS));

    // Configure Clock Generator PLLA Clock (12MHz Xtal * (15+1) = 192MHz)
    // Disable the PLL
    CKGR_PLLAR = CKGR_PLLAR_ONE;
    // Enable with the correct settings
    CKGR_PLLAR = CKGR_PLLAR_ONE | (1 << CKGR_PLLAR_DIVA_Off) |
        (15 << CKGR_PLLAR_MULA_Off) | (0x3F << CKGR_PLLAR_PLLACOUNT_Off);
    // Wait for a lock
    while (!(PMC_SR & PMC_SR_LOCKA));

    // Configure Clock Generator USB UTMI PLL (12MHz Xtal * 40 = 480MHz)
    // Enable the UTMI PLLA
    CKGR_UCKR = CKGR_UCKR_UPLLEN | (0xF << CKGR_UCKR_UPLLCOUNT_Off);
    // Wait for a lock
    while (!(PMC_SR & PMC_SR_LOCKU));

    // Configure Master Clock Controller (MCK = PLLA / 2 = 96MHz)
    // Program clock divider as 2
    PMC_MCKR = (PMC_MCKR & ~(PMC_MCKR_PRES_Msk)) | PMC_MCKR_PRES_CLK_2;
    // Program clock source as PLLA
    PMC_MCKR = (PMC_MCKR & ~(PMC_MCKR_CSS_Msk)) | PMC_MCKR_CSS_PLLA_CLK;
    // Wait for the master clock to be ready
    while (!(PMC_SR & PMC_SR_MCKRDY));

    // Zero the uninitialized data segment
    if (&bss_end - &bss_start > 0) {
        memset(&bss_start, 0, &bss_end - &bss_start);
    }

    // Load the initialized data segment
    if (&data_start != &data_load) {
        memcpy(&data_start, &data_load, &data_end - &data_start);
    }

    // Divide the interrupts into 4 groups of 4; 0-3, 4-7, 8-11, 12-15.
    // Interrupts within the same group will not preempt each other but an
    // interrupt from a group with a lower priority will. When two interrupts
    // within the same group are received at the same time, the one with the
    // lower priority number will be serviced first.
    AIRCR = AIRCR_VECTKEY | (0x5 << AIRCR_PRIGROUP_Off);

    // Set SVC Interrupt Priority to 4
    SHPR2 = ((SHPR2 & ~SHPR2_PRI_11_Msk) | (0x40 << SHPR2_PRI_11_Off));

    // Trap Divide-by-0 as Hard Fault
    CCR |= CCR_DIV_0_TRP;

    // Enable Exceptions
    asm volatile ("cpsie f");

    // Enable the Serial Console
    console_init();

    // Initialize the TWI Driver
    twi_init();

    // Enable Interrupts
    asm volatile ("cpsie i");

    // Print terminal headline
    kputs("\r\n\r\n");
    kputs("nixieclock-firmware: Nixie Clock Main Firmware Program\r\n");
    kputs("Copyright (C) 2013 - 2015 Joe Ciccone and Ed Koloski\r\n");
    kputs("This program comes with ABSOLUTELY NO WARRANTY; for details type 'license show'.\r\n");
    kputs("This is free software, and you are welcome to redistribute it\r\n");
    kputs("under certain conditions; type 'license show' for details.\r\n");
    kputs("\r\n");

    // Print the reset cause
    kputs("Reset Reason: ");
    switch (RSTC_SR & RSTC_SR_RSTTYP_Msk) {
    case RSTC_SR_RSTTYP_GENERAL:    kputs("General");   break;
    case RSTC_SR_RSTTYP_BACKUP:     kputs("Backup");    break;
    case RSTC_SR_RSTTYP_WATCHDOG:   kputs("Watchdog");  break;
    case RSTC_SR_RSTTYP_SOFTWARE:   kputs("Software");  break;
    case RSTC_SR_RSTTYP_USER:       kputs("User");      break;
    default:
        kprintf("Unknown (%lu)", ((RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Off));
    }
    kputs("\r\n");

    // Initialize Services
    clock_init();
    audio_init();
    display_init();
    keyboard_init();

    // Enable the Interactive Console
    console_start();

    // Play a sine-wave to debugging
    audio_play_sine();

    // Initialization Complete
    while (1) {}
}