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