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 22 static int dwc3_host_get_irq(struct dwc3 *dwc) 23 { 24 struct platform_device *dwc3_pdev = to_platform_device(dwc->dev); 25 int irq; 26 27 irq = platform_get_irq_byname(dwc3_pdev, "host"); 28 if (irq > 0) 29 goto out; 30 31 if (irq == -EPROBE_DEFER) 32 goto out; 33 34 irq = platform_get_irq_byname(dwc3_pdev, "dwc_usb3"); 35 if (irq > 0) 36 goto out; 37 38 if (irq == -EPROBE_DEFER) 39 goto out; 40 41 irq = platform_get_irq(dwc3_pdev, 0); 42 if (irq > 0) 43 goto out; 44 45 if (irq != -EPROBE_DEFER) 46 dev_err(dwc->dev, "missing host IRQ\n"); 47 48 if (!irq) 49 irq = -EINVAL; 50 51 out: 52 return irq; 53 } 54 55 int dwc3_host_init(struct dwc3 *dwc) 56 { 57 struct property_entry props[2]; 58 struct platform_device *xhci; 59 int ret, irq; 60 struct resource *res; 61 struct platform_device *dwc3_pdev = to_platform_device(dwc->dev); 62 63 irq = dwc3_host_get_irq(dwc); 64 if (irq < 0) 65 return irq; 66 67 res = platform_get_resource_byname(dwc3_pdev, IORESOURCE_IRQ, "host"); 68 if (!res) 69 res = platform_get_resource_byname(dwc3_pdev, IORESOURCE_IRQ, 70 "dwc_usb3"); 71 if (!res) 72 res = platform_get_resource(dwc3_pdev, IORESOURCE_IRQ, 0); 73 if (!res) 74 return -ENOMEM; 75 76 dwc->xhci_resources[1].start = irq; 77 dwc->xhci_resources[1].end = irq; 78 dwc->xhci_resources[1].flags = res->flags; 79 dwc->xhci_resources[1].name = res->name; 80 81 xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO); 82 if (!xhci) { 83 dev_err(dwc->dev, "couldn't allocate xHCI device\n"); 84 return -ENOMEM; 85 } 86 87 xhci->dev.parent = dwc->dev; 88 89 dwc->xhci = xhci; 90 91 ret = platform_device_add_resources(xhci, dwc->xhci_resources, 92 DWC3_XHCI_RESOURCES_NUM); 93 if (ret) { 94 dev_err(dwc->dev, "couldn't add resources to xHCI device\n"); 95 goto err1; 96 } 97 98 memset(props, 0, sizeof(struct property_entry) * ARRAY_SIZE(props)); 99 100 if (dwc->usb3_lpm_capable) { 101 props[0].name = "usb3-lpm-capable"; 102 ret = platform_device_add_properties(xhci, props); 103 if (ret) { 104 dev_err(dwc->dev, "failed to add properties to xHCI\n"); 105 goto err1; 106 } 107 } 108 109 phy_create_lookup(dwc->usb2_generic_phy, "usb2-phy", 110 dev_name(dwc->dev)); 111 phy_create_lookup(dwc->usb3_generic_phy, "usb3-phy", 112 dev_name(dwc->dev)); 113 114 ret = platform_device_add(xhci); 115 if (ret) { 116 dev_err(dwc->dev, "failed to register xHCI device\n"); 117 goto err2; 118 } 119 120 return 0; 121 err2: 122 phy_remove_lookup(dwc->usb2_generic_phy, "usb2-phy", 123 dev_name(dwc->dev)); 124 phy_remove_lookup(dwc->usb3_generic_phy, "usb3-phy", 125 dev_name(dwc->dev)); 126 err1: 127 platform_device_put(xhci); 128 return ret; 129 } 130 131 void dwc3_host_exit(struct dwc3 *dwc) 132 { 133 phy_remove_lookup(dwc->usb2_generic_phy, "usb2-phy", 134 dev_name(dwc->dev)); 135 phy_remove_lookup(dwc->usb3_generic_phy, "usb3-phy", 136 dev_name(dwc->dev)); 137 platform_device_unregister(dwc->xhci); 138 } 139