diff options
| author | Russell King <rmk@flint.arm.linux.org.uk> | 2003-09-17 14:21:55 +0100 |
|---|---|---|
| committer | Russell King <rmk@flint.arm.linux.org.uk> | 2003-09-17 14:21:55 +0100 |
| commit | 893ff1950c8495bcd9f2c75e202e20dcffeb911d (patch) | |
| tree | 7b839af208abfadd5f97082fd4634058bf4e9b33 | |
| parent | 12326f131c98232a5d9b37c7dfcd68c61413b13c (diff) | |
[ARM] Provide bus type and support for logic modules.
The IMPD-1 is a logic module (a stackable module) - rather than
trying to abuse platform devices, create our own bus type to handle
these.
| -rw-r--r-- | arch/arm/mach-integrator/Makefile | 2 | ||||
| -rw-r--r-- | arch/arm/mach-integrator/core.c | 30 | ||||
| -rw-r--r-- | arch/arm/mach-integrator/impd1.c | 61 | ||||
| -rw-r--r-- | arch/arm/mach-integrator/lm.c | 92 | ||||
| -rw-r--r-- | include/asm-arm/arch-integrator/lm.h | 23 |
5 files changed, 171 insertions, 37 deletions
diff --git a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile index bfd77c270a06..c126c5307174 100644 --- a/arch/arm/mach-integrator/Makefile +++ b/arch/arm/mach-integrator/Makefile @@ -4,7 +4,7 @@ # Object file lists. -obj-y := core.o time.o +obj-y := core.o lm.o time.o obj-$(CONFIG_LEDS) += leds.o obj-$(CONFIG_PCI) += pci_v3.o pci.o diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c index c7e7eb4a9c43..67d0fc309304 100644 --- a/arch/arm/mach-integrator/core.c +++ b/arch/arm/mach-integrator/core.c @@ -34,6 +34,8 @@ #include <asm/hardware/amba.h> #include <asm/hardware/amba_kmi.h> +#include <asm/arch/lm.h> + #include <asm/mach/arch.h> #include <asm/mach/irq.h> #include <asm/mach/map.h> @@ -46,6 +48,7 @@ * just for now). */ #define VA_IC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE) +#define VA_SC_BASE IO_ADDRESS(INTEGRATOR_SC_BASE) #define VA_CMIC_BASE IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_IC_OFFSET /* @@ -66,7 +69,7 @@ * f1a00000 1a000000 Debug LEDs * f1b00000 1b000000 GPIO */ - + static struct map_desc integrator_io_desc[] __initdata = { { IO_ADDRESS(INTEGRATOR_HDR_BASE), INTEGRATOR_HDR_BASE, SZ_4K, MT_DEVICE }, { IO_ADDRESS(INTEGRATOR_SC_BASE), INTEGRATOR_SC_BASE, SZ_4K, MT_DEVICE }, @@ -89,7 +92,7 @@ static void __init integrator_map_io(void) iotable_init(integrator_io_desc, ARRAY_SIZE(integrator_io_desc)); } -#define ALLPCI ( (1 << IRQ_PCIINT0) | (1 << IRQ_PCIINT1) | (1 << IRQ_PCIINT2) | (1 << IRQ_PCIINT3) ) +#define ALLPCI ( (1 << IRQ_PCIINT0) | (1 << IRQ_PCIINT1) | (1 << IRQ_PCIINT2) | (1 << IRQ_PCIINT3) ) static void sc_mask_irq(unsigned int irq) { @@ -161,6 +164,7 @@ static struct amba_device *amba_devs[] __initdata = { static int __init register_devices(void) { + unsigned long sc_dec; int i; for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { @@ -169,6 +173,28 @@ static int __init register_devices(void) amba_device_register(d, &iomem_resource); } + sc_dec = readl(VA_SC_BASE + INTEGRATOR_SC_DEC_OFFSET); + for (i = 0; i < 4; i++) { + struct lm_device *lmdev; + + if ((sc_dec & (16 << i)) == 0) + continue; + + lmdev = kmalloc(sizeof(struct lm_device), GFP_KERNEL); + if (!lmdev) + continue; + + memset(lmdev, 0, sizeof(struct lm_device)); + + lmdev->resource.start = 0xc0000000 + 0x10000000 * i; + lmdev->resource.end = lmdev->resource.start + 0x0fffffff; + lmdev->resource.flags = IORESOURCE_MEM; + lmdev->irq = IRQ_EXPINT0 + i; + lmdev->id = i; + + lm_device_register(lmdev); + } + return 0; } diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c index 15e2e27da2de..1fc9d9535ab8 100644 --- a/arch/arm/mach-integrator/impd1.c +++ b/arch/arm/mach-integrator/impd1.c @@ -10,7 +10,7 @@ * This file provides the core support for the IM-PD1 module. * * Module / boot parameters. - * id=n impd1.id=n - set the logic module position in stack to 'n' + * lmid=n impd1.lmid=n - set the logic module position in stack to 'n' */ #include <linux/module.h> #include <linux/moduleparam.h> @@ -21,17 +21,15 @@ #include <asm/io.h> #include <asm/hardware/icst525.h> #include <asm/hardware/amba.h> +#include <asm/arch/lm.h> #include <asm/arch/impd1.h> #include <asm/sizes.h> static int module_id; -module_param_named(lmid, module_id, int, 0); +module_param_named(lmid, module_id, int, 0444); MODULE_PARM_DESC(lmid, "logic module stack position"); -#define ROM_OFFSET 0x0fffff00 -#define ROM_SIZE 256 - struct impd1_module { void *base; }; @@ -142,17 +140,15 @@ static struct impd1_device impd1_devs[] = { } }; -static int impd1_probe(struct device *dev) +static int impd1_probe(struct lm_device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct resource *res = &pdev->resource[0]; struct impd1_module *impd1; int i, ret; - if (pdev->id != module_id) + if (dev->id != module_id) return -EINVAL; - if (!request_mem_region(res->start, SZ_4K, "LM registers")) + if (!request_mem_region(dev->resource.start, SZ_4K, "LM registers")) return -EBUSY; impd1 = kmalloc(sizeof(struct impd1_module), GFP_KERNEL); @@ -162,22 +158,22 @@ static int impd1_probe(struct device *dev) } memset(impd1, 0, sizeof(struct impd1_module)); - impd1->base = ioremap(res->start, SZ_4K); + impd1->base = ioremap(dev->resource.start, SZ_4K); if (!impd1->base) { ret = -ENOMEM; goto free_impd1; } - dev_set_drvdata(dev, impd1); + lm_set_drvdata(dev, impd1); - printk("IM-PD1 found at 0x%08lx\n", res->start); + printk("IM-PD1 found at 0x%08lx\n", dev->resource.start); for (i = 0; i < ARRAY_SIZE(impd1_devs); i++) { struct impd1_device *idev = impd1_devs + i; struct amba_device *d; unsigned long pc_base; - pc_base = res->start + idev->offset; + pc_base = dev->resource.start + idev->offset; d = kmalloc(sizeof(struct amba_device), GFP_KERNEL); if (!d) @@ -186,16 +182,16 @@ static int impd1_probe(struct device *dev) memset(d, 0, sizeof(struct amba_device)); snprintf(d->dev.bus_id, sizeof(d->dev.bus_id), - "lm%x:%5.5lx", pdev->id, idev->offset >> 12); + "lm%x:%5.5lx", dev->id, idev->offset >> 12); - d->dev.parent = &pdev->dev; - d->res.start = res->start + idev->offset; + d->dev.parent = &dev->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 = pdev->resource[1].start; + d->irq = dev->irq; d->periphid = idev->id; - ret = amba_device_register(d, res); + ret = amba_device_register(d, &dev->resource); if (ret) { printk("unable to register device %s: %d\n", d->dev.bus_id, ret); @@ -211,47 +207,44 @@ static int impd1_probe(struct device *dev) if (impd1) kfree(impd1); release_lm: - release_mem_region(res->start, SZ_4K); + release_mem_region(dev->resource.start, SZ_4K); return ret; } -static int impd1_remove(struct device *dev) +static void impd1_remove(struct lm_device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct resource *res = &pdev->resource[0]; - struct impd1_module *impd1 = dev_get_drvdata(dev); + struct impd1_module *impd1 = lm_get_drvdata(dev); struct list_head *l, *n; - list_for_each_safe(l, n, &dev->children) { + list_for_each_safe(l, n, &dev->dev.children) { struct device *d = list_to_dev(l); device_unregister(d); } - dev_set_drvdata(dev, NULL); + lm_set_drvdata(dev, NULL); iounmap(impd1->base); kfree(impd1); - release_mem_region(res->start, SZ_4K); - - return 0; + release_mem_region(dev->resource.start, SZ_4K); } -static struct device_driver impd1_driver = { - .name = "lm", - .bus = &platform_bus_type, +static struct lm_driver impd1_driver = { + .drv = { + .name = "impd1", + }, .probe = impd1_probe, .remove = impd1_remove, }; static int __init impd1_init(void) { - return driver_register(&impd1_driver); + return lm_driver_register(&impd1_driver); } static void __exit impd1_exit(void) { - driver_unregister(&impd1_driver); + lm_driver_unregister(&impd1_driver); } module_init(impd1_init); diff --git a/arch/arm/mach-integrator/lm.c b/arch/arm/mach-integrator/lm.c new file mode 100644 index 000000000000..86051e509cfd --- /dev/null +++ b/arch/arm/mach-integrator/lm.c @@ -0,0 +1,92 @@ +/* + * linux/arch/arm/mach-integrator/lm.c + * + * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/init.h> +#include <linux/device.h> + +#include <asm/arch/lm.h> + +#define to_lm_device(d) container_of(d, struct lm_device, dev) +#define to_lm_driver(d) container_of(d, struct lm_driver, drv) + +static int lm_match(struct device *dev, struct device_driver *drv) +{ + return 1; +} + +static struct bus_type lm_bustype = { + .name = "logicmodule", + .match = lm_match, +// .suspend = lm_suspend, +// .resume = lm_resume, +}; + +static int __init lm_init(void) +{ + return bus_register(&lm_bustype); +} + +postcore_initcall(lm_init); + +static int lm_bus_probe(struct device *dev) +{ + struct lm_device *lmdev = to_lm_device(dev); + struct lm_driver *lmdrv = to_lm_driver(dev->driver); + + return lmdrv->probe(lmdev); +} + +static int lm_bus_remove(struct device *dev) +{ + struct lm_device *lmdev = to_lm_device(dev); + struct lm_driver *lmdrv = to_lm_driver(dev->driver); + + lmdrv->remove(lmdev); + return 0; +} + +int lm_driver_register(struct lm_driver *drv) +{ + drv->drv.bus = &lm_bustype; + drv->drv.probe = lm_bus_probe; + drv->drv.remove = lm_bus_remove; + + return driver_register(&drv->drv); +} + +void lm_driver_unregister(struct lm_driver *drv) +{ + driver_unregister(&drv->drv); +} + +static void lm_device_release(struct device *dev) +{ + struct lm_device *d = to_lm_device(dev); + + kfree(d); +} + +int lm_device_register(struct lm_device *dev) +{ + int ret; + + dev->dev.release = lm_device_release; + dev->dev.bus = &lm_bustype; + + snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), "lm%d", dev->id); + dev->resource.name = dev->dev.bus_id; + + ret = request_resource(&iomem_resource, &dev->resource); + if (ret == 0) { + ret = device_register(&dev->dev); + if (ret) + release_resource(&dev->resource); + } + return ret; +} diff --git a/include/asm-arm/arch-integrator/lm.h b/include/asm-arm/arch-integrator/lm.h new file mode 100644 index 000000000000..d792b112974c --- /dev/null +++ b/include/asm-arm/arch-integrator/lm.h @@ -0,0 +1,23 @@ + +struct lm_device { + struct device dev; + struct resource resource; + unsigned int irq; + unsigned int id; +}; + +struct lm_driver { + struct device_driver drv; + int (*probe)(struct lm_device *); + void (*remove)(struct lm_device *); + int (*suspend)(struct lm_device *, u32); + int (*resume)(struct lm_device *); +}; + +int lm_driver_register(struct lm_driver *drv); +void lm_driver_unregister(struct lm_driver *drv); + +int lm_device_register(struct lm_device *dev); + +#define lm_get_drvdata(lm) dev_get_drvdata(&(lm)->dev) +#define lm_set_drvdata(lm,d) dev_set_drvdata(&(lm)->dev, d) |
