1 /*
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>
13 #include <linux/string.h>
14 #include <linux/slab.h>
15 #include <linux/io.h>
16 #include <linux/pm.h>
17 #include <linux/pm_runtime.h>
18 #include <linux/amba/bus.h>
19 
20 #include <asm/irq.h>
21 #include <asm/sizes.h>
22 
23 #define to_amba_driver(d)	container_of(d, struct amba_driver, drv)
24 
25 static const struct amba_id *
amba_lookup(const struct amba_id * table,struct amba_device * dev)26 amba_lookup(const struct amba_id *table, struct amba_device *dev)
27 {
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 
amba_match(struct device * dev,struct device_driver * drv)40 static 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
amba_uevent(struct device * dev,struct kobj_uevent_env * env)49 static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
50 {
51 	struct amba_device *pcdev = to_amba_device(dev);
52 	int retval = 0;
53 
54 	retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid);
55 	return retval;
56 }
57 #else
58 #define amba_uevent NULL
59 #endif
60 
61 #define amba_attr_func(name,fmt,arg...)					\
62 static ssize_t name##_show(struct device *_dev,				\
63 			   struct device_attribute *attr, char *buf)	\
64 {									\
65 	struct amba_device *dev = to_amba_device(_dev);			\
66 	return sprintf(buf, fmt, arg);					\
67 }
68 
69 #define amba_attr(name,fmt,arg...)	\
70 amba_attr_func(name,fmt,arg)		\
71 static DEVICE_ATTR(name, S_IRUGO, name##_show, NULL)
72 
73 amba_attr_func(id, "%08x\n", dev->periphid);
74 amba_attr(irq0, "%u\n", dev->irq[0]);
75 amba_attr(irq1, "%u\n", dev->irq[1]);
76 amba_attr_func(resource, "\t%016llx\t%016llx\t%016lx\n",
77 	 (unsigned long long)dev->res.start, (unsigned long long)dev->res.end,
78 	 dev->res.flags);
79 
80 static struct device_attribute amba_dev_attrs[] = {
81 	__ATTR_RO(id),
82 	__ATTR_RO(resource),
83 	__ATTR_NULL,
84 };
85 
86 #ifdef CONFIG_PM_SLEEP
87 
amba_legacy_suspend(struct device * dev,pm_message_t mesg)88 static int amba_legacy_suspend(struct device *dev, pm_message_t mesg)
89 {
90 	struct amba_driver *adrv = to_amba_driver(dev->driver);
91 	struct amba_device *adev = to_amba_device(dev);
92 	int ret = 0;
93 
94 	if (dev->driver && adrv->suspend)
95 		ret = adrv->suspend(adev, mesg);
96 
97 	return ret;
98 }
99 
amba_legacy_resume(struct device * dev)100 static int amba_legacy_resume(struct device *dev)
101 {
102 	struct amba_driver *adrv = to_amba_driver(dev->driver);
103 	struct amba_device *adev = to_amba_device(dev);
104 	int ret = 0;
105 
106 	if (dev->driver && adrv->resume)
107 		ret = adrv->resume(adev);
108 
109 	return ret;
110 }
111 
amba_pm_prepare(struct device * dev)112 static int amba_pm_prepare(struct device *dev)
113 {
114 	struct device_driver *drv = dev->driver;
115 	int ret = 0;
116 
117 	if (drv && drv->pm && drv->pm->prepare)
118 		ret = drv->pm->prepare(dev);
119 
120 	return ret;
121 }
122 
amba_pm_complete(struct device * dev)123 static void amba_pm_complete(struct device *dev)
124 {
125 	struct device_driver *drv = dev->driver;
126 
127 	if (drv && drv->pm && drv->pm->complete)
128 		drv->pm->complete(dev);
129 }
130 
131 #else /* !CONFIG_PM_SLEEP */
132 
133 #define amba_pm_prepare		NULL
134 #define amba_pm_complete		NULL
135 
136 #endif /* !CONFIG_PM_SLEEP */
137 
138 #ifdef CONFIG_SUSPEND
139 
amba_pm_suspend(struct device * dev)140 static int amba_pm_suspend(struct device *dev)
141 {
142 	struct device_driver *drv = dev->driver;
143 	int ret = 0;
144 
145 	if (!drv)
146 		return 0;
147 
148 	if (drv->pm) {
149 		if (drv->pm->suspend)
150 			ret = drv->pm->suspend(dev);
151 	} else {
152 		ret = amba_legacy_suspend(dev, PMSG_SUSPEND);
153 	}
154 
155 	return ret;
156 }
157 
amba_pm_suspend_noirq(struct device * dev)158 static int amba_pm_suspend_noirq(struct device *dev)
159 {
160 	struct device_driver *drv = dev->driver;
161 	int ret = 0;
162 
163 	if (!drv)
164 		return 0;
165 
166 	if (drv->pm) {
167 		if (drv->pm->suspend_noirq)
168 			ret = drv->pm->suspend_noirq(dev);
169 	}
170 
171 	return ret;
172 }
173 
amba_pm_resume(struct device * dev)174 static int amba_pm_resume(struct device *dev)
175 {
176 	struct device_driver *drv = dev->driver;
177 	int ret = 0;
178 
179 	if (!drv)
180 		return 0;
181 
182 	if (drv->pm) {
183 		if (drv->pm->resume)
184 			ret = drv->pm->resume(dev);
185 	} else {
186 		ret = amba_legacy_resume(dev);
187 	}
188 
189 	return ret;
190 }
191 
amba_pm_resume_noirq(struct device * dev)192 static int amba_pm_resume_noirq(struct device *dev)
193 {
194 	struct device_driver *drv = dev->driver;
195 	int ret = 0;
196 
197 	if (!drv)
198 		return 0;
199 
200 	if (drv->pm) {
201 		if (drv->pm->resume_noirq)
202 			ret = drv->pm->resume_noirq(dev);
203 	}
204 
205 	return ret;
206 }
207 
208 #else /* !CONFIG_SUSPEND */
209 
210 #define amba_pm_suspend		NULL
211 #define amba_pm_resume		NULL
212 #define amba_pm_suspend_noirq	NULL
213 #define amba_pm_resume_noirq	NULL
214 
215 #endif /* !CONFIG_SUSPEND */
216 
217 #ifdef CONFIG_HIBERNATE_CALLBACKS
218 
amba_pm_freeze(struct device * dev)219 static int amba_pm_freeze(struct device *dev)
220 {
221 	struct device_driver *drv = dev->driver;
222 	int ret = 0;
223 
224 	if (!drv)
225 		return 0;
226 
227 	if (drv->pm) {
228 		if (drv->pm->freeze)
229 			ret = drv->pm->freeze(dev);
230 	} else {
231 		ret = amba_legacy_suspend(dev, PMSG_FREEZE);
232 	}
233 
234 	return ret;
235 }
236 
amba_pm_freeze_noirq(struct device * dev)237 static int amba_pm_freeze_noirq(struct device *dev)
238 {
239 	struct device_driver *drv = dev->driver;
240 	int ret = 0;
241 
242 	if (!drv)
243 		return 0;
244 
245 	if (drv->pm) {
246 		if (drv->pm->freeze_noirq)
247 			ret = drv->pm->freeze_noirq(dev);
248 	}
249 
250 	return ret;
251 }
252 
amba_pm_thaw(struct device * dev)253 static int amba_pm_thaw(struct device *dev)
254 {
255 	struct device_driver *drv = dev->driver;
256 	int ret = 0;
257 
258 	if (!drv)
259 		return 0;
260 
261 	if (drv->pm) {
262 		if (drv->pm->thaw)
263 			ret = drv->pm->thaw(dev);
264 	} else {
265 		ret = amba_legacy_resume(dev);
266 	}
267 
268 	return ret;
269 }
270 
amba_pm_thaw_noirq(struct device * dev)271 static int amba_pm_thaw_noirq(struct device *dev)
272 {
273 	struct device_driver *drv = dev->driver;
274 	int ret = 0;
275 
276 	if (!drv)
277 		return 0;
278 
279 	if (drv->pm) {
280 		if (drv->pm->thaw_noirq)
281 			ret = drv->pm->thaw_noirq(dev);
282 	}
283 
284 	return ret;
285 }
286 
amba_pm_poweroff(struct device * dev)287 static int amba_pm_poweroff(struct device *dev)
288 {
289 	struct device_driver *drv = dev->driver;
290 	int ret = 0;
291 
292 	if (!drv)
293 		return 0;
294 
295 	if (drv->pm) {
296 		if (drv->pm->poweroff)
297 			ret = drv->pm->poweroff(dev);
298 	} else {
299 		ret = amba_legacy_suspend(dev, PMSG_HIBERNATE);
300 	}
301 
302 	return ret;
303 }
304 
amba_pm_poweroff_noirq(struct device * dev)305 static int amba_pm_poweroff_noirq(struct device *dev)
306 {
307 	struct device_driver *drv = dev->driver;
308 	int ret = 0;
309 
310 	if (!drv)
311 		return 0;
312 
313 	if (drv->pm) {
314 		if (drv->pm->poweroff_noirq)
315 			ret = drv->pm->poweroff_noirq(dev);
316 	}
317 
318 	return ret;
319 }
320 
amba_pm_restore(struct device * dev)321 static int amba_pm_restore(struct device *dev)
322 {
323 	struct device_driver *drv = dev->driver;
324 	int ret = 0;
325 
326 	if (!drv)
327 		return 0;
328 
329 	if (drv->pm) {
330 		if (drv->pm->restore)
331 			ret = drv->pm->restore(dev);
332 	} else {
333 		ret = amba_legacy_resume(dev);
334 	}
335 
336 	return ret;
337 }
338 
amba_pm_restore_noirq(struct device * dev)339 static int amba_pm_restore_noirq(struct device *dev)
340 {
341 	struct device_driver *drv = dev->driver;
342 	int ret = 0;
343 
344 	if (!drv)
345 		return 0;
346 
347 	if (drv->pm) {
348 		if (drv->pm->restore_noirq)
349 			ret = drv->pm->restore_noirq(dev);
350 	}
351 
352 	return ret;
353 }
354 
355 #else /* !CONFIG_HIBERNATE_CALLBACKS */
356 
357 #define amba_pm_freeze		NULL
358 #define amba_pm_thaw		NULL
359 #define amba_pm_poweroff		NULL
360 #define amba_pm_restore		NULL
361 #define amba_pm_freeze_noirq	NULL
362 #define amba_pm_thaw_noirq		NULL
363 #define amba_pm_poweroff_noirq	NULL
364 #define amba_pm_restore_noirq	NULL
365 
366 #endif /* !CONFIG_HIBERNATE_CALLBACKS */
367 
368 #ifdef CONFIG_PM
369 
370 static const struct dev_pm_ops amba_pm = {
371 	.prepare	= amba_pm_prepare,
372 	.complete	= amba_pm_complete,
373 	.suspend	= amba_pm_suspend,
374 	.resume		= amba_pm_resume,
375 	.freeze		= amba_pm_freeze,
376 	.thaw		= amba_pm_thaw,
377 	.poweroff	= amba_pm_poweroff,
378 	.restore	= amba_pm_restore,
379 	.suspend_noirq	= amba_pm_suspend_noirq,
380 	.resume_noirq	= amba_pm_resume_noirq,
381 	.freeze_noirq	= amba_pm_freeze_noirq,
382 	.thaw_noirq	= amba_pm_thaw_noirq,
383 	.poweroff_noirq	= amba_pm_poweroff_noirq,
384 	.restore_noirq	= amba_pm_restore_noirq,
385 	SET_RUNTIME_PM_OPS(
386 		pm_generic_runtime_suspend,
387 		pm_generic_runtime_resume,
388 		pm_generic_runtime_idle
389 	)
390 };
391 
392 #define AMBA_PM (&amba_pm)
393 
394 #else /* !CONFIG_PM */
395 
396 #define AMBA_PM	NULL
397 
398 #endif /* !CONFIG_PM */
399 
400 /*
401  * Primecells are part of the Advanced Microcontroller Bus Architecture,
402  * so we call the bus "amba".
403  */
404 struct bus_type amba_bustype = {
405 	.name		= "amba",
406 	.dev_attrs	= amba_dev_attrs,
407 	.match		= amba_match,
408 	.uevent		= amba_uevent,
409 	.pm		= AMBA_PM,
410 };
411 
amba_init(void)412 static int __init amba_init(void)
413 {
414 	return bus_register(&amba_bustype);
415 }
416 
417 postcore_initcall(amba_init);
418 
amba_get_enable_pclk(struct amba_device * pcdev)419 static int amba_get_enable_pclk(struct amba_device *pcdev)
420 {
421 	struct clk *pclk = clk_get(&pcdev->dev, "apb_pclk");
422 	int ret;
423 
424 	pcdev->pclk = pclk;
425 
426 	if (IS_ERR(pclk))
427 		return PTR_ERR(pclk);
428 
429 	ret = clk_enable(pclk);
430 	if (ret)
431 		clk_put(pclk);
432 
433 	return ret;
434 }
435 
amba_put_disable_pclk(struct amba_device * pcdev)436 static void amba_put_disable_pclk(struct amba_device *pcdev)
437 {
438 	struct clk *pclk = pcdev->pclk;
439 
440 	clk_disable(pclk);
441 	clk_put(pclk);
442 }
443 
amba_get_enable_vcore(struct amba_device * pcdev)444 static int amba_get_enable_vcore(struct amba_device *pcdev)
445 {
446 	struct regulator *vcore = regulator_get(&pcdev->dev, "vcore");
447 	int ret;
448 
449 	pcdev->vcore = vcore;
450 
451 	if (IS_ERR(vcore)) {
452 		/* It is OK not to supply a vcore regulator */
453 		if (PTR_ERR(vcore) == -ENODEV)
454 			return 0;
455 		return PTR_ERR(vcore);
456 	}
457 
458 	ret = regulator_enable(vcore);
459 	if (ret) {
460 		regulator_put(vcore);
461 		pcdev->vcore = ERR_PTR(-ENODEV);
462 	}
463 
464 	return ret;
465 }
466 
amba_put_disable_vcore(struct amba_device * pcdev)467 static void amba_put_disable_vcore(struct amba_device *pcdev)
468 {
469 	struct regulator *vcore = pcdev->vcore;
470 
471 	if (!IS_ERR(vcore)) {
472 		regulator_disable(vcore);
473 		regulator_put(vcore);
474 	}
475 }
476 
477 /*
478  * These are the device model conversion veneers; they convert the
479  * device model structures to our more specific structures.
480  */
amba_probe(struct device * dev)481 static int amba_probe(struct device *dev)
482 {
483 	struct amba_device *pcdev = to_amba_device(dev);
484 	struct amba_driver *pcdrv = to_amba_driver(dev->driver);
485 	const struct amba_id *id = amba_lookup(pcdrv->id_table, pcdev);
486 	int ret;
487 
488 	do {
489 		ret = amba_get_enable_vcore(pcdev);
490 		if (ret)
491 			break;
492 
493 		ret = amba_get_enable_pclk(pcdev);
494 		if (ret)
495 			break;
496 
497 		ret = pcdrv->probe(pcdev, id);
498 		if (ret == 0)
499 			break;
500 
501 		amba_put_disable_pclk(pcdev);
502 		amba_put_disable_vcore(pcdev);
503 	} while (0);
504 
505 	return ret;
506 }
507 
amba_remove(struct device * dev)508 static int amba_remove(struct device *dev)
509 {
510 	struct amba_device *pcdev = to_amba_device(dev);
511 	struct amba_driver *drv = to_amba_driver(dev->driver);
512 	int ret = drv->remove(pcdev);
513 
514 	amba_put_disable_pclk(pcdev);
515 	amba_put_disable_vcore(pcdev);
516 
517 	return ret;
518 }
519 
amba_shutdown(struct device * dev)520 static void amba_shutdown(struct device *dev)
521 {
522 	struct amba_driver *drv = to_amba_driver(dev->driver);
523 	drv->shutdown(to_amba_device(dev));
524 }
525 
526 /**
527  *	amba_driver_register - register an AMBA device driver
528  *	@drv: amba device driver structure
529  *
530  *	Register an AMBA device driver with the Linux device model
531  *	core.  If devices pre-exist, the drivers probe function will
532  *	be called.
533  */
amba_driver_register(struct amba_driver * drv)534 int amba_driver_register(struct amba_driver *drv)
535 {
536 	drv->drv.bus = &amba_bustype;
537 
538 #define SETFN(fn)	if (drv->fn) drv->drv.fn = amba_##fn
539 	SETFN(probe);
540 	SETFN(remove);
541 	SETFN(shutdown);
542 
543 	return driver_register(&drv->drv);
544 }
545 
546 /**
547  *	amba_driver_unregister - remove an AMBA device driver
548  *	@drv: AMBA device driver structure to remove
549  *
550  *	Unregister an AMBA device driver from the Linux device
551  *	model.  The device model will call the drivers remove function
552  *	for each device the device driver is currently handling.
553  */
amba_driver_unregister(struct amba_driver * drv)554 void amba_driver_unregister(struct amba_driver *drv)
555 {
556 	driver_unregister(&drv->drv);
557 }
558 
559 
amba_device_release(struct device * dev)560 static void amba_device_release(struct device *dev)
561 {
562 	struct amba_device *d = to_amba_device(dev);
563 
564 	if (d->res.parent)
565 		release_resource(&d->res);
566 	kfree(d);
567 }
568 
569 /**
570  *	amba_device_register - register an AMBA device
571  *	@dev: AMBA device to register
572  *	@parent: parent memory resource
573  *
574  *	Setup the AMBA device, reading the cell ID if present.
575  *	Claim the resource, and register the AMBA device with
576  *	the Linux device manager.
577  */
amba_device_register(struct amba_device * dev,struct resource * parent)578 int amba_device_register(struct amba_device *dev, struct resource *parent)
579 {
580 	u32 size;
581 	void __iomem *tmp;
582 	int i, ret;
583 
584 	device_initialize(&dev->dev);
585 
586 	/*
587 	 * Copy from device_add
588 	 */
589 	if (dev->dev.init_name) {
590 		dev_set_name(&dev->dev, "%s", dev->dev.init_name);
591 		dev->dev.init_name = NULL;
592 	}
593 
594 	dev->dev.release = amba_device_release;
595 	dev->dev.bus = &amba_bustype;
596 	dev->dev.dma_mask = &dev->dma_mask;
597 	dev->res.name = dev_name(&dev->dev);
598 
599 	if (!dev->dev.coherent_dma_mask && dev->dma_mask)
600 		dev_warn(&dev->dev, "coherent dma mask is unset\n");
601 
602 	ret = request_resource(parent, &dev->res);
603 	if (ret)
604 		goto err_out;
605 
606 	/*
607 	 * Dynamically calculate the size of the resource
608 	 * and use this for iomap
609 	 */
610 	size = resource_size(&dev->res);
611 	tmp = ioremap(dev->res.start, size);
612 	if (!tmp) {
613 		ret = -ENOMEM;
614 		goto err_release;
615 	}
616 
617 	ret = amba_get_enable_pclk(dev);
618 	if (ret == 0) {
619 		u32 pid, cid;
620 
621 		/*
622 		 * Read pid and cid based on size of resource
623 		 * they are located at end of region
624 		 */
625 		for (pid = 0, i = 0; i < 4; i++)
626 			pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) <<
627 				(i * 8);
628 		for (cid = 0, i = 0; i < 4; i++)
629 			cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) <<
630 				(i * 8);
631 
632 		amba_put_disable_pclk(dev);
633 
634 		if (cid == AMBA_CID)
635 			dev->periphid = pid;
636 
637 		if (!dev->periphid)
638 			ret = -ENODEV;
639 	}
640 
641 	iounmap(tmp);
642 
643 	if (ret)
644 		goto err_release;
645 
646 	ret = device_add(&dev->dev);
647 	if (ret)
648 		goto err_release;
649 
650 	if (dev->irq[0] != NO_IRQ)
651 		ret = device_create_file(&dev->dev, &dev_attr_irq0);
652 	if (ret == 0 && dev->irq[1] != NO_IRQ)
653 		ret = device_create_file(&dev->dev, &dev_attr_irq1);
654 	if (ret == 0)
655 		return ret;
656 
657 	device_unregister(&dev->dev);
658 
659  err_release:
660 	release_resource(&dev->res);
661  err_out:
662 	return ret;
663 }
664 
665 /**
666  *	amba_device_unregister - unregister an AMBA device
667  *	@dev: AMBA device to remove
668  *
669  *	Remove the specified AMBA device from the Linux device
670  *	manager.  All files associated with this object will be
671  *	destroyed, and device drivers notified that the device has
672  *	been removed.  The AMBA device's resources including
673  *	the amba_device structure will be freed once all
674  *	references to it have been dropped.
675  */
amba_device_unregister(struct amba_device * dev)676 void amba_device_unregister(struct amba_device *dev)
677 {
678 	device_unregister(&dev->dev);
679 }
680 
681 
682 struct find_data {
683 	struct amba_device *dev;
684 	struct device *parent;
685 	const char *busid;
686 	unsigned int id;
687 	unsigned int mask;
688 };
689 
amba_find_match(struct device * dev,void * data)690 static int amba_find_match(struct device *dev, void *data)
691 {
692 	struct find_data *d = data;
693 	struct amba_device *pcdev = to_amba_device(dev);
694 	int r;
695 
696 	r = (pcdev->periphid & d->mask) == d->id;
697 	if (d->parent)
698 		r &= d->parent == dev->parent;
699 	if (d->busid)
700 		r &= strcmp(dev_name(dev), d->busid) == 0;
701 
702 	if (r) {
703 		get_device(dev);
704 		d->dev = pcdev;
705 	}
706 
707 	return r;
708 }
709 
710 /**
711  *	amba_find_device - locate an AMBA device given a bus id
712  *	@busid: bus id for device (or NULL)
713  *	@parent: parent device (or NULL)
714  *	@id: peripheral ID (or 0)
715  *	@mask: peripheral ID mask (or 0)
716  *
717  *	Return the AMBA device corresponding to the supplied parameters.
718  *	If no device matches, returns NULL.
719  *
720  *	NOTE: When a valid device is found, its refcount is
721  *	incremented, and must be decremented before the returned
722  *	reference.
723  */
724 struct amba_device *
amba_find_device(const char * busid,struct device * parent,unsigned int id,unsigned int mask)725 amba_find_device(const char *busid, struct device *parent, unsigned int id,
726 		 unsigned int mask)
727 {
728 	struct find_data data;
729 
730 	data.dev = NULL;
731 	data.parent = parent;
732 	data.busid = busid;
733 	data.id = id;
734 	data.mask = mask;
735 
736 	bus_for_each_dev(&amba_bustype, NULL, &data, amba_find_match);
737 
738 	return data.dev;
739 }
740 
741 /**
742  *	amba_request_regions - request all mem regions associated with device
743  *	@dev: amba_device structure for device
744  *	@name: name, or NULL to use driver name
745  */
amba_request_regions(struct amba_device * dev,const char * name)746 int amba_request_regions(struct amba_device *dev, const char *name)
747 {
748 	int ret = 0;
749 	u32 size;
750 
751 	if (!name)
752 		name = dev->dev.driver->name;
753 
754 	size = resource_size(&dev->res);
755 
756 	if (!request_mem_region(dev->res.start, size, name))
757 		ret = -EBUSY;
758 
759 	return ret;
760 }
761 
762 /**
763  *	amba_release_regions - release mem regions associated with device
764  *	@dev: amba_device structure for device
765  *
766  *	Release regions claimed by a successful call to amba_request_regions.
767  */
amba_release_regions(struct amba_device * dev)768 void amba_release_regions(struct amba_device *dev)
769 {
770 	u32 size;
771 
772 	size = resource_size(&dev->res);
773 	release_mem_region(dev->res.start, size);
774 }
775 
776 EXPORT_SYMBOL(amba_driver_register);
777 EXPORT_SYMBOL(amba_driver_unregister);
778 EXPORT_SYMBOL(amba_device_register);
779 EXPORT_SYMBOL(amba_device_unregister);
780 EXPORT_SYMBOL(amba_find_device);
781 EXPORT_SYMBOL(amba_request_regions);
782 EXPORT_SYMBOL(amba_release_regions);
783