18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2012 Freescale Semiconductor, Inc. 48c2ecf20Sopenharmony_ci * Copyright (C) 2012 Marek Vasut <marex@denx.de> 58c2ecf20Sopenharmony_ci * on behalf of DENX Software Engineering GmbH 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 108c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 118c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 128c2ecf20Sopenharmony_ci#include <linux/usb/chipidea.h> 138c2ecf20Sopenharmony_ci#include <linux/usb/of.h> 148c2ecf20Sopenharmony_ci#include <linux/clk.h> 158c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h> 168c2ecf20Sopenharmony_ci#include <linux/pm_qos.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "ci.h" 198c2ecf20Sopenharmony_ci#include "ci_hdrc_imx.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistruct ci_hdrc_imx_platform_flag { 228c2ecf20Sopenharmony_ci unsigned int flags; 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic const struct ci_hdrc_imx_platform_flag imx23_usb_data = { 268c2ecf20Sopenharmony_ci .flags = CI_HDRC_TURN_VBUS_EARLY_ON | 278c2ecf20Sopenharmony_ci CI_HDRC_DISABLE_STREAMING, 288c2ecf20Sopenharmony_ci}; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic const struct ci_hdrc_imx_platform_flag imx27_usb_data = { 318c2ecf20Sopenharmony_ci .flags = CI_HDRC_DISABLE_STREAMING, 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic const struct ci_hdrc_imx_platform_flag imx28_usb_data = { 358c2ecf20Sopenharmony_ci .flags = CI_HDRC_IMX28_WRITE_FIX | 368c2ecf20Sopenharmony_ci CI_HDRC_TURN_VBUS_EARLY_ON | 378c2ecf20Sopenharmony_ci CI_HDRC_DISABLE_STREAMING, 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic const struct ci_hdrc_imx_platform_flag imx6q_usb_data = { 418c2ecf20Sopenharmony_ci .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | 428c2ecf20Sopenharmony_ci CI_HDRC_TURN_VBUS_EARLY_ON | 438c2ecf20Sopenharmony_ci CI_HDRC_DISABLE_STREAMING, 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic const struct ci_hdrc_imx_platform_flag imx6sl_usb_data = { 478c2ecf20Sopenharmony_ci .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | 488c2ecf20Sopenharmony_ci CI_HDRC_TURN_VBUS_EARLY_ON | 498c2ecf20Sopenharmony_ci CI_HDRC_DISABLE_HOST_STREAMING, 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic const struct ci_hdrc_imx_platform_flag imx6sx_usb_data = { 538c2ecf20Sopenharmony_ci .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | 548c2ecf20Sopenharmony_ci CI_HDRC_TURN_VBUS_EARLY_ON | 558c2ecf20Sopenharmony_ci CI_HDRC_DISABLE_HOST_STREAMING, 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic const struct ci_hdrc_imx_platform_flag imx6ul_usb_data = { 598c2ecf20Sopenharmony_ci .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | 608c2ecf20Sopenharmony_ci CI_HDRC_TURN_VBUS_EARLY_ON | 618c2ecf20Sopenharmony_ci CI_HDRC_DISABLE_DEVICE_STREAMING, 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic const struct ci_hdrc_imx_platform_flag imx7d_usb_data = { 658c2ecf20Sopenharmony_ci .flags = CI_HDRC_SUPPORTS_RUNTIME_PM, 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic const struct ci_hdrc_imx_platform_flag imx7ulp_usb_data = { 698c2ecf20Sopenharmony_ci .flags = CI_HDRC_SUPPORTS_RUNTIME_PM | 708c2ecf20Sopenharmony_ci CI_HDRC_PMQOS, 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic const struct ci_hdrc_imx_platform_flag imx8ulp_usb_data = { 748c2ecf20Sopenharmony_ci .flags = CI_HDRC_SUPPORTS_RUNTIME_PM, 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic const struct of_device_id ci_hdrc_imx_dt_ids[] = { 788c2ecf20Sopenharmony_ci { .compatible = "fsl,imx23-usb", .data = &imx23_usb_data}, 798c2ecf20Sopenharmony_ci { .compatible = "fsl,imx28-usb", .data = &imx28_usb_data}, 808c2ecf20Sopenharmony_ci { .compatible = "fsl,imx27-usb", .data = &imx27_usb_data}, 818c2ecf20Sopenharmony_ci { .compatible = "fsl,imx6q-usb", .data = &imx6q_usb_data}, 828c2ecf20Sopenharmony_ci { .compatible = "fsl,imx6sl-usb", .data = &imx6sl_usb_data}, 838c2ecf20Sopenharmony_ci { .compatible = "fsl,imx6sx-usb", .data = &imx6sx_usb_data}, 848c2ecf20Sopenharmony_ci { .compatible = "fsl,imx6ul-usb", .data = &imx6ul_usb_data}, 858c2ecf20Sopenharmony_ci { .compatible = "fsl,imx7d-usb", .data = &imx7d_usb_data}, 868c2ecf20Sopenharmony_ci { .compatible = "fsl,imx7ulp-usb", .data = &imx7ulp_usb_data}, 878c2ecf20Sopenharmony_ci { .compatible = "fsl,imx8ulp-usb", .data = &imx8ulp_usb_data}, 888c2ecf20Sopenharmony_ci { /* sentinel */ } 898c2ecf20Sopenharmony_ci}; 908c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistruct ci_hdrc_imx_data { 938c2ecf20Sopenharmony_ci struct usb_phy *phy; 948c2ecf20Sopenharmony_ci struct platform_device *ci_pdev; 958c2ecf20Sopenharmony_ci struct clk *clk; 968c2ecf20Sopenharmony_ci struct imx_usbmisc_data *usbmisc_data; 978c2ecf20Sopenharmony_ci bool supports_runtime_pm; 988c2ecf20Sopenharmony_ci bool override_phy_control; 998c2ecf20Sopenharmony_ci bool in_lpm; 1008c2ecf20Sopenharmony_ci struct pinctrl *pinctrl; 1018c2ecf20Sopenharmony_ci struct pinctrl_state *pinctrl_hsic_active; 1028c2ecf20Sopenharmony_ci struct regulator *hsic_pad_regulator; 1038c2ecf20Sopenharmony_ci /* SoC before i.mx6 (except imx23/imx28) needs three clks */ 1048c2ecf20Sopenharmony_ci bool need_three_clks; 1058c2ecf20Sopenharmony_ci struct clk *clk_ipg; 1068c2ecf20Sopenharmony_ci struct clk *clk_ahb; 1078c2ecf20Sopenharmony_ci struct clk *clk_per; 1088c2ecf20Sopenharmony_ci /* --------------------------------- */ 1098c2ecf20Sopenharmony_ci struct pm_qos_request pm_qos_req; 1108c2ecf20Sopenharmony_ci const struct ci_hdrc_imx_platform_flag *plat_data; 1118c2ecf20Sopenharmony_ci}; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* Common functions shared by usbmisc drivers */ 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct platform_device *misc_pdev; 1188c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 1198c2ecf20Sopenharmony_ci struct of_phandle_args args; 1208c2ecf20Sopenharmony_ci struct imx_usbmisc_data *data; 1218c2ecf20Sopenharmony_ci int ret; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* 1248c2ecf20Sopenharmony_ci * In case the fsl,usbmisc property is not present this device doesn't 1258c2ecf20Sopenharmony_ci * need usbmisc. Return NULL (which is no error here) 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_ci if (!of_get_property(np, "fsl,usbmisc", NULL)) 1288c2ecf20Sopenharmony_ci return NULL; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 1318c2ecf20Sopenharmony_ci if (!data) 1328c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci ret = of_parse_phandle_with_args(np, "fsl,usbmisc", "#index-cells", 1358c2ecf20Sopenharmony_ci 0, &args); 1368c2ecf20Sopenharmony_ci if (ret) { 1378c2ecf20Sopenharmony_ci dev_err(dev, "Failed to parse property fsl,usbmisc, errno %d\n", 1388c2ecf20Sopenharmony_ci ret); 1398c2ecf20Sopenharmony_ci return ERR_PTR(ret); 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci data->index = args.args[0]; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci misc_pdev = of_find_device_by_node(args.np); 1458c2ecf20Sopenharmony_ci of_node_put(args.np); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (!misc_pdev) 1488c2ecf20Sopenharmony_ci return ERR_PTR(-EPROBE_DEFER); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (!platform_get_drvdata(misc_pdev)) { 1518c2ecf20Sopenharmony_ci put_device(&misc_pdev->dev); 1528c2ecf20Sopenharmony_ci return ERR_PTR(-EPROBE_DEFER); 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci data->dev = &misc_pdev->dev; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* 1578c2ecf20Sopenharmony_ci * Check the various over current related properties. If over current 1588c2ecf20Sopenharmony_ci * detection is disabled we're not interested in the polarity. 1598c2ecf20Sopenharmony_ci */ 1608c2ecf20Sopenharmony_ci if (of_find_property(np, "disable-over-current", NULL)) { 1618c2ecf20Sopenharmony_ci data->disable_oc = 1; 1628c2ecf20Sopenharmony_ci } else if (of_find_property(np, "over-current-active-high", NULL)) { 1638c2ecf20Sopenharmony_ci data->oc_pol_active_low = 0; 1648c2ecf20Sopenharmony_ci data->oc_pol_configured = 1; 1658c2ecf20Sopenharmony_ci } else if (of_find_property(np, "over-current-active-low", NULL)) { 1668c2ecf20Sopenharmony_ci data->oc_pol_active_low = 1; 1678c2ecf20Sopenharmony_ci data->oc_pol_configured = 1; 1688c2ecf20Sopenharmony_ci } else { 1698c2ecf20Sopenharmony_ci dev_warn(dev, "No over current polarity defined\n"); 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci data->pwr_pol = of_property_read_bool(np, "power-active-high"); 1738c2ecf20Sopenharmony_ci data->evdo = of_property_read_bool(np, "external-vbus-divider"); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI) 1768c2ecf20Sopenharmony_ci data->ulpi = 1; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "samsung,picophy-pre-emp-curr-control", 1798c2ecf20Sopenharmony_ci &data->emp_curr_control)) 1808c2ecf20Sopenharmony_ci data->emp_curr_control = -1; 1818c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "samsung,picophy-dc-vol-level-adjust", 1828c2ecf20Sopenharmony_ci &data->dc_vol_level_adjust)) 1838c2ecf20Sopenharmony_ci data->dc_vol_level_adjust = -1; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci return data; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci/* End of common functions shared by usbmisc drivers*/ 1898c2ecf20Sopenharmony_cistatic int imx_get_clks(struct device *dev) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 1928c2ecf20Sopenharmony_ci int ret = 0; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci data->clk_ipg = devm_clk_get(dev, "ipg"); 1958c2ecf20Sopenharmony_ci if (IS_ERR(data->clk_ipg)) { 1968c2ecf20Sopenharmony_ci /* If the platform only needs one clocks */ 1978c2ecf20Sopenharmony_ci data->clk = devm_clk_get(dev, NULL); 1988c2ecf20Sopenharmony_ci if (IS_ERR(data->clk)) { 1998c2ecf20Sopenharmony_ci ret = PTR_ERR(data->clk); 2008c2ecf20Sopenharmony_ci dev_err(dev, 2018c2ecf20Sopenharmony_ci "Failed to get clks, err=%ld,%ld\n", 2028c2ecf20Sopenharmony_ci PTR_ERR(data->clk), PTR_ERR(data->clk_ipg)); 2038c2ecf20Sopenharmony_ci return ret; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci return ret; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci data->clk_ahb = devm_clk_get(dev, "ahb"); 2098c2ecf20Sopenharmony_ci if (IS_ERR(data->clk_ahb)) { 2108c2ecf20Sopenharmony_ci ret = PTR_ERR(data->clk_ahb); 2118c2ecf20Sopenharmony_ci dev_err(dev, 2128c2ecf20Sopenharmony_ci "Failed to get ahb clock, err=%d\n", ret); 2138c2ecf20Sopenharmony_ci return ret; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci data->clk_per = devm_clk_get(dev, "per"); 2178c2ecf20Sopenharmony_ci if (IS_ERR(data->clk_per)) { 2188c2ecf20Sopenharmony_ci ret = PTR_ERR(data->clk_per); 2198c2ecf20Sopenharmony_ci dev_err(dev, 2208c2ecf20Sopenharmony_ci "Failed to get per clock, err=%d\n", ret); 2218c2ecf20Sopenharmony_ci return ret; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci data->need_three_clks = true; 2258c2ecf20Sopenharmony_ci return ret; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic int imx_prepare_enable_clks(struct device *dev) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 2318c2ecf20Sopenharmony_ci int ret = 0; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if (data->need_three_clks) { 2348c2ecf20Sopenharmony_ci ret = clk_prepare_enable(data->clk_ipg); 2358c2ecf20Sopenharmony_ci if (ret) { 2368c2ecf20Sopenharmony_ci dev_err(dev, 2378c2ecf20Sopenharmony_ci "Failed to prepare/enable ipg clk, err=%d\n", 2388c2ecf20Sopenharmony_ci ret); 2398c2ecf20Sopenharmony_ci return ret; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci ret = clk_prepare_enable(data->clk_ahb); 2438c2ecf20Sopenharmony_ci if (ret) { 2448c2ecf20Sopenharmony_ci dev_err(dev, 2458c2ecf20Sopenharmony_ci "Failed to prepare/enable ahb clk, err=%d\n", 2468c2ecf20Sopenharmony_ci ret); 2478c2ecf20Sopenharmony_ci clk_disable_unprepare(data->clk_ipg); 2488c2ecf20Sopenharmony_ci return ret; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci ret = clk_prepare_enable(data->clk_per); 2528c2ecf20Sopenharmony_ci if (ret) { 2538c2ecf20Sopenharmony_ci dev_err(dev, 2548c2ecf20Sopenharmony_ci "Failed to prepare/enable per clk, err=%d\n", 2558c2ecf20Sopenharmony_ci ret); 2568c2ecf20Sopenharmony_ci clk_disable_unprepare(data->clk_ahb); 2578c2ecf20Sopenharmony_ci clk_disable_unprepare(data->clk_ipg); 2588c2ecf20Sopenharmony_ci return ret; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci } else { 2618c2ecf20Sopenharmony_ci ret = clk_prepare_enable(data->clk); 2628c2ecf20Sopenharmony_ci if (ret) { 2638c2ecf20Sopenharmony_ci dev_err(dev, 2648c2ecf20Sopenharmony_ci "Failed to prepare/enable clk, err=%d\n", 2658c2ecf20Sopenharmony_ci ret); 2668c2ecf20Sopenharmony_ci return ret; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci return ret; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic void imx_disable_unprepare_clks(struct device *dev) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (data->need_three_clks) { 2788c2ecf20Sopenharmony_ci clk_disable_unprepare(data->clk_per); 2798c2ecf20Sopenharmony_ci clk_disable_unprepare(data->clk_ahb); 2808c2ecf20Sopenharmony_ci clk_disable_unprepare(data->clk_ipg); 2818c2ecf20Sopenharmony_ci } else { 2828c2ecf20Sopenharmony_ci clk_disable_unprepare(data->clk); 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned int event) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct device *dev = ci->dev->parent; 2898c2ecf20Sopenharmony_ci struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 2908c2ecf20Sopenharmony_ci int ret = 0; 2918c2ecf20Sopenharmony_ci struct imx_usbmisc_data *mdata = data->usbmisc_data; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci switch (event) { 2948c2ecf20Sopenharmony_ci case CI_HDRC_IMX_HSIC_ACTIVE_EVENT: 2958c2ecf20Sopenharmony_ci if (data->pinctrl) { 2968c2ecf20Sopenharmony_ci ret = pinctrl_select_state(data->pinctrl, 2978c2ecf20Sopenharmony_ci data->pinctrl_hsic_active); 2988c2ecf20Sopenharmony_ci if (ret) 2998c2ecf20Sopenharmony_ci dev_err(dev, 3008c2ecf20Sopenharmony_ci "hsic_active select failed, err=%d\n", 3018c2ecf20Sopenharmony_ci ret); 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci break; 3048c2ecf20Sopenharmony_ci case CI_HDRC_IMX_HSIC_SUSPEND_EVENT: 3058c2ecf20Sopenharmony_ci ret = imx_usbmisc_hsic_set_connect(mdata); 3068c2ecf20Sopenharmony_ci if (ret) 3078c2ecf20Sopenharmony_ci dev_err(dev, 3088c2ecf20Sopenharmony_ci "hsic_set_connect failed, err=%d\n", ret); 3098c2ecf20Sopenharmony_ci break; 3108c2ecf20Sopenharmony_ci case CI_HDRC_CONTROLLER_VBUS_EVENT: 3118c2ecf20Sopenharmony_ci if (ci->vbus_active) 3128c2ecf20Sopenharmony_ci ret = imx_usbmisc_charger_detection(mdata, true); 3138c2ecf20Sopenharmony_ci else 3148c2ecf20Sopenharmony_ci ret = imx_usbmisc_charger_detection(mdata, false); 3158c2ecf20Sopenharmony_ci if (ci->usb_phy) 3168c2ecf20Sopenharmony_ci schedule_work(&ci->usb_phy->chg_work); 3178c2ecf20Sopenharmony_ci break; 3188c2ecf20Sopenharmony_ci default: 3198c2ecf20Sopenharmony_ci break; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci return ret; 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic int ci_hdrc_imx_probe(struct platform_device *pdev) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci struct ci_hdrc_imx_data *data; 3288c2ecf20Sopenharmony_ci struct ci_hdrc_platform_data pdata = { 3298c2ecf20Sopenharmony_ci .name = dev_name(&pdev->dev), 3308c2ecf20Sopenharmony_ci .capoffset = DEF_CAPOFFSET, 3318c2ecf20Sopenharmony_ci .notify_event = ci_hdrc_imx_notify_event, 3328c2ecf20Sopenharmony_ci }; 3338c2ecf20Sopenharmony_ci int ret; 3348c2ecf20Sopenharmony_ci const struct of_device_id *of_id; 3358c2ecf20Sopenharmony_ci const struct ci_hdrc_imx_platform_flag *imx_platform_flag; 3368c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 3378c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci of_id = of_match_device(ci_hdrc_imx_dt_ids, dev); 3408c2ecf20Sopenharmony_ci if (!of_id) 3418c2ecf20Sopenharmony_ci return -ENODEV; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci imx_platform_flag = of_id->data; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 3468c2ecf20Sopenharmony_ci if (!data) 3478c2ecf20Sopenharmony_ci return -ENOMEM; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci data->plat_data = imx_platform_flag; 3508c2ecf20Sopenharmony_ci pdata.flags |= imx_platform_flag->flags; 3518c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, data); 3528c2ecf20Sopenharmony_ci data->usbmisc_data = usbmisc_get_init_data(dev); 3538c2ecf20Sopenharmony_ci if (IS_ERR(data->usbmisc_data)) 3548c2ecf20Sopenharmony_ci return PTR_ERR(data->usbmisc_data); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if ((of_usb_get_phy_mode(dev->of_node) == USBPHY_INTERFACE_MODE_HSIC) 3578c2ecf20Sopenharmony_ci && data->usbmisc_data) { 3588c2ecf20Sopenharmony_ci pdata.flags |= CI_HDRC_IMX_IS_HSIC; 3598c2ecf20Sopenharmony_ci data->usbmisc_data->hsic = 1; 3608c2ecf20Sopenharmony_ci data->pinctrl = devm_pinctrl_get(dev); 3618c2ecf20Sopenharmony_ci if (PTR_ERR(data->pinctrl) == -ENODEV) 3628c2ecf20Sopenharmony_ci data->pinctrl = NULL; 3638c2ecf20Sopenharmony_ci else if (IS_ERR(data->pinctrl)) { 3648c2ecf20Sopenharmony_ci if (PTR_ERR(data->pinctrl) != -EPROBE_DEFER) 3658c2ecf20Sopenharmony_ci dev_err(dev, "pinctrl get failed, err=%ld\n", 3668c2ecf20Sopenharmony_ci PTR_ERR(data->pinctrl)); 3678c2ecf20Sopenharmony_ci return PTR_ERR(data->pinctrl); 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci data->hsic_pad_regulator = 3718c2ecf20Sopenharmony_ci devm_regulator_get_optional(dev, "hsic"); 3728c2ecf20Sopenharmony_ci if (PTR_ERR(data->hsic_pad_regulator) == -ENODEV) { 3738c2ecf20Sopenharmony_ci /* no pad regualator is needed */ 3748c2ecf20Sopenharmony_ci data->hsic_pad_regulator = NULL; 3758c2ecf20Sopenharmony_ci } else if (IS_ERR(data->hsic_pad_regulator)) { 3768c2ecf20Sopenharmony_ci if (PTR_ERR(data->hsic_pad_regulator) != -EPROBE_DEFER) 3778c2ecf20Sopenharmony_ci dev_err(dev, 3788c2ecf20Sopenharmony_ci "Get HSIC pad regulator error: %ld\n", 3798c2ecf20Sopenharmony_ci PTR_ERR(data->hsic_pad_regulator)); 3808c2ecf20Sopenharmony_ci return PTR_ERR(data->hsic_pad_regulator); 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci if (data->hsic_pad_regulator) { 3848c2ecf20Sopenharmony_ci ret = regulator_enable(data->hsic_pad_regulator); 3858c2ecf20Sopenharmony_ci if (ret) { 3868c2ecf20Sopenharmony_ci dev_err(dev, 3878c2ecf20Sopenharmony_ci "Failed to enable HSIC pad regulator\n"); 3888c2ecf20Sopenharmony_ci return ret; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* HSIC pinctrl handling */ 3948c2ecf20Sopenharmony_ci if (data->pinctrl) { 3958c2ecf20Sopenharmony_ci struct pinctrl_state *pinctrl_hsic_idle; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci pinctrl_hsic_idle = pinctrl_lookup_state(data->pinctrl, "idle"); 3988c2ecf20Sopenharmony_ci if (IS_ERR(pinctrl_hsic_idle)) { 3998c2ecf20Sopenharmony_ci dev_err(dev, 4008c2ecf20Sopenharmony_ci "pinctrl_hsic_idle lookup failed, err=%ld\n", 4018c2ecf20Sopenharmony_ci PTR_ERR(pinctrl_hsic_idle)); 4028c2ecf20Sopenharmony_ci return PTR_ERR(pinctrl_hsic_idle); 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci ret = pinctrl_select_state(data->pinctrl, pinctrl_hsic_idle); 4068c2ecf20Sopenharmony_ci if (ret) { 4078c2ecf20Sopenharmony_ci dev_err(dev, "hsic_idle select failed, err=%d\n", ret); 4088c2ecf20Sopenharmony_ci return ret; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci data->pinctrl_hsic_active = pinctrl_lookup_state(data->pinctrl, 4128c2ecf20Sopenharmony_ci "active"); 4138c2ecf20Sopenharmony_ci if (IS_ERR(data->pinctrl_hsic_active)) { 4148c2ecf20Sopenharmony_ci dev_err(dev, 4158c2ecf20Sopenharmony_ci "pinctrl_hsic_active lookup failed, err=%ld\n", 4168c2ecf20Sopenharmony_ci PTR_ERR(data->pinctrl_hsic_active)); 4178c2ecf20Sopenharmony_ci return PTR_ERR(data->pinctrl_hsic_active); 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (pdata.flags & CI_HDRC_PMQOS) 4228c2ecf20Sopenharmony_ci cpu_latency_qos_add_request(&data->pm_qos_req, 0); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci ret = imx_get_clks(dev); 4258c2ecf20Sopenharmony_ci if (ret) 4268c2ecf20Sopenharmony_ci goto disable_hsic_regulator; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci ret = imx_prepare_enable_clks(dev); 4298c2ecf20Sopenharmony_ci if (ret) 4308c2ecf20Sopenharmony_ci goto disable_hsic_regulator; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci data->phy = devm_usb_get_phy_by_phandle(dev, "fsl,usbphy", 0); 4338c2ecf20Sopenharmony_ci if (IS_ERR(data->phy)) { 4348c2ecf20Sopenharmony_ci ret = PTR_ERR(data->phy); 4358c2ecf20Sopenharmony_ci if (ret != -ENODEV) 4368c2ecf20Sopenharmony_ci goto err_clk; 4378c2ecf20Sopenharmony_ci data->phy = devm_usb_get_phy_by_phandle(dev, "phys", 0); 4388c2ecf20Sopenharmony_ci if (IS_ERR(data->phy)) { 4398c2ecf20Sopenharmony_ci ret = PTR_ERR(data->phy); 4408c2ecf20Sopenharmony_ci if (ret == -ENODEV) 4418c2ecf20Sopenharmony_ci data->phy = NULL; 4428c2ecf20Sopenharmony_ci else 4438c2ecf20Sopenharmony_ci goto err_clk; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci pdata.usb_phy = data->phy; 4488c2ecf20Sopenharmony_ci if (data->usbmisc_data) 4498c2ecf20Sopenharmony_ci data->usbmisc_data->usb_phy = data->phy; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if ((of_device_is_compatible(np, "fsl,imx53-usb") || 4528c2ecf20Sopenharmony_ci of_device_is_compatible(np, "fsl,imx51-usb")) && pdata.usb_phy && 4538c2ecf20Sopenharmony_ci of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI) { 4548c2ecf20Sopenharmony_ci pdata.flags |= CI_HDRC_OVERRIDE_PHY_CONTROL; 4558c2ecf20Sopenharmony_ci data->override_phy_control = true; 4568c2ecf20Sopenharmony_ci usb_phy_init(pdata.usb_phy); 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM) 4608c2ecf20Sopenharmony_ci data->supports_runtime_pm = true; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci ret = imx_usbmisc_init(data->usbmisc_data); 4638c2ecf20Sopenharmony_ci if (ret) { 4648c2ecf20Sopenharmony_ci dev_err(dev, "usbmisc init failed, ret=%d\n", ret); 4658c2ecf20Sopenharmony_ci goto err_clk; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci data->ci_pdev = ci_hdrc_add_device(dev, 4698c2ecf20Sopenharmony_ci pdev->resource, pdev->num_resources, 4708c2ecf20Sopenharmony_ci &pdata); 4718c2ecf20Sopenharmony_ci if (IS_ERR(data->ci_pdev)) { 4728c2ecf20Sopenharmony_ci ret = PTR_ERR(data->ci_pdev); 4738c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 4748c2ecf20Sopenharmony_ci dev_err(dev, "ci_hdrc_add_device failed, err=%d\n", 4758c2ecf20Sopenharmony_ci ret); 4768c2ecf20Sopenharmony_ci goto err_clk; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci if (data->usbmisc_data) { 4808c2ecf20Sopenharmony_ci if (!IS_ERR(pdata.id_extcon.edev) || 4818c2ecf20Sopenharmony_ci of_property_read_bool(np, "usb-role-switch")) 4828c2ecf20Sopenharmony_ci data->usbmisc_data->ext_id = 1; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci if (!IS_ERR(pdata.vbus_extcon.edev) || 4858c2ecf20Sopenharmony_ci of_property_read_bool(np, "usb-role-switch")) 4868c2ecf20Sopenharmony_ci data->usbmisc_data->ext_vbus = 1; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci /* usbmisc needs to know dr mode to choose wakeup setting */ 4898c2ecf20Sopenharmony_ci data->usbmisc_data->available_role = 4908c2ecf20Sopenharmony_ci ci_hdrc_query_available_role(data->ci_pdev); 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci ret = imx_usbmisc_init_post(data->usbmisc_data); 4948c2ecf20Sopenharmony_ci if (ret) { 4958c2ecf20Sopenharmony_ci dev_err(dev, "usbmisc post failed, ret=%d\n", ret); 4968c2ecf20Sopenharmony_ci goto disable_device; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (data->supports_runtime_pm) { 5008c2ecf20Sopenharmony_ci pm_runtime_set_active(dev); 5018c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci device_set_wakeup_capable(dev, true); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci return 0; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cidisable_device: 5098c2ecf20Sopenharmony_ci ci_hdrc_remove_device(data->ci_pdev); 5108c2ecf20Sopenharmony_cierr_clk: 5118c2ecf20Sopenharmony_ci imx_disable_unprepare_clks(dev); 5128c2ecf20Sopenharmony_cidisable_hsic_regulator: 5138c2ecf20Sopenharmony_ci if (data->hsic_pad_regulator) 5148c2ecf20Sopenharmony_ci /* don't overwrite original ret (cf. EPROBE_DEFER) */ 5158c2ecf20Sopenharmony_ci regulator_disable(data->hsic_pad_regulator); 5168c2ecf20Sopenharmony_ci if (pdata.flags & CI_HDRC_PMQOS) 5178c2ecf20Sopenharmony_ci cpu_latency_qos_remove_request(&data->pm_qos_req); 5188c2ecf20Sopenharmony_ci data->ci_pdev = NULL; 5198c2ecf20Sopenharmony_ci return ret; 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cistatic int ci_hdrc_imx_remove(struct platform_device *pdev) 5238c2ecf20Sopenharmony_ci{ 5248c2ecf20Sopenharmony_ci struct ci_hdrc_imx_data *data = platform_get_drvdata(pdev); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci if (data->supports_runtime_pm) { 5278c2ecf20Sopenharmony_ci pm_runtime_get_sync(&pdev->dev); 5288c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 5298c2ecf20Sopenharmony_ci pm_runtime_put_noidle(&pdev->dev); 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci if (data->ci_pdev) 5328c2ecf20Sopenharmony_ci ci_hdrc_remove_device(data->ci_pdev); 5338c2ecf20Sopenharmony_ci if (data->override_phy_control) 5348c2ecf20Sopenharmony_ci usb_phy_shutdown(data->phy); 5358c2ecf20Sopenharmony_ci if (data->ci_pdev) { 5368c2ecf20Sopenharmony_ci imx_disable_unprepare_clks(&pdev->dev); 5378c2ecf20Sopenharmony_ci if (data->plat_data->flags & CI_HDRC_PMQOS) 5388c2ecf20Sopenharmony_ci cpu_latency_qos_remove_request(&data->pm_qos_req); 5398c2ecf20Sopenharmony_ci if (data->hsic_pad_regulator) 5408c2ecf20Sopenharmony_ci regulator_disable(data->hsic_pad_regulator); 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci return 0; 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic void ci_hdrc_imx_shutdown(struct platform_device *pdev) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci ci_hdrc_imx_remove(pdev); 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cistatic int __maybe_unused imx_controller_suspend(struct device *dev) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 5548c2ecf20Sopenharmony_ci int ret = 0; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci dev_dbg(dev, "at %s\n", __func__); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci ret = imx_usbmisc_hsic_set_clk(data->usbmisc_data, false); 5598c2ecf20Sopenharmony_ci if (ret) { 5608c2ecf20Sopenharmony_ci dev_err(dev, "usbmisc hsic_set_clk failed, ret=%d\n", ret); 5618c2ecf20Sopenharmony_ci return ret; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci imx_disable_unprepare_clks(dev); 5658c2ecf20Sopenharmony_ci if (data->plat_data->flags & CI_HDRC_PMQOS) 5668c2ecf20Sopenharmony_ci cpu_latency_qos_remove_request(&data->pm_qos_req); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci data->in_lpm = true; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci return 0; 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_cistatic int __maybe_unused imx_controller_resume(struct device *dev) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 5768c2ecf20Sopenharmony_ci int ret = 0; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci dev_dbg(dev, "at %s\n", __func__); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if (!data->in_lpm) { 5818c2ecf20Sopenharmony_ci WARN_ON(1); 5828c2ecf20Sopenharmony_ci return 0; 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci if (data->plat_data->flags & CI_HDRC_PMQOS) 5868c2ecf20Sopenharmony_ci cpu_latency_qos_add_request(&data->pm_qos_req, 0); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci ret = imx_prepare_enable_clks(dev); 5898c2ecf20Sopenharmony_ci if (ret) 5908c2ecf20Sopenharmony_ci return ret; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci data->in_lpm = false; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci ret = imx_usbmisc_set_wakeup(data->usbmisc_data, false); 5958c2ecf20Sopenharmony_ci if (ret) { 5968c2ecf20Sopenharmony_ci dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret); 5978c2ecf20Sopenharmony_ci goto clk_disable; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci ret = imx_usbmisc_hsic_set_clk(data->usbmisc_data, true); 6018c2ecf20Sopenharmony_ci if (ret) { 6028c2ecf20Sopenharmony_ci dev_err(dev, "usbmisc hsic_set_clk failed, ret=%d\n", ret); 6038c2ecf20Sopenharmony_ci goto hsic_set_clk_fail; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci return 0; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cihsic_set_clk_fail: 6098c2ecf20Sopenharmony_ci imx_usbmisc_set_wakeup(data->usbmisc_data, true); 6108c2ecf20Sopenharmony_ciclk_disable: 6118c2ecf20Sopenharmony_ci imx_disable_unprepare_clks(dev); 6128c2ecf20Sopenharmony_ci return ret; 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistatic int __maybe_unused ci_hdrc_imx_suspend(struct device *dev) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci int ret; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci if (data->in_lpm) 6228c2ecf20Sopenharmony_ci /* The core's suspend doesn't run */ 6238c2ecf20Sopenharmony_ci return 0; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (device_may_wakeup(dev)) { 6268c2ecf20Sopenharmony_ci ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true); 6278c2ecf20Sopenharmony_ci if (ret) { 6288c2ecf20Sopenharmony_ci dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", 6298c2ecf20Sopenharmony_ci ret); 6308c2ecf20Sopenharmony_ci return ret; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci ret = imx_controller_suspend(dev); 6358c2ecf20Sopenharmony_ci if (ret) 6368c2ecf20Sopenharmony_ci return ret; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci pinctrl_pm_select_sleep_state(dev); 6398c2ecf20Sopenharmony_ci return ret; 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_cistatic int __maybe_unused ci_hdrc_imx_resume(struct device *dev) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 6458c2ecf20Sopenharmony_ci int ret; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci pinctrl_pm_select_default_state(dev); 6488c2ecf20Sopenharmony_ci ret = imx_controller_resume(dev); 6498c2ecf20Sopenharmony_ci if (!ret && data->supports_runtime_pm) { 6508c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 6518c2ecf20Sopenharmony_ci pm_runtime_set_active(dev); 6528c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci return ret; 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic int __maybe_unused ci_hdrc_imx_runtime_suspend(struct device *dev) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); 6618c2ecf20Sopenharmony_ci int ret; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci if (data->in_lpm) { 6648c2ecf20Sopenharmony_ci WARN_ON(1); 6658c2ecf20Sopenharmony_ci return 0; 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true); 6698c2ecf20Sopenharmony_ci if (ret) { 6708c2ecf20Sopenharmony_ci dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret); 6718c2ecf20Sopenharmony_ci return ret; 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci return imx_controller_suspend(dev); 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_cistatic int __maybe_unused ci_hdrc_imx_runtime_resume(struct device *dev) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci return imx_controller_resume(dev); 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistatic const struct dev_pm_ops ci_hdrc_imx_pm_ops = { 6838c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(ci_hdrc_imx_suspend, ci_hdrc_imx_resume) 6848c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(ci_hdrc_imx_runtime_suspend, 6858c2ecf20Sopenharmony_ci ci_hdrc_imx_runtime_resume, NULL) 6868c2ecf20Sopenharmony_ci}; 6878c2ecf20Sopenharmony_cistatic struct platform_driver ci_hdrc_imx_driver = { 6888c2ecf20Sopenharmony_ci .probe = ci_hdrc_imx_probe, 6898c2ecf20Sopenharmony_ci .remove = ci_hdrc_imx_remove, 6908c2ecf20Sopenharmony_ci .shutdown = ci_hdrc_imx_shutdown, 6918c2ecf20Sopenharmony_ci .driver = { 6928c2ecf20Sopenharmony_ci .name = "imx_usb", 6938c2ecf20Sopenharmony_ci .of_match_table = ci_hdrc_imx_dt_ids, 6948c2ecf20Sopenharmony_ci .pm = &ci_hdrc_imx_pm_ops, 6958c2ecf20Sopenharmony_ci }, 6968c2ecf20Sopenharmony_ci}; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_cimodule_platform_driver(ci_hdrc_imx_driver); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:imx-usb"); 7018c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 7028c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("CI HDRC i.MX USB binding"); 7038c2ecf20Sopenharmony_ciMODULE_AUTHOR("Marek Vasut <marex@denx.de>"); 7048c2ecf20Sopenharmony_ciMODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>"); 705