18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * platform.c - DesignWare HS OTG Controller platform driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) Matthijs Kooijman <matthijs@stdin.nl>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
88c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions
98c2ecf20Sopenharmony_ci * are met:
108c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
118c2ecf20Sopenharmony_ci *    notice, this list of conditions, and the following disclaimer,
128c2ecf20Sopenharmony_ci *    without modification.
138c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
148c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
158c2ecf20Sopenharmony_ci *    documentation and/or other materials provided with the distribution.
168c2ecf20Sopenharmony_ci * 3. The names of the above-listed copyright holders may not be used
178c2ecf20Sopenharmony_ci *    to endorse or promote products derived from this software without
188c2ecf20Sopenharmony_ci *    specific prior written permission.
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci * ALTERNATIVELY, this software may be distributed under the terms of the
218c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") as published by the Free Software
228c2ecf20Sopenharmony_ci * Foundation; either version 2 of the License, or (at your option) any
238c2ecf20Sopenharmony_ci * later version.
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
268c2ecf20Sopenharmony_ci * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
278c2ecf20Sopenharmony_ci * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
288c2ecf20Sopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
298c2ecf20Sopenharmony_ci * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
308c2ecf20Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
318c2ecf20Sopenharmony_ci * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
328c2ecf20Sopenharmony_ci * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
338c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
348c2ecf20Sopenharmony_ci * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
358c2ecf20Sopenharmony_ci * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
368c2ecf20Sopenharmony_ci */
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#include <linux/kernel.h>
398c2ecf20Sopenharmony_ci#include <linux/module.h>
408c2ecf20Sopenharmony_ci#include <linux/slab.h>
418c2ecf20Sopenharmony_ci#include <linux/clk.h>
428c2ecf20Sopenharmony_ci#include <linux/device.h>
438c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
448c2ecf20Sopenharmony_ci#include <linux/of_device.h>
458c2ecf20Sopenharmony_ci#include <linux/mutex.h>
468c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
478c2ecf20Sopenharmony_ci#include <linux/phy/phy.h>
488c2ecf20Sopenharmony_ci#include <linux/platform_data/s3c-hsotg.h>
498c2ecf20Sopenharmony_ci#include <linux/reset.h>
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#include <linux/usb/of.h>
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#include "core.h"
548c2ecf20Sopenharmony_ci#include "hcd.h"
558c2ecf20Sopenharmony_ci#include "debug.h"
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic const char dwc2_driver_name[] = "dwc2";
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci/*
608c2ecf20Sopenharmony_ci * Check the dr_mode against the module configuration and hardware
618c2ecf20Sopenharmony_ci * capabilities.
628c2ecf20Sopenharmony_ci *
638c2ecf20Sopenharmony_ci * The hardware, module, and dr_mode, can each be set to host, device,
648c2ecf20Sopenharmony_ci * or otg. Check that all these values are compatible and adjust the
658c2ecf20Sopenharmony_ci * value of dr_mode if possible.
668c2ecf20Sopenharmony_ci *
678c2ecf20Sopenharmony_ci *                      actual
688c2ecf20Sopenharmony_ci *    HW  MOD dr_mode   dr_mode
698c2ecf20Sopenharmony_ci *  ------------------------------
708c2ecf20Sopenharmony_ci *   HST  HST  any    :  HST
718c2ecf20Sopenharmony_ci *   HST  DEV  any    :  ---
728c2ecf20Sopenharmony_ci *   HST  OTG  any    :  HST
738c2ecf20Sopenharmony_ci *
748c2ecf20Sopenharmony_ci *   DEV  HST  any    :  ---
758c2ecf20Sopenharmony_ci *   DEV  DEV  any    :  DEV
768c2ecf20Sopenharmony_ci *   DEV  OTG  any    :  DEV
778c2ecf20Sopenharmony_ci *
788c2ecf20Sopenharmony_ci *   OTG  HST  any    :  HST
798c2ecf20Sopenharmony_ci *   OTG  DEV  any    :  DEV
808c2ecf20Sopenharmony_ci *   OTG  OTG  any    :  dr_mode
818c2ecf20Sopenharmony_ci */
828c2ecf20Sopenharmony_cistatic int dwc2_get_dr_mode(struct dwc2_hsotg *hsotg)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	enum usb_dr_mode mode;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	hsotg->dr_mode = usb_get_dr_mode(hsotg->dev);
878c2ecf20Sopenharmony_ci	if (hsotg->dr_mode == USB_DR_MODE_UNKNOWN)
888c2ecf20Sopenharmony_ci		hsotg->dr_mode = USB_DR_MODE_OTG;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	mode = hsotg->dr_mode;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	if (dwc2_hw_is_device(hsotg)) {
938c2ecf20Sopenharmony_ci		if (IS_ENABLED(CONFIG_USB_DWC2_HOST)) {
948c2ecf20Sopenharmony_ci			dev_err(hsotg->dev,
958c2ecf20Sopenharmony_ci				"Controller does not support host mode.\n");
968c2ecf20Sopenharmony_ci			return -EINVAL;
978c2ecf20Sopenharmony_ci		}
988c2ecf20Sopenharmony_ci		mode = USB_DR_MODE_PERIPHERAL;
998c2ecf20Sopenharmony_ci	} else if (dwc2_hw_is_host(hsotg)) {
1008c2ecf20Sopenharmony_ci		if (IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL)) {
1018c2ecf20Sopenharmony_ci			dev_err(hsotg->dev,
1028c2ecf20Sopenharmony_ci				"Controller does not support device mode.\n");
1038c2ecf20Sopenharmony_ci			return -EINVAL;
1048c2ecf20Sopenharmony_ci		}
1058c2ecf20Sopenharmony_ci		mode = USB_DR_MODE_HOST;
1068c2ecf20Sopenharmony_ci	} else {
1078c2ecf20Sopenharmony_ci		if (IS_ENABLED(CONFIG_USB_DWC2_HOST))
1088c2ecf20Sopenharmony_ci			mode = USB_DR_MODE_HOST;
1098c2ecf20Sopenharmony_ci		else if (IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL))
1108c2ecf20Sopenharmony_ci			mode = USB_DR_MODE_PERIPHERAL;
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	if (mode != hsotg->dr_mode) {
1148c2ecf20Sopenharmony_ci		dev_warn(hsotg->dev,
1158c2ecf20Sopenharmony_ci			 "Configuration mismatch. dr_mode forced to %s\n",
1168c2ecf20Sopenharmony_ci			mode == USB_DR_MODE_HOST ? "host" : "device");
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci		hsotg->dr_mode = mode;
1198c2ecf20Sopenharmony_ci	}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	return 0;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	struct platform_device *pdev = to_platform_device(hsotg->dev);
1278c2ecf20Sopenharmony_ci	int ret;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
1308c2ecf20Sopenharmony_ci				    hsotg->supplies);
1318c2ecf20Sopenharmony_ci	if (ret)
1328c2ecf20Sopenharmony_ci		return ret;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	if (hsotg->clk) {
1358c2ecf20Sopenharmony_ci		ret = clk_prepare_enable(hsotg->clk);
1368c2ecf20Sopenharmony_ci		if (ret)
1378c2ecf20Sopenharmony_ci			return ret;
1388c2ecf20Sopenharmony_ci	}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	if (hsotg->uphy) {
1418c2ecf20Sopenharmony_ci		ret = usb_phy_init(hsotg->uphy);
1428c2ecf20Sopenharmony_ci	} else if (hsotg->plat && hsotg->plat->phy_init) {
1438c2ecf20Sopenharmony_ci		ret = hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
1448c2ecf20Sopenharmony_ci	} else {
1458c2ecf20Sopenharmony_ci		ret = phy_init(hsotg->phy);
1468c2ecf20Sopenharmony_ci		if (ret == 0)
1478c2ecf20Sopenharmony_ci			ret = phy_power_on(hsotg->phy);
1488c2ecf20Sopenharmony_ci	}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	return ret;
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci/**
1548c2ecf20Sopenharmony_ci * dwc2_lowlevel_hw_enable - enable platform lowlevel hw resources
1558c2ecf20Sopenharmony_ci * @hsotg: The driver state
1568c2ecf20Sopenharmony_ci *
1578c2ecf20Sopenharmony_ci * A wrapper for platform code responsible for controlling
1588c2ecf20Sopenharmony_ci * low-level USB platform resources (phy, clock, regulators)
1598c2ecf20Sopenharmony_ci */
1608c2ecf20Sopenharmony_ciint dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	int ret = __dwc2_lowlevel_hw_enable(hsotg);
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	if (ret == 0)
1658c2ecf20Sopenharmony_ci		hsotg->ll_hw_enabled = true;
1668c2ecf20Sopenharmony_ci	return ret;
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	struct platform_device *pdev = to_platform_device(hsotg->dev);
1728c2ecf20Sopenharmony_ci	int ret = 0;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	if (hsotg->uphy) {
1758c2ecf20Sopenharmony_ci		usb_phy_shutdown(hsotg->uphy);
1768c2ecf20Sopenharmony_ci	} else if (hsotg->plat && hsotg->plat->phy_exit) {
1778c2ecf20Sopenharmony_ci		ret = hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);
1788c2ecf20Sopenharmony_ci	} else {
1798c2ecf20Sopenharmony_ci		ret = phy_power_off(hsotg->phy);
1808c2ecf20Sopenharmony_ci		if (ret == 0)
1818c2ecf20Sopenharmony_ci			ret = phy_exit(hsotg->phy);
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci	if (ret)
1848c2ecf20Sopenharmony_ci		return ret;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	if (hsotg->clk)
1878c2ecf20Sopenharmony_ci		clk_disable_unprepare(hsotg->clk);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	return regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci/**
1938c2ecf20Sopenharmony_ci * dwc2_lowlevel_hw_disable - disable platform lowlevel hw resources
1948c2ecf20Sopenharmony_ci * @hsotg: The driver state
1958c2ecf20Sopenharmony_ci *
1968c2ecf20Sopenharmony_ci * A wrapper for platform code responsible for controlling
1978c2ecf20Sopenharmony_ci * low-level USB platform resources (phy, clock, regulators)
1988c2ecf20Sopenharmony_ci */
1998c2ecf20Sopenharmony_ciint dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	int ret = __dwc2_lowlevel_hw_disable(hsotg);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	if (ret == 0)
2048c2ecf20Sopenharmony_ci		hsotg->ll_hw_enabled = false;
2058c2ecf20Sopenharmony_ci	return ret;
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	int i, ret;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	hsotg->reset = devm_reset_control_get_optional(hsotg->dev, "dwc2");
2138c2ecf20Sopenharmony_ci	if (IS_ERR(hsotg->reset)) {
2148c2ecf20Sopenharmony_ci		ret = PTR_ERR(hsotg->reset);
2158c2ecf20Sopenharmony_ci		dev_err(hsotg->dev, "error getting reset control %d\n", ret);
2168c2ecf20Sopenharmony_ci		return ret;
2178c2ecf20Sopenharmony_ci	}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	reset_control_deassert(hsotg->reset);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	hsotg->reset_ecc = devm_reset_control_get_optional(hsotg->dev, "dwc2-ecc");
2228c2ecf20Sopenharmony_ci	if (IS_ERR(hsotg->reset_ecc)) {
2238c2ecf20Sopenharmony_ci		ret = PTR_ERR(hsotg->reset_ecc);
2248c2ecf20Sopenharmony_ci		dev_err(hsotg->dev, "error getting reset control for ecc %d\n", ret);
2258c2ecf20Sopenharmony_ci		return ret;
2268c2ecf20Sopenharmony_ci	}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	reset_control_deassert(hsotg->reset_ecc);
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	/*
2318c2ecf20Sopenharmony_ci	 * Attempt to find a generic PHY, then look for an old style
2328c2ecf20Sopenharmony_ci	 * USB PHY and then fall back to pdata
2338c2ecf20Sopenharmony_ci	 */
2348c2ecf20Sopenharmony_ci	hsotg->phy = devm_phy_get(hsotg->dev, "usb2-phy");
2358c2ecf20Sopenharmony_ci	if (IS_ERR(hsotg->phy)) {
2368c2ecf20Sopenharmony_ci		ret = PTR_ERR(hsotg->phy);
2378c2ecf20Sopenharmony_ci		switch (ret) {
2388c2ecf20Sopenharmony_ci		case -ENODEV:
2398c2ecf20Sopenharmony_ci		case -ENOSYS:
2408c2ecf20Sopenharmony_ci			hsotg->phy = NULL;
2418c2ecf20Sopenharmony_ci			break;
2428c2ecf20Sopenharmony_ci		case -EPROBE_DEFER:
2438c2ecf20Sopenharmony_ci			return ret;
2448c2ecf20Sopenharmony_ci		default:
2458c2ecf20Sopenharmony_ci			dev_err(hsotg->dev, "error getting phy %d\n", ret);
2468c2ecf20Sopenharmony_ci			return ret;
2478c2ecf20Sopenharmony_ci		}
2488c2ecf20Sopenharmony_ci	}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	if (!hsotg->phy) {
2518c2ecf20Sopenharmony_ci		hsotg->uphy = devm_usb_get_phy(hsotg->dev, USB_PHY_TYPE_USB2);
2528c2ecf20Sopenharmony_ci		if (IS_ERR(hsotg->uphy)) {
2538c2ecf20Sopenharmony_ci			ret = PTR_ERR(hsotg->uphy);
2548c2ecf20Sopenharmony_ci			switch (ret) {
2558c2ecf20Sopenharmony_ci			case -ENODEV:
2568c2ecf20Sopenharmony_ci			case -ENXIO:
2578c2ecf20Sopenharmony_ci				hsotg->uphy = NULL;
2588c2ecf20Sopenharmony_ci				break;
2598c2ecf20Sopenharmony_ci			case -EPROBE_DEFER:
2608c2ecf20Sopenharmony_ci				return ret;
2618c2ecf20Sopenharmony_ci			default:
2628c2ecf20Sopenharmony_ci				dev_err(hsotg->dev, "error getting usb phy %d\n",
2638c2ecf20Sopenharmony_ci					ret);
2648c2ecf20Sopenharmony_ci				return ret;
2658c2ecf20Sopenharmony_ci			}
2668c2ecf20Sopenharmony_ci		}
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	hsotg->plat = dev_get_platdata(hsotg->dev);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	/* Clock */
2728c2ecf20Sopenharmony_ci	hsotg->clk = devm_clk_get_optional(hsotg->dev, "otg");
2738c2ecf20Sopenharmony_ci	if (IS_ERR(hsotg->clk)) {
2748c2ecf20Sopenharmony_ci		dev_err(hsotg->dev, "cannot get otg clock\n");
2758c2ecf20Sopenharmony_ci		return PTR_ERR(hsotg->clk);
2768c2ecf20Sopenharmony_ci	}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	/* Regulators */
2798c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++)
2808c2ecf20Sopenharmony_ci		hsotg->supplies[i].supply = dwc2_hsotg_supply_names[i];
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	ret = devm_regulator_bulk_get(hsotg->dev, ARRAY_SIZE(hsotg->supplies),
2838c2ecf20Sopenharmony_ci				      hsotg->supplies);
2848c2ecf20Sopenharmony_ci	if (ret) {
2858c2ecf20Sopenharmony_ci		if (ret != -EPROBE_DEFER)
2868c2ecf20Sopenharmony_ci			dev_err(hsotg->dev, "failed to request supplies: %d\n",
2878c2ecf20Sopenharmony_ci				ret);
2888c2ecf20Sopenharmony_ci		return ret;
2898c2ecf20Sopenharmony_ci	}
2908c2ecf20Sopenharmony_ci	return 0;
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci/**
2948c2ecf20Sopenharmony_ci * dwc2_driver_remove() - Called when the DWC_otg core is unregistered with the
2958c2ecf20Sopenharmony_ci * DWC_otg driver
2968c2ecf20Sopenharmony_ci *
2978c2ecf20Sopenharmony_ci * @dev: Platform device
2988c2ecf20Sopenharmony_ci *
2998c2ecf20Sopenharmony_ci * This routine is called, for example, when the rmmod command is executed. The
3008c2ecf20Sopenharmony_ci * device may or may not be electrically present. If it is present, the driver
3018c2ecf20Sopenharmony_ci * stops device processing. Any resources used on behalf of this device are
3028c2ecf20Sopenharmony_ci * freed.
3038c2ecf20Sopenharmony_ci */
3048c2ecf20Sopenharmony_cistatic int dwc2_driver_remove(struct platform_device *dev)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	dwc2_debugfs_exit(hsotg);
3098c2ecf20Sopenharmony_ci	if (hsotg->hcd_enabled)
3108c2ecf20Sopenharmony_ci		dwc2_hcd_remove(hsotg);
3118c2ecf20Sopenharmony_ci	if (hsotg->gadget_enabled)
3128c2ecf20Sopenharmony_ci		dwc2_hsotg_remove(hsotg);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	dwc2_drd_exit(hsotg);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	if (hsotg->params.activate_stm_id_vb_detection)
3178c2ecf20Sopenharmony_ci		regulator_disable(hsotg->usb33d);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	if (hsotg->ll_hw_enabled)
3208c2ecf20Sopenharmony_ci		dwc2_lowlevel_hw_disable(hsotg);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	reset_control_assert(hsotg->reset);
3238c2ecf20Sopenharmony_ci	reset_control_assert(hsotg->reset_ecc);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	return 0;
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci/**
3298c2ecf20Sopenharmony_ci * dwc2_driver_shutdown() - Called on device shutdown
3308c2ecf20Sopenharmony_ci *
3318c2ecf20Sopenharmony_ci * @dev: Platform device
3328c2ecf20Sopenharmony_ci *
3338c2ecf20Sopenharmony_ci * In specific conditions (involving usb hubs) dwc2 devices can create a
3348c2ecf20Sopenharmony_ci * lot of interrupts, even to the point of overwhelming devices running
3358c2ecf20Sopenharmony_ci * at low frequencies. Some devices need to do special clock handling
3368c2ecf20Sopenharmony_ci * at shutdown-time which may bring the system clock below the threshold
3378c2ecf20Sopenharmony_ci * of being able to handle the dwc2 interrupts. Disabling dwc2-irqs
3388c2ecf20Sopenharmony_ci * prevents reboots/poweroffs from getting stuck in such cases.
3398c2ecf20Sopenharmony_ci */
3408c2ecf20Sopenharmony_cistatic void dwc2_driver_shutdown(struct platform_device *dev)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	dwc2_disable_global_interrupts(hsotg);
3458c2ecf20Sopenharmony_ci	synchronize_irq(hsotg->irq);
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci/**
3498c2ecf20Sopenharmony_ci * dwc2_check_core_endianness() - Returns true if core and AHB have
3508c2ecf20Sopenharmony_ci * opposite endianness.
3518c2ecf20Sopenharmony_ci * @hsotg:	Programming view of the DWC_otg controller.
3528c2ecf20Sopenharmony_ci */
3538c2ecf20Sopenharmony_cistatic bool dwc2_check_core_endianness(struct dwc2_hsotg *hsotg)
3548c2ecf20Sopenharmony_ci{
3558c2ecf20Sopenharmony_ci	u32 snpsid;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	snpsid = ioread32(hsotg->regs + GSNPSID);
3588c2ecf20Sopenharmony_ci	if ((snpsid & GSNPSID_ID_MASK) == DWC2_OTG_ID ||
3598c2ecf20Sopenharmony_ci	    (snpsid & GSNPSID_ID_MASK) == DWC2_FS_IOT_ID ||
3608c2ecf20Sopenharmony_ci	    (snpsid & GSNPSID_ID_MASK) == DWC2_HS_IOT_ID)
3618c2ecf20Sopenharmony_ci		return false;
3628c2ecf20Sopenharmony_ci	return true;
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci/**
3668c2ecf20Sopenharmony_ci * Check core version
3678c2ecf20Sopenharmony_ci *
3688c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller
3698c2ecf20Sopenharmony_ci *
3708c2ecf20Sopenharmony_ci */
3718c2ecf20Sopenharmony_ciint dwc2_check_core_version(struct dwc2_hsotg *hsotg)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	struct dwc2_hw_params *hw = &hsotg->hw_params;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	/*
3768c2ecf20Sopenharmony_ci	 * Attempt to ensure this device is really a DWC_otg Controller.
3778c2ecf20Sopenharmony_ci	 * Read and verify the GSNPSID register contents. The value should be
3788c2ecf20Sopenharmony_ci	 * 0x45f4xxxx, 0x5531xxxx or 0x5532xxxx
3798c2ecf20Sopenharmony_ci	 */
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	hw->snpsid = dwc2_readl(hsotg, GSNPSID);
3828c2ecf20Sopenharmony_ci	if ((hw->snpsid & GSNPSID_ID_MASK) != DWC2_OTG_ID &&
3838c2ecf20Sopenharmony_ci	    (hw->snpsid & GSNPSID_ID_MASK) != DWC2_FS_IOT_ID &&
3848c2ecf20Sopenharmony_ci	    (hw->snpsid & GSNPSID_ID_MASK) != DWC2_HS_IOT_ID) {
3858c2ecf20Sopenharmony_ci		dev_err(hsotg->dev, "Bad value for GSNPSID: 0x%08x\n",
3868c2ecf20Sopenharmony_ci			hw->snpsid);
3878c2ecf20Sopenharmony_ci		return -ENODEV;
3888c2ecf20Sopenharmony_ci	}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	dev_dbg(hsotg->dev, "Core Release: %1x.%1x%1x%1x (snpsid=%x)\n",
3918c2ecf20Sopenharmony_ci		hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf,
3928c2ecf20Sopenharmony_ci		hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid);
3938c2ecf20Sopenharmony_ci	return 0;
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci/**
3978c2ecf20Sopenharmony_ci * dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg
3988c2ecf20Sopenharmony_ci * driver
3998c2ecf20Sopenharmony_ci *
4008c2ecf20Sopenharmony_ci * @dev: Platform device
4018c2ecf20Sopenharmony_ci *
4028c2ecf20Sopenharmony_ci * This routine creates the driver components required to control the device
4038c2ecf20Sopenharmony_ci * (core, HCD, and PCD) and initializes the device. The driver components are
4048c2ecf20Sopenharmony_ci * stored in a dwc2_hsotg structure. A reference to the dwc2_hsotg is saved
4058c2ecf20Sopenharmony_ci * in the device private data. This allows the driver to access the dwc2_hsotg
4068c2ecf20Sopenharmony_ci * structure on subsequent calls to driver methods for this device.
4078c2ecf20Sopenharmony_ci */
4088c2ecf20Sopenharmony_cistatic int dwc2_driver_probe(struct platform_device *dev)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	struct dwc2_hsotg *hsotg;
4118c2ecf20Sopenharmony_ci	struct resource *res;
4128c2ecf20Sopenharmony_ci	int retval;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	hsotg = devm_kzalloc(&dev->dev, sizeof(*hsotg), GFP_KERNEL);
4158c2ecf20Sopenharmony_ci	if (!hsotg)
4168c2ecf20Sopenharmony_ci		return -ENOMEM;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	hsotg->dev = &dev->dev;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	/*
4218c2ecf20Sopenharmony_ci	 * Use reasonable defaults so platforms don't have to provide these.
4228c2ecf20Sopenharmony_ci	 */
4238c2ecf20Sopenharmony_ci	if (!dev->dev.dma_mask)
4248c2ecf20Sopenharmony_ci		dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
4258c2ecf20Sopenharmony_ci	retval = dma_set_coherent_mask(&dev->dev, DMA_BIT_MASK(32));
4268c2ecf20Sopenharmony_ci	if (retval) {
4278c2ecf20Sopenharmony_ci		dev_err(&dev->dev, "can't set coherent DMA mask: %d\n", retval);
4288c2ecf20Sopenharmony_ci		return retval;
4298c2ecf20Sopenharmony_ci	}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	hsotg->regs = devm_platform_get_and_ioremap_resource(dev, 0, &res);
4328c2ecf20Sopenharmony_ci	if (IS_ERR(hsotg->regs))
4338c2ecf20Sopenharmony_ci		return PTR_ERR(hsotg->regs);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n",
4368c2ecf20Sopenharmony_ci		(unsigned long)res->start, hsotg->regs);
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	retval = dwc2_lowlevel_hw_init(hsotg);
4398c2ecf20Sopenharmony_ci	if (retval)
4408c2ecf20Sopenharmony_ci		return retval;
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	spin_lock_init(&hsotg->lock);
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	hsotg->irq = platform_get_irq(dev, 0);
4458c2ecf20Sopenharmony_ci	if (hsotg->irq < 0)
4468c2ecf20Sopenharmony_ci		return hsotg->irq;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	dev_dbg(hsotg->dev, "registering common handler for irq%d\n",
4498c2ecf20Sopenharmony_ci		hsotg->irq);
4508c2ecf20Sopenharmony_ci	retval = devm_request_irq(hsotg->dev, hsotg->irq,
4518c2ecf20Sopenharmony_ci				  dwc2_handle_common_intr, IRQF_SHARED,
4528c2ecf20Sopenharmony_ci				  dev_name(hsotg->dev), hsotg);
4538c2ecf20Sopenharmony_ci	if (retval)
4548c2ecf20Sopenharmony_ci		return retval;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	hsotg->vbus_supply = devm_regulator_get_optional(hsotg->dev, "vbus");
4578c2ecf20Sopenharmony_ci	if (IS_ERR(hsotg->vbus_supply)) {
4588c2ecf20Sopenharmony_ci		retval = PTR_ERR(hsotg->vbus_supply);
4598c2ecf20Sopenharmony_ci		hsotg->vbus_supply = NULL;
4608c2ecf20Sopenharmony_ci		if (retval != -ENODEV)
4618c2ecf20Sopenharmony_ci			return retval;
4628c2ecf20Sopenharmony_ci	}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	retval = dwc2_lowlevel_hw_enable(hsotg);
4658c2ecf20Sopenharmony_ci	if (retval)
4668c2ecf20Sopenharmony_ci		return retval;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	hsotg->needs_byte_swap = dwc2_check_core_endianness(hsotg);
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	retval = dwc2_get_dr_mode(hsotg);
4718c2ecf20Sopenharmony_ci	if (retval)
4728c2ecf20Sopenharmony_ci		goto error;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	hsotg->need_phy_for_wake =
4758c2ecf20Sopenharmony_ci		of_property_read_bool(dev->dev.of_node,
4768c2ecf20Sopenharmony_ci				      "snps,need-phy-for-wake");
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	/*
4798c2ecf20Sopenharmony_ci	 * Before performing any core related operations
4808c2ecf20Sopenharmony_ci	 * check core version.
4818c2ecf20Sopenharmony_ci	 */
4828c2ecf20Sopenharmony_ci	retval = dwc2_check_core_version(hsotg);
4838c2ecf20Sopenharmony_ci	if (retval)
4848c2ecf20Sopenharmony_ci		goto error;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	/*
4878c2ecf20Sopenharmony_ci	 * Reset before dwc2_get_hwparams() then it could get power-on real
4888c2ecf20Sopenharmony_ci	 * reset value form registers.
4898c2ecf20Sopenharmony_ci	 */
4908c2ecf20Sopenharmony_ci	retval = dwc2_core_reset(hsotg, false);
4918c2ecf20Sopenharmony_ci	if (retval)
4928c2ecf20Sopenharmony_ci		goto error;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	/* Detect config values from hardware */
4958c2ecf20Sopenharmony_ci	retval = dwc2_get_hwparams(hsotg);
4968c2ecf20Sopenharmony_ci	if (retval)
4978c2ecf20Sopenharmony_ci		goto error;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	/*
5008c2ecf20Sopenharmony_ci	 * For OTG cores, set the force mode bits to reflect the value
5018c2ecf20Sopenharmony_ci	 * of dr_mode. Force mode bits should not be touched at any
5028c2ecf20Sopenharmony_ci	 * other time after this.
5038c2ecf20Sopenharmony_ci	 */
5048c2ecf20Sopenharmony_ci	dwc2_force_dr_mode(hsotg);
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	retval = dwc2_init_params(hsotg);
5078c2ecf20Sopenharmony_ci	if (retval)
5088c2ecf20Sopenharmony_ci		goto error;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	if (hsotg->params.activate_stm_id_vb_detection) {
5118c2ecf20Sopenharmony_ci		u32 ggpio;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci		hsotg->usb33d = devm_regulator_get(hsotg->dev, "usb33d");
5148c2ecf20Sopenharmony_ci		if (IS_ERR(hsotg->usb33d)) {
5158c2ecf20Sopenharmony_ci			retval = PTR_ERR(hsotg->usb33d);
5168c2ecf20Sopenharmony_ci			if (retval != -EPROBE_DEFER)
5178c2ecf20Sopenharmony_ci				dev_err(hsotg->dev,
5188c2ecf20Sopenharmony_ci					"failed to request usb33d supply: %d\n",
5198c2ecf20Sopenharmony_ci					retval);
5208c2ecf20Sopenharmony_ci			goto error;
5218c2ecf20Sopenharmony_ci		}
5228c2ecf20Sopenharmony_ci		retval = regulator_enable(hsotg->usb33d);
5238c2ecf20Sopenharmony_ci		if (retval) {
5248c2ecf20Sopenharmony_ci			dev_err(hsotg->dev,
5258c2ecf20Sopenharmony_ci				"failed to enable usb33d supply: %d\n", retval);
5268c2ecf20Sopenharmony_ci			goto error;
5278c2ecf20Sopenharmony_ci		}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci		ggpio = dwc2_readl(hsotg, GGPIO);
5308c2ecf20Sopenharmony_ci		ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN;
5318c2ecf20Sopenharmony_ci		ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN;
5328c2ecf20Sopenharmony_ci		dwc2_writel(hsotg, ggpio, GGPIO);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci		/* ID/VBUS detection startup time */
5358c2ecf20Sopenharmony_ci		usleep_range(5000, 7000);
5368c2ecf20Sopenharmony_ci	}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	retval = dwc2_drd_init(hsotg);
5398c2ecf20Sopenharmony_ci	if (retval) {
5408c2ecf20Sopenharmony_ci		if (retval != -EPROBE_DEFER)
5418c2ecf20Sopenharmony_ci			dev_err(hsotg->dev, "failed to initialize dual-role\n");
5428c2ecf20Sopenharmony_ci		goto error_init;
5438c2ecf20Sopenharmony_ci	}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	if (hsotg->dr_mode != USB_DR_MODE_HOST) {
5468c2ecf20Sopenharmony_ci		retval = dwc2_gadget_init(hsotg);
5478c2ecf20Sopenharmony_ci		if (retval)
5488c2ecf20Sopenharmony_ci			goto error_drd;
5498c2ecf20Sopenharmony_ci		hsotg->gadget_enabled = 1;
5508c2ecf20Sopenharmony_ci	}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	/*
5538c2ecf20Sopenharmony_ci	 * If we need PHY for wakeup we must be wakeup capable.
5548c2ecf20Sopenharmony_ci	 * When we have a device that can wake without the PHY we
5558c2ecf20Sopenharmony_ci	 * can adjust this condition.
5568c2ecf20Sopenharmony_ci	 */
5578c2ecf20Sopenharmony_ci	if (hsotg->need_phy_for_wake)
5588c2ecf20Sopenharmony_ci		device_set_wakeup_capable(&dev->dev, true);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	hsotg->reset_phy_on_wake =
5618c2ecf20Sopenharmony_ci		of_property_read_bool(dev->dev.of_node,
5628c2ecf20Sopenharmony_ci				      "snps,reset-phy-on-wake");
5638c2ecf20Sopenharmony_ci	if (hsotg->reset_phy_on_wake && !hsotg->phy) {
5648c2ecf20Sopenharmony_ci		dev_warn(hsotg->dev,
5658c2ecf20Sopenharmony_ci			 "Quirk reset-phy-on-wake only supports generic PHYs\n");
5668c2ecf20Sopenharmony_ci		hsotg->reset_phy_on_wake = false;
5678c2ecf20Sopenharmony_ci	}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) {
5708c2ecf20Sopenharmony_ci		retval = dwc2_hcd_init(hsotg);
5718c2ecf20Sopenharmony_ci		if (retval) {
5728c2ecf20Sopenharmony_ci			if (hsotg->gadget_enabled)
5738c2ecf20Sopenharmony_ci				dwc2_hsotg_remove(hsotg);
5748c2ecf20Sopenharmony_ci			goto error_drd;
5758c2ecf20Sopenharmony_ci		}
5768c2ecf20Sopenharmony_ci		hsotg->hcd_enabled = 1;
5778c2ecf20Sopenharmony_ci	}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	platform_set_drvdata(dev, hsotg);
5808c2ecf20Sopenharmony_ci	hsotg->hibernated = 0;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	dwc2_debugfs_init(hsotg);
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	/* Gadget code manages lowlevel hw on its own */
5858c2ecf20Sopenharmony_ci	if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
5868c2ecf20Sopenharmony_ci		dwc2_lowlevel_hw_disable(hsotg);
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \
5898c2ecf20Sopenharmony_ci	IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
5908c2ecf20Sopenharmony_ci	/* Postponed adding a new gadget to the udc class driver list */
5918c2ecf20Sopenharmony_ci	if (hsotg->gadget_enabled) {
5928c2ecf20Sopenharmony_ci		retval = usb_add_gadget_udc(hsotg->dev, &hsotg->gadget);
5938c2ecf20Sopenharmony_ci		if (retval) {
5948c2ecf20Sopenharmony_ci			hsotg->gadget.udc = NULL;
5958c2ecf20Sopenharmony_ci			dwc2_hsotg_remove(hsotg);
5968c2ecf20Sopenharmony_ci			goto error_debugfs;
5978c2ecf20Sopenharmony_ci		}
5988c2ecf20Sopenharmony_ci	}
5998c2ecf20Sopenharmony_ci#endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */
6008c2ecf20Sopenharmony_ci	return 0;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \
6038c2ecf20Sopenharmony_ci	IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
6048c2ecf20Sopenharmony_cierror_debugfs:
6058c2ecf20Sopenharmony_ci	dwc2_debugfs_exit(hsotg);
6068c2ecf20Sopenharmony_ci	if (hsotg->hcd_enabled)
6078c2ecf20Sopenharmony_ci		dwc2_hcd_remove(hsotg);
6088c2ecf20Sopenharmony_ci#endif
6098c2ecf20Sopenharmony_cierror_drd:
6108c2ecf20Sopenharmony_ci	dwc2_drd_exit(hsotg);
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_cierror_init:
6138c2ecf20Sopenharmony_ci	if (hsotg->params.activate_stm_id_vb_detection)
6148c2ecf20Sopenharmony_ci		regulator_disable(hsotg->usb33d);
6158c2ecf20Sopenharmony_cierror:
6168c2ecf20Sopenharmony_ci	if (hsotg->ll_hw_enabled)
6178c2ecf20Sopenharmony_ci		dwc2_lowlevel_hw_disable(hsotg);
6188c2ecf20Sopenharmony_ci	return retval;
6198c2ecf20Sopenharmony_ci}
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_cistatic int __maybe_unused dwc2_suspend(struct device *dev)
6228c2ecf20Sopenharmony_ci{
6238c2ecf20Sopenharmony_ci	struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
6248c2ecf20Sopenharmony_ci	bool is_device_mode = dwc2_is_device_mode(dwc2);
6258c2ecf20Sopenharmony_ci	int ret = 0;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	if (is_device_mode)
6288c2ecf20Sopenharmony_ci		dwc2_hsotg_suspend(dwc2);
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	dwc2_drd_suspend(dwc2);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	if (dwc2->params.activate_stm_id_vb_detection) {
6338c2ecf20Sopenharmony_ci		unsigned long flags;
6348c2ecf20Sopenharmony_ci		u32 ggpio, gotgctl;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci		/*
6378c2ecf20Sopenharmony_ci		 * Need to force the mode to the current mode to avoid Mode
6388c2ecf20Sopenharmony_ci		 * Mismatch Interrupt when ID detection will be disabled.
6398c2ecf20Sopenharmony_ci		 */
6408c2ecf20Sopenharmony_ci		dwc2_force_mode(dwc2, !is_device_mode);
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci		spin_lock_irqsave(&dwc2->lock, flags);
6438c2ecf20Sopenharmony_ci		gotgctl = dwc2_readl(dwc2, GOTGCTL);
6448c2ecf20Sopenharmony_ci		/* bypass debounce filter, enable overrides */
6458c2ecf20Sopenharmony_ci		gotgctl |= GOTGCTL_DBNCE_FLTR_BYPASS;
6468c2ecf20Sopenharmony_ci		gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN;
6478c2ecf20Sopenharmony_ci		/* Force A / B session if needed */
6488c2ecf20Sopenharmony_ci		if (gotgctl & GOTGCTL_ASESVLD)
6498c2ecf20Sopenharmony_ci			gotgctl |= GOTGCTL_AVALOVAL;
6508c2ecf20Sopenharmony_ci		if (gotgctl & GOTGCTL_BSESVLD)
6518c2ecf20Sopenharmony_ci			gotgctl |= GOTGCTL_BVALOVAL;
6528c2ecf20Sopenharmony_ci		dwc2_writel(dwc2, gotgctl, GOTGCTL);
6538c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&dwc2->lock, flags);
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci		ggpio = dwc2_readl(dwc2, GGPIO);
6568c2ecf20Sopenharmony_ci		ggpio &= ~GGPIO_STM32_OTG_GCCFG_IDEN;
6578c2ecf20Sopenharmony_ci		ggpio &= ~GGPIO_STM32_OTG_GCCFG_VBDEN;
6588c2ecf20Sopenharmony_ci		dwc2_writel(dwc2, ggpio, GGPIO);
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci		regulator_disable(dwc2->usb33d);
6618c2ecf20Sopenharmony_ci	}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	if (dwc2->ll_hw_enabled &&
6648c2ecf20Sopenharmony_ci	    (is_device_mode || dwc2_host_can_poweroff_phy(dwc2))) {
6658c2ecf20Sopenharmony_ci		ret = __dwc2_lowlevel_hw_disable(dwc2);
6668c2ecf20Sopenharmony_ci		dwc2->phy_off_for_suspend = true;
6678c2ecf20Sopenharmony_ci	}
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	return ret;
6708c2ecf20Sopenharmony_ci}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_cistatic int __maybe_unused dwc2_resume(struct device *dev)
6738c2ecf20Sopenharmony_ci{
6748c2ecf20Sopenharmony_ci	struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
6758c2ecf20Sopenharmony_ci	int ret = 0;
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	if (dwc2->phy_off_for_suspend && dwc2->ll_hw_enabled) {
6788c2ecf20Sopenharmony_ci		ret = __dwc2_lowlevel_hw_enable(dwc2);
6798c2ecf20Sopenharmony_ci		if (ret)
6808c2ecf20Sopenharmony_ci			return ret;
6818c2ecf20Sopenharmony_ci	}
6828c2ecf20Sopenharmony_ci	dwc2->phy_off_for_suspend = false;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	if (dwc2->params.activate_stm_id_vb_detection) {
6858c2ecf20Sopenharmony_ci		unsigned long flags;
6868c2ecf20Sopenharmony_ci		u32 ggpio, gotgctl;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci		ret = regulator_enable(dwc2->usb33d);
6898c2ecf20Sopenharmony_ci		if (ret)
6908c2ecf20Sopenharmony_ci			return ret;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci		ggpio = dwc2_readl(dwc2, GGPIO);
6938c2ecf20Sopenharmony_ci		ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN;
6948c2ecf20Sopenharmony_ci		ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN;
6958c2ecf20Sopenharmony_ci		dwc2_writel(dwc2, ggpio, GGPIO);
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci		/* ID/VBUS detection startup time */
6988c2ecf20Sopenharmony_ci		usleep_range(5000, 7000);
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci		spin_lock_irqsave(&dwc2->lock, flags);
7018c2ecf20Sopenharmony_ci		gotgctl = dwc2_readl(dwc2, GOTGCTL);
7028c2ecf20Sopenharmony_ci		gotgctl &= ~GOTGCTL_DBNCE_FLTR_BYPASS;
7038c2ecf20Sopenharmony_ci		gotgctl &= ~(GOTGCTL_BVALOEN | GOTGCTL_AVALOEN |
7048c2ecf20Sopenharmony_ci			     GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL);
7058c2ecf20Sopenharmony_ci		dwc2_writel(dwc2, gotgctl, GOTGCTL);
7068c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&dwc2->lock, flags);
7078c2ecf20Sopenharmony_ci	}
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	/* Need to restore FORCEDEVMODE/FORCEHOSTMODE */
7108c2ecf20Sopenharmony_ci	dwc2_force_dr_mode(dwc2);
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	dwc2_drd_resume(dwc2);
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	if (dwc2_is_device_mode(dwc2))
7158c2ecf20Sopenharmony_ci		ret = dwc2_hsotg_resume(dwc2);
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	return ret;
7188c2ecf20Sopenharmony_ci}
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_cistatic const struct dev_pm_ops dwc2_dev_pm_ops = {
7218c2ecf20Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(dwc2_suspend, dwc2_resume)
7228c2ecf20Sopenharmony_ci};
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_cistatic struct platform_driver dwc2_platform_driver = {
7258c2ecf20Sopenharmony_ci	.driver = {
7268c2ecf20Sopenharmony_ci		.name = dwc2_driver_name,
7278c2ecf20Sopenharmony_ci		.of_match_table = dwc2_of_match_table,
7288c2ecf20Sopenharmony_ci		.pm = &dwc2_dev_pm_ops,
7298c2ecf20Sopenharmony_ci	},
7308c2ecf20Sopenharmony_ci	.probe = dwc2_driver_probe,
7318c2ecf20Sopenharmony_ci	.remove = dwc2_driver_remove,
7328c2ecf20Sopenharmony_ci	.shutdown = dwc2_driver_shutdown,
7338c2ecf20Sopenharmony_ci};
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_cimodule_platform_driver(dwc2_platform_driver);
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DESIGNWARE HS OTG Platform Glue");
7388c2ecf20Sopenharmony_ciMODULE_AUTHOR("Matthijs Kooijman <matthijs@stdin.nl>");
7398c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
740