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, ®); 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