aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/amba/bus.c88
-rw-r--r--include/linux/amba/bus.h11
2 files changed, 80 insertions, 19 deletions
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index f60b2b6a0931..d31590e7011b 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -122,6 +122,31 @@ static int __init amba_init(void)
122 122
123postcore_initcall(amba_init); 123postcore_initcall(amba_init);
124 124
125static int amba_get_enable_pclk(struct amba_device *pcdev)
126{
127 struct clk *pclk = clk_get(&pcdev->dev, "apb_pclk");
128 int ret;
129
130 pcdev->pclk = pclk;
131
132 if (IS_ERR(pclk))
133 return PTR_ERR(pclk);
134
135 ret = clk_enable(pclk);
136 if (ret)
137 clk_put(pclk);
138
139 return ret;
140}
141
142static void amba_put_disable_pclk(struct amba_device *pcdev)
143{
144 struct clk *pclk = pcdev->pclk;
145
146 clk_disable(pclk);
147 clk_put(pclk);
148}
149
125/* 150/*
126 * These are the device model conversion veneers; they convert the 151 * These are the device model conversion veneers; they convert the
127 * device model structures to our more specific structures. 152 * device model structures to our more specific structures.
@@ -130,17 +155,33 @@ static int amba_probe(struct device *dev)
130{ 155{
131 struct amba_device *pcdev = to_amba_device(dev); 156 struct amba_device *pcdev = to_amba_device(dev);
132 struct amba_driver *pcdrv = to_amba_driver(dev->driver); 157 struct amba_driver *pcdrv = to_amba_driver(dev->driver);
133 struct amba_id *id; 158 struct amba_id *id = amba_lookup(pcdrv->id_table, pcdev);
159 int ret;
134 160
135 id = amba_lookup(pcdrv->id_table, pcdev); 161 do {
162 ret = amba_get_enable_pclk(pcdev);
163 if (ret)
164 break;
165
166 ret = pcdrv->probe(pcdev, id);
167 if (ret == 0)
168 break;
136 169
137 return pcdrv->probe(pcdev, id); 170 amba_put_disable_pclk(pcdev);
171 } while (0);
172
173 return ret;
138} 174}
139 175
140static int amba_remove(struct device *dev) 176static int amba_remove(struct device *dev)
141{ 177{
178 struct amba_device *pcdev = to_amba_device(dev);
142 struct amba_driver *drv = to_amba_driver(dev->driver); 179 struct amba_driver *drv = to_amba_driver(dev->driver);
143 return drv->remove(to_amba_device(dev)); 180 int ret = drv->remove(pcdev);
181
182 amba_put_disable_pclk(pcdev);
183
184 return ret;
144} 185}
145 186
146static void amba_shutdown(struct device *dev) 187static void amba_shutdown(struct device *dev)
@@ -203,7 +244,6 @@ static void amba_device_release(struct device *dev)
203 */ 244 */
204int amba_device_register(struct amba_device *dev, struct resource *parent) 245int amba_device_register(struct amba_device *dev, struct resource *parent)
205{ 246{
206 u32 pid, cid;
207 u32 size; 247 u32 size;
208 void __iomem *tmp; 248 void __iomem *tmp;
209 int i, ret; 249 int i, ret;
@@ -241,25 +281,35 @@ int amba_device_register(struct amba_device *dev, struct resource *parent)
241 goto err_release; 281 goto err_release;
242 } 282 }
243 283
244 /* 284 ret = amba_get_enable_pclk(dev);
245 * Read pid and cid based on size of resource 285 if (ret == 0) {
246 * they are located at end of region 286 u32 pid, cid;
247 */
248 for (pid = 0, i = 0; i < 4; i++)
249 pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) << (i * 8);
250 for (cid = 0, i = 0; i < 4; i++)
251 cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) << (i * 8);
252 287
253 iounmap(tmp); 288 /*
289 * Read pid and cid based on size of resource
290 * they are located at end of region
291 */
292 for (pid = 0, i = 0; i < 4; i++)
293 pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) <<
294 (i * 8);
295 for (cid = 0, i = 0; i < 4; i++)
296 cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) <<
297 (i * 8);
254 298
255 if (cid == 0xb105f00d) 299 amba_put_disable_pclk(dev);
256 dev->periphid = pid;
257 300
258 if (!dev->periphid) { 301 if (cid == 0xb105f00d)
259 ret = -ENODEV; 302 dev->periphid = pid;
260 goto err_release; 303
304 if (!dev->periphid)
305 ret = -ENODEV;
261 } 306 }
262 307
308 iounmap(tmp);
309
310 if (ret)
311 goto err_release;
312
263 ret = device_add(&dev->dev); 313 ret = device_add(&dev->dev);
264 if (ret) 314 if (ret)
265 goto err_release; 315 goto err_release;
diff --git a/include/linux/amba/bus.h b/include/linux/amba/bus.h
index 8b1038607831..b0c174012436 100644
--- a/include/linux/amba/bus.h
+++ b/include/linux/amba/bus.h
@@ -14,14 +14,19 @@
14#ifndef ASMARM_AMBA_H 14#ifndef ASMARM_AMBA_H
15#define ASMARM_AMBA_H 15#define ASMARM_AMBA_H
16 16
17#include <linux/clk.h>
17#include <linux/device.h> 18#include <linux/device.h>
19#include <linux/err.h>
18#include <linux/resource.h> 20#include <linux/resource.h>
19 21
20#define AMBA_NR_IRQS 2 22#define AMBA_NR_IRQS 2
21 23
24struct clk;
25
22struct amba_device { 26struct amba_device {
23 struct device dev; 27 struct device dev;
24 struct resource res; 28 struct resource res;
29 struct clk *pclk;
25 u64 dma_mask; 30 u64 dma_mask;
26 unsigned int periphid; 31 unsigned int periphid;
27 unsigned int irq[AMBA_NR_IRQS]; 32 unsigned int irq[AMBA_NR_IRQS];
@@ -59,6 +64,12 @@ struct amba_device *amba_find_device(const char *, struct device *, unsigned int
59int amba_request_regions(struct amba_device *, const char *); 64int amba_request_regions(struct amba_device *, const char *);
60void amba_release_regions(struct amba_device *); 65void amba_release_regions(struct amba_device *);
61 66
67#define amba_pclk_enable(d) \
68 (IS_ERR((d)->pclk) ? 0 : clk_enable((d)->pclk))
69
70#define amba_pclk_disable(d) \
71 do { if (!IS_ERR((d)->pclk)) clk_disable((d)->pclk); } while (0)
72
62#define amba_config(d) (((d)->periphid >> 24) & 0xff) 73#define amba_config(d) (((d)->periphid >> 24) & 0xff)
63#define amba_rev(d) (((d)->periphid >> 20) & 0x0f) 74#define amba_rev(d) (((d)->periphid >> 20) & 0x0f)
64#define amba_manf(d) (((d)->periphid >> 12) & 0xff) 75#define amba_manf(d) (((d)->periphid >> 12) & 0xff)