summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/gadget/Kconfig18
-rw-r--r--drivers/usb/gadget/Makefile1
-rw-r--r--drivers/usb/gadget/ci13xxx_msm.c58
-rw-r--r--drivers/usb/gadget/ci13xxx_pci.c124
-rw-r--r--drivers/usb/gadget/ci13xxx_udc.c78
-rw-r--r--drivers/usb/gadget/ci13xxx_udc.h3
6 files changed, 180 insertions, 102 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 55aad9278f77..47e086a0b7f2 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -378,16 +378,28 @@ config USB_FSL_QE
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
@@ -484,7 +496,7 @@ config USB_EG20T
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
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 1565253bfdd2..3786c7cdd807 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -22,6 +22,7 @@ fsl_usb2_udc-$(CONFIG_ARCH_MXC) += fsl_mxc_udc.o
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
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index 6e77446ef52a..418de0e61c5a 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -10,16 +10,12 @@
#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;
@@ -60,54 +56,40 @@ static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = {
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;
}
diff --git a/drivers/usb/gadget/ci13xxx_pci.c b/drivers/usb/gadget/ci13xxx_pci.c
index ef5da49eb809..ea03fabd4d97 100644
--- a/drivers/usb/gadget/ci13xxx_pci.c
+++ b/drivers/usb/gadget/ci13xxx_pci.c
@@ -10,10 +10,13 @@
* 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"
@@ -21,25 +24,14 @@
/******************************************************************************
* 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,
};
/**
@@ -54,9 +46,10 @@ static struct ci13xxx_udc_driver ci13xxx_pci_udc_driver = {
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;
@@ -71,45 +64,50 @@ static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
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:
@@ -126,10 +124,10 @@ static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
*/
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);
}
@@ -140,10 +138,22 @@ static void __devexit ci13xxx_pci_remove(struct pci_dev *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);
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 3b47ca1b64ee..009a3cd5895d 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -55,6 +55,8 @@
#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>
@@ -67,7 +69,6 @@
#include "ci13xxx_udc.h"
-
/******************************************************************************
* DEFINE
*****************************************************************************/
@@ -2806,7 +2807,7 @@ static int ci13xxx_stop(struct usb_gadget_driver *driver)
* 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;
@@ -2901,7 +2902,7 @@ static void udc_release(struct device *dev)
* 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;
@@ -2935,7 +2936,7 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
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;
@@ -3033,3 +3034,72 @@ static void udc_remove(void)
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");
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index f17ffecc36c2..f605090777ce 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -103,6 +103,8 @@ struct ci13xxx_ep {
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)
@@ -144,6 +146,7 @@ struct ci13xxx {
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 */