Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Driver for Aeroflex Gaisler GRLIB GRUSBHC EHCI host controller
0004  *
0005  * GRUSBHC is typically found on LEON/GRLIB SoCs
0006  *
0007  * (c) Jan Andersson <jan@gaisler.com>
0008  *
0009  * Based on ehci-ppc-of.c which is:
0010  * (c) Valentine Barshak <vbarshak@ru.mvista.com>
0011  * and in turn based on "ehci-ppc-soc.c" by Stefan Roese <sr@denx.de>
0012  * and "ohci-ppc-of.c" by Sylvain Munaut <tnt@246tNt.com>
0013  */
0014 
0015 #include <linux/err.h>
0016 #include <linux/signal.h>
0017 
0018 #include <linux/of_irq.h>
0019 #include <linux/of_address.h>
0020 #include <linux/of_platform.h>
0021 
0022 #define GRUSBHC_HCIVERSION 0x0100 /* Known value of cap. reg. HCIVERSION */
0023 
0024 static const struct hc_driver ehci_grlib_hc_driver = {
0025     .description        = hcd_name,
0026     .product_desc       = "GRLIB GRUSBHC EHCI",
0027     .hcd_priv_size      = sizeof(struct ehci_hcd),
0028 
0029     /*
0030      * generic hardware linkage
0031      */
0032     .irq            = ehci_irq,
0033     .flags          = HCD_MEMORY | HCD_DMA | HCD_USB2 | HCD_BH,
0034 
0035     /*
0036      * basic lifecycle operations
0037      */
0038     .reset          = ehci_setup,
0039     .start          = ehci_run,
0040     .stop           = ehci_stop,
0041     .shutdown       = ehci_shutdown,
0042 
0043     /*
0044      * managing i/o requests and associated device resources
0045      */
0046     .urb_enqueue        = ehci_urb_enqueue,
0047     .urb_dequeue        = ehci_urb_dequeue,
0048     .endpoint_disable   = ehci_endpoint_disable,
0049     .endpoint_reset     = ehci_endpoint_reset,
0050 
0051     /*
0052      * scheduling support
0053      */
0054     .get_frame_number   = ehci_get_frame,
0055 
0056     /*
0057      * root hub support
0058      */
0059     .hub_status_data    = ehci_hub_status_data,
0060     .hub_control        = ehci_hub_control,
0061 #ifdef  CONFIG_PM
0062     .bus_suspend        = ehci_bus_suspend,
0063     .bus_resume     = ehci_bus_resume,
0064 #endif
0065     .relinquish_port    = ehci_relinquish_port,
0066     .port_handed_over   = ehci_port_handed_over,
0067 
0068     .clear_tt_buffer_complete   = ehci_clear_tt_buffer_complete,
0069 };
0070 
0071 
0072 static int ehci_hcd_grlib_probe(struct platform_device *op)
0073 {
0074     struct device_node *dn = op->dev.of_node;
0075     struct usb_hcd *hcd;
0076     struct ehci_hcd *ehci = NULL;
0077     struct resource res;
0078     u32 hc_capbase;
0079     int irq;
0080     int rv;
0081 
0082     if (usb_disabled())
0083         return -ENODEV;
0084 
0085     dev_dbg(&op->dev, "initializing GRUSBHC EHCI USB Controller\n");
0086 
0087     rv = of_address_to_resource(dn, 0, &res);
0088     if (rv)
0089         return rv;
0090 
0091     /* usb_create_hcd requires dma_mask != NULL */
0092     op->dev.dma_mask = &op->dev.coherent_dma_mask;
0093     hcd = usb_create_hcd(&ehci_grlib_hc_driver, &op->dev,
0094             "GRUSBHC EHCI USB");
0095     if (!hcd)
0096         return -ENOMEM;
0097 
0098     hcd->rsrc_start = res.start;
0099     hcd->rsrc_len = resource_size(&res);
0100 
0101     irq = irq_of_parse_and_map(dn, 0);
0102     if (irq == NO_IRQ) {
0103         dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n",
0104             __FILE__);
0105         rv = -EBUSY;
0106         goto err_irq;
0107     }
0108 
0109     hcd->regs = devm_ioremap_resource(&op->dev, &res);
0110     if (IS_ERR(hcd->regs)) {
0111         rv = PTR_ERR(hcd->regs);
0112         goto err_ioremap;
0113     }
0114 
0115     ehci = hcd_to_ehci(hcd);
0116 
0117     ehci->caps = hcd->regs;
0118 
0119     /* determine endianness of this implementation */
0120     hc_capbase = ehci_readl(ehci, &ehci->caps->hc_capbase);
0121     if (HC_VERSION(ehci, hc_capbase) != GRUSBHC_HCIVERSION) {
0122         ehci->big_endian_mmio = 1;
0123         ehci->big_endian_desc = 1;
0124         ehci->big_endian_capbase = 1;
0125     }
0126 
0127     rv = usb_add_hcd(hcd, irq, 0);
0128     if (rv)
0129         goto err_ioremap;
0130 
0131     device_wakeup_enable(hcd->self.controller);
0132     return 0;
0133 
0134 err_ioremap:
0135     irq_dispose_mapping(irq);
0136 err_irq:
0137     usb_put_hcd(hcd);
0138 
0139     return rv;
0140 }
0141 
0142 
0143 static int ehci_hcd_grlib_remove(struct platform_device *op)
0144 {
0145     struct usb_hcd *hcd = platform_get_drvdata(op);
0146 
0147     dev_dbg(&op->dev, "stopping GRLIB GRUSBHC EHCI USB Controller\n");
0148 
0149     usb_remove_hcd(hcd);
0150 
0151     irq_dispose_mapping(hcd->irq);
0152 
0153     usb_put_hcd(hcd);
0154 
0155     return 0;
0156 }
0157 
0158 
0159 static const struct of_device_id ehci_hcd_grlib_of_match[] = {
0160     {
0161         .name = "GAISLER_EHCI",
0162      },
0163     {
0164         .name = "01_026",
0165      },
0166     {},
0167 };
0168 MODULE_DEVICE_TABLE(of, ehci_hcd_grlib_of_match);
0169 
0170 
0171 static struct platform_driver ehci_grlib_driver = {
0172     .probe      = ehci_hcd_grlib_probe,
0173     .remove     = ehci_hcd_grlib_remove,
0174     .shutdown   = usb_hcd_platform_shutdown,
0175     .driver = {
0176         .name = "grlib-ehci",
0177         .of_match_table = ehci_hcd_grlib_of_match,
0178     },
0179 };