blob: 936c98cb247571fb33427200cc9c95bedf4b21a4 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/arm/common/amba.c
3 *
4 * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/module.h>
11#include <linux/init.h>
12#include <linux/device.h>
Tim Schmielau4e57b682005-10-30 15:03:48 -080013#include <linux/string.h>
14#include <linux/slab.h>
Russell King934848d2009-01-08 09:58:51 +000015#include <linux/io.h>
Rabin Vincentba74ec72011-02-23 04:33:17 +010016#include <linux/pm.h>
17#include <linux/pm_runtime.h>
Russell Kinga62c80e2006-01-07 13:52:45 +000018#include <linux/amba/bus.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019
Russell King934848d2009-01-08 09:58:51 +000020#include <asm/irq.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <asm/sizes.h>
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#define to_amba_driver(d) container_of(d, struct amba_driver, drv)
24
Russell Kingc862aab2011-02-19 15:55:26 +000025static const struct amba_id *
26amba_lookup(const struct amba_id *table, struct amba_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -070027{
28 int ret = 0;
29
30 while (table->mask) {
31 ret = (dev->periphid & table->mask) == table->id;
32 if (ret)
33 break;
34 table++;
35 }
36
37 return ret ? table : NULL;
38}
39
40static int amba_match(struct device *dev, struct device_driver *drv)
41{
42 struct amba_device *pcdev = to_amba_device(dev);
43 struct amba_driver *pcdrv = to_amba_driver(drv);
44
45 return amba_lookup(pcdrv->id_table, pcdev) != NULL;
46}
47
48#ifdef CONFIG_HOTPLUG
Kay Sievers7eff2e72007-08-14 15:15:12 +020049static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
Linus Torvalds1da177e2005-04-16 15:20:36 -070050{
51 struct amba_device *pcdev = to_amba_device(dev);
Kay Sievers7eff2e72007-08-14 15:15:12 +020052 int retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
Kay Sievers7eff2e72007-08-14 15:15:12 +020054 retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid);
Dave Martin523817b2011-10-05 14:44:57 +010055 if (retval)
56 return retval;
57
58 retval = add_uevent_var(env, "MODALIAS=amba:d%08X", pcdev->periphid);
Eric Rannaudbf624562007-03-30 22:23:12 -070059 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -070060}
61#else
Paul Jackson6d20b032005-11-25 20:04:26 -080062#define amba_uevent NULL
Linus Torvalds1da177e2005-04-16 15:20:36 -070063#endif
64
Russell King96b13f52006-11-30 14:04:49 +000065#define amba_attr_func(name,fmt,arg...) \
66static ssize_t name##_show(struct device *_dev, \
67 struct device_attribute *attr, char *buf) \
68{ \
69 struct amba_device *dev = to_amba_device(_dev); \
70 return sprintf(buf, fmt, arg); \
71}
72
73#define amba_attr(name,fmt,arg...) \
74amba_attr_func(name,fmt,arg) \
75static DEVICE_ATTR(name, S_IRUGO, name##_show, NULL)
76
77amba_attr_func(id, "%08x\n", dev->periphid);
78amba_attr(irq0, "%u\n", dev->irq[0]);
79amba_attr(irq1, "%u\n", dev->irq[1]);
80amba_attr_func(resource, "\t%016llx\t%016llx\t%016lx\n",
81 (unsigned long long)dev->res.start, (unsigned long long)dev->res.end,
82 dev->res.flags);
83
84static struct device_attribute amba_dev_attrs[] = {
85 __ATTR_RO(id),
86 __ATTR_RO(resource),
87 __ATTR_NULL,
88};
89
Rabin Vincentba74ec72011-02-23 04:33:17 +010090#ifdef CONFIG_PM_SLEEP
91
92static int amba_legacy_suspend(struct device *dev, pm_message_t mesg)
93{
94 struct amba_driver *adrv = to_amba_driver(dev->driver);
95 struct amba_device *adev = to_amba_device(dev);
96 int ret = 0;
97
98 if (dev->driver && adrv->suspend)
99 ret = adrv->suspend(adev, mesg);
100
101 return ret;
102}
103
104static int amba_legacy_resume(struct device *dev)
105{
106 struct amba_driver *adrv = to_amba_driver(dev->driver);
107 struct amba_device *adev = to_amba_device(dev);
108 int ret = 0;
109
110 if (dev->driver && adrv->resume)
111 ret = adrv->resume(adev);
112
113 return ret;
114}
115
116static int amba_pm_prepare(struct device *dev)
117{
118 struct device_driver *drv = dev->driver;
119 int ret = 0;
120
121 if (drv && drv->pm && drv->pm->prepare)
122 ret = drv->pm->prepare(dev);
123
124 return ret;
125}
126
127static void amba_pm_complete(struct device *dev)
128{
129 struct device_driver *drv = dev->driver;
130
131 if (drv && drv->pm && drv->pm->complete)
132 drv->pm->complete(dev);
133}
134
135#else /* !CONFIG_PM_SLEEP */
136
137#define amba_pm_prepare NULL
138#define amba_pm_complete NULL
139
140#endif /* !CONFIG_PM_SLEEP */
141
142#ifdef CONFIG_SUSPEND
143
144static int amba_pm_suspend(struct device *dev)
145{
146 struct device_driver *drv = dev->driver;
147 int ret = 0;
148
149 if (!drv)
150 return 0;
151
152 if (drv->pm) {
153 if (drv->pm->suspend)
154 ret = drv->pm->suspend(dev);
155 } else {
156 ret = amba_legacy_suspend(dev, PMSG_SUSPEND);
157 }
158
159 return ret;
160}
161
162static int amba_pm_suspend_noirq(struct device *dev)
163{
164 struct device_driver *drv = dev->driver;
165 int ret = 0;
166
167 if (!drv)
168 return 0;
169
170 if (drv->pm) {
171 if (drv->pm->suspend_noirq)
172 ret = drv->pm->suspend_noirq(dev);
173 }
174
175 return ret;
176}
177
178static int amba_pm_resume(struct device *dev)
179{
180 struct device_driver *drv = dev->driver;
181 int ret = 0;
182
183 if (!drv)
184 return 0;
185
186 if (drv->pm) {
187 if (drv->pm->resume)
188 ret = drv->pm->resume(dev);
189 } else {
190 ret = amba_legacy_resume(dev);
191 }
192
193 return ret;
194}
195
196static int amba_pm_resume_noirq(struct device *dev)
197{
198 struct device_driver *drv = dev->driver;
199 int ret = 0;
200
201 if (!drv)
202 return 0;
203
204 if (drv->pm) {
205 if (drv->pm->resume_noirq)
206 ret = drv->pm->resume_noirq(dev);
207 }
208
209 return ret;
210}
211
212#else /* !CONFIG_SUSPEND */
213
214#define amba_pm_suspend NULL
215#define amba_pm_resume NULL
216#define amba_pm_suspend_noirq NULL
217#define amba_pm_resume_noirq NULL
218
219#endif /* !CONFIG_SUSPEND */
220
Rafael J. Wysocki1f112ce2011-04-11 22:54:42 +0200221#ifdef CONFIG_HIBERNATE_CALLBACKS
Rabin Vincentba74ec72011-02-23 04:33:17 +0100222
223static int amba_pm_freeze(struct device *dev)
224{
225 struct device_driver *drv = dev->driver;
226 int ret = 0;
227
228 if (!drv)
229 return 0;
230
231 if (drv->pm) {
232 if (drv->pm->freeze)
233 ret = drv->pm->freeze(dev);
234 } else {
235 ret = amba_legacy_suspend(dev, PMSG_FREEZE);
236 }
237
238 return ret;
239}
240
241static int amba_pm_freeze_noirq(struct device *dev)
242{
243 struct device_driver *drv = dev->driver;
244 int ret = 0;
245
246 if (!drv)
247 return 0;
248
249 if (drv->pm) {
250 if (drv->pm->freeze_noirq)
251 ret = drv->pm->freeze_noirq(dev);
252 }
253
254 return ret;
255}
256
257static int amba_pm_thaw(struct device *dev)
258{
259 struct device_driver *drv = dev->driver;
260 int ret = 0;
261
262 if (!drv)
263 return 0;
264
265 if (drv->pm) {
266 if (drv->pm->thaw)
267 ret = drv->pm->thaw(dev);
268 } else {
269 ret = amba_legacy_resume(dev);
270 }
271
272 return ret;
273}
274
275static int amba_pm_thaw_noirq(struct device *dev)
276{
277 struct device_driver *drv = dev->driver;
278 int ret = 0;
279
280 if (!drv)
281 return 0;
282
283 if (drv->pm) {
284 if (drv->pm->thaw_noirq)
285 ret = drv->pm->thaw_noirq(dev);
286 }
287
288 return ret;
289}
290
291static int amba_pm_poweroff(struct device *dev)
292{
293 struct device_driver *drv = dev->driver;
294 int ret = 0;
295
296 if (!drv)
297 return 0;
298
299 if (drv->pm) {
300 if (drv->pm->poweroff)
301 ret = drv->pm->poweroff(dev);
302 } else {
303 ret = amba_legacy_suspend(dev, PMSG_HIBERNATE);
304 }
305
306 return ret;
307}
308
309static int amba_pm_poweroff_noirq(struct device *dev)
310{
311 struct device_driver *drv = dev->driver;
312 int ret = 0;
313
314 if (!drv)
315 return 0;
316
317 if (drv->pm) {
318 if (drv->pm->poweroff_noirq)
319 ret = drv->pm->poweroff_noirq(dev);
320 }
321
322 return ret;
323}
324
325static int amba_pm_restore(struct device *dev)
326{
327 struct device_driver *drv = dev->driver;
328 int ret = 0;
329
330 if (!drv)
331 return 0;
332
333 if (drv->pm) {
334 if (drv->pm->restore)
335 ret = drv->pm->restore(dev);
336 } else {
337 ret = amba_legacy_resume(dev);
338 }
339
340 return ret;
341}
342
343static int amba_pm_restore_noirq(struct device *dev)
344{
345 struct device_driver *drv = dev->driver;
346 int ret = 0;
347
348 if (!drv)
349 return 0;
350
351 if (drv->pm) {
352 if (drv->pm->restore_noirq)
353 ret = drv->pm->restore_noirq(dev);
354 }
355
356 return ret;
357}
358
Rafael J. Wysocki1f112ce2011-04-11 22:54:42 +0200359#else /* !CONFIG_HIBERNATE_CALLBACKS */
Rabin Vincentba74ec72011-02-23 04:33:17 +0100360
361#define amba_pm_freeze NULL
362#define amba_pm_thaw NULL
363#define amba_pm_poweroff NULL
364#define amba_pm_restore NULL
365#define amba_pm_freeze_noirq NULL
366#define amba_pm_thaw_noirq NULL
367#define amba_pm_poweroff_noirq NULL
368#define amba_pm_restore_noirq NULL
369
Rafael J. Wysocki1f112ce2011-04-11 22:54:42 +0200370#endif /* !CONFIG_HIBERNATE_CALLBACKS */
Rabin Vincentba74ec72011-02-23 04:33:17 +0100371
Russell King92b97f02011-08-14 09:13:48 +0100372#ifdef CONFIG_PM_RUNTIME
373/*
374 * Hooks to provide runtime PM of the pclk (bus clock). It is safe to
375 * enable/disable the bus clock at runtime PM suspend/resume as this
376 * does not result in loss of context. However, disabling vcore power
377 * would do, so we leave that to the driver.
378 */
379static int amba_pm_runtime_suspend(struct device *dev)
380{
381 struct amba_device *pcdev = to_amba_device(dev);
382 int ret = pm_generic_runtime_suspend(dev);
383
384 if (ret == 0 && dev->driver)
385 clk_disable(pcdev->pclk);
386
387 return ret;
388}
389
390static int amba_pm_runtime_resume(struct device *dev)
391{
392 struct amba_device *pcdev = to_amba_device(dev);
393 int ret;
394
395 if (dev->driver) {
396 ret = clk_enable(pcdev->pclk);
397 /* Failure is probably fatal to the system, but... */
398 if (ret)
399 return ret;
400 }
401
402 return pm_generic_runtime_resume(dev);
403}
404#endif
405
Rabin Vincentba74ec72011-02-23 04:33:17 +0100406#ifdef CONFIG_PM
407
408static const struct dev_pm_ops amba_pm = {
409 .prepare = amba_pm_prepare,
410 .complete = amba_pm_complete,
411 .suspend = amba_pm_suspend,
412 .resume = amba_pm_resume,
413 .freeze = amba_pm_freeze,
414 .thaw = amba_pm_thaw,
415 .poweroff = amba_pm_poweroff,
416 .restore = amba_pm_restore,
417 .suspend_noirq = amba_pm_suspend_noirq,
418 .resume_noirq = amba_pm_resume_noirq,
419 .freeze_noirq = amba_pm_freeze_noirq,
420 .thaw_noirq = amba_pm_thaw_noirq,
421 .poweroff_noirq = amba_pm_poweroff_noirq,
422 .restore_noirq = amba_pm_restore_noirq,
423 SET_RUNTIME_PM_OPS(
Russell King92b97f02011-08-14 09:13:48 +0100424 amba_pm_runtime_suspend,
425 amba_pm_runtime_resume,
Rabin Vincentba74ec72011-02-23 04:33:17 +0100426 pm_generic_runtime_idle
427 )
428};
429
430#define AMBA_PM (&amba_pm)
431
432#else /* !CONFIG_PM */
433
434#define AMBA_PM NULL
435
436#endif /* !CONFIG_PM */
437
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438/*
439 * Primecells are part of the Advanced Microcontroller Bus Architecture,
440 * so we call the bus "amba".
441 */
Rob Herring394d5ae2011-02-12 15:58:25 +0100442struct bus_type amba_bustype = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 .name = "amba",
Russell King96b13f52006-11-30 14:04:49 +0000444 .dev_attrs = amba_dev_attrs,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 .match = amba_match,
Paul Jackson6d20b032005-11-25 20:04:26 -0800446 .uevent = amba_uevent,
Rabin Vincentba74ec72011-02-23 04:33:17 +0100447 .pm = AMBA_PM,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448};
449
450static int __init amba_init(void)
451{
452 return bus_register(&amba_bustype);
453}
454
455postcore_initcall(amba_init);
456
Russell King7cfe2492010-07-15 10:47:14 +0100457static int amba_get_enable_pclk(struct amba_device *pcdev)
458{
459 struct clk *pclk = clk_get(&pcdev->dev, "apb_pclk");
460 int ret;
461
462 pcdev->pclk = pclk;
463
464 if (IS_ERR(pclk))
465 return PTR_ERR(pclk);
466
Russell Kingac3e2fa2011-09-22 12:20:55 +0100467 ret = clk_prepare(pclk);
468 if (ret) {
Russell King7cfe2492010-07-15 10:47:14 +0100469 clk_put(pclk);
Russell Kingac3e2fa2011-09-22 12:20:55 +0100470 return ret;
471 }
472
473 ret = clk_enable(pclk);
474 if (ret) {
475 clk_unprepare(pclk);
476 clk_put(pclk);
477 }
Russell King7cfe2492010-07-15 10:47:14 +0100478
479 return ret;
480}
481
482static void amba_put_disable_pclk(struct amba_device *pcdev)
483{
484 struct clk *pclk = pcdev->pclk;
485
486 clk_disable(pclk);
Russell Kingac3e2fa2011-09-22 12:20:55 +0100487 clk_unprepare(pclk);
Russell King7cfe2492010-07-15 10:47:14 +0100488 clk_put(pclk);
489}
490
Linus Walleij65500fa2010-11-04 13:06:59 +0100491static int amba_get_enable_vcore(struct amba_device *pcdev)
492{
493 struct regulator *vcore = regulator_get(&pcdev->dev, "vcore");
494 int ret;
495
496 pcdev->vcore = vcore;
497
498 if (IS_ERR(vcore)) {
499 /* It is OK not to supply a vcore regulator */
500 if (PTR_ERR(vcore) == -ENODEV)
501 return 0;
502 return PTR_ERR(vcore);
503 }
504
505 ret = regulator_enable(vcore);
506 if (ret) {
507 regulator_put(vcore);
508 pcdev->vcore = ERR_PTR(-ENODEV);
509 }
510
511 return ret;
512}
513
514static void amba_put_disable_vcore(struct amba_device *pcdev)
515{
516 struct regulator *vcore = pcdev->vcore;
517
518 if (!IS_ERR(vcore)) {
519 regulator_disable(vcore);
520 regulator_put(vcore);
521 }
522}
523
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524/*
525 * These are the device model conversion veneers; they convert the
526 * device model structures to our more specific structures.
527 */
528static int amba_probe(struct device *dev)
529{
530 struct amba_device *pcdev = to_amba_device(dev);
531 struct amba_driver *pcdrv = to_amba_driver(dev->driver);
Russell Kingc862aab2011-02-19 15:55:26 +0000532 const struct amba_id *id = amba_lookup(pcdrv->id_table, pcdev);
Russell King7cfe2492010-07-15 10:47:14 +0100533 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
Russell King7cfe2492010-07-15 10:47:14 +0100535 do {
Linus Walleij65500fa2010-11-04 13:06:59 +0100536 ret = amba_get_enable_vcore(pcdev);
537 if (ret)
538 break;
539
Russell King7cfe2492010-07-15 10:47:14 +0100540 ret = amba_get_enable_pclk(pcdev);
541 if (ret)
542 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543
Russell King92b97f02011-08-14 09:13:48 +0100544 pm_runtime_get_noresume(dev);
545 pm_runtime_set_active(dev);
546 pm_runtime_enable(dev);
547
Russell King7cfe2492010-07-15 10:47:14 +0100548 ret = pcdrv->probe(pcdev, id);
549 if (ret == 0)
550 break;
551
Russell King92b97f02011-08-14 09:13:48 +0100552 pm_runtime_disable(dev);
553 pm_runtime_set_suspended(dev);
554 pm_runtime_put_noidle(dev);
555
Russell King7cfe2492010-07-15 10:47:14 +0100556 amba_put_disable_pclk(pcdev);
Linus Walleij65500fa2010-11-04 13:06:59 +0100557 amba_put_disable_vcore(pcdev);
Russell King7cfe2492010-07-15 10:47:14 +0100558 } while (0);
559
560 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561}
562
563static int amba_remove(struct device *dev)
564{
Russell King7cfe2492010-07-15 10:47:14 +0100565 struct amba_device *pcdev = to_amba_device(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 struct amba_driver *drv = to_amba_driver(dev->driver);
Russell King92b97f02011-08-14 09:13:48 +0100567 int ret;
568
569 pm_runtime_get_sync(dev);
570 ret = drv->remove(pcdev);
571 pm_runtime_put_noidle(dev);
572
573 /* Undo the runtime PM settings in amba_probe() */
574 pm_runtime_disable(dev);
575 pm_runtime_set_suspended(dev);
576 pm_runtime_put_noidle(dev);
Russell King7cfe2492010-07-15 10:47:14 +0100577
578 amba_put_disable_pclk(pcdev);
Linus Walleij65500fa2010-11-04 13:06:59 +0100579 amba_put_disable_vcore(pcdev);
Russell King7cfe2492010-07-15 10:47:14 +0100580
581 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582}
583
584static void amba_shutdown(struct device *dev)
585{
586 struct amba_driver *drv = to_amba_driver(dev->driver);
587 drv->shutdown(to_amba_device(dev));
588}
589
590/**
591 * amba_driver_register - register an AMBA device driver
592 * @drv: amba device driver structure
593 *
594 * Register an AMBA device driver with the Linux device model
595 * core. If devices pre-exist, the drivers probe function will
596 * be called.
597 */
598int amba_driver_register(struct amba_driver *drv)
599{
600 drv->drv.bus = &amba_bustype;
601
602#define SETFN(fn) if (drv->fn) drv->drv.fn = amba_##fn
603 SETFN(probe);
604 SETFN(remove);
605 SETFN(shutdown);
606
607 return driver_register(&drv->drv);
608}
609
610/**
611 * amba_driver_unregister - remove an AMBA device driver
612 * @drv: AMBA device driver structure to remove
613 *
614 * Unregister an AMBA device driver from the Linux device
615 * model. The device model will call the drivers remove function
616 * for each device the device driver is currently handling.
617 */
618void amba_driver_unregister(struct amba_driver *drv)
619{
620 driver_unregister(&drv->drv);
621}
622
623
624static void amba_device_release(struct device *dev)
625{
626 struct amba_device *d = to_amba_device(dev);
627
628 if (d->res.parent)
629 release_resource(&d->res);
630 kfree(d);
631}
632
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633/**
634 * amba_device_register - register an AMBA device
635 * @dev: AMBA device to register
636 * @parent: parent memory resource
637 *
638 * Setup the AMBA device, reading the cell ID if present.
639 * Claim the resource, and register the AMBA device with
640 * the Linux device manager.
641 */
642int amba_device_register(struct amba_device *dev, struct resource *parent)
643{
Leo Chen8afe0b92009-07-28 23:34:59 +0100644 u32 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 void __iomem *tmp;
646 int i, ret;
647
Russell King557dca52009-07-05 22:39:08 +0100648 device_initialize(&dev->dev);
649
650 /*
651 * Copy from device_add
652 */
653 if (dev->dev.init_name) {
654 dev_set_name(&dev->dev, "%s", dev->dev.init_name);
655 dev->dev.init_name = NULL;
656 }
657
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 dev->dev.release = amba_device_release;
659 dev->dev.bus = &amba_bustype;
660 dev->dev.dma_mask = &dev->dma_mask;
Kay Sievers9d6b4c82009-03-24 16:38:22 -0700661 dev->res.name = dev_name(&dev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662
663 if (!dev->dev.coherent_dma_mask && dev->dma_mask)
664 dev_warn(&dev->dev, "coherent dma mask is unset\n");
665
666 ret = request_resource(parent, &dev->res);
Russell King96b13f52006-11-30 14:04:49 +0000667 if (ret)
668 goto err_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
Linus Walleij97ceed12011-03-24 16:12:40 +0100670 /* Hard-coded primecell ID instead of plug-n-play */
671 if (dev->periphid != 0)
672 goto skip_probe;
673
Leo Chen8afe0b92009-07-28 23:34:59 +0100674 /*
675 * Dynamically calculate the size of the resource
676 * and use this for iomap
677 */
678 size = resource_size(&dev->res);
679 tmp = ioremap(dev->res.start, size);
Russell King96b13f52006-11-30 14:04:49 +0000680 if (!tmp) {
681 ret = -ENOMEM;
682 goto err_release;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 }
Russell King96b13f52006-11-30 14:04:49 +0000684
Russell King7cfe2492010-07-15 10:47:14 +0100685 ret = amba_get_enable_pclk(dev);
686 if (ret == 0) {
687 u32 pid, cid;
688
689 /*
690 * Read pid and cid based on size of resource
691 * they are located at end of region
692 */
693 for (pid = 0, i = 0; i < 4; i++)
694 pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) <<
695 (i * 8);
696 for (cid = 0, i = 0; i < 4; i++)
697 cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) <<
698 (i * 8);
699
700 amba_put_disable_pclk(dev);
701
Linus Walleij01723a92010-09-07 22:43:19 +0100702 if (cid == AMBA_CID)
Russell King7cfe2492010-07-15 10:47:14 +0100703 dev->periphid = pid;
704
705 if (!dev->periphid)
706 ret = -ENODEV;
707 }
Russell King96b13f52006-11-30 14:04:49 +0000708
709 iounmap(tmp);
710
Russell King7cfe2492010-07-15 10:47:14 +0100711 if (ret)
Russell King96b13f52006-11-30 14:04:49 +0000712 goto err_release;
Russell King96b13f52006-11-30 14:04:49 +0000713
Linus Walleij97ceed12011-03-24 16:12:40 +0100714 skip_probe:
Russell King557dca52009-07-05 22:39:08 +0100715 ret = device_add(&dev->dev);
Russell King96b13f52006-11-30 14:04:49 +0000716 if (ret)
717 goto err_release;
718
719 if (dev->irq[0] != NO_IRQ)
720 ret = device_create_file(&dev->dev, &dev_attr_irq0);
721 if (ret == 0 && dev->irq[1] != NO_IRQ)
722 ret = device_create_file(&dev->dev, &dev_attr_irq1);
723 if (ret == 0)
724 return ret;
725
726 device_unregister(&dev->dev);
727
728 err_release:
729 release_resource(&dev->res);
730 err_out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 return ret;
732}
733
734/**
735 * amba_device_unregister - unregister an AMBA device
736 * @dev: AMBA device to remove
737 *
738 * Remove the specified AMBA device from the Linux device
739 * manager. All files associated with this object will be
740 * destroyed, and device drivers notified that the device has
741 * been removed. The AMBA device's resources including
742 * the amba_device structure will be freed once all
743 * references to it have been dropped.
744 */
745void amba_device_unregister(struct amba_device *dev)
746{
747 device_unregister(&dev->dev);
748}
749
750
751struct find_data {
752 struct amba_device *dev;
753 struct device *parent;
754 const char *busid;
755 unsigned int id;
756 unsigned int mask;
757};
758
759static int amba_find_match(struct device *dev, void *data)
760{
761 struct find_data *d = data;
762 struct amba_device *pcdev = to_amba_device(dev);
763 int r;
764
765 r = (pcdev->periphid & d->mask) == d->id;
766 if (d->parent)
767 r &= d->parent == dev->parent;
768 if (d->busid)
Kay Sievers9d6b4c82009-03-24 16:38:22 -0700769 r &= strcmp(dev_name(dev), d->busid) == 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
771 if (r) {
772 get_device(dev);
773 d->dev = pcdev;
774 }
775
776 return r;
777}
778
779/**
780 * amba_find_device - locate an AMBA device given a bus id
781 * @busid: bus id for device (or NULL)
782 * @parent: parent device (or NULL)
783 * @id: peripheral ID (or 0)
784 * @mask: peripheral ID mask (or 0)
785 *
786 * Return the AMBA device corresponding to the supplied parameters.
787 * If no device matches, returns NULL.
788 *
789 * NOTE: When a valid device is found, its refcount is
790 * incremented, and must be decremented before the returned
791 * reference.
792 */
793struct amba_device *
794amba_find_device(const char *busid, struct device *parent, unsigned int id,
795 unsigned int mask)
796{
797 struct find_data data;
798
799 data.dev = NULL;
800 data.parent = parent;
801 data.busid = busid;
802 data.id = id;
803 data.mask = mask;
804
805 bus_for_each_dev(&amba_bustype, NULL, &data, amba_find_match);
806
807 return data.dev;
808}
809
810/**
811 * amba_request_regions - request all mem regions associated with device
812 * @dev: amba_device structure for device
813 * @name: name, or NULL to use driver name
814 */
815int amba_request_regions(struct amba_device *dev, const char *name)
816{
817 int ret = 0;
Leo Chen8afe0b92009-07-28 23:34:59 +0100818 u32 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
820 if (!name)
821 name = dev->dev.driver->name;
822
Leo Chen8afe0b92009-07-28 23:34:59 +0100823 size = resource_size(&dev->res);
824
825 if (!request_mem_region(dev->res.start, size, name))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 ret = -EBUSY;
827
828 return ret;
829}
830
831/**
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300832 * amba_release_regions - release mem regions associated with device
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 * @dev: amba_device structure for device
834 *
835 * Release regions claimed by a successful call to amba_request_regions.
836 */
837void amba_release_regions(struct amba_device *dev)
838{
Leo Chen8afe0b92009-07-28 23:34:59 +0100839 u32 size;
840
841 size = resource_size(&dev->res);
842 release_mem_region(dev->res.start, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843}
844
845EXPORT_SYMBOL(amba_driver_register);
846EXPORT_SYMBOL(amba_driver_unregister);
847EXPORT_SYMBOL(amba_device_register);
848EXPORT_SYMBOL(amba_device_unregister);
849EXPORT_SYMBOL(amba_find_device);
850EXPORT_SYMBOL(amba_request_regions);
851EXPORT_SYMBOL(amba_release_regions);