Hi Felipe, Here is my "more-invasive" approach to making the dwc3 driver support hibernation on our HAPS platform. This gets rid of the fake platform device that is constructed by the bus glue for the dwc3.ko module, and turns it into a library-like module that can be called from the bus glue code. This will allow the HAPS PCI glue to get a pointer to the dwc3 context, so it can easily do the things it needs for hibernation. It gets rid of the (I think) strange need to have pm-runtime calls in both the dwc3 module and the bus glue module. Why should we have two sets of those for a single piece of hardware anyway? Or two platform devices for a single piece of hardware for that matter? And, it results in a nice reduction in the lines of code. If someone really needs a separate platform device for the dwc3.ko module, they can write a small piece of code to do that, much like Sebastian did for the xhci driver. But I don't see why that should be necessary. Note that I didn't add the hibernation code itself to this patch. This patch just changes the API between the dwc3.ko module and the PCI and OMAP glue modules. Is there a reason why this approach won't work, or why it is inferior to what you have now? - Paul --- drivers/usb/dwc3/core.c | 98 ++++++++++++++++-------------------------- drivers/usb/dwc3/core.h | 7 ++- drivers/usb/dwc3/dwc3-omap.c | 67 +++++++++++----------------- drivers/usb/dwc3/dwc3-pci.c | 87 +++++++++---------------------------- drivers/usb/dwc3/ep0.c | 1 - drivers/usb/dwc3/gadget.c | 15 +----- 6 files changed, 93 insertions(+), 182 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index fd6917b..7647c87 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -40,7 +40,6 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/spinlock.h> -#include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/interrupt.h> #include <linux/ioport.h> @@ -69,7 +68,7 @@ MODULE_PARM_DESC(maximum_speed, "Maximum supported speed."); static DECLARE_BITMAP(dwc3_devs, DWC3_DEVS_POSSIBLE); -int dwc3_get_device_id(void) +static int dwc3_get_device_id(void) { int id; @@ -88,9 +87,8 @@ again: return id; } -EXPORT_SYMBOL_GPL(dwc3_get_device_id); -void dwc3_put_device_id(int id) +static void dwc3_put_device_id(int id) { int ret; @@ -101,7 +99,6 @@ void dwc3_put_device_id(int id) WARN(!ret, "dwc3: ID %d not in use\n", id); clear_bit(id, dwc3_devs); } -EXPORT_SYMBOL_GPL(dwc3_put_device_id); void dwc3_set_mode(struct dwc3 *dwc, u32 mode) { @@ -402,63 +399,50 @@ static void dwc3_core_exit(struct dwc3 *dwc) #define DWC3_ALIGN_MASK (16 - 1) -static int __devinit dwc3_probe(struct platform_device *pdev) +struct dwc3 * __devinit dwc3_init(struct device *dev, struct resource *res, + int irq, int irqf) { - struct device_node *node = pdev->dev.of_node; - struct resource *res; + struct device_node *node = dev->of_node; struct dwc3 *dwc; - struct device *dev = &pdev->dev; - - int ret = -ENOMEM; - int irq; void __iomem *regs; void *mem; + int devid; + int ret = -ENOMEM; + u8 mode; mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); if (!mem) { dev_err(dev, "not enough memory\n"); - return -ENOMEM; + goto err0; } dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); dwc->mem = mem; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "missing resource\n"); - return -ENODEV; - } - - dwc->res = res; - - res = devm_request_mem_region(dev, res->start, resource_size(res), - dev_name(dev)); - if (!res) { - dev_err(dev, "can't request mem region\n"); - return -ENOMEM; + devid = dwc3_get_device_id(); + if (devid < 0) { + ret = devid; + goto err0; } + dwc->devid = devid; regs = devm_ioremap(dev, res->start, resource_size(res)); if (!regs) { dev_err(dev, "ioremap failed\n"); - return -ENOMEM; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "missing IRQ\n"); - return -ENODEV; + ret = -EINVAL; + goto err0; } spin_lock_init(&dwc->lock); - platform_set_drvdata(pdev, dwc); + dwc->res = res; dwc->regs = regs; dwc->regs_size = resource_size(res); dwc->dev = dev; dwc->irq = irq; + dwc->irqf = irqf; if (!strncmp("super", maximum_speed, 5)) dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; @@ -481,7 +465,7 @@ static int __devinit dwc3_probe(struct platform_device *pdev) ret = dwc3_core_init(dwc); if (ret) { dev_err(dev, "failed to initialize core\n"); - return ret; + goto err0; } mode = DWC3_MODE(dwc->hwparams.hwparams0); @@ -531,7 +515,7 @@ static int __devinit dwc3_probe(struct platform_device *pdev) pm_runtime_allow(dev); - return 0; + return dwc; err2: switch (mode) { @@ -553,18 +537,17 @@ err2: err1: dwc3_core_exit(dwc); - return ret; +err0: + return ERR_PTR(ret); } +EXPORT_SYMBOL_GPL(dwc3_init); -static int __devexit dwc3_remove(struct platform_device *pdev) +void __devexit dwc3_exit(struct dwc3 *dwc) { - struct dwc3 *dwc = platform_get_drvdata(pdev); - struct resource *res; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct device *dev = dwc->dev; - pm_runtime_put(&pdev->dev); - pm_runtime_disable(&pdev->dev); + pm_runtime_put(dev); + pm_runtime_disable(dev); dwc3_debugfs_exit(dwc); @@ -585,31 +568,24 @@ static int __devexit dwc3_remove(struct platform_device *pdev) } dwc3_core_exit(dwc); - - return 0; + dwc3_put_device_id(dwc->devid); } +EXPORT_SYMBOL_GPL(dwc3_exit); -static struct platform_driver dwc3_driver = { - .probe = dwc3_probe, - .remove = __devexit_p(dwc3_remove), - .driver = { - .name = "dwc3", - }, -}; - -MODULE_ALIAS("platform:dwc3"); +MODULE_ALIAS("dwc3"); MODULE_AUTHOR("Felipe Balbi <balbi@xxxxxx>"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver"); -static int __devinit dwc3_init(void) +static int __devinit dwc3_module_init(void) { - return platform_driver_register(&dwc3_driver); + /* all init is done in dwc3_init(), called from bus glue module */ + return 0; } -module_init(dwc3_init); +module_init(dwc3_module_init); -static void __exit dwc3_exit(void) +static void __exit dwc3_module_exit(void) { - platform_driver_unregister(&dwc3_driver); + /* all teardown is done in dwc3_exit(), called from bus glue module */ } -module_exit(dwc3_exit); +module_exit(dwc3_module_exit); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 6c7945b..1979c94 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -595,6 +595,8 @@ struct dwc3 { size_t regs_size; int irq; + int irqf; + int devid; u32 num_event_buffers; u32 u1u2; @@ -778,7 +780,8 @@ void dwc3_host_exit(struct dwc3 *dwc); int dwc3_gadget_init(struct dwc3 *dwc); void dwc3_gadget_exit(struct dwc3 *dwc); -extern int dwc3_get_device_id(void); -extern void dwc3_put_device_id(int id); +extern struct dwc3 * __devinit dwc3_init(struct device *dev, + struct resource *res, int irq, int irqf); +extern void __devexit dwc3_exit(struct dwc3 *dwc); #endif /* __DRIVERS_USB_DWC3_CORE_H */ diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index d7d9c0e..8a1d47e 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -131,7 +131,7 @@ struct dwc3_omap { /* device lock */ spinlock_t lock; - struct platform_device *dwc3; + struct dwc3 *dwc; struct device *dev; int irq; @@ -199,12 +199,11 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) struct dwc3_omap_data *pdata = pdev->dev.platform_data; struct device_node *node = pdev->dev.of_node; - struct platform_device *dwc3; + struct dwc3 *dwc; struct dwc3_omap *omap; struct resource *res; struct device *dev = &pdev->dev; - int devid; int size; int ret = -ENOMEM; int irq; @@ -225,13 +224,13 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 1); if (irq < 0) { - dev_err(dev, "missing IRQ resource\n"); + dev_err(dev, "missing IRQ resource 1\n"); return -EINVAL; } res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!res) { - dev_err(dev, "missing memory base resource\n"); + dev_err(dev, "missing memory base resource 1\n"); return -EINVAL; } @@ -241,34 +240,19 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) return -ENOMEM; } - devid = dwc3_get_device_id(); - if (devid < 0) - return -ENODEV; - - dwc3 = platform_device_alloc("dwc3", devid); - if (!dwc3) { - dev_err(dev, "couldn't allocate dwc3 device\n"); - goto err1; - } - context = devm_kzalloc(dev, resource_size(res), GFP_KERNEL); if (!context) { dev_err(dev, "couldn't allocate dwc3 context memory\n"); - goto err2; + return -ENOMEM; } spin_lock_init(&omap->lock); - dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask); - dwc3->dev.parent = dev; - dwc3->dev.dma_mask = dev->dma_mask; - dwc3->dev.dma_parms = dev->dma_parms; omap->resource_size = resource_size(res); omap->context = context; omap->dev = dev; omap->irq = irq; omap->base = base; - omap->dwc3 = dwc3; reg = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS); @@ -300,8 +284,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE); /* Set No-Idle and No-Standby */ - reg &= ~(USBOTGSS_STANDBYMODE_MASK - | USBOTGSS_IDLEMODE_MASK); + reg &= ~(USBOTGSS_STANDBYMODE_MASK | USBOTGSS_IDLEMODE_MASK); reg |= (USBOTGSS_SYSCONFIG_STANDBYMODE(USBOTGSS_STANDBYMODE_NO_STANDBY) | USBOTGSS_SYSCONFIG_IDLEMODE(USBOTGSS_IDLEMODE_NO_IDLE)); @@ -313,7 +296,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) if (ret) { dev_err(dev, "failed to request IRQ #%d --> %d\n", omap->irq, ret); - goto err2; + goto err1; } /* enable all IRQs */ @@ -332,27 +315,31 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg); - ret = platform_device_add_resources(dwc3, pdev->resource, - pdev->num_resources); - if (ret) { - dev_err(dev, "couldn't add resources to dwc3 device\n"); - goto err2; + ret = -EINVAL; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "missing IRQ resource 0\n"); + goto err1; } - ret = platform_device_add(dwc3); - if (ret) { - dev_err(dev, "failed to register dwc3 device\n"); - goto err2; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "missing memory base resource 0\n"); + goto err1; } - return 0; + dwc = dwc3_init(dev, res, irq, 0); + if (PTR_ERR(dwc)) { + dev_err(dev, "dwc3_init() failed\n"); + ret = PTR_ERR(dwc); + goto err1; + } + omap->dwc = dwc; -err2: - platform_device_put(dwc3); + return 0; err1: - dwc3_put_device_id(devid); - return ret; } @@ -360,9 +347,7 @@ static int __devexit dwc3_omap_remove(struct platform_device *pdev) { struct dwc3_omap *omap = platform_get_drvdata(pdev); - platform_device_unregister(omap->dwc3); - - dwc3_put_device_id(omap->dwc3->id); + dwc3_exit(omap->dwc); return 0; } diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index a81b30e..898019c 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -40,7 +40,7 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/pci.h> -#include <linux/platform_device.h> +#include <linux/interrupt.h> #include "core.h" @@ -48,91 +48,49 @@ #define PCI_VENDOR_ID_SYNOPSYS 0x16c3 #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd -struct dwc3_pci { - struct device *dev; - struct platform_device *dwc3; -}; - static int __devinit dwc3_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) { - struct resource res[2]; - struct platform_device *dwc3; - struct dwc3_pci *glue; - int ret = -ENOMEM; - int devid; + struct resource *res; + struct dwc3 *dwc; struct device *dev = &pci->dev; - glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL); - if (!glue) { - dev_err(dev, "not enough memory\n"); - return -ENOMEM; - } - - glue->dev = dev; + int ret; ret = pci_enable_device(pci); if (ret) { dev_err(dev, "failed to enable pci device\n"); - return -ENODEV; + return ret; } pci_set_power_state(pci, PCI_D0); pci_set_master(pci); - ret = -ENOMEM; - - devid = dwc3_get_device_id(); - if (devid < 0) + res = devm_request_mem_region(dev, pci_resource_start(pci, 0), + pci_resource_len(pci, 0), dev_name(dev)); + if (!res) { + dev_err(dev, "can't request mem region\n"); + ret = -EBUSY; goto err1; + } - dwc3 = platform_device_alloc("dwc3", devid); - if (!dwc3) { - dev_err(dev, "couldn't allocate dwc3 device\n"); + if (!pci->irq) { + dev_err(dev, "no IRQ for PCI device\n"); + ret = -ENODEV; goto err1; } - memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res)); - - res[0].start = pci_resource_start(pci, 0); - res[0].end = pci_resource_end(pci, 0); - res[0].name = "dwc_usb3"; - res[0].flags = IORESOURCE_MEM; - - res[1].start = pci->irq; - res[1].name = "dwc_usb3"; - res[1].flags = IORESOURCE_IRQ; - - ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res)); - if (ret) { - dev_err(dev, "couldn't add resources to dwc3 device\n"); - goto err2; + dwc = dwc3_init(dev, res, pci->irq, IRQF_SHARED); + if (PTR_ERR(dwc)) { + dev_err(dev, "dwc3_init() failed\n"); + ret = PTR_ERR(dwc); + goto err1; } - pci_set_drvdata(pci, glue); - - dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask); - - dwc3->dev.dma_mask = dev->dma_mask; - dwc3->dev.dma_parms = dev->dma_parms; - dwc3->dev.parent = dev; - glue->dwc3 = dwc3; - - ret = platform_device_add(dwc3); - if (ret) { - dev_err(dev, "failed to register dwc3 device\n"); - goto err3; - } + pci_set_drvdata(pci, dwc); return 0; -err3: - pci_set_drvdata(pci, NULL); - platform_device_put(dwc3); - -err2: - dwc3_put_device_id(devid); - err1: pci_disable_device(pci); @@ -141,10 +99,9 @@ err1: static void __devexit dwc3_pci_remove(struct pci_dev *pci) { - struct dwc3_pci *glue = pci_get_drvdata(pci); + struct dwc3 *dwc = pci_get_drvdata(pci); - dwc3_put_device_id(glue->dwc3->id); - platform_device_unregister(glue->dwc3); + dwc3_exit(dwc); pci_set_drvdata(pci, NULL); pci_disable_device(pci); } diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 25910e2..fc17110 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -39,7 +39,6 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/spinlock.h> -#include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/interrupt.h> #include <linux/io.h> diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 3430dbb..5ef3213 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -40,7 +40,6 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/spinlock.h> -#include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/interrupt.h> #include <linux/io.h> @@ -2249,7 +2248,6 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) { u32 reg; int ret; - int irq; dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req), &dwc->ctrl_req_addr, GFP_KERNEL); @@ -2307,13 +2305,11 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) if (ret) goto err4; - irq = platform_get_irq(to_platform_device(dwc->dev), 0); - - ret = request_irq(irq, dwc3_interrupt, IRQF_SHARED, - "dwc3", dwc); + ret = devm_request_irq(dwc->dev, dwc->irq, dwc3_interrupt, dwc->irqf, + "dwc3", dwc); if (ret) { dev_err(dwc->dev, "failed to request irq #%d --> %d\n", - irq, ret); + dwc->irq, ret); goto err5; } @@ -2349,7 +2345,6 @@ err7: err6: dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00); - free_irq(irq, dwc); err5: dwc3_gadget_free_endpoints(dwc); @@ -2375,13 +2370,9 @@ err0: void dwc3_gadget_exit(struct dwc3 *dwc) { - int irq; - usb_del_gadget_udc(&dwc->gadget); - irq = platform_get_irq(to_platform_device(dwc->dev), 0); dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00); - free_irq(irq, dwc); dwc3_gadget_free_endpoints(dwc); -- 1.7.4.4 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html