Driver model for sa1101
Matan Ziv-Av
matan@svgalib.org
Sat Jul 10 13:26:07 CEST 2004
The attached patch integrates the sa1101 code better with the driver
model. Now pcmcia is initialized, and recognizes card insertion/removal,
but does not seem to receive interrupts, and does not work. Example:
DETECT Vcc -1069726244 Vpp -1069726244 irq -1069643856
sa1101_pcmcia: CF sock=1 VPP 33 ???
DETECT Vcc -1069726244 Vpp -1069726244 irq -1069726244
sa1101_pcmcia: CF sock=1 VPP 33 ???
DETECT Vcc -1069726244 Vpp -1069726244 irq -1069726244
sa1101_pcmcia: CF sock=1 VPP 33 ???
VFS: Mounted root (ext2 filesystem).
Mounted devfs on /dev
Freeing init memory: 68K
init started: BusyBox v1.00-pre10 (2004.07.10-08:20+0000) multi-call binary
CLASS: registering class device: ID = 'vcs1'
class_hotplug - name = vcs1
/bin/sh: can't access tty; job control turned off
/ # CLASS: registering class device: ID = 'vcsa1'
class_hotplug - name = vcsa1
DETECT Vcc -1069726244 Vpp -1069726244 irq -1069643856
DETECT Vcc -1069726244 Vpp -1069726244 irq -1069643856
sa1101_pcmcia: CF sock=1 VPP 33 ???
DETECT Vcc -1069726244 Vpp -1069726244 irq -1069726244
sa1101_pcmcia: CF sock=1 VPP 33 ???
DETECT Vcc -1069726244 Vpp -1069726244 irq -1069726244
sa1101_pcmcia: CF sock=1 VPP 33 ???
CLASS: registering class device: ID = 'vcs2'
class_hotplug - name = vcs2
CLASS: registering class device: ID = 'vcsa2'
class_hotplug - name = vcsa2
DETECT Vcc -1069726244 Vpp -1069726244 irq -1069643856
DETECT Vcc -1069726244 Vpp -1069726244 irq -1069643856
sa1101_pcmcia: CF sock=1 VPP 33 ???
DETECT Vcc -1069726244 Vpp -1069726244 irq -1069726244
sa1101_pcmcia: CF sock=1 VPP 33 ???
DETECT Vcc -1069726244 Vpp -1069726244 irq -1069726244
sa1101_pcmcia: CF sock=1 VPP 33 ???
DETECT Vcc -1069726244 Vpp -1069726244 irq -1069643856
sa1101_pcmcia: sock=0 unrecognised VPP 33
soc_common_pcmcia: unable to configure socket 0
cs: pcmcia_socket0: unable to apply power.
DETECT Vcc -1069726244 Vpp -1069726244 irq -1069643856
I hope someone else will debug the PCMCIA, since I intend to work on the
USB host.
The code certainly needs a lot of cleaning up, but I think it is better
to work at least to 2.4 level functionality before I do that.
--
Matan Ziv-Av. matan@svgalib.org
-------------- next part --------------
diff -urbB kernel26/arch/arm/common/sa1101.c my2/arch/arm/common/sa1101.c
--- kernel26/arch/arm/common/sa1101.c 2004-07-07 20:26:18.000000000 +0300
+++ my2/arch/arm/common/sa1101.c 2004-07-10 14:12:28.000000000 +0300
@@ -32,7 +32,7 @@
#include <asm/arch/SA-1101.h>
#include <asm/hardware/sa1101.h>
#include <asm/mach/irq.h>
-#include <asm/arch/irq.h>
+#include <asm/arch/irqs.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -44,6 +44,146 @@
* anchor point for all the other drivers.
*/
+static int sa1101_match(struct device *_dev, struct device_driver *_drv);
+static int sa1101_bus_suspend(struct device *dev, u32 state);
+static int sa1101_bus_resume(struct device *dev);
+
+struct bus_type sa1101_bus_type = {
+ .name = "sa1101-bus",
+ .match = sa1101_match,
+ .suspend = sa1101_bus_suspend,
+ .resume = sa1101_bus_resume,
+};
+
+struct sa1101_dev_info {
+ unsigned long offset;
+ unsigned long skpcr_mask;
+ unsigned int devid;
+ unsigned int irq[6];
+};
+
+static struct sa1101_dev_info sa1101_devices[] = {
+#if 0
+ {
+ .offset = SA1111_USB,
+ .skpcr_mask = SKPCR_UCLKEN,
+ .devid = SA1111_DEVID_USB,
+ .irq = {
+ IRQ_USBPWR,
+ IRQ_HCIM,
+ IRQ_HCIBUFFACC,
+ IRQ_HCIRMTWKP,
+ IRQ_NHCIMFCIR,
+ IRQ_USB_PORT_RESUME
+ },
+ },
+ {
+ .offset = 0x0600,
+ .skpcr_mask = SKPCR_I2SCLKEN | SKPCR_L3CLKEN,
+ .devid = SA1111_DEVID_SAC,
+ .irq = {
+ AUDXMTDMADONEA,
+ AUDXMTDMADONEB,
+ AUDRCVDMADONEA,
+ AUDRCVDMADONEB
+ },
+ },
+ {
+ .offset = 0x0800,
+ .skpcr_mask = SKPCR_SCLKEN,
+ .devid = SA1111_DEVID_SSP,
+ },
+ {
+ .offset = SA1111_KBD,
+ .skpcr_mask = SKPCR_PTCLKEN,
+ .devid = SA1111_DEVID_PS2,
+ .irq = {
+ IRQ_TPRXINT,
+ IRQ_TPTXINT
+ },
+ },
+ {
+ .offset = SA1111_MSE,
+ .skpcr_mask = SKPCR_PMCLKEN,
+ .devid = SA1111_DEVID_PS2,
+ .irq = {
+ IRQ_MSRXINT,
+ IRQ_MSTXINT
+ },
+ },
+#endif
+ {
+ .offset = 0x1e0000,
+ .skpcr_mask = 0,
+ .devid = SA1101_DEVID_PCMCIA,
+ .irq = {
+ IRQ_S0_READY_NINT,
+ IRQ_S0_CD_VALID,
+ IRQ_S0_BVD1_STSCHG,
+ IRQ_S1_READY_NINT,
+ IRQ_S1_CD_VALID,
+ IRQ_S1_BVD1_STSCHG,
+ },
+ },
+};
+
+static void sa1101_dev_release(struct device *_dev)
+{
+ struct sa1101_dev *dev = SA1101_DEV(_dev);
+
+ release_resource(&dev->res);
+ kfree(dev);
+}
+
+static int
+sa1101_init_one_child(struct device *parent, struct resource *parent_res,
+ struct sa1101_dev_info *info)
+{
+ struct sa1101_dev *dev;
+ int ret;
+
+ dev = kmalloc(sizeof(struct sa1101_dev), GFP_KERNEL);
+ if (!dev) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ memset(dev, 0, sizeof(struct sa1101_dev));
+
+ snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id),
+ "%4.4lx", info->offset);
+
+ dev->devid = info->devid;
+ dev->dev.parent = parent;
+ dev->dev.bus = &sa1101_bus_type;
+ dev->dev.release = sa1101_dev_release;
+ dev->dev.coherent_dma_mask = 0xffffffff;
+ dev->res.start = 0x18000000 + info->offset;
+ dev->res.end = dev->res.start + 0x1ffff;
+ dev->res.name = dev->dev.bus_id;
+ dev->res.flags = IORESOURCE_MEM;
+ dev->mapbase = (u8 *)0xf4000000 + info->offset;
+ dev->skpcr_mask = info->skpcr_mask;
+ memmove(dev->irq, info->irq, sizeof(dev->irq));
+#if 0
+ ret = request_resource(parent_res, &dev->res);
+ if (ret) {
+ printk("SA1101: failed to allocate resource for %s\n",
+ dev->res.name);
+ kfree(dev);
+ goto out;
+ }
+#endif
+ ret = device_register(&dev->dev);
+ if (ret) {
+ release_resource(&dev->res);
+ kfree(dev);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
static struct resource sa1101_resource = {
.name = "SA1101"
};
@@ -52,24 +192,23 @@
* Figure out whether we can see the SA1101
*/
-int __init sa1101_probe(unsigned long phys_addr)
+int sa1101_probe(struct device * _dev)
{
- int ret = -ENODEV;
+ struct sa1101_dev *dev = SA1101_DEV(_dev);
+ /* should check */
+ int i;
+ u32 has_devs;
- sa1101_resource.start = phys_addr;
- sa1101_resource.end = phys_addr + 0x00400000;
+ sa1101_wake();
+ sa1101_init_irq(GPIO_JORNADA820_SA1101_CHAIN_IRQ);
- if (request_resource(&iomem_resource, &sa1101_resource)) {
- printk(KERN_INFO "Failed to map SA1101 chip.\n");
- ret = -EBUSY;
- goto out;
- }
+ has_devs = 0xffffffff;
- printk(KERN_INFO "SA1101 Microprocessor Companion Chip mapped.\n");
- ret=0;
+ for (i = 0; i < ARRAY_SIZE(sa1101_devices); i++)
+ if (has_devs & (1 << i))
+ sa1101_init_one_child(&dev->dev, &dev->res, &sa1101_devices[i]);
- out:
- return ret;
+ return 0;
}
/*
@@ -94,14 +233,14 @@
sa1101_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
{
unsigned int stat0, stat1, i;
-// printk("Got sa1101 interrupt (%d).\n", irq); // DEBUG
stat0 = INTSTATCLR0;
stat1 = INTSTATCLR1;
INTSTATCLR0 = stat0;
- desc->chip->ack(irq);
INTSTATCLR1 = stat1;
+ desc->chip->ack(irq);
+
if (stat0 == 0 && stat1 == 0) {
do_bad_IRQ(irq, desc, regs);
return;
@@ -121,7 +260,6 @@
static void sa1101_ack_irq(unsigned int irq)
{
-// printk("Got SA1101 interrupt %d.\n", irq); // DEBUG
}
static void mask_low_irq(unsigned int irq)
@@ -250,10 +388,8 @@
{
unsigned int irq;
- // printk("initializing sa1101...\n"); // DEBUG
-
alloc_irq_space(64); /* XXX - still needed??? */
- request_mem_region(_INTTEST0, 512, "irqs"); // XXX - still needed???
+ request_mem_region(_INTTEST0, 512, "irqs-1101"); // XXX - still needed???
/* disable all IRQs */
INTENABLE0 = 0;
@@ -289,8 +425,10 @@
*/
// request_irq(sa1101_irq, debug_sa1101_irq_handler, SA_INTERRUPT,
// "SA1101 chain interrupt", NULL); // DEBUG
- set_irq_chained_handler(sa1101_irq, sa1101_irq_handler); // NORMAL
+
set_irq_type(sa1101_irq, IRQT_RISING);
+ set_irq_data(sa1101_irq, (void *)_INTTEST0);
+ set_irq_chained_handler(sa1101_irq, sa1101_irq_handler); // NORMAL
}
extern void sa1101_wake(void)
@@ -372,13 +510,99 @@
/*********************************************************************************/
+EXPORT_SYMBOL_GPL(sa1101_wake);
+EXPORT_SYMBOL_GPL(sa1101_doze);
+EXPORT_SYMBOL_GPL(sa1101_usb_init);
+EXPORT_SYMBOL_GPL(sa1101_usb_shutdown);
+EXPORT_SYMBOL_GPL(sa1101_vga_init);
+EXPORT_SYMBOL_GPL(sa1101_vga_shutdown);
+
+#if 0
+EXPORT_SYMBOL_GPL(sa1101_enable_device);
+EXPORT_SYMBOL_GPL(sa1101_disable_device);
+EXPORT_SYMBOL_GPL(sa1101_pll_clock);
+#endif
+
+static int sa1101_match(struct device *_dev, struct device_driver *_drv)
+{
+ struct sa1101_dev *dev = SA1101_DEV(_dev);
+ struct sa1101_driver *drv = SA1101_DRV(_drv);
+
+ return dev->devid == drv->devid;
+}
+
+static int sa1101_bus_suspend(struct device *dev, u32 state)
+{
+ struct sa1101_dev *sadev = SA1101_DEV(dev);
+ struct sa1101_driver *drv = SA1101_DRV(dev->driver);
+ int ret = 0;
+
+ if (drv && drv->suspend)
+ ret = drv->suspend(sadev, state);
+ return ret;
+}
+
+static int sa1101_bus_resume(struct device *dev)
+{
+ struct sa1101_dev *sadev = SA1101_DEV(dev);
+ struct sa1101_driver *drv = SA1101_DRV(dev->driver);
+ int ret = 0;
+
+ if (drv && drv->resume)
+ ret = drv->resume(sadev);
+ return ret;
+}
+
+static int sa1101_bus_probe(struct device *dev)
+{
+ struct sa1101_dev *sadev = SA1101_DEV(dev);
+ struct sa1101_driver *drv = SA1101_DRV(dev->driver);
+ int ret = -ENODEV;
+
+ if (drv->probe)
+ ret = drv->probe(sadev);
+ return ret;
+}
+
+static int sa1101_bus_remove(struct device *dev)
+{
+ struct sa1101_dev *sadev = SA1101_DEV(dev);
+ struct sa1101_driver *drv = SA1101_DRV(dev->driver);
+ int ret = -ENODEV;
+
+ if (drv->remove)
+ ret = drv->remove(sadev);
+ return ret;
+}
+
+static int sa1101_suspend(struct device *dev, u32 state, u32 level) {
+ return 0;
+}
+
+static int sa1101_resume(struct device *dev, u32 level) {
+ return 0;
+}
+
+static int sa1101_remove(struct device *dev)
+{
+ return 0;
+}
+
+static struct device_driver sa1101_device_driver = {
+ .name = "sa1101-bus",
+ .bus = &platform_bus_type,
+ .probe = sa1101_probe,
+ .remove = sa1101_remove,
+ .suspend = sa1101_suspend,
+ .resume = sa1101_resume,
+};
+
int sa1101_driver_register(struct sa1101_driver *driver)
{
-// WARN_ON(driver->drv.suspend || driver->drv.resume || driver->drv.probe || driver->drv.remove);
-// driver->drv.probe = sa1101_bus_probe;
-// driver->drv.remove = sa1101_bus_remove;
-// driver->drv.bus = &sa1101_bus_type;
- printk("registering sa1101 driver %s\n",driver->drv.name);
+ WARN_ON(driver->drv.suspend || driver->drv.resume || driver->drv.probe || driver->drv.remove);
+ driver->drv.probe = sa1101_bus_probe;
+ driver->drv.remove = sa1101_bus_remove;
+ driver->drv.bus = &sa1101_bus_type;
return driver_register(&driver->drv);
}
@@ -387,24 +611,26 @@
driver_unregister(&driver->drv);
}
+static int __init sa1101_init(void)
+{
+ int ret = bus_register(&sa1101_bus_type);
-EXPORT_SYMBOL_GPL(sa1101_wake);
-EXPORT_SYMBOL_GPL(sa1101_doze);
-EXPORT_SYMBOL_GPL(sa1101_usb_init);
-EXPORT_SYMBOL_GPL(sa1101_usb_shutdown);
-EXPORT_SYMBOL_GPL(sa1101_vga_init);
-EXPORT_SYMBOL_GPL(sa1101_vga_shutdown);
+ if (ret == 0)
+ driver_register(&sa1101_device_driver);
+ return ret;
+}
-#if 0
-EXPORT_SYMBOL_GPL(sa1101_enable_device);
-EXPORT_SYMBOL_GPL(sa1101_disable_device);
-EXPORT_SYMBOL_GPL(sa1101_pll_clock);
-EXPORT_SYMBOL_GPL(sa1101_driver_register);
-EXPORT_SYMBOL_GPL(sa1101_driver_unregister);
+static void __exit sa1101_exit(void)
+{
+ driver_unregister(&sa1101_device_driver);
+ bus_unregister(&sa1101_bus_type);
+}
module_init(sa1101_init);
module_exit(sa1101_exit);
-#endif
+
+EXPORT_SYMBOL_GPL(sa1101_driver_register);
+EXPORT_SYMBOL_GPL(sa1101_driver_unregister);
MODULE_DESCRIPTION("Main driver for SA-1101 companion chip.");
MODULE_LICENSE("GPL");
diff -urbB kernel26/arch/arm/mach-sa1100/jornada820.c my2/arch/arm/mach-sa1100/jornada820.c
--- kernel26/arch/arm/mach-sa1100/jornada820.c 2004-07-08 19:21:17.000000000 +0300
+++ my2/arch/arm/mach-sa1100/jornada820.c 2004-07-10 13:26:18.000000000 +0300
@@ -16,8 +16,37 @@
#include <asm/irq.h>
#include <asm/hardware.h>
#include <asm/delay.h>
+#include <linux/device.h>
#include "generic.h"
+
+static struct resource sa1101_resources[] = {
+ [0] = {
+ .start = 0x18000000,
+ .end = 0x1bffffff,
+ .flags = IORESOURCE_MEM,
+ },
+/*
+ [1] = {
+ .start = ,
+ .end = IRQ_NEPONSET_SA1111,
+ .flags = IORESOURCE_IRQ,
+ },
+*/
+};
+
+static struct platform_device sa1101_device = {
+ .name = "sa1101-bus",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(sa1101_resources),
+ .resource = sa1101_resources,
+};
+
+static struct platform_device *devices[] __initdata = {
+ &sa1101_device,
+};
+
+
/* *********************************************************************** */
/* Initialize the Jornada 820. */
/* *********************************************************************** */
@@ -58,9 +87,13 @@
/* TODO: remove. */
/* Initialize the 1101. */
- sa1101_probe(SA1101_BASE);
- sa1101_wake();
- sa1101_init_irq(GPIO_JORNADA820_SA1101_CHAIN_IRQ);
+// sa1101_probe(SA1101_BASE);
+// sa1101_wake();
+// sa1101_init_irq(GPIO_JORNADA820_SA1101_CHAIN_IRQ);
+
+
+ return platform_add_devices(devices, ARRAY_SIZE(devices));
+
return 0;
}
diff -urbB kernel26/include/asm-arm/hardware/sa1101.h my2/include/asm-arm/hardware/sa1101.h
--- kernel26/include/asm-arm/hardware/sa1101.h 2004-07-08 13:02:59.000000000 +0300
+++ my2/include/asm-arm/hardware/sa1101.h 2004-07-10 14:10:12.000000000 +0300
@@ -12,9 +12,18 @@
#ifndef __ASSEMBLY__
+struct sa1101_dev {
+ struct device dev;
+ unsigned int devid;
+ struct resource res;
+ void *mapbase;
+ unsigned int skpcr_mask;
+ unsigned int irq[6];
+};
+
/* TODO: driver interface */
/*------------------------*/
-extern int sa1101_probe(unsigned long phys_addr);
+extern int sa1101_probe(struct device *dev);
extern void sa1101_wake(void);
extern void sa1101_doze(void);
@@ -46,16 +55,6 @@
#define SA1101_DEVID_PCMCIA 8
#define SA1101_DEVID_KEYPAD 9
-struct sa1101_dev {
- struct device dev;
- unsigned int devid;
- struct resource res;
- void *mapbase;
- unsigned int skpcr_mask;
- unsigned int irq[6];
- u64 dma_mask;
-};
-
#define SA1101_DEV(_d) container_of((_d), struct sa1101_dev, dev)
#define sa1101_get_drvdata(d) dev_get_drvdata(&(d)->dev)
More information about the Jornada820
mailing list