18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2016 MediaTek Inc. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Chunfeng Yun <chunfeng.yun@mediatek.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/clk.h> 98c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 108c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/of_address.h> 148c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "mtu3.h" 188c2ecf20Sopenharmony_ci#include "mtu3_dr.h" 198c2ecf20Sopenharmony_ci#include "mtu3_debug.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* u2-port0 should be powered on and enabled; */ 228c2ecf20Sopenharmony_ciint ssusb_check_clocks(struct ssusb_mtk *ssusb, u32 ex_clks) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci void __iomem *ibase = ssusb->ippc_base; 258c2ecf20Sopenharmony_ci u32 value, check_val; 268c2ecf20Sopenharmony_ci int ret; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci check_val = ex_clks | SSUSB_SYS125_RST_B_STS | SSUSB_SYSPLL_STABLE | 298c2ecf20Sopenharmony_ci SSUSB_REF_RST_B_STS; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci ret = readl_poll_timeout(ibase + U3D_SSUSB_IP_PW_STS1, value, 328c2ecf20Sopenharmony_ci (check_val == (value & check_val)), 100, 20000); 338c2ecf20Sopenharmony_ci if (ret) { 348c2ecf20Sopenharmony_ci dev_err(ssusb->dev, "clks of sts1 are not stable!\n"); 358c2ecf20Sopenharmony_ci return ret; 368c2ecf20Sopenharmony_ci } 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci ret = readl_poll_timeout(ibase + U3D_SSUSB_IP_PW_STS2, value, 398c2ecf20Sopenharmony_ci (value & SSUSB_U2_MAC_SYS_RST_B_STS), 100, 10000); 408c2ecf20Sopenharmony_ci if (ret) { 418c2ecf20Sopenharmony_ci dev_err(ssusb->dev, "mac2 clock is not stable\n"); 428c2ecf20Sopenharmony_ci return ret; 438c2ecf20Sopenharmony_ci } 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci return 0; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic int ssusb_phy_init(struct ssusb_mtk *ssusb) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci int i; 518c2ecf20Sopenharmony_ci int ret; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci for (i = 0; i < ssusb->num_phys; i++) { 548c2ecf20Sopenharmony_ci ret = phy_init(ssusb->phys[i]); 558c2ecf20Sopenharmony_ci if (ret) 568c2ecf20Sopenharmony_ci goto exit_phy; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci return 0; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ciexit_phy: 618c2ecf20Sopenharmony_ci for (; i > 0; i--) 628c2ecf20Sopenharmony_ci phy_exit(ssusb->phys[i - 1]); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci return ret; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic int ssusb_phy_exit(struct ssusb_mtk *ssusb) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci int i; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci for (i = 0; i < ssusb->num_phys; i++) 728c2ecf20Sopenharmony_ci phy_exit(ssusb->phys[i]); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return 0; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic int ssusb_phy_power_on(struct ssusb_mtk *ssusb) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci int i; 808c2ecf20Sopenharmony_ci int ret; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci for (i = 0; i < ssusb->num_phys; i++) { 838c2ecf20Sopenharmony_ci ret = phy_power_on(ssusb->phys[i]); 848c2ecf20Sopenharmony_ci if (ret) 858c2ecf20Sopenharmony_ci goto power_off_phy; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci return 0; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cipower_off_phy: 908c2ecf20Sopenharmony_ci for (; i > 0; i--) 918c2ecf20Sopenharmony_ci phy_power_off(ssusb->phys[i - 1]); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return ret; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic void ssusb_phy_power_off(struct ssusb_mtk *ssusb) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci unsigned int i; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci for (i = 0; i < ssusb->num_phys; i++) 1018c2ecf20Sopenharmony_ci phy_power_off(ssusb->phys[i]); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic int ssusb_clks_enable(struct ssusb_mtk *ssusb) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci int ret; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci ret = clk_prepare_enable(ssusb->sys_clk); 1098c2ecf20Sopenharmony_ci if (ret) { 1108c2ecf20Sopenharmony_ci dev_err(ssusb->dev, "failed to enable sys_clk\n"); 1118c2ecf20Sopenharmony_ci goto sys_clk_err; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci ret = clk_prepare_enable(ssusb->ref_clk); 1158c2ecf20Sopenharmony_ci if (ret) { 1168c2ecf20Sopenharmony_ci dev_err(ssusb->dev, "failed to enable ref_clk\n"); 1178c2ecf20Sopenharmony_ci goto ref_clk_err; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci ret = clk_prepare_enable(ssusb->mcu_clk); 1218c2ecf20Sopenharmony_ci if (ret) { 1228c2ecf20Sopenharmony_ci dev_err(ssusb->dev, "failed to enable mcu_clk\n"); 1238c2ecf20Sopenharmony_ci goto mcu_clk_err; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci ret = clk_prepare_enable(ssusb->dma_clk); 1278c2ecf20Sopenharmony_ci if (ret) { 1288c2ecf20Sopenharmony_ci dev_err(ssusb->dev, "failed to enable dma_clk\n"); 1298c2ecf20Sopenharmony_ci goto dma_clk_err; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci return 0; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cidma_clk_err: 1358c2ecf20Sopenharmony_ci clk_disable_unprepare(ssusb->mcu_clk); 1368c2ecf20Sopenharmony_cimcu_clk_err: 1378c2ecf20Sopenharmony_ci clk_disable_unprepare(ssusb->ref_clk); 1388c2ecf20Sopenharmony_ciref_clk_err: 1398c2ecf20Sopenharmony_ci clk_disable_unprepare(ssusb->sys_clk); 1408c2ecf20Sopenharmony_cisys_clk_err: 1418c2ecf20Sopenharmony_ci return ret; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic void ssusb_clks_disable(struct ssusb_mtk *ssusb) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci clk_disable_unprepare(ssusb->dma_clk); 1478c2ecf20Sopenharmony_ci clk_disable_unprepare(ssusb->mcu_clk); 1488c2ecf20Sopenharmony_ci clk_disable_unprepare(ssusb->ref_clk); 1498c2ecf20Sopenharmony_ci clk_disable_unprepare(ssusb->sys_clk); 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic int ssusb_rscs_init(struct ssusb_mtk *ssusb) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci int ret = 0; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci ret = regulator_enable(ssusb->vusb33); 1578c2ecf20Sopenharmony_ci if (ret) { 1588c2ecf20Sopenharmony_ci dev_err(ssusb->dev, "failed to enable vusb33\n"); 1598c2ecf20Sopenharmony_ci goto vusb33_err; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci ret = ssusb_clks_enable(ssusb); 1638c2ecf20Sopenharmony_ci if (ret) 1648c2ecf20Sopenharmony_ci goto clks_err; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci ret = ssusb_phy_init(ssusb); 1678c2ecf20Sopenharmony_ci if (ret) { 1688c2ecf20Sopenharmony_ci dev_err(ssusb->dev, "failed to init phy\n"); 1698c2ecf20Sopenharmony_ci goto phy_init_err; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci ret = ssusb_phy_power_on(ssusb); 1738c2ecf20Sopenharmony_ci if (ret) { 1748c2ecf20Sopenharmony_ci dev_err(ssusb->dev, "failed to power on phy\n"); 1758c2ecf20Sopenharmony_ci goto phy_err; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return 0; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ciphy_err: 1818c2ecf20Sopenharmony_ci ssusb_phy_exit(ssusb); 1828c2ecf20Sopenharmony_ciphy_init_err: 1838c2ecf20Sopenharmony_ci ssusb_clks_disable(ssusb); 1848c2ecf20Sopenharmony_ciclks_err: 1858c2ecf20Sopenharmony_ci regulator_disable(ssusb->vusb33); 1868c2ecf20Sopenharmony_civusb33_err: 1878c2ecf20Sopenharmony_ci return ret; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic void ssusb_rscs_exit(struct ssusb_mtk *ssusb) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci ssusb_clks_disable(ssusb); 1938c2ecf20Sopenharmony_ci regulator_disable(ssusb->vusb33); 1948c2ecf20Sopenharmony_ci ssusb_phy_power_off(ssusb); 1958c2ecf20Sopenharmony_ci ssusb_phy_exit(ssusb); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic void ssusb_ip_sw_reset(struct ssusb_mtk *ssusb) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci /* reset whole ip (xhci & u3d) */ 2018c2ecf20Sopenharmony_ci mtu3_setbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST); 2028c2ecf20Sopenharmony_ci udelay(1); 2038c2ecf20Sopenharmony_ci mtu3_clrbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci /* 2068c2ecf20Sopenharmony_ci * device ip may be powered on in firmware/BROM stage before entering 2078c2ecf20Sopenharmony_ci * kernel stage; 2088c2ecf20Sopenharmony_ci * power down device ip, otherwise ip-sleep will fail when working as 2098c2ecf20Sopenharmony_ci * host only mode 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_ci mtu3_setbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN); 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci struct device_node *node = pdev->dev.of_node; 2178c2ecf20Sopenharmony_ci struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; 2188c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 2198c2ecf20Sopenharmony_ci int i; 2208c2ecf20Sopenharmony_ci int ret; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci ssusb->vusb33 = devm_regulator_get(dev, "vusb33"); 2238c2ecf20Sopenharmony_ci if (IS_ERR(ssusb->vusb33)) { 2248c2ecf20Sopenharmony_ci dev_err(dev, "failed to get vusb33\n"); 2258c2ecf20Sopenharmony_ci return PTR_ERR(ssusb->vusb33); 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci ssusb->sys_clk = devm_clk_get(dev, "sys_ck"); 2298c2ecf20Sopenharmony_ci if (IS_ERR(ssusb->sys_clk)) { 2308c2ecf20Sopenharmony_ci dev_err(dev, "failed to get sys clock\n"); 2318c2ecf20Sopenharmony_ci return PTR_ERR(ssusb->sys_clk); 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci ssusb->ref_clk = devm_clk_get_optional(dev, "ref_ck"); 2358c2ecf20Sopenharmony_ci if (IS_ERR(ssusb->ref_clk)) 2368c2ecf20Sopenharmony_ci return PTR_ERR(ssusb->ref_clk); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci ssusb->mcu_clk = devm_clk_get_optional(dev, "mcu_ck"); 2398c2ecf20Sopenharmony_ci if (IS_ERR(ssusb->mcu_clk)) 2408c2ecf20Sopenharmony_ci return PTR_ERR(ssusb->mcu_clk); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci ssusb->dma_clk = devm_clk_get_optional(dev, "dma_ck"); 2438c2ecf20Sopenharmony_ci if (IS_ERR(ssusb->dma_clk)) 2448c2ecf20Sopenharmony_ci return PTR_ERR(ssusb->dma_clk); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci ssusb->num_phys = of_count_phandle_with_args(node, 2478c2ecf20Sopenharmony_ci "phys", "#phy-cells"); 2488c2ecf20Sopenharmony_ci if (ssusb->num_phys > 0) { 2498c2ecf20Sopenharmony_ci ssusb->phys = devm_kcalloc(dev, ssusb->num_phys, 2508c2ecf20Sopenharmony_ci sizeof(*ssusb->phys), GFP_KERNEL); 2518c2ecf20Sopenharmony_ci if (!ssusb->phys) 2528c2ecf20Sopenharmony_ci return -ENOMEM; 2538c2ecf20Sopenharmony_ci } else { 2548c2ecf20Sopenharmony_ci ssusb->num_phys = 0; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci for (i = 0; i < ssusb->num_phys; i++) { 2588c2ecf20Sopenharmony_ci ssusb->phys[i] = devm_of_phy_get_by_index(dev, node, i); 2598c2ecf20Sopenharmony_ci if (IS_ERR(ssusb->phys[i])) { 2608c2ecf20Sopenharmony_ci dev_err(dev, "failed to get phy-%d\n", i); 2618c2ecf20Sopenharmony_ci return PTR_ERR(ssusb->phys[i]); 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci ssusb->ippc_base = devm_platform_ioremap_resource_byname(pdev, "ippc"); 2668c2ecf20Sopenharmony_ci if (IS_ERR(ssusb->ippc_base)) 2678c2ecf20Sopenharmony_ci return PTR_ERR(ssusb->ippc_base); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci ssusb->dr_mode = usb_get_dr_mode(dev); 2708c2ecf20Sopenharmony_ci if (ssusb->dr_mode == USB_DR_MODE_UNKNOWN) 2718c2ecf20Sopenharmony_ci ssusb->dr_mode = USB_DR_MODE_OTG; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (ssusb->dr_mode == USB_DR_MODE_PERIPHERAL) 2748c2ecf20Sopenharmony_ci goto out; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* if host role is supported */ 2778c2ecf20Sopenharmony_ci ret = ssusb_wakeup_of_property_parse(ssusb, node); 2788c2ecf20Sopenharmony_ci if (ret) { 2798c2ecf20Sopenharmony_ci dev_err(dev, "failed to parse uwk property\n"); 2808c2ecf20Sopenharmony_ci return ret; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* optional property, ignore the error if it does not exist */ 2848c2ecf20Sopenharmony_ci of_property_read_u32(node, "mediatek,u3p-dis-msk", 2858c2ecf20Sopenharmony_ci &ssusb->u3p_dis_msk); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci otg_sx->vbus = devm_regulator_get(dev, "vbus"); 2888c2ecf20Sopenharmony_ci if (IS_ERR(otg_sx->vbus)) { 2898c2ecf20Sopenharmony_ci dev_err(dev, "failed to get vbus\n"); 2908c2ecf20Sopenharmony_ci return PTR_ERR(otg_sx->vbus); 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (ssusb->dr_mode == USB_DR_MODE_HOST) 2948c2ecf20Sopenharmony_ci goto out; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* if dual-role mode is supported */ 2978c2ecf20Sopenharmony_ci otg_sx->is_u3_drd = of_property_read_bool(node, "mediatek,usb3-drd"); 2988c2ecf20Sopenharmony_ci otg_sx->manual_drd_enabled = 2998c2ecf20Sopenharmony_ci of_property_read_bool(node, "enable-manual-drd"); 3008c2ecf20Sopenharmony_ci otg_sx->role_sw_used = of_property_read_bool(node, "usb-role-switch"); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (!otg_sx->role_sw_used && of_property_read_bool(node, "extcon")) { 3038c2ecf20Sopenharmony_ci otg_sx->edev = extcon_get_edev_by_phandle(ssusb->dev, 0); 3048c2ecf20Sopenharmony_ci if (IS_ERR(otg_sx->edev)) { 3058c2ecf20Sopenharmony_ci dev_err(ssusb->dev, "couldn't get extcon device\n"); 3068c2ecf20Sopenharmony_ci return PTR_ERR(otg_sx->edev); 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ciout: 3118c2ecf20Sopenharmony_ci dev_info(dev, "dr_mode: %d, is_u3_dr: %d, u3p_dis_msk: %x, drd: %s\n", 3128c2ecf20Sopenharmony_ci ssusb->dr_mode, otg_sx->is_u3_drd, ssusb->u3p_dis_msk, 3138c2ecf20Sopenharmony_ci otg_sx->manual_drd_enabled ? "manual" : "auto"); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci return 0; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic int mtu3_probe(struct platform_device *pdev) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct device_node *node = pdev->dev.of_node; 3218c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 3228c2ecf20Sopenharmony_ci struct ssusb_mtk *ssusb; 3238c2ecf20Sopenharmony_ci int ret = -ENOMEM; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci /* all elements are set to ZERO as default value */ 3268c2ecf20Sopenharmony_ci ssusb = devm_kzalloc(dev, sizeof(*ssusb), GFP_KERNEL); 3278c2ecf20Sopenharmony_ci if (!ssusb) 3288c2ecf20Sopenharmony_ci return -ENOMEM; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); 3318c2ecf20Sopenharmony_ci if (ret) { 3328c2ecf20Sopenharmony_ci dev_err(dev, "No suitable DMA config available\n"); 3338c2ecf20Sopenharmony_ci return -ENOTSUPP; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, ssusb); 3378c2ecf20Sopenharmony_ci ssusb->dev = dev; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci ret = get_ssusb_rscs(pdev, ssusb); 3408c2ecf20Sopenharmony_ci if (ret) 3418c2ecf20Sopenharmony_ci return ret; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci ssusb_debugfs_create_root(ssusb); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci /* enable power domain */ 3468c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 3478c2ecf20Sopenharmony_ci pm_runtime_get_sync(dev); 3488c2ecf20Sopenharmony_ci device_enable_async_suspend(dev); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci ret = ssusb_rscs_init(ssusb); 3518c2ecf20Sopenharmony_ci if (ret) 3528c2ecf20Sopenharmony_ci goto comm_init_err; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci ssusb_ip_sw_reset(ssusb); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_USB_MTU3_HOST)) 3578c2ecf20Sopenharmony_ci ssusb->dr_mode = USB_DR_MODE_HOST; 3588c2ecf20Sopenharmony_ci else if (IS_ENABLED(CONFIG_USB_MTU3_GADGET)) 3598c2ecf20Sopenharmony_ci ssusb->dr_mode = USB_DR_MODE_PERIPHERAL; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* default as host */ 3628c2ecf20Sopenharmony_ci ssusb->is_host = !(ssusb->dr_mode == USB_DR_MODE_PERIPHERAL); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci switch (ssusb->dr_mode) { 3658c2ecf20Sopenharmony_ci case USB_DR_MODE_PERIPHERAL: 3668c2ecf20Sopenharmony_ci ret = ssusb_gadget_init(ssusb); 3678c2ecf20Sopenharmony_ci if (ret) { 3688c2ecf20Sopenharmony_ci dev_err(dev, "failed to initialize gadget\n"); 3698c2ecf20Sopenharmony_ci goto comm_exit; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci break; 3728c2ecf20Sopenharmony_ci case USB_DR_MODE_HOST: 3738c2ecf20Sopenharmony_ci ret = ssusb_host_init(ssusb, node); 3748c2ecf20Sopenharmony_ci if (ret) { 3758c2ecf20Sopenharmony_ci dev_err(dev, "failed to initialize host\n"); 3768c2ecf20Sopenharmony_ci goto comm_exit; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci break; 3798c2ecf20Sopenharmony_ci case USB_DR_MODE_OTG: 3808c2ecf20Sopenharmony_ci ret = ssusb_gadget_init(ssusb); 3818c2ecf20Sopenharmony_ci if (ret) { 3828c2ecf20Sopenharmony_ci dev_err(dev, "failed to initialize gadget\n"); 3838c2ecf20Sopenharmony_ci goto comm_exit; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci ret = ssusb_host_init(ssusb, node); 3878c2ecf20Sopenharmony_ci if (ret) { 3888c2ecf20Sopenharmony_ci dev_err(dev, "failed to initialize host\n"); 3898c2ecf20Sopenharmony_ci goto gadget_exit; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci ret = ssusb_otg_switch_init(ssusb); 3938c2ecf20Sopenharmony_ci if (ret) { 3948c2ecf20Sopenharmony_ci dev_err(dev, "failed to initialize switch\n"); 3958c2ecf20Sopenharmony_ci goto host_exit; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci break; 3988c2ecf20Sopenharmony_ci default: 3998c2ecf20Sopenharmony_ci dev_err(dev, "unsupported mode: %d\n", ssusb->dr_mode); 4008c2ecf20Sopenharmony_ci ret = -EINVAL; 4018c2ecf20Sopenharmony_ci goto comm_exit; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci return 0; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cihost_exit: 4078c2ecf20Sopenharmony_ci ssusb_host_exit(ssusb); 4088c2ecf20Sopenharmony_cigadget_exit: 4098c2ecf20Sopenharmony_ci ssusb_gadget_exit(ssusb); 4108c2ecf20Sopenharmony_cicomm_exit: 4118c2ecf20Sopenharmony_ci ssusb_rscs_exit(ssusb); 4128c2ecf20Sopenharmony_cicomm_init_err: 4138c2ecf20Sopenharmony_ci pm_runtime_put_sync(dev); 4148c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 4158c2ecf20Sopenharmony_ci ssusb_debugfs_remove_root(ssusb); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci return ret; 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic int mtu3_remove(struct platform_device *pdev) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci struct ssusb_mtk *ssusb = platform_get_drvdata(pdev); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci switch (ssusb->dr_mode) { 4258c2ecf20Sopenharmony_ci case USB_DR_MODE_PERIPHERAL: 4268c2ecf20Sopenharmony_ci ssusb_gadget_exit(ssusb); 4278c2ecf20Sopenharmony_ci break; 4288c2ecf20Sopenharmony_ci case USB_DR_MODE_HOST: 4298c2ecf20Sopenharmony_ci ssusb_host_exit(ssusb); 4308c2ecf20Sopenharmony_ci break; 4318c2ecf20Sopenharmony_ci case USB_DR_MODE_OTG: 4328c2ecf20Sopenharmony_ci ssusb_otg_switch_exit(ssusb); 4338c2ecf20Sopenharmony_ci ssusb_gadget_exit(ssusb); 4348c2ecf20Sopenharmony_ci ssusb_host_exit(ssusb); 4358c2ecf20Sopenharmony_ci break; 4368c2ecf20Sopenharmony_ci default: 4378c2ecf20Sopenharmony_ci return -EINVAL; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci ssusb_rscs_exit(ssusb); 4418c2ecf20Sopenharmony_ci pm_runtime_put_sync(&pdev->dev); 4428c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 4438c2ecf20Sopenharmony_ci ssusb_debugfs_remove_root(ssusb); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci return 0; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci/* 4498c2ecf20Sopenharmony_ci * when support dual-role mode, we reject suspend when 4508c2ecf20Sopenharmony_ci * it works as device mode; 4518c2ecf20Sopenharmony_ci */ 4528c2ecf20Sopenharmony_cistatic int __maybe_unused mtu3_suspend(struct device *dev) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci struct ssusb_mtk *ssusb = dev_get_drvdata(dev); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci dev_dbg(dev, "%s\n", __func__); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci /* REVISIT: disconnect it for only device mode? */ 4598c2ecf20Sopenharmony_ci if (!ssusb->is_host) 4608c2ecf20Sopenharmony_ci return 0; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci ssusb_host_disable(ssusb, true); 4638c2ecf20Sopenharmony_ci ssusb_phy_power_off(ssusb); 4648c2ecf20Sopenharmony_ci ssusb_clks_disable(ssusb); 4658c2ecf20Sopenharmony_ci ssusb_wakeup_set(ssusb, true); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci return 0; 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic int __maybe_unused mtu3_resume(struct device *dev) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci struct ssusb_mtk *ssusb = dev_get_drvdata(dev); 4738c2ecf20Sopenharmony_ci int ret; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci dev_dbg(dev, "%s\n", __func__); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (!ssusb->is_host) 4788c2ecf20Sopenharmony_ci return 0; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci ssusb_wakeup_set(ssusb, false); 4818c2ecf20Sopenharmony_ci ret = ssusb_clks_enable(ssusb); 4828c2ecf20Sopenharmony_ci if (ret) 4838c2ecf20Sopenharmony_ci goto clks_err; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci ret = ssusb_phy_power_on(ssusb); 4868c2ecf20Sopenharmony_ci if (ret) 4878c2ecf20Sopenharmony_ci goto phy_err; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci ssusb_host_enable(ssusb); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci return 0; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ciphy_err: 4948c2ecf20Sopenharmony_ci ssusb_clks_disable(ssusb); 4958c2ecf20Sopenharmony_ciclks_err: 4968c2ecf20Sopenharmony_ci return ret; 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_cistatic const struct dev_pm_ops mtu3_pm_ops = { 5008c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(mtu3_suspend, mtu3_resume) 5018c2ecf20Sopenharmony_ci}; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci#define DEV_PM_OPS (IS_ENABLED(CONFIG_PM) ? &mtu3_pm_ops : NULL) 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistatic const struct of_device_id mtu3_of_match[] = { 5088c2ecf20Sopenharmony_ci {.compatible = "mediatek,mt8173-mtu3",}, 5098c2ecf20Sopenharmony_ci {.compatible = "mediatek,mtu3",}, 5108c2ecf20Sopenharmony_ci {}, 5118c2ecf20Sopenharmony_ci}; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, mtu3_of_match); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci#endif 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic struct platform_driver mtu3_driver = { 5188c2ecf20Sopenharmony_ci .probe = mtu3_probe, 5198c2ecf20Sopenharmony_ci .remove = mtu3_remove, 5208c2ecf20Sopenharmony_ci .driver = { 5218c2ecf20Sopenharmony_ci .name = MTU3_DRIVER_NAME, 5228c2ecf20Sopenharmony_ci .pm = DEV_PM_OPS, 5238c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(mtu3_of_match), 5248c2ecf20Sopenharmony_ci }, 5258c2ecf20Sopenharmony_ci}; 5268c2ecf20Sopenharmony_cimodule_platform_driver(mtu3_driver); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ciMODULE_AUTHOR("Chunfeng Yun <chunfeng.yun@mediatek.com>"); 5298c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 5308c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MediaTek USB3 DRD Controller Driver"); 531