linux/drivers/usb/host/uhci-platform.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Generic UHCI HCD (Host Controller Driver) for Platform Devices
   4 *
   5 * Copyright (c) 2011 Tony Prisk <linux@prisktech.co.nz>
   6 *
   7 * This file is based on uhci-grlib.c
   8 * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu
   9 */
  10
  11#include <linux/of.h>
  12#include <linux/device.h>
  13#include <linux/platform_device.h>
  14
  15static int uhci_platform_init(struct usb_hcd *hcd)
  16{
  17        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
  18
  19        /* Probe number of ports if not already provided by DT */
  20        if (!uhci->rh_numports)
  21                uhci->rh_numports = uhci_count_ports(hcd);
  22
  23        /* Set up pointers to to generic functions */
  24        uhci->reset_hc = uhci_generic_reset_hc;
  25        uhci->check_and_reset_hc = uhci_generic_check_and_reset_hc;
  26
  27        /* No special actions need to be taken for the functions below */
  28        uhci->configure_hc = NULL;
  29        uhci->resume_detect_interrupts_are_broken = NULL;
  30        uhci->global_suspend_mode_is_broken = NULL;
  31
  32        /* Reset if the controller isn't already safely quiescent. */
  33        check_and_reset_hc(uhci);
  34        return 0;
  35}
  36
  37static const struct hc_driver uhci_platform_hc_driver = {
  38        .description =          hcd_name,
  39        .product_desc =         "Generic UHCI Host Controller",
  40        .hcd_priv_size =        sizeof(struct uhci_hcd),
  41
  42        /* Generic hardware linkage */
  43        .irq =                  uhci_irq,
  44        .flags =                HCD_MEMORY | HCD_USB11,
  45
  46        /* Basic lifecycle operations */
  47        .reset =                uhci_platform_init,
  48        .start =                uhci_start,
  49#ifdef CONFIG_PM
  50        .pci_suspend =          NULL,
  51        .pci_resume =           NULL,
  52        .bus_suspend =          uhci_rh_suspend,
  53        .bus_resume =           uhci_rh_resume,
  54#endif
  55        .stop =                 uhci_stop,
  56
  57        .urb_enqueue =          uhci_urb_enqueue,
  58        .urb_dequeue =          uhci_urb_dequeue,
  59
  60        .endpoint_disable =     uhci_hcd_endpoint_disable,
  61        .get_frame_number =     uhci_hcd_get_frame_number,
  62
  63        .hub_status_data =      uhci_hub_status_data,
  64        .hub_control =          uhci_hub_control,
  65};
  66
  67static int uhci_hcd_platform_probe(struct platform_device *pdev)
  68{
  69        struct device_node *np = pdev->dev.of_node;
  70        struct usb_hcd *hcd;
  71        struct uhci_hcd *uhci;
  72        struct resource *res;
  73        int ret;
  74
  75        if (usb_disabled())
  76                return -ENODEV;
  77
  78        /*
  79         * Right now device-tree probed devices don't get dma_mask set.
  80         * Since shared usb code relies on it, set it here for now.
  81         * Once we have dma capability bindings this can go away.
  82         */
  83        ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
  84        if (ret)
  85                return ret;
  86
  87        hcd = usb_create_hcd(&uhci_platform_hc_driver, &pdev->dev,
  88                        pdev->name);
  89        if (!hcd)
  90                return -ENOMEM;
  91
  92        uhci = hcd_to_uhci(hcd);
  93
  94        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  95        hcd->regs = devm_ioremap_resource(&pdev->dev, res);
  96        if (IS_ERR(hcd->regs)) {
  97                ret = PTR_ERR(hcd->regs);
  98                goto err_rmr;
  99        }
 100        hcd->rsrc_start = res->start;
 101        hcd->rsrc_len = resource_size(res);
 102
 103        uhci->regs = hcd->regs;
 104
 105        /* Grab some things from the device-tree */
 106        if (np) {
 107                u32 num_ports;
 108
 109                if (of_property_read_u32(np, "#ports", &num_ports) == 0) {
 110                        uhci->rh_numports = num_ports;
 111                        dev_info(&pdev->dev,
 112                                "Detected %d ports from device-tree\n",
 113                                num_ports);
 114                }
 115                if (of_device_is_compatible(np, "aspeed,ast2400-uhci") ||
 116                    of_device_is_compatible(np, "aspeed,ast2500-uhci")) {
 117                        uhci->is_aspeed = 1;
 118                        dev_info(&pdev->dev,
 119                                 "Enabled Aspeed implementation workarounds\n");
 120                }
 121        }
 122
 123        /* Get and enable clock if any specified */
 124        uhci->clk = devm_clk_get(&pdev->dev, NULL);
 125        if (IS_ERR(uhci->clk)) {
 126                ret = PTR_ERR(uhci->clk);
 127                goto err_rmr;
 128        }
 129        ret = clk_prepare_enable(uhci->clk);
 130        if (ret) {
 131                dev_err(&pdev->dev, "Error couldn't enable clock (%d)\n", ret);
 132                goto err_rmr;
 133        }
 134
 135        ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED);
 136        if (ret)
 137                goto err_clk;
 138
 139        device_wakeup_enable(hcd->self.controller);
 140        return 0;
 141
 142err_clk:
 143        clk_disable_unprepare(uhci->clk);
 144err_rmr:
 145        usb_put_hcd(hcd);
 146
 147        return ret;
 148}
 149
 150static int uhci_hcd_platform_remove(struct platform_device *pdev)
 151{
 152        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 153        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 154
 155        clk_disable_unprepare(uhci->clk);
 156        usb_remove_hcd(hcd);
 157        usb_put_hcd(hcd);
 158
 159        return 0;
 160}
 161
 162/* Make sure the controller is quiescent and that we're not using it
 163 * any more.  This is mainly for the benefit of programs which, like kexec,
 164 * expect the hardware to be idle: not doing DMA or generating IRQs.
 165 *
 166 * This routine may be called in a damaged or failing kernel.  Hence we
 167 * do not acquire the spinlock before shutting down the controller.
 168 */
 169static void uhci_hcd_platform_shutdown(struct platform_device *op)
 170{
 171        struct usb_hcd *hcd = platform_get_drvdata(op);
 172
 173        uhci_hc_died(hcd_to_uhci(hcd));
 174}
 175
 176static const struct of_device_id platform_uhci_ids[] = {
 177        { .compatible = "generic-uhci", },
 178        { .compatible = "platform-uhci", },
 179        {}
 180};
 181MODULE_DEVICE_TABLE(of, platform_uhci_ids);
 182
 183static struct platform_driver uhci_platform_driver = {
 184        .probe          = uhci_hcd_platform_probe,
 185        .remove         = uhci_hcd_platform_remove,
 186        .shutdown       = uhci_hcd_platform_shutdown,
 187        .driver = {
 188                .name = "platform-uhci",
 189                .of_match_table = platform_uhci_ids,
 190        },
 191};
 192