USB: s3c_hsotg: define USB_GADGET_DUALSPEED in Kconfig
[safe/jmp/linux-2.6] / drivers / usb / host / isp1760-if.c
index 051ef7b..ec85d0c 100644 (file)
@@ -3,6 +3,7 @@
  * Currently there is support for
  * - OpenFirmware
  * - PCI
+ * - PDEV (generic platform device centralized driver model)
  *
  * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
  *
 
 #include <linux/usb.h>
 #include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/usb/isp1760.h>
+#include <linux/usb/hcd.h>
 
-#include "../core/hcd.h"
 #include "isp1760-hcd.h"
 
-#ifdef CONFIG_USB_ISP1760_OF
+#ifdef CONFIG_PPC_OF
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #endif
 
-#ifdef CONFIG_USB_ISP1760_PCI
+#ifdef CONFIG_PCI
 #include <linux/pci.h>
 #endif
 
-#ifdef CONFIG_USB_ISP1760_OF
+#ifdef CONFIG_PPC_OF
 static int of_isp1760_probe(struct of_device *dev,
                const struct of_device_id *match)
 {
        struct usb_hcd *hcd;
-       struct device_node *dp = dev->node;
+       struct device_node *dp = dev->dev.of_node;
        struct resource *res;
        struct resource memory;
        struct of_irq oirq;
        int virq;
-       u64 res_len;
+       resource_size_t res_len;
        int ret;
        const unsigned int *prop;
        unsigned int devflags = 0;
@@ -42,13 +45,12 @@ static int of_isp1760_probe(struct of_device *dev,
        if (ret)
                return -ENXIO;
 
-       res = request_mem_region(memory.start, memory.end - memory.start + 1,
-                       dev_name(&dev->dev));
+       res_len = resource_size(&memory);
+
+       res = request_mem_region(memory.start, res_len, dev_name(&dev->dev));
        if (!res)
                return -EBUSY;
 
-       res_len = memory.end - memory.start + 1;
-
        if (of_irq_map_one(dp, 0, &oirq)) {
                ret = -ENODEV;
                goto release_reg;
@@ -60,9 +62,6 @@ static int of_isp1760_probe(struct of_device *dev,
        if (of_device_is_compatible(dp, "nxp,usb-isp1761"))
                devflags |= ISP1760_FLAG_ISP1761;
 
-       if (of_get_property(dp, "port1-disable", NULL) != NULL)
-               devflags |= ISP1760_FLAG_PORT1_DIS;
-
        /* Some systems wire up only 16 of the 32 data lines */
        prop = of_get_property(dp, "bus-width", NULL);
        if (prop && *prop == 16)
@@ -92,7 +91,7 @@ static int of_isp1760_probe(struct of_device *dev,
        return ret;
 
 release_reg:
-       release_mem_region(memory.start, memory.end - memory.start + 1);
+       release_mem_region(memory.start, res_len);
        return ret;
 }
 
@@ -109,7 +108,7 @@ static int of_isp1760_remove(struct of_device *dev)
        return 0;
 }
 
-static struct of_device_id of_isp1760_match[] = {
+static const struct of_device_id of_isp1760_match[] = {
        {
                .compatible = "nxp,usb-isp1760",
        },
@@ -121,31 +120,34 @@ static struct of_device_id of_isp1760_match[] = {
 MODULE_DEVICE_TABLE(of, of_isp1760_match);
 
 static struct of_platform_driver isp1760_of_driver = {
-       .name           = "nxp-isp1760",
-       .match_table    = of_isp1760_match,
+       .driver = {
+               .name = "nxp-isp1760",
+               .owner = THIS_MODULE,
+               .of_match_table = of_isp1760_match,
+       },
        .probe          = of_isp1760_probe,
        .remove         = of_isp1760_remove,
 };
 #endif
 
-#ifdef CONFIG_USB_ISP1760_PCI
-static u32 nxp_pci_io_base;
-static u32 iolength;
-static u32 pci_mem_phy0;
-static u32 length;
-static u8 __iomem *chip_addr;
-static u8 __iomem *iobase;
-
+#ifdef CONFIG_PCI
 static int __devinit isp1761_pci_probe(struct pci_dev *dev,
                const struct pci_device_id *id)
 {
        u8 latency, limit;
        __u32 reg_data;
        int retry_count;
-       int length;
-       int status = 1;
        struct usb_hcd *hcd;
        unsigned int devflags = 0;
+       int ret_status = 0;
+
+       resource_size_t pci_mem_phy0;
+       resource_size_t memlength;
+
+       u8 __iomem *chip_addr;
+       u8 __iomem *iobase;
+       resource_size_t nxp_pci_io_base;
+       resource_size_t iolength;
 
        if (usb_disabled())
                return -ENODEV;
@@ -168,26 +170,30 @@ static int __devinit isp1761_pci_probe(struct pci_dev *dev,
        iobase = ioremap_nocache(nxp_pci_io_base, iolength);
        if (!iobase) {
                printk(KERN_ERR "ioremap #1\n");
-               release_mem_region(nxp_pci_io_base, iolength);
-               return -ENOMEM;
+               ret_status = -ENOMEM;
+               goto cleanup1;
        }
        /* Grab the PLX PCI shared memory of the ISP 1761 we need  */
        pci_mem_phy0 = pci_resource_start(dev, 3);
-       length = pci_resource_len(dev, 3);
-
-       if (length < 0xffff) {
-               printk(KERN_ERR "memory length for this resource is less than "
-                               "required\n");
-               release_mem_region(nxp_pci_io_base, iolength);
-               iounmap(iobase);
-               return  -ENOMEM;
+       memlength = pci_resource_len(dev, 3);
+       if (memlength < 0xffff) {
+               printk(KERN_ERR "memory length for this resource is wrong\n");
+               ret_status = -ENOMEM;
+               goto cleanup2;
        }
 
-       if (!request_mem_region(pci_mem_phy0, length, "ISP-PCI")) {
+       if (!request_mem_region(pci_mem_phy0, memlength, "ISP-PCI")) {
                printk(KERN_ERR "host controller already in use\n");
-               release_mem_region(nxp_pci_io_base, iolength);
-               iounmap(iobase);
-               return -EBUSY;
+               ret_status = -EBUSY;
+               goto cleanup2;
+       }
+
+       /* map available memory */
+       chip_addr = ioremap_nocache(pci_mem_phy0,memlength);
+       if (!chip_addr) {
+               printk(KERN_ERR "Error ioremap failed\n");
+               ret_status = -ENOMEM;
+               goto cleanup3;
        }
 
        /* bad pci latencies can contribute to overruns */
@@ -210,38 +216,54 @@ static int __devinit isp1761_pci_probe(struct pci_dev *dev,
                 * */
                writel(0xface, chip_addr + HC_SCRATCH_REG);
                udelay(100);
-               reg_data = readl(chip_addr + HC_SCRATCH_REG);
+               reg_data = readl(chip_addr + HC_SCRATCH_REG) & 0x0000ffff;
                retry_count--;
        }
 
+       iounmap(chip_addr);
+
        /* Host Controller presence is detected by writing to scratch register
         * and reading back and checking the contents are same or not
         */
        if (reg_data != 0xFACE) {
-               err("scratch register mismatch %x", reg_data);
-               goto clean;
+               dev_err(&dev->dev, "scratch register mismatch %x\n", reg_data);
+               ret_status = -ENOMEM;
+               goto cleanup3;
        }
 
        pci_set_master(dev);
 
-       status = readl(iobase + 0x68);
-       status |= 0x900;
-       writel(status, iobase + 0x68);
+       /* configure PLX PCI chip to pass interrupts */
+#define PLX_INT_CSR_REG 0x68
+       reg_data = readl(iobase + PLX_INT_CSR_REG);
+       reg_data |= 0x900;
+       writel(reg_data, iobase + PLX_INT_CSR_REG);
 
        dev->dev.dma_mask = NULL;
-       hcd = isp1760_register(pci_mem_phy0, length, dev->irq,
+       hcd = isp1760_register(pci_mem_phy0, memlength, dev->irq,
                IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev_name(&dev->dev),
                devflags);
+       if (IS_ERR(hcd)) {
+               ret_status = -ENODEV;
+               goto cleanup3;
+       }
+
+       /* done with PLX IO access */
+       iounmap(iobase);
+       release_mem_region(nxp_pci_io_base, iolength);
+
        pci_set_drvdata(dev, hcd);
-       if (!hcd)
-               return 0;
-clean:
-       status = -ENODEV;
+       return 0;
+
+cleanup3:
+       release_mem_region(pci_mem_phy0, memlength);
+cleanup2:
        iounmap(iobase);
-       release_mem_region(pci_mem_phy0, length);
+cleanup1:
        release_mem_region(nxp_pci_io_base, iolength);
-       return status;
+       return ret_status;
 }
+
 static void isp1761_pci_remove(struct pci_dev *dev)
 {
        struct usb_hcd *hcd;
@@ -254,12 +276,6 @@ static void isp1761_pci_remove(struct pci_dev *dev)
        usb_put_hcd(hcd);
 
        pci_disable_device(dev);
-
-       iounmap(iobase);
-       iounmap(chip_addr);
-
-       release_mem_region(nxp_pci_io_base, iolength);
-       release_mem_region(pci_mem_phy0, length);
 }
 
 static void isp1761_pci_shutdown(struct pci_dev *dev)
@@ -267,12 +283,16 @@ static void isp1761_pci_shutdown(struct pci_dev *dev)
        printk(KERN_ERR "ips1761_pci_shutdown\n");
 }
 
-static const struct pci_device_id isp1760_plx [] = { {
-       /* handle any USB 2.0 EHCI controller */
-       PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_OTHER << 8) | (0x06 << 16)), ~0),
-               .driver_data = 0,
-},
-{ /* end: all zeroes */ }
+static const struct pci_device_id isp1760_plx [] = {
+       {
+               .class          = PCI_CLASS_BRIDGE_OTHER << 8,
+               .class_mask     = ~0,
+               .vendor         = PCI_VENDOR_ID_PLX,
+               .device         = 0x5406,
+               .subvendor      = PCI_VENDOR_ID_PLX,
+               .subdevice      = 0x9054,
+       },
+       { }
 };
 MODULE_DEVICE_TABLE(pci, isp1760_plx);
 
@@ -285,43 +305,122 @@ static struct pci_driver isp1761_pci_driver = {
 };
 #endif
 
+static int __devinit isp1760_plat_probe(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct usb_hcd *hcd;
+       struct resource *mem_res;
+       struct resource *irq_res;
+       resource_size_t mem_size;
+       struct isp1760_platform_data *priv = pdev->dev.platform_data;
+       unsigned int devflags = 0;
+       unsigned long irqflags = IRQF_SHARED | IRQF_DISABLED;
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem_res) {
+               pr_warning("isp1760: Memory resource not available\n");
+               ret = -ENODEV;
+               goto out;
+       }
+       mem_size = resource_size(mem_res);
+       if (!request_mem_region(mem_res->start, mem_size, "isp1760")) {
+               pr_warning("isp1760: Cannot reserve the memory resource\n");
+               ret = -EBUSY;
+               goto out;
+       }
+
+       irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!irq_res) {
+               pr_warning("isp1760: IRQ resource not available\n");
+               return -ENODEV;
+       }
+       irqflags |= irq_res->flags & IRQF_TRIGGER_MASK;
+
+       if (priv) {
+               if (priv->is_isp1761)
+                       devflags |= ISP1760_FLAG_ISP1761;
+               if (priv->bus_width_16)
+                       devflags |= ISP1760_FLAG_BUS_WIDTH_16;
+               if (priv->port1_otg)
+                       devflags |= ISP1760_FLAG_OTG_EN;
+               if (priv->analog_oc)
+                       devflags |= ISP1760_FLAG_ANALOG_OC;
+               if (priv->dack_polarity_high)
+                       devflags |= ISP1760_FLAG_DACK_POL_HIGH;
+               if (priv->dreq_polarity_high)
+                       devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
+       }
+
+       hcd = isp1760_register(mem_res->start, mem_size, irq_res->start,
+                              irqflags, &pdev->dev, dev_name(&pdev->dev), devflags);
+       if (IS_ERR(hcd)) {
+               pr_warning("isp1760: Failed to register the HCD device\n");
+               ret = -ENODEV;
+               goto cleanup;
+       }
+
+       pr_info("ISP1760 USB device initialised\n");
+       return ret;
+
+cleanup:
+       release_mem_region(mem_res->start, mem_size);
+out:
+       return ret;
+}
+
+static int __devexit isp1760_plat_remove(struct platform_device *pdev)
+{
+       struct resource *mem_res;
+       resource_size_t mem_size;
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       mem_size = resource_size(mem_res);
+       release_mem_region(mem_res->start, mem_size);
+
+       return 0;
+}
+
+static struct platform_driver isp1760_plat_driver = {
+       .probe  = isp1760_plat_probe,
+       .remove = __devexit_p(isp1760_plat_remove),
+       .driver = {
+               .name   = "isp1760",
+       },
+};
+
 static int __init isp1760_init(void)
 {
-       int ret = -ENODEV;
+       int ret, any_ret = -ENODEV;
 
        init_kmem_once();
 
-#ifdef CONFIG_USB_ISP1760_OF
+       ret = platform_driver_register(&isp1760_plat_driver);
+       if (!ret)
+               any_ret = 0;
+#ifdef CONFIG_PPC_OF
        ret = of_register_platform_driver(&isp1760_of_driver);
-       if (ret) {
-               deinit_kmem_cache();
-               return ret;
-       }
+       if (!ret)
+               any_ret = 0;
 #endif
-#ifdef CONFIG_USB_ISP1760_PCI
+#ifdef CONFIG_PCI
        ret = pci_register_driver(&isp1761_pci_driver);
-       if (ret)
-               goto unreg_of;
+       if (!ret)
+               any_ret = 0;
 #endif
-       return ret;
 
-#ifdef CONFIG_USB_ISP1760_PCI
-unreg_of:
-#endif
-#ifdef CONFIG_USB_ISP1760_OF
-       of_unregister_platform_driver(&isp1760_of_driver);
-#endif
-       deinit_kmem_cache();
-       return ret;
+       if (any_ret)
+               deinit_kmem_cache();
+       return any_ret;
 }
 module_init(isp1760_init);
 
 static void __exit isp1760_exit(void)
 {
-#ifdef CONFIG_USB_ISP1760_OF
+       platform_driver_unregister(&isp1760_plat_driver);
+#ifdef CONFIG_PPC_OF
        of_unregister_platform_driver(&isp1760_of_driver);
 #endif
-#ifdef CONFIG_USB_ISP1760_PCI
+#ifdef CONFIG_PCI
        pci_unregister_driver(&isp1761_pci_driver);
 #endif
        deinit_kmem_cache();