From e039614a0ce6df645f8fa4cbe32e4b21fe46a288 Mon Sep 17 00:00:00 2001
From: Dmitry Baryshkov <dbaryshkov@gmail.com>
Date: Sun, 20 Jan 2008 02:44:03 +0300
Subject: [PATCH 56/64] Support resetting by asserting GPIO pin

This adds support for resetting via assertion of GPIO pin.
This e.g. is used on Sharp Zaurus SL-6000.

Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
---
 arch/arm/mach-pxa/gpio.c          |   43 +++++++++++++++++++++++++++++++++++++
 arch/arm/mach-pxa/pm.c            |    4 +-
 include/asm-arm/arch-pxa/system.h |   10 ++++++++
 3 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-pxa/gpio.c b/arch/arm/mach-pxa/gpio.c
index 8638dd7..589da3b 100644
--- a/arch/arm/mach-pxa/gpio.c
+++ b/arch/arm/mach-pxa/gpio.c
@@ -19,6 +19,7 @@
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/arch/pxa-regs.h>
+#include <asm/arch/system.h>
 
 #include "generic.h"
 
@@ -194,4 +195,46 @@ void __init pxa_init_gpio(int gpio_nr)
 			pxa_gpio_chip[i/32].chip.ngpio = gpio_nr - i;
 		gpiochip_add(&pxa_gpio_chip[i/32].chip);
 	}
+
+	if (reset_gpio < gpio_nr)
+		init_reset_gpio();
+}
+
+int reset_gpio = -1;
+static int __init reset_gpio_setup(char *str)
+{
+	if (get_option(&str, &reset_gpio) != 1) {
+		printk(KERN_ERR "reset_gpio: bad value secified");
+		return 0;
+	}
+
+	return 1;
+}
+
+__setup("reset_gpio=", reset_gpio_setup);
+
+int init_reset_gpio(void)
+{
+	int rc = 0;
+	if (reset_gpio == -1)
+		goto out;
+
+	rc = gpio_request(reset_gpio, "reset generator");
+	if (rc) {
+		printk(KERN_ERR "Can't request reset_gpio\n");
+		goto out;
+	}
+
+	rc = gpio_direction_input(reset_gpio);
+	if (rc) {
+		printk(KERN_ERR "Can't configure reset_gpio for input\n");
+		gpio_free(reset_gpio);
+		goto out;
+	}
+
+out:
+	if (rc)
+		reset_gpio = -1;
+
+	return rc;
 }
diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c
index a941c71..64f37e5 100644
--- a/arch/arm/mach-pxa/pm.c
+++ b/arch/arm/mach-pxa/pm.c
@@ -40,8 +40,8 @@ int pxa_pm_enter(suspend_state_t state)
 
 	pxa_cpu_pm_fns->save(sleep_save);
 
-	/* Clear sleep reset status */
-	RCSR = RCSR_SMR;
+	/* Clear reset status */
+	RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR;
 
 	/* before sleeping, calculate and save a checksum */
 	for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++)
diff --git a/include/asm-arm/arch-pxa/system.h b/include/asm-arm/arch-pxa/system.h
index 1d56a3e..c075018 100644
--- a/include/asm-arm/arch-pxa/system.h
+++ b/include/asm-arm/arch-pxa/system.h
@@ -11,6 +11,7 @@
  */
 
 #include <asm/proc-fns.h>
+#include <asm/gpio.h>
 #include "hardware.h"
 #include "pxa-regs.h"
 
@@ -19,12 +20,21 @@ static inline void arch_idle(void)
 	cpu_do_idle();
 }
 
+extern int reset_gpio;
+
+int init_reset_gpio(void);
 
 static inline void arch_reset(char mode)
 {
+	RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR;
+
 	if (mode == 's') {
 		/* Jump into ROM at address 0 */
 		cpu_reset(0);
+	} else if (mode == 'g' && reset_gpio != -1) {
+		/* Use GPIO reset */
+		gpio_direction_output(reset_gpio, 0);
+		gpio_set_value(reset_gpio, 1);
 	} else {
 		/* Initialize the watchdog and let it fire */
 		OWER = OWER_WME;
-- 
1.5.3.8