sh: Keep track of allowed sleep modes

Add code to keep track of supported sleep modes. This to
only export cpuidle modes that are backed by board support
code. Also, do not allow suspend-to-ram if sdram board code
is missing.

Signed-off-by: Magnus Damm <damm@opensource.se>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
diff --git a/arch/sh/include/asm/suspend.h b/arch/sh/include/asm/suspend.h
index 8e2c55d..8eddf23 100644
--- a/arch/sh/include/asm/suspend.h
+++ b/arch/sh/include/asm/suspend.h
@@ -61,6 +61,9 @@
 	struct sh_sleep_regs data;
 };
 
+/* a bitmap of supported sleep modes (SUSP_SH..) */
+extern unsigned long sh_mobile_sleep_supported;
+
 #endif
 
 /* flags passed to assembly suspend code */
diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c
index 1c504bd..83972aa 100644
--- a/arch/sh/kernel/cpu/shmobile/cpuidle.c
+++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c
@@ -87,25 +87,31 @@
 
 	dev->safe_state = state;
 
-	state = &dev->states[i++];
-	snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
-	strncpy(state->desc, "SuperH Sleep Mode [SF]", CPUIDLE_DESC_LEN);
-	state->exit_latency = 100;
-	state->target_residency = 1 * 2;
-	state->power_usage = 1;
-	state->flags = 0;
-	state->flags |= CPUIDLE_FLAG_TIME_VALID;
-	state->enter = cpuidle_sleep_enter;
+	if (sh_mobile_sleep_supported & SUSP_SH_SF) {
+		state = &dev->states[i++];
+		snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
+		strncpy(state->desc, "SuperH Sleep Mode [SF]",
+			CPUIDLE_DESC_LEN);
+		state->exit_latency = 100;
+		state->target_residency = 1 * 2;
+		state->power_usage = 1;
+		state->flags = 0;
+		state->flags |= CPUIDLE_FLAG_TIME_VALID;
+		state->enter = cpuidle_sleep_enter;
+	}
 
-	state = &dev->states[i++];
-	snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
-	strncpy(state->desc, "SuperH Mobile Standby Mode [SF]", CPUIDLE_DESC_LEN);
-	state->exit_latency = 2300;
-	state->target_residency = 1 * 2;
-	state->power_usage = 1;
-	state->flags = 0;
-	state->flags |= CPUIDLE_FLAG_TIME_VALID;
-	state->enter = cpuidle_sleep_enter;
+	if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) {
+		state = &dev->states[i++];
+		snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
+		strncpy(state->desc, "SuperH Mobile Standby Mode [SF]",
+			CPUIDLE_DESC_LEN);
+		state->exit_latency = 2300;
+		state->target_residency = 1 * 2;
+		state->power_usage = 1;
+		state->flags = 0;
+		state->flags |= CPUIDLE_FLAG_TIME_VALID;
+		state->enter = cpuidle_sleep_enter;
+	}
 
 	dev->state_count = i;
 
diff --git a/arch/sh/kernel/cpu/shmobile/pm.c b/arch/sh/kernel/cpu/shmobile/pm.c
index cb3d28f..a94dc48 100644
--- a/arch/sh/kernel/cpu/shmobile/pm.c
+++ b/arch/sh/kernel/cpu/shmobile/pm.c
@@ -67,6 +67,8 @@
 extern char sh_mobile_sleep_resume_start;
 extern char sh_mobile_sleep_resume_end;
 
+unsigned long sh_mobile_sleep_supported = SUSP_SH_SLEEP;
+
 void sh_mobile_register_self_refresh(unsigned long flags,
 				     void *pre_start, void *pre_end,
 				     void *post_start, void *post_end)
@@ -103,10 +105,15 @@
 	vp = onchip_mem + 0x600; /* located at interrupt vector */
 	n = &sh_mobile_sleep_resume_end - &sh_mobile_sleep_resume_start;
 	memcpy(vp, &sh_mobile_sleep_resume_start, n);
+
+	sh_mobile_sleep_supported |= flags;
 }
 
 static int sh_pm_enter(suspend_state_t state)
 {
+	if (!(sh_mobile_sleep_supported & SUSP_MODE_STANDBY_SF))
+		return -ENXIO;
+
 	local_irq_disable();
 	set_bl_bit();
 	sh_mobile_call_standby(SUSP_MODE_STANDBY_SF);