aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/omap_hwmod.c
diff options
context:
space:
mode:
authorPaul Walmsley <paul@pwsan.com>2010-12-14 14:42:35 -0500
committerPaul Walmsley <paul@pwsan.com>2010-12-21 21:55:12 -0500
commitdc6d1cda044b24c3d9f8e4af0431887ebe3488ef (patch)
tree475596354e1a9e3d861ee02e50e0b82575377cb3 /arch/arm/mach-omap2/omap_hwmod.c
parentbd36179eec2827cd60b4a8c6e180cc030c74a4ec (diff)
OMAP2+: hwmod: upgrade per-hwmod mutex to a spinlock
Change the per-hwmod mutex to a spinlock. (The per-hwmod lock serializes most post-initialization hwmod operations such as enable, idle, and shutdown.) Spinlocks are needed, because in some cases, hwmods must be enabled from timer interrupt disabled-context, such as an ISR. The current use-case that is driving this is the OMAP GPIO block ISR: it can trigger interrupts even with its clocks disabled, but these clocks are needed for register accesses in the ISR to succeed. This patch also effectively reverts commit 848240223c35fcc71c424ad51a8e8aef42d3879c - this patch makes _omap_hwmod_enable() and _omap_hwmod_init() static, renames them back to _enable() and _idle(), and changes their callers to call the spinlocking versions. Previously, since omap_hwmod_{enable,init}() attempted to take mutexes, these functions could not be called while the timer interrupt was disabled; but now that the functions use spinlocks and save and restore the IRQ state, it is appropriate to call them directly. Kevin Hilman <khilman@deeprootsystems.com> originally proposed this patch - thanks Kevin. Signed-off-by: Paul Walmsley <paul@pwsan.com> Cc: Kevin Hilman <khilman@deeprootsystems.com> Cc: BenoƮt Cousson <b-cousson@ti.com>
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c105
1 files changed, 59 insertions, 46 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 12a0b9a30a30..31990e92c573 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -135,6 +135,7 @@
135#include <linux/err.h> 135#include <linux/err.h>
136#include <linux/list.h> 136#include <linux/list.h>
137#include <linux/mutex.h> 137#include <linux/mutex.h>
138#include <linux/spinlock.h>
138 139
139#include <plat/common.h> 140#include <plat/common.h>
140#include <plat/cpu.h> 141#include <plat/cpu.h>
@@ -1192,17 +1193,14 @@ static int _reset(struct omap_hwmod *oh)
1192} 1193}
1193 1194
1194/** 1195/**
1195 * _omap_hwmod_enable - enable an omap_hwmod 1196 * _enable - enable an omap_hwmod
1196 * @oh: struct omap_hwmod * 1197 * @oh: struct omap_hwmod *
1197 * 1198 *
1198 * Enables an omap_hwmod @oh such that the MPU can access the hwmod's 1199 * Enables an omap_hwmod @oh such that the MPU can access the hwmod's
1199 * register target. (This function has a full name -- 1200 * register target. Returns -EINVAL if the hwmod is in the wrong
1200 * _omap_hwmod_enable() rather than simply _enable() -- because it is 1201 * state or passes along the return value of _wait_target_ready().
1201 * currently required by the pm34xx.c idle loop.) Returns -EINVAL if
1202 * the hwmod is in the wrong state or passes along the return value of
1203 * _wait_target_ready().
1204 */ 1202 */
1205int _omap_hwmod_enable(struct omap_hwmod *oh) 1203static int _enable(struct omap_hwmod *oh)
1206{ 1204{
1207 int r; 1205 int r;
1208 1206
@@ -1249,16 +1247,14 @@ int _omap_hwmod_enable(struct omap_hwmod *oh)
1249} 1247}
1250 1248
1251/** 1249/**
1252 * _omap_hwmod_idle - idle an omap_hwmod 1250 * _idle - idle an omap_hwmod
1253 * @oh: struct omap_hwmod * 1251 * @oh: struct omap_hwmod *
1254 * 1252 *
1255 * Idles an omap_hwmod @oh. This should be called once the hwmod has 1253 * Idles an omap_hwmod @oh. This should be called once the hwmod has
1256 * no further work. (This function has a full name -- 1254 * no further work. Returns -EINVAL if the hwmod is in the wrong
1257 * _omap_hwmod_idle() rather than simply _idle() -- because it is 1255 * state or returns 0.
1258 * currently required by the pm34xx.c idle loop.) Returns -EINVAL if
1259 * the hwmod is in the wrong state or returns 0.
1260 */ 1256 */
1261int _omap_hwmod_idle(struct omap_hwmod *oh) 1257static int _idle(struct omap_hwmod *oh)
1262{ 1258{
1263 if (oh->_state != _HWMOD_STATE_ENABLED) { 1259 if (oh->_state != _HWMOD_STATE_ENABLED) {
1264 WARN(1, "omap_hwmod: %s: idle state can only be entered from " 1260 WARN(1, "omap_hwmod: %s: idle state can only be entered from "
@@ -1304,11 +1300,11 @@ static int _shutdown(struct omap_hwmod *oh)
1304 if (oh->class->pre_shutdown) { 1300 if (oh->class->pre_shutdown) {
1305 prev_state = oh->_state; 1301 prev_state = oh->_state;
1306 if (oh->_state == _HWMOD_STATE_IDLE) 1302 if (oh->_state == _HWMOD_STATE_IDLE)
1307 _omap_hwmod_enable(oh); 1303 _enable(oh);
1308 ret = oh->class->pre_shutdown(oh); 1304 ret = oh->class->pre_shutdown(oh);
1309 if (ret) { 1305 if (ret) {
1310 if (prev_state == _HWMOD_STATE_IDLE) 1306 if (prev_state == _HWMOD_STATE_IDLE)
1311 _omap_hwmod_idle(oh); 1307 _idle(oh);
1312 return ret; 1308 return ret;
1313 } 1309 }
1314 } 1310 }
@@ -1381,7 +1377,7 @@ static int _setup(struct omap_hwmod *oh, void *data)
1381 if ((oh->flags & HWMOD_INIT_NO_RESET) && oh->rst_lines_cnt == 1) 1377 if ((oh->flags & HWMOD_INIT_NO_RESET) && oh->rst_lines_cnt == 1)
1382 return 0; 1378 return 0;
1383 1379
1384 r = _omap_hwmod_enable(oh); 1380 r = _enable(oh);
1385 if (r) { 1381 if (r) {
1386 pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n", 1382 pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n",
1387 oh->name, oh->_state); 1383 oh->name, oh->_state);
@@ -1393,7 +1389,7 @@ static int _setup(struct omap_hwmod *oh, void *data)
1393 1389
1394 /* 1390 /*
1395 * OCP_SYSCONFIG bits need to be reprogrammed after a softreset. 1391 * OCP_SYSCONFIG bits need to be reprogrammed after a softreset.
1396 * The _omap_hwmod_enable() function should be split to 1392 * The _enable() function should be split to
1397 * avoid the rewrite of the OCP_SYSCONFIG register. 1393 * avoid the rewrite of the OCP_SYSCONFIG register.
1398 */ 1394 */
1399 if (oh->class->sysc) { 1395 if (oh->class->sysc) {
@@ -1415,7 +1411,7 @@ static int _setup(struct omap_hwmod *oh, void *data)
1415 postsetup_state = _HWMOD_STATE_ENABLED; 1411 postsetup_state = _HWMOD_STATE_ENABLED;
1416 1412
1417 if (postsetup_state == _HWMOD_STATE_IDLE) 1413 if (postsetup_state == _HWMOD_STATE_IDLE)
1418 _omap_hwmod_idle(oh); 1414 _idle(oh);
1419 else if (postsetup_state == _HWMOD_STATE_DISABLED) 1415 else if (postsetup_state == _HWMOD_STATE_DISABLED)
1420 _shutdown(oh); 1416 _shutdown(oh);
1421 else if (postsetup_state != _HWMOD_STATE_ENABLED) 1417 else if (postsetup_state != _HWMOD_STATE_ENABLED)
@@ -1521,7 +1517,7 @@ int omap_hwmod_register(struct omap_hwmod *oh)
1521 1517
1522 list_add_tail(&oh->node, &omap_hwmod_list); 1518 list_add_tail(&oh->node, &omap_hwmod_list);
1523 1519
1524 mutex_init(&oh->_mutex); 1520 spin_lock_init(&oh->_lock);
1525 1521
1526 oh->_state = _HWMOD_STATE_REGISTERED; 1522 oh->_state = _HWMOD_STATE_REGISTERED;
1527 1523
@@ -1681,18 +1677,18 @@ int omap_hwmod_unregister(struct omap_hwmod *oh)
1681int omap_hwmod_enable(struct omap_hwmod *oh) 1677int omap_hwmod_enable(struct omap_hwmod *oh)
1682{ 1678{
1683 int r; 1679 int r;
1680 unsigned long flags;
1684 1681
1685 if (!oh) 1682 if (!oh)
1686 return -EINVAL; 1683 return -EINVAL;
1687 1684
1688 mutex_lock(&oh->_mutex); 1685 spin_lock_irqsave(&oh->_lock, flags);
1689 r = _omap_hwmod_enable(oh); 1686 r = _enable(oh);
1690 mutex_unlock(&oh->_mutex); 1687 spin_unlock_irqrestore(&oh->_lock, flags);
1691 1688
1692 return r; 1689 return r;
1693} 1690}
1694 1691
1695
1696/** 1692/**
1697 * omap_hwmod_idle - idle an omap_hwmod 1693 * omap_hwmod_idle - idle an omap_hwmod
1698 * @oh: struct omap_hwmod * 1694 * @oh: struct omap_hwmod *
@@ -1702,12 +1698,14 @@ int omap_hwmod_enable(struct omap_hwmod *oh)
1702 */ 1698 */
1703int omap_hwmod_idle(struct omap_hwmod *oh) 1699int omap_hwmod_idle(struct omap_hwmod *oh)
1704{ 1700{
1701 unsigned long flags;
1702
1705 if (!oh) 1703 if (!oh)
1706 return -EINVAL; 1704 return -EINVAL;
1707 1705
1708 mutex_lock(&oh->_mutex); 1706 spin_lock_irqsave(&oh->_lock, flags);
1709 _omap_hwmod_idle(oh); 1707 _idle(oh);
1710 mutex_unlock(&oh->_mutex); 1708 spin_unlock_irqrestore(&oh->_lock, flags);
1711 1709
1712 return 0; 1710 return 0;
1713} 1711}
@@ -1722,12 +1720,14 @@ int omap_hwmod_idle(struct omap_hwmod *oh)
1722 */ 1720 */
1723int omap_hwmod_shutdown(struct omap_hwmod *oh) 1721int omap_hwmod_shutdown(struct omap_hwmod *oh)
1724{ 1722{
1723 unsigned long flags;
1724
1725 if (!oh) 1725 if (!oh)
1726 return -EINVAL; 1726 return -EINVAL;
1727 1727
1728 mutex_lock(&oh->_mutex); 1728 spin_lock_irqsave(&oh->_lock, flags);
1729 _shutdown(oh); 1729 _shutdown(oh);
1730 mutex_unlock(&oh->_mutex); 1730 spin_unlock_irqrestore(&oh->_lock, flags);
1731 1731
1732 return 0; 1732 return 0;
1733} 1733}
@@ -1740,9 +1740,11 @@ int omap_hwmod_shutdown(struct omap_hwmod *oh)
1740 */ 1740 */
1741int omap_hwmod_enable_clocks(struct omap_hwmod *oh) 1741int omap_hwmod_enable_clocks(struct omap_hwmod *oh)
1742{ 1742{
1743 mutex_lock(&oh->_mutex); 1743 unsigned long flags;
1744
1745 spin_lock_irqsave(&oh->_lock, flags);
1744 _enable_clocks(oh); 1746 _enable_clocks(oh);
1745 mutex_unlock(&oh->_mutex); 1747 spin_unlock_irqrestore(&oh->_lock, flags);
1746 1748
1747 return 0; 1749 return 0;
1748} 1750}
@@ -1755,9 +1757,11 @@ int omap_hwmod_enable_clocks(struct omap_hwmod *oh)
1755 */ 1757 */
1756int omap_hwmod_disable_clocks(struct omap_hwmod *oh) 1758int omap_hwmod_disable_clocks(struct omap_hwmod *oh)
1757{ 1759{
1758 mutex_lock(&oh->_mutex); 1760 unsigned long flags;
1761
1762 spin_lock_irqsave(&oh->_lock, flags);
1759 _disable_clocks(oh); 1763 _disable_clocks(oh);
1760 mutex_unlock(&oh->_mutex); 1764 spin_unlock_irqrestore(&oh->_lock, flags);
1761 1765
1762 return 0; 1766 return 0;
1763} 1767}
@@ -1801,13 +1805,14 @@ void omap_hwmod_ocp_barrier(struct omap_hwmod *oh)
1801int omap_hwmod_reset(struct omap_hwmod *oh) 1805int omap_hwmod_reset(struct omap_hwmod *oh)
1802{ 1806{
1803 int r; 1807 int r;
1808 unsigned long flags;
1804 1809
1805 if (!oh) 1810 if (!oh)
1806 return -EINVAL; 1811 return -EINVAL;
1807 1812
1808 mutex_lock(&oh->_mutex); 1813 spin_lock_irqsave(&oh->_lock, flags);
1809 r = _reset(oh); 1814 r = _reset(oh);
1810 mutex_unlock(&oh->_mutex); 1815 spin_unlock_irqrestore(&oh->_lock, flags);
1811 1816
1812 return r; 1817 return r;
1813} 1818}
@@ -2004,13 +2009,15 @@ int omap_hwmod_del_initiator_dep(struct omap_hwmod *oh,
2004 */ 2009 */
2005int omap_hwmod_enable_wakeup(struct omap_hwmod *oh) 2010int omap_hwmod_enable_wakeup(struct omap_hwmod *oh)
2006{ 2011{
2012 unsigned long flags;
2013
2007 if (!oh->class->sysc || 2014 if (!oh->class->sysc ||
2008 !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) 2015 !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP))
2009 return -EINVAL; 2016 return -EINVAL;
2010 2017
2011 mutex_lock(&oh->_mutex); 2018 spin_lock_irqsave(&oh->_lock, flags);
2012 _enable_wakeup(oh); 2019 _enable_wakeup(oh);
2013 mutex_unlock(&oh->_mutex); 2020 spin_unlock_irqrestore(&oh->_lock, flags);
2014 2021
2015 return 0; 2022 return 0;
2016} 2023}
@@ -2029,13 +2036,15 @@ int omap_hwmod_enable_wakeup(struct omap_hwmod *oh)
2029 */ 2036 */
2030int omap_hwmod_disable_wakeup(struct omap_hwmod *oh) 2037int omap_hwmod_disable_wakeup(struct omap_hwmod *oh)
2031{ 2038{
2039 unsigned long flags;
2040
2032 if (!oh->class->sysc || 2041 if (!oh->class->sysc ||
2033 !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) 2042 !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP))
2034 return -EINVAL; 2043 return -EINVAL;
2035 2044
2036 mutex_lock(&oh->_mutex); 2045 spin_lock_irqsave(&oh->_lock, flags);
2037 _disable_wakeup(oh); 2046 _disable_wakeup(oh);
2038 mutex_unlock(&oh->_mutex); 2047 spin_unlock_irqrestore(&oh->_lock, flags);
2039 2048
2040 return 0; 2049 return 0;
2041} 2050}
@@ -2055,13 +2064,14 @@ int omap_hwmod_disable_wakeup(struct omap_hwmod *oh)
2055int omap_hwmod_assert_hardreset(struct omap_hwmod *oh, const char *name) 2064int omap_hwmod_assert_hardreset(struct omap_hwmod *oh, const char *name)
2056{ 2065{
2057 int ret; 2066 int ret;
2067 unsigned long flags;
2058 2068
2059 if (!oh) 2069 if (!oh)
2060 return -EINVAL; 2070 return -EINVAL;
2061 2071
2062 mutex_lock(&oh->_mutex); 2072 spin_lock_irqsave(&oh->_lock, flags);
2063 ret = _assert_hardreset(oh, name); 2073 ret = _assert_hardreset(oh, name);
2064 mutex_unlock(&oh->_mutex); 2074 spin_unlock_irqrestore(&oh->_lock, flags);
2065 2075
2066 return ret; 2076 return ret;
2067} 2077}
@@ -2081,13 +2091,14 @@ int omap_hwmod_assert_hardreset(struct omap_hwmod *oh, const char *name)
2081int omap_hwmod_deassert_hardreset(struct omap_hwmod *oh, const char *name) 2091int omap_hwmod_deassert_hardreset(struct omap_hwmod *oh, const char *name)
2082{ 2092{
2083 int ret; 2093 int ret;
2094 unsigned long flags;
2084 2095
2085 if (!oh) 2096 if (!oh)
2086 return -EINVAL; 2097 return -EINVAL;
2087 2098
2088 mutex_lock(&oh->_mutex); 2099 spin_lock_irqsave(&oh->_lock, flags);
2089 ret = _deassert_hardreset(oh, name); 2100 ret = _deassert_hardreset(oh, name);
2090 mutex_unlock(&oh->_mutex); 2101 spin_unlock_irqrestore(&oh->_lock, flags);
2091 2102
2092 return ret; 2103 return ret;
2093} 2104}
@@ -2106,13 +2117,14 @@ int omap_hwmod_deassert_hardreset(struct omap_hwmod *oh, const char *name)
2106int omap_hwmod_read_hardreset(struct omap_hwmod *oh, const char *name) 2117int omap_hwmod_read_hardreset(struct omap_hwmod *oh, const char *name)
2107{ 2118{
2108 int ret; 2119 int ret;
2120 unsigned long flags;
2109 2121
2110 if (!oh) 2122 if (!oh)
2111 return -EINVAL; 2123 return -EINVAL;
2112 2124
2113 mutex_lock(&oh->_mutex); 2125 spin_lock_irqsave(&oh->_lock, flags);
2114 ret = _read_hardreset(oh, name); 2126 ret = _read_hardreset(oh, name);
2115 mutex_unlock(&oh->_mutex); 2127 spin_unlock_irqrestore(&oh->_lock, flags);
2116 2128
2117 return ret; 2129 return ret;
2118} 2130}
@@ -2180,6 +2192,7 @@ int omap_hwmod_for_each_by_class(const char *classname,
2180int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state) 2192int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state)
2181{ 2193{
2182 int ret; 2194 int ret;
2195 unsigned long flags;
2183 2196
2184 if (!oh) 2197 if (!oh)
2185 return -EINVAL; 2198 return -EINVAL;
@@ -2189,7 +2202,7 @@ int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state)
2189 state != _HWMOD_STATE_IDLE) 2202 state != _HWMOD_STATE_IDLE)
2190 return -EINVAL; 2203 return -EINVAL;
2191 2204
2192 mutex_lock(&oh->_mutex); 2205 spin_lock_irqsave(&oh->_lock, flags);
2193 2206
2194 if (oh->_state != _HWMOD_STATE_REGISTERED) { 2207 if (oh->_state != _HWMOD_STATE_REGISTERED) {
2195 ret = -EINVAL; 2208 ret = -EINVAL;
@@ -2200,7 +2213,7 @@ int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state)
2200 ret = 0; 2213 ret = 0;
2201 2214
2202ohsps_unlock: 2215ohsps_unlock:
2203 mutex_unlock(&oh->_mutex); 2216 spin_unlock_irqrestore(&oh->_lock, flags);
2204 2217
2205 return ret; 2218 return ret;
2206} 2219}