diff mbox

OMAP2plus: PM: omap_device: API for set/get MIDLE mode

Message ID 1285990750-10117-1-git-send-email-manjugk@ti.com (mailing list archive)
State New, archived
Delegated to: Paul Walmsley
Headers show

Commit Message

manjugk manjugk Oct. 2, 2010, 3:39 a.m. UTC
None
diff mbox

Patch

diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 955861a..4f638fe 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -250,6 +250,35 @@  static int _set_master_standbymode(struct omap_hwmod *oh, u8 standbymode,
 }
 
 /**
+ * _get_master_standbymode: get the OCP_SYSCONFIG MIDLEMODE field in @midlemode
+ * @oh: struct omap_hwmod *
+ * @standbymode: pointer to get mstandby mode bits(shifted to bit 0)
+ *
+ * Get the master standby mode bits in @midlemode for the @oh hwmod.
+ * Does not fetch the data from the hardware instead returns value
+ * from sysc_cache. Returns -EINVAL upon error or 0 upon success.
+ */
+static int _get_master_standbymode(struct omap_hwmod *oh, u32 *midlemode)
+{
+	u32 mstandby_mask;
+	u8 mstandby_shift;
+
+	if (!oh->class->sysc ||
+	    !(oh->class->sysc->sysc_flags & SYSC_HAS_MIDLEMODE))
+		return -EINVAL;
+
+	if (!oh->class->sysc->sysc_fields) {
+		WARN(1, "omap_hwmod: %s: offset struct for sysconfig not"
+					" provided in class\n", oh->name);
+		return -EINVAL;
+	}
+
+	*midlemode = ((oh->_sysc_cache) & mstandby_mask) >> mstandby_shift;
+
+	return 0;
+}
+
+/**
  * _set_slave_idlemode: set the OCP_SYSCONFIG SIDLEMODE field in @v
  * @oh: struct omap_hwmod *
  * @idlemode: SIDLEMODE field bits
@@ -1421,6 +1450,60 @@  int omap_hwmod_set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode)
 }
 
 /**
+ * omap_hwmod_set_master_idlemode - set the hwmod's OCP master idlemode
+ * @oh: struct omap_hwmod *
+ * @idlemode: SIDLEMODE field bits (shifted to bit 0)
+ *
+ * Sets the IP block's OCP master idlemode in hardware, and updates our
+ * local copy.  Intended to be used by drivers that have some erratum
+ * that requires direct manipulation of the MIDLEMODE bits.  Returns
+ * -EINVAL if @oh is null, or passes along the return value from
+ * _set_master_standbymode().
+ *
+ * Any users of this function should be scrutinized carefully.
+ */
+int omap_hwmod_set_master_idlemode(struct omap_hwmod *oh, u8 midlemode)
+{
+	u32 v;
+	int retval = 0;
+
+	if (!oh)
+		return -EINVAL;
+
+	v = oh->_sysc_cache;
+
+	retval = _set_master_standbymode(oh, midlemode, &v);
+	if (!retval)
+		_write_sysconfig(v, oh);
+
+	return retval;
+}
+
+/**
+ * omap_hwmod_get_master_idlemode - set the hwmod's OCP master idlemode
+ * @oh: struct omap_hwmod *
+ * @idlemode: pointer to get SIDLEMODE field bits (shifted to bit 0)
+ *
+ * Gets the IP block's OCP master idlemode from our local copy. Intended
+ * to be used by drivers that have some erratum that requires direct
+ * manipulation of the MIDLEMODE bits. Returns -EINVAL if @oh is null,
+ * or passes along the return value from _get_master_standbymode().
+ *
+ * Any users of this function should be scrutinized carefully.
+ */
+int omap_hwmod_get_master_idlemode(struct omap_hwmod *oh, u32 *idlemode)
+{
+	int retval = 0;
+
+	if (!oh)
+		return -EINVAL;
+
+	retval = _get_master_standbymode(oh, idlemode);
+
+	return retval;
+}
+
+/**
  * omap_hwmod_register - register a struct omap_hwmod
  * @oh: struct omap_hwmod *
  *
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index c1835af..13d5f0a 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -524,6 +524,9 @@  int omap_hwmod_disable_clocks(struct omap_hwmod *oh);
 
 int omap_hwmod_set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode);
 
+int omap_hwmod_set_master_idlemode(struct omap_hwmod *oh, u8 midlemode);
+int omap_hwmod_get_master_idlemode(struct omap_hwmod *oh, u32 *idlemode);
+
 int omap_hwmod_reset(struct omap_hwmod *oh);
 void omap_hwmod_ocp_barrier(struct omap_hwmod *oh);
 
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index abe933c..d782314 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -584,6 +584,42 @@  int omap_device_idle(struct platform_device *pdev)
 }
 
 /**
+ * omap_device_mstandby - set/get mstandby mode an omap_device
+ * @od: struct omap_device * to idle
+ * @midlemode: MIDLEMODE field bits (shifted to bit 0)
+ * @set_mstandby: flag for mstandby get/set
+ *
+ * Sets/Gets the IP block's OCP master standby in hardware. Intended
+ * to be used by drivers that have some erratum that requires direct
+ * manipulation of the MSTANDBYMODE bits. Returns -EINVAL if the
+ * omap_device is not currently enabled or passes along the return value
+ * of omap_hwmod_set_master_idlemode()/omap_hwmod_get_master_idlemode().
+ */
+int omap_device_mstandby(struct platform_device *pdev, u8 *midlemode,
+						bool set_mstandby)
+{
+	int ret, i;
+	struct omap_device *od;
+	struct omap_hwmod *oh;
+
+	od = _find_by_pdev(pdev);
+	if (od->_state != OMAP_DEVICE_STATE_ENABLED) {
+		WARN(1, "omap_device: %s.%d: %s() called from invalid state %d\n",
+		     od->pdev.name, od->pdev.id, __func__, od->_state);
+		return -EINVAL;
+	}
+
+	oh = *od->hwmods;
+	for (i = 0; i < od->hwmods_cnt; i++) {
+		if (set_mstandby)
+			ret = omap_hwmod_set_master_idlemode(oh, *midlemode);
+		else
+			ret = omap_hwmod_get_master_idlemode(oh, midlemode);
+	}
+	return ret;
+}
+
+/**
  * omap_device_shutdown - shut down an omap_device
  * @od: struct omap_device * to shut down
  *