18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * USB Glue for Amlogic G12A SoCs
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2019 BayLibre, SAS
68c2ecf20Sopenharmony_ci * Author: Neil Armstrong <narmstrong@baylibre.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci/*
108c2ecf20Sopenharmony_ci * The USB is organized with a glue around the DWC3 Controller IP as :
118c2ecf20Sopenharmony_ci * - Control registers for each USB2 Ports
128c2ecf20Sopenharmony_ci * - Control registers for the USB PHY layer
138c2ecf20Sopenharmony_ci * - SuperSpeed PHY can be enabled only if port is used
148c2ecf20Sopenharmony_ci * - Dynamic OTG switching with ID change interrupt
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/module.h>
188c2ecf20Sopenharmony_ci#include <linux/kernel.h>
198c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
208c2ecf20Sopenharmony_ci#include <linux/clk.h>
218c2ecf20Sopenharmony_ci#include <linux/of.h>
228c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
238c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
248c2ecf20Sopenharmony_ci#include <linux/regmap.h>
258c2ecf20Sopenharmony_ci#include <linux/bitfield.h>
268c2ecf20Sopenharmony_ci#include <linux/bitops.h>
278c2ecf20Sopenharmony_ci#include <linux/reset.h>
288c2ecf20Sopenharmony_ci#include <linux/phy/phy.h>
298c2ecf20Sopenharmony_ci#include <linux/usb/otg.h>
308c2ecf20Sopenharmony_ci#include <linux/usb/role.h>
318c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h>
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/* USB2 Ports Control Registers, offsets are per-port */
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#define U2P_REG_SIZE						0x20
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#define U2P_R0							0x0
388c2ecf20Sopenharmony_ci	#define U2P_R0_HOST_DEVICE				BIT(0)
398c2ecf20Sopenharmony_ci	#define U2P_R0_POWER_OK					BIT(1)
408c2ecf20Sopenharmony_ci	#define U2P_R0_HAST_MODE				BIT(2)
418c2ecf20Sopenharmony_ci	#define U2P_R0_POWER_ON_RESET				BIT(3)
428c2ecf20Sopenharmony_ci	#define U2P_R0_ID_PULLUP				BIT(4)
438c2ecf20Sopenharmony_ci	#define U2P_R0_DRV_VBUS					BIT(5)
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#define U2P_R1							0x4
468c2ecf20Sopenharmony_ci	#define U2P_R1_PHY_READY				BIT(0)
478c2ecf20Sopenharmony_ci	#define U2P_R1_ID_DIG					BIT(1)
488c2ecf20Sopenharmony_ci	#define U2P_R1_OTG_SESSION_VALID			BIT(2)
498c2ecf20Sopenharmony_ci	#define U2P_R1_VBUS_VALID				BIT(3)
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci/* USB Glue Control Registers */
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define G12A_GLUE_OFFSET					0x80
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#define USB_R0							0x00
568c2ecf20Sopenharmony_ci	#define USB_R0_P30_LANE0_TX2RX_LOOPBACK			BIT(17)
578c2ecf20Sopenharmony_ci	#define USB_R0_P30_LANE0_EXT_PCLK_REQ			BIT(18)
588c2ecf20Sopenharmony_ci	#define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK		GENMASK(28, 19)
598c2ecf20Sopenharmony_ci	#define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK		GENMASK(30, 29)
608c2ecf20Sopenharmony_ci	#define USB_R0_U2D_ACT					BIT(31)
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci#define USB_R1							0x04
638c2ecf20Sopenharmony_ci	#define USB_R1_U3H_BIGENDIAN_GS				BIT(0)
648c2ecf20Sopenharmony_ci	#define USB_R1_U3H_PME_ENABLE				BIT(1)
658c2ecf20Sopenharmony_ci	#define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK		GENMASK(4, 2)
668c2ecf20Sopenharmony_ci	#define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK		GENMASK(9, 7)
678c2ecf20Sopenharmony_ci	#define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK		GENMASK(13, 12)
688c2ecf20Sopenharmony_ci	#define USB_R1_U3H_HOST_U3_PORT_DISABLE			BIT(16)
698c2ecf20Sopenharmony_ci	#define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT	BIT(17)
708c2ecf20Sopenharmony_ci	#define USB_R1_U3H_HOST_MSI_ENABLE			BIT(18)
718c2ecf20Sopenharmony_ci	#define USB_R1_U3H_FLADJ_30MHZ_REG_MASK			GENMASK(24, 19)
728c2ecf20Sopenharmony_ci	#define USB_R1_P30_PCS_TX_SWING_FULL_MASK		GENMASK(31, 25)
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci#define USB_R2							0x08
758c2ecf20Sopenharmony_ci	#define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK		GENMASK(25, 20)
768c2ecf20Sopenharmony_ci	#define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK		GENMASK(31, 26)
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci#define USB_R3							0x0c
798c2ecf20Sopenharmony_ci	#define USB_R3_P30_SSC_ENABLE				BIT(0)
808c2ecf20Sopenharmony_ci	#define USB_R3_P30_SSC_RANGE_MASK			GENMASK(3, 1)
818c2ecf20Sopenharmony_ci	#define USB_R3_P30_SSC_REF_CLK_SEL_MASK			GENMASK(12, 4)
828c2ecf20Sopenharmony_ci	#define USB_R3_P30_REF_SSP_EN				BIT(13)
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci#define USB_R4							0x10
858c2ecf20Sopenharmony_ci	#define USB_R4_P21_PORT_RESET_0				BIT(0)
868c2ecf20Sopenharmony_ci	#define USB_R4_P21_SLEEP_M0				BIT(1)
878c2ecf20Sopenharmony_ci	#define USB_R4_MEM_PD_MASK				GENMASK(3, 2)
888c2ecf20Sopenharmony_ci	#define USB_R4_P21_ONLY					BIT(4)
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci#define USB_R5							0x14
918c2ecf20Sopenharmony_ci	#define USB_R5_ID_DIG_SYNC				BIT(0)
928c2ecf20Sopenharmony_ci	#define USB_R5_ID_DIG_REG				BIT(1)
938c2ecf20Sopenharmony_ci	#define USB_R5_ID_DIG_CFG_MASK				GENMASK(3, 2)
948c2ecf20Sopenharmony_ci	#define USB_R5_ID_DIG_EN_0				BIT(4)
958c2ecf20Sopenharmony_ci	#define USB_R5_ID_DIG_EN_1				BIT(5)
968c2ecf20Sopenharmony_ci	#define USB_R5_ID_DIG_CURR				BIT(6)
978c2ecf20Sopenharmony_ci	#define USB_R5_ID_DIG_IRQ				BIT(7)
988c2ecf20Sopenharmony_ci	#define USB_R5_ID_DIG_TH_MASK				GENMASK(15, 8)
998c2ecf20Sopenharmony_ci	#define USB_R5_ID_DIG_CNT_MASK				GENMASK(23, 16)
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci#define PHY_COUNT						3
1028c2ecf20Sopenharmony_ci#define USB2_OTG_PHY						1
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic struct clk_bulk_data meson_gxl_clocks[] = {
1058c2ecf20Sopenharmony_ci	{ .id = "usb_ctrl" },
1068c2ecf20Sopenharmony_ci	{ .id = "ddr" },
1078c2ecf20Sopenharmony_ci};
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic struct clk_bulk_data meson_g12a_clocks[] = {
1108c2ecf20Sopenharmony_ci	{ .id = NULL },
1118c2ecf20Sopenharmony_ci};
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic struct clk_bulk_data meson_a1_clocks[] = {
1148c2ecf20Sopenharmony_ci	{ .id = "usb_ctrl" },
1158c2ecf20Sopenharmony_ci	{ .id = "usb_bus" },
1168c2ecf20Sopenharmony_ci	{ .id = "xtal_usb_ctrl" },
1178c2ecf20Sopenharmony_ci};
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic const char * const meson_gxm_phy_names[] = {
1208c2ecf20Sopenharmony_ci	"usb2-phy0", "usb2-phy1", "usb2-phy2",
1218c2ecf20Sopenharmony_ci};
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic const char * const meson_g12a_phy_names[] = {
1248c2ecf20Sopenharmony_ci	"usb2-phy0", "usb2-phy1", "usb3-phy0",
1258c2ecf20Sopenharmony_ci};
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci/*
1288c2ecf20Sopenharmony_ci * Amlogic A1 has a single physical PHY, in slot 1, but still has the
1298c2ecf20Sopenharmony_ci * two U2 PHY controls register blocks like G12A.
1308c2ecf20Sopenharmony_ci * AXG has the similar scheme, thus needs the same tweak.
1318c2ecf20Sopenharmony_ci * Handling the first PHY on slot 1 would need a large amount of code
1328c2ecf20Sopenharmony_ci * changes, and the current management is generic enough to handle it
1338c2ecf20Sopenharmony_ci * correctly when only the "usb2-phy1" phy is specified on-par with the
1348c2ecf20Sopenharmony_ci * DT bindings.
1358c2ecf20Sopenharmony_ci */
1368c2ecf20Sopenharmony_cistatic const char * const meson_a1_phy_names[] = {
1378c2ecf20Sopenharmony_ci	"usb2-phy0", "usb2-phy1"
1388c2ecf20Sopenharmony_ci};
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistruct dwc3_meson_g12a;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistruct dwc3_meson_g12a_drvdata {
1438c2ecf20Sopenharmony_ci	bool otg_switch_supported;
1448c2ecf20Sopenharmony_ci	bool otg_phy_host_port_disable;
1458c2ecf20Sopenharmony_ci	struct clk_bulk_data *clks;
1468c2ecf20Sopenharmony_ci	int num_clks;
1478c2ecf20Sopenharmony_ci	const char * const *phy_names;
1488c2ecf20Sopenharmony_ci	int num_phys;
1498c2ecf20Sopenharmony_ci	int (*setup_regmaps)(struct dwc3_meson_g12a *priv, void __iomem *base);
1508c2ecf20Sopenharmony_ci	int (*usb2_init_phy)(struct dwc3_meson_g12a *priv, int i,
1518c2ecf20Sopenharmony_ci			     enum phy_mode mode);
1528c2ecf20Sopenharmony_ci	int (*set_phy_mode)(struct dwc3_meson_g12a *priv, int i,
1538c2ecf20Sopenharmony_ci			    enum phy_mode mode);
1548c2ecf20Sopenharmony_ci	int (*usb_init)(struct dwc3_meson_g12a *priv);
1558c2ecf20Sopenharmony_ci	int (*usb_post_init)(struct dwc3_meson_g12a *priv);
1568c2ecf20Sopenharmony_ci};
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic int dwc3_meson_gxl_setup_regmaps(struct dwc3_meson_g12a *priv,
1598c2ecf20Sopenharmony_ci					void __iomem *base);
1608c2ecf20Sopenharmony_cistatic int dwc3_meson_g12a_setup_regmaps(struct dwc3_meson_g12a *priv,
1618c2ecf20Sopenharmony_ci					 void __iomem *base);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic int dwc3_meson_g12a_usb2_init_phy(struct dwc3_meson_g12a *priv, int i,
1648c2ecf20Sopenharmony_ci					 enum phy_mode mode);
1658c2ecf20Sopenharmony_cistatic int dwc3_meson_gxl_usb2_init_phy(struct dwc3_meson_g12a *priv, int i,
1668c2ecf20Sopenharmony_ci					enum phy_mode mode);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic int dwc3_meson_g12a_set_phy_mode(struct dwc3_meson_g12a *priv,
1698c2ecf20Sopenharmony_ci					int i, enum phy_mode mode);
1708c2ecf20Sopenharmony_cistatic int dwc3_meson_gxl_set_phy_mode(struct dwc3_meson_g12a *priv,
1718c2ecf20Sopenharmony_ci				       int i, enum phy_mode mode);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv);
1748c2ecf20Sopenharmony_cistatic int dwc3_meson_gxl_usb_init(struct dwc3_meson_g12a *priv);
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic int dwc3_meson_gxl_usb_post_init(struct dwc3_meson_g12a *priv);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci/*
1798c2ecf20Sopenharmony_ci * For GXL and GXM SoCs:
1808c2ecf20Sopenharmony_ci * USB Phy muxing between the DWC2 Device controller and the DWC3 Host
1818c2ecf20Sopenharmony_ci * controller is buggy when switching from Device to Host when USB port
1828c2ecf20Sopenharmony_ci * is unpopulated, it causes the DWC3 to hard crash.
1838c2ecf20Sopenharmony_ci * When populated (including OTG switching with ID pin), the switch works
1848c2ecf20Sopenharmony_ci * like a charm like on the G12A platforms.
1858c2ecf20Sopenharmony_ci * In order to still switch from Host to Device on an USB Type-A port,
1868c2ecf20Sopenharmony_ci * an U2_PORT_DISABLE bit has been added to disconnect the DWC3 Host
1878c2ecf20Sopenharmony_ci * controller from the port, but when used the DWC3 controller must be
1888c2ecf20Sopenharmony_ci * reset to recover usage of the port.
1898c2ecf20Sopenharmony_ci */
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic struct dwc3_meson_g12a_drvdata gxl_drvdata = {
1928c2ecf20Sopenharmony_ci	.otg_switch_supported = true,
1938c2ecf20Sopenharmony_ci	.otg_phy_host_port_disable = true,
1948c2ecf20Sopenharmony_ci	.clks = meson_gxl_clocks,
1958c2ecf20Sopenharmony_ci	.num_clks = ARRAY_SIZE(meson_g12a_clocks),
1968c2ecf20Sopenharmony_ci	.phy_names = meson_a1_phy_names,
1978c2ecf20Sopenharmony_ci	.num_phys = ARRAY_SIZE(meson_a1_phy_names),
1988c2ecf20Sopenharmony_ci	.setup_regmaps = dwc3_meson_gxl_setup_regmaps,
1998c2ecf20Sopenharmony_ci	.usb2_init_phy = dwc3_meson_gxl_usb2_init_phy,
2008c2ecf20Sopenharmony_ci	.set_phy_mode = dwc3_meson_gxl_set_phy_mode,
2018c2ecf20Sopenharmony_ci	.usb_init = dwc3_meson_gxl_usb_init,
2028c2ecf20Sopenharmony_ci	.usb_post_init = dwc3_meson_gxl_usb_post_init,
2038c2ecf20Sopenharmony_ci};
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic struct dwc3_meson_g12a_drvdata gxm_drvdata = {
2068c2ecf20Sopenharmony_ci	.otg_switch_supported = true,
2078c2ecf20Sopenharmony_ci	.otg_phy_host_port_disable = true,
2088c2ecf20Sopenharmony_ci	.clks = meson_gxl_clocks,
2098c2ecf20Sopenharmony_ci	.num_clks = ARRAY_SIZE(meson_g12a_clocks),
2108c2ecf20Sopenharmony_ci	.phy_names = meson_gxm_phy_names,
2118c2ecf20Sopenharmony_ci	.num_phys = ARRAY_SIZE(meson_gxm_phy_names),
2128c2ecf20Sopenharmony_ci	.setup_regmaps = dwc3_meson_gxl_setup_regmaps,
2138c2ecf20Sopenharmony_ci	.usb2_init_phy = dwc3_meson_gxl_usb2_init_phy,
2148c2ecf20Sopenharmony_ci	.set_phy_mode = dwc3_meson_gxl_set_phy_mode,
2158c2ecf20Sopenharmony_ci	.usb_init = dwc3_meson_gxl_usb_init,
2168c2ecf20Sopenharmony_ci	.usb_post_init = dwc3_meson_gxl_usb_post_init,
2178c2ecf20Sopenharmony_ci};
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic struct dwc3_meson_g12a_drvdata axg_drvdata = {
2208c2ecf20Sopenharmony_ci	.otg_switch_supported = true,
2218c2ecf20Sopenharmony_ci	.clks = meson_gxl_clocks,
2228c2ecf20Sopenharmony_ci	.num_clks = ARRAY_SIZE(meson_gxl_clocks),
2238c2ecf20Sopenharmony_ci	.phy_names = meson_a1_phy_names,
2248c2ecf20Sopenharmony_ci	.num_phys = ARRAY_SIZE(meson_a1_phy_names),
2258c2ecf20Sopenharmony_ci	.setup_regmaps = dwc3_meson_gxl_setup_regmaps,
2268c2ecf20Sopenharmony_ci	.usb2_init_phy = dwc3_meson_gxl_usb2_init_phy,
2278c2ecf20Sopenharmony_ci	.set_phy_mode = dwc3_meson_gxl_set_phy_mode,
2288c2ecf20Sopenharmony_ci	.usb_init = dwc3_meson_g12a_usb_init,
2298c2ecf20Sopenharmony_ci	.usb_post_init = dwc3_meson_gxl_usb_post_init,
2308c2ecf20Sopenharmony_ci};
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic struct dwc3_meson_g12a_drvdata g12a_drvdata = {
2338c2ecf20Sopenharmony_ci	.otg_switch_supported = true,
2348c2ecf20Sopenharmony_ci	.clks = meson_g12a_clocks,
2358c2ecf20Sopenharmony_ci	.num_clks = ARRAY_SIZE(meson_g12a_clocks),
2368c2ecf20Sopenharmony_ci	.phy_names = meson_g12a_phy_names,
2378c2ecf20Sopenharmony_ci	.num_phys = ARRAY_SIZE(meson_g12a_phy_names),
2388c2ecf20Sopenharmony_ci	.setup_regmaps = dwc3_meson_g12a_setup_regmaps,
2398c2ecf20Sopenharmony_ci	.usb2_init_phy = dwc3_meson_g12a_usb2_init_phy,
2408c2ecf20Sopenharmony_ci	.set_phy_mode = dwc3_meson_g12a_set_phy_mode,
2418c2ecf20Sopenharmony_ci	.usb_init = dwc3_meson_g12a_usb_init,
2428c2ecf20Sopenharmony_ci};
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic struct dwc3_meson_g12a_drvdata a1_drvdata = {
2458c2ecf20Sopenharmony_ci	.otg_switch_supported = false,
2468c2ecf20Sopenharmony_ci	.clks = meson_a1_clocks,
2478c2ecf20Sopenharmony_ci	.num_clks = ARRAY_SIZE(meson_a1_clocks),
2488c2ecf20Sopenharmony_ci	.phy_names = meson_a1_phy_names,
2498c2ecf20Sopenharmony_ci	.num_phys = ARRAY_SIZE(meson_a1_phy_names),
2508c2ecf20Sopenharmony_ci	.setup_regmaps = dwc3_meson_g12a_setup_regmaps,
2518c2ecf20Sopenharmony_ci	.usb2_init_phy = dwc3_meson_g12a_usb2_init_phy,
2528c2ecf20Sopenharmony_ci	.set_phy_mode = dwc3_meson_g12a_set_phy_mode,
2538c2ecf20Sopenharmony_ci	.usb_init = dwc3_meson_g12a_usb_init,
2548c2ecf20Sopenharmony_ci};
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_cistruct dwc3_meson_g12a {
2578c2ecf20Sopenharmony_ci	struct device		*dev;
2588c2ecf20Sopenharmony_ci	struct regmap		*u2p_regmap[PHY_COUNT];
2598c2ecf20Sopenharmony_ci	struct regmap		*usb_glue_regmap;
2608c2ecf20Sopenharmony_ci	struct reset_control	*reset;
2618c2ecf20Sopenharmony_ci	struct phy		*phys[PHY_COUNT];
2628c2ecf20Sopenharmony_ci	enum usb_dr_mode	otg_mode;
2638c2ecf20Sopenharmony_ci	enum phy_mode		otg_phy_mode;
2648c2ecf20Sopenharmony_ci	unsigned int		usb2_ports;
2658c2ecf20Sopenharmony_ci	unsigned int		usb3_ports;
2668c2ecf20Sopenharmony_ci	struct regulator	*vbus;
2678c2ecf20Sopenharmony_ci	struct usb_role_switch_desc switch_desc;
2688c2ecf20Sopenharmony_ci	struct usb_role_switch	*role_switch;
2698c2ecf20Sopenharmony_ci	const struct dwc3_meson_g12a_drvdata *drvdata;
2708c2ecf20Sopenharmony_ci};
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistatic int dwc3_meson_gxl_set_phy_mode(struct dwc3_meson_g12a *priv,
2738c2ecf20Sopenharmony_ci					 int i, enum phy_mode mode)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	return phy_set_mode(priv->phys[i], mode);
2768c2ecf20Sopenharmony_ci}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_cistatic int dwc3_meson_gxl_usb2_init_phy(struct dwc3_meson_g12a *priv, int i,
2798c2ecf20Sopenharmony_ci					enum phy_mode mode)
2808c2ecf20Sopenharmony_ci{
2818c2ecf20Sopenharmony_ci	/* On GXL PHY must be started in device mode for DWC2 init */
2828c2ecf20Sopenharmony_ci	return priv->drvdata->set_phy_mode(priv, i,
2838c2ecf20Sopenharmony_ci				(i == USB2_OTG_PHY) ? PHY_MODE_USB_DEVICE
2848c2ecf20Sopenharmony_ci						    : PHY_MODE_USB_HOST);
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_cistatic int dwc3_meson_g12a_set_phy_mode(struct dwc3_meson_g12a *priv,
2888c2ecf20Sopenharmony_ci					 int i, enum phy_mode mode)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	if (mode == PHY_MODE_USB_HOST)
2918c2ecf20Sopenharmony_ci		regmap_update_bits(priv->u2p_regmap[i], U2P_R0,
2928c2ecf20Sopenharmony_ci				U2P_R0_HOST_DEVICE,
2938c2ecf20Sopenharmony_ci				U2P_R0_HOST_DEVICE);
2948c2ecf20Sopenharmony_ci	else
2958c2ecf20Sopenharmony_ci		regmap_update_bits(priv->u2p_regmap[i], U2P_R0,
2968c2ecf20Sopenharmony_ci				U2P_R0_HOST_DEVICE, 0);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	return 0;
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_cistatic int dwc3_meson_g12a_usb2_init_phy(struct dwc3_meson_g12a *priv, int i,
3028c2ecf20Sopenharmony_ci					 enum phy_mode mode)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	int ret;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	regmap_update_bits(priv->u2p_regmap[i], U2P_R0,
3078c2ecf20Sopenharmony_ci			U2P_R0_POWER_ON_RESET,
3088c2ecf20Sopenharmony_ci			U2P_R0_POWER_ON_RESET);
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	if (priv->drvdata->otg_switch_supported && i == USB2_OTG_PHY) {
3118c2ecf20Sopenharmony_ci		regmap_update_bits(priv->u2p_regmap[i], U2P_R0,
3128c2ecf20Sopenharmony_ci				   U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS,
3138c2ecf20Sopenharmony_ci				   U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS);
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci		ret = priv->drvdata->set_phy_mode(priv, i, mode);
3168c2ecf20Sopenharmony_ci	} else
3178c2ecf20Sopenharmony_ci		ret = priv->drvdata->set_phy_mode(priv, i,
3188c2ecf20Sopenharmony_ci						  PHY_MODE_USB_HOST);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	if (ret)
3218c2ecf20Sopenharmony_ci		return ret;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	regmap_update_bits(priv->u2p_regmap[i], U2P_R0,
3248c2ecf20Sopenharmony_ci			U2P_R0_POWER_ON_RESET, 0);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	return 0;
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cistatic int dwc3_meson_g12a_usb2_init(struct dwc3_meson_g12a *priv,
3308c2ecf20Sopenharmony_ci				     enum phy_mode mode)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	int i, ret;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	for (i = 0; i < priv->drvdata->num_phys; ++i) {
3358c2ecf20Sopenharmony_ci		if (!priv->phys[i])
3368c2ecf20Sopenharmony_ci			continue;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci		if (!strstr(priv->drvdata->phy_names[i], "usb2"))
3398c2ecf20Sopenharmony_ci			continue;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci		ret = priv->drvdata->usb2_init_phy(priv, i, mode);
3428c2ecf20Sopenharmony_ci		if (ret)
3438c2ecf20Sopenharmony_ci			return ret;
3448c2ecf20Sopenharmony_ci	}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	return 0;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic void dwc3_meson_g12a_usb3_init(struct dwc3_meson_g12a *priv)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	regmap_update_bits(priv->usb_glue_regmap, USB_R3,
3528c2ecf20Sopenharmony_ci			USB_R3_P30_SSC_RANGE_MASK |
3538c2ecf20Sopenharmony_ci			USB_R3_P30_REF_SSP_EN,
3548c2ecf20Sopenharmony_ci			USB_R3_P30_SSC_ENABLE |
3558c2ecf20Sopenharmony_ci			FIELD_PREP(USB_R3_P30_SSC_RANGE_MASK, 2) |
3568c2ecf20Sopenharmony_ci			USB_R3_P30_REF_SSP_EN);
3578c2ecf20Sopenharmony_ci	udelay(2);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	regmap_update_bits(priv->usb_glue_regmap, USB_R2,
3608c2ecf20Sopenharmony_ci			USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK,
3618c2ecf20Sopenharmony_ci			FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK, 0x15));
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	regmap_update_bits(priv->usb_glue_regmap, USB_R2,
3648c2ecf20Sopenharmony_ci			USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK,
3658c2ecf20Sopenharmony_ci			FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK, 0x20));
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	udelay(2);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	regmap_update_bits(priv->usb_glue_regmap, USB_R1,
3708c2ecf20Sopenharmony_ci			USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT,
3718c2ecf20Sopenharmony_ci			USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	regmap_update_bits(priv->usb_glue_regmap, USB_R1,
3748c2ecf20Sopenharmony_ci			USB_R1_P30_PCS_TX_SWING_FULL_MASK,
3758c2ecf20Sopenharmony_ci			FIELD_PREP(USB_R1_P30_PCS_TX_SWING_FULL_MASK, 127));
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic void dwc3_meson_g12a_usb_otg_apply_mode(struct dwc3_meson_g12a *priv,
3798c2ecf20Sopenharmony_ci					       enum phy_mode mode)
3808c2ecf20Sopenharmony_ci{
3818c2ecf20Sopenharmony_ci	if (mode == PHY_MODE_USB_DEVICE) {
3828c2ecf20Sopenharmony_ci		if (priv->otg_mode != USB_DR_MODE_OTG &&
3838c2ecf20Sopenharmony_ci		    priv->drvdata->otg_phy_host_port_disable)
3848c2ecf20Sopenharmony_ci			/* Isolate the OTG PHY port from the Host Controller */
3858c2ecf20Sopenharmony_ci			regmap_update_bits(priv->usb_glue_regmap, USB_R1,
3868c2ecf20Sopenharmony_ci				USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK,
3878c2ecf20Sopenharmony_ci				FIELD_PREP(USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK,
3888c2ecf20Sopenharmony_ci					   BIT(USB2_OTG_PHY)));
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci		regmap_update_bits(priv->usb_glue_regmap, USB_R0,
3918c2ecf20Sopenharmony_ci				USB_R0_U2D_ACT, USB_R0_U2D_ACT);
3928c2ecf20Sopenharmony_ci		regmap_update_bits(priv->usb_glue_regmap, USB_R0,
3938c2ecf20Sopenharmony_ci				USB_R0_U2D_SS_SCALEDOWN_MODE_MASK, 0);
3948c2ecf20Sopenharmony_ci		regmap_update_bits(priv->usb_glue_regmap, USB_R4,
3958c2ecf20Sopenharmony_ci				USB_R4_P21_SLEEP_M0, USB_R4_P21_SLEEP_M0);
3968c2ecf20Sopenharmony_ci	} else {
3978c2ecf20Sopenharmony_ci		if (priv->otg_mode != USB_DR_MODE_OTG &&
3988c2ecf20Sopenharmony_ci		    priv->drvdata->otg_phy_host_port_disable) {
3998c2ecf20Sopenharmony_ci			regmap_update_bits(priv->usb_glue_regmap, USB_R1,
4008c2ecf20Sopenharmony_ci				USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK, 0);
4018c2ecf20Sopenharmony_ci			msleep(500);
4028c2ecf20Sopenharmony_ci		}
4038c2ecf20Sopenharmony_ci		regmap_update_bits(priv->usb_glue_regmap, USB_R0,
4048c2ecf20Sopenharmony_ci				USB_R0_U2D_ACT, 0);
4058c2ecf20Sopenharmony_ci		regmap_update_bits(priv->usb_glue_regmap, USB_R4,
4068c2ecf20Sopenharmony_ci				USB_R4_P21_SLEEP_M0, 0);
4078c2ecf20Sopenharmony_ci	}
4088c2ecf20Sopenharmony_ci}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_cistatic int dwc3_meson_g12a_usb_init_glue(struct dwc3_meson_g12a *priv,
4118c2ecf20Sopenharmony_ci					 enum phy_mode mode)
4128c2ecf20Sopenharmony_ci{
4138c2ecf20Sopenharmony_ci	int ret;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	ret = dwc3_meson_g12a_usb2_init(priv, mode);
4168c2ecf20Sopenharmony_ci	if (ret)
4178c2ecf20Sopenharmony_ci		return ret;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	regmap_update_bits(priv->usb_glue_regmap, USB_R1,
4208c2ecf20Sopenharmony_ci			USB_R1_U3H_FLADJ_30MHZ_REG_MASK,
4218c2ecf20Sopenharmony_ci			FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20));
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	regmap_update_bits(priv->usb_glue_regmap, USB_R5,
4248c2ecf20Sopenharmony_ci			USB_R5_ID_DIG_EN_0,
4258c2ecf20Sopenharmony_ci			USB_R5_ID_DIG_EN_0);
4268c2ecf20Sopenharmony_ci	regmap_update_bits(priv->usb_glue_regmap, USB_R5,
4278c2ecf20Sopenharmony_ci			USB_R5_ID_DIG_EN_1,
4288c2ecf20Sopenharmony_ci			USB_R5_ID_DIG_EN_1);
4298c2ecf20Sopenharmony_ci	regmap_update_bits(priv->usb_glue_regmap, USB_R5,
4308c2ecf20Sopenharmony_ci			USB_R5_ID_DIG_TH_MASK,
4318c2ecf20Sopenharmony_ci			FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff));
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	/* If we have an actual SuperSpeed port, initialize it */
4348c2ecf20Sopenharmony_ci	if (priv->usb3_ports)
4358c2ecf20Sopenharmony_ci		dwc3_meson_g12a_usb3_init(priv);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	dwc3_meson_g12a_usb_otg_apply_mode(priv, mode);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	return 0;
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic const struct regmap_config phy_meson_g12a_usb_glue_regmap_conf = {
4438c2ecf20Sopenharmony_ci	.name = "usb-glue",
4448c2ecf20Sopenharmony_ci	.reg_bits = 8,
4458c2ecf20Sopenharmony_ci	.val_bits = 32,
4468c2ecf20Sopenharmony_ci	.reg_stride = 4,
4478c2ecf20Sopenharmony_ci	.max_register = USB_R5,
4488c2ecf20Sopenharmony_ci};
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_cistatic int dwc3_meson_g12a_get_phys(struct dwc3_meson_g12a *priv)
4518c2ecf20Sopenharmony_ci{
4528c2ecf20Sopenharmony_ci	const char *phy_name;
4538c2ecf20Sopenharmony_ci	int i;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	for (i = 0 ; i < priv->drvdata->num_phys ; ++i) {
4568c2ecf20Sopenharmony_ci		phy_name = priv->drvdata->phy_names[i];
4578c2ecf20Sopenharmony_ci		priv->phys[i] = devm_phy_optional_get(priv->dev, phy_name);
4588c2ecf20Sopenharmony_ci		if (!priv->phys[i])
4598c2ecf20Sopenharmony_ci			continue;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci		if (IS_ERR(priv->phys[i]))
4628c2ecf20Sopenharmony_ci			return PTR_ERR(priv->phys[i]);
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci		if (strstr(phy_name, "usb3"))
4658c2ecf20Sopenharmony_ci			priv->usb3_ports++;
4668c2ecf20Sopenharmony_ci		else
4678c2ecf20Sopenharmony_ci			priv->usb2_ports++;
4688c2ecf20Sopenharmony_ci	}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	dev_info(priv->dev, "USB2 ports: %d\n", priv->usb2_ports);
4718c2ecf20Sopenharmony_ci	dev_info(priv->dev, "USB3 ports: %d\n", priv->usb3_ports);
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	return 0;
4748c2ecf20Sopenharmony_ci}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_cistatic enum phy_mode dwc3_meson_g12a_get_id(struct dwc3_meson_g12a *priv)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci	u32 reg;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	regmap_read(priv->usb_glue_regmap, USB_R5, &reg);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	if (reg & (USB_R5_ID_DIG_SYNC | USB_R5_ID_DIG_REG))
4838c2ecf20Sopenharmony_ci		return PHY_MODE_USB_DEVICE;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	return PHY_MODE_USB_HOST;
4868c2ecf20Sopenharmony_ci}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_cistatic int dwc3_meson_g12a_otg_mode_set(struct dwc3_meson_g12a *priv,
4898c2ecf20Sopenharmony_ci					enum phy_mode mode)
4908c2ecf20Sopenharmony_ci{
4918c2ecf20Sopenharmony_ci	int ret;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	if (!priv->drvdata->otg_switch_supported || !priv->phys[USB2_OTG_PHY])
4948c2ecf20Sopenharmony_ci		return -EINVAL;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	if (mode == PHY_MODE_USB_HOST)
4978c2ecf20Sopenharmony_ci		dev_info(priv->dev, "switching to Host Mode\n");
4988c2ecf20Sopenharmony_ci	else
4998c2ecf20Sopenharmony_ci		dev_info(priv->dev, "switching to Device Mode\n");
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	if (priv->vbus) {
5028c2ecf20Sopenharmony_ci		if (mode == PHY_MODE_USB_DEVICE)
5038c2ecf20Sopenharmony_ci			ret = regulator_disable(priv->vbus);
5048c2ecf20Sopenharmony_ci		else
5058c2ecf20Sopenharmony_ci			ret = regulator_enable(priv->vbus);
5068c2ecf20Sopenharmony_ci		if (ret)
5078c2ecf20Sopenharmony_ci			return ret;
5088c2ecf20Sopenharmony_ci	}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	priv->otg_phy_mode = mode;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	ret = priv->drvdata->set_phy_mode(priv, USB2_OTG_PHY, mode);
5138c2ecf20Sopenharmony_ci	if (ret)
5148c2ecf20Sopenharmony_ci		return ret;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	dwc3_meson_g12a_usb_otg_apply_mode(priv, mode);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	return 0;
5198c2ecf20Sopenharmony_ci}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cistatic int dwc3_meson_g12a_role_set(struct usb_role_switch *sw,
5228c2ecf20Sopenharmony_ci				    enum usb_role role)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	struct dwc3_meson_g12a *priv = usb_role_switch_get_drvdata(sw);
5258c2ecf20Sopenharmony_ci	enum phy_mode mode;
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	if (role == USB_ROLE_NONE)
5288c2ecf20Sopenharmony_ci		return 0;
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	mode = (role == USB_ROLE_HOST) ? PHY_MODE_USB_HOST
5318c2ecf20Sopenharmony_ci				       : PHY_MODE_USB_DEVICE;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	if (mode == priv->otg_phy_mode)
5348c2ecf20Sopenharmony_ci		return 0;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	if (priv->drvdata->otg_phy_host_port_disable)
5378c2ecf20Sopenharmony_ci		dev_warn_once(priv->dev, "Broken manual OTG switch\n");
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	return dwc3_meson_g12a_otg_mode_set(priv, mode);
5408c2ecf20Sopenharmony_ci}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_cistatic enum usb_role dwc3_meson_g12a_role_get(struct usb_role_switch *sw)
5438c2ecf20Sopenharmony_ci{
5448c2ecf20Sopenharmony_ci	struct dwc3_meson_g12a *priv = usb_role_switch_get_drvdata(sw);
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	return priv->otg_phy_mode == PHY_MODE_USB_HOST ?
5478c2ecf20Sopenharmony_ci		USB_ROLE_HOST : USB_ROLE_DEVICE;
5488c2ecf20Sopenharmony_ci}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_cistatic irqreturn_t dwc3_meson_g12a_irq_thread(int irq, void *data)
5518c2ecf20Sopenharmony_ci{
5528c2ecf20Sopenharmony_ci	struct dwc3_meson_g12a *priv = data;
5538c2ecf20Sopenharmony_ci	enum phy_mode otg_id;
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	otg_id = dwc3_meson_g12a_get_id(priv);
5568c2ecf20Sopenharmony_ci	if (otg_id != priv->otg_phy_mode) {
5578c2ecf20Sopenharmony_ci		if (dwc3_meson_g12a_otg_mode_set(priv, otg_id))
5588c2ecf20Sopenharmony_ci			dev_warn(priv->dev, "Failed to switch OTG mode\n");
5598c2ecf20Sopenharmony_ci	}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	regmap_update_bits(priv->usb_glue_regmap, USB_R5,
5628c2ecf20Sopenharmony_ci			   USB_R5_ID_DIG_IRQ, 0);
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
5658c2ecf20Sopenharmony_ci}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_cistatic struct device *dwc3_meson_g12_find_child(struct device *dev,
5688c2ecf20Sopenharmony_ci						const char *compatible)
5698c2ecf20Sopenharmony_ci{
5708c2ecf20Sopenharmony_ci	struct platform_device *pdev;
5718c2ecf20Sopenharmony_ci	struct device_node *np;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	np = of_get_compatible_child(dev->of_node, compatible);
5748c2ecf20Sopenharmony_ci	if (!np)
5758c2ecf20Sopenharmony_ci		return NULL;
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	pdev = of_find_device_by_node(np);
5788c2ecf20Sopenharmony_ci	of_node_put(np);
5798c2ecf20Sopenharmony_ci	if (!pdev)
5808c2ecf20Sopenharmony_ci		return NULL;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	return &pdev->dev;
5838c2ecf20Sopenharmony_ci}
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_cistatic int dwc3_meson_g12a_otg_init(struct platform_device *pdev,
5868c2ecf20Sopenharmony_ci				    struct dwc3_meson_g12a *priv)
5878c2ecf20Sopenharmony_ci{
5888c2ecf20Sopenharmony_ci	enum phy_mode otg_id;
5898c2ecf20Sopenharmony_ci	int ret, irq;
5908c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	if (!priv->drvdata->otg_switch_supported)
5938c2ecf20Sopenharmony_ci		return 0;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	if (priv->otg_mode == USB_DR_MODE_OTG) {
5968c2ecf20Sopenharmony_ci		/* Ack irq before registering */
5978c2ecf20Sopenharmony_ci		regmap_update_bits(priv->usb_glue_regmap, USB_R5,
5988c2ecf20Sopenharmony_ci				   USB_R5_ID_DIG_IRQ, 0);
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci		irq = platform_get_irq(pdev, 0);
6018c2ecf20Sopenharmony_ci		if (irq < 0)
6028c2ecf20Sopenharmony_ci			return irq;
6038c2ecf20Sopenharmony_ci		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
6048c2ecf20Sopenharmony_ci						dwc3_meson_g12a_irq_thread,
6058c2ecf20Sopenharmony_ci						IRQF_ONESHOT, pdev->name, priv);
6068c2ecf20Sopenharmony_ci		if (ret)
6078c2ecf20Sopenharmony_ci			return ret;
6088c2ecf20Sopenharmony_ci	}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	/* Setup OTG mode corresponding to the ID pin */
6118c2ecf20Sopenharmony_ci	if (priv->otg_mode == USB_DR_MODE_OTG) {
6128c2ecf20Sopenharmony_ci		otg_id = dwc3_meson_g12a_get_id(priv);
6138c2ecf20Sopenharmony_ci		if (otg_id != priv->otg_phy_mode) {
6148c2ecf20Sopenharmony_ci			if (dwc3_meson_g12a_otg_mode_set(priv, otg_id))
6158c2ecf20Sopenharmony_ci				dev_warn(dev, "Failed to switch OTG mode\n");
6168c2ecf20Sopenharmony_ci		}
6178c2ecf20Sopenharmony_ci	}
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	/* Setup role switcher */
6208c2ecf20Sopenharmony_ci	priv->switch_desc.usb2_port = dwc3_meson_g12_find_child(dev,
6218c2ecf20Sopenharmony_ci								"snps,dwc3");
6228c2ecf20Sopenharmony_ci	priv->switch_desc.udc = dwc3_meson_g12_find_child(dev, "snps,dwc2");
6238c2ecf20Sopenharmony_ci	priv->switch_desc.allow_userspace_control = true;
6248c2ecf20Sopenharmony_ci	priv->switch_desc.set = dwc3_meson_g12a_role_set;
6258c2ecf20Sopenharmony_ci	priv->switch_desc.get = dwc3_meson_g12a_role_get;
6268c2ecf20Sopenharmony_ci	priv->switch_desc.driver_data = priv;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	priv->role_switch = usb_role_switch_register(dev, &priv->switch_desc);
6298c2ecf20Sopenharmony_ci	if (IS_ERR(priv->role_switch))
6308c2ecf20Sopenharmony_ci		dev_warn(dev, "Unable to register Role Switch\n");
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	return 0;
6338c2ecf20Sopenharmony_ci}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_cistatic int dwc3_meson_gxl_setup_regmaps(struct dwc3_meson_g12a *priv,
6368c2ecf20Sopenharmony_ci					void __iomem *base)
6378c2ecf20Sopenharmony_ci{
6388c2ecf20Sopenharmony_ci	/* GXL controls the PHY mode in the PHY registers unlike G12A */
6398c2ecf20Sopenharmony_ci	priv->usb_glue_regmap = devm_regmap_init_mmio(priv->dev, base,
6408c2ecf20Sopenharmony_ci					&phy_meson_g12a_usb_glue_regmap_conf);
6418c2ecf20Sopenharmony_ci	return PTR_ERR_OR_ZERO(priv->usb_glue_regmap);
6428c2ecf20Sopenharmony_ci}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_cistatic int dwc3_meson_g12a_setup_regmaps(struct dwc3_meson_g12a *priv,
6458c2ecf20Sopenharmony_ci					 void __iomem *base)
6468c2ecf20Sopenharmony_ci{
6478c2ecf20Sopenharmony_ci	int i;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	priv->usb_glue_regmap = devm_regmap_init_mmio(priv->dev,
6508c2ecf20Sopenharmony_ci					base + G12A_GLUE_OFFSET,
6518c2ecf20Sopenharmony_ci					&phy_meson_g12a_usb_glue_regmap_conf);
6528c2ecf20Sopenharmony_ci	if (IS_ERR(priv->usb_glue_regmap))
6538c2ecf20Sopenharmony_ci		return PTR_ERR(priv->usb_glue_regmap);
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	/* Create a regmap for each USB2 PHY control register set */
6568c2ecf20Sopenharmony_ci	for (i = 0; i < priv->drvdata->num_phys; i++) {
6578c2ecf20Sopenharmony_ci		struct regmap_config u2p_regmap_config = {
6588c2ecf20Sopenharmony_ci			.reg_bits = 8,
6598c2ecf20Sopenharmony_ci			.val_bits = 32,
6608c2ecf20Sopenharmony_ci			.reg_stride = 4,
6618c2ecf20Sopenharmony_ci			.max_register = U2P_R1,
6628c2ecf20Sopenharmony_ci		};
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci		if (!strstr(priv->drvdata->phy_names[i], "usb2"))
6658c2ecf20Sopenharmony_ci			continue;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci		u2p_regmap_config.name = devm_kasprintf(priv->dev, GFP_KERNEL,
6688c2ecf20Sopenharmony_ci							"u2p-%d", i);
6698c2ecf20Sopenharmony_ci		if (!u2p_regmap_config.name)
6708c2ecf20Sopenharmony_ci			return -ENOMEM;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci		priv->u2p_regmap[i] = devm_regmap_init_mmio(priv->dev,
6738c2ecf20Sopenharmony_ci						base + (i * U2P_REG_SIZE),
6748c2ecf20Sopenharmony_ci						&u2p_regmap_config);
6758c2ecf20Sopenharmony_ci		if (IS_ERR(priv->u2p_regmap[i]))
6768c2ecf20Sopenharmony_ci			return PTR_ERR(priv->u2p_regmap[i]);
6778c2ecf20Sopenharmony_ci	}
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	return 0;
6808c2ecf20Sopenharmony_ci}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_cistatic int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv)
6838c2ecf20Sopenharmony_ci{
6848c2ecf20Sopenharmony_ci	return dwc3_meson_g12a_usb_init_glue(priv, priv->otg_phy_mode);
6858c2ecf20Sopenharmony_ci}
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_cistatic int dwc3_meson_gxl_usb_init(struct dwc3_meson_g12a *priv)
6888c2ecf20Sopenharmony_ci{
6898c2ecf20Sopenharmony_ci	return dwc3_meson_g12a_usb_init_glue(priv, PHY_MODE_USB_DEVICE);
6908c2ecf20Sopenharmony_ci}
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_cistatic int dwc3_meson_gxl_usb_post_init(struct dwc3_meson_g12a *priv)
6938c2ecf20Sopenharmony_ci{
6948c2ecf20Sopenharmony_ci	int ret;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	ret = priv->drvdata->set_phy_mode(priv, USB2_OTG_PHY,
6978c2ecf20Sopenharmony_ci					  priv->otg_phy_mode);
6988c2ecf20Sopenharmony_ci	if (ret)
6998c2ecf20Sopenharmony_ci		return ret;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	dwc3_meson_g12a_usb_otg_apply_mode(priv, priv->otg_phy_mode);
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	return 0;
7048c2ecf20Sopenharmony_ci}
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_cistatic int dwc3_meson_g12a_probe(struct platform_device *pdev)
7078c2ecf20Sopenharmony_ci{
7088c2ecf20Sopenharmony_ci	struct dwc3_meson_g12a	*priv;
7098c2ecf20Sopenharmony_ci	struct device		*dev = &pdev->dev;
7108c2ecf20Sopenharmony_ci	struct device_node	*np = dev->of_node;
7118c2ecf20Sopenharmony_ci	void __iomem *base;
7128c2ecf20Sopenharmony_ci	int ret, i;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
7158c2ecf20Sopenharmony_ci	if (!priv)
7168c2ecf20Sopenharmony_ci		return -ENOMEM;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	base = devm_platform_ioremap_resource(pdev, 0);
7198c2ecf20Sopenharmony_ci	if (IS_ERR(base))
7208c2ecf20Sopenharmony_ci		return PTR_ERR(base);
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	priv->drvdata = of_device_get_match_data(&pdev->dev);
7238c2ecf20Sopenharmony_ci	priv->dev = dev;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	priv->vbus = devm_regulator_get_optional(dev, "vbus");
7268c2ecf20Sopenharmony_ci	if (IS_ERR(priv->vbus)) {
7278c2ecf20Sopenharmony_ci		if (PTR_ERR(priv->vbus) == -EPROBE_DEFER)
7288c2ecf20Sopenharmony_ci			return PTR_ERR(priv->vbus);
7298c2ecf20Sopenharmony_ci		priv->vbus = NULL;
7308c2ecf20Sopenharmony_ci	}
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	ret = devm_clk_bulk_get(dev,
7338c2ecf20Sopenharmony_ci				priv->drvdata->num_clks,
7348c2ecf20Sopenharmony_ci				priv->drvdata->clks);
7358c2ecf20Sopenharmony_ci	if (ret)
7368c2ecf20Sopenharmony_ci		return ret;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	ret = clk_bulk_prepare_enable(priv->drvdata->num_clks,
7398c2ecf20Sopenharmony_ci				      priv->drvdata->clks);
7408c2ecf20Sopenharmony_ci	if (ret)
7418c2ecf20Sopenharmony_ci		return ret;
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, priv);
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	priv->reset = devm_reset_control_get_shared(dev, NULL);
7468c2ecf20Sopenharmony_ci	if (IS_ERR(priv->reset)) {
7478c2ecf20Sopenharmony_ci		ret = PTR_ERR(priv->reset);
7488c2ecf20Sopenharmony_ci		dev_err(dev, "failed to get device reset, err=%d\n", ret);
7498c2ecf20Sopenharmony_ci		goto err_disable_clks;
7508c2ecf20Sopenharmony_ci	}
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	ret = reset_control_reset(priv->reset);
7538c2ecf20Sopenharmony_ci	if (ret)
7548c2ecf20Sopenharmony_ci		goto err_disable_clks;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	ret = dwc3_meson_g12a_get_phys(priv);
7578c2ecf20Sopenharmony_ci	if (ret)
7588c2ecf20Sopenharmony_ci		goto err_disable_clks;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	ret = priv->drvdata->setup_regmaps(priv, base);
7618c2ecf20Sopenharmony_ci	if (ret)
7628c2ecf20Sopenharmony_ci		goto err_disable_clks;
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	if (priv->vbus) {
7658c2ecf20Sopenharmony_ci		ret = regulator_enable(priv->vbus);
7668c2ecf20Sopenharmony_ci		if (ret)
7678c2ecf20Sopenharmony_ci			goto err_disable_clks;
7688c2ecf20Sopenharmony_ci	}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	/* Get dr_mode */
7718c2ecf20Sopenharmony_ci	priv->otg_mode = usb_get_dr_mode(dev);
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	if (priv->otg_mode == USB_DR_MODE_PERIPHERAL)
7748c2ecf20Sopenharmony_ci		priv->otg_phy_mode = PHY_MODE_USB_DEVICE;
7758c2ecf20Sopenharmony_ci	else
7768c2ecf20Sopenharmony_ci		priv->otg_phy_mode = PHY_MODE_USB_HOST;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	ret = priv->drvdata->usb_init(priv);
7798c2ecf20Sopenharmony_ci	if (ret)
7808c2ecf20Sopenharmony_ci		goto err_disable_regulator;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	/* Init PHYs */
7838c2ecf20Sopenharmony_ci	for (i = 0 ; i < PHY_COUNT ; ++i) {
7848c2ecf20Sopenharmony_ci		ret = phy_init(priv->phys[i]);
7858c2ecf20Sopenharmony_ci		if (ret)
7868c2ecf20Sopenharmony_ci			goto err_disable_regulator;
7878c2ecf20Sopenharmony_ci	}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	/* Set PHY Power */
7908c2ecf20Sopenharmony_ci	for (i = 0 ; i < PHY_COUNT ; ++i) {
7918c2ecf20Sopenharmony_ci		ret = phy_power_on(priv->phys[i]);
7928c2ecf20Sopenharmony_ci		if (ret)
7938c2ecf20Sopenharmony_ci			goto err_phys_exit;
7948c2ecf20Sopenharmony_ci	}
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	if (priv->drvdata->usb_post_init) {
7978c2ecf20Sopenharmony_ci		ret = priv->drvdata->usb_post_init(priv);
7988c2ecf20Sopenharmony_ci		if (ret)
7998c2ecf20Sopenharmony_ci			goto err_phys_power;
8008c2ecf20Sopenharmony_ci	}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	ret = of_platform_populate(np, NULL, NULL, dev);
8038c2ecf20Sopenharmony_ci	if (ret)
8048c2ecf20Sopenharmony_ci		goto err_phys_power;
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	ret = dwc3_meson_g12a_otg_init(pdev, priv);
8078c2ecf20Sopenharmony_ci	if (ret)
8088c2ecf20Sopenharmony_ci		goto err_plat_depopulate;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	pm_runtime_set_active(dev);
8118c2ecf20Sopenharmony_ci	pm_runtime_enable(dev);
8128c2ecf20Sopenharmony_ci	pm_runtime_get_sync(dev);
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	return 0;
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_cierr_plat_depopulate:
8178c2ecf20Sopenharmony_ci	of_platform_depopulate(dev);
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_cierr_phys_power:
8208c2ecf20Sopenharmony_ci	for (i = 0 ; i < PHY_COUNT ; ++i)
8218c2ecf20Sopenharmony_ci		phy_power_off(priv->phys[i]);
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_cierr_phys_exit:
8248c2ecf20Sopenharmony_ci	for (i = 0 ; i < PHY_COUNT ; ++i)
8258c2ecf20Sopenharmony_ci		phy_exit(priv->phys[i]);
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_cierr_disable_regulator:
8288c2ecf20Sopenharmony_ci	if (priv->vbus)
8298c2ecf20Sopenharmony_ci		regulator_disable(priv->vbus);
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_cierr_disable_clks:
8328c2ecf20Sopenharmony_ci	clk_bulk_disable_unprepare(priv->drvdata->num_clks,
8338c2ecf20Sopenharmony_ci				   priv->drvdata->clks);
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	return ret;
8368c2ecf20Sopenharmony_ci}
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_cistatic int dwc3_meson_g12a_remove(struct platform_device *pdev)
8398c2ecf20Sopenharmony_ci{
8408c2ecf20Sopenharmony_ci	struct dwc3_meson_g12a *priv = platform_get_drvdata(pdev);
8418c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
8428c2ecf20Sopenharmony_ci	int i;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	if (priv->drvdata->otg_switch_supported)
8458c2ecf20Sopenharmony_ci		usb_role_switch_unregister(priv->role_switch);
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	of_platform_depopulate(dev);
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	for (i = 0 ; i < PHY_COUNT ; ++i) {
8508c2ecf20Sopenharmony_ci		phy_power_off(priv->phys[i]);
8518c2ecf20Sopenharmony_ci		phy_exit(priv->phys[i]);
8528c2ecf20Sopenharmony_ci	}
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	pm_runtime_disable(dev);
8558c2ecf20Sopenharmony_ci	pm_runtime_put_noidle(dev);
8568c2ecf20Sopenharmony_ci	pm_runtime_set_suspended(dev);
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	clk_bulk_disable_unprepare(priv->drvdata->num_clks,
8598c2ecf20Sopenharmony_ci				   priv->drvdata->clks);
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	return 0;
8628c2ecf20Sopenharmony_ci}
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_cistatic int __maybe_unused dwc3_meson_g12a_runtime_suspend(struct device *dev)
8658c2ecf20Sopenharmony_ci{
8668c2ecf20Sopenharmony_ci	struct dwc3_meson_g12a	*priv = dev_get_drvdata(dev);
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	clk_bulk_disable_unprepare(priv->drvdata->num_clks,
8698c2ecf20Sopenharmony_ci				   priv->drvdata->clks);
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	return 0;
8728c2ecf20Sopenharmony_ci}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_cistatic int __maybe_unused dwc3_meson_g12a_runtime_resume(struct device *dev)
8758c2ecf20Sopenharmony_ci{
8768c2ecf20Sopenharmony_ci	struct dwc3_meson_g12a	*priv = dev_get_drvdata(dev);
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	return clk_bulk_prepare_enable(priv->drvdata->num_clks,
8798c2ecf20Sopenharmony_ci				       priv->drvdata->clks);
8808c2ecf20Sopenharmony_ci}
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_cistatic int __maybe_unused dwc3_meson_g12a_suspend(struct device *dev)
8838c2ecf20Sopenharmony_ci{
8848c2ecf20Sopenharmony_ci	struct dwc3_meson_g12a *priv = dev_get_drvdata(dev);
8858c2ecf20Sopenharmony_ci	int i, ret;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	if (priv->vbus && priv->otg_phy_mode == PHY_MODE_USB_HOST) {
8888c2ecf20Sopenharmony_ci		ret = regulator_disable(priv->vbus);
8898c2ecf20Sopenharmony_ci		if (ret)
8908c2ecf20Sopenharmony_ci			return ret;
8918c2ecf20Sopenharmony_ci	}
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	for (i = 0 ; i < PHY_COUNT ; ++i) {
8948c2ecf20Sopenharmony_ci		phy_power_off(priv->phys[i]);
8958c2ecf20Sopenharmony_ci		phy_exit(priv->phys[i]);
8968c2ecf20Sopenharmony_ci	}
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	reset_control_assert(priv->reset);
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	return 0;
9018c2ecf20Sopenharmony_ci}
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_cistatic int __maybe_unused dwc3_meson_g12a_resume(struct device *dev)
9048c2ecf20Sopenharmony_ci{
9058c2ecf20Sopenharmony_ci	struct dwc3_meson_g12a *priv = dev_get_drvdata(dev);
9068c2ecf20Sopenharmony_ci	int i, ret;
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	reset_control_deassert(priv->reset);
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	ret = priv->drvdata->usb_init(priv);
9118c2ecf20Sopenharmony_ci	if (ret)
9128c2ecf20Sopenharmony_ci		return ret;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	/* Init PHYs */
9158c2ecf20Sopenharmony_ci	for (i = 0 ; i < PHY_COUNT ; ++i) {
9168c2ecf20Sopenharmony_ci		ret = phy_init(priv->phys[i]);
9178c2ecf20Sopenharmony_ci		if (ret)
9188c2ecf20Sopenharmony_ci			return ret;
9198c2ecf20Sopenharmony_ci	}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	/* Set PHY Power */
9228c2ecf20Sopenharmony_ci	for (i = 0 ; i < PHY_COUNT ; ++i) {
9238c2ecf20Sopenharmony_ci		ret = phy_power_on(priv->phys[i]);
9248c2ecf20Sopenharmony_ci		if (ret)
9258c2ecf20Sopenharmony_ci			return ret;
9268c2ecf20Sopenharmony_ci	}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	if (priv->vbus && priv->otg_phy_mode == PHY_MODE_USB_HOST) {
9298c2ecf20Sopenharmony_ci		ret = regulator_enable(priv->vbus);
9308c2ecf20Sopenharmony_ci		if (ret)
9318c2ecf20Sopenharmony_ci			return ret;
9328c2ecf20Sopenharmony_ci	}
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	if (priv->drvdata->usb_post_init) {
9358c2ecf20Sopenharmony_ci		ret = priv->drvdata->usb_post_init(priv);
9368c2ecf20Sopenharmony_ci		if (ret)
9378c2ecf20Sopenharmony_ci			return ret;
9388c2ecf20Sopenharmony_ci	}
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	return 0;
9418c2ecf20Sopenharmony_ci}
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_cistatic const struct dev_pm_ops dwc3_meson_g12a_dev_pm_ops = {
9448c2ecf20Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(dwc3_meson_g12a_suspend, dwc3_meson_g12a_resume)
9458c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(dwc3_meson_g12a_runtime_suspend,
9468c2ecf20Sopenharmony_ci			   dwc3_meson_g12a_runtime_resume, NULL)
9478c2ecf20Sopenharmony_ci};
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_cistatic const struct of_device_id dwc3_meson_g12a_match[] = {
9508c2ecf20Sopenharmony_ci	{
9518c2ecf20Sopenharmony_ci		.compatible = "amlogic,meson-gxl-usb-ctrl",
9528c2ecf20Sopenharmony_ci		.data = &gxl_drvdata,
9538c2ecf20Sopenharmony_ci	},
9548c2ecf20Sopenharmony_ci	{
9558c2ecf20Sopenharmony_ci		.compatible = "amlogic,meson-gxm-usb-ctrl",
9568c2ecf20Sopenharmony_ci		.data = &gxm_drvdata,
9578c2ecf20Sopenharmony_ci	},
9588c2ecf20Sopenharmony_ci	{
9598c2ecf20Sopenharmony_ci		.compatible = "amlogic,meson-axg-usb-ctrl",
9608c2ecf20Sopenharmony_ci		.data = &axg_drvdata,
9618c2ecf20Sopenharmony_ci	},
9628c2ecf20Sopenharmony_ci	{
9638c2ecf20Sopenharmony_ci		.compatible = "amlogic,meson-g12a-usb-ctrl",
9648c2ecf20Sopenharmony_ci		.data = &g12a_drvdata,
9658c2ecf20Sopenharmony_ci	},
9668c2ecf20Sopenharmony_ci	{
9678c2ecf20Sopenharmony_ci		.compatible = "amlogic,meson-a1-usb-ctrl",
9688c2ecf20Sopenharmony_ci		.data = &a1_drvdata,
9698c2ecf20Sopenharmony_ci	},
9708c2ecf20Sopenharmony_ci	{ /* Sentinel */ }
9718c2ecf20Sopenharmony_ci};
9728c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, dwc3_meson_g12a_match);
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_cistatic struct platform_driver dwc3_meson_g12a_driver = {
9758c2ecf20Sopenharmony_ci	.probe		= dwc3_meson_g12a_probe,
9768c2ecf20Sopenharmony_ci	.remove		= dwc3_meson_g12a_remove,
9778c2ecf20Sopenharmony_ci	.driver		= {
9788c2ecf20Sopenharmony_ci		.name	= "dwc3-meson-g12a",
9798c2ecf20Sopenharmony_ci		.of_match_table = dwc3_meson_g12a_match,
9808c2ecf20Sopenharmony_ci		.pm	= &dwc3_meson_g12a_dev_pm_ops,
9818c2ecf20Sopenharmony_ci	},
9828c2ecf20Sopenharmony_ci};
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_cimodule_platform_driver(dwc3_meson_g12a_driver);
9858c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
9868c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Amlogic Meson G12A USB Glue Layer");
9878c2ecf20Sopenharmony_ciMODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
988