1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * linux/arch/arm/common/amba.c 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved. 61da177e4SLinus Torvalds */ 71da177e4SLinus Torvalds #include <linux/module.h> 81da177e4SLinus Torvalds #include <linux/init.h> 91da177e4SLinus Torvalds #include <linux/device.h> 104e57b681STim Schmielau #include <linux/string.h> 114e57b681STim Schmielau #include <linux/slab.h> 12934848daSRussell King #include <linux/io.h> 13ba74ec7fSRabin Vincent #include <linux/pm.h> 14ba74ec7fSRabin Vincent #include <linux/pm_runtime.h> 15f48c767cSUlf Hansson #include <linux/pm_domain.h> 16a62c80e5SRussell King #include <linux/amba/bus.h> 17a875cfbbSAlessandro Rubini #include <linux/sizes.h> 183cf38571SAntonios Motakis #include <linux/limits.h> 19bcd3006fSStephen Boyd #include <linux/clk/clk-conf.h> 2007397df2SNipun Gupta #include <linux/platform_device.h> 2179bdcb20SDINH L NGUYEN #include <linux/reset.h> 221da177e4SLinus Torvalds 23934848daSRussell King #include <asm/irq.h> 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds #define to_amba_driver(d) container_of(d, struct amba_driver, drv) 261da177e4SLinus Torvalds 274a2910faSMike Leach /* called on periphid match and class 0x9 coresight device. */ 284a2910faSMike Leach static int 294a2910faSMike Leach amba_cs_uci_id_match(const struct amba_id *table, struct amba_device *dev) 304a2910faSMike Leach { 314a2910faSMike Leach int ret = 0; 324a2910faSMike Leach struct amba_cs_uci_id *uci; 334a2910faSMike Leach 344a2910faSMike Leach uci = table->data; 354a2910faSMike Leach 364a2910faSMike Leach /* no table data or zero mask - return match on periphid */ 374a2910faSMike Leach if (!uci || (uci->devarch_mask == 0)) 384a2910faSMike Leach return 1; 394a2910faSMike Leach 404a2910faSMike Leach /* test against read devtype and masked devarch value */ 414a2910faSMike Leach ret = (dev->uci.devtype == uci->devtype) && 424a2910faSMike Leach ((dev->uci.devarch & uci->devarch_mask) == uci->devarch); 434a2910faSMike Leach return ret; 444a2910faSMike Leach } 454a2910faSMike Leach 46c862aab0SRussell King static const struct amba_id * 47c862aab0SRussell King amba_lookup(const struct amba_id *table, struct amba_device *dev) 481da177e4SLinus Torvalds { 491da177e4SLinus Torvalds while (table->mask) { 504a2910faSMike Leach if (((dev->periphid & table->mask) == table->id) && 514a2910faSMike Leach ((dev->cid != CORESIGHT_CID) || 524a2910faSMike Leach (amba_cs_uci_id_match(table, dev)))) 534a2910faSMike Leach return table; 541da177e4SLinus Torvalds table++; 551da177e4SLinus Torvalds } 564a2910faSMike Leach return NULL; 571da177e4SLinus Torvalds } 581da177e4SLinus Torvalds 595150a8f0SUwe Kleine-König static int amba_get_enable_pclk(struct amba_device *pcdev) 601da177e4SLinus Torvalds { 615150a8f0SUwe Kleine-König int ret; 621da177e4SLinus Torvalds 635150a8f0SUwe Kleine-König pcdev->pclk = clk_get(&pcdev->dev, "apb_pclk"); 645150a8f0SUwe Kleine-König if (IS_ERR(pcdev->pclk)) 655150a8f0SUwe Kleine-König return PTR_ERR(pcdev->pclk); 663cf38571SAntonios Motakis 675150a8f0SUwe Kleine-König ret = clk_prepare_enable(pcdev->pclk); 685150a8f0SUwe Kleine-König if (ret) 695150a8f0SUwe Kleine-König clk_put(pcdev->pclk); 705150a8f0SUwe Kleine-König 715150a8f0SUwe Kleine-König return ret; 721da177e4SLinus Torvalds } 731da177e4SLinus Torvalds 745150a8f0SUwe Kleine-König static void amba_put_disable_pclk(struct amba_device *pcdev) 751da177e4SLinus Torvalds { 765150a8f0SUwe Kleine-König clk_disable_unprepare(pcdev->pclk); 775150a8f0SUwe Kleine-König clk_put(pcdev->pclk); 781da177e4SLinus Torvalds } 791da177e4SLinus Torvalds 805150a8f0SUwe Kleine-König 813cf38571SAntonios Motakis static ssize_t driver_override_show(struct device *_dev, 823cf38571SAntonios Motakis struct device_attribute *attr, char *buf) 833cf38571SAntonios Motakis { 843cf38571SAntonios Motakis struct amba_device *dev = to_amba_device(_dev); 856a7228d9SGeert Uytterhoeven ssize_t len; 863cf38571SAntonios Motakis 876a7228d9SGeert Uytterhoeven device_lock(_dev); 886a7228d9SGeert Uytterhoeven len = sprintf(buf, "%s\n", dev->driver_override); 896a7228d9SGeert Uytterhoeven device_unlock(_dev); 906a7228d9SGeert Uytterhoeven return len; 913cf38571SAntonios Motakis } 923cf38571SAntonios Motakis 933cf38571SAntonios Motakis static ssize_t driver_override_store(struct device *_dev, 943cf38571SAntonios Motakis struct device_attribute *attr, 953cf38571SAntonios Motakis const char *buf, size_t count) 963cf38571SAntonios Motakis { 973cf38571SAntonios Motakis struct amba_device *dev = to_amba_device(_dev); 986a7228d9SGeert Uytterhoeven char *driver_override, *old, *cp; 993cf38571SAntonios Motakis 100d2ffed51SGeert Uytterhoeven /* We need to keep extra room for a newline */ 101d2ffed51SGeert Uytterhoeven if (count >= (PAGE_SIZE - 1)) 1023cf38571SAntonios Motakis return -EINVAL; 1033cf38571SAntonios Motakis 1043cf38571SAntonios Motakis driver_override = kstrndup(buf, count, GFP_KERNEL); 1053cf38571SAntonios Motakis if (!driver_override) 1063cf38571SAntonios Motakis return -ENOMEM; 1073cf38571SAntonios Motakis 1083cf38571SAntonios Motakis cp = strchr(driver_override, '\n'); 1093cf38571SAntonios Motakis if (cp) 1103cf38571SAntonios Motakis *cp = '\0'; 1113cf38571SAntonios Motakis 1126a7228d9SGeert Uytterhoeven device_lock(_dev); 1136a7228d9SGeert Uytterhoeven old = dev->driver_override; 1143cf38571SAntonios Motakis if (strlen(driver_override)) { 1153cf38571SAntonios Motakis dev->driver_override = driver_override; 1163cf38571SAntonios Motakis } else { 1173cf38571SAntonios Motakis kfree(driver_override); 1183cf38571SAntonios Motakis dev->driver_override = NULL; 1193cf38571SAntonios Motakis } 1206a7228d9SGeert Uytterhoeven device_unlock(_dev); 1213cf38571SAntonios Motakis 1223cf38571SAntonios Motakis kfree(old); 1233cf38571SAntonios Motakis 1243cf38571SAntonios Motakis return count; 1253cf38571SAntonios Motakis } 126966449a3SGreg Kroah-Hartman static DEVICE_ATTR_RW(driver_override); 1273cf38571SAntonios Motakis 12896b13f5cSRussell King #define amba_attr_func(name,fmt,arg...) \ 12996b13f5cSRussell King static ssize_t name##_show(struct device *_dev, \ 13096b13f5cSRussell King struct device_attribute *attr, char *buf) \ 13196b13f5cSRussell King { \ 13296b13f5cSRussell King struct amba_device *dev = to_amba_device(_dev); \ 13396b13f5cSRussell King return sprintf(buf, fmt, arg); \ 134966449a3SGreg Kroah-Hartman } \ 135966449a3SGreg Kroah-Hartman static DEVICE_ATTR_RO(name) 13696b13f5cSRussell King 13796b13f5cSRussell King amba_attr_func(id, "%08x\n", dev->periphid); 138966449a3SGreg Kroah-Hartman amba_attr_func(irq0, "%u\n", dev->irq[0]); 139966449a3SGreg Kroah-Hartman amba_attr_func(irq1, "%u\n", dev->irq[1]); 14096b13f5cSRussell King amba_attr_func(resource, "\t%016llx\t%016llx\t%016lx\n", 14196b13f5cSRussell King (unsigned long long)dev->res.start, (unsigned long long)dev->res.end, 14296b13f5cSRussell King dev->res.flags); 14396b13f5cSRussell King 144966449a3SGreg Kroah-Hartman static struct attribute *amba_dev_attrs[] = { 145966449a3SGreg Kroah-Hartman &dev_attr_id.attr, 146966449a3SGreg Kroah-Hartman &dev_attr_resource.attr, 147966449a3SGreg Kroah-Hartman &dev_attr_driver_override.attr, 148966449a3SGreg Kroah-Hartman NULL, 14996b13f5cSRussell King }; 150966449a3SGreg Kroah-Hartman ATTRIBUTE_GROUPS(amba_dev); 15196b13f5cSRussell King 1525150a8f0SUwe Kleine-König static int amba_match(struct device *dev, struct device_driver *drv) 1535150a8f0SUwe Kleine-König { 1545150a8f0SUwe Kleine-König struct amba_device *pcdev = to_amba_device(dev); 1555150a8f0SUwe Kleine-König struct amba_driver *pcdrv = to_amba_driver(drv); 1565150a8f0SUwe Kleine-König 1575150a8f0SUwe Kleine-König /* When driver_override is set, only bind to the matching driver */ 1585150a8f0SUwe Kleine-König if (pcdev->driver_override) 1595150a8f0SUwe Kleine-König return !strcmp(pcdev->driver_override, drv->name); 1605150a8f0SUwe Kleine-König 1615150a8f0SUwe Kleine-König return amba_lookup(pcdrv->id_table, pcdev) != NULL; 1625150a8f0SUwe Kleine-König } 1635150a8f0SUwe Kleine-König 1645150a8f0SUwe Kleine-König static int amba_uevent(struct device *dev, struct kobj_uevent_env *env) 1655150a8f0SUwe Kleine-König { 1665150a8f0SUwe Kleine-König struct amba_device *pcdev = to_amba_device(dev); 1675150a8f0SUwe Kleine-König int retval = 0; 1685150a8f0SUwe Kleine-König 1695150a8f0SUwe Kleine-König retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid); 1705150a8f0SUwe Kleine-König if (retval) 1715150a8f0SUwe Kleine-König return retval; 1725150a8f0SUwe Kleine-König 1735150a8f0SUwe Kleine-König retval = add_uevent_var(env, "MODALIAS=amba:d%08X", pcdev->periphid); 1745150a8f0SUwe Kleine-König return retval; 1755150a8f0SUwe Kleine-König } 1765150a8f0SUwe Kleine-König 1771da177e4SLinus Torvalds /* 1781da177e4SLinus Torvalds * These are the device model conversion veneers; they convert the 1791da177e4SLinus Torvalds * device model structures to our more specific structures. 1801da177e4SLinus Torvalds */ 1811da177e4SLinus Torvalds static int amba_probe(struct device *dev) 1821da177e4SLinus Torvalds { 1831da177e4SLinus Torvalds struct amba_device *pcdev = to_amba_device(dev); 1841da177e4SLinus Torvalds struct amba_driver *pcdrv = to_amba_driver(dev->driver); 185c862aab0SRussell King const struct amba_id *id = amba_lookup(pcdrv->id_table, pcdev); 1867cfe2494SRussell King int ret; 1871da177e4SLinus Torvalds 1887cfe2494SRussell King do { 189bcd3006fSStephen Boyd ret = of_clk_set_defaults(dev->of_node, false); 190bcd3006fSStephen Boyd if (ret < 0) 191bcd3006fSStephen Boyd break; 192bcd3006fSStephen Boyd 193207f1a2dSUlf Hansson ret = dev_pm_domain_attach(dev, true); 194d21bc89eSUlf Hansson if (ret) 1957cfe2494SRussell King break; 1961da177e4SLinus Torvalds 197207f1a2dSUlf Hansson ret = amba_get_enable_pclk(pcdev); 198207f1a2dSUlf Hansson if (ret) { 199207f1a2dSUlf Hansson dev_pm_domain_detach(dev, true); 200207f1a2dSUlf Hansson break; 201207f1a2dSUlf Hansson } 202207f1a2dSUlf Hansson 20392b97f0aSRussell King pm_runtime_get_noresume(dev); 20492b97f0aSRussell King pm_runtime_set_active(dev); 20592b97f0aSRussell King pm_runtime_enable(dev); 20692b97f0aSRussell King 2077cfe2494SRussell King ret = pcdrv->probe(pcdev, id); 2087cfe2494SRussell King if (ret == 0) 2097cfe2494SRussell King break; 2107cfe2494SRussell King 21192b97f0aSRussell King pm_runtime_disable(dev); 21292b97f0aSRussell King pm_runtime_set_suspended(dev); 21392b97f0aSRussell King pm_runtime_put_noidle(dev); 21492b97f0aSRussell King 2157cfe2494SRussell King amba_put_disable_pclk(pcdev); 216207f1a2dSUlf Hansson dev_pm_domain_detach(dev, true); 2177cfe2494SRussell King } while (0); 2187cfe2494SRussell King 2197cfe2494SRussell King return ret; 2201da177e4SLinus Torvalds } 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds static int amba_remove(struct device *dev) 2231da177e4SLinus Torvalds { 2247cfe2494SRussell King struct amba_device *pcdev = to_amba_device(dev); 2251da177e4SLinus Torvalds struct amba_driver *drv = to_amba_driver(dev->driver); 22692b97f0aSRussell King 22792b97f0aSRussell King pm_runtime_get_sync(dev); 228de5d7adbSUwe Kleine-König if (drv->remove) 2293fd269e7SUwe Kleine-König drv->remove(pcdev); 23092b97f0aSRussell King pm_runtime_put_noidle(dev); 23192b97f0aSRussell King 23292b97f0aSRussell King /* Undo the runtime PM settings in amba_probe() */ 23392b97f0aSRussell King pm_runtime_disable(dev); 23492b97f0aSRussell King pm_runtime_set_suspended(dev); 23592b97f0aSRussell King pm_runtime_put_noidle(dev); 2367cfe2494SRussell King 2377cfe2494SRussell King amba_put_disable_pclk(pcdev); 238207f1a2dSUlf Hansson dev_pm_domain_detach(dev, true); 2397cfe2494SRussell King 2403fd269e7SUwe Kleine-König return 0; 2411da177e4SLinus Torvalds } 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds static void amba_shutdown(struct device *dev) 2441da177e4SLinus Torvalds { 245*f170b59fSUwe Kleine-König struct amba_driver *drv; 246de5d7adbSUwe Kleine-König 247*f170b59fSUwe Kleine-König if (!dev->driver) 248*f170b59fSUwe Kleine-König return; 249*f170b59fSUwe Kleine-König 250*f170b59fSUwe Kleine-König drv = to_amba_driver(dev->driver); 251de5d7adbSUwe Kleine-König if (drv->shutdown) 2521da177e4SLinus Torvalds drv->shutdown(to_amba_device(dev)); 2531da177e4SLinus Torvalds } 2541da177e4SLinus Torvalds 255*f170b59fSUwe Kleine-König #ifdef CONFIG_PM 256*f170b59fSUwe Kleine-König /* 257*f170b59fSUwe Kleine-König * Hooks to provide runtime PM of the pclk (bus clock). It is safe to 258*f170b59fSUwe Kleine-König * enable/disable the bus clock at runtime PM suspend/resume as this 259*f170b59fSUwe Kleine-König * does not result in loss of context. 260*f170b59fSUwe Kleine-König */ 261*f170b59fSUwe Kleine-König static int amba_pm_runtime_suspend(struct device *dev) 262*f170b59fSUwe Kleine-König { 263*f170b59fSUwe Kleine-König struct amba_device *pcdev = to_amba_device(dev); 264*f170b59fSUwe Kleine-König int ret = pm_generic_runtime_suspend(dev); 265*f170b59fSUwe Kleine-König 266*f170b59fSUwe Kleine-König if (ret == 0 && dev->driver) { 267*f170b59fSUwe Kleine-König if (pm_runtime_is_irq_safe(dev)) 268*f170b59fSUwe Kleine-König clk_disable(pcdev->pclk); 269*f170b59fSUwe Kleine-König else 270*f170b59fSUwe Kleine-König clk_disable_unprepare(pcdev->pclk); 271*f170b59fSUwe Kleine-König } 272*f170b59fSUwe Kleine-König 273*f170b59fSUwe Kleine-König return ret; 274*f170b59fSUwe Kleine-König } 275*f170b59fSUwe Kleine-König 276*f170b59fSUwe Kleine-König static int amba_pm_runtime_resume(struct device *dev) 277*f170b59fSUwe Kleine-König { 278*f170b59fSUwe Kleine-König struct amba_device *pcdev = to_amba_device(dev); 279*f170b59fSUwe Kleine-König int ret; 280*f170b59fSUwe Kleine-König 281*f170b59fSUwe Kleine-König if (dev->driver) { 282*f170b59fSUwe Kleine-König if (pm_runtime_is_irq_safe(dev)) 283*f170b59fSUwe Kleine-König ret = clk_enable(pcdev->pclk); 284*f170b59fSUwe Kleine-König else 285*f170b59fSUwe Kleine-König ret = clk_prepare_enable(pcdev->pclk); 286*f170b59fSUwe Kleine-König /* Failure is probably fatal to the system, but... */ 287*f170b59fSUwe Kleine-König if (ret) 288*f170b59fSUwe Kleine-König return ret; 289*f170b59fSUwe Kleine-König } 290*f170b59fSUwe Kleine-König 291*f170b59fSUwe Kleine-König return pm_generic_runtime_resume(dev); 292*f170b59fSUwe Kleine-König } 293*f170b59fSUwe Kleine-König #endif /* CONFIG_PM */ 294*f170b59fSUwe Kleine-König 295*f170b59fSUwe Kleine-König static const struct dev_pm_ops amba_pm = { 296*f170b59fSUwe Kleine-König .suspend = pm_generic_suspend, 297*f170b59fSUwe Kleine-König .resume = pm_generic_resume, 298*f170b59fSUwe Kleine-König .freeze = pm_generic_freeze, 299*f170b59fSUwe Kleine-König .thaw = pm_generic_thaw, 300*f170b59fSUwe Kleine-König .poweroff = pm_generic_poweroff, 301*f170b59fSUwe Kleine-König .restore = pm_generic_restore, 302*f170b59fSUwe Kleine-König SET_RUNTIME_PM_OPS( 303*f170b59fSUwe Kleine-König amba_pm_runtime_suspend, 304*f170b59fSUwe Kleine-König amba_pm_runtime_resume, 305*f170b59fSUwe Kleine-König NULL 306*f170b59fSUwe Kleine-König ) 307*f170b59fSUwe Kleine-König }; 308*f170b59fSUwe Kleine-König 309*f170b59fSUwe Kleine-König /* 310*f170b59fSUwe Kleine-König * Primecells are part of the Advanced Microcontroller Bus Architecture, 311*f170b59fSUwe Kleine-König * so we call the bus "amba". 312*f170b59fSUwe Kleine-König * DMA configuration for platform and AMBA bus is same. So here we reuse 313*f170b59fSUwe Kleine-König * platform's DMA config routine. 314*f170b59fSUwe Kleine-König */ 315*f170b59fSUwe Kleine-König struct bus_type amba_bustype = { 316*f170b59fSUwe Kleine-König .name = "amba", 317*f170b59fSUwe Kleine-König .dev_groups = amba_dev_groups, 318*f170b59fSUwe Kleine-König .match = amba_match, 319*f170b59fSUwe Kleine-König .uevent = amba_uevent, 320*f170b59fSUwe Kleine-König .probe = amba_probe, 321*f170b59fSUwe Kleine-König .remove = amba_remove, 322*f170b59fSUwe Kleine-König .shutdown = amba_shutdown, 323*f170b59fSUwe Kleine-König .dma_configure = platform_dma_configure, 324*f170b59fSUwe Kleine-König .pm = &amba_pm, 325*f170b59fSUwe Kleine-König }; 326*f170b59fSUwe Kleine-König EXPORT_SYMBOL_GPL(amba_bustype); 327*f170b59fSUwe Kleine-König 328*f170b59fSUwe Kleine-König static int __init amba_init(void) 329*f170b59fSUwe Kleine-König { 330*f170b59fSUwe Kleine-König return bus_register(&amba_bustype); 331*f170b59fSUwe Kleine-König } 332*f170b59fSUwe Kleine-König 333*f170b59fSUwe Kleine-König postcore_initcall(amba_init); 334*f170b59fSUwe Kleine-König 3351da177e4SLinus Torvalds /** 3361da177e4SLinus Torvalds * amba_driver_register - register an AMBA device driver 3371da177e4SLinus Torvalds * @drv: amba device driver structure 3381da177e4SLinus Torvalds * 3391da177e4SLinus Torvalds * Register an AMBA device driver with the Linux device model 3401da177e4SLinus Torvalds * core. If devices pre-exist, the drivers probe function will 3411da177e4SLinus Torvalds * be called. 3421da177e4SLinus Torvalds */ 3431da177e4SLinus Torvalds int amba_driver_register(struct amba_driver *drv) 3441da177e4SLinus Torvalds { 345de5d7adbSUwe Kleine-König if (!drv->probe) 346de5d7adbSUwe Kleine-König return -EINVAL; 3471da177e4SLinus Torvalds 348de5d7adbSUwe Kleine-König drv->drv.bus = &amba_bustype; 3491da177e4SLinus Torvalds 3501da177e4SLinus Torvalds return driver_register(&drv->drv); 3511da177e4SLinus Torvalds } 3521da177e4SLinus Torvalds 3531da177e4SLinus Torvalds /** 3541da177e4SLinus Torvalds * amba_driver_unregister - remove an AMBA device driver 3551da177e4SLinus Torvalds * @drv: AMBA device driver structure to remove 3561da177e4SLinus Torvalds * 3571da177e4SLinus Torvalds * Unregister an AMBA device driver from the Linux device 3581da177e4SLinus Torvalds * model. The device model will call the drivers remove function 3591da177e4SLinus Torvalds * for each device the device driver is currently handling. 3601da177e4SLinus Torvalds */ 3611da177e4SLinus Torvalds void amba_driver_unregister(struct amba_driver *drv) 3621da177e4SLinus Torvalds { 3631da177e4SLinus Torvalds driver_unregister(&drv->drv); 3641da177e4SLinus Torvalds } 3651da177e4SLinus Torvalds 3661da177e4SLinus Torvalds 3671da177e4SLinus Torvalds static void amba_device_release(struct device *dev) 3681da177e4SLinus Torvalds { 3691da177e4SLinus Torvalds struct amba_device *d = to_amba_device(dev); 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds if (d->res.parent) 3721da177e4SLinus Torvalds release_resource(&d->res); 3731da177e4SLinus Torvalds kfree(d); 3741da177e4SLinus Torvalds } 3751da177e4SLinus Torvalds 376a41980f2SMarek Szyprowski static int amba_device_try_add(struct amba_device *dev, struct resource *parent) 3771da177e4SLinus Torvalds { 3788afe0b96SLeo Chen u32 size; 3791da177e4SLinus Torvalds void __iomem *tmp; 3801da177e4SLinus Torvalds int i, ret; 3811da177e4SLinus Torvalds 3822eac58d5SRussell King WARN_ON(dev->irq[0] == (unsigned int)-1); 3832eac58d5SRussell King WARN_ON(dev->irq[1] == (unsigned int)-1); 3842eac58d5SRussell King 3851da177e4SLinus Torvalds ret = request_resource(parent, &dev->res); 38696b13f5cSRussell King if (ret) 38796b13f5cSRussell King goto err_out; 38896b13f5cSRussell King 38997ceed1fSLinus Walleij /* Hard-coded primecell ID instead of plug-n-play */ 39097ceed1fSLinus Walleij if (dev->periphid != 0) 39197ceed1fSLinus Walleij goto skip_probe; 39297ceed1fSLinus Walleij 3938afe0b96SLeo Chen /* 3948afe0b96SLeo Chen * Dynamically calculate the size of the resource 3958afe0b96SLeo Chen * and use this for iomap 3968afe0b96SLeo Chen */ 3978afe0b96SLeo Chen size = resource_size(&dev->res); 3988afe0b96SLeo Chen tmp = ioremap(dev->res.start, size); 3991da177e4SLinus Torvalds if (!tmp) { 4001da177e4SLinus Torvalds ret = -ENOMEM; 40196b13f5cSRussell King goto err_release; 4021da177e4SLinus Torvalds } 4031da177e4SLinus Torvalds 404a41980f2SMarek Szyprowski ret = dev_pm_domain_attach(&dev->dev, true); 405d21bc89eSUlf Hansson if (ret) { 406a41980f2SMarek Szyprowski iounmap(tmp); 407a41980f2SMarek Szyprowski goto err_release; 408a41980f2SMarek Szyprowski } 409a41980f2SMarek Szyprowski 4107cfe2494SRussell King ret = amba_get_enable_pclk(dev); 4117cfe2494SRussell King if (ret == 0) { 4127cfe2494SRussell King u32 pid, cid; 41379bdcb20SDINH L NGUYEN struct reset_control *rstc; 41479bdcb20SDINH L NGUYEN 41579bdcb20SDINH L NGUYEN /* 41679bdcb20SDINH L NGUYEN * Find reset control(s) of the amba bus and de-assert them. 41779bdcb20SDINH L NGUYEN */ 41879bdcb20SDINH L NGUYEN rstc = of_reset_control_array_get_optional_shared(dev->dev.of_node); 41979bdcb20SDINH L NGUYEN if (IS_ERR(rstc)) { 420e963408eSRussell King ret = PTR_ERR(rstc); 421e963408eSRussell King if (ret != -EPROBE_DEFER) 422e963408eSRussell King dev_err(&dev->dev, "can't get reset: %d\n", 423e963408eSRussell King ret); 424e963408eSRussell King goto err_reset; 42579bdcb20SDINH L NGUYEN } 42679bdcb20SDINH L NGUYEN reset_control_deassert(rstc); 42779bdcb20SDINH L NGUYEN reset_control_put(rstc); 4287cfe2494SRussell King 4298afe0b96SLeo Chen /* 4308afe0b96SLeo Chen * Read pid and cid based on size of resource 4318afe0b96SLeo Chen * they are located at end of region 4328afe0b96SLeo Chen */ 4331da177e4SLinus Torvalds for (pid = 0, i = 0; i < 4; i++) 4347cfe2494SRussell King pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) << 4357cfe2494SRussell King (i * 8); 4361da177e4SLinus Torvalds for (cid = 0, i = 0; i < 4; i++) 4377cfe2494SRussell King cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) << 4387cfe2494SRussell King (i * 8); 4391da177e4SLinus Torvalds 4404a2910faSMike Leach if (cid == CORESIGHT_CID) { 4414a2910faSMike Leach /* set the base to the start of the last 4k block */ 4424a2910faSMike Leach void __iomem *csbase = tmp + size - 4096; 4434a2910faSMike Leach 4444a2910faSMike Leach dev->uci.devarch = 4454a2910faSMike Leach readl(csbase + UCI_REG_DEVARCH_OFFSET); 4464a2910faSMike Leach dev->uci.devtype = 4474a2910faSMike Leach readl(csbase + UCI_REG_DEVTYPE_OFFSET) & 0xff; 4484a2910faSMike Leach } 4494a2910faSMike Leach 4507cfe2494SRussell King amba_put_disable_pclk(dev); 4511da177e4SLinus Torvalds 4524a2910faSMike Leach if (cid == AMBA_CID || cid == CORESIGHT_CID) { 4531da177e4SLinus Torvalds dev->periphid = pid; 4544a2910faSMike Leach dev->cid = cid; 4554a2910faSMike Leach } 4561da177e4SLinus Torvalds 4577cfe2494SRussell King if (!dev->periphid) 4581da177e4SLinus Torvalds ret = -ENODEV; 45996b13f5cSRussell King } 4601da177e4SLinus Torvalds 4617cfe2494SRussell King iounmap(tmp); 462a41980f2SMarek Szyprowski dev_pm_domain_detach(&dev->dev, true); 4637cfe2494SRussell King 4647cfe2494SRussell King if (ret) 4657cfe2494SRussell King goto err_release; 4667cfe2494SRussell King 46797ceed1fSLinus Walleij skip_probe: 468557dca5fSRussell King ret = device_add(&dev->dev); 46996b13f5cSRussell King if (ret) 47096b13f5cSRussell King goto err_release; 47196b13f5cSRussell King 472dfb85185SRussell King if (dev->irq[0]) 47396b13f5cSRussell King ret = device_create_file(&dev->dev, &dev_attr_irq0); 474dfb85185SRussell King if (ret == 0 && dev->irq[1]) 47596b13f5cSRussell King ret = device_create_file(&dev->dev, &dev_attr_irq1); 47696b13f5cSRussell King if (ret == 0) 47796b13f5cSRussell King return ret; 47896b13f5cSRussell King 47996b13f5cSRussell King device_unregister(&dev->dev); 48096b13f5cSRussell King 48196b13f5cSRussell King err_release: 4821da177e4SLinus Torvalds release_resource(&dev->res); 48396b13f5cSRussell King err_out: 4841da177e4SLinus Torvalds return ret; 485e963408eSRussell King 486e963408eSRussell King err_reset: 487e963408eSRussell King amba_put_disable_pclk(dev); 488e963408eSRussell King iounmap(tmp); 489e963408eSRussell King dev_pm_domain_detach(&dev->dev, true); 490e963408eSRussell King goto err_release; 4911da177e4SLinus Torvalds } 492a41980f2SMarek Szyprowski 493a41980f2SMarek Szyprowski /* 494a41980f2SMarek Szyprowski * Registration of AMBA device require reading its pid and cid registers. 495a41980f2SMarek Szyprowski * To do this, the device must be turned on (if it is a part of power domain) 496a41980f2SMarek Szyprowski * and have clocks enabled. However in some cases those resources might not be 497a41980f2SMarek Szyprowski * yet available. Returning EPROBE_DEFER is not a solution in such case, 498a41980f2SMarek Szyprowski * because callers don't handle this special error code. Instead such devices 499a41980f2SMarek Szyprowski * are added to the special list and their registration is retried from 500a41980f2SMarek Szyprowski * periodic worker, until all resources are available and registration succeeds. 501a41980f2SMarek Szyprowski */ 502a41980f2SMarek Szyprowski struct deferred_device { 503a41980f2SMarek Szyprowski struct amba_device *dev; 504a41980f2SMarek Szyprowski struct resource *parent; 505a41980f2SMarek Szyprowski struct list_head node; 506a41980f2SMarek Szyprowski }; 507a41980f2SMarek Szyprowski 508a41980f2SMarek Szyprowski static LIST_HEAD(deferred_devices); 509a41980f2SMarek Szyprowski static DEFINE_MUTEX(deferred_devices_lock); 510a41980f2SMarek Szyprowski 511a41980f2SMarek Szyprowski static void amba_deferred_retry_func(struct work_struct *dummy); 512a41980f2SMarek Szyprowski static DECLARE_DELAYED_WORK(deferred_retry_work, amba_deferred_retry_func); 513a41980f2SMarek Szyprowski 514a41980f2SMarek Szyprowski #define DEFERRED_DEVICE_TIMEOUT (msecs_to_jiffies(5 * 1000)) 515a41980f2SMarek Szyprowski 516039599c9SRob Herring static int amba_deferred_retry(void) 517a41980f2SMarek Szyprowski { 518a41980f2SMarek Szyprowski struct deferred_device *ddev, *tmp; 519a41980f2SMarek Szyprowski 520a41980f2SMarek Szyprowski mutex_lock(&deferred_devices_lock); 521a41980f2SMarek Szyprowski 522a41980f2SMarek Szyprowski list_for_each_entry_safe(ddev, tmp, &deferred_devices, node) { 523a41980f2SMarek Szyprowski int ret = amba_device_try_add(ddev->dev, ddev->parent); 524a41980f2SMarek Szyprowski 525a41980f2SMarek Szyprowski if (ret == -EPROBE_DEFER) 526a41980f2SMarek Szyprowski continue; 527a41980f2SMarek Szyprowski 528a41980f2SMarek Szyprowski list_del_init(&ddev->node); 529a41980f2SMarek Szyprowski kfree(ddev); 530a41980f2SMarek Szyprowski } 531a41980f2SMarek Szyprowski 532039599c9SRob Herring mutex_unlock(&deferred_devices_lock); 533039599c9SRob Herring 534039599c9SRob Herring return 0; 535039599c9SRob Herring } 536039599c9SRob Herring late_initcall(amba_deferred_retry); 537039599c9SRob Herring 538039599c9SRob Herring static void amba_deferred_retry_func(struct work_struct *dummy) 539039599c9SRob Herring { 540039599c9SRob Herring amba_deferred_retry(); 541039599c9SRob Herring 542a41980f2SMarek Szyprowski if (!list_empty(&deferred_devices)) 543a41980f2SMarek Szyprowski schedule_delayed_work(&deferred_retry_work, 544a41980f2SMarek Szyprowski DEFERRED_DEVICE_TIMEOUT); 545a41980f2SMarek Szyprowski } 546a41980f2SMarek Szyprowski 547a41980f2SMarek Szyprowski /** 548a41980f2SMarek Szyprowski * amba_device_add - add a previously allocated AMBA device structure 549a41980f2SMarek Szyprowski * @dev: AMBA device allocated by amba_device_alloc 550a41980f2SMarek Szyprowski * @parent: resource parent for this devices resources 551a41980f2SMarek Szyprowski * 552a41980f2SMarek Szyprowski * Claim the resource, and read the device cell ID if not already 553a41980f2SMarek Szyprowski * initialized. Register the AMBA device with the Linux device 554a41980f2SMarek Szyprowski * manager. 555a41980f2SMarek Szyprowski */ 556a41980f2SMarek Szyprowski int amba_device_add(struct amba_device *dev, struct resource *parent) 557a41980f2SMarek Szyprowski { 558a41980f2SMarek Szyprowski int ret = amba_device_try_add(dev, parent); 559a41980f2SMarek Szyprowski 560a41980f2SMarek Szyprowski if (ret == -EPROBE_DEFER) { 561a41980f2SMarek Szyprowski struct deferred_device *ddev; 562a41980f2SMarek Szyprowski 563a41980f2SMarek Szyprowski ddev = kmalloc(sizeof(*ddev), GFP_KERNEL); 564a41980f2SMarek Szyprowski if (!ddev) 565a41980f2SMarek Szyprowski return -ENOMEM; 566a41980f2SMarek Szyprowski 567a41980f2SMarek Szyprowski ddev->dev = dev; 568a41980f2SMarek Szyprowski ddev->parent = parent; 569a41980f2SMarek Szyprowski ret = 0; 570a41980f2SMarek Szyprowski 571a41980f2SMarek Szyprowski mutex_lock(&deferred_devices_lock); 572a41980f2SMarek Szyprowski 573a41980f2SMarek Szyprowski if (list_empty(&deferred_devices)) 574a41980f2SMarek Szyprowski schedule_delayed_work(&deferred_retry_work, 575a41980f2SMarek Szyprowski DEFERRED_DEVICE_TIMEOUT); 576a41980f2SMarek Szyprowski list_add_tail(&ddev->node, &deferred_devices); 577a41980f2SMarek Szyprowski 578a41980f2SMarek Szyprowski mutex_unlock(&deferred_devices_lock); 579a41980f2SMarek Szyprowski } 580a41980f2SMarek Szyprowski return ret; 581a41980f2SMarek Szyprowski } 582d5dc9271SRussell King EXPORT_SYMBOL_GPL(amba_device_add); 583d5dc9271SRussell King 5846026aa90SLinus Walleij static struct amba_device * 5856026aa90SLinus Walleij amba_aphb_device_add(struct device *parent, const char *name, 5866026aa90SLinus Walleij resource_size_t base, size_t size, int irq1, int irq2, 5873ad909bcSLinus Walleij void *pdata, unsigned int periphid, u64 dma_mask, 5883ad909bcSLinus Walleij struct resource *resbase) 5896026aa90SLinus Walleij { 5906026aa90SLinus Walleij struct amba_device *dev; 5916026aa90SLinus Walleij int ret; 5926026aa90SLinus Walleij 5936026aa90SLinus Walleij dev = amba_device_alloc(name, base, size); 5946026aa90SLinus Walleij if (!dev) 5956026aa90SLinus Walleij return ERR_PTR(-ENOMEM); 5966026aa90SLinus Walleij 5976026aa90SLinus Walleij dev->dev.coherent_dma_mask = dma_mask; 5986026aa90SLinus Walleij dev->irq[0] = irq1; 5996026aa90SLinus Walleij dev->irq[1] = irq2; 6006026aa90SLinus Walleij dev->periphid = periphid; 6016026aa90SLinus Walleij dev->dev.platform_data = pdata; 6026026aa90SLinus Walleij dev->dev.parent = parent; 6036026aa90SLinus Walleij 6043ad909bcSLinus Walleij ret = amba_device_add(dev, resbase); 6056026aa90SLinus Walleij if (ret) { 6066026aa90SLinus Walleij amba_device_put(dev); 6076026aa90SLinus Walleij return ERR_PTR(ret); 6086026aa90SLinus Walleij } 6096026aa90SLinus Walleij 6106026aa90SLinus Walleij return dev; 6116026aa90SLinus Walleij } 6126026aa90SLinus Walleij 6136026aa90SLinus Walleij struct amba_device * 6146026aa90SLinus Walleij amba_apb_device_add(struct device *parent, const char *name, 6156026aa90SLinus Walleij resource_size_t base, size_t size, int irq1, int irq2, 6166026aa90SLinus Walleij void *pdata, unsigned int periphid) 6176026aa90SLinus Walleij { 6186026aa90SLinus Walleij return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata, 6193ad909bcSLinus Walleij periphid, 0, &iomem_resource); 6206026aa90SLinus Walleij } 6216026aa90SLinus Walleij EXPORT_SYMBOL_GPL(amba_apb_device_add); 6226026aa90SLinus Walleij 6236026aa90SLinus Walleij struct amba_device * 6246026aa90SLinus Walleij amba_ahb_device_add(struct device *parent, const char *name, 6256026aa90SLinus Walleij resource_size_t base, size_t size, int irq1, int irq2, 6266026aa90SLinus Walleij void *pdata, unsigned int periphid) 6276026aa90SLinus Walleij { 6286026aa90SLinus Walleij return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata, 6293ad909bcSLinus Walleij periphid, ~0ULL, &iomem_resource); 6306026aa90SLinus Walleij } 6316026aa90SLinus Walleij EXPORT_SYMBOL_GPL(amba_ahb_device_add); 6326026aa90SLinus Walleij 6333ad909bcSLinus Walleij struct amba_device * 6343ad909bcSLinus Walleij amba_apb_device_add_res(struct device *parent, const char *name, 6353ad909bcSLinus Walleij resource_size_t base, size_t size, int irq1, 6363ad909bcSLinus Walleij int irq2, void *pdata, unsigned int periphid, 6373ad909bcSLinus Walleij struct resource *resbase) 6383ad909bcSLinus Walleij { 6393ad909bcSLinus Walleij return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata, 6403ad909bcSLinus Walleij periphid, 0, resbase); 6413ad909bcSLinus Walleij } 6423ad909bcSLinus Walleij EXPORT_SYMBOL_GPL(amba_apb_device_add_res); 6433ad909bcSLinus Walleij 6443ad909bcSLinus Walleij struct amba_device * 6453ad909bcSLinus Walleij amba_ahb_device_add_res(struct device *parent, const char *name, 6463ad909bcSLinus Walleij resource_size_t base, size_t size, int irq1, 6473ad909bcSLinus Walleij int irq2, void *pdata, unsigned int periphid, 6483ad909bcSLinus Walleij struct resource *resbase) 6493ad909bcSLinus Walleij { 6503ad909bcSLinus Walleij return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata, 6513ad909bcSLinus Walleij periphid, ~0ULL, resbase); 6523ad909bcSLinus Walleij } 6533ad909bcSLinus Walleij EXPORT_SYMBOL_GPL(amba_ahb_device_add_res); 6543ad909bcSLinus Walleij 6553ad909bcSLinus Walleij 656d5dc9271SRussell King static void amba_device_initialize(struct amba_device *dev, const char *name) 657d5dc9271SRussell King { 658d5dc9271SRussell King device_initialize(&dev->dev); 659d5dc9271SRussell King if (name) 660d5dc9271SRussell King dev_set_name(&dev->dev, "%s", name); 661d5dc9271SRussell King dev->dev.release = amba_device_release; 662d5dc9271SRussell King dev->dev.bus = &amba_bustype; 663446b2a93SRussell King dev->dev.dma_mask = &dev->dev.coherent_dma_mask; 664f4584884SUlf Hansson dev->dev.dma_parms = &dev->dma_parms; 665d5dc9271SRussell King dev->res.name = dev_name(&dev->dev); 666d5dc9271SRussell King } 667d5dc9271SRussell King 668d5dc9271SRussell King /** 669d5dc9271SRussell King * amba_device_alloc - allocate an AMBA device 670d5dc9271SRussell King * @name: sysfs name of the AMBA device 671d5dc9271SRussell King * @base: base of AMBA device 672d5dc9271SRussell King * @size: size of AMBA device 673d5dc9271SRussell King * 674d5dc9271SRussell King * Allocate and initialize an AMBA device structure. Returns %NULL 675d5dc9271SRussell King * on failure. 676d5dc9271SRussell King */ 677d5dc9271SRussell King struct amba_device *amba_device_alloc(const char *name, resource_size_t base, 678d5dc9271SRussell King size_t size) 679d5dc9271SRussell King { 680d5dc9271SRussell King struct amba_device *dev; 681d5dc9271SRussell King 682d5dc9271SRussell King dev = kzalloc(sizeof(*dev), GFP_KERNEL); 683d5dc9271SRussell King if (dev) { 684d5dc9271SRussell King amba_device_initialize(dev, name); 685d5dc9271SRussell King dev->res.start = base; 686d5dc9271SRussell King dev->res.end = base + size - 1; 687d5dc9271SRussell King dev->res.flags = IORESOURCE_MEM; 688d5dc9271SRussell King } 689d5dc9271SRussell King 690d5dc9271SRussell King return dev; 691d5dc9271SRussell King } 692d5dc9271SRussell King EXPORT_SYMBOL_GPL(amba_device_alloc); 693d5dc9271SRussell King 694d5dc9271SRussell King /** 695d5dc9271SRussell King * amba_device_register - register an AMBA device 696d5dc9271SRussell King * @dev: AMBA device to register 697d5dc9271SRussell King * @parent: parent memory resource 698d5dc9271SRussell King * 699d5dc9271SRussell King * Setup the AMBA device, reading the cell ID if present. 700d5dc9271SRussell King * Claim the resource, and register the AMBA device with 701d5dc9271SRussell King * the Linux device manager. 702d5dc9271SRussell King */ 703d5dc9271SRussell King int amba_device_register(struct amba_device *dev, struct resource *parent) 704d5dc9271SRussell King { 705d5dc9271SRussell King amba_device_initialize(dev, dev->dev.init_name); 706d5dc9271SRussell King dev->dev.init_name = NULL; 707d5dc9271SRussell King 708d5dc9271SRussell King return amba_device_add(dev, parent); 709d5dc9271SRussell King } 710d5dc9271SRussell King 711d5dc9271SRussell King /** 712d5dc9271SRussell King * amba_device_put - put an AMBA device 713d5dc9271SRussell King * @dev: AMBA device to put 714d5dc9271SRussell King */ 715d5dc9271SRussell King void amba_device_put(struct amba_device *dev) 716d5dc9271SRussell King { 717d5dc9271SRussell King put_device(&dev->dev); 718d5dc9271SRussell King } 719d5dc9271SRussell King EXPORT_SYMBOL_GPL(amba_device_put); 7201da177e4SLinus Torvalds 7211da177e4SLinus Torvalds /** 7221da177e4SLinus Torvalds * amba_device_unregister - unregister an AMBA device 7231da177e4SLinus Torvalds * @dev: AMBA device to remove 7241da177e4SLinus Torvalds * 7251da177e4SLinus Torvalds * Remove the specified AMBA device from the Linux device 7261da177e4SLinus Torvalds * manager. All files associated with this object will be 7271da177e4SLinus Torvalds * destroyed, and device drivers notified that the device has 7281da177e4SLinus Torvalds * been removed. The AMBA device's resources including 7291da177e4SLinus Torvalds * the amba_device structure will be freed once all 7301da177e4SLinus Torvalds * references to it have been dropped. 7311da177e4SLinus Torvalds */ 7321da177e4SLinus Torvalds void amba_device_unregister(struct amba_device *dev) 7331da177e4SLinus Torvalds { 7341da177e4SLinus Torvalds device_unregister(&dev->dev); 7351da177e4SLinus Torvalds } 7361da177e4SLinus Torvalds 7371da177e4SLinus Torvalds 7381da177e4SLinus Torvalds struct find_data { 7391da177e4SLinus Torvalds struct amba_device *dev; 7401da177e4SLinus Torvalds struct device *parent; 7411da177e4SLinus Torvalds const char *busid; 7421da177e4SLinus Torvalds unsigned int id; 7431da177e4SLinus Torvalds unsigned int mask; 7441da177e4SLinus Torvalds }; 7451da177e4SLinus Torvalds 7461da177e4SLinus Torvalds static int amba_find_match(struct device *dev, void *data) 7471da177e4SLinus Torvalds { 7481da177e4SLinus Torvalds struct find_data *d = data; 7491da177e4SLinus Torvalds struct amba_device *pcdev = to_amba_device(dev); 7501da177e4SLinus Torvalds int r; 7511da177e4SLinus Torvalds 7521da177e4SLinus Torvalds r = (pcdev->periphid & d->mask) == d->id; 7531da177e4SLinus Torvalds if (d->parent) 7541da177e4SLinus Torvalds r &= d->parent == dev->parent; 7551da177e4SLinus Torvalds if (d->busid) 7569d6b4c82SKay Sievers r &= strcmp(dev_name(dev), d->busid) == 0; 7571da177e4SLinus Torvalds 7581da177e4SLinus Torvalds if (r) { 7591da177e4SLinus Torvalds get_device(dev); 7601da177e4SLinus Torvalds d->dev = pcdev; 7611da177e4SLinus Torvalds } 7621da177e4SLinus Torvalds 7631da177e4SLinus Torvalds return r; 7641da177e4SLinus Torvalds } 7651da177e4SLinus Torvalds 7661da177e4SLinus Torvalds /** 7671da177e4SLinus Torvalds * amba_find_device - locate an AMBA device given a bus id 7681da177e4SLinus Torvalds * @busid: bus id for device (or NULL) 7691da177e4SLinus Torvalds * @parent: parent device (or NULL) 7701da177e4SLinus Torvalds * @id: peripheral ID (or 0) 7711da177e4SLinus Torvalds * @mask: peripheral ID mask (or 0) 7721da177e4SLinus Torvalds * 7731da177e4SLinus Torvalds * Return the AMBA device corresponding to the supplied parameters. 7741da177e4SLinus Torvalds * If no device matches, returns NULL. 7751da177e4SLinus Torvalds * 7761da177e4SLinus Torvalds * NOTE: When a valid device is found, its refcount is 7771da177e4SLinus Torvalds * incremented, and must be decremented before the returned 7781da177e4SLinus Torvalds * reference. 7791da177e4SLinus Torvalds */ 7801da177e4SLinus Torvalds struct amba_device * 7811da177e4SLinus Torvalds amba_find_device(const char *busid, struct device *parent, unsigned int id, 7821da177e4SLinus Torvalds unsigned int mask) 7831da177e4SLinus Torvalds { 7841da177e4SLinus Torvalds struct find_data data; 7851da177e4SLinus Torvalds 7861da177e4SLinus Torvalds data.dev = NULL; 7871da177e4SLinus Torvalds data.parent = parent; 7881da177e4SLinus Torvalds data.busid = busid; 7891da177e4SLinus Torvalds data.id = id; 7901da177e4SLinus Torvalds data.mask = mask; 7911da177e4SLinus Torvalds 7921da177e4SLinus Torvalds bus_for_each_dev(&amba_bustype, NULL, &data, amba_find_match); 7931da177e4SLinus Torvalds 7941da177e4SLinus Torvalds return data.dev; 7951da177e4SLinus Torvalds } 7961da177e4SLinus Torvalds 7971da177e4SLinus Torvalds /** 7981da177e4SLinus Torvalds * amba_request_regions - request all mem regions associated with device 7991da177e4SLinus Torvalds * @dev: amba_device structure for device 8001da177e4SLinus Torvalds * @name: name, or NULL to use driver name 8011da177e4SLinus Torvalds */ 8021da177e4SLinus Torvalds int amba_request_regions(struct amba_device *dev, const char *name) 8031da177e4SLinus Torvalds { 8041da177e4SLinus Torvalds int ret = 0; 8058afe0b96SLeo Chen u32 size; 8061da177e4SLinus Torvalds 8071da177e4SLinus Torvalds if (!name) 8081da177e4SLinus Torvalds name = dev->dev.driver->name; 8091da177e4SLinus Torvalds 8108afe0b96SLeo Chen size = resource_size(&dev->res); 8118afe0b96SLeo Chen 8128afe0b96SLeo Chen if (!request_mem_region(dev->res.start, size, name)) 8131da177e4SLinus Torvalds ret = -EBUSY; 8141da177e4SLinus Torvalds 8151da177e4SLinus Torvalds return ret; 8161da177e4SLinus Torvalds } 8171da177e4SLinus Torvalds 8181da177e4SLinus Torvalds /** 81925985edcSLucas De Marchi * amba_release_regions - release mem regions associated with device 8201da177e4SLinus Torvalds * @dev: amba_device structure for device 8211da177e4SLinus Torvalds * 8221da177e4SLinus Torvalds * Release regions claimed by a successful call to amba_request_regions. 8231da177e4SLinus Torvalds */ 8241da177e4SLinus Torvalds void amba_release_regions(struct amba_device *dev) 8251da177e4SLinus Torvalds { 8268afe0b96SLeo Chen u32 size; 8278afe0b96SLeo Chen 8288afe0b96SLeo Chen size = resource_size(&dev->res); 8298afe0b96SLeo Chen release_mem_region(dev->res.start, size); 8301da177e4SLinus Torvalds } 8311da177e4SLinus Torvalds 8321da177e4SLinus Torvalds EXPORT_SYMBOL(amba_driver_register); 8331da177e4SLinus Torvalds EXPORT_SYMBOL(amba_driver_unregister); 8341da177e4SLinus Torvalds EXPORT_SYMBOL(amba_device_register); 8351da177e4SLinus Torvalds EXPORT_SYMBOL(amba_device_unregister); 8361da177e4SLinus Torvalds EXPORT_SYMBOL(amba_find_device); 8371da177e4SLinus Torvalds EXPORT_SYMBOL(amba_request_regions); 8381da177e4SLinus Torvalds EXPORT_SYMBOL(amba_release_regions); 839