1 /* 2 * Driver for Aeroflex Gaisler GRLIB GRUSBHC EHCI host controller 3 * 4 * GRUSBHC is typically found on LEON/GRLIB SoCs 5 * 6 * (c) Jan Andersson <jan@gaisler.com> 7 * 8 * Based on ehci-ppc-of.c which is: 9 * (c) Valentine Barshak <vbarshak@ru.mvista.com> 10 * and in turn based on "ehci-ppc-soc.c" by Stefan Roese <sr@denx.de> 11 * and "ohci-ppc-of.c" by Sylvain Munaut <tnt@246tNt.com> 12 * 13 * This program is free software; you can redistribute it and/or modify it 14 * under the terms of the GNU General Public License as published by the 15 * Free Software Foundation; either version 2 of the License, or (at your 16 * option) any later version. 17 * 18 * This program is distributed in the hope that it will be useful, but 19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 21 * for more details. 22 * 23 * You should have received a copy of the GNU General Public License 24 * along with this program; if not, write to the Free Software Foundation, 25 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 26 */ 27 28 29 #include <linux/signal.h> 30 31 #include <linux/of_irq.h> 32 #include <linux/of_address.h> 33 #include <linux/of_platform.h> 34 35 #define GRUSBHC_HCIVERSION 0x0100 /* Known value of cap. reg. HCIVERSION */ 36 37 /* called during probe() after chip reset completes */ 38 static int ehci_grlib_setup(struct usb_hcd *hcd) 39 { 40 struct ehci_hcd *ehci = hcd_to_ehci(hcd); 41 int retval; 42 43 retval = ehci_setup(hcd); 44 if (retval) 45 return retval; 46 47 ehci_port_power(ehci, 1); 48 49 return retval; 50 } 51 52 53 static const struct hc_driver ehci_grlib_hc_driver = { 54 .description = hcd_name, 55 .product_desc = "GRLIB GRUSBHC EHCI", 56 .hcd_priv_size = sizeof(struct ehci_hcd), 57 58 /* 59 * generic hardware linkage 60 */ 61 .irq = ehci_irq, 62 .flags = HCD_MEMORY | HCD_USB2, 63 64 /* 65 * basic lifecycle operations 66 */ 67 .reset = ehci_grlib_setup, 68 .start = ehci_run, 69 .stop = ehci_stop, 70 .shutdown = ehci_shutdown, 71 72 /* 73 * managing i/o requests and associated device resources 74 */ 75 .urb_enqueue = ehci_urb_enqueue, 76 .urb_dequeue = ehci_urb_dequeue, 77 .endpoint_disable = ehci_endpoint_disable, 78 .endpoint_reset = ehci_endpoint_reset, 79 80 /* 81 * scheduling support 82 */ 83 .get_frame_number = ehci_get_frame, 84 85 /* 86 * root hub support 87 */ 88 .hub_status_data = ehci_hub_status_data, 89 .hub_control = ehci_hub_control, 90 #ifdef CONFIG_PM 91 .bus_suspend = ehci_bus_suspend, 92 .bus_resume = ehci_bus_resume, 93 #endif 94 .relinquish_port = ehci_relinquish_port, 95 .port_handed_over = ehci_port_handed_over, 96 97 .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, 98 }; 99 100 101 static int __devinit ehci_hcd_grlib_probe(struct platform_device *op) 102 { 103 struct device_node *dn = op->dev.of_node; 104 struct usb_hcd *hcd; 105 struct ehci_hcd *ehci = NULL; 106 struct resource res; 107 u32 hc_capbase; 108 int irq; 109 int rv; 110 111 if (usb_disabled()) 112 return -ENODEV; 113 114 dev_dbg(&op->dev, "initializing GRUSBHC EHCI USB Controller\n"); 115 116 rv = of_address_to_resource(dn, 0, &res); 117 if (rv) 118 return rv; 119 120 /* usb_create_hcd requires dma_mask != NULL */ 121 op->dev.dma_mask = &op->dev.coherent_dma_mask; 122 hcd = usb_create_hcd(&ehci_grlib_hc_driver, &op->dev, 123 "GRUSBHC EHCI USB"); 124 if (!hcd) 125 return -ENOMEM; 126 127 hcd->rsrc_start = res.start; 128 hcd->rsrc_len = resource_size(&res); 129 130 irq = irq_of_parse_and_map(dn, 0); 131 if (irq == NO_IRQ) { 132 printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__); 133 rv = -EBUSY; 134 goto err_irq; 135 } 136 137 hcd->regs = devm_request_and_ioremap(&op->dev, &res); 138 if (!hcd->regs) { 139 pr_err("%s: devm_request_and_ioremap failed\n", __FILE__); 140 rv = -ENOMEM; 141 goto err_ioremap; 142 } 143 144 ehci = hcd_to_ehci(hcd); 145 146 ehci->caps = hcd->regs; 147 148 /* determine endianness of this implementation */ 149 hc_capbase = ehci_readl(ehci, &ehci->caps->hc_capbase); 150 if (HC_VERSION(ehci, hc_capbase) != GRUSBHC_HCIVERSION) { 151 ehci->big_endian_mmio = 1; 152 ehci->big_endian_desc = 1; 153 ehci->big_endian_capbase = 1; 154 } 155 156 rv = usb_add_hcd(hcd, irq, 0); 157 if (rv) 158 goto err_ioremap; 159 160 return 0; 161 162 err_ioremap: 163 irq_dispose_mapping(irq); 164 err_irq: 165 usb_put_hcd(hcd); 166 167 return rv; 168 } 169 170 171 static int ehci_hcd_grlib_remove(struct platform_device *op) 172 { 173 struct usb_hcd *hcd = dev_get_drvdata(&op->dev); 174 175 dev_set_drvdata(&op->dev, NULL); 176 177 dev_dbg(&op->dev, "stopping GRLIB GRUSBHC EHCI USB Controller\n"); 178 179 usb_remove_hcd(hcd); 180 181 irq_dispose_mapping(hcd->irq); 182 183 usb_put_hcd(hcd); 184 185 return 0; 186 } 187 188 189 static void ehci_hcd_grlib_shutdown(struct platform_device *op) 190 { 191 struct usb_hcd *hcd = dev_get_drvdata(&op->dev); 192 193 if (hcd->driver->shutdown) 194 hcd->driver->shutdown(hcd); 195 } 196 197 198 static const struct of_device_id ehci_hcd_grlib_of_match[] = { 199 { 200 .name = "GAISLER_EHCI", 201 }, 202 { 203 .name = "01_026", 204 }, 205 {}, 206 }; 207 MODULE_DEVICE_TABLE(of, ehci_hcd_grlib_of_match); 208 209 210 static struct platform_driver ehci_grlib_driver = { 211 .probe = ehci_hcd_grlib_probe, 212 .remove = ehci_hcd_grlib_remove, 213 .shutdown = ehci_hcd_grlib_shutdown, 214 .driver = { 215 .name = "grlib-ehci", 216 .owner = THIS_MODULE, 217 .of_match_table = ehci_hcd_grlib_of_match, 218 }, 219 }; 220