diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 69b36e1..18c21fa 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -1,7 +1,7 @@
 /*
  * OMAP powerdomain control
  *
- * Copyright (C) 2007-2008, 2011 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008, 2011-2012 Texas Instruments, Inc.
  * Copyright (C) 2007-2011 Nokia Corporation
  *
  * Written by Paul Walmsley
@@ -128,14 +128,14 @@ static void _update_logic_membank_counters(struct powerdomain *pwrdm)
 
 	prev_logic_pwrst = pwrdm_read_prev_logic_pwrst(pwrdm);
 	if ((pwrdm->pwrsts_logic_ret == PWRSTS_OFF_RET) &&
-	    (prev_logic_pwrst == PWRDM_POWER_OFF))
+	    (prev_logic_pwrst == PWRDM_LOGIC_MEM_PWRST_OFF))
 		pwrdm->ret_logic_off_counter++;
 
 	for (i = 0; i < pwrdm->banks; i++) {
 		prev_mem_pwrst = pwrdm_read_prev_mem_pwrst(pwrdm, i);
 
 		if ((pwrdm->pwrsts_mem_ret[i] == PWRSTS_OFF_RET) &&
-		    (prev_mem_pwrst == PWRDM_POWER_OFF))
+		    (prev_mem_pwrst == PWRDM_LOGIC_MEM_PWRST_OFF))
 			pwrdm->ret_mem_off_counter[i]++;
 	}
 }
@@ -199,6 +199,201 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
 	return 0;
 }
 
+/**
+ * Search down then up for a valid state from a list of allowed states.
+ * Used by states conversion functions (_pwrdm_fpwrst_to_*) to look for
+ * allowed power and logic states for a powerdomain.
+ *
+ * @pwrsts: list of allowed states, defined as a bitmask
+ * @pwrst: initial state to be used as a starting point
+ * @min: minimum (i.e. lowest consumption) allowed state
+ * @max: maximum (i.e. highest consumption) allowed state
+ *
+ * Returns the matching allowed state.
+ */
+static inline int _match_pwrst(u32 pwrsts, int pwrst, int min, int max)
+{
+	int found = 1, new_pwrst = pwrst;
+
+	/*
+	 * If the power domain does not allow any state programmation
+	 * return the max state which is always allowed
+	 */
+	if (!pwrsts)
+		return max;
+
+	/*
+	 * Search lower: if the requested state is not supported
+	 * try the lower states, stopping at the minimum allowed
+	 * state
+	 */
+	while (!(pwrsts & (1 << new_pwrst))) {
+		if (new_pwrst <= min) {
+			found = 0;
+			break;
+		}
+		new_pwrst--;
+	}
+
+	/*
+	 * Search higher: if no lower state found fallback to the higher
+	 * states, stopping at the maximum allowed state
+	 */
+	if (!found) {
+		new_pwrst = pwrst;
+		while (!(pwrsts & (1 << new_pwrst))) {
+			if (new_pwrst >= max) {
+				new_pwrst = max;
+				break;
+			}
+			new_pwrst++;
+		}
+	}
+
+	return new_pwrst;
+}
+
+/**
+ * _pwrdm_fpwrst_to_pwrst - Convert functional (i.e. logical) to
+ * internal (i.e. registers) values for the power domains states.
+ * @struct powerdomain * to convert the values for
+ * @fpwrst: functional power state
+ *
+ * Returns the internal power state value for the power domain, or
+ * -EINVAL in case of invalid parameters passed in.
+ */
+static int _pwrdm_fpwrst_to_pwrst(struct powerdomain *pwrdm, u8 fpwrst)
+{
+	int ret;
+
+	if (!pwrdm) {
+		pr_err_ratelimited("%s: NULL pwrdm\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (fpwrst) {
+	case PWRDM_FUNC_PWRST_ON:
+		ret = PWRDM_POWER_ON;
+		break;
+	case PWRDM_FUNC_PWRST_INACTIVE:
+		ret = PWRDM_POWER_INACTIVE;
+		break;
+	case PWRDM_FUNC_PWRST_CSWR:
+	case PWRDM_FUNC_PWRST_OSWR:
+		ret = PWRDM_POWER_RET;
+		break;
+	case PWRDM_FUNC_PWRST_OFF:
+		ret = PWRDM_POWER_OFF;
+		break;
+	default:
+		pr_err_ratelimited("%s: powerdomain %s: bad fpwrst %0x\n",
+				   __func__, pwrdm->name, fpwrst);
+		return -EINVAL;
+	}
+
+	ret = _match_pwrst(pwrdm->pwrsts, ret,
+			   PWRDM_POWER_OFF,
+			   PWRDM_POWER_ON);
+
+	pr_debug("powerdomain %s: convert fpwrst %0x to pwrst %0x\n",
+		 pwrdm->name, fpwrst, ret);
+
+	return ret;
+}
+
+/**
+ * _pwrdm_fpwrst_to_logic_pwrst - Convert functional (i.e. logical) to
+ * internal (i.e. registers) values for the power domains logic states.
+ * @struct powerdomain * to convert the values for
+ * @pwrst: functional power state
+ *
+ * Returns the internal logic state value for the power domain, or
+ * -EINVAL in case of invalid parameters passed in.
+ */
+static int _pwrdm_fpwrst_to_logic_pwrst(struct powerdomain *pwrdm, u8 fpwrst)
+{
+	int ret;
+
+	if (!pwrdm) {
+		pr_err_ratelimited("%s: NULL pwrdm\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (fpwrst) {
+	case PWRDM_FUNC_PWRST_ON:
+	case PWRDM_FUNC_PWRST_INACTIVE:
+	case PWRDM_FUNC_PWRST_CSWR:
+		ret = PWRDM_LOGIC_MEM_PWRST_RET;
+		break;
+	case PWRDM_FUNC_PWRST_OSWR:
+	case PWRDM_FUNC_PWRST_OFF:
+		ret = PWRDM_LOGIC_MEM_PWRST_OFF;
+		break;
+	default:
+		pr_err_ratelimited("%s: powerdomain %s: bad fpwrst %0x\n",
+				   __func__, pwrdm->name, fpwrst);
+		return -EINVAL;
+	}
+
+	ret = _match_pwrst(pwrdm->pwrsts_logic_ret, ret,
+			   PWRDM_LOGIC_MEM_PWRST_OFF,
+			   PWRDM_LOGIC_MEM_PWRST_RET);
+
+	pr_debug("powerdomain %s: convert fpwrst %0x to logic %0x pwrst\n",
+		 pwrdm->name, fpwrst, ret);
+
+	return ret;
+}
+
+/**
+ * _pwrdm_pwrst_to_fpwrst - Convert internal (i.e. registers) to
+ * functional (i.e. logical) values for the power domains states.
+ * @struct powerdomain * to convert the values for
+ * @pwrst: internal power state
+ *
+ * Returns the functional power state value for the power domain, or
+ * -EINVAL in case of invalid parameters passed in.
+ */
+static int _pwrdm_pwrst_to_fpwrst(struct powerdomain *pwrdm, u8 pwrst, u8 logic)
+{
+	int ret;
+
+	if (!pwrdm) {
+		pr_err_ratelimited("%s: NULL pwrdm\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (pwrst) {
+	case PWRDM_POWER_ON:
+		ret = PWRDM_FUNC_PWRST_ON;
+		break;
+	case PWRDM_POWER_INACTIVE:
+		ret = PWRDM_FUNC_PWRST_INACTIVE;
+		break;
+	case PWRDM_POWER_RET:
+		logic = _match_pwrst(pwrdm->pwrsts_logic_ret, logic,
+				     PWRDM_LOGIC_MEM_PWRST_OFF,
+				     PWRDM_LOGIC_MEM_PWRST_RET);
+
+		if (logic == PWRDM_LOGIC_MEM_PWRST_OFF)
+			ret = PWRDM_FUNC_PWRST_OSWR;
+		else
+			ret = PWRDM_FUNC_PWRST_CSWR;
+		break;
+	case PWRDM_POWER_OFF:
+		ret = PWRDM_FUNC_PWRST_OFF;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	pr_debug("powerdomain: convert pwrst (%0x,%0x) to fpwrst %0x\n",
+		 pwrst, logic, ret);
+
+	return ret;
+}
+
+
 /* Public functions */
 
 /**
@@ -464,6 +659,111 @@ int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm)
 	return pwrdm->banks;
 }
 
+/* Types of sleep_switch used in pwrdm_set_fpwrst */
+#define FORCEWAKEUP_SWITCH	0
+#define LOWPOWERSTATE_SWITCH	1
+
+/**
+ * pwrdm_set_fpwrst - program next powerdomain functional power state
+ * @pwrdm: struct powerdomain * to set
+ * @fpwrst: power domain functional state, one of the PWRDM_FUNC_* macros
+ *
+ * This programs the pwrdm next functional state, sets the dependencies
+ * and waits for the state to be applied.
+ */
+int pwrdm_set_fpwrst(struct powerdomain *pwrdm, enum pwrdm_func_state fpwrst)
+{
+	u8 curr_pwrst, next_fpwrst;
+	int pwrst = _pwrdm_fpwrst_to_pwrst(pwrdm, fpwrst);
+	int logic = _pwrdm_fpwrst_to_logic_pwrst(pwrdm, fpwrst);
+	int sleep_switch = -1, ret = 0, hwsup = 0;
+
+	if (!pwrdm || IS_ERR(pwrdm) || (pwrst < 0) || (logic < 0)) {
+		pr_debug("%s: invalid params: pwrdm=%p, fpwrst=%0x\n",
+			 __func__, pwrdm, fpwrst);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: set fpwrst %0x to pwrdm %s\n",
+		 __func__, fpwrst, pwrdm->name);
+
+	next_fpwrst = pwrdm_read_next_fpwrst(pwrdm);
+	if (next_fpwrst == fpwrst)
+		return ret;
+
+	curr_pwrst = pwrdm_read_pwrst(pwrdm);
+	if (curr_pwrst < PWRDM_POWER_ON) {
+		if ((curr_pwrst > pwrst) &&
+			(pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) {
+			sleep_switch = LOWPOWERSTATE_SWITCH;
+		} else {
+			hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]);
+			clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
+			sleep_switch = FORCEWAKEUP_SWITCH;
+		}
+	}
+
+	if (logic != pwrdm_read_logic_retst(pwrdm))
+		pwrdm_set_logic_retst(pwrdm, logic);
+
+	ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
+	if (ret)
+		pr_err("%s: unable to set power state of powerdomain: %s\n",
+		       __func__, pwrdm->name);
+
+	switch (sleep_switch) {
+	case FORCEWAKEUP_SWITCH:
+		if (hwsup)
+			clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
+		else
+			clkdm_sleep(pwrdm->pwrdm_clkdms[0]);
+		break;
+	case LOWPOWERSTATE_SWITCH:
+		pwrdm_set_lowpwrstchange(pwrdm);
+		pwrdm_wait_transition(pwrdm);
+		pwrdm_state_switch(pwrdm);
+		break;
+	}
+
+	return ret;
+}
+
+/**
+ * pwrdm_set_next_fpwrst - set next powerdomain functional power state
+ * @pwrdm: struct powerdomain * to set
+ * @fpwrst: power domain functional state, one of the PWRDM_FUNC_* macros
+ *
+ * This programs the pwrdm next functional state
+ */
+int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm,
+			  enum pwrdm_func_state fpwrst)
+{
+	int pwrst = _pwrdm_fpwrst_to_pwrst(pwrdm, fpwrst);
+	int logic = _pwrdm_fpwrst_to_logic_pwrst(pwrdm, fpwrst);
+	int ret = 0;
+
+	if (!pwrdm || IS_ERR(pwrdm) || (pwrst < 0) || (logic < 0)) {
+		pr_debug("%s: invalid params: pwrdm=%p, fpwrst=%0x\n",
+			 __func__, pwrdm, fpwrst);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: set fpwrst %0x to pwrdm %s\n",
+		 __func__, fpwrst, pwrdm->name);
+
+	ret = pwrdm_set_logic_retst(pwrdm, logic);
+	if (ret)
+		pr_err("%s: unable to set logic state %0x of powerdomain: %s\n",
+		       __func__, logic, pwrdm->name);
+
+	ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
+	if (ret)
+		pr_err("%s: unable to set power state %0x of powerdomain: %s\n",
+		       __func__, pwrst, pwrdm->name);
+
+	return ret;
+};
+
 /**
  * pwrdm_set_next_pwrst - set next powerdomain power state
  * @pwrdm: struct powerdomain * to set
@@ -482,6 +782,13 @@ int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
 	if (!pwrdm)
 		return -EINVAL;
 
+	/*
+	 * Do nothing in case the power domain does not have any
+	 * valid state, e.g. DPLL domains.
+	 */
+	if (!pwrdm->pwrsts)
+		return 0;
+
 	if (!(pwrdm->pwrsts & (1 << pwrst)))
 		return -EINVAL;
 
@@ -521,6 +828,22 @@ int pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
 }
 
 /**
+ * pwrdm_read_next_fpwrst - get next powerdomain functional power state
+ * @pwrdm: struct powerdomain * to get power state
+ *
+ * Return the powerdomain @pwrdm's next functional power state.
+ * Returns -EINVAL if the powerdomain pointer is null or returns
+ * the next power state upon success.
+ */
+int pwrdm_read_next_fpwrst(struct powerdomain *pwrdm)
+{
+	int next_pwrst = pwrdm_read_next_pwrst(pwrdm);
+	int next_logic = pwrdm_read_logic_retst(pwrdm);
+
+	return _pwrdm_pwrst_to_fpwrst(pwrdm, next_pwrst, next_logic);
+}
+
+/**
  * pwrdm_read_pwrst - get current powerdomain power state
  * @pwrdm: struct powerdomain * to get power state
  *
@@ -546,6 +869,22 @@ int pwrdm_read_pwrst(struct powerdomain *pwrdm)
 }
 
 /**
+ * pwrdm_read_fpwrst - get current powerdomain functional power state
+ * @pwrdm: struct powerdomain * to get power state
+ *
+ * Return the powerdomain @pwrdm's current functional power state.
+ * Returns -EINVAL if the powerdomain pointer is null or returns
+ * the current power state upon success.
+ */
+int pwrdm_read_fpwrst(struct powerdomain *pwrdm)
+{
+	int pwrst = pwrdm_read_pwrst(pwrdm);
+	int logic = pwrdm_read_logic_pwrst(pwrdm);
+
+	return _pwrdm_pwrst_to_fpwrst(pwrdm, pwrst, logic);
+}
+
+/**
  * pwrdm_read_prev_pwrst - get previous powerdomain power state
  * @pwrdm: struct powerdomain * to get previous power state
  *
@@ -567,9 +906,25 @@ int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
 }
 
 /**
+ * pwrdm_read_prev_fpwrst - get previous powerdomain functional power state
+ * @pwrdm: struct powerdomain * to get previous power state
+ *
+ * Return the powerdomain @pwrdm's previous functional power state.
+ * Returns -EINVAL if the powerdomain pointer is null or returns the
+ * previous power state upon success.
+ */
+int pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm)
+{
+	int prev_pwrst = pwrdm_read_prev_pwrst(pwrdm);
+	int prev_logic = pwrdm_read_prev_logic_pwrst(pwrdm);
+
+	return _pwrdm_pwrst_to_fpwrst(pwrdm, prev_pwrst, prev_logic);
+}
+
+/**
  * pwrdm_set_logic_retst - set powerdomain logic power state upon retention
  * @pwrdm: struct powerdomain * to set
- * @pwrst: one of the PWRDM_POWER_* macros
+ * @pwrst: one of the PWRDM_LOGIC_MEM_PWRST_* macros
  *
  * Set the next power state @pwrst that the logic portion of the
  * powerdomain @pwrdm will enter when the powerdomain enters retention.
@@ -584,6 +939,13 @@ int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
 	if (!pwrdm)
 		return -EINVAL;
 
+	/*
+	 * Do nothing in case the power domain does not have any
+	 * valid state, e.g. DPLL domains.
+	 */
+	if (!pwrdm->pwrsts_logic_ret)
+		return 0;
+
 	if (!(pwrdm->pwrsts_logic_ret & (1 << pwrst)))
 		return -EINVAL;
 
@@ -600,7 +962,7 @@ int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
  * pwrdm_set_mem_onst - set memory power state while powerdomain ON
  * @pwrdm: struct powerdomain * to set
  * @bank: memory bank number to set (0-3)
- * @pwrst: one of the PWRDM_POWER_* macros
+ * @pwrst: one of the PWRDM_LOGIC_MEM_PWRST_* macros
  *
  * Set the next power state @pwrst that memory bank @bank of the
  * powerdomain @pwrdm will enter when the powerdomain enters the ON
@@ -637,7 +999,7 @@ int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
  * pwrdm_set_mem_retst - set memory power state while powerdomain in RET
  * @pwrdm: struct powerdomain * to set
  * @bank: memory bank number to set (0-3)
- * @pwrst: one of the PWRDM_POWER_* macros
+ * @pwrst: one of the PWRDM_LOGIC_MEM_PWRST_* macros
  *
  * Set the next power state @pwrst that memory bank @bank of the
  * powerdomain @pwrdm will enter when the powerdomain enters the
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
index baee906..aa5de4f 100644
--- a/arch/arm/mach-omap2/powerdomain.h
+++ b/arch/arm/mach-omap2/powerdomain.h
@@ -1,7 +1,7 @@
 /*
  * OMAP2/3/4 powerdomain control
  *
- * Copyright (C) 2007-2008, 2010 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008, 2010, 2012 Texas Instruments, Inc.
  * Copyright (C) 2007-2011 Nokia Corporation
  *
  * Paul Walmsley
@@ -9,9 +9,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * XXX This should be moved to the mach-omap2/ directory at the earliest
- * opportunity.
  */
 
 #ifndef __ARCH_ARM_MACH_OMAP2_POWERDOMAIN_H
@@ -26,6 +23,26 @@
 
 #include "voltage.h"
 
+/* Powerdomain functional power states, used by the external API functions */
+enum pwrdm_func_state {
+	PWRDM_FUNC_PWRST_OFF		= 0x0,
+	PWRDM_FUNC_PWRST_OSWR,
+	PWRDM_FUNC_PWRST_CSWR,
+	PWRDM_FUNC_PWRST_INACTIVE,
+	PWRDM_FUNC_PWRST_ON,
+	PWRDM_MAX_FUNC_PWRSTS		/* Last value, used as the max value */
+};
+
+/*
+ * Powerdomains logic and memory functional power states,
+ * used by the external API functions
+ */
+enum pwrdm_logic_mem_state {
+	PWRDM_LOGIC_MEM_PWRST_OFF	= 0x0,
+	PWRDM_LOGIC_MEM_PWRST_RET,
+	PWRDM_MAX_LOGIC_MEM_PWRST	/* Last value, used as the max value */
+};
+
 /* Powerdomain basic power states */
 #define PWRDM_POWER_OFF		0x0
 #define PWRDM_POWER_RET		0x1
@@ -206,6 +223,13 @@ struct voltagedomain *pwrdm_get_voltdm(struct powerdomain *pwrdm);
 
 int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm);
 
+int pwrdm_set_fpwrst(struct powerdomain *pwrdm, enum pwrdm_func_state fpwrst);
+int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm,
+			  enum pwrdm_func_state fpwrst);
+int pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm);
+int pwrdm_read_fpwrst(struct powerdomain *pwrdm);
+int pwrdm_read_next_fpwrst(struct powerdomain *pwrdm);
+
 int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst);
 int pwrdm_read_next_pwrst(struct powerdomain *pwrdm);
 int pwrdm_read_pwrst(struct powerdomain *pwrdm);
