[PATCH 5/10] deadbat-cpu-idle.patch

Werner Almesberger werner at openmoko.org
Tue Jul 15 13:01:14 CEST 2008


This patch makes the CPU enter IDLE mode while waiting in wait_for_power.

To wake up from IDLE mode, we need an interrupt. Note that this interrupt
only needs to be signaled to the CPU, but the CPU does not have to execute
it. However, it has to clear the interrupt or, upon returning from the
interrupt handler, the system will immediately be interrupted by the same
interrupt.

We have the following sources of external events:

- battery insertion / battery voltage rises above Vth(batok)
- USB insertion (giving us 100mA)
- adapter insertion (giving us 1A)
- USB host signals availability of 500mA
- 1Hz tick

USB signaling is already handled by an interrupt handler, so we just use
what's there. USB insertion and the 1Hz tick cause PMU interrupts, so we
need to enable the interrupt path from the PMU. Adapter insertion is
handled as part of USB insertion.

We don't wake up from IDLE on battery insertion or when the battery
voltage rises above the threshold. Instead, we just poll for it on each
1Hz tick.

Signed-off-by: Werner Almesberger <werner at openmoko.org>

Index: u-boot/board/neo1973/gta02/gta02.c
===================================================================
--- u-boot.orig/board/neo1973/gta02/gta02.c	2008-07-14 20:33:54.000000000 -0300
+++ u-boot/board/neo1973/gta02/gta02.c	2008-07-14 20:45:54.000000000 -0300
@@ -34,6 +34,7 @@
 #include <s3c2440.h>
 #include <i2c.h>
 #include <bootmenu.h>
+#include <asm/atomic.h>
 
 #include "../common/neo1973.h"
 #include "../common/jbt6k74.h"
@@ -316,6 +317,56 @@
 		pcf50633_usb_maxcurrent(1000);
 }
 
+static int have_int(uint8_t mask1, uint8_t mask2);
+
+static void clear_pmu_int(void)
+{
+	S3C24X0_INTERRUPT * const intr = S3C24X0_GetBase_INTERRUPT();
+	S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
+
+	/* read the PMU's interrupt register and store what we found for later
+	   use */
+	have_int(0, 0);
+
+	/* clear EINT9/GPG1 in the MCU's interrupt path */
+	gpio->EINTPEND = 1 << 9;
+	intr->SRCPND = BIT_EINT8_23;
+	intr->INTPND = BIT_EINT8_23;
+}
+
+static void cpu_idle(void)
+{
+	S3C24X0_INTERRUPT * const intr = S3C24X0_GetBase_INTERRUPT();
+	S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
+	S3C24X0_CLOCK_POWER * const clk = S3C24X0_GetBase_CLOCK_POWER();
+	unsigned long flags;
+
+	/*
+	 * We don't want to execute interrupts throughout all this, since
+	 * u-boot's interrupt handling code isn't modular, and getting a "real"
+	 * interrupt without clearing it in the interrupt handler would cause
+	 * us to loop permanently.
+	 */
+	local_irq_save(flags);
+
+	/* enable PMU interrupts */
+	intr->INTMSK &= ~BIT_EINT8_23;
+	gpio->EINTMASK &= ~(1 << 9);
+
+	/* go idle */
+	clk->CLKCON |= 1 << 2;
+
+	 /* disable PMU interrupts */
+	intr->INTMSK |= BIT_EINT8_23;
+	gpio->EINTMASK |= 1 << 9;
+
+	/* collect PMU interrupts and clear them */
+	clear_pmu_int();
+
+	/* we're safe now */
+	local_irq_restore(flags);
+}
+
 static void wait_for_power(void)
 {
 	int seconds = 0;
@@ -337,6 +388,8 @@
 		if (pcf50633_usb_last_maxcurrent >= 500)
 			break;
 
+		cpu_idle();
+
 		if (neo1973_new_second())
 			seconds++;
 




More information about the openmoko-kernel mailing list