Index: linux-2.6/include/linux/pm_domain.h
===================================================================
--- linux-2.6.orig/include/linux/pm_domain.h
+++ linux-2.6/include/linux/pm_domain.h
@@ -12,7 +12,7 @@
 #include <linux/device.h>
 
 struct dev_power_governor {
-	bool (*power_down_ok)(struct dev_power_domain *domain);
+	int (*choose_state)(struct dev_power_domain *domain);
 };
 
 struct generic_power_domain {
@@ -23,12 +23,14 @@ struct generic_power_domain {
 	struct list_head device_list;
 	struct mutex lock;
 	struct dev_power_governor *gov;
-	unsigned int in_progress;
+	int nr_states;
+	int current_state;
 	bool power_is_off;
+	unsigned int in_progress;
 	unsigned int device_count;
 	unsigned int suspended_count;
-	int (*power_off)(struct dev_power_domain *domain);
-	int (*power_on)(struct dev_power_domain *domain);
+	int (*set_state)(struct dev_power_domain *domain, int state);
+	bool (*power_off_state)(struct dev_power_domain *domain, int state);
 	int (*start_device)(struct device *dev);
 	int (*stop_device)(struct device *dev);
 };
@@ -48,7 +50,8 @@ extern int pm_genpd_add_subdomain(struct
 extern int pm_genpd_remove_subdomain(struct generic_power_domain *genpd,
 				     struct generic_power_domain *target);
 extern void pm_genpd_init(struct generic_power_domain *genpd,
-			  struct dev_power_governor *gov, bool is_off);
+			  struct dev_power_governor *gov, int nr_states,
+			  int cur_state);
 #else
 static inline int pm_genpd_add_device(struct generic_power_domain *genpd,
 				      struct device *dev)
@@ -71,7 +74,8 @@ static inline int pm_genpd_remove_subdom
 	return -ENOSYS;
 }
 static inline void pm_genpd_init(struct generic_power_domain *genpd,
-				 struct dev_power_governor *gov, bool is_off) {}
+				 struct dev_power_governor *gov,
+				 int nr_states, int cur_state) {}
 #endif
 
 #endif /* _LINUX_PM_DOMAIN_H */
Index: linux-2.6/drivers/base/power/domain.c
===================================================================
--- linux-2.6.orig/drivers/base/power/domain.c
+++ linux-2.6/drivers/base/power/domain.c
@@ -62,6 +62,7 @@ static int __pm_genpd_poweroff(struct ge
 	struct generic_power_domain *subdomain;
 	struct dev_list_entry *dle;
 	unsigned int not_suspended;
+	int new_state;
 	int ret;
 
 	if (genpd->power_is_off)
@@ -83,9 +84,23 @@ static int __pm_genpd_poweroff(struct ge
 			return ret;
 	}
 
-	if (genpd->gov && genpd->gov->power_down_ok) {
-		if (!genpd->gov->power_down_ok(&genpd->domain))
-			return -EAGAIN;
+	new_state = (genpd->gov && genpd->gov->choose_state) ?
+			genpd->gov->choose_state(&genpd->domain) : 1;
+	if (new_state < 0 || new_state >= genpd->nr_states)
+		return -EAGAIN;
+
+	if (new_state == genpd->current_state)
+		return 0;
+
+	if (genpd->power_off_state
+	    && !genpd->power_off_state(&genpd->domain, new_state)) {
+		if (genpd->set_state) {
+			ret = genpd->set_state(&genpd->domain, new_state);
+			if (ret)
+				return ret;
+		}
+		genpd->current_state = new_state;
+		return 0;
 	}
 
 	list_for_each_entry_reverse(dle, &genpd->device_list, node) {
@@ -105,9 +120,13 @@ static int __pm_genpd_poweroff(struct ge
 			goto err_dev;
 	}
 
-	if (genpd->power_off)
-		genpd->power_off(&genpd->domain);
+	if (genpd->set_state) {
+		ret = genpd->set_state(&genpd->domain, new_state);
+		if (ret)
+			goto err_dev;
+	}
 
+	genpd->current_state = new_state;
 	genpd->power_is_off = true;
 
 	return 0;
@@ -199,14 +218,17 @@ static int __pm_genpd_poweron(struct gen
 {
 	struct dev_list_entry *dle;
 
-	if (!genpd->power_is_off)
+	if (genpd->current_state == 0)
 		return 0;
 
-	if (genpd->power_on) {
-		int ret = genpd->power_on(&genpd->domain);
+	if (genpd->set_state) {
+		int ret = genpd->set_state(&genpd->domain, 0);
 		if (ret)
 			return ret;
 	}
+	genpd->current_state = 0;
+	if (!genpd->power_is_off)
+		return 0;
 
 	genpd->power_is_off = false;
 
@@ -363,8 +385,8 @@ static int pm_genpd_suspend_noirq(struct
 
 	mutex_lock(&genpd->lock);
 	if (++genpd->suspended_count == genpd->device_count) {
-		if (genpd->power_off)
-			genpd->power_off(&genpd->domain);
+		if (genpd->set_state)
+			genpd->set_state(&genpd->domain, genpd->nr_states - 1);
 	}
 	mutex_unlock(&genpd->lock);
 
@@ -395,8 +417,8 @@ static int pm_genpd_resume_noirq(struct
 
 	mutex_lock(&genpd->lock);
 	if (genpd->suspended_count == genpd->device_count) {
-		if (genpd->power_on) {
-			int ret = genpd->power_on(&genpd->domain);
+		if (genpd->set_state) {
+			int ret = genpd->set_state(&genpd->domain, 0);
 			if (ret) {
 				mutex_unlock(&genpd->lock);
 				return ret;
@@ -713,10 +735,12 @@ int pm_genpd_remove_subdomain(struct gen
  * pm_genpd_init - Initialize a generic I/O power domain object.
  * @genpd: Power domain object to initialize.
  * @gov: Power domain governor to associate with the domain (may be NULL).
- * @is_off: Initial value of the domain's power_is_off field.
+ * @nr_states: Number of power domain states (must be greater than 1).
+ * @cur_state: Initial state of the power domain.
  */
 void pm_genpd_init(struct generic_power_domain *genpd,
-		   struct dev_power_governor *gov, bool is_off)
+		   struct dev_power_governor *gov, int nr_states,
+		   int cur_state)
 {
 	if (IS_ERR_OR_NULL(genpd))
 		return;
@@ -727,8 +751,14 @@ void pm_genpd_init(struct generic_power_
 	INIT_LIST_HEAD(&genpd->subdomain_list);
 	mutex_init(&genpd->lock);
 	genpd->gov = gov;
+	genpd->nr_states = nr_states > 1 ? nr_states : 2;
+	if (cur_state < 0 || cur_state >= nr_states)
+		cur_state = 0;
+	genpd->current_state = cur_state;
+	genpd->power_is_off = genpd->power_off_state ?
+		genpd->power_off_state(&genpd->domain, cur_state) :
+			(cur_state > 0);
 	genpd->in_progress = 0;
-	genpd->power_is_off = is_off;
 	genpd->device_count = 0;
 	genpd->suspended_count = 0;
 	genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend;
Index: linux-2.6/arch/arm/mach-shmobile/pm-sh7372.c
===================================================================
--- linux-2.6.orig/arch/arm/mach-shmobile/pm-sh7372.c
+++ linux-2.6/arch/arm/mach-shmobile/pm-sh7372.c
@@ -70,15 +70,20 @@ static int pd_power_up(struct dev_power_
 	return 0;
 }
 
+static int pd_set_state(struct dev_power_domain *domain, int state)
+{
+	return state > 0 ? pd_power_down(domain) : pd_power_up(domain);
+}
+
 static void sh7372_init_domain(struct generic_power_domain *domain,
 			       struct sh7372_domain_data *pdata)
 {
-	pm_genpd_init(domain, NULL, false);
 	domain->domain.platform_data = pdata;
 	domain->stop_device = pm_runtime_clk_suspend;
 	domain->start_device = pm_runtime_clk_resume;
-	domain->power_off = pd_power_down;
-	domain->power_on = pd_power_up;
+	domain->set_state = pd_set_state;
+	domain->power_off_state = NULL;
+	pm_genpd_init(domain, NULL, 2, 0);
 }
 
 void sh7372_add_device_to_domain(struct generic_power_domain *domain,
