Merge tag 'split-asm_system_h-for-linus-20120328' of git://git.kernel.org/pub/scm...
[linux-2.6.git] / drivers / net / ethernet / cirrus / cs89x0.c
index 98c171b..b9406cb 100644 (file)
 
 */
 
-/* Always include 'config.h' first in case the user wants to turn on
-   or override something. */
-#include <linux/module.h>
 
 /*
  * Set this to zero to disable DMA code
 
 */
 
+#include <linux/module.h>
+#include <linux/printk.h>
 #include <linux/errno.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/platform_device.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <linux/atomic.h>
 #if ALLOW_DMA
 #include <asm/dma.h>
 #endif
@@ -173,26 +174,20 @@ static char version[] __initdata =
    them to system IRQ numbers. This mapping is card specific and is set to
    the configuration of the Cirrus Eval board for this chip. */
 #if defined(CONFIG_MACH_IXDP2351)
+#define CS89x0_NONISA_IRQ
 static unsigned int netcard_portlist[] __used __initdata = {IXDP2351_VIRT_CS8900_BASE, 0};
 static unsigned int cs8900_irq_map[] = {IRQ_IXDP2351_CS8900, 0, 0, 0};
 #elif defined(CONFIG_ARCH_IXDP2X01)
+#define CS89x0_NONISA_IRQ
 static unsigned int netcard_portlist[] __used __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0};
 static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0};
-#elif defined(CONFIG_MACH_QQ2440)
-#include <mach/qq2440.h>
-static unsigned int netcard_portlist[] __used __initdata = { QQ2440_CS8900_VIRT_BASE + 0x300, 0 };
-static unsigned int cs8900_irq_map[] = { QQ2440_CS8900_IRQ, 0, 0, 0 };
-#elif defined(CONFIG_MACH_MX31ADS)
-#include <mach/board-mx31ads.h>
-static unsigned int netcard_portlist[] __used __initdata = {
-       PBC_BASE_ADDRESS + PBC_CS8900A_IOBASE + 0x300, 0
-};
-static unsigned cs8900_irq_map[] = {EXPIO_INT_ENET_INT, 0, 0, 0};
 #else
+#ifndef CONFIG_CS89x0_PLATFORM
 static unsigned int netcard_portlist[] __used __initdata =
    { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
 static unsigned int cs8900_irq_map[] = {10,11,12,5};
 #endif
+#endif
 
 #if DEBUGGING
 static unsigned int net_debug = DEBUGGING;
@@ -235,11 +230,16 @@ struct net_local {
        unsigned char *end_dma_buff;    /* points to the end of the buffer */
        unsigned char *rx_dma_ptr;      /* points to the next packet  */
 #endif
+#ifdef CONFIG_CS89x0_PLATFORM
+       void __iomem *virt_addr;/* Virtual address for accessing the CS89x0. */
+       unsigned long phys_addr;/* Physical address for accessing the CS89x0. */
+       unsigned long size;     /* Length of CS89x0 memory region. */
+#endif
 };
 
 /* Index to functions, as function prototypes. */
 
-static int cs89x0_probe1(struct net_device *dev, int ioaddr, int modular);
+static int cs89x0_probe1(struct net_device *dev, unsigned long ioaddr, int modular);
 static int net_open(struct net_device *dev);
 static netdev_tx_t net_send_packet(struct sk_buff *skb, struct net_device *dev);
 static irqreturn_t net_interrupt(int irq, void *dev_id);
@@ -293,6 +293,7 @@ static int __init media_fn(char *str)
 __setup("cs89x0_media=", media_fn);
 
 
+#ifndef CONFIG_CS89x0_PLATFORM
 /* Check for a network adaptor of this type, and return '0' iff one exists.
    If dev->base_addr == 0, probe all likely locations.
    If dev->base_addr == 1, always return failure.
@@ -342,6 +343,7 @@ out:
        return ERR_PTR(err);
 }
 #endif
+#endif
 
 #if defined(CONFIG_MACH_IXDP2351)
 static u16
@@ -503,7 +505,7 @@ static const struct net_device_ops net_ops = {
  */
 
 static int __init
-cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
+cs89x0_probe1(struct net_device *dev, unsigned long ioaddr, int modular)
 {
        struct net_local *lp = netdev_priv(dev);
        static unsigned version_printed;
@@ -528,15 +530,12 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
                lp->force = g_cs89x0_media__force;
 #endif
 
-#if defined(CONFIG_MACH_QQ2440)
-               lp->force |= FORCE_RJ45 | FORCE_FULL;
-#endif
         }
 
        /* Grab the region so we can find another board if autoIRQ fails. */
        /* WTF is going on here? */
        if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, DRV_NAME)) {
-               printk(KERN_ERR "%s: request_region(0x%x, 0x%x) failed\n",
+               printk(KERN_ERR "%s: request_region(0x%lx, 0x%x) failed\n",
                                DRV_NAME, ioaddr, NETCARD_IO_EXTENT);
                retval = -EBUSY;
                goto out1;
@@ -548,7 +547,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
           will skip the test for the ADD_PORT. */
        if (ioaddr & 1) {
                if (net_debug > 1)
-                       printk(KERN_INFO "%s: odd ioaddr 0x%x\n", dev->name, ioaddr);
+                       printk(KERN_INFO "%s: odd ioaddr 0x%lx\n", dev->name, ioaddr);
                if ((ioaddr & 2) != 2)
                        if ((readword(ioaddr & ~3, ADD_PORT) & ADD_MASK) != ADD_SIG) {
                                printk(KERN_ERR "%s: bad signature 0x%x\n",
@@ -559,13 +558,13 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
        }
 
        ioaddr &= ~3;
-       printk(KERN_DEBUG "PP_addr at %x[%x]: 0x%x\n",
+       printk(KERN_DEBUG "PP_addr at %lx[%x]: 0x%x\n",
                        ioaddr, ADD_PORT, readword(ioaddr, ADD_PORT));
        writeword(ioaddr, ADD_PORT, PP_ChipID);
 
        tmp = readword(ioaddr, DATA_PORT);
        if (tmp != CHIP_EISA_ID_SIG) {
-               printk(KERN_DEBUG "%s: incorrect signature at %x[%x]: 0x%x!="
+               printk(KERN_DEBUG "%s: incorrect signature at %lx[%x]: 0x%x!="
                        CHIP_EISA_ID_SIG_STR "\n",
                        dev->name, ioaddr, DATA_PORT, tmp);
                retval = -ENODEV;
@@ -735,8 +734,9 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
                        dev->irq = i;
        } else {
                i = lp->isa_config & INT_NO_MASK;
+#ifndef CONFIG_CS89x0_PLATFORM
                if (lp->chip_type == CS8900) {
-#ifdef CONFIG_CS89x0_NONISA_IRQ
+#ifdef CS89x0_NONISA_IRQ
                        i = cs8900_irq_map[0];
 #else
                        /* Translate the IRQ using the IRQ mapping table. */
@@ -757,6 +757,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
                        }
 #endif
                }
+#endif
                if (!dev->irq)
                        dev->irq = i;
        }
@@ -1167,6 +1168,7 @@ write_irq(struct net_device *dev, int chip_type, int irq)
        int i;
 
        if (chip_type == CS8900) {
+#ifndef CONFIG_CS89x0_PLATFORM
                /* Search the mapping table for the corresponding IRQ pin. */
                for (i = 0; i != ARRAY_SIZE(cs8900_irq_map); i++)
                        if (cs8900_irq_map[i] == irq)
@@ -1174,6 +1176,10 @@ write_irq(struct net_device *dev, int chip_type, int irq)
                /* Not found */
                if (i == ARRAY_SIZE(cs8900_irq_map))
                        i = 3;
+#else
+               /* INTRQ0 pin is used for interrupt generation. */
+               i = 0;
+#endif
                writereg(dev, PP_CS8900_ISAINT, i);
        } else {
                writereg(dev, PP_CS8920_ISAINT, irq);
@@ -1227,7 +1233,7 @@ net_open(struct net_device *dev)
        }
        else
        {
-#ifndef CONFIG_CS89x0_NONISA_IRQ
+#if !defined(CS89x0_NONISA_IRQ) && !defined(CONFIG_CS89x0_PLATFORM)
                if (((1 << dev->irq) & lp->irq_map) == 0) {
                        printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
                                dev->name, dev->irq, lp->irq_map);
@@ -1745,7 +1751,7 @@ static int set_mac_address(struct net_device *dev, void *p)
        return 0;
 }
 
-#ifdef MODULE
+#if defined(MODULE) && !defined(CONFIG_CS89x0_PLATFORM)
 
 static struct net_device *dev_cs89x0;
 
@@ -1899,7 +1905,97 @@ cleanup_module(void)
        release_region(dev_cs89x0->base_addr, NETCARD_IO_EXTENT);
        free_netdev(dev_cs89x0);
 }
-#endif /* MODULE */
+#endif /* MODULE && !CONFIG_CS89x0_PLATFORM */
+
+#ifdef CONFIG_CS89x0_PLATFORM
+static int __init cs89x0_platform_probe(struct platform_device *pdev)
+{
+       struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
+       struct net_local *lp;
+       struct resource *mem_res;
+       int err;
+
+       if (!dev)
+               return -ENOMEM;
+
+       lp = netdev_priv(dev);
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       dev->irq = platform_get_irq(pdev, 0);
+       if (mem_res == NULL || dev->irq <= 0) {
+               dev_warn(&dev->dev, "memory/interrupt resource missing.\n");
+               err = -ENXIO;
+               goto free;
+       }
+
+       lp->phys_addr = mem_res->start;
+       lp->size = resource_size(mem_res);
+       if (!request_mem_region(lp->phys_addr, lp->size, DRV_NAME)) {
+               dev_warn(&dev->dev, "request_mem_region() failed.\n");
+               err = -EBUSY;
+               goto free;
+       }
+
+       lp->virt_addr = ioremap(lp->phys_addr, lp->size);
+       if (!lp->virt_addr) {
+               dev_warn(&dev->dev, "ioremap() failed.\n");
+               err = -ENOMEM;
+               goto release;
+       }
+
+       err = cs89x0_probe1(dev, (unsigned long)lp->virt_addr, 0);
+       if (err) {
+               dev_warn(&dev->dev, "no cs8900 or cs8920 detected.\n");
+               goto unmap;
+       }
+
+       platform_set_drvdata(pdev, dev);
+       return 0;
+
+unmap:
+       iounmap(lp->virt_addr);
+release:
+       release_mem_region(lp->phys_addr, lp->size);
+free:
+       free_netdev(dev);
+       return err;
+}
+
+static int cs89x0_platform_remove(struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+       struct net_local *lp = netdev_priv(dev);
+
+       unregister_netdev(dev);
+       iounmap(lp->virt_addr);
+       release_mem_region(lp->phys_addr, lp->size);
+       free_netdev(dev);
+       return 0;
+}
+
+static struct platform_driver cs89x0_driver = {
+       .driver = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .remove = cs89x0_platform_remove,
+};
+
+static int __init cs89x0_init(void)
+{
+       return platform_driver_probe(&cs89x0_driver, cs89x0_platform_probe);
+}
+
+module_init(cs89x0_init);
+
+static void __exit cs89x0_cleanup(void)
+{
+       platform_driver_unregister(&cs89x0_driver);
+}
+
+module_exit(cs89x0_cleanup);
+
+#endif /* CONFIG_CS89x0_PLATFORM */
 
 /*
  * Local variables: