Commit 893ff195 authored by Russell King's avatar Russell King

[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.
parent 12326f13
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
# Object file lists. # Object file lists.
obj-y := core.o time.o obj-y := core.o lm.o time.o
obj-$(CONFIG_LEDS) += leds.o obj-$(CONFIG_LEDS) += leds.o
obj-$(CONFIG_PCI) += pci_v3.o pci.o obj-$(CONFIG_PCI) += pci_v3.o pci.o
......
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
#include <asm/hardware/amba.h> #include <asm/hardware/amba.h>
#include <asm/hardware/amba_kmi.h> #include <asm/hardware/amba_kmi.h>
#include <asm/arch/lm.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/mach/irq.h> #include <asm/mach/irq.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
...@@ -46,6 +48,7 @@ ...@@ -46,6 +48,7 @@
* just for now). * just for now).
*/ */
#define VA_IC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE) #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 #define VA_CMIC_BASE IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_IC_OFFSET
/* /*
...@@ -66,7 +69,7 @@ ...@@ -66,7 +69,7 @@
* f1a00000 1a000000 Debug LEDs * f1a00000 1a000000 Debug LEDs
* f1b00000 1b000000 GPIO * f1b00000 1b000000 GPIO
*/ */
static struct map_desc integrator_io_desc[] __initdata = { static struct map_desc integrator_io_desc[] __initdata = {
{ IO_ADDRESS(INTEGRATOR_HDR_BASE), INTEGRATOR_HDR_BASE, SZ_4K, MT_DEVICE }, { IO_ADDRESS(INTEGRATOR_HDR_BASE), INTEGRATOR_HDR_BASE, SZ_4K, MT_DEVICE },
{ IO_ADDRESS(INTEGRATOR_SC_BASE), INTEGRATOR_SC_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) ...@@ -89,7 +92,7 @@ static void __init integrator_map_io(void)
iotable_init(integrator_io_desc, ARRAY_SIZE(integrator_io_desc)); 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) static void sc_mask_irq(unsigned int irq)
{ {
...@@ -161,6 +164,7 @@ static struct amba_device *amba_devs[] __initdata = { ...@@ -161,6 +164,7 @@ static struct amba_device *amba_devs[] __initdata = {
static int __init register_devices(void) static int __init register_devices(void)
{ {
unsigned long sc_dec;
int i; int i;
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
...@@ -169,6 +173,28 @@ static int __init register_devices(void) ...@@ -169,6 +173,28 @@ static int __init register_devices(void)
amba_device_register(d, &iomem_resource); 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; return 0;
} }
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* This file provides the core support for the IM-PD1 module. * This file provides the core support for the IM-PD1 module.
* *
* Module / boot parameters. * 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/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
...@@ -21,17 +21,15 @@ ...@@ -21,17 +21,15 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/hardware/icst525.h> #include <asm/hardware/icst525.h>
#include <asm/hardware/amba.h> #include <asm/hardware/amba.h>
#include <asm/arch/lm.h>
#include <asm/arch/impd1.h> #include <asm/arch/impd1.h>
#include <asm/sizes.h> #include <asm/sizes.h>
static int module_id; 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"); MODULE_PARM_DESC(lmid, "logic module stack position");
#define ROM_OFFSET 0x0fffff00
#define ROM_SIZE 256
struct impd1_module { struct impd1_module {
void *base; void *base;
}; };
...@@ -142,17 +140,15 @@ static struct impd1_device impd1_devs[] = { ...@@ -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; struct impd1_module *impd1;
int i, ret; int i, ret;
if (pdev->id != module_id) if (dev->id != module_id)
return -EINVAL; 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; return -EBUSY;
impd1 = kmalloc(sizeof(struct impd1_module), GFP_KERNEL); impd1 = kmalloc(sizeof(struct impd1_module), GFP_KERNEL);
...@@ -162,22 +158,22 @@ static int impd1_probe(struct device *dev) ...@@ -162,22 +158,22 @@ static int impd1_probe(struct device *dev)
} }
memset(impd1, 0, sizeof(struct impd1_module)); 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) { if (!impd1->base) {
ret = -ENOMEM; ret = -ENOMEM;
goto free_impd1; 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++) { for (i = 0; i < ARRAY_SIZE(impd1_devs); i++) {
struct impd1_device *idev = impd1_devs + i; struct impd1_device *idev = impd1_devs + i;
struct amba_device *d; struct amba_device *d;
unsigned long pc_base; 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); d = kmalloc(sizeof(struct amba_device), GFP_KERNEL);
if (!d) if (!d)
...@@ -186,16 +182,16 @@ static int impd1_probe(struct device *dev) ...@@ -186,16 +182,16 @@ static int impd1_probe(struct device *dev)
memset(d, 0, sizeof(struct amba_device)); memset(d, 0, sizeof(struct amba_device));
snprintf(d->dev.bus_id, sizeof(d->dev.bus_id), 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->dev.parent = &dev->dev;
d->res.start = res->start + idev->offset; d->res.start = dev->resource.start + idev->offset;
d->res.end = d->res.start + SZ_4K - 1; d->res.end = d->res.start + SZ_4K - 1;
d->res.flags = IORESOURCE_MEM; d->res.flags = IORESOURCE_MEM;
d->irq = pdev->resource[1].start; d->irq = dev->irq;
d->periphid = idev->id; d->periphid = idev->id;
ret = amba_device_register(d, res); ret = amba_device_register(d, &dev->resource);
if (ret) { if (ret) {
printk("unable to register device %s: %d\n", printk("unable to register device %s: %d\n",
d->dev.bus_id, ret); d->dev.bus_id, ret);
...@@ -211,47 +207,44 @@ static int impd1_probe(struct device *dev) ...@@ -211,47 +207,44 @@ static int impd1_probe(struct device *dev)
if (impd1) if (impd1)
kfree(impd1); kfree(impd1);
release_lm: release_lm:
release_mem_region(res->start, SZ_4K); release_mem_region(dev->resource.start, SZ_4K);
return ret; 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 impd1_module *impd1 = lm_get_drvdata(dev);
struct resource *res = &pdev->resource[0];
struct impd1_module *impd1 = dev_get_drvdata(dev);
struct list_head *l, *n; 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); struct device *d = list_to_dev(l);
device_unregister(d); device_unregister(d);
} }
dev_set_drvdata(dev, NULL); lm_set_drvdata(dev, NULL);
iounmap(impd1->base); iounmap(impd1->base);
kfree(impd1); kfree(impd1);
release_mem_region(res->start, SZ_4K); release_mem_region(dev->resource.start, SZ_4K);
return 0;
} }
static struct device_driver impd1_driver = { static struct lm_driver impd1_driver = {
.name = "lm", .drv = {
.bus = &platform_bus_type, .name = "impd1",
},
.probe = impd1_probe, .probe = impd1_probe,
.remove = impd1_remove, .remove = impd1_remove,
}; };
static int __init impd1_init(void) static int __init impd1_init(void)
{ {
return driver_register(&impd1_driver); return lm_driver_register(&impd1_driver);
} }
static void __exit impd1_exit(void) static void __exit impd1_exit(void)
{ {
driver_unregister(&impd1_driver); lm_driver_unregister(&impd1_driver);
} }
module_init(impd1_init); module_init(impd1_init);
......
/*
* 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;
}
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)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment