GNU Linux-libre 4.19.245-gnu1
[releases.git] / drivers / usb / host / ehci-grlib.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Driver for Aeroflex Gaisler GRLIB GRUSBHC EHCI host controller
4  *
5  * GRUSBHC is typically found on LEON/GRLIB SoCs
6  *
7  * (c) Jan Andersson <jan@gaisler.com>
8  *
9  * Based on ehci-ppc-of.c which is:
10  * (c) Valentine Barshak <vbarshak@ru.mvista.com>
11  * and in turn based on "ehci-ppc-soc.c" by Stefan Roese <sr@denx.de>
12  * and "ohci-ppc-of.c" by Sylvain Munaut <tnt@246tNt.com>
13  */
14
15 #include <linux/err.h>
16 #include <linux/signal.h>
17
18 #include <linux/of_irq.h>
19 #include <linux/of_address.h>
20 #include <linux/of_platform.h>
21
22 #define GRUSBHC_HCIVERSION 0x0100 /* Known value of cap. reg. HCIVERSION */
23
24 static const struct hc_driver ehci_grlib_hc_driver = {
25         .description            = hcd_name,
26         .product_desc           = "GRLIB GRUSBHC EHCI",
27         .hcd_priv_size          = sizeof(struct ehci_hcd),
28
29         /*
30          * generic hardware linkage
31          */
32         .irq                    = ehci_irq,
33         .flags                  = HCD_MEMORY | HCD_USB2 | HCD_BH,
34
35         /*
36          * basic lifecycle operations
37          */
38         .reset                  = ehci_setup,
39         .start                  = ehci_run,
40         .stop                   = ehci_stop,
41         .shutdown               = ehci_shutdown,
42
43         /*
44          * managing i/o requests and associated device resources
45          */
46         .urb_enqueue            = ehci_urb_enqueue,
47         .urb_dequeue            = ehci_urb_dequeue,
48         .endpoint_disable       = ehci_endpoint_disable,
49         .endpoint_reset         = ehci_endpoint_reset,
50
51         /*
52          * scheduling support
53          */
54         .get_frame_number       = ehci_get_frame,
55
56         /*
57          * root hub support
58          */
59         .hub_status_data        = ehci_hub_status_data,
60         .hub_control            = ehci_hub_control,
61 #ifdef  CONFIG_PM
62         .bus_suspend            = ehci_bus_suspend,
63         .bus_resume             = ehci_bus_resume,
64 #endif
65         .relinquish_port        = ehci_relinquish_port,
66         .port_handed_over       = ehci_port_handed_over,
67
68         .clear_tt_buffer_complete       = ehci_clear_tt_buffer_complete,
69 };
70
71
72 static int ehci_hcd_grlib_probe(struct platform_device *op)
73 {
74         struct device_node *dn = op->dev.of_node;
75         struct usb_hcd *hcd;
76         struct ehci_hcd *ehci = NULL;
77         struct resource res;
78         u32 hc_capbase;
79         int irq;
80         int rv;
81
82         if (usb_disabled())
83                 return -ENODEV;
84
85         dev_dbg(&op->dev, "initializing GRUSBHC EHCI USB Controller\n");
86
87         rv = of_address_to_resource(dn, 0, &res);
88         if (rv)
89                 return rv;
90
91         /* usb_create_hcd requires dma_mask != NULL */
92         op->dev.dma_mask = &op->dev.coherent_dma_mask;
93         hcd = usb_create_hcd(&ehci_grlib_hc_driver, &op->dev,
94                         "GRUSBHC EHCI USB");
95         if (!hcd)
96                 return -ENOMEM;
97
98         hcd->rsrc_start = res.start;
99         hcd->rsrc_len = resource_size(&res);
100
101         irq = irq_of_parse_and_map(dn, 0);
102         if (irq == NO_IRQ) {
103                 dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n",
104                         __FILE__);
105                 rv = -EBUSY;
106                 goto err_irq;
107         }
108
109         hcd->regs = devm_ioremap_resource(&op->dev, &res);
110         if (IS_ERR(hcd->regs)) {
111                 rv = PTR_ERR(hcd->regs);
112                 goto err_ioremap;
113         }
114
115         ehci = hcd_to_ehci(hcd);
116
117         ehci->caps = hcd->regs;
118
119         /* determine endianness of this implementation */
120         hc_capbase = ehci_readl(ehci, &ehci->caps->hc_capbase);
121         if (HC_VERSION(ehci, hc_capbase) != GRUSBHC_HCIVERSION) {
122                 ehci->big_endian_mmio = 1;
123                 ehci->big_endian_desc = 1;
124                 ehci->big_endian_capbase = 1;
125         }
126
127         rv = usb_add_hcd(hcd, irq, 0);
128         if (rv)
129                 goto err_ioremap;
130
131         device_wakeup_enable(hcd->self.controller);
132         return 0;
133
134 err_ioremap:
135         irq_dispose_mapping(irq);
136 err_irq:
137         usb_put_hcd(hcd);
138
139         return rv;
140 }
141
142
143 static int ehci_hcd_grlib_remove(struct platform_device *op)
144 {
145         struct usb_hcd *hcd = platform_get_drvdata(op);
146
147         dev_dbg(&op->dev, "stopping GRLIB GRUSBHC EHCI USB Controller\n");
148
149         usb_remove_hcd(hcd);
150
151         irq_dispose_mapping(hcd->irq);
152
153         usb_put_hcd(hcd);
154
155         return 0;
156 }
157
158
159 static const struct of_device_id ehci_hcd_grlib_of_match[] = {
160         {
161                 .name = "GAISLER_EHCI",
162          },
163         {
164                 .name = "01_026",
165          },
166         {},
167 };
168 MODULE_DEVICE_TABLE(of, ehci_hcd_grlib_of_match);
169
170
171 static struct platform_driver ehci_grlib_driver = {
172         .probe          = ehci_hcd_grlib_probe,
173         .remove         = ehci_hcd_grlib_remove,
174         .shutdown       = usb_hcd_platform_shutdown,
175         .driver = {
176                 .name = "grlib-ehci",
177                 .of_match_table = ehci_hcd_grlib_of_match,
178         },
179 };