15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 2197ba5f4SPaul Zimmerman /* 3197ba5f4SPaul Zimmerman * platform.c - DesignWare HS OTG Controller platform driver 4197ba5f4SPaul Zimmerman * 5197ba5f4SPaul Zimmerman * Copyright (C) Matthijs Kooijman <matthijs@stdin.nl> 6197ba5f4SPaul Zimmerman * 7197ba5f4SPaul Zimmerman * Redistribution and use in source and binary forms, with or without 8197ba5f4SPaul Zimmerman * modification, are permitted provided that the following conditions 9197ba5f4SPaul Zimmerman * are met: 10197ba5f4SPaul Zimmerman * 1. Redistributions of source code must retain the above copyright 11197ba5f4SPaul Zimmerman * notice, this list of conditions, and the following disclaimer, 12197ba5f4SPaul Zimmerman * without modification. 13197ba5f4SPaul Zimmerman * 2. Redistributions in binary form must reproduce the above copyright 14197ba5f4SPaul Zimmerman * notice, this list of conditions and the following disclaimer in the 15197ba5f4SPaul Zimmerman * documentation and/or other materials provided with the distribution. 16197ba5f4SPaul Zimmerman * 3. The names of the above-listed copyright holders may not be used 17197ba5f4SPaul Zimmerman * to endorse or promote products derived from this software without 18197ba5f4SPaul Zimmerman * specific prior written permission. 19197ba5f4SPaul Zimmerman * 20197ba5f4SPaul Zimmerman * ALTERNATIVELY, this software may be distributed under the terms of the 21197ba5f4SPaul Zimmerman * GNU General Public License ("GPL") as published by the Free Software 22197ba5f4SPaul Zimmerman * Foundation; either version 2 of the License, or (at your option) any 23197ba5f4SPaul Zimmerman * later version. 24197ba5f4SPaul Zimmerman * 25197ba5f4SPaul Zimmerman * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 26197ba5f4SPaul Zimmerman * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 27197ba5f4SPaul Zimmerman * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28197ba5f4SPaul Zimmerman * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 29197ba5f4SPaul Zimmerman * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 30197ba5f4SPaul Zimmerman * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 31197ba5f4SPaul Zimmerman * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 32197ba5f4SPaul Zimmerman * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 33197ba5f4SPaul Zimmerman * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 34197ba5f4SPaul Zimmerman * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35197ba5f4SPaul Zimmerman * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36197ba5f4SPaul Zimmerman */ 37197ba5f4SPaul Zimmerman 38197ba5f4SPaul Zimmerman #include <linux/kernel.h> 39197ba5f4SPaul Zimmerman #include <linux/module.h> 40197ba5f4SPaul Zimmerman #include <linux/slab.h> 4109a75e85SMarek Szyprowski #include <linux/clk.h> 42197ba5f4SPaul Zimmerman #include <linux/device.h> 43197ba5f4SPaul Zimmerman #include <linux/dma-mapping.h> 44197ba5f4SPaul Zimmerman #include <linux/of_device.h> 457ad8096eSMarek Szyprowski #include <linux/mutex.h> 46197ba5f4SPaul Zimmerman #include <linux/platform_device.h> 4709a75e85SMarek Szyprowski #include <linux/phy/phy.h> 4809a75e85SMarek Szyprowski #include <linux/platform_data/s3c-hsotg.h> 4983f8da56SDinh Nguyen #include <linux/reset.h> 50197ba5f4SPaul Zimmerman 51c0155b9dSKever Yang #include <linux/usb/of.h> 52c0155b9dSKever Yang 53197ba5f4SPaul Zimmerman #include "core.h" 54197ba5f4SPaul Zimmerman #include "hcd.h" 55f91eea44SMian Yousaf Kaukab #include "debug.h" 56197ba5f4SPaul Zimmerman 57197ba5f4SPaul Zimmerman static const char dwc2_driver_name[] = "dwc2"; 58197ba5f4SPaul Zimmerman 595268ed9dSJohn Youn /* 605268ed9dSJohn Youn * Check the dr_mode against the module configuration and hardware 615268ed9dSJohn Youn * capabilities. 625268ed9dSJohn Youn * 635268ed9dSJohn Youn * The hardware, module, and dr_mode, can each be set to host, device, 645268ed9dSJohn Youn * or otg. Check that all these values are compatible and adjust the 655268ed9dSJohn Youn * value of dr_mode if possible. 665268ed9dSJohn Youn * 675268ed9dSJohn Youn * actual 685268ed9dSJohn Youn * HW MOD dr_mode dr_mode 695268ed9dSJohn Youn * ------------------------------ 705268ed9dSJohn Youn * HST HST any : HST 715268ed9dSJohn Youn * HST DEV any : --- 725268ed9dSJohn Youn * HST OTG any : HST 735268ed9dSJohn Youn * 745268ed9dSJohn Youn * DEV HST any : --- 755268ed9dSJohn Youn * DEV DEV any : DEV 765268ed9dSJohn Youn * DEV OTG any : DEV 775268ed9dSJohn Youn * 785268ed9dSJohn Youn * OTG HST any : HST 795268ed9dSJohn Youn * OTG DEV any : DEV 805268ed9dSJohn Youn * OTG OTG any : dr_mode 815268ed9dSJohn Youn */ 825268ed9dSJohn Youn static int dwc2_get_dr_mode(struct dwc2_hsotg *hsotg) 835268ed9dSJohn Youn { 845268ed9dSJohn Youn enum usb_dr_mode mode; 855268ed9dSJohn Youn 865268ed9dSJohn Youn hsotg->dr_mode = usb_get_dr_mode(hsotg->dev); 875268ed9dSJohn Youn if (hsotg->dr_mode == USB_DR_MODE_UNKNOWN) 885268ed9dSJohn Youn hsotg->dr_mode = USB_DR_MODE_OTG; 895268ed9dSJohn Youn 905268ed9dSJohn Youn mode = hsotg->dr_mode; 915268ed9dSJohn Youn 925268ed9dSJohn Youn if (dwc2_hw_is_device(hsotg)) { 935268ed9dSJohn Youn if (IS_ENABLED(CONFIG_USB_DWC2_HOST)) { 945268ed9dSJohn Youn dev_err(hsotg->dev, 955268ed9dSJohn Youn "Controller does not support host mode.\n"); 965268ed9dSJohn Youn return -EINVAL; 975268ed9dSJohn Youn } 985268ed9dSJohn Youn mode = USB_DR_MODE_PERIPHERAL; 995268ed9dSJohn Youn } else if (dwc2_hw_is_host(hsotg)) { 1005268ed9dSJohn Youn if (IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL)) { 1015268ed9dSJohn Youn dev_err(hsotg->dev, 1025268ed9dSJohn Youn "Controller does not support device mode.\n"); 1035268ed9dSJohn Youn return -EINVAL; 1045268ed9dSJohn Youn } 1055268ed9dSJohn Youn mode = USB_DR_MODE_HOST; 1065268ed9dSJohn Youn } else { 1075268ed9dSJohn Youn if (IS_ENABLED(CONFIG_USB_DWC2_HOST)) 1085268ed9dSJohn Youn mode = USB_DR_MODE_HOST; 1095268ed9dSJohn Youn else if (IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL)) 1105268ed9dSJohn Youn mode = USB_DR_MODE_PERIPHERAL; 1115268ed9dSJohn Youn } 1125268ed9dSJohn Youn 1135268ed9dSJohn Youn if (mode != hsotg->dr_mode) { 1145268ed9dSJohn Youn dev_warn(hsotg->dev, 1155268ed9dSJohn Youn "Configuration mismatch. dr_mode forced to %s\n", 1165268ed9dSJohn Youn mode == USB_DR_MODE_HOST ? "host" : "device"); 1175268ed9dSJohn Youn 1185268ed9dSJohn Youn hsotg->dr_mode = mode; 1195268ed9dSJohn Youn } 1205268ed9dSJohn Youn 1215268ed9dSJohn Youn return 0; 1225268ed9dSJohn Youn } 1235268ed9dSJohn Youn 12409a75e85SMarek Szyprowski static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg) 12509a75e85SMarek Szyprowski { 12609a75e85SMarek Szyprowski struct platform_device *pdev = to_platform_device(hsotg->dev); 12709a75e85SMarek Szyprowski int ret; 12809a75e85SMarek Szyprowski 12909a75e85SMarek Szyprowski ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), 13009a75e85SMarek Szyprowski hsotg->supplies); 13109a75e85SMarek Szyprowski if (ret) 13209a75e85SMarek Szyprowski return ret; 13309a75e85SMarek Szyprowski 1348aa90cf2SStefan Wahren if (hsotg->clk) { 13509a75e85SMarek Szyprowski ret = clk_prepare_enable(hsotg->clk); 13609a75e85SMarek Szyprowski if (ret) 13709a75e85SMarek Szyprowski return ret; 1388aa90cf2SStefan Wahren } 13909a75e85SMarek Szyprowski 14034c0887fSJohn Youn if (hsotg->uphy) { 14109a75e85SMarek Szyprowski ret = usb_phy_init(hsotg->uphy); 14234c0887fSJohn Youn } else if (hsotg->plat && hsotg->plat->phy_init) { 14309a75e85SMarek Szyprowski ret = hsotg->plat->phy_init(pdev, hsotg->plat->phy_type); 14434c0887fSJohn Youn } else { 14509a75e85SMarek Szyprowski ret = phy_power_on(hsotg->phy); 14609a75e85SMarek Szyprowski if (ret == 0) 14709a75e85SMarek Szyprowski ret = phy_init(hsotg->phy); 14809a75e85SMarek Szyprowski } 14909a75e85SMarek Szyprowski 15009a75e85SMarek Szyprowski return ret; 15109a75e85SMarek Szyprowski } 15209a75e85SMarek Szyprowski 15309a75e85SMarek Szyprowski /** 15409a75e85SMarek Szyprowski * dwc2_lowlevel_hw_enable - enable platform lowlevel hw resources 15509a75e85SMarek Szyprowski * @hsotg: The driver state 15609a75e85SMarek Szyprowski * 15709a75e85SMarek Szyprowski * A wrapper for platform code responsible for controlling 15809a75e85SMarek Szyprowski * low-level USB platform resources (phy, clock, regulators) 15909a75e85SMarek Szyprowski */ 16009a75e85SMarek Szyprowski int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg) 16109a75e85SMarek Szyprowski { 16209a75e85SMarek Szyprowski int ret = __dwc2_lowlevel_hw_enable(hsotg); 16309a75e85SMarek Szyprowski 16409a75e85SMarek Szyprowski if (ret == 0) 16509a75e85SMarek Szyprowski hsotg->ll_hw_enabled = true; 16609a75e85SMarek Szyprowski return ret; 16709a75e85SMarek Szyprowski } 16809a75e85SMarek Szyprowski 16909a75e85SMarek Szyprowski static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg) 17009a75e85SMarek Szyprowski { 17109a75e85SMarek Szyprowski struct platform_device *pdev = to_platform_device(hsotg->dev); 17209a75e85SMarek Szyprowski int ret = 0; 17309a75e85SMarek Szyprowski 17434c0887fSJohn Youn if (hsotg->uphy) { 17509a75e85SMarek Szyprowski usb_phy_shutdown(hsotg->uphy); 17634c0887fSJohn Youn } else if (hsotg->plat && hsotg->plat->phy_exit) { 17709a75e85SMarek Szyprowski ret = hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); 17834c0887fSJohn Youn } else { 17909a75e85SMarek Szyprowski ret = phy_exit(hsotg->phy); 18009a75e85SMarek Szyprowski if (ret == 0) 18109a75e85SMarek Szyprowski ret = phy_power_off(hsotg->phy); 18209a75e85SMarek Szyprowski } 18309a75e85SMarek Szyprowski if (ret) 18409a75e85SMarek Szyprowski return ret; 18509a75e85SMarek Szyprowski 1868aa90cf2SStefan Wahren if (hsotg->clk) 18709a75e85SMarek Szyprowski clk_disable_unprepare(hsotg->clk); 18809a75e85SMarek Szyprowski 18909a75e85SMarek Szyprowski ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), 19009a75e85SMarek Szyprowski hsotg->supplies); 19109a75e85SMarek Szyprowski 19209a75e85SMarek Szyprowski return ret; 19309a75e85SMarek Szyprowski } 19409a75e85SMarek Szyprowski 19509a75e85SMarek Szyprowski /** 19609a75e85SMarek Szyprowski * dwc2_lowlevel_hw_disable - disable platform lowlevel hw resources 19709a75e85SMarek Szyprowski * @hsotg: The driver state 19809a75e85SMarek Szyprowski * 19909a75e85SMarek Szyprowski * A wrapper for platform code responsible for controlling 20009a75e85SMarek Szyprowski * low-level USB platform resources (phy, clock, regulators) 20109a75e85SMarek Szyprowski */ 20209a75e85SMarek Szyprowski int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg) 20309a75e85SMarek Szyprowski { 20409a75e85SMarek Szyprowski int ret = __dwc2_lowlevel_hw_disable(hsotg); 20509a75e85SMarek Szyprowski 20609a75e85SMarek Szyprowski if (ret == 0) 20709a75e85SMarek Szyprowski hsotg->ll_hw_enabled = false; 20809a75e85SMarek Szyprowski return ret; 20909a75e85SMarek Szyprowski } 21009a75e85SMarek Szyprowski 21109a75e85SMarek Szyprowski static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) 21209a75e85SMarek Szyprowski { 21309a75e85SMarek Szyprowski int i, ret; 21409a75e85SMarek Szyprowski 21583f8da56SDinh Nguyen hsotg->reset = devm_reset_control_get_optional(hsotg->dev, "dwc2"); 21683f8da56SDinh Nguyen if (IS_ERR(hsotg->reset)) { 21783f8da56SDinh Nguyen ret = PTR_ERR(hsotg->reset); 2188ec32c38SPhilipp Zabel dev_err(hsotg->dev, "error getting reset control %d\n", ret); 21983f8da56SDinh Nguyen return ret; 22083f8da56SDinh Nguyen } 22183f8da56SDinh Nguyen 22283f8da56SDinh Nguyen reset_control_deassert(hsotg->reset); 22383f8da56SDinh Nguyen 224f2830ad4SDinh Nguyen hsotg->reset_ecc = devm_reset_control_get_optional(hsotg->dev, "dwc2-ecc"); 225f2830ad4SDinh Nguyen if (IS_ERR(hsotg->reset_ecc)) { 226f2830ad4SDinh Nguyen ret = PTR_ERR(hsotg->reset_ecc); 227f2830ad4SDinh Nguyen dev_err(hsotg->dev, "error getting reset control for ecc %d\n", ret); 228f2830ad4SDinh Nguyen return ret; 229f2830ad4SDinh Nguyen } 230f2830ad4SDinh Nguyen 231f2830ad4SDinh Nguyen reset_control_deassert(hsotg->reset_ecc); 232f2830ad4SDinh Nguyen 23309a75e85SMarek Szyprowski /* 23409a75e85SMarek Szyprowski * Attempt to find a generic PHY, then look for an old style 23509a75e85SMarek Szyprowski * USB PHY and then fall back to pdata 23609a75e85SMarek Szyprowski */ 23709a75e85SMarek Szyprowski hsotg->phy = devm_phy_get(hsotg->dev, "usb2-phy"); 23809a75e85SMarek Szyprowski if (IS_ERR(hsotg->phy)) { 2396c2dad69SStefan Wahren ret = PTR_ERR(hsotg->phy); 2406c2dad69SStefan Wahren switch (ret) { 2416c2dad69SStefan Wahren case -ENODEV: 2426c2dad69SStefan Wahren case -ENOSYS: 24309a75e85SMarek Szyprowski hsotg->phy = NULL; 2446c2dad69SStefan Wahren break; 2456c2dad69SStefan Wahren case -EPROBE_DEFER: 2466c2dad69SStefan Wahren return ret; 2476c2dad69SStefan Wahren default: 2486c2dad69SStefan Wahren dev_err(hsotg->dev, "error getting phy %d\n", ret); 2496c2dad69SStefan Wahren return ret; 25009a75e85SMarek Szyprowski } 2516c2dad69SStefan Wahren } 2526c2dad69SStefan Wahren 2536c2dad69SStefan Wahren if (!hsotg->phy) { 2546c2dad69SStefan Wahren hsotg->uphy = devm_usb_get_phy(hsotg->dev, USB_PHY_TYPE_USB2); 2556c2dad69SStefan Wahren if (IS_ERR(hsotg->uphy)) { 2566c2dad69SStefan Wahren ret = PTR_ERR(hsotg->uphy); 2576c2dad69SStefan Wahren switch (ret) { 2586c2dad69SStefan Wahren case -ENODEV: 2596c2dad69SStefan Wahren case -ENXIO: 2606c2dad69SStefan Wahren hsotg->uphy = NULL; 2616c2dad69SStefan Wahren break; 2626c2dad69SStefan Wahren case -EPROBE_DEFER: 2636c2dad69SStefan Wahren return ret; 2646c2dad69SStefan Wahren default: 2656c2dad69SStefan Wahren dev_err(hsotg->dev, "error getting usb phy %d\n", 2666c2dad69SStefan Wahren ret); 2676c2dad69SStefan Wahren return ret; 2686c2dad69SStefan Wahren } 2696c2dad69SStefan Wahren } 2706c2dad69SStefan Wahren } 2716c2dad69SStefan Wahren 2726c2dad69SStefan Wahren hsotg->plat = dev_get_platdata(hsotg->dev); 27309a75e85SMarek Szyprowski 27409a75e85SMarek Szyprowski /* Clock */ 27560722c4eSChunfeng Yun hsotg->clk = devm_clk_get_optional(hsotg->dev, "otg"); 27609a75e85SMarek Szyprowski if (IS_ERR(hsotg->clk)) { 27760722c4eSChunfeng Yun dev_err(hsotg->dev, "cannot get otg clock\n"); 27860722c4eSChunfeng Yun return PTR_ERR(hsotg->clk); 27909a75e85SMarek Szyprowski } 28009a75e85SMarek Szyprowski 28109a75e85SMarek Szyprowski /* Regulators */ 28209a75e85SMarek Szyprowski for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++) 28309a75e85SMarek Szyprowski hsotg->supplies[i].supply = dwc2_hsotg_supply_names[i]; 28409a75e85SMarek Szyprowski 28509a75e85SMarek Szyprowski ret = devm_regulator_bulk_get(hsotg->dev, ARRAY_SIZE(hsotg->supplies), 28609a75e85SMarek Szyprowski hsotg->supplies); 28709a75e85SMarek Szyprowski if (ret) { 2888e11a977SMarek Szyprowski if (ret != -EPROBE_DEFER) 2898e11a977SMarek Szyprowski dev_err(hsotg->dev, "failed to request supplies: %d\n", 2908e11a977SMarek Szyprowski ret); 29109a75e85SMarek Szyprowski return ret; 29209a75e85SMarek Szyprowski } 29309a75e85SMarek Szyprowski return 0; 29409a75e85SMarek Szyprowski } 29509a75e85SMarek Szyprowski 296197ba5f4SPaul Zimmerman /** 297197ba5f4SPaul Zimmerman * dwc2_driver_remove() - Called when the DWC_otg core is unregistered with the 298197ba5f4SPaul Zimmerman * DWC_otg driver 299197ba5f4SPaul Zimmerman * 300197ba5f4SPaul Zimmerman * @dev: Platform device 301197ba5f4SPaul Zimmerman * 302197ba5f4SPaul Zimmerman * This routine is called, for example, when the rmmod command is executed. The 303197ba5f4SPaul Zimmerman * device may or may not be electrically present. If it is present, the driver 304197ba5f4SPaul Zimmerman * stops device processing. Any resources used on behalf of this device are 305197ba5f4SPaul Zimmerman * freed. 306197ba5f4SPaul Zimmerman */ 307197ba5f4SPaul Zimmerman static int dwc2_driver_remove(struct platform_device *dev) 308197ba5f4SPaul Zimmerman { 309197ba5f4SPaul Zimmerman struct dwc2_hsotg *hsotg = platform_get_drvdata(dev); 310197ba5f4SPaul Zimmerman 311f91eea44SMian Yousaf Kaukab dwc2_debugfs_exit(hsotg); 312e39af88fSMarek Szyprowski if (hsotg->hcd_enabled) 313197ba5f4SPaul Zimmerman dwc2_hcd_remove(hsotg); 314e39af88fSMarek Szyprowski if (hsotg->gadget_enabled) 3151f91b4ccSFelipe Balbi dwc2_hsotg_remove(hsotg); 316197ba5f4SPaul Zimmerman 317a415083aSAmelie Delaunay if (hsotg->params.activate_stm_id_vb_detection) 318a415083aSAmelie Delaunay regulator_disable(hsotg->usb33d); 319a415083aSAmelie Delaunay 32009a75e85SMarek Szyprowski if (hsotg->ll_hw_enabled) 32109a75e85SMarek Szyprowski dwc2_lowlevel_hw_disable(hsotg); 32209a75e85SMarek Szyprowski 32383f8da56SDinh Nguyen reset_control_assert(hsotg->reset); 324f2830ad4SDinh Nguyen reset_control_assert(hsotg->reset_ecc); 32583f8da56SDinh Nguyen 326197ba5f4SPaul Zimmerman return 0; 327197ba5f4SPaul Zimmerman } 328197ba5f4SPaul Zimmerman 329a40a0031SHeiko Stübner /** 330a40a0031SHeiko Stübner * dwc2_driver_shutdown() - Called on device shutdown 331a40a0031SHeiko Stübner * 332a40a0031SHeiko Stübner * @dev: Platform device 333a40a0031SHeiko Stübner * 334a40a0031SHeiko Stübner * In specific conditions (involving usb hubs) dwc2 devices can create a 335a40a0031SHeiko Stübner * lot of interrupts, even to the point of overwhelming devices running 336a40a0031SHeiko Stübner * at low frequencies. Some devices need to do special clock handling 337a40a0031SHeiko Stübner * at shutdown-time which may bring the system clock below the threshold 338a40a0031SHeiko Stübner * of being able to handle the dwc2 interrupts. Disabling dwc2-irqs 339a40a0031SHeiko Stübner * prevents reboots/poweroffs from getting stuck in such cases. 340a40a0031SHeiko Stübner */ 341a40a0031SHeiko Stübner static void dwc2_driver_shutdown(struct platform_device *dev) 342a40a0031SHeiko Stübner { 343a40a0031SHeiko Stübner struct dwc2_hsotg *hsotg = platform_get_drvdata(dev); 344a40a0031SHeiko Stübner 3454fdf228cSMinas Harutyunyan dwc2_disable_global_interrupts(hsotg); 3464fdf228cSMinas Harutyunyan synchronize_irq(hsotg->irq); 347a40a0031SHeiko Stübner } 348a40a0031SHeiko Stübner 349197ba5f4SPaul Zimmerman /** 350fe369e18SGevorg Sahakyan * dwc2_check_core_endianness() - Returns true if core and AHB have 351fe369e18SGevorg Sahakyan * opposite endianness. 352fe369e18SGevorg Sahakyan * @hsotg: Programming view of the DWC_otg controller. 353fe369e18SGevorg Sahakyan */ 354fe369e18SGevorg Sahakyan static bool dwc2_check_core_endianness(struct dwc2_hsotg *hsotg) 355fe369e18SGevorg Sahakyan { 356fe369e18SGevorg Sahakyan u32 snpsid; 357fe369e18SGevorg Sahakyan 358fe369e18SGevorg Sahakyan snpsid = ioread32(hsotg->regs + GSNPSID); 359fe369e18SGevorg Sahakyan if ((snpsid & GSNPSID_ID_MASK) == DWC2_OTG_ID || 360fe369e18SGevorg Sahakyan (snpsid & GSNPSID_ID_MASK) == DWC2_FS_IOT_ID || 361fe369e18SGevorg Sahakyan (snpsid & GSNPSID_ID_MASK) == DWC2_HS_IOT_ID) 362fe369e18SGevorg Sahakyan return false; 363fe369e18SGevorg Sahakyan return true; 364fe369e18SGevorg Sahakyan } 365fe369e18SGevorg Sahakyan 366fe369e18SGevorg Sahakyan /** 36765dc2e72SMinas Harutyunyan * Check core version 36865dc2e72SMinas Harutyunyan * 36965dc2e72SMinas Harutyunyan * @hsotg: Programming view of the DWC_otg controller 37065dc2e72SMinas Harutyunyan * 37165dc2e72SMinas Harutyunyan */ 37265dc2e72SMinas Harutyunyan int dwc2_check_core_version(struct dwc2_hsotg *hsotg) 37365dc2e72SMinas Harutyunyan { 37465dc2e72SMinas Harutyunyan struct dwc2_hw_params *hw = &hsotg->hw_params; 37565dc2e72SMinas Harutyunyan 37665dc2e72SMinas Harutyunyan /* 37765dc2e72SMinas Harutyunyan * Attempt to ensure this device is really a DWC_otg Controller. 37865dc2e72SMinas Harutyunyan * Read and verify the GSNPSID register contents. The value should be 37965dc2e72SMinas Harutyunyan * 0x45f4xxxx, 0x5531xxxx or 0x5532xxxx 38065dc2e72SMinas Harutyunyan */ 38165dc2e72SMinas Harutyunyan 38265dc2e72SMinas Harutyunyan hw->snpsid = dwc2_readl(hsotg, GSNPSID); 38365dc2e72SMinas Harutyunyan if ((hw->snpsid & GSNPSID_ID_MASK) != DWC2_OTG_ID && 38465dc2e72SMinas Harutyunyan (hw->snpsid & GSNPSID_ID_MASK) != DWC2_FS_IOT_ID && 38565dc2e72SMinas Harutyunyan (hw->snpsid & GSNPSID_ID_MASK) != DWC2_HS_IOT_ID) { 38665dc2e72SMinas Harutyunyan dev_err(hsotg->dev, "Bad value for GSNPSID: 0x%08x\n", 38765dc2e72SMinas Harutyunyan hw->snpsid); 38865dc2e72SMinas Harutyunyan return -ENODEV; 38965dc2e72SMinas Harutyunyan } 39065dc2e72SMinas Harutyunyan 39165dc2e72SMinas Harutyunyan dev_dbg(hsotg->dev, "Core Release: %1x.%1x%1x%1x (snpsid=%x)\n", 39265dc2e72SMinas Harutyunyan hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf, 39365dc2e72SMinas Harutyunyan hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid); 39465dc2e72SMinas Harutyunyan return 0; 39565dc2e72SMinas Harutyunyan } 39665dc2e72SMinas Harutyunyan 39765dc2e72SMinas Harutyunyan /** 398197ba5f4SPaul Zimmerman * dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg 399197ba5f4SPaul Zimmerman * driver 400197ba5f4SPaul Zimmerman * 401197ba5f4SPaul Zimmerman * @dev: Platform device 402197ba5f4SPaul Zimmerman * 403197ba5f4SPaul Zimmerman * This routine creates the driver components required to control the device 404197ba5f4SPaul Zimmerman * (core, HCD, and PCD) and initializes the device. The driver components are 405197ba5f4SPaul Zimmerman * stored in a dwc2_hsotg structure. A reference to the dwc2_hsotg is saved 406197ba5f4SPaul Zimmerman * in the device private data. This allows the driver to access the dwc2_hsotg 407197ba5f4SPaul Zimmerman * structure on subsequent calls to driver methods for this device. 408197ba5f4SPaul Zimmerman */ 409197ba5f4SPaul Zimmerman static int dwc2_driver_probe(struct platform_device *dev) 410197ba5f4SPaul Zimmerman { 411197ba5f4SPaul Zimmerman struct dwc2_hsotg *hsotg; 412197ba5f4SPaul Zimmerman struct resource *res; 413197ba5f4SPaul Zimmerman int retval; 414197ba5f4SPaul Zimmerman 415197ba5f4SPaul Zimmerman hsotg = devm_kzalloc(&dev->dev, sizeof(*hsotg), GFP_KERNEL); 416197ba5f4SPaul Zimmerman if (!hsotg) 417197ba5f4SPaul Zimmerman return -ENOMEM; 418197ba5f4SPaul Zimmerman 419197ba5f4SPaul Zimmerman hsotg->dev = &dev->dev; 420197ba5f4SPaul Zimmerman 421197ba5f4SPaul Zimmerman /* 422197ba5f4SPaul Zimmerman * Use reasonable defaults so platforms don't have to provide these. 423197ba5f4SPaul Zimmerman */ 424197ba5f4SPaul Zimmerman if (!dev->dev.dma_mask) 425197ba5f4SPaul Zimmerman dev->dev.dma_mask = &dev->dev.coherent_dma_mask; 426197ba5f4SPaul Zimmerman retval = dma_set_coherent_mask(&dev->dev, DMA_BIT_MASK(32)); 42742c6a252SStefan Wahren if (retval) { 42842c6a252SStefan Wahren dev_err(&dev->dev, "can't set coherent DMA mask: %d\n", retval); 429197ba5f4SPaul Zimmerman return retval; 43042c6a252SStefan Wahren } 431197ba5f4SPaul Zimmerman 4325bf7e288SDejin Zheng hsotg->regs = devm_platform_get_and_ioremap_resource(dev, 0, &res); 433197ba5f4SPaul Zimmerman if (IS_ERR(hsotg->regs)) 434197ba5f4SPaul Zimmerman return PTR_ERR(hsotg->regs); 435197ba5f4SPaul Zimmerman 436197ba5f4SPaul Zimmerman dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n", 437197ba5f4SPaul Zimmerman (unsigned long)res->start, hsotg->regs); 438197ba5f4SPaul Zimmerman 43909a75e85SMarek Szyprowski retval = dwc2_lowlevel_hw_init(hsotg); 440ecb176c6SMian Yousaf Kaukab if (retval) 441ecb176c6SMian Yousaf Kaukab return retval; 442ecb176c6SMian Yousaf Kaukab 44309a75e85SMarek Szyprowski spin_lock_init(&hsotg->lock); 44409a75e85SMarek Szyprowski 445a40a0031SHeiko Stübner hsotg->irq = platform_get_irq(dev, 0); 446b33f3706SStephen Boyd if (hsotg->irq < 0) 447a40a0031SHeiko Stübner return hsotg->irq; 448f74875dcSStefan Wahren 449f74875dcSStefan Wahren dev_dbg(hsotg->dev, "registering common handler for irq%d\n", 450a40a0031SHeiko Stübner hsotg->irq); 451a40a0031SHeiko Stübner retval = devm_request_irq(hsotg->dev, hsotg->irq, 452f74875dcSStefan Wahren dwc2_handle_common_intr, IRQF_SHARED, 453f74875dcSStefan Wahren dev_name(hsotg->dev), hsotg); 454f74875dcSStefan Wahren if (retval) 455f74875dcSStefan Wahren return retval; 456f74875dcSStefan Wahren 457e0f681c2SFabrice Gasnier hsotg->vbus_supply = devm_regulator_get_optional(hsotg->dev, "vbus"); 458e0f681c2SFabrice Gasnier if (IS_ERR(hsotg->vbus_supply)) { 459e0f681c2SFabrice Gasnier retval = PTR_ERR(hsotg->vbus_supply); 460e0f681c2SFabrice Gasnier hsotg->vbus_supply = NULL; 461e0f681c2SFabrice Gasnier if (retval != -ENODEV) 462e0f681c2SFabrice Gasnier return retval; 463e0f681c2SFabrice Gasnier } 464e0f681c2SFabrice Gasnier 46509a75e85SMarek Szyprowski retval = dwc2_lowlevel_hw_enable(hsotg); 46609a75e85SMarek Szyprowski if (retval) 46709a75e85SMarek Szyprowski return retval; 46809a75e85SMarek Szyprowski 469d9707490SBruno Meirelles Herrera hsotg->needs_byte_swap = dwc2_check_core_endianness(hsotg); 470d9707490SBruno Meirelles Herrera 4715268ed9dSJohn Youn retval = dwc2_get_dr_mode(hsotg); 4725268ed9dSJohn Youn if (retval) 473a6ef3e02SJohn Youn goto error; 4745268ed9dSJohn Youn 475c846b03fSDouglas Anderson hsotg->need_phy_for_wake = 476c846b03fSDouglas Anderson of_property_read_bool(dev->dev.of_node, 477c846b03fSDouglas Anderson "snps,need-phy-for-wake"); 478c846b03fSDouglas Anderson 47903b32e4cSJohn Youn /* 48065dc2e72SMinas Harutyunyan * Before performing any core related operations 48165dc2e72SMinas Harutyunyan * check core version. 48265dc2e72SMinas Harutyunyan */ 48365dc2e72SMinas Harutyunyan retval = dwc2_check_core_version(hsotg); 48465dc2e72SMinas Harutyunyan if (retval) 48565dc2e72SMinas Harutyunyan goto error; 48665dc2e72SMinas Harutyunyan 48765dc2e72SMinas Harutyunyan /* 48803b32e4cSJohn Youn * Reset before dwc2_get_hwparams() then it could get power-on real 48903b32e4cSJohn Youn * reset value form registers. 49003b32e4cSJohn Youn */ 49113b1f8e2SVardan Mikayelyan retval = dwc2_core_reset(hsotg, false); 49213b1f8e2SVardan Mikayelyan if (retval) 49313b1f8e2SVardan Mikayelyan goto error; 49403b32e4cSJohn Youn 49503b32e4cSJohn Youn /* Detect config values from hardware */ 49609a75e85SMarek Szyprowski retval = dwc2_get_hwparams(hsotg); 49709a75e85SMarek Szyprowski if (retval) 49809a75e85SMarek Szyprowski goto error; 49909a75e85SMarek Szyprowski 50013b1f8e2SVardan Mikayelyan /* 50113b1f8e2SVardan Mikayelyan * For OTG cores, set the force mode bits to reflect the value 50213b1f8e2SVardan Mikayelyan * of dr_mode. Force mode bits should not be touched at any 50313b1f8e2SVardan Mikayelyan * other time after this. 50413b1f8e2SVardan Mikayelyan */ 50525362d31SJohn Youn dwc2_force_dr_mode(hsotg); 506263b7fb5SJohn Youn 507334bbd4eSJohn Youn retval = dwc2_init_params(hsotg); 508334bbd4eSJohn Youn if (retval) 509334bbd4eSJohn Youn goto error; 510334bbd4eSJohn Youn 511a415083aSAmelie Delaunay if (hsotg->params.activate_stm_id_vb_detection) { 512a415083aSAmelie Delaunay u32 ggpio; 513a415083aSAmelie Delaunay 514a415083aSAmelie Delaunay hsotg->usb33d = devm_regulator_get(hsotg->dev, "usb33d"); 515a415083aSAmelie Delaunay if (IS_ERR(hsotg->usb33d)) { 516a415083aSAmelie Delaunay retval = PTR_ERR(hsotg->usb33d); 517a415083aSAmelie Delaunay if (retval != -EPROBE_DEFER) 518a415083aSAmelie Delaunay dev_err(hsotg->dev, 519a415083aSAmelie Delaunay "failed to request usb33d supply: %d\n", 520a415083aSAmelie Delaunay retval); 521a415083aSAmelie Delaunay goto error; 522a415083aSAmelie Delaunay } 523a415083aSAmelie Delaunay retval = regulator_enable(hsotg->usb33d); 524a415083aSAmelie Delaunay if (retval) { 525a415083aSAmelie Delaunay dev_err(hsotg->dev, 526a415083aSAmelie Delaunay "failed to enable usb33d supply: %d\n", retval); 527a415083aSAmelie Delaunay goto error; 528a415083aSAmelie Delaunay } 529a415083aSAmelie Delaunay 530a415083aSAmelie Delaunay ggpio = dwc2_readl(hsotg, GGPIO); 531a415083aSAmelie Delaunay ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN; 532a415083aSAmelie Delaunay ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN; 533a415083aSAmelie Delaunay dwc2_writel(hsotg, ggpio, GGPIO); 534a415083aSAmelie Delaunay } 535a415083aSAmelie Delaunay 536e39af88fSMarek Szyprowski if (hsotg->dr_mode != USB_DR_MODE_HOST) { 537f3768997SVardan Mikayelyan retval = dwc2_gadget_init(hsotg); 538117777b2SDinh Nguyen if (retval) 539a415083aSAmelie Delaunay goto error_init; 540e39af88fSMarek Szyprowski hsotg->gadget_enabled = 1; 541e39af88fSMarek Szyprowski } 542e39af88fSMarek Szyprowski 543c846b03fSDouglas Anderson /* 544c846b03fSDouglas Anderson * If we need PHY for wakeup we must be wakeup capable. 545c846b03fSDouglas Anderson * When we have a device that can wake without the PHY we 546c846b03fSDouglas Anderson * can adjust this condition. 547c846b03fSDouglas Anderson */ 548c846b03fSDouglas Anderson if (hsotg->need_phy_for_wake) 549c846b03fSDouglas Anderson device_set_wakeup_capable(&dev->dev, true); 550c846b03fSDouglas Anderson 551c40cf770SDouglas Anderson hsotg->reset_phy_on_wake = 552c40cf770SDouglas Anderson of_property_read_bool(dev->dev.of_node, 553c40cf770SDouglas Anderson "snps,reset-phy-on-wake"); 554c40cf770SDouglas Anderson if (hsotg->reset_phy_on_wake && !hsotg->phy) { 555c40cf770SDouglas Anderson dev_warn(hsotg->dev, 556c40cf770SDouglas Anderson "Quirk reset-phy-on-wake only supports generic PHYs\n"); 557c40cf770SDouglas Anderson hsotg->reset_phy_on_wake = false; 558c40cf770SDouglas Anderson } 559c40cf770SDouglas Anderson 560e39af88fSMarek Szyprowski if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) { 5614fe160d5SHeiner Kallweit retval = dwc2_hcd_init(hsotg); 562e39af88fSMarek Szyprowski if (retval) { 563e39af88fSMarek Szyprowski if (hsotg->gadget_enabled) 5641f91b4ccSFelipe Balbi dwc2_hsotg_remove(hsotg); 565a415083aSAmelie Delaunay goto error_init; 566e39af88fSMarek Szyprowski } 567e39af88fSMarek Szyprowski hsotg->hcd_enabled = 1; 568e39af88fSMarek Szyprowski } 569197ba5f4SPaul Zimmerman 570197ba5f4SPaul Zimmerman platform_set_drvdata(dev, hsotg); 57120fe4409SVardan Mikayelyan hsotg->hibernated = 0; 572197ba5f4SPaul Zimmerman 573f91eea44SMian Yousaf Kaukab dwc2_debugfs_init(hsotg); 574f91eea44SMian Yousaf Kaukab 57509a75e85SMarek Szyprowski /* Gadget code manages lowlevel hw on its own */ 57609a75e85SMarek Szyprowski if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) 57709a75e85SMarek Szyprowski dwc2_lowlevel_hw_disable(hsotg); 57809a75e85SMarek Szyprowski 579207324a3SMinas Harutyunyan #if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \ 580207324a3SMinas Harutyunyan IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) 581207324a3SMinas Harutyunyan /* Postponed adding a new gadget to the udc class driver list */ 582207324a3SMinas Harutyunyan if (hsotg->gadget_enabled) { 583207324a3SMinas Harutyunyan retval = usb_add_gadget_udc(hsotg->dev, &hsotg->gadget); 584207324a3SMinas Harutyunyan if (retval) { 58533a06f13SMarek Szyprowski hsotg->gadget.udc = NULL; 586207324a3SMinas Harutyunyan dwc2_hsotg_remove(hsotg); 587e1c08cf2SMartin Blumenstingl goto error_debugfs; 588207324a3SMinas Harutyunyan } 589207324a3SMinas Harutyunyan } 590207324a3SMinas Harutyunyan #endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */ 59109a75e85SMarek Szyprowski return 0; 59209a75e85SMarek Szyprowski 593e1c08cf2SMartin Blumenstingl error_debugfs: 594e1c08cf2SMartin Blumenstingl dwc2_debugfs_exit(hsotg); 595e1c08cf2SMartin Blumenstingl if (hsotg->hcd_enabled) 596e1c08cf2SMartin Blumenstingl dwc2_hcd_remove(hsotg); 597a415083aSAmelie Delaunay error_init: 598a415083aSAmelie Delaunay if (hsotg->params.activate_stm_id_vb_detection) 599a415083aSAmelie Delaunay regulator_disable(hsotg->usb33d); 60009a75e85SMarek Szyprowski error: 60133a06f13SMarek Szyprowski if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) 60209a75e85SMarek Szyprowski dwc2_lowlevel_hw_disable(hsotg); 603197ba5f4SPaul Zimmerman return retval; 604197ba5f4SPaul Zimmerman } 605197ba5f4SPaul Zimmerman 606da9f3289SFabio Estevam static int __maybe_unused dwc2_suspend(struct device *dev) 607117777b2SDinh Nguyen { 608bcc06078SDinh Nguyen struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); 609c846b03fSDouglas Anderson bool is_device_mode = dwc2_is_device_mode(dwc2); 610117777b2SDinh Nguyen int ret = 0; 611117777b2SDinh Nguyen 612c846b03fSDouglas Anderson if (is_device_mode) 61309a75e85SMarek Szyprowski dwc2_hsotg_suspend(dwc2); 614135b3c43SYunzhi Li 615a415083aSAmelie Delaunay if (dwc2->params.activate_stm_id_vb_detection) { 616a415083aSAmelie Delaunay unsigned long flags; 617a415083aSAmelie Delaunay u32 ggpio, gotgctl; 618a415083aSAmelie Delaunay 619a415083aSAmelie Delaunay /* 620a415083aSAmelie Delaunay * Need to force the mode to the current mode to avoid Mode 621a415083aSAmelie Delaunay * Mismatch Interrupt when ID detection will be disabled. 622a415083aSAmelie Delaunay */ 623a415083aSAmelie Delaunay dwc2_force_mode(dwc2, !is_device_mode); 624a415083aSAmelie Delaunay 625a415083aSAmelie Delaunay spin_lock_irqsave(&dwc2->lock, flags); 626a415083aSAmelie Delaunay gotgctl = dwc2_readl(dwc2, GOTGCTL); 627a415083aSAmelie Delaunay /* bypass debounce filter, enable overrides */ 628a415083aSAmelie Delaunay gotgctl |= GOTGCTL_DBNCE_FLTR_BYPASS; 629a415083aSAmelie Delaunay gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN; 630a415083aSAmelie Delaunay /* Force A / B session if needed */ 631a415083aSAmelie Delaunay if (gotgctl & GOTGCTL_ASESVLD) 632a415083aSAmelie Delaunay gotgctl |= GOTGCTL_AVALOVAL; 633a415083aSAmelie Delaunay if (gotgctl & GOTGCTL_BSESVLD) 634a415083aSAmelie Delaunay gotgctl |= GOTGCTL_BVALOVAL; 635a415083aSAmelie Delaunay dwc2_writel(dwc2, gotgctl, GOTGCTL); 636a415083aSAmelie Delaunay spin_unlock_irqrestore(&dwc2->lock, flags); 637a415083aSAmelie Delaunay 638a415083aSAmelie Delaunay ggpio = dwc2_readl(dwc2, GGPIO); 639a415083aSAmelie Delaunay ggpio &= ~GGPIO_STM32_OTG_GCCFG_IDEN; 640a415083aSAmelie Delaunay ggpio &= ~GGPIO_STM32_OTG_GCCFG_VBDEN; 641a415083aSAmelie Delaunay dwc2_writel(dwc2, ggpio, GGPIO); 642a415083aSAmelie Delaunay 643a415083aSAmelie Delaunay regulator_disable(dwc2->usb33d); 644a415083aSAmelie Delaunay } 645a415083aSAmelie Delaunay 646c846b03fSDouglas Anderson if (dwc2->ll_hw_enabled && 647c846b03fSDouglas Anderson (is_device_mode || dwc2_host_can_poweroff_phy(dwc2))) { 64809a75e85SMarek Szyprowski ret = __dwc2_lowlevel_hw_disable(dwc2); 649c846b03fSDouglas Anderson dwc2->phy_off_for_suspend = true; 650c846b03fSDouglas Anderson } 65109a75e85SMarek Szyprowski 652117777b2SDinh Nguyen return ret; 653117777b2SDinh Nguyen } 654117777b2SDinh Nguyen 655da9f3289SFabio Estevam static int __maybe_unused dwc2_resume(struct device *dev) 656117777b2SDinh Nguyen { 657bcc06078SDinh Nguyen struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); 658117777b2SDinh Nguyen int ret = 0; 659117777b2SDinh Nguyen 660c846b03fSDouglas Anderson if (dwc2->phy_off_for_suspend && dwc2->ll_hw_enabled) { 66109a75e85SMarek Szyprowski ret = __dwc2_lowlevel_hw_enable(dwc2); 66209a75e85SMarek Szyprowski if (ret) 66309a75e85SMarek Szyprowski return ret; 664135b3c43SYunzhi Li } 665c846b03fSDouglas Anderson dwc2->phy_off_for_suspend = false; 66609a75e85SMarek Szyprowski 667a415083aSAmelie Delaunay if (dwc2->params.activate_stm_id_vb_detection) { 668a415083aSAmelie Delaunay unsigned long flags; 669a415083aSAmelie Delaunay u32 ggpio, gotgctl; 670a415083aSAmelie Delaunay 671a415083aSAmelie Delaunay ret = regulator_enable(dwc2->usb33d); 672a415083aSAmelie Delaunay if (ret) 673a415083aSAmelie Delaunay return ret; 674a415083aSAmelie Delaunay 675a415083aSAmelie Delaunay ggpio = dwc2_readl(dwc2, GGPIO); 676a415083aSAmelie Delaunay ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN; 677a415083aSAmelie Delaunay ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN; 678a415083aSAmelie Delaunay dwc2_writel(dwc2, ggpio, GGPIO); 679a415083aSAmelie Delaunay 680a415083aSAmelie Delaunay /* ID/VBUS detection startup time */ 681a415083aSAmelie Delaunay usleep_range(5000, 7000); 682a415083aSAmelie Delaunay 683a415083aSAmelie Delaunay spin_lock_irqsave(&dwc2->lock, flags); 684a415083aSAmelie Delaunay gotgctl = dwc2_readl(dwc2, GOTGCTL); 685a415083aSAmelie Delaunay gotgctl &= ~GOTGCTL_DBNCE_FLTR_BYPASS; 686a415083aSAmelie Delaunay gotgctl &= ~(GOTGCTL_BVALOEN | GOTGCTL_AVALOEN | 687a415083aSAmelie Delaunay GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL); 688a415083aSAmelie Delaunay dwc2_writel(dwc2, gotgctl, GOTGCTL); 689a415083aSAmelie Delaunay spin_unlock_irqrestore(&dwc2->lock, flags); 690a415083aSAmelie Delaunay } 691a415083aSAmelie Delaunay 692a415083aSAmelie Delaunay /* Need to restore FORCEDEVMODE/FORCEHOSTMODE */ 693a415083aSAmelie Delaunay dwc2_force_dr_mode(dwc2); 694a415083aSAmelie Delaunay 69509a75e85SMarek Szyprowski if (dwc2_is_device_mode(dwc2)) 69609a75e85SMarek Szyprowski ret = dwc2_hsotg_resume(dwc2); 69709a75e85SMarek Szyprowski 698117777b2SDinh Nguyen return ret; 699117777b2SDinh Nguyen } 700117777b2SDinh Nguyen 701bcc06078SDinh Nguyen static const struct dev_pm_ops dwc2_dev_pm_ops = { 702bcc06078SDinh Nguyen SET_SYSTEM_SLEEP_PM_OPS(dwc2_suspend, dwc2_resume) 703bcc06078SDinh Nguyen }; 704bcc06078SDinh Nguyen 705197ba5f4SPaul Zimmerman static struct platform_driver dwc2_platform_driver = { 706197ba5f4SPaul Zimmerman .driver = { 707197ba5f4SPaul Zimmerman .name = dwc2_driver_name, 708197ba5f4SPaul Zimmerman .of_match_table = dwc2_of_match_table, 709bcc06078SDinh Nguyen .pm = &dwc2_dev_pm_ops, 710197ba5f4SPaul Zimmerman }, 711197ba5f4SPaul Zimmerman .probe = dwc2_driver_probe, 712197ba5f4SPaul Zimmerman .remove = dwc2_driver_remove, 713a40a0031SHeiko Stübner .shutdown = dwc2_driver_shutdown, 714197ba5f4SPaul Zimmerman }; 715197ba5f4SPaul Zimmerman 716197ba5f4SPaul Zimmerman module_platform_driver(dwc2_platform_driver); 717197ba5f4SPaul Zimmerman 718197ba5f4SPaul Zimmerman MODULE_DESCRIPTION("DESIGNWARE HS OTG Platform Glue"); 719197ba5f4SPaul Zimmerman MODULE_AUTHOR("Matthijs Kooijman <matthijs@stdin.nl>"); 720197ba5f4SPaul Zimmerman MODULE_LICENSE("Dual BSD/GPL"); 721