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 */