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