From f99d18feab15a58e4ec8e7f2850b8d4f10d9909a Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 6 Feb 2004 15:02:20 +0000 Subject: [PATCH] [ARM] Update AMBA device/driver support - Add methods to request/release regions. - Add method to find AMBA devices. - Only register devices whose ID is known. - Devices may have two interrupt signals. - Add hotplug method. --- arch/arm/common/amba.c | 140 ++++++++++++++++++++++++++----- arch/arm/mach-integrator/core.c | 10 +-- arch/arm/mach-integrator/impd1.c | 3 +- include/asm-arm/hardware/amba.h | 12 ++- 4 files changed, 136 insertions(+), 29 deletions(-) diff --git a/arch/arm/common/amba.c b/arch/arm/common/amba.c index 0947c1b8fc1e5..cdfc26e27e012 100644 --- a/arch/arm/common/amba.c +++ b/arch/arm/common/amba.c @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -41,6 +42,23 @@ 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_hotplug(struct device *dev, char **envp, int nr_env, char *buf, int bufsz) +{ + struct amba_device *pcdev = to_amba_device(dev); + + if (nr_env < 2) + return -ENOMEM; + + snprintf(buf, bufsz, "AMBA_ID=%08lx", pcdev->periphid); + *envp++ = buf; + *envp++ = NULL; + return 0; +} +#else +#define amba_hotplug NULL +#endif + static int amba_suspend(struct device *dev, u32 state) { struct amba_driver *drv = to_amba_driver(dev->driver); @@ -68,6 +86,7 @@ static int amba_resume(struct device *dev) static struct bus_type amba_bustype = { .name = "amba", .match = amba_match, + .hotplug = amba_hotplug, .suspend = amba_suspend, .resume = amba_resume, }; @@ -149,27 +168,19 @@ static void amba_device_release(struct device *dev) kfree(d); } -static ssize_t show_id(struct device *_dev, char *buf) -{ - struct amba_device *dev = to_amba_device(_dev); - return sprintf(buf, "%08x\n", dev->periphid); -} -static DEVICE_ATTR(id, S_IRUGO, show_id, NULL); +#define amba_attr(name,fmt,arg...) \ +static ssize_t show_##name(struct device *_dev, char *buf) \ +{ \ + struct amba_device *dev = to_amba_device(_dev); \ + return sprintf(buf, fmt, arg); \ +} \ +static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) -static ssize_t show_irq(struct device *_dev, char *buf) -{ - struct amba_device *dev = to_amba_device(_dev); - return sprintf(buf, "%u\n", dev->irq); -} -static DEVICE_ATTR(irq, S_IRUGO, show_irq, NULL); - -static ssize_t show_res(struct device *_dev, char *buf) -{ - struct amba_device *dev = to_amba_device(_dev); - return sprintf(buf, "\t%08lx\t%08lx\t%08lx\n", - dev->res.start, dev->res.end, dev->res.flags); -} -static DEVICE_ATTR(resource, S_IRUGO, show_res, NULL); +amba_attr(id, "%08x\n", dev->periphid); +amba_attr(irq0, "%u\n", dev->irq[0]); +amba_attr(irq1, "%u\n", dev->irq[1]); +amba_attr(resource, "\t%08lx\t%08lx\t%08lx\n", + dev->res.start, dev->res.end, dev->res.flags); /** * amba_device_register - register an AMBA device @@ -208,10 +219,17 @@ int amba_device_register(struct amba_device *dev, struct resource *parent) if (cid == 0xb105f00d) dev->periphid = pid; - ret = device_register(&dev->dev); + if (dev->periphid) + ret = device_register(&dev->dev); + else + ret = -ENODEV; + if (ret == 0) { device_create_file(&dev->dev, &dev_attr_id); - device_create_file(&dev->dev, &dev_attr_irq); + if (dev->irq[0] != NO_IRQ) + device_create_file(&dev->dev, &dev_attr_irq0); + if (dev->irq[1] != NO_IRQ) + device_create_file(&dev->dev, &dev_attr_irq1); device_create_file(&dev->dev, &dev_attr_resource); } else { out: @@ -237,7 +255,85 @@ void amba_device_unregister(struct amba_device *dev) device_unregister(&dev->dev); } + +struct find_data { + struct amba_device *dev; + struct device *parent; + const char *busid; + unsigned int id; + unsigned int mask; +}; + +static int amba_find_match(struct device *dev, void *data) +{ + struct find_data *d = data; + struct amba_device *pcdev = to_amba_device(dev); + int r; + + r = (pcdev->periphid & d->mask) == d->id; + if (d->parent) + r &= d->parent == dev->parent; + if (d->busid) + r &= strcmp(dev->bus_id, d->busid) == 0; + + if (r) { + get_device(dev); + d->dev = pcdev; + } + + return r; +} + +/** + * amba_find_device - locate an AMBA device given a bus id + * @busid: bus id for device (or NULL) + * @parent: parent device (or NULL) + * @id: peripheral ID (or 0) + * @mask: peripheral ID mask (or 0) + * + * Return the AMBA device corresponding to the supplied parameters. + * If no device matches, returns NULL. + * + * NOTE: When a valid device is found, its refcount is + * incremented, and must be decremented before the returned + * reference. + */ +struct amba_device * +amba_find_device(const char *busid, struct device *parent, unsigned int id, + unsigned int mask) +{ + struct find_data data; + + data.dev = NULL; + data.parent = parent; + data.busid = busid; + data.id = id; + data.mask = mask; + + bus_for_each_dev(&amba_bustype, NULL, &data, amba_find_match); + + return data.dev; +} + +int amba_request_regions(struct amba_device *dev, const char *name) +{ + int ret = 0; + + if (!request_mem_region(dev->res.start, SZ_4K, name)) + ret = -EBUSY; + + return ret; +} + +void amba_release_regions(struct amba_device *dev) +{ + release_mem_region(dev->res.start, SZ_4K); +} + EXPORT_SYMBOL(amba_driver_register); EXPORT_SYMBOL(amba_driver_unregister); EXPORT_SYMBOL(amba_device_register); EXPORT_SYMBOL(amba_device_unregister); +EXPORT_SYMBOL(amba_find_device); +EXPORT_SYMBOL(amba_request_regions); +EXPORT_SYMBOL(amba_release_regions); diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c index 5ca1a1dda4953..a4f8fdfa7e939 100644 --- a/arch/arm/mach-integrator/core.c +++ b/arch/arm/mach-integrator/core.c @@ -25,7 +25,7 @@ static struct amba_device rtc_device = { .end = INTEGRATOR_RTC_BASE + SZ_4K - 1, .flags = IORESOURCE_MEM, }, - .irq = IRQ_RTCINT, + .irq = { IRQ_RTCINT, NO_IRQ }, .periphid = 0x00041030, }; @@ -38,7 +38,7 @@ static struct amba_device uart0_device = { .end = INTEGRATOR_UART0_BASE + SZ_4K - 1, .flags = IORESOURCE_MEM, }, - .irq = IRQ_UARTINT0, + .irq = { IRQ_UARTINT0, NO_IRQ }, .periphid = 0x0041010, }; @@ -51,7 +51,7 @@ static struct amba_device uart1_device = { .end = INTEGRATOR_UART1_BASE + SZ_4K - 1, .flags = IORESOURCE_MEM, }, - .irq = IRQ_UARTINT1, + .irq = { IRQ_UARTINT1, NO_IRQ }, .periphid = 0x0041010, }; @@ -64,7 +64,7 @@ static struct amba_device kmi0_device = { .end = KMI0_BASE + SZ_4K - 1, .flags = IORESOURCE_MEM, }, - .irq = IRQ_KMIINT0, + .irq = { IRQ_KMIINT0, NO_IRQ }, .periphid = 0x00041050, }; @@ -77,7 +77,7 @@ static struct amba_device kmi1_device = { .end = KMI1_BASE + SZ_4K - 1, .flags = IORESOURCE_MEM, }, - .irq = IRQ_KMIINT1, + .irq = { IRQ_KMIINT1, NO_IRQ }, .periphid = 0x00041050, }; diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c index 1fc9d9535ab8c..dfdd5ecdf1315 100644 --- a/arch/arm/mach-integrator/impd1.c +++ b/arch/arm/mach-integrator/impd1.c @@ -188,7 +188,8 @@ static int impd1_probe(struct lm_device *dev) d->res.start = dev->resource.start + idev->offset; d->res.end = d->res.start + SZ_4K - 1; d->res.flags = IORESOURCE_MEM; - d->irq = dev->irq; + d->irq[0] = dev->irq; + d->irq[1] = dev->irq; d->periphid = idev->id; ret = amba_device_register(d, &dev->resource); diff --git a/include/asm-arm/hardware/amba.h b/include/asm-arm/hardware/amba.h index 174afa5d16c2e..17bb14bf43767 100644 --- a/include/asm-arm/hardware/amba.h +++ b/include/asm-arm/hardware/amba.h @@ -10,11 +10,13 @@ #ifndef ASMARM_AMBA_H #define ASMARM_AMBA_H +#define AMBA_NR_IRQS 2 + struct amba_device { struct device dev; struct resource res; - unsigned int irq; unsigned int periphid; + unsigned int irq[AMBA_NR_IRQS]; }; struct amba_id { @@ -40,5 +42,13 @@ int amba_driver_register(struct amba_driver *); void amba_driver_unregister(struct amba_driver *); int amba_device_register(struct amba_device *, struct resource *); void amba_device_unregister(struct amba_device *); +struct amba_device *amba_find_device(const char *, struct device *, unsigned int, unsigned int); +int amba_request_regions(struct amba_device *, const char *); +void amba_release_regions(struct amba_device *); + +#define amba_config(d) (((d)->periphid >> 24) & 0xff) +#define amba_rev(d) (((d)->periphid >> 20) & 0x0f) +#define amba_manf(d) (((d)->periphid >> 12) & 0xff) +#define amba_part(d) ((d)->periphid & 0xfff) #endif -- 2.53.0