Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * dwc3-haps.c - Synopsys HAPS PCI Specific glue layer
0004  *
0005  * Copyright (C) 2018 Synopsys, Inc.
0006  *
0007  * Authors: Thinh Nguyen <thinhn@synopsys.com>,
0008  *          John Youn <johnyoun@synopsys.com>
0009  */
0010 
0011 #include <linux/kernel.h>
0012 #include <linux/module.h>
0013 #include <linux/slab.h>
0014 #include <linux/pci.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/property.h>
0017 
0018 /**
0019  * struct dwc3_haps - Driver private structure
0020  * @dwc3: child dwc3 platform_device
0021  * @pci: our link to PCI bus
0022  */
0023 struct dwc3_haps {
0024     struct platform_device *dwc3;
0025     struct pci_dev *pci;
0026 };
0027 
0028 static const struct property_entry initial_properties[] = {
0029     PROPERTY_ENTRY_BOOL("snps,usb3_lpm_capable"),
0030     PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
0031     PROPERTY_ENTRY_BOOL("snps,dis_enblslpm_quirk"),
0032     PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
0033     { },
0034 };
0035 
0036 static const struct software_node dwc3_haps_swnode = {
0037     .properties = initial_properties,
0038 };
0039 
0040 static int dwc3_haps_probe(struct pci_dev *pci,
0041                const struct pci_device_id *id)
0042 {
0043     struct dwc3_haps    *dwc;
0044     struct device       *dev = &pci->dev;
0045     struct resource     res[2];
0046     int         ret;
0047 
0048     ret = pcim_enable_device(pci);
0049     if (ret) {
0050         dev_err(dev, "failed to enable pci device\n");
0051         return -ENODEV;
0052     }
0053 
0054     pci_set_master(pci);
0055 
0056     dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
0057     if (!dwc)
0058         return -ENOMEM;
0059 
0060     dwc->dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
0061     if (!dwc->dwc3)
0062         return -ENOMEM;
0063 
0064     memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
0065 
0066     res[0].start    = pci_resource_start(pci, 0);
0067     res[0].end  = pci_resource_end(pci, 0);
0068     res[0].name = "dwc_usb3";
0069     res[0].flags    = IORESOURCE_MEM;
0070 
0071     res[1].start    = pci->irq;
0072     res[1].name = "dwc_usb3";
0073     res[1].flags    = IORESOURCE_IRQ;
0074 
0075     ret = platform_device_add_resources(dwc->dwc3, res, ARRAY_SIZE(res));
0076     if (ret) {
0077         dev_err(dev, "couldn't add resources to dwc3 device\n");
0078         goto err;
0079     }
0080 
0081     dwc->pci = pci;
0082     dwc->dwc3->dev.parent = dev;
0083 
0084     ret = device_add_software_node(&dwc->dwc3->dev, &dwc3_haps_swnode);
0085     if (ret)
0086         goto err;
0087 
0088     ret = platform_device_add(dwc->dwc3);
0089     if (ret) {
0090         dev_err(dev, "failed to register dwc3 device\n");
0091         goto err;
0092     }
0093 
0094     pci_set_drvdata(pci, dwc);
0095 
0096     return 0;
0097 err:
0098     device_remove_software_node(&dwc->dwc3->dev);
0099     platform_device_put(dwc->dwc3);
0100     return ret;
0101 }
0102 
0103 static void dwc3_haps_remove(struct pci_dev *pci)
0104 {
0105     struct dwc3_haps *dwc = pci_get_drvdata(pci);
0106 
0107     device_remove_software_node(&dwc->dwc3->dev);
0108     platform_device_unregister(dwc->dwc3);
0109 }
0110 
0111 static const struct pci_device_id dwc3_haps_id_table[] = {
0112     {
0113         PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
0114                PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
0115         /*
0116          * i.MX6QP and i.MX7D platform use a PCIe controller with the
0117          * same VID and PID as this USB controller. The system may
0118          * incorrectly match this driver to that PCIe controller. To
0119          * workaround this, specifically use class type USB to prevent
0120          * incorrect driver matching.
0121          */
0122         .class = (PCI_CLASS_SERIAL_USB << 8),
0123         .class_mask = 0xffff00,
0124     },
0125     {
0126         PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
0127                PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI),
0128     },
0129     {
0130         PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
0131                PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31),
0132     },
0133     {  }    /* Terminating Entry */
0134 };
0135 MODULE_DEVICE_TABLE(pci, dwc3_haps_id_table);
0136 
0137 static struct pci_driver dwc3_haps_driver = {
0138     .name       = "dwc3-haps",
0139     .id_table   = dwc3_haps_id_table,
0140     .probe      = dwc3_haps_probe,
0141     .remove     = dwc3_haps_remove,
0142 };
0143 
0144 MODULE_AUTHOR("Thinh Nguyen <thinhn@synopsys.com>");
0145 MODULE_LICENSE("GPL v2");
0146 MODULE_DESCRIPTION("Synopsys HAPS PCI Glue Layer");
0147 
0148 module_pci_driver(dwc3_haps_driver);