18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * dwc3-of-simple.c - OF glue layer for simple integrations 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2015 Texas Instruments Incorporated - https://www.ti.com 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Felipe Balbi <balbi@ti.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This is a combination of the old dwc3-qcom.c by Ivan T. Ivanov 108c2ecf20Sopenharmony_ci * <iivanov@mm-sol.com> and the original patch adding support for Xilinx' SoC 118c2ecf20Sopenharmony_ci * by Subbaraya Sundeep Bhatta <subbaraya.sundeep.bhatta@xilinx.com> 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 188c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 198c2ecf20Sopenharmony_ci#include <linux/clk.h> 208c2ecf20Sopenharmony_ci#include <linux/of.h> 218c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 228c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 238c2ecf20Sopenharmony_ci#include <linux/reset.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistruct dwc3_of_simple { 268c2ecf20Sopenharmony_ci struct device *dev; 278c2ecf20Sopenharmony_ci struct clk_bulk_data *clks; 288c2ecf20Sopenharmony_ci int num_clocks; 298c2ecf20Sopenharmony_ci struct reset_control *resets; 308c2ecf20Sopenharmony_ci bool need_reset; 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic int dwc3_of_simple_probe(struct platform_device *pdev) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci struct dwc3_of_simple *simple; 368c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 378c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci int ret; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci simple = devm_kzalloc(dev, sizeof(*simple), GFP_KERNEL); 428c2ecf20Sopenharmony_ci if (!simple) 438c2ecf20Sopenharmony_ci return -ENOMEM; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, simple); 468c2ecf20Sopenharmony_ci simple->dev = dev; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* 498c2ecf20Sopenharmony_ci * Some controllers need to toggle the usb3-otg reset before trying to 508c2ecf20Sopenharmony_ci * initialize the PHY, otherwise the PHY times out. 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "rockchip,rk3399-dwc3")) 538c2ecf20Sopenharmony_ci simple->need_reset = true; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci simple->resets = of_reset_control_array_get(np, false, true, 568c2ecf20Sopenharmony_ci true); 578c2ecf20Sopenharmony_ci if (IS_ERR(simple->resets)) { 588c2ecf20Sopenharmony_ci ret = PTR_ERR(simple->resets); 598c2ecf20Sopenharmony_ci dev_err(dev, "failed to get device resets, err=%d\n", ret); 608c2ecf20Sopenharmony_ci return ret; 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci ret = reset_control_deassert(simple->resets); 648c2ecf20Sopenharmony_ci if (ret) 658c2ecf20Sopenharmony_ci goto err_resetc_put; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci ret = clk_bulk_get_all(simple->dev, &simple->clks); 688c2ecf20Sopenharmony_ci if (ret < 0) 698c2ecf20Sopenharmony_ci goto err_resetc_assert; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci simple->num_clocks = ret; 728c2ecf20Sopenharmony_ci ret = clk_bulk_prepare_enable(simple->num_clocks, simple->clks); 738c2ecf20Sopenharmony_ci if (ret) 748c2ecf20Sopenharmony_ci goto err_resetc_assert; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci ret = of_platform_populate(np, NULL, NULL, dev); 778c2ecf20Sopenharmony_ci if (ret) 788c2ecf20Sopenharmony_ci goto err_clk_put; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci pm_runtime_set_active(dev); 818c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 828c2ecf20Sopenharmony_ci pm_runtime_get_sync(dev); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci return 0; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cierr_clk_put: 878c2ecf20Sopenharmony_ci clk_bulk_disable_unprepare(simple->num_clocks, simple->clks); 888c2ecf20Sopenharmony_ci clk_bulk_put_all(simple->num_clocks, simple->clks); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cierr_resetc_assert: 918c2ecf20Sopenharmony_ci reset_control_assert(simple->resets); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cierr_resetc_put: 948c2ecf20Sopenharmony_ci reset_control_put(simple->resets); 958c2ecf20Sopenharmony_ci return ret; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic void __dwc3_of_simple_teardown(struct dwc3_of_simple *simple) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci of_platform_depopulate(simple->dev); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci clk_bulk_disable_unprepare(simple->num_clocks, simple->clks); 1038c2ecf20Sopenharmony_ci clk_bulk_put_all(simple->num_clocks, simple->clks); 1048c2ecf20Sopenharmony_ci simple->num_clocks = 0; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci reset_control_assert(simple->resets); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci reset_control_put(simple->resets); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci pm_runtime_disable(simple->dev); 1118c2ecf20Sopenharmony_ci pm_runtime_put_noidle(simple->dev); 1128c2ecf20Sopenharmony_ci pm_runtime_set_suspended(simple->dev); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic int dwc3_of_simple_remove(struct platform_device *pdev) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct dwc3_of_simple *simple = platform_get_drvdata(pdev); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci __dwc3_of_simple_teardown(simple); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci return 0; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic void dwc3_of_simple_shutdown(struct platform_device *pdev) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci struct dwc3_of_simple *simple = platform_get_drvdata(pdev); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci __dwc3_of_simple_teardown(simple); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic int __maybe_unused dwc3_of_simple_runtime_suspend(struct device *dev) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct dwc3_of_simple *simple = dev_get_drvdata(dev); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci clk_bulk_disable(simple->num_clocks, simple->clks); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci return 0; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic int __maybe_unused dwc3_of_simple_runtime_resume(struct device *dev) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci struct dwc3_of_simple *simple = dev_get_drvdata(dev); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return clk_bulk_enable(simple->num_clocks, simple->clks); 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic int __maybe_unused dwc3_of_simple_suspend(struct device *dev) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct dwc3_of_simple *simple = dev_get_drvdata(dev); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (simple->need_reset) 1528c2ecf20Sopenharmony_ci reset_control_assert(simple->resets); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return 0; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic int __maybe_unused dwc3_of_simple_resume(struct device *dev) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci struct dwc3_of_simple *simple = dev_get_drvdata(dev); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (simple->need_reset) 1628c2ecf20Sopenharmony_ci reset_control_deassert(simple->resets); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci return 0; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic const struct dev_pm_ops dwc3_of_simple_dev_pm_ops = { 1688c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(dwc3_of_simple_suspend, dwc3_of_simple_resume) 1698c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(dwc3_of_simple_runtime_suspend, 1708c2ecf20Sopenharmony_ci dwc3_of_simple_runtime_resume, NULL) 1718c2ecf20Sopenharmony_ci}; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic const struct of_device_id of_dwc3_simple_match[] = { 1748c2ecf20Sopenharmony_ci { .compatible = "rockchip,rk3399-dwc3" }, 1758c2ecf20Sopenharmony_ci { .compatible = "xlnx,zynqmp-dwc3" }, 1768c2ecf20Sopenharmony_ci { .compatible = "cavium,octeon-7130-usb-uctl" }, 1778c2ecf20Sopenharmony_ci { .compatible = "sprd,sc9860-dwc3" }, 1788c2ecf20Sopenharmony_ci { .compatible = "allwinner,sun50i-h6-dwc3" }, 1798c2ecf20Sopenharmony_ci { .compatible = "hisilicon,hi3670-dwc3" }, 1808c2ecf20Sopenharmony_ci { .compatible = "intel,keembay-dwc3" }, 1818c2ecf20Sopenharmony_ci { /* Sentinel */ } 1828c2ecf20Sopenharmony_ci}; 1838c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_dwc3_simple_match); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic struct platform_driver dwc3_of_simple_driver = { 1868c2ecf20Sopenharmony_ci .probe = dwc3_of_simple_probe, 1878c2ecf20Sopenharmony_ci .remove = dwc3_of_simple_remove, 1888c2ecf20Sopenharmony_ci .shutdown = dwc3_of_simple_shutdown, 1898c2ecf20Sopenharmony_ci .driver = { 1908c2ecf20Sopenharmony_ci .name = "dwc3-of-simple", 1918c2ecf20Sopenharmony_ci .of_match_table = of_dwc3_simple_match, 1928c2ecf20Sopenharmony_ci .pm = &dwc3_of_simple_dev_pm_ops, 1938c2ecf20Sopenharmony_ci }, 1948c2ecf20Sopenharmony_ci}; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cimodule_platform_driver(dwc3_of_simple_driver); 1978c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1988c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DesignWare USB3 OF Simple Glue Layer"); 1998c2ecf20Sopenharmony_ciMODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); 200