Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-1.0+
0002 /*
0003  * OHCI HCD (Host Controller Driver) for USB.
0004  *
0005  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
0006  * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
0007  * (C) Copyright 2002 Hewlett-Packard Company
0008  * (C) Copyright 2006 Sylvain Munaut <tnt@246tNt.com>
0009  *
0010  * Bus glue for OHCI HC on the of_platform bus
0011  *
0012  * Modified for of_platform bus from ohci-sa1111.c
0013  *
0014  * This file is licenced under the GPL.
0015  */
0016 
0017 #include <linux/signal.h>
0018 #include <linux/of_address.h>
0019 #include <linux/of_irq.h>
0020 #include <linux/of_platform.h>
0021 
0022 static int
0023 ohci_ppc_of_start(struct usb_hcd *hcd)
0024 {
0025     struct ohci_hcd *ohci = hcd_to_ohci(hcd);
0026     int     ret;
0027 
0028     if ((ret = ohci_init(ohci)) < 0)
0029         return ret;
0030 
0031     if ((ret = ohci_run(ohci)) < 0) {
0032         dev_err(hcd->self.controller, "can't start %s\n",
0033             hcd->self.bus_name);
0034         ohci_stop(hcd);
0035         return ret;
0036     }
0037 
0038     return 0;
0039 }
0040 
0041 static const struct hc_driver ohci_ppc_of_hc_driver = {
0042     .description =      hcd_name,
0043     .product_desc =     "OF OHCI",
0044     .hcd_priv_size =    sizeof(struct ohci_hcd),
0045 
0046     /*
0047      * generic hardware linkage
0048      */
0049     .irq =          ohci_irq,
0050     .flags =        HCD_USB11 | HCD_DMA | HCD_MEMORY,
0051 
0052     /*
0053      * basic lifecycle operations
0054      */
0055     .start =        ohci_ppc_of_start,
0056     .stop =         ohci_stop,
0057     .shutdown =         ohci_shutdown,
0058 
0059     /*
0060      * managing i/o requests and associated device resources
0061      */
0062     .urb_enqueue =      ohci_urb_enqueue,
0063     .urb_dequeue =      ohci_urb_dequeue,
0064     .endpoint_disable = ohci_endpoint_disable,
0065 
0066     /*
0067      * scheduling support
0068      */
0069     .get_frame_number = ohci_get_frame,
0070 
0071     /*
0072      * root hub support
0073      */
0074     .hub_status_data =  ohci_hub_status_data,
0075     .hub_control =      ohci_hub_control,
0076 #ifdef  CONFIG_PM
0077     .bus_suspend =      ohci_bus_suspend,
0078     .bus_resume =       ohci_bus_resume,
0079 #endif
0080     .start_port_reset = ohci_start_port_reset,
0081 };
0082 
0083 
0084 static int ohci_hcd_ppc_of_probe(struct platform_device *op)
0085 {
0086     struct device_node *dn = op->dev.of_node;
0087     struct usb_hcd *hcd;
0088     struct ohci_hcd *ohci;
0089     struct resource res;
0090     int irq;
0091 
0092     int rv;
0093     int is_bigendian;
0094     struct device_node *np;
0095 
0096     if (usb_disabled())
0097         return -ENODEV;
0098 
0099     is_bigendian =
0100         of_device_is_compatible(dn, "ohci-bigendian") ||
0101         of_device_is_compatible(dn, "ohci-be");
0102 
0103     dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
0104 
0105     rv = of_address_to_resource(dn, 0, &res);
0106     if (rv)
0107         return rv;
0108 
0109     hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB");
0110     if (!hcd)
0111         return -ENOMEM;
0112 
0113     hcd->rsrc_start = res.start;
0114     hcd->rsrc_len = resource_size(&res);
0115 
0116     hcd->regs = devm_ioremap_resource(&op->dev, &res);
0117     if (IS_ERR(hcd->regs)) {
0118         rv = PTR_ERR(hcd->regs);
0119         goto err_rmr;
0120     }
0121 
0122     irq = irq_of_parse_and_map(dn, 0);
0123     if (irq == NO_IRQ) {
0124         dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n",
0125             __FILE__);
0126         rv = -EBUSY;
0127         goto err_rmr;
0128     }
0129 
0130     ohci = hcd_to_ohci(hcd);
0131     if (is_bigendian) {
0132         ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
0133         if (of_device_is_compatible(dn, "fsl,mpc5200-ohci"))
0134             ohci->flags |= OHCI_QUIRK_FRAME_NO;
0135         if (of_device_is_compatible(dn, "mpc5200-ohci"))
0136             ohci->flags |= OHCI_QUIRK_FRAME_NO;
0137     }
0138 
0139     ohci_hcd_init(ohci);
0140 
0141     rv = usb_add_hcd(hcd, irq, 0);
0142     if (rv == 0) {
0143         device_wakeup_enable(hcd->self.controller);
0144         return 0;
0145     }
0146 
0147     /* by now, 440epx is known to show usb_23 erratum */
0148     np = of_find_compatible_node(NULL, NULL, "ibm,usb-ehci-440epx");
0149 
0150     /* Work around - At this point ohci_run has executed, the
0151     * controller is running, everything, the root ports, etc., is
0152     * set up.  If the ehci driver is loaded, put the ohci core in
0153     * the suspended state.  The ehci driver will bring it out of
0154     * suspended state when / if a non-high speed USB device is
0155     * attached to the USB Host port.  If the ehci driver is not
0156     * loaded, do nothing. request_mem_region is used to test if
0157     * the ehci driver is loaded.
0158     */
0159     if (np !=  NULL) {
0160         if (!of_address_to_resource(np, 0, &res)) {
0161             if (!request_mem_region(res.start, 0x4, hcd_name)) {
0162                 writel_be((readl_be(&ohci->regs->control) |
0163                     OHCI_USB_SUSPEND), &ohci->regs->control);
0164                     (void) readl_be(&ohci->regs->control);
0165             } else
0166                 release_mem_region(res.start, 0x4);
0167         } else
0168             pr_debug("%s: cannot get ehci offset from fdt\n", __FILE__);
0169         of_node_put(np);
0170     }
0171 
0172     irq_dispose_mapping(irq);
0173 err_rmr:
0174     usb_put_hcd(hcd);
0175 
0176     return rv;
0177 }
0178 
0179 static int ohci_hcd_ppc_of_remove(struct platform_device *op)
0180 {
0181     struct usb_hcd *hcd = platform_get_drvdata(op);
0182 
0183     dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
0184 
0185     usb_remove_hcd(hcd);
0186 
0187     irq_dispose_mapping(hcd->irq);
0188 
0189     usb_put_hcd(hcd);
0190 
0191     return 0;
0192 }
0193 
0194 static const struct of_device_id ohci_hcd_ppc_of_match[] = {
0195 #ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
0196     {
0197         .name = "usb",
0198         .compatible = "ohci-bigendian",
0199     },
0200     {
0201         .name = "usb",
0202         .compatible = "ohci-be",
0203     },
0204 #endif
0205 #ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE
0206     {
0207         .name = "usb",
0208         .compatible = "ohci-littledian",
0209     },
0210     {
0211         .name = "usb",
0212         .compatible = "ohci-le",
0213     },
0214 #endif
0215     {},
0216 };
0217 MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match);
0218 
0219 #if !defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \
0220     !defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE)
0221 #error "No endianness selected for ppc-of-ohci"
0222 #endif
0223 
0224 
0225 static struct platform_driver ohci_hcd_ppc_of_driver = {
0226     .probe      = ohci_hcd_ppc_of_probe,
0227     .remove     = ohci_hcd_ppc_of_remove,
0228     .shutdown   = usb_hcd_platform_shutdown,
0229     .driver = {
0230         .name = "ppc-of-ohci",
0231         .of_match_table = ohci_hcd_ppc_of_match,
0232     },
0233 };
0234