summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVic Yang <victoryang@chromium.org>2012-12-12 15:53:09 +0800
committerGerrit <chrome-bot@google.com>2012-12-12 19:52:13 -0800
commit243e935ad471b8ad706a4a2989f0b986f39b9a63 (patch)
treecb7de50102c3dacd998a1063678e36d918a99a17
parent73a0bb2ecfe4a8b2dbb5a2885ddcd06fa8e1424a (diff)
downloadchrome-ec-243e935ad471b8ad706a4a2989f0b986f39b9a63.tar.gz
stm32: Add option to select timer for hardware clock
Hardware clock uses two timers, currently TIM3 and TIM4. This CL adds an option to select between TIM2, TIM3, and TIM4, so that we can use any one the three timer as a PWM source. BUG=chrome-os-partner:14319, chrome-os-partner:7463 TEST=Build and run on snow/spring. Build success on daisy. BRANCH=none Change-Id: I1a00b3d491ee3e131708b573f6ea70e6b56c96dd Signed-off-by: Vic Yang <victoryang@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/39584
-rw-r--r--board/daisy/board.h4
-rw-r--r--board/snow/board.h4
-rw-r--r--board/spring/board.h4
-rw-r--r--chip/stm32/hwtimer.c136
4 files changed, 88 insertions, 60 deletions
diff --git a/board/daisy/board.h b/board/daisy/board.h
index b2308abc6f..da85579d7d 100644
--- a/board/daisy/board.h
+++ b/board/daisy/board.h
@@ -47,6 +47,10 @@
#define I2C_PORT_CHARGER I2C_PORT_HOST
#define I2C_PORT_SLAVE 1
+/* Timer selection */
+#define TIM_CLOCK_MSB 3
+#define TIM_CLOCK_LSB 4
+
/* GPIO signal list */
enum gpio_signal {
/* Inputs with interrupt handlers are first for efficiency */
diff --git a/board/snow/board.h b/board/snow/board.h
index 749960bc6f..072b5ec40e 100644
--- a/board/snow/board.h
+++ b/board/snow/board.h
@@ -59,6 +59,10 @@
/* Battery */
#define CONFIG_BATTERY_BQ20Z453
+/* Timer selection */
+#define TIM_CLOCK_MSB 3
+#define TIM_CLOCK_LSB 4
+
/* GPIO signal list */
enum gpio_signal {
/* Inputs with interrupt handlers are first for efficiency */
diff --git a/board/spring/board.h b/board/spring/board.h
index e31a635fad..192eddc550 100644
--- a/board/spring/board.h
+++ b/board/spring/board.h
@@ -55,6 +55,10 @@
/* Battery */
#define CONFIG_BATTERY_BQ20Z453
+/* Timer selection */
+#define TIM_CLOCK_MSB 2
+#define TIM_CLOCK_LSB 4
+
/* ADC signal */
#define CONFIG_ADC
enum adc_channel {
diff --git a/chip/stm32/hwtimer.c b/chip/stm32/hwtimer.c
index 3a58e9dcd1..ef09a8dd5e 100644
--- a/chip/stm32/hwtimer.c
+++ b/chip/stm32/hwtimer.c
@@ -21,6 +21,15 @@
#define TIM_WD 1 /* Timer to use for watchdog */
#endif
+/*
+ * TIM_CLOCK_MSB and TIM_CLOCK_LSB must be defined per board. The available
+ * values are 2, 3, and 4. This gives us flexibility to make any of the three
+ * timer as a PWM source.
+ */
+#define IRQ_TIM(n) STM32_CAT(STM32_IRQ_TIM, n, )
+#define IRQ_MSB IRQ_TIM(TIM_CLOCK_MSB)
+#define IRQ_LSB IRQ_TIM(TIM_CLOCK_LSB)
+
enum {
TIM_WD_BASE = STM32_TIM1_BASE,
};
@@ -31,33 +40,33 @@ void __hw_clock_event_set(uint32_t deadline)
{
last_deadline = deadline;
- if ((deadline >> 16) > STM32_TIM_CNT(3)) {
+ if ((deadline >> 16) > STM32_TIM_CNT(TIM_CLOCK_MSB)) {
/* first set a match on the MSB */
- STM32_TIM_CCR1(3) = deadline >> 16;
+ STM32_TIM_CCR1(TIM_CLOCK_MSB) = deadline >> 16;
/* disable LSB match */
- STM32_TIM_DIER(4) &= ~2;
+ STM32_TIM_DIER(TIM_CLOCK_LSB) &= ~2;
/* Clear the match flags */
- STM32_TIM_SR(3) = ~2;
- STM32_TIM_SR(4) = ~2;
+ STM32_TIM_SR(TIM_CLOCK_MSB) = ~2;
+ STM32_TIM_SR(TIM_CLOCK_LSB) = ~2;
/* Set the match interrupt */
- STM32_TIM_DIER(3) |= 2;
+ STM32_TIM_DIER(TIM_CLOCK_MSB) |= 2;
}
/*
- * In the unlikely case where the MSB on TIM3 has increased and matched
+ * In the unlikely case where the MSB has increased and matched
* the deadline MSB before we set the match interrupt, as the STM
* hardware timer won't trigger an interrupt, we fall back to the
* following LSB event code to set another interrupt.
*/
- if ((deadline >> 16) == STM32_TIM_CNT(3)) {
+ if ((deadline >> 16) == STM32_TIM_CNT(TIM_CLOCK_MSB)) {
/* we can set a match on the LSB only */
- STM32_TIM_CCR1(4) = deadline & 0xffff;
+ STM32_TIM_CCR1(TIM_CLOCK_LSB) = deadline & 0xffff;
/* disable MSB match */
- STM32_TIM_DIER(3) &= ~2;
+ STM32_TIM_DIER(TIM_CLOCK_MSB) &= ~2;
/* Clear the match flags */
- STM32_TIM_SR(3) = ~2;
- STM32_TIM_SR(4) = ~2;
+ STM32_TIM_SR(TIM_CLOCK_MSB) = ~2;
+ STM32_TIM_SR(TIM_CLOCK_LSB) = ~2;
/* Set the match interrupt */
- STM32_TIM_DIER(4) |= 2;
+ STM32_TIM_DIER(TIM_CLOCK_LSB) |= 2;
}
/*
* If the LSB deadline is already in the past and won't trigger an
@@ -75,8 +84,8 @@ uint32_t __hw_clock_event_get(void)
void __hw_clock_event_clear(void)
{
/* Disable the match interrupts */
- STM32_TIM_DIER(4) &= ~2;
- STM32_TIM_DIER(3) &= ~2;
+ STM32_TIM_DIER(TIM_CLOCK_LSB) &= ~2;
+ STM32_TIM_DIER(TIM_CLOCK_MSB) &= ~2;
}
uint32_t __hw_clock_source_read(void)
@@ -86,89 +95,95 @@ uint32_t __hw_clock_source_read(void)
/* Ensure the two half-words are coherent */
do {
- hi = STM32_TIM_CNT(3);
- lo = STM32_TIM_CNT(4);
- } while (hi != STM32_TIM_CNT(3));
+ hi = STM32_TIM_CNT(TIM_CLOCK_MSB);
+ lo = STM32_TIM_CNT(TIM_CLOCK_LSB);
+ } while (hi != STM32_TIM_CNT(TIM_CLOCK_MSB));
return (hi << 16) | lo;
}
void __hw_clock_source_set(uint32_t ts)
{
- STM32_TIM_CNT(3) = ts >> 16;
- STM32_TIM_CNT(4) = ts & 0xffff;
+ STM32_TIM_CNT(TIM_CLOCK_MSB) = ts >> 16;
+ STM32_TIM_CNT(TIM_CLOCK_LSB) = ts & 0xffff;
}
static void __hw_clock_source_irq(void)
{
- uint32_t stat_tim3 = STM32_TIM_SR(3);
+ uint32_t stat_tim_msb = STM32_TIM_SR(TIM_CLOCK_MSB);
/* Clear status */
- STM32_TIM_SR(4) = 0;
- STM32_TIM_SR(3) = 0;
+ STM32_TIM_SR(TIM_CLOCK_LSB) = 0;
+ STM32_TIM_SR(TIM_CLOCK_MSB) = 0;
/*
* Find expired timers and set the new timer deadline
* signal overflow if the 16-bit MSB counter has overflowed.
*/
- process_timers(stat_tim3 & 0x01);
+ process_timers(stat_tim_msb & 0x01);
}
-DECLARE_IRQ(STM32_IRQ_TIM3, __hw_clock_source_irq, 1);
-DECLARE_IRQ(STM32_IRQ_TIM4, __hw_clock_source_irq, 1);
+DECLARE_IRQ(IRQ_MSB, __hw_clock_source_irq, 1);
+DECLARE_IRQ(IRQ_LSB, __hw_clock_source_irq, 1);
int __hw_clock_source_init(uint32_t start_t)
{
/*
* we use 2 chained 16-bit counters to emulate a 32-bit one :
- * TIM3 is the MSB (Slave)
- * TIM4 is the LSB (Master)
+ * TIM_CLOCK_MSB is the MSB (Slave)
+ * TIM_CLOCK_LSB is the LSB (Master)
*/
- /* Enable TIM3 and TIM4 clocks */
- STM32_RCC_APB1ENR |= 0x6;
+ /* Enable TIM_CLOCK_MSB and TIM_CLOCK_LSB clocks */
+ STM32_RCC_APB1ENR |= (1 << (TIM_CLOCK_MSB - 2)) |
+ (1 << (TIM_CLOCK_LSB - 2));
/*
* Timer configuration : Upcounter, counter disabled, update event only
* on overflow.
*/
- STM32_TIM_CR1(3) = 0x0004;
- STM32_TIM_CR1(4) = 0x0004;
- /* TIM4 (master mode) generates a periodic trigger signal on each UEV */
- STM32_TIM_CR2(3) = 0x0000;
- STM32_TIM_CR2(4) = 0x0020;
- /* TIM3 (slave mode) uses ITR3 as internal trigger */
- STM32_TIM_SMCR(3) = 0x0037;
- STM32_TIM_SMCR(4) = 0x0000;
+ STM32_TIM_CR1(TIM_CLOCK_MSB) = 0x0004;
+ STM32_TIM_CR1(TIM_CLOCK_LSB) = 0x0004;
+ /*
+ * TIM_CLOCK_LSB (master mode) generates a periodic trigger signal on
+ * each UEV
+ */
+ STM32_TIM_CR2(TIM_CLOCK_MSB) = 0x0000;
+ STM32_TIM_CR2(TIM_CLOCK_LSB) = 0x0020;
+ /* TIM_CLOCK_MSB (slave mode) uses TIM_CLOCK_LSB as internal trigger */
+ STM32_TIM_SMCR(TIM_CLOCK_MSB) = 0x0007 | ((TIM_CLOCK_LSB - 1) << 4);
+ STM32_TIM_SMCR(TIM_CLOCK_LSB) = 0x0000;
/* Auto-reload value : 16-bit free-running counters */
- STM32_TIM_ARR(3) = 0xffff;
- STM32_TIM_ARR(4) = 0xffff;
- /* Pre-scaler value :
- * TIM4 is counting microseconds, TIM3 is counting every TIM4 overflow.
+ STM32_TIM_ARR(TIM_CLOCK_MSB) = 0xffff;
+ STM32_TIM_ARR(TIM_CLOCK_LSB) = 0xffff;
+ /*
+ * Pre-scaler value :
+ * TIM_CLOCK_LSB is counting microseconds, TIM_CLOCK_MSB is counting
+ * every TIM_CLOCK_LSB overflow.
*/
- STM32_TIM_PSC(3) = 0;
- STM32_TIM_PSC(4) = CLOCKSOURCE_DIVIDER - 1;
+ STM32_TIM_PSC(TIM_CLOCK_MSB) = 0;
+ STM32_TIM_PSC(TIM_CLOCK_LSB) = CLOCKSOURCE_DIVIDER - 1;
/* Reload the pre-scaler */
- STM32_TIM_EGR(3) = 0x0001;
- STM32_TIM_EGR(4) = 0x0001;
+ STM32_TIM_EGR(TIM_CLOCK_MSB) = 0x0001;
+ STM32_TIM_EGR(TIM_CLOCK_LSB) = 0x0001;
- /* setup the overflow interrupt on TIM3 */
- STM32_TIM_DIER(3) = 0x0001;
- STM32_TIM_DIER(4) = 0x0000;
+ /* setup the overflow interrupt on TIM_CLOCK_MSB */
+ STM32_TIM_DIER(TIM_CLOCK_MSB) = 0x0001;
+ STM32_TIM_DIER(TIM_CLOCK_LSB) = 0x0000;
/* Start counting */
- STM32_TIM_CR1(3) |= 1;
- STM32_TIM_CR1(4) |= 1;
+ STM32_TIM_CR1(TIM_CLOCK_MSB) |= 1;
+ STM32_TIM_CR1(TIM_CLOCK_LSB) |= 1;
/* Override the count with the start value now that counting has
* started. */
__hw_clock_source_set(start_t);
/* Enable timer interrupts */
- task_enable_irq(STM32_IRQ_TIM3);
- task_enable_irq(STM32_IRQ_TIM4);
+ task_enable_irq(IRQ_MSB);
+ task_enable_irq(IRQ_LSB);
- return STM32_IRQ_TIM4;
+ return IRQ_LSB;
}
/*
@@ -224,18 +239,19 @@ void hwtimer_setup_watchdog(void)
*/
timer->cr1 = 0x0014 | (1 << 7);
- /* TIM (slave mode) uses ITR3 as internal trigger */
- timer->smcr = 0x0037;
+ /* TIM (slave mode) uses TIM_CLOCK_LSB as internal trigger */
+ timer->smcr = 0x0007 | ((TIM_CLOCK_LSB - 1) << 4);
/*
* The auto-reload value is based on the period between rollovers for
- * TIM4. Since TIM4 runs at 1MHz, it will overflow in 65.536ms. We
- * divide our required watchdog period by this amount to obtain the
- * number of times TIM4 can overflow before we generate an interrupt.
+ * TIM_CLOCK_LSB. Since TIM_CLOCK_LSB runs at 1MHz, it will overflow
+ * in 65.536ms. We divide our required watchdog period by this amount
+ * to obtain the number of times TIM_CLOCK_LSB can overflow before we
+ * generate an interrupt.
*/
timer->arr = timer->cnt = WATCHDOG_PERIOD_MS * 1000 / (1 << 16);
- /* count on every TIM4 overflow */
+ /* count on every TIM_CLOCK_LSB overflow */
timer->psc = 0;
/* Reload the pre-scaler from arr when it goes below zero */