aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuman Anna <s-anna@ti.com>2014-07-02 19:00:59 -0400
committerOhad Ben-Cohen <ohad@wizery.com>2014-07-29 04:46:25 -0400
commite1e4528f8c99624494043597859e7f9421832833 (patch)
tree2491adc13e640f56c6748c93a06b8e4c65025fc9
parent9a3c4145af32125c5ee39c0272662b47307a8323 (diff)
hwspinlock/omap: enable module before reading SYSSTATUS register
The number of hwspinlocks are determined based on the value read from the IP block's SYSSTATUS register. However, the module may not be enabled and clocked, and the read may result in a bus error. This particular issue is seen rather easily on AM33XX, since the module wakeup is software controlled, and it is disabled out of reset. Make sure the module is enabled and clocked before reading the SYSSTATUS register. Signed-off-by: Suman Anna <s-anna@ti.com> [replace pm_runtime_put_sync with lenient pm_runtime_put] Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
-rw-r--r--drivers/hwspinlock/omap_hwspinlock.c27
1 files changed, 20 insertions, 7 deletions
diff --git a/drivers/hwspinlock/omap_hwspinlock.c b/drivers/hwspinlock/omap_hwspinlock.c
index 292869cc9034..c1e2cd4d85fe 100644
--- a/drivers/hwspinlock/omap_hwspinlock.c
+++ b/drivers/hwspinlock/omap_hwspinlock.c
@@ -98,10 +98,29 @@ static int omap_hwspinlock_probe(struct platform_device *pdev)
98 if (!io_base) 98 if (!io_base)
99 return -ENOMEM; 99 return -ENOMEM;
100 100
101 /*
102 * make sure the module is enabled and clocked before reading
103 * the module SYSSTATUS register
104 */
105 pm_runtime_enable(&pdev->dev);
106 ret = pm_runtime_get_sync(&pdev->dev);
107 if (ret < 0) {
108 pm_runtime_put_noidle(&pdev->dev);
109 goto iounmap_base;
110 }
111
101 /* Determine number of locks */ 112 /* Determine number of locks */
102 i = readl(io_base + SYSSTATUS_OFFSET); 113 i = readl(io_base + SYSSTATUS_OFFSET);
103 i >>= SPINLOCK_NUMLOCKS_BIT_OFFSET; 114 i >>= SPINLOCK_NUMLOCKS_BIT_OFFSET;
104 115
116 /*
117 * runtime PM will make sure the clock of this module is
118 * enabled again iff at least one lock is requested
119 */
120 ret = pm_runtime_put(&pdev->dev);
121 if (ret < 0)
122 goto iounmap_base;
123
105 /* one of the four lsb's must be set, and nothing else */ 124 /* one of the four lsb's must be set, and nothing else */
106 if (hweight_long(i & 0xf) != 1 || i > 8) { 125 if (hweight_long(i & 0xf) != 1 || i > 8) {
107 ret = -EINVAL; 126 ret = -EINVAL;
@@ -121,12 +140,6 @@ static int omap_hwspinlock_probe(struct platform_device *pdev)
121 for (i = 0, hwlock = &bank->lock[0]; i < num_locks; i++, hwlock++) 140 for (i = 0, hwlock = &bank->lock[0]; i < num_locks; i++, hwlock++)
122 hwlock->priv = io_base + LOCK_BASE_OFFSET + sizeof(u32) * i; 141 hwlock->priv = io_base + LOCK_BASE_OFFSET + sizeof(u32) * i;
123 142
124 /*
125 * runtime PM will make sure the clock of this module is
126 * enabled iff at least one lock is requested
127 */
128 pm_runtime_enable(&pdev->dev);
129
130 ret = hwspin_lock_register(bank, &pdev->dev, &omap_hwspinlock_ops, 143 ret = hwspin_lock_register(bank, &pdev->dev, &omap_hwspinlock_ops,
131 pdata->base_id, num_locks); 144 pdata->base_id, num_locks);
132 if (ret) 145 if (ret)
@@ -135,9 +148,9 @@ static int omap_hwspinlock_probe(struct platform_device *pdev)
135 return 0; 148 return 0;
136 149
137reg_fail: 150reg_fail:
138 pm_runtime_disable(&pdev->dev);
139 kfree(bank); 151 kfree(bank);
140iounmap_base: 152iounmap_base:
153 pm_runtime_disable(&pdev->dev);
141 iounmap(io_base); 154 iounmap(io_base);
142 return ret; 155 return ret;
143} 156}