162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * USB Glue for Amlogic G12A SoCs
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2019 BayLibre, SAS
662306a36Sopenharmony_ci * Author: Neil Armstrong <narmstrong@baylibre.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci/*
1062306a36Sopenharmony_ci * The USB is organized with a glue around the DWC3 Controller IP as :
1162306a36Sopenharmony_ci * - Control registers for each USB2 Ports
1262306a36Sopenharmony_ci * - Control registers for the USB PHY layer
1362306a36Sopenharmony_ci * - SuperSpeed PHY can be enabled only if port is used
1462306a36Sopenharmony_ci * - Dynamic OTG switching with ID change interrupt
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <linux/module.h>
1862306a36Sopenharmony_ci#include <linux/kernel.h>
1962306a36Sopenharmony_ci#include <linux/platform_device.h>
2062306a36Sopenharmony_ci#include <linux/clk.h>
2162306a36Sopenharmony_ci#include <linux/of.h>
2262306a36Sopenharmony_ci#include <linux/of_platform.h>
2362306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2462306a36Sopenharmony_ci#include <linux/regmap.h>
2562306a36Sopenharmony_ci#include <linux/bitfield.h>
2662306a36Sopenharmony_ci#include <linux/bitops.h>
2762306a36Sopenharmony_ci#include <linux/reset.h>
2862306a36Sopenharmony_ci#include <linux/phy/phy.h>
2962306a36Sopenharmony_ci#include <linux/usb/otg.h>
3062306a36Sopenharmony_ci#include <linux/usb/role.h>
3162306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/* USB2 Ports Control Registers, offsets are per-port */
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define U2P_REG_SIZE						0x20
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define U2P_R0							0x0
3862306a36Sopenharmony_ci	#define U2P_R0_HOST_DEVICE				BIT(0)
3962306a36Sopenharmony_ci	#define U2P_R0_POWER_OK					BIT(1)
4062306a36Sopenharmony_ci	#define U2P_R0_HAST_MODE				BIT(2)
4162306a36Sopenharmony_ci	#define U2P_R0_POWER_ON_RESET				BIT(3)
4262306a36Sopenharmony_ci	#define U2P_R0_ID_PULLUP				BIT(4)
4362306a36Sopenharmony_ci	#define U2P_R0_DRV_VBUS					BIT(5)
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define U2P_R1							0x4
4662306a36Sopenharmony_ci	#define U2P_R1_PHY_READY				BIT(0)
4762306a36Sopenharmony_ci	#define U2P_R1_ID_DIG					BIT(1)
4862306a36Sopenharmony_ci	#define U2P_R1_OTG_SESSION_VALID			BIT(2)
4962306a36Sopenharmony_ci	#define U2P_R1_VBUS_VALID				BIT(3)
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/* USB Glue Control Registers */
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#define G12A_GLUE_OFFSET					0x80
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define USB_R0							0x00
5662306a36Sopenharmony_ci	#define USB_R0_P30_LANE0_TX2RX_LOOPBACK			BIT(17)
5762306a36Sopenharmony_ci	#define USB_R0_P30_LANE0_EXT_PCLK_REQ			BIT(18)
5862306a36Sopenharmony_ci	#define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK		GENMASK(28, 19)
5962306a36Sopenharmony_ci	#define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK		GENMASK(30, 29)
6062306a36Sopenharmony_ci	#define USB_R0_U2D_ACT					BIT(31)
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#define USB_R1							0x04
6362306a36Sopenharmony_ci	#define USB_R1_U3H_BIGENDIAN_GS				BIT(0)
6462306a36Sopenharmony_ci	#define USB_R1_U3H_PME_ENABLE				BIT(1)
6562306a36Sopenharmony_ci	#define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK		GENMASK(4, 2)
6662306a36Sopenharmony_ci	#define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK		GENMASK(9, 7)
6762306a36Sopenharmony_ci	#define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK		GENMASK(13, 12)
6862306a36Sopenharmony_ci	#define USB_R1_U3H_HOST_U3_PORT_DISABLE			BIT(16)
6962306a36Sopenharmony_ci	#define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT	BIT(17)
7062306a36Sopenharmony_ci	#define USB_R1_U3H_HOST_MSI_ENABLE			BIT(18)
7162306a36Sopenharmony_ci	#define USB_R1_U3H_FLADJ_30MHZ_REG_MASK			GENMASK(24, 19)
7262306a36Sopenharmony_ci	#define USB_R1_P30_PCS_TX_SWING_FULL_MASK		GENMASK(31, 25)
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci#define USB_R2							0x08
7562306a36Sopenharmony_ci	#define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK		GENMASK(25, 20)
7662306a36Sopenharmony_ci	#define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK		GENMASK(31, 26)
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci#define USB_R3							0x0c
7962306a36Sopenharmony_ci	#define USB_R3_P30_SSC_ENABLE				BIT(0)
8062306a36Sopenharmony_ci	#define USB_R3_P30_SSC_RANGE_MASK			GENMASK(3, 1)
8162306a36Sopenharmony_ci	#define USB_R3_P30_SSC_REF_CLK_SEL_MASK			GENMASK(12, 4)
8262306a36Sopenharmony_ci	#define USB_R3_P30_REF_SSP_EN				BIT(13)
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci#define USB_R4							0x10
8562306a36Sopenharmony_ci	#define USB_R4_P21_PORT_RESET_0				BIT(0)
8662306a36Sopenharmony_ci	#define USB_R4_P21_SLEEP_M0				BIT(1)
8762306a36Sopenharmony_ci	#define USB_R4_MEM_PD_MASK				GENMASK(3, 2)
8862306a36Sopenharmony_ci	#define USB_R4_P21_ONLY					BIT(4)
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci#define USB_R5							0x14
9162306a36Sopenharmony_ci	#define USB_R5_ID_DIG_SYNC				BIT(0)
9262306a36Sopenharmony_ci	#define USB_R5_ID_DIG_REG				BIT(1)
9362306a36Sopenharmony_ci	#define USB_R5_ID_DIG_CFG_MASK				GENMASK(3, 2)
9462306a36Sopenharmony_ci	#define USB_R5_ID_DIG_EN_0				BIT(4)
9562306a36Sopenharmony_ci	#define USB_R5_ID_DIG_EN_1				BIT(5)
9662306a36Sopenharmony_ci	#define USB_R5_ID_DIG_CURR				BIT(6)
9762306a36Sopenharmony_ci	#define USB_R5_ID_DIG_IRQ				BIT(7)
9862306a36Sopenharmony_ci	#define USB_R5_ID_DIG_TH_MASK				GENMASK(15, 8)
9962306a36Sopenharmony_ci	#define USB_R5_ID_DIG_CNT_MASK				GENMASK(23, 16)
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci#define PHY_COUNT						3
10262306a36Sopenharmony_ci#define USB2_OTG_PHY						1
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic struct clk_bulk_data meson_gxl_clocks[] = {
10562306a36Sopenharmony_ci	{ .id = "usb_ctrl" },
10662306a36Sopenharmony_ci	{ .id = "ddr" },
10762306a36Sopenharmony_ci};
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic struct clk_bulk_data meson_g12a_clocks[] = {
11062306a36Sopenharmony_ci	{ .id = NULL },
11162306a36Sopenharmony_ci};
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic struct clk_bulk_data meson_a1_clocks[] = {
11462306a36Sopenharmony_ci	{ .id = "usb_ctrl" },
11562306a36Sopenharmony_ci	{ .id = "usb_bus" },
11662306a36Sopenharmony_ci	{ .id = "xtal_usb_ctrl" },
11762306a36Sopenharmony_ci};
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic const char * const meson_gxm_phy_names[] = {
12062306a36Sopenharmony_ci	"usb2-phy0", "usb2-phy1", "usb2-phy2",
12162306a36Sopenharmony_ci};
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic const char * const meson_g12a_phy_names[] = {
12462306a36Sopenharmony_ci	"usb2-phy0", "usb2-phy1", "usb3-phy0",
12562306a36Sopenharmony_ci};
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci/*
12862306a36Sopenharmony_ci * Amlogic A1 has a single physical PHY, in slot 1, but still has the
12962306a36Sopenharmony_ci * two U2 PHY controls register blocks like G12A.
13062306a36Sopenharmony_ci * AXG has the similar scheme, thus needs the same tweak.
13162306a36Sopenharmony_ci * Handling the first PHY on slot 1 would need a large amount of code
13262306a36Sopenharmony_ci * changes, and the current management is generic enough to handle it
13362306a36Sopenharmony_ci * correctly when only the "usb2-phy1" phy is specified on-par with the
13462306a36Sopenharmony_ci * DT bindings.
13562306a36Sopenharmony_ci */
13662306a36Sopenharmony_cistatic const char * const meson_a1_phy_names[] = {
13762306a36Sopenharmony_ci	"usb2-phy0", "usb2-phy1"
13862306a36Sopenharmony_ci};
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistruct dwc3_meson_g12a;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistruct dwc3_meson_g12a_drvdata {
14362306a36Sopenharmony_ci	bool otg_phy_host_port_disable;
14462306a36Sopenharmony_ci	struct clk_bulk_data *clks;
14562306a36Sopenharmony_ci	int num_clks;
14662306a36Sopenharmony_ci	const char * const *phy_names;
14762306a36Sopenharmony_ci	int num_phys;
14862306a36Sopenharmony_ci	int (*setup_regmaps)(struct dwc3_meson_g12a *priv, void __iomem *base);
14962306a36Sopenharmony_ci	int (*usb2_init_phy)(struct dwc3_meson_g12a *priv, int i,
15062306a36Sopenharmony_ci			     enum phy_mode mode);
15162306a36Sopenharmony_ci	int (*set_phy_mode)(struct dwc3_meson_g12a *priv, int i,
15262306a36Sopenharmony_ci			    enum phy_mode mode);
15362306a36Sopenharmony_ci	int (*usb_init)(struct dwc3_meson_g12a *priv);
15462306a36Sopenharmony_ci	int (*usb_post_init)(struct dwc3_meson_g12a *priv);
15562306a36Sopenharmony_ci};
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistatic int dwc3_meson_gxl_setup_regmaps(struct dwc3_meson_g12a *priv,
15862306a36Sopenharmony_ci					void __iomem *base);
15962306a36Sopenharmony_cistatic int dwc3_meson_g12a_setup_regmaps(struct dwc3_meson_g12a *priv,
16062306a36Sopenharmony_ci					 void __iomem *base);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic int dwc3_meson_g12a_usb2_init_phy(struct dwc3_meson_g12a *priv, int i,
16362306a36Sopenharmony_ci					 enum phy_mode mode);
16462306a36Sopenharmony_cistatic int dwc3_meson_gxl_usb2_init_phy(struct dwc3_meson_g12a *priv, int i,
16562306a36Sopenharmony_ci					enum phy_mode mode);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic int dwc3_meson_g12a_set_phy_mode(struct dwc3_meson_g12a *priv,
16862306a36Sopenharmony_ci					int i, enum phy_mode mode);
16962306a36Sopenharmony_cistatic int dwc3_meson_gxl_set_phy_mode(struct dwc3_meson_g12a *priv,
17062306a36Sopenharmony_ci				       int i, enum phy_mode mode);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv);
17362306a36Sopenharmony_cistatic int dwc3_meson_gxl_usb_init(struct dwc3_meson_g12a *priv);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic int dwc3_meson_gxl_usb_post_init(struct dwc3_meson_g12a *priv);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci/*
17862306a36Sopenharmony_ci * For GXL and GXM SoCs:
17962306a36Sopenharmony_ci * USB Phy muxing between the DWC2 Device controller and the DWC3 Host
18062306a36Sopenharmony_ci * controller is buggy when switching from Device to Host when USB port
18162306a36Sopenharmony_ci * is unpopulated, it causes the DWC3 to hard crash.
18262306a36Sopenharmony_ci * When populated (including OTG switching with ID pin), the switch works
18362306a36Sopenharmony_ci * like a charm like on the G12A platforms.
18462306a36Sopenharmony_ci * In order to still switch from Host to Device on an USB Type-A port,
18562306a36Sopenharmony_ci * an U2_PORT_DISABLE bit has been added to disconnect the DWC3 Host
18662306a36Sopenharmony_ci * controller from the port, but when used the DWC3 controller must be
18762306a36Sopenharmony_ci * reset to recover usage of the port.
18862306a36Sopenharmony_ci */
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic const struct dwc3_meson_g12a_drvdata gxl_drvdata = {
19162306a36Sopenharmony_ci	.otg_phy_host_port_disable = true,
19262306a36Sopenharmony_ci	.clks = meson_gxl_clocks,
19362306a36Sopenharmony_ci	.num_clks = ARRAY_SIZE(meson_g12a_clocks),
19462306a36Sopenharmony_ci	.phy_names = meson_a1_phy_names,
19562306a36Sopenharmony_ci	.num_phys = ARRAY_SIZE(meson_a1_phy_names),
19662306a36Sopenharmony_ci	.setup_regmaps = dwc3_meson_gxl_setup_regmaps,
19762306a36Sopenharmony_ci	.usb2_init_phy = dwc3_meson_gxl_usb2_init_phy,
19862306a36Sopenharmony_ci	.set_phy_mode = dwc3_meson_gxl_set_phy_mode,
19962306a36Sopenharmony_ci	.usb_init = dwc3_meson_gxl_usb_init,
20062306a36Sopenharmony_ci	.usb_post_init = dwc3_meson_gxl_usb_post_init,
20162306a36Sopenharmony_ci};
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic const struct dwc3_meson_g12a_drvdata gxm_drvdata = {
20462306a36Sopenharmony_ci	.otg_phy_host_port_disable = true,
20562306a36Sopenharmony_ci	.clks = meson_gxl_clocks,
20662306a36Sopenharmony_ci	.num_clks = ARRAY_SIZE(meson_g12a_clocks),
20762306a36Sopenharmony_ci	.phy_names = meson_gxm_phy_names,
20862306a36Sopenharmony_ci	.num_phys = ARRAY_SIZE(meson_gxm_phy_names),
20962306a36Sopenharmony_ci	.setup_regmaps = dwc3_meson_gxl_setup_regmaps,
21062306a36Sopenharmony_ci	.usb2_init_phy = dwc3_meson_gxl_usb2_init_phy,
21162306a36Sopenharmony_ci	.set_phy_mode = dwc3_meson_gxl_set_phy_mode,
21262306a36Sopenharmony_ci	.usb_init = dwc3_meson_gxl_usb_init,
21362306a36Sopenharmony_ci	.usb_post_init = dwc3_meson_gxl_usb_post_init,
21462306a36Sopenharmony_ci};
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic const struct dwc3_meson_g12a_drvdata axg_drvdata = {
21762306a36Sopenharmony_ci	.clks = meson_gxl_clocks,
21862306a36Sopenharmony_ci	.num_clks = ARRAY_SIZE(meson_gxl_clocks),
21962306a36Sopenharmony_ci	.phy_names = meson_a1_phy_names,
22062306a36Sopenharmony_ci	.num_phys = ARRAY_SIZE(meson_a1_phy_names),
22162306a36Sopenharmony_ci	.setup_regmaps = dwc3_meson_gxl_setup_regmaps,
22262306a36Sopenharmony_ci	.usb2_init_phy = dwc3_meson_gxl_usb2_init_phy,
22362306a36Sopenharmony_ci	.set_phy_mode = dwc3_meson_gxl_set_phy_mode,
22462306a36Sopenharmony_ci	.usb_init = dwc3_meson_g12a_usb_init,
22562306a36Sopenharmony_ci	.usb_post_init = dwc3_meson_gxl_usb_post_init,
22662306a36Sopenharmony_ci};
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic const struct dwc3_meson_g12a_drvdata g12a_drvdata = {
22962306a36Sopenharmony_ci	.clks = meson_g12a_clocks,
23062306a36Sopenharmony_ci	.num_clks = ARRAY_SIZE(meson_g12a_clocks),
23162306a36Sopenharmony_ci	.phy_names = meson_g12a_phy_names,
23262306a36Sopenharmony_ci	.num_phys = ARRAY_SIZE(meson_g12a_phy_names),
23362306a36Sopenharmony_ci	.setup_regmaps = dwc3_meson_g12a_setup_regmaps,
23462306a36Sopenharmony_ci	.usb2_init_phy = dwc3_meson_g12a_usb2_init_phy,
23562306a36Sopenharmony_ci	.set_phy_mode = dwc3_meson_g12a_set_phy_mode,
23662306a36Sopenharmony_ci	.usb_init = dwc3_meson_g12a_usb_init,
23762306a36Sopenharmony_ci};
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic const struct dwc3_meson_g12a_drvdata a1_drvdata = {
24062306a36Sopenharmony_ci	.clks = meson_a1_clocks,
24162306a36Sopenharmony_ci	.num_clks = ARRAY_SIZE(meson_a1_clocks),
24262306a36Sopenharmony_ci	.phy_names = meson_a1_phy_names,
24362306a36Sopenharmony_ci	.num_phys = ARRAY_SIZE(meson_a1_phy_names),
24462306a36Sopenharmony_ci	.setup_regmaps = dwc3_meson_g12a_setup_regmaps,
24562306a36Sopenharmony_ci	.usb2_init_phy = dwc3_meson_g12a_usb2_init_phy,
24662306a36Sopenharmony_ci	.set_phy_mode = dwc3_meson_g12a_set_phy_mode,
24762306a36Sopenharmony_ci	.usb_init = dwc3_meson_g12a_usb_init,
24862306a36Sopenharmony_ci};
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistruct dwc3_meson_g12a {
25162306a36Sopenharmony_ci	struct device		*dev;
25262306a36Sopenharmony_ci	struct regmap		*u2p_regmap[PHY_COUNT];
25362306a36Sopenharmony_ci	struct regmap		*usb_glue_regmap;
25462306a36Sopenharmony_ci	struct reset_control	*reset;
25562306a36Sopenharmony_ci	struct phy		*phys[PHY_COUNT];
25662306a36Sopenharmony_ci	enum usb_dr_mode	otg_mode;
25762306a36Sopenharmony_ci	enum phy_mode		otg_phy_mode;
25862306a36Sopenharmony_ci	unsigned int		usb2_ports;
25962306a36Sopenharmony_ci	unsigned int		usb3_ports;
26062306a36Sopenharmony_ci	struct regulator	*vbus;
26162306a36Sopenharmony_ci	struct usb_role_switch_desc switch_desc;
26262306a36Sopenharmony_ci	struct usb_role_switch	*role_switch;
26362306a36Sopenharmony_ci	const struct dwc3_meson_g12a_drvdata *drvdata;
26462306a36Sopenharmony_ci};
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_cistatic int dwc3_meson_gxl_set_phy_mode(struct dwc3_meson_g12a *priv,
26762306a36Sopenharmony_ci					 int i, enum phy_mode mode)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	return phy_set_mode(priv->phys[i], mode);
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic int dwc3_meson_gxl_usb2_init_phy(struct dwc3_meson_g12a *priv, int i,
27362306a36Sopenharmony_ci					enum phy_mode mode)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	/* On GXL PHY must be started in device mode for DWC2 init */
27662306a36Sopenharmony_ci	return priv->drvdata->set_phy_mode(priv, i,
27762306a36Sopenharmony_ci				(i == USB2_OTG_PHY) ? PHY_MODE_USB_DEVICE
27862306a36Sopenharmony_ci						    : PHY_MODE_USB_HOST);
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic int dwc3_meson_g12a_set_phy_mode(struct dwc3_meson_g12a *priv,
28262306a36Sopenharmony_ci					 int i, enum phy_mode mode)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	if (mode == PHY_MODE_USB_HOST)
28562306a36Sopenharmony_ci		regmap_update_bits(priv->u2p_regmap[i], U2P_R0,
28662306a36Sopenharmony_ci				U2P_R0_HOST_DEVICE,
28762306a36Sopenharmony_ci				U2P_R0_HOST_DEVICE);
28862306a36Sopenharmony_ci	else
28962306a36Sopenharmony_ci		regmap_update_bits(priv->u2p_regmap[i], U2P_R0,
29062306a36Sopenharmony_ci				U2P_R0_HOST_DEVICE, 0);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	return 0;
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic int dwc3_meson_g12a_usb2_init_phy(struct dwc3_meson_g12a *priv, int i,
29662306a36Sopenharmony_ci					 enum phy_mode mode)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	int ret;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	regmap_update_bits(priv->u2p_regmap[i], U2P_R0,
30162306a36Sopenharmony_ci			U2P_R0_POWER_ON_RESET,
30262306a36Sopenharmony_ci			U2P_R0_POWER_ON_RESET);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	if (i == USB2_OTG_PHY) {
30562306a36Sopenharmony_ci		regmap_update_bits(priv->u2p_regmap[i], U2P_R0,
30662306a36Sopenharmony_ci				   U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS,
30762306a36Sopenharmony_ci				   U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci		ret = priv->drvdata->set_phy_mode(priv, i, mode);
31062306a36Sopenharmony_ci	} else
31162306a36Sopenharmony_ci		ret = priv->drvdata->set_phy_mode(priv, i,
31262306a36Sopenharmony_ci						  PHY_MODE_USB_HOST);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (ret)
31562306a36Sopenharmony_ci		return ret;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	regmap_update_bits(priv->u2p_regmap[i], U2P_R0,
31862306a36Sopenharmony_ci			U2P_R0_POWER_ON_RESET, 0);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	return 0;
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic int dwc3_meson_g12a_usb2_init(struct dwc3_meson_g12a *priv,
32462306a36Sopenharmony_ci				     enum phy_mode mode)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	int i, ret;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	for (i = 0; i < priv->drvdata->num_phys; ++i) {
32962306a36Sopenharmony_ci		if (!priv->phys[i])
33062306a36Sopenharmony_ci			continue;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci		if (!strstr(priv->drvdata->phy_names[i], "usb2"))
33362306a36Sopenharmony_ci			continue;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci		ret = priv->drvdata->usb2_init_phy(priv, i, mode);
33662306a36Sopenharmony_ci		if (ret)
33762306a36Sopenharmony_ci			return ret;
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	return 0;
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic void dwc3_meson_g12a_usb3_init(struct dwc3_meson_g12a *priv)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	regmap_update_bits(priv->usb_glue_regmap, USB_R3,
34662306a36Sopenharmony_ci			USB_R3_P30_SSC_RANGE_MASK |
34762306a36Sopenharmony_ci			USB_R3_P30_REF_SSP_EN,
34862306a36Sopenharmony_ci			USB_R3_P30_SSC_ENABLE |
34962306a36Sopenharmony_ci			FIELD_PREP(USB_R3_P30_SSC_RANGE_MASK, 2) |
35062306a36Sopenharmony_ci			USB_R3_P30_REF_SSP_EN);
35162306a36Sopenharmony_ci	udelay(2);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	regmap_update_bits(priv->usb_glue_regmap, USB_R2,
35462306a36Sopenharmony_ci			USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK,
35562306a36Sopenharmony_ci			FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK, 0x15));
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	regmap_update_bits(priv->usb_glue_regmap, USB_R2,
35862306a36Sopenharmony_ci			USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK,
35962306a36Sopenharmony_ci			FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK, 0x20));
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	udelay(2);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	regmap_update_bits(priv->usb_glue_regmap, USB_R1,
36462306a36Sopenharmony_ci			USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT,
36562306a36Sopenharmony_ci			USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	regmap_update_bits(priv->usb_glue_regmap, USB_R1,
36862306a36Sopenharmony_ci			USB_R1_P30_PCS_TX_SWING_FULL_MASK,
36962306a36Sopenharmony_ci			FIELD_PREP(USB_R1_P30_PCS_TX_SWING_FULL_MASK, 127));
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic void dwc3_meson_g12a_usb_otg_apply_mode(struct dwc3_meson_g12a *priv,
37362306a36Sopenharmony_ci					       enum phy_mode mode)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	if (mode == PHY_MODE_USB_DEVICE) {
37662306a36Sopenharmony_ci		if (priv->otg_mode != USB_DR_MODE_OTG &&
37762306a36Sopenharmony_ci		    priv->drvdata->otg_phy_host_port_disable)
37862306a36Sopenharmony_ci			/* Isolate the OTG PHY port from the Host Controller */
37962306a36Sopenharmony_ci			regmap_update_bits(priv->usb_glue_regmap, USB_R1,
38062306a36Sopenharmony_ci				USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK,
38162306a36Sopenharmony_ci				FIELD_PREP(USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK,
38262306a36Sopenharmony_ci					   BIT(USB2_OTG_PHY)));
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci		regmap_update_bits(priv->usb_glue_regmap, USB_R0,
38562306a36Sopenharmony_ci				USB_R0_U2D_ACT, USB_R0_U2D_ACT);
38662306a36Sopenharmony_ci		regmap_update_bits(priv->usb_glue_regmap, USB_R0,
38762306a36Sopenharmony_ci				USB_R0_U2D_SS_SCALEDOWN_MODE_MASK, 0);
38862306a36Sopenharmony_ci		regmap_update_bits(priv->usb_glue_regmap, USB_R4,
38962306a36Sopenharmony_ci				USB_R4_P21_SLEEP_M0, USB_R4_P21_SLEEP_M0);
39062306a36Sopenharmony_ci	} else {
39162306a36Sopenharmony_ci		if (priv->otg_mode != USB_DR_MODE_OTG &&
39262306a36Sopenharmony_ci		    priv->drvdata->otg_phy_host_port_disable) {
39362306a36Sopenharmony_ci			regmap_update_bits(priv->usb_glue_regmap, USB_R1,
39462306a36Sopenharmony_ci				USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK, 0);
39562306a36Sopenharmony_ci			msleep(500);
39662306a36Sopenharmony_ci		}
39762306a36Sopenharmony_ci		regmap_update_bits(priv->usb_glue_regmap, USB_R0,
39862306a36Sopenharmony_ci				USB_R0_U2D_ACT, 0);
39962306a36Sopenharmony_ci		regmap_update_bits(priv->usb_glue_regmap, USB_R4,
40062306a36Sopenharmony_ci				USB_R4_P21_SLEEP_M0, 0);
40162306a36Sopenharmony_ci	}
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic int dwc3_meson_g12a_usb_init_glue(struct dwc3_meson_g12a *priv,
40562306a36Sopenharmony_ci					 enum phy_mode mode)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	int ret;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	ret = dwc3_meson_g12a_usb2_init(priv, mode);
41062306a36Sopenharmony_ci	if (ret)
41162306a36Sopenharmony_ci		return ret;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	regmap_update_bits(priv->usb_glue_regmap, USB_R1,
41462306a36Sopenharmony_ci			USB_R1_U3H_FLADJ_30MHZ_REG_MASK,
41562306a36Sopenharmony_ci			FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20));
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	regmap_update_bits(priv->usb_glue_regmap, USB_R5,
41862306a36Sopenharmony_ci			USB_R5_ID_DIG_EN_0,
41962306a36Sopenharmony_ci			USB_R5_ID_DIG_EN_0);
42062306a36Sopenharmony_ci	regmap_update_bits(priv->usb_glue_regmap, USB_R5,
42162306a36Sopenharmony_ci			USB_R5_ID_DIG_EN_1,
42262306a36Sopenharmony_ci			USB_R5_ID_DIG_EN_1);
42362306a36Sopenharmony_ci	regmap_update_bits(priv->usb_glue_regmap, USB_R5,
42462306a36Sopenharmony_ci			USB_R5_ID_DIG_TH_MASK,
42562306a36Sopenharmony_ci			FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff));
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	/* If we have an actual SuperSpeed port, initialize it */
42862306a36Sopenharmony_ci	if (priv->usb3_ports)
42962306a36Sopenharmony_ci		dwc3_meson_g12a_usb3_init(priv);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	dwc3_meson_g12a_usb_otg_apply_mode(priv, mode);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	return 0;
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic const struct regmap_config phy_meson_g12a_usb_glue_regmap_conf = {
43762306a36Sopenharmony_ci	.name = "usb-glue",
43862306a36Sopenharmony_ci	.reg_bits = 8,
43962306a36Sopenharmony_ci	.val_bits = 32,
44062306a36Sopenharmony_ci	.reg_stride = 4,
44162306a36Sopenharmony_ci	.max_register = USB_R5,
44262306a36Sopenharmony_ci};
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_cistatic int dwc3_meson_g12a_get_phys(struct dwc3_meson_g12a *priv)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	const char *phy_name;
44762306a36Sopenharmony_ci	int i;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	for (i = 0 ; i < priv->drvdata->num_phys ; ++i) {
45062306a36Sopenharmony_ci		phy_name = priv->drvdata->phy_names[i];
45162306a36Sopenharmony_ci		priv->phys[i] = devm_phy_optional_get(priv->dev, phy_name);
45262306a36Sopenharmony_ci		if (!priv->phys[i])
45362306a36Sopenharmony_ci			continue;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci		if (IS_ERR(priv->phys[i]))
45662306a36Sopenharmony_ci			return PTR_ERR(priv->phys[i]);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci		if (strstr(phy_name, "usb3"))
45962306a36Sopenharmony_ci			priv->usb3_ports++;
46062306a36Sopenharmony_ci		else
46162306a36Sopenharmony_ci			priv->usb2_ports++;
46262306a36Sopenharmony_ci	}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	dev_info(priv->dev, "USB2 ports: %d\n", priv->usb2_ports);
46562306a36Sopenharmony_ci	dev_info(priv->dev, "USB3 ports: %d\n", priv->usb3_ports);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	return 0;
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_cistatic enum phy_mode dwc3_meson_g12a_get_id(struct dwc3_meson_g12a *priv)
47162306a36Sopenharmony_ci{
47262306a36Sopenharmony_ci	u32 reg;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	regmap_read(priv->usb_glue_regmap, USB_R5, &reg);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	if (reg & (USB_R5_ID_DIG_SYNC | USB_R5_ID_DIG_REG))
47762306a36Sopenharmony_ci		return PHY_MODE_USB_DEVICE;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	return PHY_MODE_USB_HOST;
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistatic int dwc3_meson_g12a_otg_mode_set(struct dwc3_meson_g12a *priv,
48362306a36Sopenharmony_ci					enum phy_mode mode)
48462306a36Sopenharmony_ci{
48562306a36Sopenharmony_ci	int ret;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	if (!priv->phys[USB2_OTG_PHY])
48862306a36Sopenharmony_ci		return -EINVAL;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (mode == PHY_MODE_USB_HOST)
49162306a36Sopenharmony_ci		dev_info(priv->dev, "switching to Host Mode\n");
49262306a36Sopenharmony_ci	else
49362306a36Sopenharmony_ci		dev_info(priv->dev, "switching to Device Mode\n");
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	if (priv->vbus) {
49662306a36Sopenharmony_ci		if (mode == PHY_MODE_USB_DEVICE)
49762306a36Sopenharmony_ci			ret = regulator_disable(priv->vbus);
49862306a36Sopenharmony_ci		else
49962306a36Sopenharmony_ci			ret = regulator_enable(priv->vbus);
50062306a36Sopenharmony_ci		if (ret)
50162306a36Sopenharmony_ci			return ret;
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	priv->otg_phy_mode = mode;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	ret = priv->drvdata->set_phy_mode(priv, USB2_OTG_PHY, mode);
50762306a36Sopenharmony_ci	if (ret)
50862306a36Sopenharmony_ci		return ret;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	dwc3_meson_g12a_usb_otg_apply_mode(priv, mode);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	return 0;
51362306a36Sopenharmony_ci}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_cistatic int dwc3_meson_g12a_role_set(struct usb_role_switch *sw,
51662306a36Sopenharmony_ci				    enum usb_role role)
51762306a36Sopenharmony_ci{
51862306a36Sopenharmony_ci	struct dwc3_meson_g12a *priv = usb_role_switch_get_drvdata(sw);
51962306a36Sopenharmony_ci	enum phy_mode mode;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	if (role == USB_ROLE_NONE)
52262306a36Sopenharmony_ci		return 0;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	mode = (role == USB_ROLE_HOST) ? PHY_MODE_USB_HOST
52562306a36Sopenharmony_ci				       : PHY_MODE_USB_DEVICE;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	if (mode == priv->otg_phy_mode)
52862306a36Sopenharmony_ci		return 0;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	if (priv->drvdata->otg_phy_host_port_disable)
53162306a36Sopenharmony_ci		dev_warn_once(priv->dev, "Broken manual OTG switch\n");
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	return dwc3_meson_g12a_otg_mode_set(priv, mode);
53462306a36Sopenharmony_ci}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_cistatic enum usb_role dwc3_meson_g12a_role_get(struct usb_role_switch *sw)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	struct dwc3_meson_g12a *priv = usb_role_switch_get_drvdata(sw);
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	return priv->otg_phy_mode == PHY_MODE_USB_HOST ?
54162306a36Sopenharmony_ci		USB_ROLE_HOST : USB_ROLE_DEVICE;
54262306a36Sopenharmony_ci}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_cistatic irqreturn_t dwc3_meson_g12a_irq_thread(int irq, void *data)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	struct dwc3_meson_g12a *priv = data;
54762306a36Sopenharmony_ci	enum phy_mode otg_id;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	otg_id = dwc3_meson_g12a_get_id(priv);
55062306a36Sopenharmony_ci	if (otg_id != priv->otg_phy_mode) {
55162306a36Sopenharmony_ci		if (dwc3_meson_g12a_otg_mode_set(priv, otg_id))
55262306a36Sopenharmony_ci			dev_warn(priv->dev, "Failed to switch OTG mode\n");
55362306a36Sopenharmony_ci	}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	regmap_update_bits(priv->usb_glue_regmap, USB_R5,
55662306a36Sopenharmony_ci			   USB_R5_ID_DIG_IRQ, 0);
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	return IRQ_HANDLED;
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_cistatic struct device *dwc3_meson_g12_find_child(struct device *dev,
56262306a36Sopenharmony_ci						const char *compatible)
56362306a36Sopenharmony_ci{
56462306a36Sopenharmony_ci	struct platform_device *pdev;
56562306a36Sopenharmony_ci	struct device_node *np;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	np = of_get_compatible_child(dev->of_node, compatible);
56862306a36Sopenharmony_ci	if (!np)
56962306a36Sopenharmony_ci		return NULL;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	pdev = of_find_device_by_node(np);
57262306a36Sopenharmony_ci	of_node_put(np);
57362306a36Sopenharmony_ci	if (!pdev)
57462306a36Sopenharmony_ci		return NULL;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	return &pdev->dev;
57762306a36Sopenharmony_ci}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_cistatic int dwc3_meson_g12a_otg_init(struct platform_device *pdev,
58062306a36Sopenharmony_ci				    struct dwc3_meson_g12a *priv)
58162306a36Sopenharmony_ci{
58262306a36Sopenharmony_ci	enum phy_mode otg_id;
58362306a36Sopenharmony_ci	int ret, irq;
58462306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	if (priv->otg_mode == USB_DR_MODE_OTG) {
58762306a36Sopenharmony_ci		/* Ack irq before registering */
58862306a36Sopenharmony_ci		regmap_update_bits(priv->usb_glue_regmap, USB_R5,
58962306a36Sopenharmony_ci				   USB_R5_ID_DIG_IRQ, 0);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci		irq = platform_get_irq(pdev, 0);
59262306a36Sopenharmony_ci		if (irq < 0)
59362306a36Sopenharmony_ci			return irq;
59462306a36Sopenharmony_ci		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
59562306a36Sopenharmony_ci						dwc3_meson_g12a_irq_thread,
59662306a36Sopenharmony_ci						IRQF_ONESHOT, pdev->name, priv);
59762306a36Sopenharmony_ci		if (ret)
59862306a36Sopenharmony_ci			return ret;
59962306a36Sopenharmony_ci	}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	/* Setup OTG mode corresponding to the ID pin */
60262306a36Sopenharmony_ci	if (priv->otg_mode == USB_DR_MODE_OTG) {
60362306a36Sopenharmony_ci		otg_id = dwc3_meson_g12a_get_id(priv);
60462306a36Sopenharmony_ci		if (otg_id != priv->otg_phy_mode) {
60562306a36Sopenharmony_ci			if (dwc3_meson_g12a_otg_mode_set(priv, otg_id))
60662306a36Sopenharmony_ci				dev_warn(dev, "Failed to switch OTG mode\n");
60762306a36Sopenharmony_ci		}
60862306a36Sopenharmony_ci	}
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	/* Setup role switcher */
61162306a36Sopenharmony_ci	priv->switch_desc.usb2_port = dwc3_meson_g12_find_child(dev,
61262306a36Sopenharmony_ci								"snps,dwc3");
61362306a36Sopenharmony_ci	priv->switch_desc.udc = dwc3_meson_g12_find_child(dev, "snps,dwc2");
61462306a36Sopenharmony_ci	priv->switch_desc.allow_userspace_control = true;
61562306a36Sopenharmony_ci	priv->switch_desc.set = dwc3_meson_g12a_role_set;
61662306a36Sopenharmony_ci	priv->switch_desc.get = dwc3_meson_g12a_role_get;
61762306a36Sopenharmony_ci	priv->switch_desc.driver_data = priv;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	priv->role_switch = usb_role_switch_register(dev, &priv->switch_desc);
62062306a36Sopenharmony_ci	if (IS_ERR(priv->role_switch))
62162306a36Sopenharmony_ci		dev_warn(dev, "Unable to register Role Switch\n");
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	return 0;
62462306a36Sopenharmony_ci}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_cistatic int dwc3_meson_gxl_setup_regmaps(struct dwc3_meson_g12a *priv,
62762306a36Sopenharmony_ci					void __iomem *base)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	/* GXL controls the PHY mode in the PHY registers unlike G12A */
63062306a36Sopenharmony_ci	priv->usb_glue_regmap = devm_regmap_init_mmio(priv->dev, base,
63162306a36Sopenharmony_ci					&phy_meson_g12a_usb_glue_regmap_conf);
63262306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(priv->usb_glue_regmap);
63362306a36Sopenharmony_ci}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_cistatic int dwc3_meson_g12a_setup_regmaps(struct dwc3_meson_g12a *priv,
63662306a36Sopenharmony_ci					 void __iomem *base)
63762306a36Sopenharmony_ci{
63862306a36Sopenharmony_ci	int i;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	priv->usb_glue_regmap = devm_regmap_init_mmio(priv->dev,
64162306a36Sopenharmony_ci					base + G12A_GLUE_OFFSET,
64262306a36Sopenharmony_ci					&phy_meson_g12a_usb_glue_regmap_conf);
64362306a36Sopenharmony_ci	if (IS_ERR(priv->usb_glue_regmap))
64462306a36Sopenharmony_ci		return PTR_ERR(priv->usb_glue_regmap);
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	/* Create a regmap for each USB2 PHY control register set */
64762306a36Sopenharmony_ci	for (i = 0; i < priv->drvdata->num_phys; i++) {
64862306a36Sopenharmony_ci		struct regmap_config u2p_regmap_config = {
64962306a36Sopenharmony_ci			.reg_bits = 8,
65062306a36Sopenharmony_ci			.val_bits = 32,
65162306a36Sopenharmony_ci			.reg_stride = 4,
65262306a36Sopenharmony_ci			.max_register = U2P_R1,
65362306a36Sopenharmony_ci		};
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci		if (!strstr(priv->drvdata->phy_names[i], "usb2"))
65662306a36Sopenharmony_ci			continue;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci		u2p_regmap_config.name = devm_kasprintf(priv->dev, GFP_KERNEL,
65962306a36Sopenharmony_ci							"u2p-%d", i);
66062306a36Sopenharmony_ci		if (!u2p_regmap_config.name)
66162306a36Sopenharmony_ci			return -ENOMEM;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci		priv->u2p_regmap[i] = devm_regmap_init_mmio(priv->dev,
66462306a36Sopenharmony_ci						base + (i * U2P_REG_SIZE),
66562306a36Sopenharmony_ci						&u2p_regmap_config);
66662306a36Sopenharmony_ci		if (IS_ERR(priv->u2p_regmap[i]))
66762306a36Sopenharmony_ci			return PTR_ERR(priv->u2p_regmap[i]);
66862306a36Sopenharmony_ci	}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	return 0;
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_cistatic int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv)
67462306a36Sopenharmony_ci{
67562306a36Sopenharmony_ci	return dwc3_meson_g12a_usb_init_glue(priv, priv->otg_phy_mode);
67662306a36Sopenharmony_ci}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_cistatic int dwc3_meson_gxl_usb_init(struct dwc3_meson_g12a *priv)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	return dwc3_meson_g12a_usb_init_glue(priv, PHY_MODE_USB_DEVICE);
68162306a36Sopenharmony_ci}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_cistatic int dwc3_meson_gxl_usb_post_init(struct dwc3_meson_g12a *priv)
68462306a36Sopenharmony_ci{
68562306a36Sopenharmony_ci	int ret;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	ret = priv->drvdata->set_phy_mode(priv, USB2_OTG_PHY,
68862306a36Sopenharmony_ci					  priv->otg_phy_mode);
68962306a36Sopenharmony_ci	if (ret)
69062306a36Sopenharmony_ci		return ret;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	dwc3_meson_g12a_usb_otg_apply_mode(priv, priv->otg_phy_mode);
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	return 0;
69562306a36Sopenharmony_ci}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_cistatic int dwc3_meson_g12a_probe(struct platform_device *pdev)
69862306a36Sopenharmony_ci{
69962306a36Sopenharmony_ci	struct dwc3_meson_g12a	*priv;
70062306a36Sopenharmony_ci	struct device		*dev = &pdev->dev;
70162306a36Sopenharmony_ci	struct device_node	*np = dev->of_node;
70262306a36Sopenharmony_ci	void __iomem *base;
70362306a36Sopenharmony_ci	int ret, i;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
70662306a36Sopenharmony_ci	if (!priv)
70762306a36Sopenharmony_ci		return -ENOMEM;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	base = devm_platform_ioremap_resource(pdev, 0);
71062306a36Sopenharmony_ci	if (IS_ERR(base))
71162306a36Sopenharmony_ci		return PTR_ERR(base);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	priv->drvdata = of_device_get_match_data(&pdev->dev);
71462306a36Sopenharmony_ci	priv->dev = dev;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	priv->vbus = devm_regulator_get_optional(dev, "vbus");
71762306a36Sopenharmony_ci	if (IS_ERR(priv->vbus)) {
71862306a36Sopenharmony_ci		if (PTR_ERR(priv->vbus) == -EPROBE_DEFER)
71962306a36Sopenharmony_ci			return PTR_ERR(priv->vbus);
72062306a36Sopenharmony_ci		priv->vbus = NULL;
72162306a36Sopenharmony_ci	}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	ret = devm_clk_bulk_get(dev,
72462306a36Sopenharmony_ci				priv->drvdata->num_clks,
72562306a36Sopenharmony_ci				priv->drvdata->clks);
72662306a36Sopenharmony_ci	if (ret)
72762306a36Sopenharmony_ci		return ret;
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	ret = clk_bulk_prepare_enable(priv->drvdata->num_clks,
73062306a36Sopenharmony_ci				      priv->drvdata->clks);
73162306a36Sopenharmony_ci	if (ret)
73262306a36Sopenharmony_ci		return ret;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	platform_set_drvdata(pdev, priv);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	priv->reset = devm_reset_control_get_shared(dev, NULL);
73762306a36Sopenharmony_ci	if (IS_ERR(priv->reset)) {
73862306a36Sopenharmony_ci		ret = PTR_ERR(priv->reset);
73962306a36Sopenharmony_ci		dev_err(dev, "failed to get device reset, err=%d\n", ret);
74062306a36Sopenharmony_ci		goto err_disable_clks;
74162306a36Sopenharmony_ci	}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	ret = reset_control_reset(priv->reset);
74462306a36Sopenharmony_ci	if (ret)
74562306a36Sopenharmony_ci		goto err_disable_clks;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	ret = dwc3_meson_g12a_get_phys(priv);
74862306a36Sopenharmony_ci	if (ret)
74962306a36Sopenharmony_ci		goto err_rearm;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	ret = priv->drvdata->setup_regmaps(priv, base);
75262306a36Sopenharmony_ci	if (ret)
75362306a36Sopenharmony_ci		goto err_rearm;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	if (priv->vbus) {
75662306a36Sopenharmony_ci		ret = regulator_enable(priv->vbus);
75762306a36Sopenharmony_ci		if (ret)
75862306a36Sopenharmony_ci			goto err_rearm;
75962306a36Sopenharmony_ci	}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	/* Get dr_mode */
76262306a36Sopenharmony_ci	priv->otg_mode = usb_get_dr_mode(dev);
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	if (priv->otg_mode == USB_DR_MODE_PERIPHERAL)
76562306a36Sopenharmony_ci		priv->otg_phy_mode = PHY_MODE_USB_DEVICE;
76662306a36Sopenharmony_ci	else
76762306a36Sopenharmony_ci		priv->otg_phy_mode = PHY_MODE_USB_HOST;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	ret = priv->drvdata->usb_init(priv);
77062306a36Sopenharmony_ci	if (ret)
77162306a36Sopenharmony_ci		goto err_disable_regulator;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	/* Init PHYs */
77462306a36Sopenharmony_ci	for (i = 0 ; i < PHY_COUNT ; ++i) {
77562306a36Sopenharmony_ci		ret = phy_init(priv->phys[i]);
77662306a36Sopenharmony_ci		if (ret)
77762306a36Sopenharmony_ci			goto err_disable_regulator;
77862306a36Sopenharmony_ci	}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	/* Set PHY Power */
78162306a36Sopenharmony_ci	for (i = 0 ; i < PHY_COUNT ; ++i) {
78262306a36Sopenharmony_ci		ret = phy_power_on(priv->phys[i]);
78362306a36Sopenharmony_ci		if (ret)
78462306a36Sopenharmony_ci			goto err_phys_exit;
78562306a36Sopenharmony_ci	}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	if (priv->drvdata->usb_post_init) {
78862306a36Sopenharmony_ci		ret = priv->drvdata->usb_post_init(priv);
78962306a36Sopenharmony_ci		if (ret)
79062306a36Sopenharmony_ci			goto err_phys_power;
79162306a36Sopenharmony_ci	}
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	ret = of_platform_populate(np, NULL, NULL, dev);
79462306a36Sopenharmony_ci	if (ret)
79562306a36Sopenharmony_ci		goto err_phys_power;
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	ret = dwc3_meson_g12a_otg_init(pdev, priv);
79862306a36Sopenharmony_ci	if (ret)
79962306a36Sopenharmony_ci		goto err_plat_depopulate;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	pm_runtime_set_active(dev);
80262306a36Sopenharmony_ci	pm_runtime_enable(dev);
80362306a36Sopenharmony_ci	pm_runtime_get_sync(dev);
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	return 0;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_cierr_plat_depopulate:
80862306a36Sopenharmony_ci	of_platform_depopulate(dev);
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_cierr_phys_power:
81162306a36Sopenharmony_ci	for (i = 0 ; i < PHY_COUNT ; ++i)
81262306a36Sopenharmony_ci		phy_power_off(priv->phys[i]);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_cierr_phys_exit:
81562306a36Sopenharmony_ci	for (i = 0 ; i < PHY_COUNT ; ++i)
81662306a36Sopenharmony_ci		phy_exit(priv->phys[i]);
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_cierr_disable_regulator:
81962306a36Sopenharmony_ci	if (priv->vbus)
82062306a36Sopenharmony_ci		regulator_disable(priv->vbus);
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_cierr_rearm:
82362306a36Sopenharmony_ci	reset_control_rearm(priv->reset);
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_cierr_disable_clks:
82662306a36Sopenharmony_ci	clk_bulk_disable_unprepare(priv->drvdata->num_clks,
82762306a36Sopenharmony_ci				   priv->drvdata->clks);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	return ret;
83062306a36Sopenharmony_ci}
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_cistatic void dwc3_meson_g12a_remove(struct platform_device *pdev)
83362306a36Sopenharmony_ci{
83462306a36Sopenharmony_ci	struct dwc3_meson_g12a *priv = platform_get_drvdata(pdev);
83562306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
83662306a36Sopenharmony_ci	int i;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	usb_role_switch_unregister(priv->role_switch);
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	of_platform_depopulate(dev);
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	for (i = 0 ; i < PHY_COUNT ; ++i) {
84362306a36Sopenharmony_ci		phy_power_off(priv->phys[i]);
84462306a36Sopenharmony_ci		phy_exit(priv->phys[i]);
84562306a36Sopenharmony_ci	}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	pm_runtime_disable(dev);
84862306a36Sopenharmony_ci	pm_runtime_put_noidle(dev);
84962306a36Sopenharmony_ci	pm_runtime_set_suspended(dev);
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	reset_control_rearm(priv->reset);
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	clk_bulk_disable_unprepare(priv->drvdata->num_clks,
85462306a36Sopenharmony_ci				   priv->drvdata->clks);
85562306a36Sopenharmony_ci}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_cistatic int __maybe_unused dwc3_meson_g12a_runtime_suspend(struct device *dev)
85862306a36Sopenharmony_ci{
85962306a36Sopenharmony_ci	struct dwc3_meson_g12a	*priv = dev_get_drvdata(dev);
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	clk_bulk_disable_unprepare(priv->drvdata->num_clks,
86262306a36Sopenharmony_ci				   priv->drvdata->clks);
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	return 0;
86562306a36Sopenharmony_ci}
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_cistatic int __maybe_unused dwc3_meson_g12a_runtime_resume(struct device *dev)
86862306a36Sopenharmony_ci{
86962306a36Sopenharmony_ci	struct dwc3_meson_g12a	*priv = dev_get_drvdata(dev);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	return clk_bulk_prepare_enable(priv->drvdata->num_clks,
87262306a36Sopenharmony_ci				       priv->drvdata->clks);
87362306a36Sopenharmony_ci}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_cistatic int __maybe_unused dwc3_meson_g12a_suspend(struct device *dev)
87662306a36Sopenharmony_ci{
87762306a36Sopenharmony_ci	struct dwc3_meson_g12a *priv = dev_get_drvdata(dev);
87862306a36Sopenharmony_ci	int i, ret;
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	if (priv->vbus && priv->otg_phy_mode == PHY_MODE_USB_HOST) {
88162306a36Sopenharmony_ci		ret = regulator_disable(priv->vbus);
88262306a36Sopenharmony_ci		if (ret)
88362306a36Sopenharmony_ci			return ret;
88462306a36Sopenharmony_ci	}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	for (i = 0 ; i < PHY_COUNT ; ++i) {
88762306a36Sopenharmony_ci		phy_power_off(priv->phys[i]);
88862306a36Sopenharmony_ci		phy_exit(priv->phys[i]);
88962306a36Sopenharmony_ci	}
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	reset_control_rearm(priv->reset);
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	return 0;
89462306a36Sopenharmony_ci}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_cistatic int __maybe_unused dwc3_meson_g12a_resume(struct device *dev)
89762306a36Sopenharmony_ci{
89862306a36Sopenharmony_ci	struct dwc3_meson_g12a *priv = dev_get_drvdata(dev);
89962306a36Sopenharmony_ci	int i, ret;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	ret = reset_control_reset(priv->reset);
90262306a36Sopenharmony_ci	if (ret)
90362306a36Sopenharmony_ci		return ret;
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	ret = priv->drvdata->usb_init(priv);
90662306a36Sopenharmony_ci	if (ret)
90762306a36Sopenharmony_ci		return ret;
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	/* Init PHYs */
91062306a36Sopenharmony_ci	for (i = 0 ; i < PHY_COUNT ; ++i) {
91162306a36Sopenharmony_ci		ret = phy_init(priv->phys[i]);
91262306a36Sopenharmony_ci		if (ret)
91362306a36Sopenharmony_ci			return ret;
91462306a36Sopenharmony_ci	}
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	/* Set PHY Power */
91762306a36Sopenharmony_ci	for (i = 0 ; i < PHY_COUNT ; ++i) {
91862306a36Sopenharmony_ci		ret = phy_power_on(priv->phys[i]);
91962306a36Sopenharmony_ci		if (ret)
92062306a36Sopenharmony_ci			return ret;
92162306a36Sopenharmony_ci	}
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	if (priv->vbus && priv->otg_phy_mode == PHY_MODE_USB_HOST) {
92462306a36Sopenharmony_ci		ret = regulator_enable(priv->vbus);
92562306a36Sopenharmony_ci		if (ret)
92662306a36Sopenharmony_ci			return ret;
92762306a36Sopenharmony_ci	}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	if (priv->drvdata->usb_post_init) {
93062306a36Sopenharmony_ci		ret = priv->drvdata->usb_post_init(priv);
93162306a36Sopenharmony_ci		if (ret)
93262306a36Sopenharmony_ci			return ret;
93362306a36Sopenharmony_ci	}
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	return 0;
93662306a36Sopenharmony_ci}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_cistatic const struct dev_pm_ops dwc3_meson_g12a_dev_pm_ops = {
93962306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(dwc3_meson_g12a_suspend, dwc3_meson_g12a_resume)
94062306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(dwc3_meson_g12a_runtime_suspend,
94162306a36Sopenharmony_ci			   dwc3_meson_g12a_runtime_resume, NULL)
94262306a36Sopenharmony_ci};
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_cistatic const struct of_device_id dwc3_meson_g12a_match[] = {
94562306a36Sopenharmony_ci	{
94662306a36Sopenharmony_ci		.compatible = "amlogic,meson-gxl-usb-ctrl",
94762306a36Sopenharmony_ci		.data = &gxl_drvdata,
94862306a36Sopenharmony_ci	},
94962306a36Sopenharmony_ci	{
95062306a36Sopenharmony_ci		.compatible = "amlogic,meson-gxm-usb-ctrl",
95162306a36Sopenharmony_ci		.data = &gxm_drvdata,
95262306a36Sopenharmony_ci	},
95362306a36Sopenharmony_ci	{
95462306a36Sopenharmony_ci		.compatible = "amlogic,meson-axg-usb-ctrl",
95562306a36Sopenharmony_ci		.data = &axg_drvdata,
95662306a36Sopenharmony_ci	},
95762306a36Sopenharmony_ci	{
95862306a36Sopenharmony_ci		.compatible = "amlogic,meson-g12a-usb-ctrl",
95962306a36Sopenharmony_ci		.data = &g12a_drvdata,
96062306a36Sopenharmony_ci	},
96162306a36Sopenharmony_ci	{
96262306a36Sopenharmony_ci		.compatible = "amlogic,meson-a1-usb-ctrl",
96362306a36Sopenharmony_ci		.data = &a1_drvdata,
96462306a36Sopenharmony_ci	},
96562306a36Sopenharmony_ci	{ /* Sentinel */ }
96662306a36Sopenharmony_ci};
96762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, dwc3_meson_g12a_match);
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_cistatic struct platform_driver dwc3_meson_g12a_driver = {
97062306a36Sopenharmony_ci	.probe		= dwc3_meson_g12a_probe,
97162306a36Sopenharmony_ci	.remove_new	= dwc3_meson_g12a_remove,
97262306a36Sopenharmony_ci	.driver		= {
97362306a36Sopenharmony_ci		.name	= "dwc3-meson-g12a",
97462306a36Sopenharmony_ci		.of_match_table = dwc3_meson_g12a_match,
97562306a36Sopenharmony_ci		.pm	= &dwc3_meson_g12a_dev_pm_ops,
97662306a36Sopenharmony_ci	},
97762306a36Sopenharmony_ci};
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_cimodule_platform_driver(dwc3_meson_g12a_driver);
98062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
98162306a36Sopenharmony_ciMODULE_DESCRIPTION("Amlogic Meson G12A USB Glue Layer");
98262306a36Sopenharmony_ciMODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
983