0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 #include <linux/kernel.h>
0043 #include <linux/module.h>
0044 #include <linux/moduleparam.h>
0045 #include <linux/spinlock.h>
0046 #include <linux/interrupt.h>
0047 #include <linux/io.h>
0048 #include <linux/slab.h>
0049 #include <linux/pci.h>
0050 #include <linux/usb.h>
0051
0052 #include <linux/usb/hcd.h>
0053 #include <linux/usb/ch11.h>
0054 #include <linux/platform_device.h>
0055 #include <linux/usb/usb_phy_generic.h>
0056
0057 #define PCI_PRODUCT_ID_HAPS_HSOTG 0xabc0
0058
0059 static const char dwc2_driver_name[] = "dwc2-pci";
0060
0061 struct dwc2_pci_glue {
0062 struct platform_device *dwc2;
0063 struct platform_device *phy;
0064 };
0065
0066
0067
0068
0069
0070
0071
0072 static void dwc2_pci_remove(struct pci_dev *pci)
0073 {
0074 struct dwc2_pci_glue *glue = pci_get_drvdata(pci);
0075
0076 platform_device_unregister(glue->dwc2);
0077 usb_phy_generic_unregister(glue->phy);
0078 pci_set_drvdata(pci, NULL);
0079 }
0080
0081 static int dwc2_pci_probe(struct pci_dev *pci,
0082 const struct pci_device_id *id)
0083 {
0084 struct resource res[2];
0085 struct platform_device *dwc2;
0086 struct platform_device *phy;
0087 int ret;
0088 struct device *dev = &pci->dev;
0089 struct dwc2_pci_glue *glue;
0090
0091 ret = pcim_enable_device(pci);
0092 if (ret) {
0093 dev_err(dev, "failed to enable pci device\n");
0094 return -ENODEV;
0095 }
0096
0097 pci_set_master(pci);
0098
0099 phy = usb_phy_generic_register();
0100 if (IS_ERR(phy)) {
0101 dev_err(dev, "error registering generic PHY (%ld)\n",
0102 PTR_ERR(phy));
0103 return PTR_ERR(phy);
0104 }
0105
0106 dwc2 = platform_device_alloc("dwc2", PLATFORM_DEVID_AUTO);
0107 if (!dwc2) {
0108 dev_err(dev, "couldn't allocate dwc2 device\n");
0109 ret = -ENOMEM;
0110 goto err;
0111 }
0112
0113 memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
0114
0115 res[0].start = pci_resource_start(pci, 0);
0116 res[0].end = pci_resource_end(pci, 0);
0117 res[0].name = "dwc2";
0118 res[0].flags = IORESOURCE_MEM;
0119
0120 res[1].start = pci->irq;
0121 res[1].name = "dwc2";
0122 res[1].flags = IORESOURCE_IRQ;
0123
0124 ret = platform_device_add_resources(dwc2, res, ARRAY_SIZE(res));
0125 if (ret) {
0126 dev_err(dev, "couldn't add resources to dwc2 device\n");
0127 goto err;
0128 }
0129
0130 dwc2->dev.parent = dev;
0131
0132 glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
0133 if (!glue) {
0134 ret = -ENOMEM;
0135 goto err;
0136 }
0137
0138 ret = platform_device_add(dwc2);
0139 if (ret) {
0140 dev_err(dev, "failed to register dwc2 device\n");
0141 goto err;
0142 }
0143
0144 glue->phy = phy;
0145 glue->dwc2 = dwc2;
0146 pci_set_drvdata(pci, glue);
0147
0148 return 0;
0149 err:
0150 usb_phy_generic_unregister(phy);
0151 platform_device_put(dwc2);
0152 return ret;
0153 }
0154
0155 static const struct pci_device_id dwc2_pci_ids[] = {
0156 {
0157 PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, PCI_PRODUCT_ID_HAPS_HSOTG),
0158 },
0159 {
0160 PCI_DEVICE(PCI_VENDOR_ID_STMICRO,
0161 PCI_DEVICE_ID_STMICRO_USB_OTG),
0162 },
0163 { }
0164 };
0165 MODULE_DEVICE_TABLE(pci, dwc2_pci_ids);
0166
0167 static struct pci_driver dwc2_pci_driver = {
0168 .name = dwc2_driver_name,
0169 .id_table = dwc2_pci_ids,
0170 .probe = dwc2_pci_probe,
0171 .remove = dwc2_pci_remove,
0172 };
0173
0174 module_pci_driver(dwc2_pci_driver);
0175
0176 MODULE_DESCRIPTION("DESIGNWARE HS OTG PCI Bus Glue");
0177 MODULE_AUTHOR("Synopsys, Inc.");
0178 MODULE_LICENSE("Dual BSD/GPL");