Set CONFIG_USB_GADGET to "m" to build this driver as a
           dynamically linked module called "fsl_qe_udc".
 
+config USB_CHIPIDEA_UDC
+       tristate "ChipIdea UDC driver"
+       select USB_GADGET_DUALSPEED
+       help
+         This module contains the ChipIdea USB device controller driver;
+         you will also need platform driver like ci13xxx_pci or ci13xxx_msm
+         to use it.
+
+         Say "y" to link the driver statically, or "m" to build a
+         dynamically linked module called "ci13xxx_udc", which will serve
+         as a driver for ChipIdea udc on different platforms.
+
 config USB_CI13XXX_PCI
        tristate "MIPS USB CI13xxx PCI UDC"
-       depends on PCI
+       depends on PCI && USB_CHIPIDEA_UDC
        select USB_GADGET_DUALSPEED
        help
          MIPS USB IP core family device controller
          Currently it only supports IP part number CI13412
 
          Say "y" to link the driver statically, or "m" to build a
-         dynamically linked module called "ci13xxx_udc" and force all
+         dynamically linked module called "ci13xxx_pci" and force all
          gadget drivers to also be dynamically linked.
 
 config USB_NET2272
 
 config USB_CI13XXX_MSM
        tristate "MIPS USB CI13xxx for MSM"
-       depends on ARCH_MSM
+       depends on ARCH_MSM && USB_CHIPIDEA_UDC
        select USB_GADGET_DUALSPEED
        select USB_MSM_OTG
        help
 
 obj-$(CONFIG_USB_M66592)       += m66592-udc.o
 obj-$(CONFIG_USB_R8A66597)     += r8a66597-udc.o
 obj-$(CONFIG_USB_FSL_QE)       += fsl_qe_udc.o
+obj-$(CONFIG_USB_CHIPIDEA_UDC) += ci13xxx_udc.o
 obj-$(CONFIG_USB_CI13XXX_PCI)  += ci13xxx_pci.o
 obj-$(CONFIG_USB_S3C_HSOTG)    += s3c-hsotg.o
 obj-$(CONFIG_USB_S3C_HSUDC)    += s3c-hsudc.o
 
 #include <linux/pm_runtime.h>
 #include <linux/usb/msm_hsusb_hw.h>
 #include <linux/usb/ulpi.h>
+#include <linux/usb/gadget.h>
 
-#include "ci13xxx_udc.c"
+#include "ci13xxx_udc.h"
 
 #define MSM_USB_BASE   (udc->regs)
 
-static irqreturn_t msm_udc_irq(int irq, void *data)
-{
-       return udc_irq();
-}
-
 static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
 {
        struct device *dev = udc->gadget.dev.parent;
 
 static int ci13xxx_msm_probe(struct platform_device *pdev)
 {
-       struct resource *res;
-       void __iomem *regs;
-       int irq;
+       struct platform_device *plat_ci;
        int ret;
 
        dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n");
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "failed to get platform resource mem\n");
-               return -ENXIO;
-       }
-
-       regs = ioremap(res->start, resource_size(res));
-       if (!regs) {
-               dev_err(&pdev->dev, "ioremap failed\n");
+       plat_ci = platform_device_alloc("ci_udc", -1);
+       if (!plat_ci) {
+               dev_err(&pdev->dev, "can't allocate ci_udc platform device\n");
                return -ENOMEM;
        }
 
-       ret = udc_probe(&ci13xxx_msm_udc_driver, &pdev->dev, regs,
-                       DEF_CAPOFFSET);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "udc_probe failed\n");
-               goto iounmap;
+       ret = platform_device_add_resources(plat_ci, pdev->resource,
+                                           pdev->num_resources);
+       if (ret) {
+               dev_err(&pdev->dev, "can't add resources to platform device\n");
+               goto put_platform;
        }
 
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(&pdev->dev, "IRQ not found\n");
-               ret = -ENXIO;
-               goto udc_remove;
-       }
+       ret = platform_device_add_data(plat_ci, &ci13xxx_msm_udc_driver,
+                                      sizeof(ci13xxx_msm_udc_driver));
+       if (ret)
+               goto put_platform;
 
-       ret = request_irq(irq, msm_udc_irq, IRQF_SHARED, pdev->name, pdev);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "request_irq failed\n");
-               goto udc_remove;
-       }
+       ret = platform_device_add(plat_ci);
+       if (ret)
+               goto put_platform;
 
        pm_runtime_no_callbacks(&pdev->dev);
        pm_runtime_enable(&pdev->dev);
 
        return 0;
 
-udc_remove:
-       udc_remove();
-iounmap:
-       iounmap(regs);
+put_platform:
+       platform_device_put(plat_ci);
 
        return ret;
 }
 
  * published by the Free Software Foundation.
  */
 
+#include <linux/platform_device.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/usb/gadget.h>
 
-#include "ci13xxx_udc.c"
+#include "ci13xxx_udc.h"
 
 /* driver name */
 #define UDC_DRIVER_NAME   "ci13xxx_pci"
 /******************************************************************************
  * PCI block
  *****************************************************************************/
-/**
- * ci13xxx_pci_irq: interrut handler
- * @irq:  irq number
- * @pdev: USB Device Controller interrupt source
- *
- * This function returns IRQ_HANDLED if the IRQ has been handled
- * This is an ISR don't trace, use attribute interface instead
- */
-static irqreturn_t ci13xxx_pci_irq(int irq, void *pdev)
-{
-       if (irq == 0) {
-               dev_err(&((struct pci_dev *)pdev)->dev, "Invalid IRQ0 usage!");
-               return IRQ_HANDLED;
-       }
-       return udc_irq();
-}
+struct ci13xxx_udc_driver pci_driver = {
+       .name           = UDC_DRIVER_NAME,
+       .capoffset      = DEF_CAPOFFSET,
+};
 
-static struct ci13xxx_udc_driver ci13xxx_pci_udc_driver = {
+struct ci13xxx_udc_driver langwell_pci_driver = {
        .name           = UDC_DRIVER_NAME,
+       .capoffset      = 0,
 };
 
 /**
 static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
                                       const struct pci_device_id *id)
 {
-       void __iomem *regs = NULL;
-       uintptr_t capoffset = DEF_CAPOFFSET;
-       int retval = 0;
+       struct ci13xxx_udc_driver *driver = (void *)id->driver_data;
+       struct platform_device *plat_ci;
+       struct resource res[3];
+       int retval = 0, nres = 2;
 
        if (id == NULL)
                return -EINVAL;
                goto disable_device;
        }
 
-       retval = pci_request_regions(pdev, UDC_DRIVER_NAME);
-       if (retval)
-               goto disable_device;
-
-       /* BAR 0 holds all the registers */
-       regs = pci_iomap(pdev, 0, 0);
-       if (!regs) {
-               dev_err(&pdev->dev, "Error mapping memory!");
-               retval = -EFAULT;
-               goto release_regions;
-       }
-       pci_set_drvdata(pdev, (__force void *)regs);
-
+       pci_set_power_state(pdev, PCI_D0);
        pci_set_master(pdev);
        pci_try_set_mwi(pdev);
 
-       if (pdev->vendor == PCI_VENDOR_ID_INTEL)
-               capoffset = 0;
+       plat_ci = platform_device_alloc("ci_udc", -1);
+       if (!plat_ci) {
+               dev_err(&pdev->dev, "can't allocate ci_udc platform device\n");
+               retval = -ENOMEM;
+               goto disable_device;
+       }
 
-       retval = udc_probe(&ci13xxx_pci_udc_driver, &pdev->dev, regs,
-                          capoffset);
+       memset(res, 0, sizeof(res));
+       res[0].start    = pci_resource_start(pdev, 0);
+       res[0].end      = pci_resource_end(pdev, 0);
+       res[0].flags    = IORESOURCE_MEM;
+       res[1].start    = pdev->irq;
+       res[1].flags    = IORESOURCE_IRQ;
+
+       retval = platform_device_add_resources(plat_ci, res, nres);
+       if (retval) {
+               dev_err(&pdev->dev, "can't add resources to platform device\n");
+               goto put_platform;
+       }
+
+       retval = platform_device_add_data(plat_ci, driver, sizeof(*driver));
        if (retval)
-               goto iounmap;
+               goto put_platform;
 
-       /* our device does not have MSI capability */
+       dma_set_coherent_mask(&plat_ci->dev, pdev->dev.coherent_dma_mask);
+       plat_ci->dev.dma_mask = pdev->dev.dma_mask;
+       plat_ci->dev.dma_parms = pdev->dev.dma_parms;
+       plat_ci->dev.parent = &pdev->dev;
 
-       retval = request_irq(pdev->irq, ci13xxx_pci_irq, IRQF_SHARED,
-                            UDC_DRIVER_NAME, pdev);
+       pci_set_drvdata(pdev, plat_ci);
+
+       retval = platform_device_add(plat_ci);
        if (retval)
-               goto gadget_remove;
+               goto put_platform;
 
        return 0;
 
- gadget_remove:
-       udc_remove();
- iounmap:
-       pci_iounmap(pdev, regs);
- release_regions:
-       pci_release_regions(pdev);
+ put_platform:
+       pci_set_drvdata(pdev, NULL);
+       platform_device_put(plat_ci);
  disable_device:
        pci_disable_device(pdev);
  done:
  */
 static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev)
 {
-       free_irq(pdev->irq, pdev);
-       udc_remove();
-       pci_iounmap(pdev, (__force void __iomem *)pci_get_drvdata(pdev));
-       pci_release_regions(pdev);
+       struct platform_device *plat_ci = pci_get_drvdata(pdev);
+
+       platform_device_unregister(plat_ci);
+       pci_set_drvdata(pdev, NULL);
        pci_disable_device(pdev);
 }
 
  * Check "pci.h" for details
  */
 static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = {
-       { PCI_DEVICE(0x153F, 0x1004) },
-       { PCI_DEVICE(0x153F, 0x1006) },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0811) },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0829) },
+       {
+               PCI_DEVICE(0x153F, 0x1004),
+               .driver_data = (kernel_ulong_t)&pci_driver,
+       },
+       {
+               PCI_DEVICE(0x153F, 0x1006),
+               .driver_data = (kernel_ulong_t)&pci_driver,
+       },
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0811),
+               .driver_data = (kernel_ulong_t)&langwell_pci_driver,
+       },
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0829),
+               .driver_data = (kernel_ulong_t)&langwell_pci_driver,
+       },
        { 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ }
 };
 MODULE_DEVICE_TABLE(pci, ci13xxx_pci_id_table);
 
 #include <linux/dmapool.h>
 #include <linux/dma-mapping.h>
 #include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/irq.h>
 
 #include "ci13xxx_udc.h"
 
-
 /******************************************************************************
  * DEFINE
  *****************************************************************************/
  * This function returns IRQ_HANDLED if the IRQ has been handled
  * It locks access to registers
  */
-static irqreturn_t udc_irq(void)
+static irqreturn_t udc_irq(int irq, void *data)
 {
        struct ci13xxx *udc = _udc;
        irqreturn_t retval;
  * Kernel assumes 32-bit DMA operations by default, no need to dma_set_mask
  */
 static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
-                    void __iomem *regs, uintptr_t capoffset)
+                    void __iomem *regs)
 {
        struct ci13xxx *udc;
        int retval = 0;
        udc->gadget.dev.parent   = dev;
        udc->gadget.dev.release  = udc_release;
 
-       retval = hw_device_init(udc, regs, capoffset);
+       retval = hw_device_init(udc, regs, driver->capoffset);
        if (retval < 0)
                goto free_udc;
 
        kfree(udc);
        _udc = NULL;
 }
+
+static int __devinit ci_udc_probe(struct platform_device *pdev)
+{
+       struct device   *dev = &pdev->dev;
+       struct ci13xxx_udc_driver *driver = dev->platform_data;
+       struct resource *res;
+       void __iomem    *base;
+       int             ret;
+
+       if (!driver) {
+               dev_err(dev, "platform data missing\n");
+               return -ENODEV;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "missing resource\n");
+               return -ENODEV;
+       }
+
+       base = devm_request_and_ioremap(dev, res);
+       if (!res) {
+               dev_err(dev, "can't request and ioremap resource\n");
+               return -ENOMEM;
+       }
+
+       ret = udc_probe(driver, dev, base);
+       if (ret)
+               return ret;
+
+       _udc->irq = platform_get_irq(pdev, 0);
+       if (_udc->irq < 0) {
+               dev_err(dev, "missing IRQ\n");
+               ret = -ENODEV;
+               goto out;
+       }
+
+       ret = request_irq(_udc->irq, udc_irq, IRQF_SHARED, driver->name, _udc);
+
+out:
+       if (ret)
+               udc_remove();
+
+       return ret;
+}
+
+static int __devexit ci_udc_remove(struct platform_device *pdev)
+{
+       free_irq(_udc->irq, _udc);
+       udc_remove();
+
+       return 0;
+}
+
+static struct platform_driver ci_udc_driver = {
+       .probe  = ci_udc_probe,
+       .remove = __devexit_p(ci_udc_remove),
+       .driver = {
+               .name   = "ci_udc",
+       },
+};
+
+module_platform_driver(ci_udc_driver);
+
+MODULE_ALIAS("platform:ci_udc");
+MODULE_ALIAS("platform:ci13xxx");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("David Lopo <dlopo@chipidea.mips.com>");
+MODULE_DESCRIPTION("ChipIdea UDC Driver");
 
 struct ci13xxx;
 struct ci13xxx_udc_driver {
        const char      *name;
+       /* offset of the capability registers */
+       uintptr_t        capoffset;
        unsigned long    flags;
 #define CI13XXX_REGS_SHARED            BIT(0)
 #define CI13XXX_REQUIRE_TRANSCEIVER    BIT(1)
        u8                         test_mode;  /* the selected test mode */
 
        struct hw_bank             hw_bank;
+       int                        irq;
        struct usb_gadget_driver  *driver;     /* 3rd party gadget driver */
        struct ci13xxx_udc_driver *udc_driver; /* device controller driver */
        int                        vbus_active; /* is VBUS active */