aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/omap_hwmod.c
diff options
context:
space:
mode:
authorPaul Walmsley <paul@pwsan.com>2010-12-14 12:42:35 -0700
committerPaul Walmsley <paul@pwsan.com>2010-12-21 19:55:12 -0700
commitbd36179eec2827cd60b4a8c6e180cc030c74a4ec (patch)
tree2de71af03907f561fc2a845e7579446b33099de5 /arch/arm/mach-omap2/omap_hwmod.c
parent2092e5ccf89db09ebde94e9aabd3c86d5fa05c6c (diff)
downloadkernel_samsung_smdk4412-bd36179eec2827cd60b4a8c6e180cc030c74a4ec.zip
kernel_samsung_smdk4412-bd36179eec2827cd60b4a8c6e180cc030c74a4ec.tar.gz
kernel_samsung_smdk4412-bd36179eec2827cd60b4a8c6e180cc030c74a4ec.tar.bz2
OMAP2+: hwmod: add support for per-class custom device reset functions
The standard omap_hwmod.c _reset() code relies on an IP block's OCP_SYSCONFIG.SOFTRESET register bit to reset the IP block. This works for most IP blocks on the chip, but unfortunately not all. For example, initiator-only IP blocks often don't have any MPU-accessible OCP-header registers, and therefore the MPU can't write to any OCP_SYSCONFIG registers in that block. Other IP blocks, such as the IVA and I2C, require a specialized reset sequence. Since we need to be able to reset these IP blocks as well, allow custom IP block reset functions to be passed into the hwmod code via a per-hwmod-class reset function pointer, struct omap_hwmod_class.reset. If .reset is non-null, then the hwmod _reset() code will call the custom function instead of the standard OCP SOFTRESET-based code. As part of this change, rename most of the existing _reset() function code to _ocp_softreset(), to indicate more clearly that it does not work for all cases. Signed-off-by: Paul Walmsley <paul@pwsan.com> Cc: BenoƮt Cousson <b-cousson@ti.com> Cc: Paul Hunt <hunt@ti.com> Cc: Stanley Liu <stanley_liu@ti.com>
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c38
1 files changed, 33 insertions, 5 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 683428f..12a0b9a 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -1089,7 +1089,7 @@ static int _read_hardreset(struct omap_hwmod *oh, const char *name)
}
/**
- * _reset - reset an omap_hwmod
+ * _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit
* @oh: struct omap_hwmod *
*
* Resets an omap_hwmod @oh via the OCP_SYSCONFIG bit. hwmod must be
@@ -1098,12 +1098,13 @@ static int _read_hardreset(struct omap_hwmod *oh, const char *name)
* the module did not reset in time, or 0 upon success.
*
* In OMAP3 a specific SYSSTATUS register is used to get the reset status.
- * Starting in OMAP4, some IPs does not have SYSSTATUS register and instead
+ * Starting in OMAP4, some IPs do not have SYSSTATUS registers and instead
* use the SYSCONFIG softreset bit to provide the status.
*
- * Note that some IP like McBSP does have a reset control but no reset status.
+ * Note that some IP like McBSP do have reset control but don't have
+ * reset status.
*/
-static int _reset(struct omap_hwmod *oh)
+static int _ocp_softreset(struct omap_hwmod *oh)
{
u32 v;
int c = 0;
@@ -1124,7 +1125,7 @@ static int _reset(struct omap_hwmod *oh)
if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
_enable_optional_clocks(oh);
- pr_debug("omap_hwmod: %s: resetting\n", oh->name);
+ pr_debug("omap_hwmod: %s: resetting via OCP SOFTRESET\n", oh->name);
v = oh->_sysc_cache;
ret = _set_softreset(oh, &v);
@@ -1164,6 +1165,33 @@ dis_opt_clks:
}
/**
+ * _reset - reset an omap_hwmod
+ * @oh: struct omap_hwmod *
+ *
+ * Resets an omap_hwmod @oh. The default software reset mechanism for
+ * most OMAP IP blocks is triggered via the OCP_SYSCONFIG.SOFTRESET
+ * bit. However, some hwmods cannot be reset via this method: some
+ * are not targets and therefore have no OCP header registers to
+ * access; others (like the IVA) have idiosyncratic reset sequences.
+ * So for these relatively rare cases, custom reset code can be
+ * supplied in the struct omap_hwmod_class .reset function pointer.
+ * Passes along the return value from either _reset() or the custom
+ * reset function - these must return -EINVAL if the hwmod cannot be
+ * reset this way or if the hwmod is in the wrong state, -ETIMEDOUT if
+ * the module did not reset in time, or 0 upon success.
+ */
+static int _reset(struct omap_hwmod *oh)
+{
+ int ret;
+
+ pr_debug("omap_hwmod: %s: resetting\n", oh->name);
+
+ ret = (oh->class->reset) ? oh->class->reset(oh) : _ocp_softreset(oh);
+
+ return ret;
+}
+
+/**
* _omap_hwmod_enable - enable an omap_hwmod
* @oh: struct omap_hwmod *
*