usb: dwc2: pci: Add device mode to the dwc2-pci driver

The pci driver now registers a platform driver, like in dwc3, and lets
its probe function do all the initialization. This allows it to
account for changes to the platform driver that were not added to the
pci driver. Also future changes to the probe function don't have to be
duplicated. This also has the effect of adding device and DRD mode to
the pci driver. Tested on the Synopsys HAPS PCIe platform.

Signed-off-by: John Youn <johnyoun@synopsys.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
John Youn 2015-03-03 17:17:49 -08:00 committed by Felipe Balbi
parent 005a64307d
commit 9024c495f3
2 changed files with 81 additions and 95 deletions

View File

@ -59,11 +59,12 @@ config USB_DWC2_PLATFORM
config USB_DWC2_PCI
tristate "DWC2 PCI"
depends on USB_DWC2_HOST && PCI
default USB_DWC2_HOST
depends on PCI
default n
select USB_DWC2_PLATFORM
help
The Designware USB2.0 PCI interface module for controllers
connected to a PCI bus. This is only used for host mode.
connected to a PCI bus.
config USB_DWC2_DEBUG
bool "Enable Debugging Messages"

View File

@ -50,112 +50,97 @@
#include <linux/usb/hcd.h>
#include <linux/usb/ch11.h>
#include "core.h"
#include "hcd.h"
#include <linux/platform_device.h>
#include <linux/usb/usb_phy_generic.h>
#define PCI_PRODUCT_ID_HAPS_HSOTG 0xabc0
static const char dwc2_driver_name[] = "dwc2";
static const char dwc2_driver_name[] = "dwc2-pci";
static const struct dwc2_core_params dwc2_module_params = {
.otg_cap = -1,
.otg_ver = -1,
.dma_enable = -1,
.dma_desc_enable = 0,
.speed = -1,
.enable_dynamic_fifo = -1,
.en_multiple_tx_fifo = -1,
.host_rx_fifo_size = 1024,
.host_nperio_tx_fifo_size = 256,
.host_perio_tx_fifo_size = 1024,
.max_transfer_size = 65535,
.max_packet_count = 511,
.host_channels = -1,
.phy_type = -1,
.phy_utmi_width = -1,
.phy_ulpi_ddr = -1,
.phy_ulpi_ext_vbus = -1,
.i2c_enable = -1,
.ulpi_fs_ls = -1,
.host_support_fs_ls_low_power = -1,
.host_ls_low_power_phy_clk = -1,
.ts_dline = -1,
.reload_ctl = -1,
.ahbcfg = -1,
.uframe_sched = -1,
struct dwc2_pci_glue {
struct platform_device *dwc2;
struct platform_device *phy;
};
/**
* dwc2_driver_remove() - Called when the DWC_otg core is unregistered with the
* DWC_otg driver
*
* @dev: Bus device
*
* This routine is called, for example, when the rmmod command is executed. The
* device may or may not be electrically present. If it is present, the driver
* stops device processing. Any resources used on behalf of this device are
* freed.
*/
static void dwc2_driver_remove(struct pci_dev *dev)
static void dwc2_pci_remove(struct pci_dev *pci)
{
struct dwc2_hsotg *hsotg = pci_get_drvdata(dev);
struct dwc2_pci_glue *glue = pci_get_drvdata(pci);
dwc2_hcd_remove(hsotg);
pci_disable_device(dev);
platform_device_unregister(glue->dwc2);
usb_phy_generic_unregister(glue->phy);
kfree(glue);
pci_set_drvdata(pci, NULL);
}
/**
* dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg
* driver
*
* @dev: Bus device
*
* This routine creates the driver components required to control the device
* (core, HCD, and PCD) and initializes the device. The driver components are
* stored in a dwc2_hsotg structure. A reference to the dwc2_hsotg is saved
* in the device private data. This allows the driver to access the dwc2_hsotg
* structure on subsequent calls to driver methods for this device.
*/
static int dwc2_driver_probe(struct pci_dev *dev,
const struct pci_device_id *id)
static int dwc2_pci_probe(struct pci_dev *pci,
const struct pci_device_id *id)
{
struct dwc2_hsotg *hsotg;
int retval;
struct resource res[2];
struct platform_device *dwc2;
struct platform_device *phy;
int ret;
struct device *dev = &pci->dev;
struct dwc2_pci_glue *glue;
hsotg = devm_kzalloc(&dev->dev, sizeof(*hsotg), GFP_KERNEL);
if (!hsotg)
return -ENOMEM;
hsotg->dev = &dev->dev;
hsotg->regs = devm_ioremap_resource(&dev->dev, &dev->resource[0]);
if (IS_ERR(hsotg->regs))
return PTR_ERR(hsotg->regs);
dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n",
(unsigned long)pci_resource_start(dev, 0), hsotg->regs);
if (pci_enable_device(dev) < 0)
ret = pcim_enable_device(pci);
if (ret) {
dev_err(dev, "failed to enable pci device\n");
return -ENODEV;
pci_set_master(dev);
retval = devm_request_irq(hsotg->dev, dev->irq,
dwc2_handle_common_intr, IRQF_SHARED,
dev_name(hsotg->dev), hsotg);
if (retval)
return retval;
spin_lock_init(&hsotg->lock);
retval = dwc2_hcd_init(hsotg, dev->irq, &dwc2_module_params);
if (retval) {
pci_disable_device(dev);
return retval;
}
pci_set_drvdata(dev, hsotg);
pci_set_master(pci);
return retval;
dwc2 = platform_device_alloc("dwc2", PLATFORM_DEVID_AUTO);
if (!dwc2) {
dev_err(dev, "couldn't allocate dwc2 device\n");
return -ENOMEM;
}
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 = "dwc2";
res[0].flags = IORESOURCE_MEM;
res[1].start = pci->irq;
res[1].name = "dwc2";
res[1].flags = IORESOURCE_IRQ;
ret = platform_device_add_resources(dwc2, res, ARRAY_SIZE(res));
if (ret) {
dev_err(dev, "couldn't add resources to dwc2 device\n");
return ret;
}
dwc2->dev.parent = dev;
phy = usb_phy_generic_register();
if (IS_ERR(phy)) {
dev_err(dev, "error registering generic PHY (%ld)\n",
PTR_ERR(phy));
return PTR_ERR(phy);
}
ret = platform_device_add(dwc2);
if (ret) {
dev_err(dev, "failed to register dwc2 device\n");
goto err;
}
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
if (!glue)
return -ENOMEM;
glue->phy = phy;
glue->dwc2 = dwc2;
pci_set_drvdata(pci, glue);
return 0;
err:
usb_phy_generic_unregister(phy);
platform_device_put(dwc2);
return ret;
}
static const struct pci_device_id dwc2_pci_ids[] = {
@ -173,8 +158,8 @@ MODULE_DEVICE_TABLE(pci, dwc2_pci_ids);
static struct pci_driver dwc2_pci_driver = {
.name = dwc2_driver_name,
.id_table = dwc2_pci_ids,
.probe = dwc2_driver_probe,
.remove = dwc2_driver_remove,
.probe = dwc2_pci_probe,
.remove = dwc2_pci_remove,
};
module_pci_driver(dwc2_pci_driver);