GNU Linux-libre 6.8.7-gnu
[releases.git] / drivers / usb / dwc2 / pci.c
1 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
2 /*
3  * pci.c - DesignWare HS OTG Controller PCI driver
4  *
5  * Copyright (C) 2004-2013 Synopsys, Inc.
6  */
7
8 /*
9  * Provides the initialization and cleanup entry points for the DWC_otg PCI
10  * driver
11  */
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/moduleparam.h>
15 #include <linux/spinlock.h>
16 #include <linux/interrupt.h>
17 #include <linux/io.h>
18 #include <linux/slab.h>
19 #include <linux/pci.h>
20 #include <linux/usb.h>
21
22 #include <linux/usb/hcd.h>
23 #include <linux/usb/ch11.h>
24 #include <linux/platform_device.h>
25 #include <linux/usb/usb_phy_generic.h>
26
27 #include "core.h"
28
29 static const char dwc2_driver_name[] = "dwc2-pci";
30
31 struct dwc2_pci_glue {
32         struct platform_device *dwc2;
33         struct platform_device *phy;
34 };
35
36 /**
37  * dwc2_pci_remove() - Provides the cleanup entry points for the DWC_otg PCI
38  * driver
39  *
40  * @pci: The programming view of DWC_otg PCI
41  */
42 static void dwc2_pci_remove(struct pci_dev *pci)
43 {
44         struct dwc2_pci_glue *glue = pci_get_drvdata(pci);
45
46         platform_device_unregister(glue->dwc2);
47         usb_phy_generic_unregister(glue->phy);
48         pci_set_drvdata(pci, NULL);
49 }
50
51 static int dwc2_pci_probe(struct pci_dev *pci,
52                           const struct pci_device_id *id)
53 {
54         struct resource         res[2];
55         struct platform_device  *dwc2;
56         struct platform_device  *phy;
57         int                     ret;
58         struct device           *dev = &pci->dev;
59         struct dwc2_pci_glue    *glue;
60
61         ret = pcim_enable_device(pci);
62         if (ret) {
63                 dev_err(dev, "failed to enable pci device\n");
64                 return -ENODEV;
65         }
66
67         pci_set_master(pci);
68
69         phy = usb_phy_generic_register();
70         if (IS_ERR(phy)) {
71                 dev_err(dev, "error registering generic PHY (%ld)\n",
72                         PTR_ERR(phy));
73                 return PTR_ERR(phy);
74         }
75
76         dwc2 = platform_device_alloc("dwc2", PLATFORM_DEVID_AUTO);
77         if (!dwc2) {
78                 dev_err(dev, "couldn't allocate dwc2 device\n");
79                 ret = -ENOMEM;
80                 goto err;
81         }
82
83         memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
84
85         res[0].start    = pci_resource_start(pci, 0);
86         res[0].end      = pci_resource_end(pci, 0);
87         res[0].name     = "dwc2";
88         res[0].flags    = IORESOURCE_MEM;
89
90         res[1].start    = pci->irq;
91         res[1].name     = "dwc2";
92         res[1].flags    = IORESOURCE_IRQ;
93
94         ret = platform_device_add_resources(dwc2, res, ARRAY_SIZE(res));
95         if (ret) {
96                 dev_err(dev, "couldn't add resources to dwc2 device\n");
97                 goto err;
98         }
99
100         dwc2->dev.parent = dev;
101
102         glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
103         if (!glue) {
104                 ret = -ENOMEM;
105                 goto err;
106         }
107
108         ret = platform_device_add(dwc2);
109         if (ret) {
110                 dev_err(dev, "failed to register dwc2 device\n");
111                 goto err;
112         }
113
114         glue->phy = phy;
115         glue->dwc2 = dwc2;
116         pci_set_drvdata(pci, glue);
117
118         return 0;
119 err:
120         usb_phy_generic_unregister(phy);
121         platform_device_put(dwc2);
122         return ret;
123 }
124
125 static struct pci_driver dwc2_pci_driver = {
126         .name = dwc2_driver_name,
127         .id_table = dwc2_pci_ids,
128         .probe = dwc2_pci_probe,
129         .remove = dwc2_pci_remove,
130 };
131
132 module_pci_driver(dwc2_pci_driver);
133
134 MODULE_DESCRIPTION("DESIGNWARE HS OTG PCI Bus Glue");
135 MODULE_AUTHOR("Synopsys, Inc.");
136 MODULE_LICENSE("Dual BSD/GPL");