diff options
Diffstat (limited to 'drivers/amba/bus.c')
-rw-r--r-- | drivers/amba/bus.c | 88 |
1 files changed, 69 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 | ||
123 | postcore_initcall(amba_init); | 123 | postcore_initcall(amba_init); |
124 | 124 | ||
125 | static 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 | |||
142 | static 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 | ||
140 | static int amba_remove(struct device *dev) | 176 | static 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 | ||
146 | static void amba_shutdown(struct device *dev) | 187 | static void amba_shutdown(struct device *dev) |
@@ -203,7 +244,6 @@ static void amba_device_release(struct device *dev) | |||
203 | */ | 244 | */ |
204 | int amba_device_register(struct amba_device *dev, struct resource *parent) | 245 | int 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; |