Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * linux/arch/arm/common/amba.c
4 : : *
5 : : * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved.
6 : : */
7 : : #include <linux/module.h>
8 : : #include <linux/init.h>
9 : : #include <linux/device.h>
10 : : #include <linux/string.h>
11 : : #include <linux/slab.h>
12 : : #include <linux/io.h>
13 : : #include <linux/pm.h>
14 : : #include <linux/pm_runtime.h>
15 : : #include <linux/pm_domain.h>
16 : : #include <linux/amba/bus.h>
17 : : #include <linux/sizes.h>
18 : : #include <linux/limits.h>
19 : : #include <linux/clk/clk-conf.h>
20 : : #include <linux/platform_device.h>
21 : : #include <linux/reset.h>
22 : :
23 : : #include <asm/irq.h>
24 : :
25 : : #define to_amba_driver(d) container_of(d, struct amba_driver, drv)
26 : :
27 : : /* called on periphid match and class 0x9 coresight device. */
28 : : static int
29 : : amba_cs_uci_id_match(const struct amba_id *table, struct amba_device *dev)
30 : : {
31 : : int ret = 0;
32 : : struct amba_cs_uci_id *uci;
33 : :
34 : 0 : uci = table->data;
35 : :
36 : : /* no table data or zero mask - return match on periphid */
37 [ # # # # ]: 0 : if (!uci || (uci->devarch_mask == 0))
38 : : return 1;
39 : :
40 : : /* test against read devtype and masked devarch value */
41 [ # # # # ]: 0 : ret = (dev->uci.devtype == uci->devtype) &&
42 : 0 : ((dev->uci.devarch & uci->devarch_mask) == uci->devarch);
43 : : return ret;
44 : : }
45 : :
46 : : static const struct amba_id *
47 : 828 : amba_lookup(const struct amba_id *table, struct amba_device *dev)
48 : : {
49 [ + - ]: 1656 : while (table->mask) {
50 [ + - - + ]: 1656 : if (((dev->periphid & table->mask) == table->id) &&
51 [ # # ]: 828 : ((dev->cid != CORESIGHT_CID) ||
52 : : (amba_cs_uci_id_match(table, dev))))
53 : 828 : return table;
54 : 0 : table++;
55 : : }
56 : : return NULL;
57 : : }
58 : :
59 : 414 : static int amba_match(struct device *dev, struct device_driver *drv)
60 : : {
61 : : struct amba_device *pcdev = to_amba_device(dev);
62 : : struct amba_driver *pcdrv = to_amba_driver(drv);
63 : :
64 : : /* When driver_override is set, only bind to the matching driver */
65 [ - + ]: 414 : if (pcdev->driver_override)
66 : 0 : return !strcmp(pcdev->driver_override, drv->name);
67 : :
68 : 414 : return amba_lookup(pcdrv->id_table, pcdev) != NULL;
69 : : }
70 : :
71 : 1656 : static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
72 : : {
73 : : struct amba_device *pcdev = to_amba_device(dev);
74 : : int retval = 0;
75 : :
76 : 1656 : retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid);
77 [ + - ]: 1656 : if (retval)
78 : : return retval;
79 : :
80 : 1656 : retval = add_uevent_var(env, "MODALIAS=amba:d%08X", pcdev->periphid);
81 : 1656 : return retval;
82 : : }
83 : :
84 : 0 : static ssize_t driver_override_show(struct device *_dev,
85 : : struct device_attribute *attr, char *buf)
86 : : {
87 : : struct amba_device *dev = to_amba_device(_dev);
88 : : ssize_t len;
89 : :
90 : : device_lock(_dev);
91 : 0 : len = sprintf(buf, "%s\n", dev->driver_override);
92 : : device_unlock(_dev);
93 : 0 : return len;
94 : : }
95 : :
96 : 0 : static ssize_t driver_override_store(struct device *_dev,
97 : : struct device_attribute *attr,
98 : : const char *buf, size_t count)
99 : : {
100 : : struct amba_device *dev = to_amba_device(_dev);
101 : : char *driver_override, *old, *cp;
102 : :
103 : : /* We need to keep extra room for a newline */
104 [ # # ]: 0 : if (count >= (PAGE_SIZE - 1))
105 : : return -EINVAL;
106 : :
107 : 0 : driver_override = kstrndup(buf, count, GFP_KERNEL);
108 [ # # ]: 0 : if (!driver_override)
109 : : return -ENOMEM;
110 : :
111 : 0 : cp = strchr(driver_override, '\n');
112 [ # # ]: 0 : if (cp)
113 : 0 : *cp = '\0';
114 : :
115 : : device_lock(_dev);
116 : 0 : old = dev->driver_override;
117 [ # # ]: 0 : if (strlen(driver_override)) {
118 : 0 : dev->driver_override = driver_override;
119 : : } else {
120 : 0 : kfree(driver_override);
121 : 0 : dev->driver_override = NULL;
122 : : }
123 : : device_unlock(_dev);
124 : :
125 : 0 : kfree(old);
126 : :
127 : 0 : return count;
128 : : }
129 : : static DEVICE_ATTR_RW(driver_override);
130 : :
131 : : #define amba_attr_func(name,fmt,arg...) \
132 : : static ssize_t name##_show(struct device *_dev, \
133 : : struct device_attribute *attr, char *buf) \
134 : : { \
135 : : struct amba_device *dev = to_amba_device(_dev); \
136 : : return sprintf(buf, fmt, arg); \
137 : : } \
138 : : static DEVICE_ATTR_RO(name)
139 : :
140 : 0 : amba_attr_func(id, "%08x\n", dev->periphid);
141 : 0 : amba_attr_func(irq0, "%u\n", dev->irq[0]);
142 : 0 : amba_attr_func(irq1, "%u\n", dev->irq[1]);
143 : 0 : amba_attr_func(resource, "\t%016llx\t%016llx\t%016lx\n",
144 : : (unsigned long long)dev->res.start, (unsigned long long)dev->res.end,
145 : : dev->res.flags);
146 : :
147 : : static struct attribute *amba_dev_attrs[] = {
148 : : &dev_attr_id.attr,
149 : : &dev_attr_resource.attr,
150 : : &dev_attr_driver_override.attr,
151 : : NULL,
152 : : };
153 : : ATTRIBUTE_GROUPS(amba_dev);
154 : :
155 : : #ifdef CONFIG_PM
156 : : /*
157 : : * Hooks to provide runtime PM of the pclk (bus clock). It is safe to
158 : : * enable/disable the bus clock at runtime PM suspend/resume as this
159 : : * does not result in loss of context.
160 : : */
161 : 0 : static int amba_pm_runtime_suspend(struct device *dev)
162 : : {
163 : : struct amba_device *pcdev = to_amba_device(dev);
164 : 0 : int ret = pm_generic_runtime_suspend(dev);
165 : :
166 [ # # # # ]: 0 : if (ret == 0 && dev->driver) {
167 [ # # ]: 0 : if (pm_runtime_is_irq_safe(dev))
168 : 0 : clk_disable(pcdev->pclk);
169 : : else
170 : 0 : clk_disable_unprepare(pcdev->pclk);
171 : : }
172 : :
173 : 0 : return ret;
174 : : }
175 : :
176 : 0 : static int amba_pm_runtime_resume(struct device *dev)
177 : : {
178 : : struct amba_device *pcdev = to_amba_device(dev);
179 : : int ret;
180 : :
181 [ # # ]: 0 : if (dev->driver) {
182 [ # # ]: 0 : if (pm_runtime_is_irq_safe(dev))
183 : 0 : ret = clk_enable(pcdev->pclk);
184 : : else
185 : 0 : ret = clk_prepare_enable(pcdev->pclk);
186 : : /* Failure is probably fatal to the system, but... */
187 [ # # ]: 0 : if (ret)
188 : : return ret;
189 : : }
190 : :
191 : 0 : return pm_generic_runtime_resume(dev);
192 : : }
193 : : #endif /* CONFIG_PM */
194 : :
195 : : static const struct dev_pm_ops amba_pm = {
196 : : .suspend = pm_generic_suspend,
197 : : .resume = pm_generic_resume,
198 : : .freeze = pm_generic_freeze,
199 : : .thaw = pm_generic_thaw,
200 : : .poweroff = pm_generic_poweroff,
201 : : .restore = pm_generic_restore,
202 : : SET_RUNTIME_PM_OPS(
203 : : amba_pm_runtime_suspend,
204 : : amba_pm_runtime_resume,
205 : : NULL
206 : : )
207 : : };
208 : :
209 : : /*
210 : : * Primecells are part of the Advanced Microcontroller Bus Architecture,
211 : : * so we call the bus "amba".
212 : : * DMA configuration for platform and AMBA bus is same. So here we reuse
213 : : * platform's DMA config routine.
214 : : */
215 : : struct bus_type amba_bustype = {
216 : : .name = "amba",
217 : : .dev_groups = amba_dev_groups,
218 : : .match = amba_match,
219 : : .uevent = amba_uevent,
220 : : .dma_configure = platform_dma_configure,
221 : : .pm = &amba_pm,
222 : : };
223 : : EXPORT_SYMBOL_GPL(amba_bustype);
224 : :
225 : 207 : static int __init amba_init(void)
226 : : {
227 : 207 : return bus_register(&amba_bustype);
228 : : }
229 : :
230 : : postcore_initcall(amba_init);
231 : :
232 : 414 : static int amba_get_enable_pclk(struct amba_device *pcdev)
233 : : {
234 : : int ret;
235 : :
236 : 414 : pcdev->pclk = clk_get(&pcdev->dev, "apb_pclk");
237 [ + + ]: 414 : if (IS_ERR(pcdev->pclk))
238 : 207 : return PTR_ERR(pcdev->pclk);
239 : :
240 : 207 : ret = clk_prepare_enable(pcdev->pclk);
241 [ - + ]: 207 : if (ret)
242 : 0 : clk_put(pcdev->pclk);
243 : :
244 : 207 : return ret;
245 : : }
246 : :
247 : 0 : static void amba_put_disable_pclk(struct amba_device *pcdev)
248 : : {
249 : 0 : clk_disable_unprepare(pcdev->pclk);
250 : 0 : clk_put(pcdev->pclk);
251 : 0 : }
252 : :
253 : : /*
254 : : * These are the device model conversion veneers; they convert the
255 : : * device model structures to our more specific structures.
256 : : */
257 : 414 : static int amba_probe(struct device *dev)
258 : : {
259 : : struct amba_device *pcdev = to_amba_device(dev);
260 : 414 : struct amba_driver *pcdrv = to_amba_driver(dev->driver);
261 : 414 : const struct amba_id *id = amba_lookup(pcdrv->id_table, pcdev);
262 : : int ret;
263 : :
264 : : do {
265 : 414 : ret = of_clk_set_defaults(dev->of_node, false);
266 [ + - ]: 414 : if (ret < 0)
267 : : break;
268 : :
269 : 414 : ret = dev_pm_domain_attach(dev, true);
270 [ + - ]: 414 : if (ret)
271 : : break;
272 : :
273 : 414 : ret = amba_get_enable_pclk(pcdev);
274 [ + + ]: 414 : if (ret) {
275 : 207 : dev_pm_domain_detach(dev, true);
276 : 207 : break;
277 : : }
278 : :
279 : : pm_runtime_get_noresume(dev);
280 : : pm_runtime_set_active(dev);
281 : 207 : pm_runtime_enable(dev);
282 : :
283 : 207 : ret = pcdrv->probe(pcdev, id);
284 [ - + ]: 207 : if (ret == 0)
285 : : break;
286 : :
287 : : pm_runtime_disable(dev);
288 : : pm_runtime_set_suspended(dev);
289 : : pm_runtime_put_noidle(dev);
290 : :
291 : 0 : amba_put_disable_pclk(pcdev);
292 : 0 : dev_pm_domain_detach(dev, true);
293 : : } while (0);
294 : :
295 : 414 : return ret;
296 : : }
297 : :
298 : 0 : static int amba_remove(struct device *dev)
299 : : {
300 : : struct amba_device *pcdev = to_amba_device(dev);
301 : 0 : struct amba_driver *drv = to_amba_driver(dev->driver);
302 : : int ret;
303 : :
304 : : pm_runtime_get_sync(dev);
305 : 0 : ret = drv->remove(pcdev);
306 : : pm_runtime_put_noidle(dev);
307 : :
308 : : /* Undo the runtime PM settings in amba_probe() */
309 : : pm_runtime_disable(dev);
310 : : pm_runtime_set_suspended(dev);
311 : : pm_runtime_put_noidle(dev);
312 : :
313 : 0 : amba_put_disable_pclk(pcdev);
314 : 0 : dev_pm_domain_detach(dev, true);
315 : :
316 : 0 : return ret;
317 : : }
318 : :
319 : 0 : static void amba_shutdown(struct device *dev)
320 : : {
321 : 0 : struct amba_driver *drv = to_amba_driver(dev->driver);
322 : 0 : drv->shutdown(to_amba_device(dev));
323 : 0 : }
324 : :
325 : : /**
326 : : * amba_driver_register - register an AMBA device driver
327 : : * @drv: amba device driver structure
328 : : *
329 : : * Register an AMBA device driver with the Linux device model
330 : : * core. If devices pre-exist, the drivers probe function will
331 : : * be called.
332 : : */
333 : 207 : int amba_driver_register(struct amba_driver *drv)
334 : : {
335 : 207 : drv->drv.bus = &amba_bustype;
336 : :
337 : : #define SETFN(fn) if (drv->fn) drv->drv.fn = amba_##fn
338 [ + - ]: 207 : SETFN(probe);
339 [ + - ]: 207 : SETFN(remove);
340 [ - + ]: 207 : SETFN(shutdown);
341 : :
342 : 207 : return driver_register(&drv->drv);
343 : : }
344 : :
345 : : /**
346 : : * amba_driver_unregister - remove an AMBA device driver
347 : : * @drv: AMBA device driver structure to remove
348 : : *
349 : : * Unregister an AMBA device driver from the Linux device
350 : : * model. The device model will call the drivers remove function
351 : : * for each device the device driver is currently handling.
352 : : */
353 : 0 : void amba_driver_unregister(struct amba_driver *drv)
354 : : {
355 : 0 : driver_unregister(&drv->drv);
356 : 0 : }
357 : :
358 : :
359 : 0 : static void amba_device_release(struct device *dev)
360 : : {
361 : : struct amba_device *d = to_amba_device(dev);
362 : :
363 [ # # ]: 0 : if (d->res.parent)
364 : 0 : release_resource(&d->res);
365 : 0 : kfree(d);
366 : 0 : }
367 : :
368 : 207 : static int amba_device_try_add(struct amba_device *dev, struct resource *parent)
369 : : {
370 : : u32 size;
371 : : void __iomem *tmp;
372 : : int i, ret;
373 : :
374 [ - + ]: 207 : WARN_ON(dev->irq[0] == (unsigned int)-1);
375 [ - + ]: 207 : WARN_ON(dev->irq[1] == (unsigned int)-1);
376 : :
377 : 207 : ret = request_resource(parent, &dev->res);
378 [ + - ]: 207 : if (ret)
379 : : goto err_out;
380 : :
381 : : /* Hard-coded primecell ID instead of plug-n-play */
382 [ - + ]: 207 : if (dev->periphid != 0)
383 : : goto skip_probe;
384 : :
385 : : /*
386 : : * Dynamically calculate the size of the resource
387 : : * and use this for iomap
388 : : */
389 : : size = resource_size(&dev->res);
390 : 0 : tmp = ioremap(dev->res.start, size);
391 [ # # ]: 0 : if (!tmp) {
392 : : ret = -ENOMEM;
393 : : goto err_release;
394 : : }
395 : :
396 : 0 : ret = dev_pm_domain_attach(&dev->dev, true);
397 [ # # ]: 0 : if (ret) {
398 : 0 : iounmap(tmp);
399 : 0 : goto err_release;
400 : : }
401 : :
402 : 0 : ret = amba_get_enable_pclk(dev);
403 [ # # ]: 0 : if (ret == 0) {
404 : : u32 pid, cid;
405 : : struct reset_control *rstc;
406 : :
407 : : /*
408 : : * Find reset control(s) of the amba bus and de-assert them.
409 : : */
410 : 0 : rstc = of_reset_control_array_get_optional_shared(dev->dev.of_node);
411 [ # # ]: 0 : if (IS_ERR(rstc)) {
412 : : ret = PTR_ERR(rstc);
413 [ # # ]: 0 : if (ret != -EPROBE_DEFER)
414 : 0 : dev_err(&dev->dev, "can't get reset: %d\n",
415 : : ret);
416 : : goto err_reset;
417 : : }
418 : 0 : reset_control_deassert(rstc);
419 : 0 : reset_control_put(rstc);
420 : :
421 : : /*
422 : : * Read pid and cid based on size of resource
423 : : * they are located at end of region
424 : : */
425 [ # # ]: 0 : for (pid = 0, i = 0; i < 4; i++)
426 : 0 : pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) <<
427 : 0 : (i * 8);
428 [ # # ]: 0 : for (cid = 0, i = 0; i < 4; i++)
429 : 0 : cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) <<
430 : 0 : (i * 8);
431 : :
432 [ # # ]: 0 : if (cid == CORESIGHT_CID) {
433 : : /* set the base to the start of the last 4k block */
434 : 0 : void __iomem *csbase = tmp + size - 4096;
435 : :
436 : 0 : dev->uci.devarch =
437 : 0 : readl(csbase + UCI_REG_DEVARCH_OFFSET);
438 : 0 : dev->uci.devtype =
439 : 0 : readl(csbase + UCI_REG_DEVTYPE_OFFSET) & 0xff;
440 : : }
441 : :
442 : 0 : amba_put_disable_pclk(dev);
443 : :
444 [ # # ]: 0 : if (cid == AMBA_CID || cid == CORESIGHT_CID) {
445 : 0 : dev->periphid = pid;
446 : 0 : dev->cid = cid;
447 : : }
448 : :
449 [ # # ]: 0 : if (!dev->periphid)
450 : : ret = -ENODEV;
451 : : }
452 : :
453 : 0 : iounmap(tmp);
454 : 0 : dev_pm_domain_detach(&dev->dev, true);
455 : :
456 [ # # ]: 0 : if (ret)
457 : : goto err_release;
458 : :
459 : : skip_probe:
460 : 207 : ret = device_add(&dev->dev);
461 [ + - ]: 207 : if (ret)
462 : : goto err_release;
463 : :
464 [ + - ]: 207 : if (dev->irq[0])
465 : 207 : ret = device_create_file(&dev->dev, &dev_attr_irq0);
466 [ + - - + ]: 207 : if (ret == 0 && dev->irq[1])
467 : 0 : ret = device_create_file(&dev->dev, &dev_attr_irq1);
468 [ - + ]: 207 : if (ret == 0)
469 : : return ret;
470 : :
471 : 0 : device_unregister(&dev->dev);
472 : :
473 : : err_release:
474 : 0 : release_resource(&dev->res);
475 : : err_out:
476 : 0 : return ret;
477 : :
478 : : err_reset:
479 : 0 : amba_put_disable_pclk(dev);
480 : 0 : iounmap(tmp);
481 : 0 : dev_pm_domain_detach(&dev->dev, true);
482 : 0 : goto err_release;
483 : : }
484 : :
485 : : /*
486 : : * Registration of AMBA device require reading its pid and cid registers.
487 : : * To do this, the device must be turned on (if it is a part of power domain)
488 : : * and have clocks enabled. However in some cases those resources might not be
489 : : * yet available. Returning EPROBE_DEFER is not a solution in such case,
490 : : * because callers don't handle this special error code. Instead such devices
491 : : * are added to the special list and their registration is retried from
492 : : * periodic worker, until all resources are available and registration succeeds.
493 : : */
494 : : struct deferred_device {
495 : : struct amba_device *dev;
496 : : struct resource *parent;
497 : : struct list_head node;
498 : : };
499 : :
500 : : static LIST_HEAD(deferred_devices);
501 : : static DEFINE_MUTEX(deferred_devices_lock);
502 : :
503 : : static void amba_deferred_retry_func(struct work_struct *dummy);
504 : : static DECLARE_DELAYED_WORK(deferred_retry_work, amba_deferred_retry_func);
505 : :
506 : : #define DEFERRED_DEVICE_TIMEOUT (msecs_to_jiffies(5 * 1000))
507 : :
508 : 0 : static void amba_deferred_retry_func(struct work_struct *dummy)
509 : : {
510 : : struct deferred_device *ddev, *tmp;
511 : :
512 : 0 : mutex_lock(&deferred_devices_lock);
513 : :
514 [ # # ]: 0 : list_for_each_entry_safe(ddev, tmp, &deferred_devices, node) {
515 : 0 : int ret = amba_device_try_add(ddev->dev, ddev->parent);
516 : :
517 [ # # ]: 0 : if (ret == -EPROBE_DEFER)
518 : 0 : continue;
519 : :
520 : : list_del_init(&ddev->node);
521 : 0 : kfree(ddev);
522 : : }
523 : :
524 [ # # ]: 0 : if (!list_empty(&deferred_devices))
525 : : schedule_delayed_work(&deferred_retry_work,
526 : : DEFERRED_DEVICE_TIMEOUT);
527 : :
528 : 0 : mutex_unlock(&deferred_devices_lock);
529 : 0 : }
530 : :
531 : : /**
532 : : * amba_device_add - add a previously allocated AMBA device structure
533 : : * @dev: AMBA device allocated by amba_device_alloc
534 : : * @parent: resource parent for this devices resources
535 : : *
536 : : * Claim the resource, and read the device cell ID if not already
537 : : * initialized. Register the AMBA device with the Linux device
538 : : * manager.
539 : : */
540 : 207 : int amba_device_add(struct amba_device *dev, struct resource *parent)
541 : : {
542 : 207 : int ret = amba_device_try_add(dev, parent);
543 : :
544 [ - + ]: 207 : if (ret == -EPROBE_DEFER) {
545 : : struct deferred_device *ddev;
546 : :
547 : : ddev = kmalloc(sizeof(*ddev), GFP_KERNEL);
548 [ # # ]: 0 : if (!ddev)
549 : : return -ENOMEM;
550 : :
551 : 0 : ddev->dev = dev;
552 : 0 : ddev->parent = parent;
553 : : ret = 0;
554 : :
555 : 0 : mutex_lock(&deferred_devices_lock);
556 : :
557 [ # # ]: 0 : if (list_empty(&deferred_devices))
558 : : schedule_delayed_work(&deferred_retry_work,
559 : : DEFERRED_DEVICE_TIMEOUT);
560 : 0 : list_add_tail(&ddev->node, &deferred_devices);
561 : :
562 : 0 : mutex_unlock(&deferred_devices_lock);
563 : : }
564 : 207 : return ret;
565 : : }
566 : : EXPORT_SYMBOL_GPL(amba_device_add);
567 : :
568 : : static struct amba_device *
569 : 0 : amba_aphb_device_add(struct device *parent, const char *name,
570 : : resource_size_t base, size_t size, int irq1, int irq2,
571 : : void *pdata, unsigned int periphid, u64 dma_mask,
572 : : struct resource *resbase)
573 : : {
574 : : struct amba_device *dev;
575 : : int ret;
576 : :
577 : 0 : dev = amba_device_alloc(name, base, size);
578 [ # # ]: 0 : if (!dev)
579 : : return ERR_PTR(-ENOMEM);
580 : :
581 : 0 : dev->dev.coherent_dma_mask = dma_mask;
582 : 0 : dev->irq[0] = irq1;
583 : 0 : dev->irq[1] = irq2;
584 : 0 : dev->periphid = periphid;
585 : 0 : dev->dev.platform_data = pdata;
586 : 0 : dev->dev.parent = parent;
587 : :
588 : 0 : ret = amba_device_add(dev, resbase);
589 [ # # ]: 0 : if (ret) {
590 : : amba_device_put(dev);
591 : 0 : return ERR_PTR(ret);
592 : : }
593 : :
594 : : return dev;
595 : : }
596 : :
597 : : struct amba_device *
598 : 0 : amba_apb_device_add(struct device *parent, const char *name,
599 : : resource_size_t base, size_t size, int irq1, int irq2,
600 : : void *pdata, unsigned int periphid)
601 : : {
602 : 0 : return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata,
603 : : periphid, 0, &iomem_resource);
604 : : }
605 : : EXPORT_SYMBOL_GPL(amba_apb_device_add);
606 : :
607 : : struct amba_device *
608 : 0 : amba_ahb_device_add(struct device *parent, const char *name,
609 : : resource_size_t base, size_t size, int irq1, int irq2,
610 : : void *pdata, unsigned int periphid)
611 : : {
612 : 0 : return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata,
613 : : periphid, ~0ULL, &iomem_resource);
614 : : }
615 : : EXPORT_SYMBOL_GPL(amba_ahb_device_add);
616 : :
617 : : struct amba_device *
618 : 0 : amba_apb_device_add_res(struct device *parent, const char *name,
619 : : resource_size_t base, size_t size, int irq1,
620 : : int irq2, void *pdata, unsigned int periphid,
621 : : struct resource *resbase)
622 : : {
623 : 0 : return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata,
624 : : periphid, 0, resbase);
625 : : }
626 : : EXPORT_SYMBOL_GPL(amba_apb_device_add_res);
627 : :
628 : : struct amba_device *
629 : 0 : amba_ahb_device_add_res(struct device *parent, const char *name,
630 : : resource_size_t base, size_t size, int irq1,
631 : : int irq2, void *pdata, unsigned int periphid,
632 : : struct resource *resbase)
633 : : {
634 : 0 : return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata,
635 : : periphid, ~0ULL, resbase);
636 : : }
637 : : EXPORT_SYMBOL_GPL(amba_ahb_device_add_res);
638 : :
639 : :
640 : 207 : static void amba_device_initialize(struct amba_device *dev, const char *name)
641 : : {
642 : 207 : device_initialize(&dev->dev);
643 [ - + ]: 207 : if (name)
644 : 0 : dev_set_name(&dev->dev, "%s", name);
645 : 207 : dev->dev.release = amba_device_release;
646 : 207 : dev->dev.bus = &amba_bustype;
647 : 207 : dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
648 : 207 : dev->res.name = dev_name(&dev->dev);
649 : 207 : }
650 : :
651 : : /**
652 : : * amba_device_alloc - allocate an AMBA device
653 : : * @name: sysfs name of the AMBA device
654 : : * @base: base of AMBA device
655 : : * @size: size of AMBA device
656 : : *
657 : : * Allocate and initialize an AMBA device structure. Returns %NULL
658 : : * on failure.
659 : : */
660 : 207 : struct amba_device *amba_device_alloc(const char *name, resource_size_t base,
661 : : size_t size)
662 : : {
663 : : struct amba_device *dev;
664 : :
665 : 207 : dev = kzalloc(sizeof(*dev), GFP_KERNEL);
666 [ + - ]: 207 : if (dev) {
667 : 207 : amba_device_initialize(dev, name);
668 : 207 : dev->res.start = base;
669 : 207 : dev->res.end = base + size - 1;
670 : 207 : dev->res.flags = IORESOURCE_MEM;
671 : : }
672 : :
673 : 207 : return dev;
674 : : }
675 : : EXPORT_SYMBOL_GPL(amba_device_alloc);
676 : :
677 : : /**
678 : : * amba_device_register - register an AMBA device
679 : : * @dev: AMBA device to register
680 : : * @parent: parent memory resource
681 : : *
682 : : * Setup the AMBA device, reading the cell ID if present.
683 : : * Claim the resource, and register the AMBA device with
684 : : * the Linux device manager.
685 : : */
686 : 0 : int amba_device_register(struct amba_device *dev, struct resource *parent)
687 : : {
688 : 0 : amba_device_initialize(dev, dev->dev.init_name);
689 : 0 : dev->dev.init_name = NULL;
690 : :
691 : 0 : return amba_device_add(dev, parent);
692 : : }
693 : :
694 : : /**
695 : : * amba_device_put - put an AMBA device
696 : : * @dev: AMBA device to put
697 : : */
698 : 0 : void amba_device_put(struct amba_device *dev)
699 : : {
700 : 0 : put_device(&dev->dev);
701 : 0 : }
702 : : EXPORT_SYMBOL_GPL(amba_device_put);
703 : :
704 : : /**
705 : : * amba_device_unregister - unregister an AMBA device
706 : : * @dev: AMBA device to remove
707 : : *
708 : : * Remove the specified AMBA device from the Linux device
709 : : * manager. All files associated with this object will be
710 : : * destroyed, and device drivers notified that the device has
711 : : * been removed. The AMBA device's resources including
712 : : * the amba_device structure will be freed once all
713 : : * references to it have been dropped.
714 : : */
715 : 0 : void amba_device_unregister(struct amba_device *dev)
716 : : {
717 : 0 : device_unregister(&dev->dev);
718 : 0 : }
719 : :
720 : :
721 : : struct find_data {
722 : : struct amba_device *dev;
723 : : struct device *parent;
724 : : const char *busid;
725 : : unsigned int id;
726 : : unsigned int mask;
727 : : };
728 : :
729 : 0 : static int amba_find_match(struct device *dev, void *data)
730 : : {
731 : : struct find_data *d = data;
732 : : struct amba_device *pcdev = to_amba_device(dev);
733 : : int r;
734 : :
735 : 0 : r = (pcdev->periphid & d->mask) == d->id;
736 [ # # ]: 0 : if (d->parent)
737 : 0 : r &= d->parent == dev->parent;
738 [ # # ]: 0 : if (d->busid)
739 : 0 : r &= strcmp(dev_name(dev), d->busid) == 0;
740 : :
741 [ # # ]: 0 : if (r) {
742 : 0 : get_device(dev);
743 : 0 : d->dev = pcdev;
744 : : }
745 : :
746 : 0 : return r;
747 : : }
748 : :
749 : : /**
750 : : * amba_find_device - locate an AMBA device given a bus id
751 : : * @busid: bus id for device (or NULL)
752 : : * @parent: parent device (or NULL)
753 : : * @id: peripheral ID (or 0)
754 : : * @mask: peripheral ID mask (or 0)
755 : : *
756 : : * Return the AMBA device corresponding to the supplied parameters.
757 : : * If no device matches, returns NULL.
758 : : *
759 : : * NOTE: When a valid device is found, its refcount is
760 : : * incremented, and must be decremented before the returned
761 : : * reference.
762 : : */
763 : : struct amba_device *
764 : 0 : amba_find_device(const char *busid, struct device *parent, unsigned int id,
765 : : unsigned int mask)
766 : : {
767 : : struct find_data data;
768 : :
769 : 0 : data.dev = NULL;
770 : 0 : data.parent = parent;
771 : 0 : data.busid = busid;
772 : 0 : data.id = id;
773 : 0 : data.mask = mask;
774 : :
775 : 0 : bus_for_each_dev(&amba_bustype, NULL, &data, amba_find_match);
776 : :
777 : 0 : return data.dev;
778 : : }
779 : :
780 : : /**
781 : : * amba_request_regions - request all mem regions associated with device
782 : : * @dev: amba_device structure for device
783 : : * @name: name, or NULL to use driver name
784 : : */
785 : 0 : int amba_request_regions(struct amba_device *dev, const char *name)
786 : : {
787 : : int ret = 0;
788 : : u32 size;
789 : :
790 [ # # ]: 0 : if (!name)
791 : 0 : name = dev->dev.driver->name;
792 : :
793 : : size = resource_size(&dev->res);
794 : :
795 [ # # ]: 0 : if (!request_mem_region(dev->res.start, size, name))
796 : : ret = -EBUSY;
797 : :
798 : 0 : return ret;
799 : : }
800 : :
801 : : /**
802 : : * amba_release_regions - release mem regions associated with device
803 : : * @dev: amba_device structure for device
804 : : *
805 : : * Release regions claimed by a successful call to amba_request_regions.
806 : : */
807 : 0 : void amba_release_regions(struct amba_device *dev)
808 : : {
809 : : u32 size;
810 : :
811 : : size = resource_size(&dev->res);
812 : 0 : release_mem_region(dev->res.start, size);
813 : 0 : }
814 : :
815 : : EXPORT_SYMBOL(amba_driver_register);
816 : : EXPORT_SYMBOL(amba_driver_unregister);
817 : : EXPORT_SYMBOL(amba_device_register);
818 : : EXPORT_SYMBOL(amba_device_unregister);
819 : : EXPORT_SYMBOL(amba_find_device);
820 : : EXPORT_SYMBOL(amba_request_regions);
821 : : EXPORT_SYMBOL(amba_release_regions);
|