linux/drivers/usb/dwc3/host.c
<<
>>
Prefs
   1/**
   2 * host.c - DesignWare USB3 DRD Controller Host Glue
   3 *
   4 * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com
   5 *
   6 * Authors: Felipe Balbi <balbi@ti.com>,
   7 *
   8 * This program is free software: you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2  of
  10 * the License as published by the Free Software Foundation.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 */
  17
  18#include <linux/platform_device.h>
  19
  20#include "core.h"
  21
  22int dwc3_host_init(struct dwc3 *dwc)
  23{
  24        struct property_entry   props[2];
  25        struct platform_device  *xhci;
  26        int                     ret, irq;
  27        struct resource         *res;
  28        struct platform_device  *dwc3_pdev = to_platform_device(dwc->dev);
  29
  30        irq = platform_get_irq_byname(dwc3_pdev, "host");
  31        if (irq == -EPROBE_DEFER)
  32                return irq;
  33
  34        if (irq <= 0) {
  35                irq = platform_get_irq_byname(dwc3_pdev, "dwc_usb3");
  36                if (irq == -EPROBE_DEFER)
  37                        return irq;
  38
  39                if (irq <= 0) {
  40                        irq = platform_get_irq(dwc3_pdev, 0);
  41                        if (irq <= 0) {
  42                                if (irq != -EPROBE_DEFER) {
  43                                        dev_err(dwc->dev,
  44                                                "missing host IRQ\n");
  45                                }
  46                                if (!irq)
  47                                        irq = -EINVAL;
  48                                return irq;
  49                        } else {
  50                                res = platform_get_resource(dwc3_pdev,
  51                                                            IORESOURCE_IRQ, 0);
  52                        }
  53                } else {
  54                        res = platform_get_resource_byname(dwc3_pdev,
  55                                                           IORESOURCE_IRQ,
  56                                                           "dwc_usb3");
  57                }
  58
  59        } else {
  60                res = platform_get_resource_byname(dwc3_pdev, IORESOURCE_IRQ,
  61                                                   "host");
  62        }
  63
  64        dwc->xhci_resources[1].start = irq;
  65        dwc->xhci_resources[1].end = irq;
  66        dwc->xhci_resources[1].flags = res->flags;
  67        dwc->xhci_resources[1].name = res->name;
  68
  69        xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
  70        if (!xhci) {
  71                dev_err(dwc->dev, "couldn't allocate xHCI device\n");
  72                return -ENOMEM;
  73        }
  74
  75        dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask);
  76
  77        xhci->dev.parent        = dwc->dev;
  78        xhci->dev.dma_mask      = dwc->dev->dma_mask;
  79        xhci->dev.dma_parms     = dwc->dev->dma_parms;
  80        xhci->dev.archdata      = dwc->dev->archdata;
  81
  82        dwc->xhci = xhci;
  83
  84        ret = platform_device_add_resources(xhci, dwc->xhci_resources,
  85                                                DWC3_XHCI_RESOURCES_NUM);
  86        if (ret) {
  87                dev_err(dwc->dev, "couldn't add resources to xHCI device\n");
  88                goto err1;
  89        }
  90
  91        memset(props, 0, sizeof(struct property_entry) * ARRAY_SIZE(props));
  92
  93        if (dwc->usb3_lpm_capable) {
  94                props[0].name = "usb3-lpm-capable";
  95                ret = platform_device_add_properties(xhci, props);
  96                if (ret) {
  97                        dev_err(dwc->dev, "failed to add properties to xHCI\n");
  98                        goto err1;
  99                }
 100        }
 101
 102        phy_create_lookup(dwc->usb2_generic_phy, "usb2-phy",
 103                          dev_name(&xhci->dev));
 104        phy_create_lookup(dwc->usb3_generic_phy, "usb3-phy",
 105                          dev_name(&xhci->dev));
 106
 107        if (dwc->dr_mode == USB_DR_MODE_OTG) {
 108                struct usb_phy *phy;
 109                phy = usb_get_phy(USB_PHY_TYPE_USB3);
 110                if (!IS_ERR(phy)) {
 111                        if (phy && phy->otg)
 112                                otg_set_host(phy->otg,
 113                                                (struct usb_bus *)(long)1);
 114                        usb_put_phy(phy);
 115                }
 116        }
 117
 118        ret = platform_device_add(xhci);
 119        if (ret) {
 120                dev_err(dwc->dev, "failed to register xHCI device\n");
 121                goto err2;
 122        }
 123
 124        return 0;
 125err2:
 126        phy_remove_lookup(dwc->usb2_generic_phy, "usb2-phy",
 127                          dev_name(&xhci->dev));
 128        phy_remove_lookup(dwc->usb3_generic_phy, "usb3-phy",
 129                          dev_name(&xhci->dev));
 130err1:
 131        platform_device_put(xhci);
 132        return ret;
 133}
 134
 135void dwc3_host_exit(struct dwc3 *dwc)
 136{
 137        phy_remove_lookup(dwc->usb2_generic_phy, "usb2-phy",
 138                          dev_name(&dwc->xhci->dev));
 139        phy_remove_lookup(dwc->usb3_generic_phy, "usb3-phy",
 140                          dev_name(&dwc->xhci->dev));
 141        platform_device_unregister(dwc->xhci);
 142}
 143