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 @@
# 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
......
......@@ -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;
}
......
......@@ -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);
......
/*
* 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