diff options
Diffstat (limited to 'drivers/amba/bus.c')
| -rw-r--r-- | drivers/amba/bus.c | 441 |
1 files changed, 170 insertions, 271 deletions
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 54eaf96ab21..3cf61a127ee 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -16,9 +16,9 @@ #include <linux/pm.h> #include <linux/pm_runtime.h> #include <linux/amba/bus.h> +#include <linux/sizes.h> #include <asm/irq.h> -#include <asm/sizes.h> #define to_amba_driver(d) container_of(d, struct amba_driver, drv) @@ -45,7 +45,6 @@ static int amba_match(struct device *dev, struct device_driver *drv) return amba_lookup(pcdrv->id_table, pcdev) != NULL; } -#ifdef CONFIG_HOTPLUG static int amba_uevent(struct device *dev, struct kobj_uevent_env *env) { struct amba_device *pcdev = to_amba_device(dev); @@ -58,9 +57,6 @@ static int amba_uevent(struct device *dev, struct kobj_uevent_env *env) retval = add_uevent_var(env, "MODALIAS=amba:d%08X", pcdev->periphid); return retval; } -#else -#define amba_uevent NULL -#endif #define amba_attr_func(name,fmt,arg...) \ static ssize_t name##_show(struct device *_dev, \ @@ -87,168 +83,11 @@ static struct device_attribute amba_dev_attrs[] = { __ATTR_NULL, }; -#ifdef CONFIG_PM_SLEEP - -static int amba_legacy_suspend(struct device *dev, pm_message_t mesg) -{ - struct amba_driver *adrv = to_amba_driver(dev->driver); - struct amba_device *adev = to_amba_device(dev); - int ret = 0; - - if (dev->driver && adrv->suspend) - ret = adrv->suspend(adev, mesg); - - return ret; -} - -static int amba_legacy_resume(struct device *dev) -{ - struct amba_driver *adrv = to_amba_driver(dev->driver); - struct amba_device *adev = to_amba_device(dev); - int ret = 0; - - if (dev->driver && adrv->resume) - ret = adrv->resume(adev); - - return ret; -} - -#endif /* CONFIG_PM_SLEEP */ - -#ifdef CONFIG_SUSPEND - -static int amba_pm_suspend(struct device *dev) -{ - struct device_driver *drv = dev->driver; - int ret = 0; - - if (!drv) - return 0; - - if (drv->pm) { - if (drv->pm->suspend) - ret = drv->pm->suspend(dev); - } else { - ret = amba_legacy_suspend(dev, PMSG_SUSPEND); - } - - return ret; -} - -static int amba_pm_resume(struct device *dev) -{ - struct device_driver *drv = dev->driver; - int ret = 0; - - if (!drv) - return 0; - - if (drv->pm) { - if (drv->pm->resume) - ret = drv->pm->resume(dev); - } else { - ret = amba_legacy_resume(dev); - } - - return ret; -} - -#else /* !CONFIG_SUSPEND */ - -#define amba_pm_suspend NULL -#define amba_pm_resume NULL - -#endif /* !CONFIG_SUSPEND */ - -#ifdef CONFIG_HIBERNATE_CALLBACKS - -static int amba_pm_freeze(struct device *dev) -{ - struct device_driver *drv = dev->driver; - int ret = 0; - - if (!drv) - return 0; - - if (drv->pm) { - if (drv->pm->freeze) - ret = drv->pm->freeze(dev); - } else { - ret = amba_legacy_suspend(dev, PMSG_FREEZE); - } - - return ret; -} - -static int amba_pm_thaw(struct device *dev) -{ - struct device_driver *drv = dev->driver; - int ret = 0; - - if (!drv) - return 0; - - if (drv->pm) { - if (drv->pm->thaw) - ret = drv->pm->thaw(dev); - } else { - ret = amba_legacy_resume(dev); - } - - return ret; -} - -static int amba_pm_poweroff(struct device *dev) -{ - struct device_driver *drv = dev->driver; - int ret = 0; - - if (!drv) - return 0; - - if (drv->pm) { - if (drv->pm->poweroff) - ret = drv->pm->poweroff(dev); - } else { - ret = amba_legacy_suspend(dev, PMSG_HIBERNATE); - } - - return ret; -} - -static int amba_pm_restore(struct device *dev) -{ - struct device_driver *drv = dev->driver; - int ret = 0; - - if (!drv) - return 0; - - if (drv->pm) { - if (drv->pm->restore) - ret = drv->pm->restore(dev); - } else { - ret = amba_legacy_resume(dev); - } - - return ret; -} - -#else /* !CONFIG_HIBERNATE_CALLBACKS */ - -#define amba_pm_freeze NULL -#define amba_pm_thaw NULL -#define amba_pm_poweroff NULL -#define amba_pm_restore NULL - -#endif /* !CONFIG_HIBERNATE_CALLBACKS */ - -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM /* * Hooks to provide runtime PM of the pclk (bus clock). It is safe to * enable/disable the bus clock at runtime PM suspend/resume as this - * does not result in loss of context. However, disabling vcore power - * would do, so we leave that to the driver. + * does not result in loss of context. */ static int amba_pm_runtime_suspend(struct device *dev) { @@ -256,7 +95,7 @@ static int amba_pm_runtime_suspend(struct device *dev) int ret = pm_generic_runtime_suspend(dev); if (ret == 0 && dev->driver) - clk_disable(pcdev->pclk); + clk_disable_unprepare(pcdev->pclk); return ret; } @@ -267,7 +106,7 @@ static int amba_pm_runtime_resume(struct device *dev) int ret; if (dev->driver) { - ret = clk_enable(pcdev->pclk); + ret = clk_prepare_enable(pcdev->pclk); /* Failure is probably fatal to the system, but... */ if (ret) return ret; @@ -277,30 +116,20 @@ static int amba_pm_runtime_resume(struct device *dev) } #endif -#ifdef CONFIG_PM - static const struct dev_pm_ops amba_pm = { - .suspend = amba_pm_suspend, - .resume = amba_pm_resume, - .freeze = amba_pm_freeze, - .thaw = amba_pm_thaw, - .poweroff = amba_pm_poweroff, - .restore = amba_pm_restore, - SET_RUNTIME_PM_OPS( + .suspend = pm_generic_suspend, + .resume = pm_generic_resume, + .freeze = pm_generic_freeze, + .thaw = pm_generic_thaw, + .poweroff = pm_generic_poweroff, + .restore = pm_generic_restore, + SET_PM_RUNTIME_PM_OPS( amba_pm_runtime_suspend, amba_pm_runtime_resume, - pm_generic_runtime_idle + NULL ) }; -#define AMBA_PM (&amba_pm) - -#else /* !CONFIG_PM */ - -#define AMBA_PM NULL - -#endif /* !CONFIG_PM */ - /* * Primecells are part of the Advanced Microcontroller Bus Architecture, * so we call the bus "amba". @@ -310,7 +139,7 @@ struct bus_type amba_bustype = { .dev_attrs = amba_dev_attrs, .match = amba_match, .uevent = amba_uevent, - .pm = AMBA_PM, + .pm = &amba_pm, }; static int __init amba_init(void) @@ -322,69 +151,23 @@ postcore_initcall(amba_init); static int amba_get_enable_pclk(struct amba_device *pcdev) { - struct clk *pclk = clk_get(&pcdev->dev, "apb_pclk"); int ret; - pcdev->pclk = pclk; + pcdev->pclk = clk_get(&pcdev->dev, "apb_pclk"); + if (IS_ERR(pcdev->pclk)) + return PTR_ERR(pcdev->pclk); - if (IS_ERR(pclk)) - return PTR_ERR(pclk); - - ret = clk_prepare(pclk); - if (ret) { - clk_put(pclk); - return ret; - } - - ret = clk_enable(pclk); - if (ret) { - clk_unprepare(pclk); - clk_put(pclk); - } + ret = clk_prepare_enable(pcdev->pclk); + if (ret) + clk_put(pcdev->pclk); return ret; } static void amba_put_disable_pclk(struct amba_device *pcdev) { - struct clk *pclk = pcdev->pclk; - - clk_disable(pclk); - clk_unprepare(pclk); - clk_put(pclk); -} - -static int amba_get_enable_vcore(struct amba_device *pcdev) -{ - struct regulator *vcore = regulator_get(&pcdev->dev, "vcore"); - int ret; - - pcdev->vcore = vcore; - - if (IS_ERR(vcore)) { - /* It is OK not to supply a vcore regulator */ - if (PTR_ERR(vcore) == -ENODEV) - return 0; - return PTR_ERR(vcore); - } - - ret = regulator_enable(vcore); - if (ret) { - regulator_put(vcore); - pcdev->vcore = ERR_PTR(-ENODEV); - } - - return ret; -} - -static void amba_put_disable_vcore(struct amba_device *pcdev) -{ - struct regulator *vcore = pcdev->vcore; - - if (!IS_ERR(vcore)) { - regulator_disable(vcore); - regulator_put(vcore); - } + clk_disable_unprepare(pcdev->pclk); + clk_put(pcdev->pclk); } /* @@ -399,10 +182,6 @@ static int amba_probe(struct device *dev) int ret; do { - ret = amba_get_enable_vcore(pcdev); - if (ret) - break; - ret = amba_get_enable_pclk(pcdev); if (ret) break; @@ -420,7 +199,6 @@ static int amba_probe(struct device *dev) pm_runtime_put_noidle(dev); amba_put_disable_pclk(pcdev); - amba_put_disable_vcore(pcdev); } while (0); return ret; @@ -442,7 +220,6 @@ static int amba_remove(struct device *dev) pm_runtime_put_noidle(dev); amba_put_disable_pclk(pcdev); - amba_put_disable_vcore(pcdev); return ret; } @@ -497,37 +274,22 @@ static void amba_device_release(struct device *dev) } /** - * amba_device_register - register an AMBA device - * @dev: AMBA device to register - * @parent: parent memory resource + * amba_device_add - add a previously allocated AMBA device structure + * @dev: AMBA device allocated by amba_device_alloc + * @parent: resource parent for this devices resources * - * Setup the AMBA device, reading the cell ID if present. - * Claim the resource, and register the AMBA device with - * the Linux device manager. + * Claim the resource, and read the device cell ID if not already + * initialized. Register the AMBA device with the Linux device + * manager. */ -int amba_device_register(struct amba_device *dev, struct resource *parent) +int amba_device_add(struct amba_device *dev, struct resource *parent) { u32 size; void __iomem *tmp; int i, ret; - device_initialize(&dev->dev); - - /* - * Copy from device_add - */ - if (dev->dev.init_name) { - dev_set_name(&dev->dev, "%s", dev->dev.init_name); - dev->dev.init_name = NULL; - } - - dev->dev.release = amba_device_release; - dev->dev.bus = &amba_bustype; - dev->dev.dma_mask = &dev->dma_mask; - dev->res.name = dev_name(&dev->dev); - - if (!dev->dev.coherent_dma_mask && dev->dma_mask) - dev_warn(&dev->dev, "coherent dma mask is unset\n"); + WARN_ON(dev->irq[0] == (unsigned int)-1); + WARN_ON(dev->irq[1] == (unsigned int)-1); ret = request_resource(parent, &dev->res); if (ret) @@ -582,9 +344,9 @@ int amba_device_register(struct amba_device *dev, struct resource *parent) if (ret) goto err_release; - if (dev->irq[0] != NO_IRQ) + if (dev->irq[0]) ret = device_create_file(&dev->dev, &dev_attr_irq0); - if (ret == 0 && dev->irq[1] != NO_IRQ) + if (ret == 0 && dev->irq[1]) ret = device_create_file(&dev->dev, &dev_attr_irq1); if (ret == 0) return ret; @@ -596,6 +358,143 @@ int amba_device_register(struct amba_device *dev, struct resource *parent) err_out: return ret; } +EXPORT_SYMBOL_GPL(amba_device_add); + +static struct amba_device * +amba_aphb_device_add(struct device *parent, const char *name, + resource_size_t base, size_t size, int irq1, int irq2, + void *pdata, unsigned int periphid, u64 dma_mask, + struct resource *resbase) +{ + struct amba_device *dev; + int ret; + + dev = amba_device_alloc(name, base, size); + if (!dev) + return ERR_PTR(-ENOMEM); + + dev->dev.coherent_dma_mask = dma_mask; + dev->irq[0] = irq1; + dev->irq[1] = irq2; + dev->periphid = periphid; + dev->dev.platform_data = pdata; + dev->dev.parent = parent; + + ret = amba_device_add(dev, resbase); + if (ret) { + amba_device_put(dev); + return ERR_PTR(ret); + } + + return dev; +} + +struct amba_device * +amba_apb_device_add(struct device *parent, const char *name, + resource_size_t base, size_t size, int irq1, int irq2, + void *pdata, unsigned int periphid) +{ + return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata, + periphid, 0, &iomem_resource); +} +EXPORT_SYMBOL_GPL(amba_apb_device_add); + +struct amba_device * +amba_ahb_device_add(struct device *parent, const char *name, + resource_size_t base, size_t size, int irq1, int irq2, + void *pdata, unsigned int periphid) +{ + return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata, + periphid, ~0ULL, &iomem_resource); +} +EXPORT_SYMBOL_GPL(amba_ahb_device_add); + +struct amba_device * +amba_apb_device_add_res(struct device *parent, const char *name, + resource_size_t base, size_t size, int irq1, + int irq2, void *pdata, unsigned int periphid, + struct resource *resbase) +{ + return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata, + periphid, 0, resbase); +} +EXPORT_SYMBOL_GPL(amba_apb_device_add_res); + +struct amba_device * +amba_ahb_device_add_res(struct device *parent, const char *name, + resource_size_t base, size_t size, int irq1, + int irq2, void *pdata, unsigned int periphid, + struct resource *resbase) +{ + return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata, + periphid, ~0ULL, resbase); +} +EXPORT_SYMBOL_GPL(amba_ahb_device_add_res); + + +static void amba_device_initialize(struct amba_device *dev, const char *name) +{ + device_initialize(&dev->dev); + if (name) + dev_set_name(&dev->dev, "%s", name); + dev->dev.release = amba_device_release; + dev->dev.bus = &amba_bustype; + dev->dev.dma_mask = &dev->dev.coherent_dma_mask; + dev->res.name = dev_name(&dev->dev); +} + +/** + * amba_device_alloc - allocate an AMBA device + * @name: sysfs name of the AMBA device + * @base: base of AMBA device + * @size: size of AMBA device + * + * Allocate and initialize an AMBA device structure. Returns %NULL + * on failure. + */ +struct amba_device *amba_device_alloc(const char *name, resource_size_t base, + size_t size) +{ + struct amba_device *dev; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev) { + amba_device_initialize(dev, name); + dev->res.start = base; + dev->res.end = base + size - 1; + dev->res.flags = IORESOURCE_MEM; + } + + return dev; +} +EXPORT_SYMBOL_GPL(amba_device_alloc); + +/** + * amba_device_register - register an AMBA device + * @dev: AMBA device to register + * @parent: parent memory resource + * + * Setup the AMBA device, reading the cell ID if present. + * Claim the resource, and register the AMBA device with + * the Linux device manager. + */ +int amba_device_register(struct amba_device *dev, struct resource *parent) +{ + amba_device_initialize(dev, dev->dev.init_name); + dev->dev.init_name = NULL; + + return amba_device_add(dev, parent); +} + +/** + * amba_device_put - put an AMBA device + * @dev: AMBA device to put + */ +void amba_device_put(struct amba_device *dev) +{ + put_device(&dev->dev); +} +EXPORT_SYMBOL_GPL(amba_device_put); /** * amba_device_unregister - unregister an AMBA device |
