0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <linux/module.h>
0016 #include <linux/irq.h>
0017 #include <linux/kernel.h>
0018 #include <linux/platform_device.h>
0019 #include <linux/pm_runtime.h>
0020
0021 #include "core.h"
0022 #include "gadget-export.h"
0023 #include "drd.h"
0024
0025 static int set_phy_power_on(struct cdns *cdns)
0026 {
0027 int ret;
0028
0029 ret = phy_power_on(cdns->usb2_phy);
0030 if (ret)
0031 return ret;
0032
0033 ret = phy_power_on(cdns->usb3_phy);
0034 if (ret)
0035 phy_power_off(cdns->usb2_phy);
0036
0037 return ret;
0038 }
0039
0040 static void set_phy_power_off(struct cdns *cdns)
0041 {
0042 phy_power_off(cdns->usb3_phy);
0043 phy_power_off(cdns->usb2_phy);
0044 }
0045
0046
0047
0048
0049
0050
0051
0052 static int cdns3_plat_probe(struct platform_device *pdev)
0053 {
0054 struct device *dev = &pdev->dev;
0055 struct resource *res;
0056 struct cdns *cdns;
0057 void __iomem *regs;
0058 int ret;
0059
0060 cdns = devm_kzalloc(dev, sizeof(*cdns), GFP_KERNEL);
0061 if (!cdns)
0062 return -ENOMEM;
0063
0064 cdns->dev = dev;
0065 cdns->pdata = dev_get_platdata(dev);
0066
0067 platform_set_drvdata(pdev, cdns);
0068
0069 ret = platform_get_irq_byname(pdev, "host");
0070 if (ret < 0)
0071 return ret;
0072
0073 cdns->xhci_res[0].start = ret;
0074 cdns->xhci_res[0].end = ret;
0075 cdns->xhci_res[0].flags = IORESOURCE_IRQ | irq_get_trigger_type(ret);
0076 cdns->xhci_res[0].name = "host";
0077
0078 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "xhci");
0079 if (!res) {
0080 dev_err(dev, "couldn't get xhci resource\n");
0081 return -ENXIO;
0082 }
0083
0084 cdns->xhci_res[1] = *res;
0085
0086 cdns->dev_irq = platform_get_irq_byname(pdev, "peripheral");
0087
0088 if (cdns->dev_irq < 0)
0089 return cdns->dev_irq;
0090
0091 regs = devm_platform_ioremap_resource_byname(pdev, "dev");
0092 if (IS_ERR(regs))
0093 return PTR_ERR(regs);
0094 cdns->dev_regs = regs;
0095
0096 cdns->otg_irq = platform_get_irq_byname(pdev, "otg");
0097 if (cdns->otg_irq < 0)
0098 return cdns->otg_irq;
0099
0100 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "otg");
0101 if (!res) {
0102 dev_err(dev, "couldn't get otg resource\n");
0103 return -ENXIO;
0104 }
0105
0106 cdns->phyrst_a_enable = device_property_read_bool(dev, "cdns,phyrst-a-enable");
0107
0108 cdns->otg_res = *res;
0109
0110 cdns->wakeup_irq = platform_get_irq_byname_optional(pdev, "wakeup");
0111 if (cdns->wakeup_irq == -EPROBE_DEFER)
0112 return cdns->wakeup_irq;
0113 else if (cdns->wakeup_irq == 0)
0114 return -EINVAL;
0115
0116 if (cdns->wakeup_irq < 0) {
0117 dev_dbg(dev, "couldn't get wakeup irq\n");
0118 cdns->wakeup_irq = 0x0;
0119 }
0120
0121 cdns->usb2_phy = devm_phy_optional_get(dev, "cdns3,usb2-phy");
0122 if (IS_ERR(cdns->usb2_phy))
0123 return PTR_ERR(cdns->usb2_phy);
0124
0125 ret = phy_init(cdns->usb2_phy);
0126 if (ret)
0127 return ret;
0128
0129 cdns->usb3_phy = devm_phy_optional_get(dev, "cdns3,usb3-phy");
0130 if (IS_ERR(cdns->usb3_phy))
0131 return PTR_ERR(cdns->usb3_phy);
0132
0133 ret = phy_init(cdns->usb3_phy);
0134 if (ret)
0135 goto err_phy3_init;
0136
0137 ret = set_phy_power_on(cdns);
0138 if (ret)
0139 goto err_phy_power_on;
0140
0141 cdns->gadget_init = cdns3_gadget_init;
0142
0143 ret = cdns_init(cdns);
0144 if (ret)
0145 goto err_cdns_init;
0146
0147 device_set_wakeup_capable(dev, true);
0148 pm_runtime_set_active(dev);
0149 pm_runtime_enable(dev);
0150 if (!(cdns->pdata && (cdns->pdata->quirks & CDNS3_DEFAULT_PM_RUNTIME_ALLOW)))
0151 pm_runtime_forbid(dev);
0152
0153
0154
0155
0156
0157
0158 pm_runtime_set_autosuspend_delay(dev, 20);
0159 pm_runtime_mark_last_busy(dev);
0160 pm_runtime_use_autosuspend(dev);
0161
0162 return 0;
0163
0164 err_cdns_init:
0165 set_phy_power_off(cdns);
0166 err_phy_power_on:
0167 phy_exit(cdns->usb3_phy);
0168 err_phy3_init:
0169 phy_exit(cdns->usb2_phy);
0170
0171 return ret;
0172 }
0173
0174
0175
0176
0177
0178
0179
0180 static int cdns3_plat_remove(struct platform_device *pdev)
0181 {
0182 struct cdns *cdns = platform_get_drvdata(pdev);
0183 struct device *dev = cdns->dev;
0184
0185 pm_runtime_get_sync(dev);
0186 pm_runtime_disable(dev);
0187 pm_runtime_put_noidle(dev);
0188 cdns_remove(cdns);
0189 set_phy_power_off(cdns);
0190 phy_exit(cdns->usb2_phy);
0191 phy_exit(cdns->usb3_phy);
0192 return 0;
0193 }
0194
0195 #ifdef CONFIG_PM
0196
0197 static int cdns3_set_platform_suspend(struct device *dev,
0198 bool suspend, bool wakeup)
0199 {
0200 struct cdns *cdns = dev_get_drvdata(dev);
0201 int ret = 0;
0202
0203 if (cdns->pdata && cdns->pdata->platform_suspend)
0204 ret = cdns->pdata->platform_suspend(dev, suspend, wakeup);
0205
0206 return ret;
0207 }
0208
0209 static int cdns3_controller_suspend(struct device *dev, pm_message_t msg)
0210 {
0211 struct cdns *cdns = dev_get_drvdata(dev);
0212 bool wakeup;
0213 unsigned long flags;
0214
0215 if (cdns->in_lpm)
0216 return 0;
0217
0218 if (PMSG_IS_AUTO(msg))
0219 wakeup = true;
0220 else
0221 wakeup = device_may_wakeup(dev);
0222
0223 cdns3_set_platform_suspend(cdns->dev, true, wakeup);
0224 set_phy_power_off(cdns);
0225 spin_lock_irqsave(&cdns->lock, flags);
0226 cdns->in_lpm = true;
0227 spin_unlock_irqrestore(&cdns->lock, flags);
0228 dev_dbg(cdns->dev, "%s ends\n", __func__);
0229
0230 return 0;
0231 }
0232
0233 static int cdns3_controller_resume(struct device *dev, pm_message_t msg)
0234 {
0235 struct cdns *cdns = dev_get_drvdata(dev);
0236 int ret;
0237 unsigned long flags;
0238
0239 if (!cdns->in_lpm)
0240 return 0;
0241
0242 if (cdns_power_is_lost(cdns)) {
0243 phy_exit(cdns->usb2_phy);
0244 ret = phy_init(cdns->usb2_phy);
0245 if (ret)
0246 return ret;
0247
0248 phy_exit(cdns->usb3_phy);
0249 ret = phy_init(cdns->usb3_phy);
0250 if (ret)
0251 return ret;
0252 }
0253
0254 ret = set_phy_power_on(cdns);
0255 if (ret)
0256 return ret;
0257
0258 cdns3_set_platform_suspend(cdns->dev, false, false);
0259
0260 spin_lock_irqsave(&cdns->lock, flags);
0261 cdns_resume(cdns, !PMSG_IS_AUTO(msg));
0262 cdns->in_lpm = false;
0263 spin_unlock_irqrestore(&cdns->lock, flags);
0264 if (cdns->wakeup_pending) {
0265 cdns->wakeup_pending = false;
0266 enable_irq(cdns->wakeup_irq);
0267 }
0268 dev_dbg(cdns->dev, "%s ends\n", __func__);
0269
0270 return ret;
0271 }
0272
0273 static int cdns3_plat_runtime_suspend(struct device *dev)
0274 {
0275 return cdns3_controller_suspend(dev, PMSG_AUTO_SUSPEND);
0276 }
0277
0278 static int cdns3_plat_runtime_resume(struct device *dev)
0279 {
0280 return cdns3_controller_resume(dev, PMSG_AUTO_RESUME);
0281 }
0282
0283 #ifdef CONFIG_PM_SLEEP
0284
0285 static int cdns3_plat_suspend(struct device *dev)
0286 {
0287 struct cdns *cdns = dev_get_drvdata(dev);
0288 int ret;
0289
0290 cdns_suspend(cdns);
0291
0292 ret = cdns3_controller_suspend(dev, PMSG_SUSPEND);
0293 if (ret)
0294 return ret;
0295
0296 if (device_may_wakeup(dev) && cdns->wakeup_irq)
0297 enable_irq_wake(cdns->wakeup_irq);
0298
0299 return ret;
0300 }
0301
0302 static int cdns3_plat_resume(struct device *dev)
0303 {
0304 return cdns3_controller_resume(dev, PMSG_RESUME);
0305 }
0306 #endif
0307 #endif
0308
0309 static const struct dev_pm_ops cdns3_pm_ops = {
0310 SET_SYSTEM_SLEEP_PM_OPS(cdns3_plat_suspend, cdns3_plat_resume)
0311 SET_RUNTIME_PM_OPS(cdns3_plat_runtime_suspend,
0312 cdns3_plat_runtime_resume, NULL)
0313 };
0314
0315 #ifdef CONFIG_OF
0316 static const struct of_device_id of_cdns3_match[] = {
0317 { .compatible = "cdns,usb3" },
0318 { },
0319 };
0320 MODULE_DEVICE_TABLE(of, of_cdns3_match);
0321 #endif
0322
0323 static struct platform_driver cdns3_driver = {
0324 .probe = cdns3_plat_probe,
0325 .remove = cdns3_plat_remove,
0326 .driver = {
0327 .name = "cdns-usb3",
0328 .of_match_table = of_match_ptr(of_cdns3_match),
0329 .pm = &cdns3_pm_ops,
0330 },
0331 };
0332
0333 module_platform_driver(cdns3_driver);
0334
0335 MODULE_ALIAS("platform:cdns3");
0336 MODULE_AUTHOR("Pawel Laszczak <pawell@cadence.com>");
0337 MODULE_LICENSE("GPL v2");
0338 MODULE_DESCRIPTION("Cadence USB3 DRD Controller Driver");