linux/drivers/usb/host/xhci-plat.c
<<
>>
Prefs
   1/*
   2 * xhci-plat.c - xHCI host controller driver platform Bus Glue.
   3 *
   4 * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
   5 * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
   6 *
   7 * A lot of code borrowed from the Linux xHCI driver.
   8 *
   9 * This program is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU General Public License
  11 * version 2 as published by the Free Software Foundation.
  12 */
  13
  14#include <linux/clk.h>
  15#include <linux/dma-mapping.h>
  16#include <linux/module.h>
  17#include <linux/of.h>
  18#include <linux/platform_device.h>
  19#include <linux/usb/phy.h>
  20#include <linux/slab.h>
  21#include <linux/usb/xhci_pdriver.h>
  22
  23#include "xhci.h"
  24
  25static struct hc_driver __read_mostly xhci_plat_hc_driver;
  26
  27static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
  28{
  29        /*
  30         * As of now platform drivers don't provide MSI support so we ensure
  31         * here that the generic code does not try to make a pci_dev from our
  32         * dev struct in order to setup MSI
  33         */
  34        xhci->quirks |= XHCI_PLAT;
  35}
  36
  37/* called during probe() after chip reset completes */
  38static int xhci_plat_setup(struct usb_hcd *hcd)
  39{
  40        return xhci_gen_setup(hcd, xhci_plat_quirks);
  41}
  42
  43static int xhci_plat_start(struct usb_hcd *hcd)
  44{
  45        return xhci_run(hcd);
  46}
  47
  48static int xhci_plat_probe(struct platform_device *pdev)
  49{
  50        struct device_node      *node = pdev->dev.of_node;
  51        struct usb_xhci_pdata   *pdata = dev_get_platdata(&pdev->dev);
  52        const struct hc_driver  *driver;
  53        struct xhci_hcd         *xhci;
  54        struct resource         *res;
  55        struct usb_hcd          *hcd;
  56        struct clk              *clk;
  57        int                     ret;
  58        int                     irq;
  59
  60        if (usb_disabled())
  61                return -ENODEV;
  62
  63        driver = &xhci_plat_hc_driver;
  64
  65        irq = platform_get_irq(pdev, 0);
  66        if (irq < 0)
  67                return -ENODEV;
  68
  69
  70        /* Initialize dma_mask and coherent_dma_mask to 32-bits */
  71        ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
  72        if (ret)
  73                return ret;
  74        if (!pdev->dev.dma_mask)
  75                pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
  76        else
  77                dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
  78
  79        hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
  80        if (!hcd)
  81                return -ENOMEM;
  82
  83        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  84        hcd->regs = devm_ioremap_resource(&pdev->dev, res);
  85        if (IS_ERR(hcd->regs)) {
  86                ret = PTR_ERR(hcd->regs);
  87                goto put_hcd;
  88        }
  89
  90        hcd->rsrc_start = res->start;
  91        hcd->rsrc_len = resource_size(res);
  92
  93        /*
  94         * Not all platforms have a clk so it is not an error if the
  95         * clock does not exists.
  96         */
  97        clk = devm_clk_get(&pdev->dev, NULL);
  98        if (!IS_ERR(clk)) {
  99                ret = clk_prepare_enable(clk);
 100                if (ret)
 101                        goto put_hcd;
 102        }
 103
 104        ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
 105        if (ret)
 106                goto disable_clk;
 107
 108
 109        /* USB 2.0 roothub is stored in the platform_device now. */
 110        hcd = dev_get_drvdata(&pdev->dev);
 111        xhci = hcd_to_xhci(hcd);
 112        xhci->clk = clk;
 113        xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev,
 114                        dev_name(&pdev->dev), hcd);
 115        if (!xhci->shared_hcd) {
 116                ret = -ENOMEM;
 117                goto dealloc_usb2_hcd;
 118        }
 119
 120        if ((node && of_property_read_bool(node, "usb3-lpm-capable")) ||
 121                        (pdata && pdata->usb3_lpm_capable))
 122                xhci->quirks |= XHCI_LPM_SUPPORT;
 123        /*
 124         * Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset)
 125         * is called by usb_add_hcd().
 126         */
 127        *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci;
 128
 129        if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
 130                xhci->shared_hcd->can_do_streams = 1;
 131
 132        hcd->usb_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0);
 133        if (IS_ERR(hcd->usb_phy)) {
 134                ret = PTR_ERR(hcd->usb_phy);
 135                if (ret == -EPROBE_DEFER)
 136                        goto put_usb3_hcd;
 137                hcd->usb_phy = NULL;
 138        } else {
 139                ret = usb_phy_init(hcd->usb_phy);
 140                if (ret)
 141                        goto put_usb3_hcd;
 142        }
 143
 144        ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
 145        if (ret)
 146                goto disable_usb_phy;
 147
 148        return 0;
 149
 150disable_usb_phy:
 151        usb_phy_shutdown(hcd->usb_phy);
 152
 153put_usb3_hcd:
 154        usb_put_hcd(xhci->shared_hcd);
 155
 156dealloc_usb2_hcd:
 157        usb_remove_hcd(hcd);
 158
 159disable_clk:
 160        if (!IS_ERR(clk))
 161                clk_disable_unprepare(clk);
 162
 163put_hcd:
 164        usb_put_hcd(hcd);
 165
 166        return ret;
 167}
 168
 169static int xhci_plat_remove(struct platform_device *dev)
 170{
 171        struct usb_hcd  *hcd = platform_get_drvdata(dev);
 172        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
 173        struct clk *clk = xhci->clk;
 174
 175        usb_remove_hcd(xhci->shared_hcd);
 176        usb_phy_shutdown(hcd->usb_phy);
 177        usb_put_hcd(xhci->shared_hcd);
 178
 179        usb_remove_hcd(hcd);
 180        if (!IS_ERR(clk))
 181                clk_disable_unprepare(clk);
 182        usb_put_hcd(hcd);
 183        kfree(xhci);
 184
 185        return 0;
 186}
 187
 188#ifdef CONFIG_PM_SLEEP
 189static int xhci_plat_suspend(struct device *dev)
 190{
 191        struct usb_hcd  *hcd = dev_get_drvdata(dev);
 192        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
 193
 194        /*
 195         * xhci_suspend() needs `do_wakeup` to know whether host is allowed
 196         * to do wakeup during suspend. Since xhci_plat_suspend is currently
 197         * only designed for system suspend, device_may_wakeup() is enough
 198         * to dertermine whether host is allowed to do wakeup. Need to
 199         * reconsider this when xhci_plat_suspend enlarges its scope, e.g.,
 200         * also applies to runtime suspend.
 201         */
 202        return xhci_suspend(xhci, device_may_wakeup(dev));
 203}
 204
 205static int xhci_plat_resume(struct device *dev)
 206{
 207        struct usb_hcd  *hcd = dev_get_drvdata(dev);
 208        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
 209
 210        return xhci_resume(xhci, 0);
 211}
 212
 213static const struct dev_pm_ops xhci_plat_pm_ops = {
 214        SET_SYSTEM_SLEEP_PM_OPS(xhci_plat_suspend, xhci_plat_resume)
 215};
 216#define DEV_PM_OPS      (&xhci_plat_pm_ops)
 217#else
 218#define DEV_PM_OPS      NULL
 219#endif /* CONFIG_PM */
 220
 221#ifdef CONFIG_OF
 222static const struct of_device_id usb_xhci_of_match[] = {
 223        { .compatible = "generic-xhci" },
 224        { .compatible = "xhci-platform" },
 225        { },
 226};
 227MODULE_DEVICE_TABLE(of, usb_xhci_of_match);
 228#endif
 229
 230static struct platform_driver usb_xhci_driver = {
 231        .probe  = xhci_plat_probe,
 232        .remove = xhci_plat_remove,
 233        .driver = {
 234                .name = "xhci-hcd",
 235                .pm = DEV_PM_OPS,
 236                .of_match_table = of_match_ptr(usb_xhci_of_match),
 237        },
 238};
 239MODULE_ALIAS("platform:xhci-hcd");
 240
 241static int __init xhci_plat_init(void)
 242{
 243        xhci_init_driver(&xhci_plat_hc_driver, xhci_plat_setup);
 244        xhci_plat_hc_driver.start = xhci_plat_start;
 245        return platform_driver_register(&usb_xhci_driver);
 246}
 247module_init(xhci_plat_init);
 248
 249static void __exit xhci_plat_exit(void)
 250{
 251        platform_driver_unregister(&usb_xhci_driver);
 252}
 253module_exit(xhci_plat_exit);
 254
 255MODULE_DESCRIPTION("xHCI Platform Host Controller Driver");
 256MODULE_LICENSE("GPL");
 257