1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Cadence USBSS DRD Driver. 4 * 5 * Copyright (C) 2018-2020 Cadence. 6 * Copyright (C) 2017-2018 NXP 7 * Copyright (C) 2019 Texas Instruments 8 * 9 * 10 * Author: Peter Chen <peter.chen@nxp.com> 11 * Pawel Laszczak <pawell@cadence.com> 12 * Roger Quadros <rogerq@ti.com> 13 */ 14 15 #include <linux/module.h> 16 #include <linux/irq.h> 17 #include <linux/kernel.h> 18 #include <linux/of.h> 19 #include <linux/platform_device.h> 20 #include <linux/pm_runtime.h> 21 22 #include "core.h" 23 #include "gadget-export.h" 24 #include "drd.h" 25 26 static int set_phy_power_on(struct cdns *cdns) 27 { 28 int ret; 29 30 ret = phy_power_on(cdns->usb2_phy); 31 if (ret) 32 return ret; 33 34 ret = phy_power_on(cdns->usb3_phy); 35 if (ret) 36 phy_power_off(cdns->usb2_phy); 37 38 return ret; 39 } 40 41 static void set_phy_power_off(struct cdns *cdns) 42 { 43 phy_power_off(cdns->usb3_phy); 44 phy_power_off(cdns->usb2_phy); 45 } 46 47 /** 48 * cdns3_plat_probe - probe for cdns3 core device 49 * @pdev: Pointer to cdns3 core platform device 50 * 51 * Returns 0 on success otherwise negative errno 52 */ 53 static int cdns3_plat_probe(struct platform_device *pdev) 54 { 55 struct device *dev = &pdev->dev; 56 struct resource *res; 57 struct cdns *cdns; 58 void __iomem *regs; 59 int ret; 60 61 cdns = devm_kzalloc(dev, sizeof(*cdns), GFP_KERNEL); 62 if (!cdns) 63 return -ENOMEM; 64 65 cdns->dev = dev; 66 cdns->pdata = dev_get_platdata(dev); 67 68 platform_set_drvdata(pdev, cdns); 69 70 ret = platform_get_irq_byname(pdev, "host"); 71 if (ret < 0) 72 return ret; 73 74 cdns->xhci_res[0].start = ret; 75 cdns->xhci_res[0].end = ret; 76 cdns->xhci_res[0].flags = IORESOURCE_IRQ | irq_get_trigger_type(ret); 77 cdns->xhci_res[0].name = "host"; 78 79 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "xhci"); 80 if (!res) { 81 dev_err(dev, "couldn't get xhci resource\n"); 82 return -ENXIO; 83 } 84 85 cdns->xhci_res[1] = *res; 86 87 cdns->dev_irq = platform_get_irq_byname(pdev, "peripheral"); 88 89 if (cdns->dev_irq < 0) 90 return dev_err_probe(dev, cdns->dev_irq, 91 "Failed to get peripheral IRQ\n"); 92 93 regs = devm_platform_ioremap_resource_byname(pdev, "dev"); 94 if (IS_ERR(regs)) 95 return dev_err_probe(dev, PTR_ERR(regs), 96 "Failed to get dev base\n"); 97 98 cdns->dev_regs = regs; 99 100 cdns->otg_irq = platform_get_irq_byname(pdev, "otg"); 101 if (cdns->otg_irq < 0) 102 return dev_err_probe(dev, cdns->otg_irq, 103 "Failed to get otg IRQ\n"); 104 105 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "otg"); 106 if (!res) { 107 dev_err(dev, "couldn't get otg resource\n"); 108 return -ENXIO; 109 } 110 111 cdns->phyrst_a_enable = device_property_read_bool(dev, "cdns,phyrst-a-enable"); 112 113 cdns->otg_res = *res; 114 115 cdns->wakeup_irq = platform_get_irq_byname_optional(pdev, "wakeup"); 116 if (cdns->wakeup_irq == -EPROBE_DEFER) 117 return cdns->wakeup_irq; 118 119 if (cdns->wakeup_irq < 0) { 120 dev_dbg(dev, "couldn't get wakeup irq\n"); 121 cdns->wakeup_irq = 0x0; 122 } 123 124 cdns->usb2_phy = devm_phy_optional_get(dev, "cdns3,usb2-phy"); 125 if (IS_ERR(cdns->usb2_phy)) 126 return dev_err_probe(dev, PTR_ERR(cdns->usb2_phy), 127 "Failed to get cdn3,usb2-phy\n"); 128 129 cdns->usb3_phy = devm_phy_optional_get(dev, "cdns3,usb3-phy"); 130 if (IS_ERR(cdns->usb3_phy)) 131 return dev_err_probe(dev, PTR_ERR(cdns->usb3_phy), 132 "Failed to get cdn3,usb3-phy\n"); 133 134 ret = phy_init(cdns->usb2_phy); 135 if (ret) 136 return ret; 137 138 ret = phy_init(cdns->usb3_phy); 139 if (ret) 140 goto err_phy3_init; 141 142 ret = set_phy_power_on(cdns); 143 if (ret) 144 goto err_phy_power_on; 145 146 cdns->gadget_init = cdns3_gadget_init; 147 148 ret = cdns_init(cdns); 149 if (ret) 150 goto err_cdns_init; 151 152 device_set_wakeup_capable(dev, true); 153 pm_runtime_set_active(dev); 154 pm_runtime_enable(dev); 155 if (!(cdns->pdata && (cdns->pdata->quirks & CDNS3_DEFAULT_PM_RUNTIME_ALLOW))) 156 pm_runtime_forbid(dev); 157 158 /* 159 * The controller needs less time between bus and controller suspend, 160 * and we also needs a small delay to avoid frequently entering low 161 * power mode. 162 */ 163 pm_runtime_set_autosuspend_delay(dev, 20); 164 pm_runtime_mark_last_busy(dev); 165 pm_runtime_use_autosuspend(dev); 166 167 return 0; 168 169 err_cdns_init: 170 set_phy_power_off(cdns); 171 err_phy_power_on: 172 phy_exit(cdns->usb3_phy); 173 err_phy3_init: 174 phy_exit(cdns->usb2_phy); 175 176 return ret; 177 } 178 179 /** 180 * cdns3_plat_remove() - unbind drd driver and clean up 181 * @pdev: Pointer to Linux platform device 182 */ 183 static void cdns3_plat_remove(struct platform_device *pdev) 184 { 185 struct cdns *cdns = platform_get_drvdata(pdev); 186 struct device *dev = cdns->dev; 187 188 pm_runtime_get_sync(dev); 189 if (!(cdns->pdata && (cdns->pdata->quirks & CDNS3_DEFAULT_PM_RUNTIME_ALLOW))) 190 pm_runtime_allow(dev); 191 192 pm_runtime_disable(dev); 193 pm_runtime_put_noidle(dev); 194 cdns_remove(cdns); 195 set_phy_power_off(cdns); 196 phy_exit(cdns->usb2_phy); 197 phy_exit(cdns->usb3_phy); 198 } 199 200 #ifdef CONFIG_PM 201 202 static int cdns3_set_platform_suspend(struct device *dev, 203 bool suspend, bool wakeup) 204 { 205 struct cdns *cdns = dev_get_drvdata(dev); 206 int ret = 0; 207 208 if (cdns->pdata && cdns->pdata->platform_suspend) 209 ret = cdns->pdata->platform_suspend(dev, suspend, wakeup); 210 211 return ret; 212 } 213 214 static int cdns3_controller_suspend(struct device *dev, pm_message_t msg) 215 { 216 struct cdns *cdns = dev_get_drvdata(dev); 217 bool wakeup; 218 unsigned long flags; 219 220 if (cdns->in_lpm) 221 return 0; 222 223 if (PMSG_IS_AUTO(msg)) 224 wakeup = true; 225 else 226 wakeup = device_may_wakeup(dev); 227 228 cdns3_set_platform_suspend(cdns->dev, true, wakeup); 229 set_phy_power_off(cdns); 230 spin_lock_irqsave(&cdns->lock, flags); 231 cdns->in_lpm = true; 232 spin_unlock_irqrestore(&cdns->lock, flags); 233 dev_dbg(cdns->dev, "%s ends\n", __func__); 234 235 return 0; 236 } 237 238 static int cdns3_controller_resume(struct device *dev, pm_message_t msg) 239 { 240 struct cdns *cdns = dev_get_drvdata(dev); 241 int ret; 242 unsigned long flags; 243 244 if (!cdns->in_lpm) 245 return 0; 246 247 if (cdns_power_is_lost(cdns)) { 248 phy_exit(cdns->usb2_phy); 249 ret = phy_init(cdns->usb2_phy); 250 if (ret) 251 return ret; 252 253 phy_exit(cdns->usb3_phy); 254 ret = phy_init(cdns->usb3_phy); 255 if (ret) 256 return ret; 257 } 258 259 ret = set_phy_power_on(cdns); 260 if (ret) 261 return ret; 262 263 cdns3_set_platform_suspend(cdns->dev, false, false); 264 265 spin_lock_irqsave(&cdns->lock, flags); 266 cdns_resume(cdns); 267 cdns->in_lpm = false; 268 spin_unlock_irqrestore(&cdns->lock, flags); 269 cdns_set_active(cdns, !PMSG_IS_AUTO(msg)); 270 if (cdns->wakeup_pending) { 271 cdns->wakeup_pending = false; 272 enable_irq(cdns->wakeup_irq); 273 } 274 dev_dbg(cdns->dev, "%s ends\n", __func__); 275 276 return ret; 277 } 278 279 static int cdns3_plat_runtime_suspend(struct device *dev) 280 { 281 return cdns3_controller_suspend(dev, PMSG_AUTO_SUSPEND); 282 } 283 284 static int cdns3_plat_runtime_resume(struct device *dev) 285 { 286 return cdns3_controller_resume(dev, PMSG_AUTO_RESUME); 287 } 288 289 #ifdef CONFIG_PM_SLEEP 290 291 static int cdns3_plat_suspend(struct device *dev) 292 { 293 struct cdns *cdns = dev_get_drvdata(dev); 294 int ret; 295 296 cdns_suspend(cdns); 297 298 ret = cdns3_controller_suspend(dev, PMSG_SUSPEND); 299 if (ret) 300 return ret; 301 302 if (device_may_wakeup(dev) && cdns->wakeup_irq) 303 enable_irq_wake(cdns->wakeup_irq); 304 305 return ret; 306 } 307 308 static int cdns3_plat_resume(struct device *dev) 309 { 310 return cdns3_controller_resume(dev, PMSG_RESUME); 311 } 312 #endif /* CONFIG_PM_SLEEP */ 313 #endif /* CONFIG_PM */ 314 315 static const struct dev_pm_ops cdns3_pm_ops = { 316 SET_SYSTEM_SLEEP_PM_OPS(cdns3_plat_suspend, cdns3_plat_resume) 317 SET_RUNTIME_PM_OPS(cdns3_plat_runtime_suspend, 318 cdns3_plat_runtime_resume, NULL) 319 }; 320 321 #ifdef CONFIG_OF 322 static const struct of_device_id of_cdns3_match[] = { 323 { .compatible = "cdns,usb3" }, 324 { }, 325 }; 326 MODULE_DEVICE_TABLE(of, of_cdns3_match); 327 #endif 328 329 static struct platform_driver cdns3_driver = { 330 .probe = cdns3_plat_probe, 331 .remove = cdns3_plat_remove, 332 .driver = { 333 .name = "cdns-usb3", 334 .of_match_table = of_match_ptr(of_cdns3_match), 335 .pm = &cdns3_pm_ops, 336 }, 337 }; 338 339 module_platform_driver(cdns3_driver); 340 341 MODULE_ALIAS("platform:cdns3"); 342 MODULE_AUTHOR("Pawel Laszczak <pawell@cadence.com>"); 343 MODULE_LICENSE("GPL v2"); 344 MODULE_DESCRIPTION("Cadence USB3 DRD Controller Driver"); 345