Merge "Support dynamically changing the system clock"

This commit is contained in:
Gerrit
2012-04-09 11:13:47 -07:00
committed by Gerrit Code Review
17 changed files with 249 additions and 151 deletions

View File

@@ -11,9 +11,6 @@
/* Config flags */
#define CONFIG_LIGHTBAR
/* 66.667 Mhz clock frequency */
#define CPU_CLOCK 66666667
/* Fan PWM channels */
#define FAN_CH_KBLIGHT 1 /* Keyboard backlight */
#define FAN_CH_POWER_LED 3 /* Power adapter LED */

View File

@@ -21,9 +21,6 @@
#define CONFIG_TMP006
#define CONFIG_USB_CHARGE
/* 66.667 Mhz clock frequency */
#define CPU_CLOCK 66666667
/* Fan PWM channels */
#define FAN_CH_CPU 0 /* CPU fan */
#define FAN_CH_KBLIGHT 1 /* Keyboard backlight */

View File

@@ -5,41 +5,74 @@
/* Clocks and power management settings */
#include <stdint.h>
#include "board.h"
#include "clock.h"
#include "config.h"
#include "console.h"
#include "gpio.h"
#include "registers.h"
#include "system.h"
#include "task.h"
#include "timer.h"
#include "uart.h"
#include "registers.h"
#include "util.h"
/**
* Idle task
* executed when no task are ready to be scheduled
*/
void __idle(void)
#define PLL_CLOCK 66666667 /* System clock = 200MHz PLL/3 = 66.667MHz */
/* Disable the PLL; run off internal oscillator. */
static void clock_disable_pll(void)
{
while (1) {
/* wait for the irq event */
asm("wfi");
/* TODO more power management here */
}
/* Switch to 16MHz internal oscillator and power down the PLL */
LM4_SYSTEM_RCC = LM4_SYSTEM_RCC_SYSDIV(0) |
LM4_SYSTEM_RCC_BYPASS |
LM4_SYSTEM_RCC_PWRDN |
LM4_SYSTEM_RCC_OSCSRC(1) |
LM4_SYSTEM_RCC_MOSCDIS;
LM4_SYSTEM_RCC2 &= ~LM4_SYSTEM_RCC2_USERCC2;
}
/* simple busy waiting before clocks are initialized */
static void wait_cycles(uint32_t cycles)
/* Enable the PLL to run at full clock speed */
static void clock_enable_pll(void)
{
/* Disable the PLL so we can reconfigure it */
clock_disable_pll();
/* Enable the PLL (PWRDN is no longer set) and set divider. PLL is
* still bypassed, since it hasn't locked yet. */
LM4_SYSTEM_RCC = LM4_SYSTEM_RCC_SYSDIV(2) |
LM4_SYSTEM_RCC_USESYSDIV |
LM4_SYSTEM_RCC_BYPASS |
LM4_SYSTEM_RCC_OSCSRC(1) |
LM4_SYSTEM_RCC_MOSCDIS;
/* Wait for the PLL to lock */
clock_wait_cycles(1024);
while (!(LM4_SYSTEM_PLLSTAT & 1))
;
/* Remove bypass on PLL */
LM4_SYSTEM_RCC &= ~LM4_SYSTEM_RCC_BYPASS;
}
void clock_wait_cycles(uint32_t cycles)
{
asm("1: subs %0, #1\n"
" bne 1b\n" :: "r"(cycles));
}
/**
* Function to measure baseline for power consumption.
int clock_get_freq(void)
{
return (LM4_SYSTEM_PLLSTAT & 1) ? PLL_CLOCK : INTERNAL_CLOCK;
}
/*****************************************************************************/
/* Console commands */
/* Function to measure baseline for power consumption.
*
* Levels :
* 0 : CPU running in tight loop
@@ -47,8 +80,7 @@ static void wait_cycles(uint32_t cycles)
* 2 : CPU in sleep mode
* 3 : CPU in sleep mode and peripherals gated
* 4 : CPU in deep sleep mode
* 5 : CPU in deep sleep mode and peripherals gated
*/
* 5 : CPU in deep sleep mode and peripherals gated */
static int command_sleep(int argc, char **argv)
{
int level = 0;
@@ -146,53 +178,71 @@ static int command_sleep(int argc, char **argv)
DECLARE_CONSOLE_COMMAND(sleep, command_sleep);
static void clock_init_pll(uint32_t value)
/* TODO: temporary holding place for notifying modules of clock change. Should
* be moved to main.c after we finish measuring the power savings, so the clock
* frequency is automatically dropped after verified boot. */
#include "i2c.h"
#include "hwtimer.h"
#include "peci.h"
#include "watchdog.h"
static int command_disable_pll(int argc, char **argv)
{
/**
* at startup, OSCSRC is PIOSC (precision internal oscillator)
* PLL and PLL2 are in power-down
*/
int freq;
/* PLL already setup */
if (LM4_SYSTEM_PLLSTAT & 1)
return;
clock_disable_pll();
/* Put a bypass on the system clock PLLs, no divider */
LM4_SYSTEM_RCC = (LM4_SYSTEM_RCC | 0x800) & ~0x400000;
LM4_SYSTEM_RCC2 = (LM4_SYSTEM_RCC2 | 0x800) & ~0x80000000;
/* Enable main and precision internal oscillators */
LM4_SYSTEM_RCC &= ~0x3;
/* Perform an auto calibration of the internal oscillator, using the
* 32.768KHz hibernate clock. */
/* TODO: (crosbug.com/p/7693) This is only needed on early chips which
* aren't factory trimmed. */
LM4_SYSTEM_PIOSCCAL = 0x80000000;
LM4_SYSTEM_PIOSCCAL = 0x80000200;
/* wait 1 million CPU cycles */
wait_cycles(512 * 1024);
/* clear PLL lock flag (aka PLLLMIS) */
LM4_SYSTEM_MISC = 0x40;
/* clear powerdown / set XTAL frequency, divider, and source */
LM4_SYSTEM_RCC = (LM4_SYSTEM_RCC & ~0x07c027f0) | (value & 0x07c007f0);
/* wait 32 CPU cycles */
wait_cycles(16);
/* wait for PLL to lock */
while (!(LM4_SYSTEM_RIS & 0x40));
/* Remove bypass on PLL */
LM4_SYSTEM_RCC = LM4_SYSTEM_RCC & ~0x800;
}
int clock_init(void)
{
/* CPU clock = PLL/3 = 66.667MHz; System clock = PLL */
BUILD_ASSERT(CPU_CLOCK == 66666667);
/* Osc source = internal 16MHz oscillator */
clock_init_pll(0x01400550);
/* Notify modules of frequency change */
freq = clock_get_freq();
hwtimer_clock_changed(freq);
#ifdef CONFIG_TASK_WATCHDOG
watchdog_clock_changed(freq);
#endif
#ifdef CONFIG_I2C
i2c_clock_changed(freq);
#endif
#ifdef CONFIG_PECI
peci_clock_changed(freq);
#endif
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(nopll, command_disable_pll);
/*****************************************************************************/
/* Initialization */
int clock_init(void)
{
#ifndef BOARD_bds
/* Only BDS has an external crystal; other boards don't have one, and
* can disable main oscillator control to reduce power consumption. */
LM4_SYSTEM_MOSCCTL = 0x04;
#endif
/* Perform an auto calibration of the internal oscillator using the
* 32.768KHz hibernate clock, unless we've already done so. */
/* TODO: (crosbug.com/p/7693) This is only needed on early chips which
* aren't factory trimmed. */
if ((LM4_SYSTEM_PIOSCSTAT & 0x300) != 0x100) {
/* Start calibration */
LM4_SYSTEM_PIOSCCAL = 0x80000000;
LM4_SYSTEM_PIOSCCAL = 0x80000200;
/* Wait for result */
clock_wait_cycles(16);
while (!(LM4_SYSTEM_PIOSCSTAT & 0x300))
;
}
/* TODO: UART seems to glitch unless we wait 500k cycles before
* enabling the PLL, but only if this is a cold boot. Why? UART
* doesn't even use the PLL'd system clock. I've heard rumors the
* Stellaris ROM library does this too, but why? */
if (!system_jumped_to_this_image())
clock_wait_cycles(500000);
clock_enable_pll();
return EC_SUCCESS;
}

View File

@@ -5,18 +5,14 @@
/* Hardware timers driver */
#include <stdint.h>
#include "board.h"
#include "clock.h"
#include "hwtimer.h"
#include "registers.h"
#include "task.h"
#define US_PER_SECOND 1000000
/* Divider to get microsecond for the clock */
#define CLOCKSOURCE_DIVIDER (CPU_CLOCK/US_PER_SECOND)
void __hw_clock_event_set(uint32_t deadline)
{
/* set the match on the deadline */
@@ -57,6 +53,14 @@ static void __hw_clock_source_irq(void)
DECLARE_IRQ(LM4_IRQ_TIMERW0A, __hw_clock_source_irq, 1);
void hwtimer_clock_changed(int freq)
{
/* Set the prescaler to increment every microsecond. This takes
* effect immediately, because the TAILD bit in TAMR is clear. */
LM4_TIMER_TAPR(6) = freq / US_PER_SECOND;
}
int __hw_clock_source_init(void)
{
volatile uint32_t scratch __attribute__((unused));
@@ -75,8 +79,10 @@ int __hw_clock_source_init(void)
LM4_TIMER_IMR(6) = 0x1;
/* 32-bit timer mode */
LM4_TIMER_CFG(6) = 4;
/* set the prescaler to increment every microsecond */
LM4_TIMER_TAPR(6) = CLOCKSOURCE_DIVIDER;
/* Set initial clock frequency */
hwtimer_clock_changed(clock_get_freq());
/* Periodic mode, counting down */
LM4_TIMER_TAMR(6) = 0x22;
/* use the full 32-bits of the timer */

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -6,6 +6,7 @@
/* I2C port module for Chrome EC */
#include "board.h"
#include "clock.h"
#include "console.h"
#include "gpio.h"
#include "i2c.h"
@@ -58,6 +59,7 @@ static int wait_idle(int port)
return EC_SUCCESS;
}
/* Transmit one block of raw data, then receive one block of raw data.
* <start> flag indicates this smbus session start from idle state.
* <stop> flag means this session can be termicate with smbus stop bit
@@ -142,7 +144,6 @@ static int i2c_transmit_receive(int port, int slave_addr,
}
int i2c_read16(int port, int slave_addr, int offset, int *data)
{
int rv;
@@ -192,6 +193,7 @@ int i2c_write16(int port, int slave_addr, int offset, int data)
return rv;
}
int i2c_read8(int port, int slave_addr, int offset, int* data)
{
int rv;
@@ -210,6 +212,7 @@ int i2c_read8(int port, int slave_addr, int offset, int* data)
return rv;
}
int i2c_write8(int port, int slave_addr, int offset, int data)
{
int rv;
@@ -226,9 +229,7 @@ int i2c_write8(int port, int slave_addr, int offset, int data)
return rv;
}
/* Read ascii string using smbus read block protocol.
* The return data <data> will be null terminated.
*/
int i2c_read_string(int port, int slave_addr, int offset, uint8_t *data,
int len)
{
@@ -259,6 +260,18 @@ exit:
}
void i2c_clock_changed(int freq)
{
LM4_I2C_MTPR(I2C_PORT_THERMAL) =
(freq / (I2C_SPEED_THERMAL * 10 * 2)) - 1;
LM4_I2C_MTPR(I2C_PORT_BATTERY) =
(freq / (I2C_SPEED_BATTERY * 10 * 2)) - 1;
LM4_I2C_MTPR(I2C_PORT_CHARGER) =
(freq / (I2C_SPEED_CHARGER * 10 * 2)) - 1;
LM4_I2C_MTPR(I2C_PORT_LIGHTBAR) =
(freq / (I2C_SPEED_LIGHTBAR * 10 * 2)) - 1;
}
/*****************************************************************************/
/* Interrupt handlers */
@@ -439,20 +452,12 @@ int i2c_init(void)
/* Initialize ports as master, with interrupts enabled */
LM4_I2C_MCR(I2C_PORT_THERMAL) = 0x10;
LM4_I2C_MTPR(I2C_PORT_THERMAL) =
(CPU_CLOCK / (I2C_SPEED_THERMAL * 10 * 2)) - 1;
LM4_I2C_MCR(I2C_PORT_BATTERY) = 0x10;
LM4_I2C_MTPR(I2C_PORT_BATTERY) =
(CPU_CLOCK / (I2C_SPEED_BATTERY * 10 * 2)) - 1;
LM4_I2C_MCR(I2C_PORT_CHARGER) = 0x10;
LM4_I2C_MTPR(I2C_PORT_CHARGER) =
(CPU_CLOCK / (I2C_SPEED_CHARGER * 10 * 2)) - 1;
LM4_I2C_MCR(I2C_PORT_LIGHTBAR) = 0x10;
LM4_I2C_MTPR(I2C_PORT_LIGHTBAR) =
(CPU_CLOCK / (I2C_SPEED_LIGHTBAR * 10 * 2)) - 1;
/* Set initial clock frequency */
i2c_clock_changed(clock_get_freq());
/* Enable irqs */
task_enable_irq(LM4_IRQ_I2C0);

View File

@@ -6,6 +6,7 @@
/* PECI interface for Chrome EC */
#include "board.h"
#include "clock.h"
#include "console.h"
#include "gpio.h"
#include "peci.h"
@@ -51,6 +52,7 @@ int peci_get_cpu_temp(void)
return v >> 6;
}
int peci_temp_sensor_poll(void)
{
last_temp_val = peci_get_cpu_temp();
@@ -61,11 +63,33 @@ int peci_temp_sensor_poll(void)
return EC_ERROR_UNKNOWN;
}
int peci_temp_sensor_get_val(int idx)
{
return last_temp_val;
}
void peci_clock_changed(int freq)
{
int baud;
/* Disable polling while reconfiguring */
LM4_PECI_CTL = 0;
/* Calculate baud setting from desired rate, compensating for internal
* and external delays. */
baud = freq / (4 * PECI_BAUD_RATE) - 2;
baud -= (freq / 1000000) * (PECI_TD_FET_NS + PECI_TD_INT_NS) / 1000;
/* Set baud rate and polling rate */
LM4_PECI_DIV = (baud << 16) |
(PECI_POLL_INTERVAL_MS * (freq / 1000 / 4096));
/* Set up temperature monitoring to report in degrees K */
LM4_PECI_CTL = ((PECI_TJMAX + 273) << 22) | 0x2001;
}
/*****************************************************************************/
/* Console commands */
@@ -88,7 +112,6 @@ DECLARE_CONSOLE_COMMAND(pecitemp, command_peci_temp);
int peci_init(void)
{
volatile uint32_t scratch __attribute__((unused));
int baud;
/* Enable the PECI module and delay a few clocks */
LM4_SYSTEM_RCGCPECI = 1;
@@ -97,21 +120,8 @@ int peci_init(void)
/* Configure GPIOs */
configure_gpios();
/* Disable polling while reconfiguring */
LM4_PECI_CTL = 0;
/* Calculate baud setting from desired rate, compensating for internal
* and external delays. */
baud = CPU_CLOCK / (4 * PECI_BAUD_RATE) - 2;
baud -= (CPU_CLOCK / 1000000) * (PECI_TD_FET_NS + PECI_TD_INT_NS)
/ 1000;
/* Set baud rate and polling rate */
LM4_PECI_DIV = (baud << 16) |
(PECI_POLL_INTERVAL_MS * (CPU_CLOCK / 1000 / 4096));
/* Set up temperature monitoring to report in degrees K */
LM4_PECI_CTL = ((PECI_TJMAX + 273) << 22) | 0x2001;
/* Set initial clock frequency */
peci_clock_changed(clock_get_freq());
return EC_SUCCESS;
}

View File

@@ -191,7 +191,17 @@ static inline int lm4_fan_addr(int ch, int offset)
#define LM4_SYSTEM_MISC LM4REG(0x400fe058)
#define LM4_SYSTEM_RESC LM4REG(0x400fe05c)
#define LM4_SYSTEM_RCC LM4REG(0x400fe060)
#define LM4_SYSTEM_RCC_SYSDIV(x) (((x) & 0xf) << 23)
#define LM4_SYSTEM_RCC_USESYSDIV (1 << 22)
#define LM4_SYSTEM_RCC_PWRDN (1 << 13)
#define LM4_SYSTEM_RCC_BYPASS (1 << 11)
#define LM4_SYSTEM_RCC_XTAL(x) (((x) & 0x1f) << 6)
#define LM4_SYSTEM_RCC_OSCSRC(x) (((x) & 0x3) << 4)
#define LM4_SYSTEM_RCC_IOSCDIS (1 << 1)
#define LM4_SYSTEM_RCC_MOSCDIS (1 << 0)
#define LM4_SYSTEM_RCC2 LM4REG(0x400fe070)
#define LM4_SYSTEM_RCC2_USERCC2 (1 << 31)
#define LM4_SYSTEM_MOSCCTL LM4REG(0x400fe07c)
#define LM4_SYSTEM_PIOSCCAL LM4REG(0x400fe150)
#define LM4_SYSTEM_PIOSCSTAT LM4REG(0x400fe154)
#define LM4_SYSTEM_PLLSTAT LM4REG(0x400fe168)

View File

@@ -1,13 +1,12 @@
/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* Watchdog driver */
#include <stdint.h>
#include "board.h"
#include "clock.h"
#include "common.h"
#include "config.h"
#include "registers.h"
@@ -25,8 +24,9 @@
/* magic value to unlock the watchdog registers */
#define LM4_WATCHDOG_MAGIC_WORD 0x1ACCE551
/* watchdog counter initial value */
static uint32_t watchdog_period;
#define WATCHDOG_PERIOD_MS 1100 /* Watchdog period in ms */
static uint32_t watchdog_period; /* Watchdog counter initial value */
/* console debug command prototypes */
int command_task_info(int argc, char **argv);
@@ -110,7 +110,15 @@ void watchdog_reload(void)
LM4_WATCHDOG_LOCK(0) = 0xdeaddead;
}
int watchdog_init(int period_ms)
void watchdog_clock_changed(int freq)
{
/* Set the timeout period */
watchdog_period = WATCHDOG_PERIOD_MS * (freq / 1000);
}
int watchdog_init(void)
{
volatile uint32_t scratch __attribute__((unused));
@@ -122,8 +130,8 @@ int watchdog_init(int period_ms)
/* Unlock watchdog registers */
LM4_WATCHDOG_LOCK(0) = LM4_WATCHDOG_MAGIC_WORD;
/* Set the time-out period */
watchdog_period = period_ms * (CPU_CLOCK / 1000);
/* Set initial timeout period */
watchdog_clock_changed(clock_get_freq());
LM4_WATCHDOG_LOAD(0) = watchdog_period;
/* de-activate the watchdog when the JTAG stops the CPU */

View File

@@ -13,19 +13,6 @@
#include "registers.h"
#include "util.h"
/**
* Idle task
* executed when no task are ready to be scheduled
*/
void __idle(void)
{
while (1) {
/* wait for the irq event */
asm("wfi");
/* TODO more power management here */
}
}
int clock_init(void)
{
uint32_t tmp_acr;

View File

@@ -35,7 +35,7 @@ typedef union {
/* declare task routine prototypes */
#define TASK(n, r, d) int r(void *);
#include TASK_LIST
void __idle(void);
static void __idle(void);
CONFIG_TASK_LIST
#undef TASK
@@ -51,6 +51,17 @@ static const char * const task_names[] = {
extern void __switchto(task_ *from, task_ *to);
/* Idle task. Executed when no tasks are ready to be scheduled. */
void __idle(void)
{
while (1) {
/* Wait for the irq event */
asm("wfi");
/* TODO: more power management here */
}
}
static void task_exit_trap(void)
{
int i = task_get_current();

View File

@@ -167,7 +167,8 @@ DECLARE_CONSOLE_COMMAND(waitms, command_wait);
static int command_get_time(int argc, char **argv)
{
timestamp_t ts = get_time();
uart_printf("Time: 0x%08x%08x us\n", ts.le.hi, ts.le.lo);
uart_printf("Time: 0x%08x%08x us (%u %u)\n", ts.le.hi, ts.le.lo,
ts.le.hi, ts.le.lo);
return EC_SUCCESS;
}

View File

@@ -1,14 +1,23 @@
/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* Clocks and power management settings */
#ifndef __CLOCK_H
#define __CLOCK_H
#ifndef __CROS_EC_CLOCK_H
#define __CROS_EC_CLOCK_H
/* set the CPU clocks and PLLs */
#include "common.h"
/* Set the CPU clocks and PLLs. */
int clock_init(void);
#endif /* __CLOCK_H */
/* Returns the current clock frequency in Hz. */
int clock_get_freq(void);
/* Wait <cycles> system clock cycles. Simple busy waiting for before
* clocks/timers are initialized. */
void clock_wait_cycles(uint32_t cycles);
#endif /* __CROS_EC_CLOCK_H */

View File

@@ -30,6 +30,9 @@ uint32_t __hw_clock_source_read(void);
*/
int __hw_clock_source_init(void);
/* Notifies the module the system clock frequency has changed to <freq>. */
void hwtimer_clock_changed(int freq);
/**
* Searches the next deadline and program it in the timer hardware.
*

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -16,6 +16,9 @@
/* Initializes the module. */
int i2c_init(void);
/* Notifies the module the system clock frequency has changed to <freq>. */
void i2c_clock_changed(int freq);
/* Reads a 16-bit register from the slave at 8-bit slave address
* <slaveaddr>, at the specified 8-bit <offset> in the slave's address
* space. */

View File

@@ -15,6 +15,9 @@ struct temp_sensor_t;
/* Initializes the module. */
int peci_init(void);
/* Notifies the module the system clock frequency has changed to <freq>. */
void peci_clock_changed(int freq);
/* Returns the current CPU temperature in degrees K, or -1 if error.
*
* Note that the PECI interface is currently a little flaky; if you get an

View File

@@ -1,21 +1,21 @@
/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* Watchdog driver */
#ifndef _WATCHDOG_H
#define _WATCHDOG_H
#ifndef __CROS_EC_WATCHDOG_H
#define __CROS_EC_WATCHDOG_H
/* Initialize the watchdog. This will cause the CPU to reboot if it has been
* more than 2 watchdog periods since watchdog_reload() has been called. */
int watchdog_init(int period_ms);
/* Reload the watchdog counter */
void watchdog_reload(void);
/**
* Initialize the watchdog
* with a reloading period of <period_ms> milliseconds.
* It reboots the CPU if the counter has not been reloaded for twice the period.
*/
int watchdog_init(int period_ms);
/* Notifies the module the system clock frequency has changed to <freq>. */
void watchdog_clock_changed(int freq);
#endif /* _WATCHDOG_H */
#endif /* __CROS_EC_WATCHDOG_H */

View File

@@ -6,16 +6,14 @@
/* Power state machine demo module for Chrome EC */
#include "board.h"
#include "clock.h"
#include "powerdemo.h"
#include "task.h"
#include "timer.h"
#include "uart.h"
#include "registers.h"
#define US_PER_SECOND 1000000
/* Divider to get microsecond for the clock */
#define CLOCKSOURCE_DIVIDER (CPU_CLOCK/US_PER_SECOND)
static volatile enum {
POWER_STATE_IDLE = 0, /* Idle */
@@ -77,7 +75,7 @@ int power_demo_init(void)
/* 32-bit timer mode */
LM4_TIMER_CFG(7) = 4;
/* Set the prescaler to increment every microsecond */
LM4_TIMER_TAPR(7) = CLOCKSOURCE_DIVIDER;
LM4_TIMER_TAPR(7) = clock_get_freq() / US_PER_SECOND;
/* One-shot, counting down */
LM4_TIMER_TAMR(7) = 0x01;
/* Set overflow interrupt */