From 4588e5e2a5f14bc63702ff19dfef8693568aa198 Mon Sep 17 00:00:00 2001
From: =?utf8?q?=E9=BB=84=E6=B6=9B?= <huangtao@rock-chips.com>
Date: Thu, 7 Apr 2011 12:18:26 +0800
Subject: [PATCH] rk29sdk: better support power on/off

---
 arch/arm/mach-rk29/Makefile              |  4 +-
 arch/arm/mach-rk29/board-rk29-ddr3sdk.c  | 13 +----
 arch/arm/mach-rk29/board-rk29sdk-power.c | 67 ++++++++++++++++++++++++
 arch/arm/mach-rk29/board-rk29sdk.c       | 13 +----
 arch/arm/mach-rk29/include/mach/board.h  |  1 +
 5 files changed, 72 insertions(+), 26 deletions(-)
 create mode 100644 arch/arm/mach-rk29/board-rk29sdk-power.c

diff --git a/arch/arm/mach-rk29/Makefile b/arch/arm/mach-rk29/Makefile
index 398be7942d47..e514af5e2323 100644
--- a/arch/arm/mach-rk29/Makefile
+++ b/arch/arm/mach-rk29/Makefile
@@ -8,8 +8,8 @@ obj-$(CONFIG_USB_GADGET) += usb_detect.o
 obj-$(CONFIG_PM) += pm.o
 obj-$(CONFIG_CPU_FREQ) += cpufreq.o
 obj-$(CONFIG_RK29_VPU) += vpu.o vpu_mem.o
-obj-$(CONFIG_MACH_RK29SDK) += board-rk29sdk.o board-rk29sdk-key.o board-rk29sdk-rfkill.o
-obj-$(CONFIG_MACH_RK29SDK_DDR3) += board-rk29-ddr3sdk.o board-rk29sdk-key.o board-rk29sdk-rfkill.o
+obj-$(CONFIG_MACH_RK29SDK) += board-rk29sdk.o board-rk29sdk-key.o board-rk29sdk-rfkill.o board-rk29sdk-power.o
+obj-$(CONFIG_MACH_RK29SDK_DDR3) += board-rk29-ddr3sdk.o board-rk29sdk-key.o board-rk29sdk-rfkill.o board-rk29sdk-power.o
 obj-$(CONFIG_MACH_RK29WINACCORD) += board-rk29-winaccord.o board-rk29sdk-key.o
 obj-$(CONFIG_MACH_RK29_AIGO) += board-rk29-aigo.o board-rk29aigo-key.o board-rk29sdk-rfkill.o
 obj-$(CONFIG_MACH_RK29_MALATA) += board-malata.o board-rk29malata-key.o board-rk29sdk-rfkill.o
diff --git a/arch/arm/mach-rk29/board-rk29-ddr3sdk.c b/arch/arm/mach-rk29/board-rk29-ddr3sdk.c
index e22a6befc51a..72a5f4b868ea 100755
--- a/arch/arm/mach-rk29/board-rk29-ddr3sdk.c
+++ b/arch/arm/mach-rk29/board-rk29-ddr3sdk.c
@@ -1874,22 +1874,11 @@ static void __init machine_rk29_init_irq(void)
 	rk29_gpio_init();
 }
 
-#define POWER_ON_PIN RK29_PIN4_PA4
-static void rk29_pm_power_off(void)
-{
-	printk(KERN_ERR "rk29_pm_power_off start...\n");
-	gpio_direction_output(POWER_ON_PIN, GPIO_LOW);
-	while (1);
-}
-
 static void __init machine_rk29_board_init(void)
 {
 	rk29_board_iomux_init();
 
-	gpio_request(POWER_ON_PIN,"poweronpin");
-	gpio_set_value(POWER_ON_PIN, GPIO_HIGH);
-	gpio_direction_output(POWER_ON_PIN, GPIO_HIGH);
-	pm_power_off = rk29_pm_power_off;
+	board_power_init();
 
 		platform_add_devices(devices, ARRAY_SIZE(devices));
 #ifdef CONFIG_I2C0_RK29
diff --git a/arch/arm/mach-rk29/board-rk29sdk-power.c b/arch/arm/mach-rk29/board-rk29sdk-power.c
new file mode 100644
index 000000000000..e63b0d99d73c
--- /dev/null
+++ b/arch/arm/mach-rk29/board-rk29sdk-power.c
@@ -0,0 +1,67 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/pm.h>
+
+#include <mach/rk29_iomap.h>
+#include <mach/gpio.h>
+#include <mach/cru.h>
+
+#define POWER_ON_PIN	RK29_PIN4_PA4
+#define PLAY_ON_PIN	RK29_PIN6_PA7
+
+static void rk29_pm_power_off(void)
+{
+	int count = 0;
+
+	local_irq_disable();
+	local_fiq_disable();
+
+	printk(KERN_ERR "rk29_pm_power_off start...\n");
+
+	/* arm enter slow mode */
+	cru_writel((cru_readl(CRU_MODE_CON) & ~CRU_CPU_MODE_MASK) | CRU_CPU_MODE_SLOW, CRU_MODE_CON);
+	LOOP(LOOPS_PER_USEC);
+
+	while (1) {
+		/* shut down the power by GPIO. */
+		if (gpio_get_value(POWER_ON_PIN) == GPIO_HIGH) {
+			printk("POWER_ON_PIN is high\n");
+			gpio_set_value(POWER_ON_PIN, GPIO_LOW);
+		}
+
+		LOOP(5 * LOOPS_PER_MSEC);
+
+		/* only normal power off can restart system safely */
+		if (system_state != SYSTEM_POWER_OFF)
+			continue;
+
+		if (gpio_get_value(PLAY_ON_PIN) != GPIO_HIGH) {
+			if (!count)
+				printk("PLAY_ON_PIN is low\n");
+			if (50 == count) /* break if keep low about 250ms */
+				break;
+			count++;
+		} else {
+			count = 0;
+		}
+	}
+
+	printk("system reboot\n");
+	gpio_set_value(POWER_ON_PIN, GPIO_HIGH);
+	system_state = SYSTEM_RESTART;
+	arm_pm_restart(0, NULL);
+
+	while (1);
+}
+
+int __init board_power_init(void)
+{
+	gpio_request(POWER_ON_PIN, "poweronpin");
+	gpio_set_value(POWER_ON_PIN, GPIO_HIGH);
+	gpio_direction_output(POWER_ON_PIN, GPIO_HIGH);
+	pm_power_off = rk29_pm_power_off;
+
+	return 0;
+}
+
diff --git a/arch/arm/mach-rk29/board-rk29sdk.c b/arch/arm/mach-rk29/board-rk29sdk.c
index 2bbcaf239fc3..ba2f881dab3f 100755
--- a/arch/arm/mach-rk29/board-rk29sdk.c
+++ b/arch/arm/mach-rk29/board-rk29sdk.c
@@ -1896,22 +1896,11 @@ static void __init machine_rk29_init_irq(void)
 	rk29_gpio_init();
 }
 
-#define POWER_ON_PIN RK29_PIN4_PA4
-static void rk29_pm_power_off(void)
-{
-	printk(KERN_ERR "rk29_pm_power_off start...\n");
-	gpio_direction_output(POWER_ON_PIN, GPIO_LOW);
-	while (1);
-}
-
 static void __init machine_rk29_board_init(void)
 {
 	rk29_board_iomux_init();
 
-	gpio_request(POWER_ON_PIN,"poweronpin");
-	gpio_set_value(POWER_ON_PIN, GPIO_HIGH);
-	gpio_direction_output(POWER_ON_PIN, GPIO_HIGH);
-	pm_power_off = rk29_pm_power_off;
+	board_power_init();
 
 		platform_add_devices(devices, ARRAY_SIZE(devices));
 #ifdef CONFIG_I2C0_RK29
diff --git a/arch/arm/mach-rk29/include/mach/board.h b/arch/arm/mach-rk29/include/mach/board.h
index 8a111c602baa..e16ef7a2bd02 100755
--- a/arch/arm/mach-rk29/include/mach/board.h
+++ b/arch/arm/mach-rk29/include/mach/board.h
@@ -234,6 +234,7 @@ struct tca6424_platform_data {
 void __init rk29_setup_early_printk(void);
 void __init rk29_map_common_io(void);
 void __init rk29_clock_init(void);
+void __init board_power_init(void);
 
 #define BOOT_MODE_NORMAL		0
 #define BOOT_MODE_FACTORY2		1
-- 
2.34.1