1c9999337SNeil Armstrong // SPDX-License-Identifier: GPL-2.0 2c9999337SNeil Armstrong /* 3c9999337SNeil Armstrong * USB Glue for Amlogic G12A SoCs 4c9999337SNeil Armstrong * 5c9999337SNeil Armstrong * Copyright (c) 2019 BayLibre, SAS 6c9999337SNeil Armstrong * Author: Neil Armstrong <narmstrong@baylibre.com> 7c9999337SNeil Armstrong */ 8c9999337SNeil Armstrong 9c9999337SNeil Armstrong /* 10c9999337SNeil Armstrong * The USB is organized with a glue around the DWC3 Controller IP as : 11c9999337SNeil Armstrong * - Control registers for each USB2 Ports 12c9999337SNeil Armstrong * - Control registers for the USB PHY layer 13c9999337SNeil Armstrong * - SuperSpeed PHY can be enabled only if port is used 14f90db107SNeil Armstrong * - Dynamic OTG switching with ID change interrupt 15c9999337SNeil Armstrong */ 16c9999337SNeil Armstrong 17c9999337SNeil Armstrong #include <linux/module.h> 18c9999337SNeil Armstrong #include <linux/kernel.h> 19c9999337SNeil Armstrong #include <linux/platform_device.h> 20c9999337SNeil Armstrong #include <linux/clk.h> 21c9999337SNeil Armstrong #include <linux/of.h> 22c9999337SNeil Armstrong #include <linux/of_platform.h> 23c9999337SNeil Armstrong #include <linux/pm_runtime.h> 24c9999337SNeil Armstrong #include <linux/regmap.h> 25c9999337SNeil Armstrong #include <linux/bitfield.h> 26c9999337SNeil Armstrong #include <linux/bitops.h> 27c9999337SNeil Armstrong #include <linux/reset.h> 28c9999337SNeil Armstrong #include <linux/phy/phy.h> 29c9999337SNeil Armstrong #include <linux/usb/otg.h> 30c9999337SNeil Armstrong #include <linux/usb/role.h> 31c9999337SNeil Armstrong #include <linux/regulator/consumer.h> 32c9999337SNeil Armstrong 33013af227SNeil Armstrong /* USB2 Ports Control Registers, offsets are per-port */ 34c9999337SNeil Armstrong 35c9999337SNeil Armstrong #define U2P_REG_SIZE 0x20 36c9999337SNeil Armstrong 37c9999337SNeil Armstrong #define U2P_R0 0x0 38c9999337SNeil Armstrong #define U2P_R0_HOST_DEVICE BIT(0) 39c9999337SNeil Armstrong #define U2P_R0_POWER_OK BIT(1) 40c9999337SNeil Armstrong #define U2P_R0_HAST_MODE BIT(2) 41c9999337SNeil Armstrong #define U2P_R0_POWER_ON_RESET BIT(3) 42c9999337SNeil Armstrong #define U2P_R0_ID_PULLUP BIT(4) 43c9999337SNeil Armstrong #define U2P_R0_DRV_VBUS BIT(5) 44c9999337SNeil Armstrong 45c9999337SNeil Armstrong #define U2P_R1 0x4 46c9999337SNeil Armstrong #define U2P_R1_PHY_READY BIT(0) 47c9999337SNeil Armstrong #define U2P_R1_ID_DIG BIT(1) 48c9999337SNeil Armstrong #define U2P_R1_OTG_SESSION_VALID BIT(2) 49c9999337SNeil Armstrong #define U2P_R1_VBUS_VALID BIT(3) 50c9999337SNeil Armstrong 51c9999337SNeil Armstrong /* USB Glue Control Registers */ 52c9999337SNeil Armstrong 53013af227SNeil Armstrong #define G12A_GLUE_OFFSET 0x80 54013af227SNeil Armstrong 55013af227SNeil Armstrong #define USB_R0 0x00 56c9999337SNeil Armstrong #define USB_R0_P30_LANE0_TX2RX_LOOPBACK BIT(17) 57c9999337SNeil Armstrong #define USB_R0_P30_LANE0_EXT_PCLK_REQ BIT(18) 58c9999337SNeil Armstrong #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK GENMASK(28, 19) 59c9999337SNeil Armstrong #define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK GENMASK(30, 29) 60c9999337SNeil Armstrong #define USB_R0_U2D_ACT BIT(31) 61c9999337SNeil Armstrong 62013af227SNeil Armstrong #define USB_R1 0x04 63c9999337SNeil Armstrong #define USB_R1_U3H_BIGENDIAN_GS BIT(0) 64c9999337SNeil Armstrong #define USB_R1_U3H_PME_ENABLE BIT(1) 65c9999337SNeil Armstrong #define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK GENMASK(4, 2) 66c9999337SNeil Armstrong #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK GENMASK(9, 7) 67c9999337SNeil Armstrong #define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK GENMASK(13, 12) 68c9999337SNeil Armstrong #define USB_R1_U3H_HOST_U3_PORT_DISABLE BIT(16) 69c9999337SNeil Armstrong #define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT BIT(17) 70c9999337SNeil Armstrong #define USB_R1_U3H_HOST_MSI_ENABLE BIT(18) 71c9999337SNeil Armstrong #define USB_R1_U3H_FLADJ_30MHZ_REG_MASK GENMASK(24, 19) 72c9999337SNeil Armstrong #define USB_R1_P30_PCS_TX_SWING_FULL_MASK GENMASK(31, 25) 73c9999337SNeil Armstrong 74013af227SNeil Armstrong #define USB_R2 0x08 75c9999337SNeil Armstrong #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(25, 20) 76c9999337SNeil Armstrong #define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK GENMASK(31, 26) 77c9999337SNeil Armstrong 78013af227SNeil Armstrong #define USB_R3 0x0c 79c9999337SNeil Armstrong #define USB_R3_P30_SSC_ENABLE BIT(0) 80c9999337SNeil Armstrong #define USB_R3_P30_SSC_RANGE_MASK GENMASK(3, 1) 81c9999337SNeil Armstrong #define USB_R3_P30_SSC_REF_CLK_SEL_MASK GENMASK(12, 4) 82c9999337SNeil Armstrong #define USB_R3_P30_REF_SSP_EN BIT(13) 83c9999337SNeil Armstrong 84013af227SNeil Armstrong #define USB_R4 0x10 85c9999337SNeil Armstrong #define USB_R4_P21_PORT_RESET_0 BIT(0) 86c9999337SNeil Armstrong #define USB_R4_P21_SLEEP_M0 BIT(1) 87c9999337SNeil Armstrong #define USB_R4_MEM_PD_MASK GENMASK(3, 2) 88c9999337SNeil Armstrong #define USB_R4_P21_ONLY BIT(4) 89c9999337SNeil Armstrong 90013af227SNeil Armstrong #define USB_R5 0x14 91c9999337SNeil Armstrong #define USB_R5_ID_DIG_SYNC BIT(0) 92c9999337SNeil Armstrong #define USB_R5_ID_DIG_REG BIT(1) 93c9999337SNeil Armstrong #define USB_R5_ID_DIG_CFG_MASK GENMASK(3, 2) 94c9999337SNeil Armstrong #define USB_R5_ID_DIG_EN_0 BIT(4) 95c9999337SNeil Armstrong #define USB_R5_ID_DIG_EN_1 BIT(5) 96c9999337SNeil Armstrong #define USB_R5_ID_DIG_CURR BIT(6) 97c9999337SNeil Armstrong #define USB_R5_ID_DIG_IRQ BIT(7) 98c9999337SNeil Armstrong #define USB_R5_ID_DIG_TH_MASK GENMASK(15, 8) 99c9999337SNeil Armstrong #define USB_R5_ID_DIG_CNT_MASK GENMASK(23, 16) 100c9999337SNeil Armstrong 1015174564cSNeil Armstrong #define PHY_COUNT 3 1025174564cSNeil Armstrong #define USB2_OTG_PHY 1 103c9999337SNeil Armstrong 104a9fc15e0SNeil Armstrong static struct clk_bulk_data meson_gxl_clocks[] = { 105a9fc15e0SNeil Armstrong { .id = "usb_ctrl" }, 106a9fc15e0SNeil Armstrong { .id = "ddr" }, 107a9fc15e0SNeil Armstrong }; 108a9fc15e0SNeil Armstrong 1091e355f21SHanjie Lin static struct clk_bulk_data meson_g12a_clocks[] = { 1101e355f21SHanjie Lin { .id = NULL }, 1111e355f21SHanjie Lin }; 1121e355f21SHanjie Lin 1131e355f21SHanjie Lin static struct clk_bulk_data meson_a1_clocks[] = { 1141e355f21SHanjie Lin { .id = "usb_ctrl" }, 1151e355f21SHanjie Lin { .id = "usb_bus" }, 1161e355f21SHanjie Lin { .id = "xtal_usb_ctrl" }, 1171e355f21SHanjie Lin }; 1181e355f21SHanjie Lin 119e5ee93d4SFelipe Balbi static const char * const meson_gxm_phy_names[] = { 120a9fc15e0SNeil Armstrong "usb2-phy0", "usb2-phy1", "usb2-phy2", 121a9fc15e0SNeil Armstrong }; 122a9fc15e0SNeil Armstrong 123e5ee93d4SFelipe Balbi static const char * const meson_g12a_phy_names[] = { 1245174564cSNeil Armstrong "usb2-phy0", "usb2-phy1", "usb3-phy0", 1255174564cSNeil Armstrong }; 1265174564cSNeil Armstrong 1275174564cSNeil Armstrong /* 1285174564cSNeil Armstrong * Amlogic A1 has a single physical PHY, in slot 1, but still has the 1295174564cSNeil Armstrong * two U2 PHY controls register blocks like G12A. 13065f3d449SNeil Armstrong * AXG has the similar scheme, thus needs the same tweak. 1315174564cSNeil Armstrong * Handling the first PHY on slot 1 would need a large amount of code 1325174564cSNeil Armstrong * changes, and the current management is generic enough to handle it 1335174564cSNeil Armstrong * correctly when only the "usb2-phy1" phy is specified on-par with the 1345174564cSNeil Armstrong * DT bindings. 1355174564cSNeil Armstrong */ 136e5ee93d4SFelipe Balbi static const char * const meson_a1_phy_names[] = { 1375174564cSNeil Armstrong "usb2-phy0", "usb2-phy1" 1385174564cSNeil Armstrong }; 1395174564cSNeil Armstrong 140013af227SNeil Armstrong struct dwc3_meson_g12a; 141013af227SNeil Armstrong 1421e355f21SHanjie Lin struct dwc3_meson_g12a_drvdata { 1431e355f21SHanjie Lin bool otg_switch_supported; 144df7e3745SNeil Armstrong bool otg_phy_host_port_disable; 1451e355f21SHanjie Lin struct clk_bulk_data *clks; 1461e355f21SHanjie Lin int num_clks; 147e5ee93d4SFelipe Balbi const char * const *phy_names; 1485174564cSNeil Armstrong int num_phys; 149013af227SNeil Armstrong int (*setup_regmaps)(struct dwc3_meson_g12a *priv, void __iomem *base); 15031306821SNeil Armstrong int (*usb2_init_phy)(struct dwc3_meson_g12a *priv, int i, 15131306821SNeil Armstrong enum phy_mode mode); 15231306821SNeil Armstrong int (*set_phy_mode)(struct dwc3_meson_g12a *priv, int i, 15331306821SNeil Armstrong enum phy_mode mode); 1545b0ba0caSNeil Armstrong int (*usb_init)(struct dwc3_meson_g12a *priv); 1555b0ba0caSNeil Armstrong int (*usb_post_init)(struct dwc3_meson_g12a *priv); 1561e355f21SHanjie Lin }; 1571e355f21SHanjie Lin 158a9fc15e0SNeil Armstrong static int dwc3_meson_gxl_setup_regmaps(struct dwc3_meson_g12a *priv, 159a9fc15e0SNeil Armstrong void __iomem *base); 160013af227SNeil Armstrong static int dwc3_meson_g12a_setup_regmaps(struct dwc3_meson_g12a *priv, 161013af227SNeil Armstrong void __iomem *base); 162013af227SNeil Armstrong 16331306821SNeil Armstrong static int dwc3_meson_g12a_usb2_init_phy(struct dwc3_meson_g12a *priv, int i, 16431306821SNeil Armstrong enum phy_mode mode); 165a9fc15e0SNeil Armstrong static int dwc3_meson_gxl_usb2_init_phy(struct dwc3_meson_g12a *priv, int i, 166a9fc15e0SNeil Armstrong enum phy_mode mode); 16731306821SNeil Armstrong 16831306821SNeil Armstrong static int dwc3_meson_g12a_set_phy_mode(struct dwc3_meson_g12a *priv, 16931306821SNeil Armstrong int i, enum phy_mode mode); 170a9fc15e0SNeil Armstrong static int dwc3_meson_gxl_set_phy_mode(struct dwc3_meson_g12a *priv, 171a9fc15e0SNeil Armstrong int i, enum phy_mode mode); 17231306821SNeil Armstrong 1735b0ba0caSNeil Armstrong static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv); 174a9fc15e0SNeil Armstrong static int dwc3_meson_gxl_usb_init(struct dwc3_meson_g12a *priv); 175a9fc15e0SNeil Armstrong 176a9fc15e0SNeil Armstrong static int dwc3_meson_gxl_usb_post_init(struct dwc3_meson_g12a *priv); 1775b0ba0caSNeil Armstrong 178df7e3745SNeil Armstrong /* 179df7e3745SNeil Armstrong * For GXL and GXM SoCs: 180df7e3745SNeil Armstrong * USB Phy muxing between the DWC2 Device controller and the DWC3 Host 181df7e3745SNeil Armstrong * controller is buggy when switching from Device to Host when USB port 182df7e3745SNeil Armstrong * is unpopulated, it causes the DWC3 to hard crash. 183df7e3745SNeil Armstrong * When populated (including OTG switching with ID pin), the switch works 184df7e3745SNeil Armstrong * like a charm like on the G12A platforms. 185df7e3745SNeil Armstrong * In order to still switch from Host to Device on an USB Type-A port, 186df7e3745SNeil Armstrong * an U2_PORT_DISABLE bit has been added to disconnect the DWC3 Host 187df7e3745SNeil Armstrong * controller from the port, but when used the DWC3 controller must be 188df7e3745SNeil Armstrong * reset to recover usage of the port. 189df7e3745SNeil Armstrong */ 190df7e3745SNeil Armstrong 191*850ebb27SHeiner Kallweit static const struct dwc3_meson_g12a_drvdata gxl_drvdata = { 192a9fc15e0SNeil Armstrong .otg_switch_supported = true, 193a9fc15e0SNeil Armstrong .otg_phy_host_port_disable = true, 194a9fc15e0SNeil Armstrong .clks = meson_gxl_clocks, 195a9fc15e0SNeil Armstrong .num_clks = ARRAY_SIZE(meson_g12a_clocks), 196a9fc15e0SNeil Armstrong .phy_names = meson_a1_phy_names, 197a9fc15e0SNeil Armstrong .num_phys = ARRAY_SIZE(meson_a1_phy_names), 198a9fc15e0SNeil Armstrong .setup_regmaps = dwc3_meson_gxl_setup_regmaps, 199a9fc15e0SNeil Armstrong .usb2_init_phy = dwc3_meson_gxl_usb2_init_phy, 200a9fc15e0SNeil Armstrong .set_phy_mode = dwc3_meson_gxl_set_phy_mode, 201a9fc15e0SNeil Armstrong .usb_init = dwc3_meson_gxl_usb_init, 202a9fc15e0SNeil Armstrong .usb_post_init = dwc3_meson_gxl_usb_post_init, 203a9fc15e0SNeil Armstrong }; 204a9fc15e0SNeil Armstrong 205*850ebb27SHeiner Kallweit static const struct dwc3_meson_g12a_drvdata gxm_drvdata = { 206a9fc15e0SNeil Armstrong .otg_switch_supported = true, 207a9fc15e0SNeil Armstrong .otg_phy_host_port_disable = true, 208a9fc15e0SNeil Armstrong .clks = meson_gxl_clocks, 209a9fc15e0SNeil Armstrong .num_clks = ARRAY_SIZE(meson_g12a_clocks), 210a9fc15e0SNeil Armstrong .phy_names = meson_gxm_phy_names, 211a9fc15e0SNeil Armstrong .num_phys = ARRAY_SIZE(meson_gxm_phy_names), 212a9fc15e0SNeil Armstrong .setup_regmaps = dwc3_meson_gxl_setup_regmaps, 213a9fc15e0SNeil Armstrong .usb2_init_phy = dwc3_meson_gxl_usb2_init_phy, 214a9fc15e0SNeil Armstrong .set_phy_mode = dwc3_meson_gxl_set_phy_mode, 215a9fc15e0SNeil Armstrong .usb_init = dwc3_meson_gxl_usb_init, 216a9fc15e0SNeil Armstrong .usb_post_init = dwc3_meson_gxl_usb_post_init, 217a9fc15e0SNeil Armstrong }; 218a9fc15e0SNeil Armstrong 219*850ebb27SHeiner Kallweit static const struct dwc3_meson_g12a_drvdata axg_drvdata = { 22065f3d449SNeil Armstrong .otg_switch_supported = true, 22165f3d449SNeil Armstrong .clks = meson_gxl_clocks, 22265f3d449SNeil Armstrong .num_clks = ARRAY_SIZE(meson_gxl_clocks), 22365f3d449SNeil Armstrong .phy_names = meson_a1_phy_names, 22465f3d449SNeil Armstrong .num_phys = ARRAY_SIZE(meson_a1_phy_names), 22565f3d449SNeil Armstrong .setup_regmaps = dwc3_meson_gxl_setup_regmaps, 22665f3d449SNeil Armstrong .usb2_init_phy = dwc3_meson_gxl_usb2_init_phy, 22765f3d449SNeil Armstrong .set_phy_mode = dwc3_meson_gxl_set_phy_mode, 22865f3d449SNeil Armstrong .usb_init = dwc3_meson_g12a_usb_init, 22965f3d449SNeil Armstrong .usb_post_init = dwc3_meson_gxl_usb_post_init, 23065f3d449SNeil Armstrong }; 23165f3d449SNeil Armstrong 232*850ebb27SHeiner Kallweit static const struct dwc3_meson_g12a_drvdata g12a_drvdata = { 2331e355f21SHanjie Lin .otg_switch_supported = true, 2341e355f21SHanjie Lin .clks = meson_g12a_clocks, 2351e355f21SHanjie Lin .num_clks = ARRAY_SIZE(meson_g12a_clocks), 2365174564cSNeil Armstrong .phy_names = meson_g12a_phy_names, 2375174564cSNeil Armstrong .num_phys = ARRAY_SIZE(meson_g12a_phy_names), 238013af227SNeil Armstrong .setup_regmaps = dwc3_meson_g12a_setup_regmaps, 23931306821SNeil Armstrong .usb2_init_phy = dwc3_meson_g12a_usb2_init_phy, 24031306821SNeil Armstrong .set_phy_mode = dwc3_meson_g12a_set_phy_mode, 2415b0ba0caSNeil Armstrong .usb_init = dwc3_meson_g12a_usb_init, 2421e355f21SHanjie Lin }; 2431e355f21SHanjie Lin 244*850ebb27SHeiner Kallweit static const struct dwc3_meson_g12a_drvdata a1_drvdata = { 2451e355f21SHanjie Lin .otg_switch_supported = false, 2461e355f21SHanjie Lin .clks = meson_a1_clocks, 2471e355f21SHanjie Lin .num_clks = ARRAY_SIZE(meson_a1_clocks), 2485174564cSNeil Armstrong .phy_names = meson_a1_phy_names, 2495174564cSNeil Armstrong .num_phys = ARRAY_SIZE(meson_a1_phy_names), 250013af227SNeil Armstrong .setup_regmaps = dwc3_meson_g12a_setup_regmaps, 25131306821SNeil Armstrong .usb2_init_phy = dwc3_meson_g12a_usb2_init_phy, 25231306821SNeil Armstrong .set_phy_mode = dwc3_meson_g12a_set_phy_mode, 2535b0ba0caSNeil Armstrong .usb_init = dwc3_meson_g12a_usb_init, 2541e355f21SHanjie Lin }; 2551e355f21SHanjie Lin 256c9999337SNeil Armstrong struct dwc3_meson_g12a { 257c9999337SNeil Armstrong struct device *dev; 258013af227SNeil Armstrong struct regmap *u2p_regmap[PHY_COUNT]; 259013af227SNeil Armstrong struct regmap *usb_glue_regmap; 260c9999337SNeil Armstrong struct reset_control *reset; 261c9999337SNeil Armstrong struct phy *phys[PHY_COUNT]; 262c9999337SNeil Armstrong enum usb_dr_mode otg_mode; 263c9999337SNeil Armstrong enum phy_mode otg_phy_mode; 264c9999337SNeil Armstrong unsigned int usb2_ports; 265c9999337SNeil Armstrong unsigned int usb3_ports; 266c9999337SNeil Armstrong struct regulator *vbus; 267c9999337SNeil Armstrong struct usb_role_switch_desc switch_desc; 268c9999337SNeil Armstrong struct usb_role_switch *role_switch; 2691e355f21SHanjie Lin const struct dwc3_meson_g12a_drvdata *drvdata; 270c9999337SNeil Armstrong }; 271c9999337SNeil Armstrong 272a9fc15e0SNeil Armstrong static int dwc3_meson_gxl_set_phy_mode(struct dwc3_meson_g12a *priv, 273a9fc15e0SNeil Armstrong int i, enum phy_mode mode) 274a9fc15e0SNeil Armstrong { 275a9fc15e0SNeil Armstrong return phy_set_mode(priv->phys[i], mode); 276a9fc15e0SNeil Armstrong } 277a9fc15e0SNeil Armstrong 278a9fc15e0SNeil Armstrong static int dwc3_meson_gxl_usb2_init_phy(struct dwc3_meson_g12a *priv, int i, 279a9fc15e0SNeil Armstrong enum phy_mode mode) 280a9fc15e0SNeil Armstrong { 281a9fc15e0SNeil Armstrong /* On GXL PHY must be started in device mode for DWC2 init */ 282a9fc15e0SNeil Armstrong return priv->drvdata->set_phy_mode(priv, i, 283a9fc15e0SNeil Armstrong (i == USB2_OTG_PHY) ? PHY_MODE_USB_DEVICE 284a9fc15e0SNeil Armstrong : PHY_MODE_USB_HOST); 285a9fc15e0SNeil Armstrong } 286a9fc15e0SNeil Armstrong 28731306821SNeil Armstrong static int dwc3_meson_g12a_set_phy_mode(struct dwc3_meson_g12a *priv, 288c9999337SNeil Armstrong int i, enum phy_mode mode) 289c9999337SNeil Armstrong { 290c9999337SNeil Armstrong if (mode == PHY_MODE_USB_HOST) 291013af227SNeil Armstrong regmap_update_bits(priv->u2p_regmap[i], U2P_R0, 292c9999337SNeil Armstrong U2P_R0_HOST_DEVICE, 293c9999337SNeil Armstrong U2P_R0_HOST_DEVICE); 294c9999337SNeil Armstrong else 295013af227SNeil Armstrong regmap_update_bits(priv->u2p_regmap[i], U2P_R0, 296c9999337SNeil Armstrong U2P_R0_HOST_DEVICE, 0); 29731306821SNeil Armstrong 29831306821SNeil Armstrong return 0; 29931306821SNeil Armstrong } 30031306821SNeil Armstrong 30131306821SNeil Armstrong static int dwc3_meson_g12a_usb2_init_phy(struct dwc3_meson_g12a *priv, int i, 30231306821SNeil Armstrong enum phy_mode mode) 30331306821SNeil Armstrong { 30431306821SNeil Armstrong int ret; 30531306821SNeil Armstrong 30631306821SNeil Armstrong regmap_update_bits(priv->u2p_regmap[i], U2P_R0, 30731306821SNeil Armstrong U2P_R0_POWER_ON_RESET, 30831306821SNeil Armstrong U2P_R0_POWER_ON_RESET); 30931306821SNeil Armstrong 31031306821SNeil Armstrong if (priv->drvdata->otg_switch_supported && i == USB2_OTG_PHY) { 31131306821SNeil Armstrong regmap_update_bits(priv->u2p_regmap[i], U2P_R0, 31231306821SNeil Armstrong U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS, 31331306821SNeil Armstrong U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS); 31431306821SNeil Armstrong 31531306821SNeil Armstrong ret = priv->drvdata->set_phy_mode(priv, i, mode); 31631306821SNeil Armstrong } else 31731306821SNeil Armstrong ret = priv->drvdata->set_phy_mode(priv, i, 31831306821SNeil Armstrong PHY_MODE_USB_HOST); 31931306821SNeil Armstrong 32031306821SNeil Armstrong if (ret) 32131306821SNeil Armstrong return ret; 32231306821SNeil Armstrong 32331306821SNeil Armstrong regmap_update_bits(priv->u2p_regmap[i], U2P_R0, 32431306821SNeil Armstrong U2P_R0_POWER_ON_RESET, 0); 32531306821SNeil Armstrong 32631306821SNeil Armstrong return 0; 327c9999337SNeil Armstrong } 328c9999337SNeil Armstrong 3295b0ba0caSNeil Armstrong static int dwc3_meson_g12a_usb2_init(struct dwc3_meson_g12a *priv, 3305b0ba0caSNeil Armstrong enum phy_mode mode) 331c9999337SNeil Armstrong { 33231306821SNeil Armstrong int i, ret; 333c9999337SNeil Armstrong 3345174564cSNeil Armstrong for (i = 0; i < priv->drvdata->num_phys; ++i) { 335c9999337SNeil Armstrong if (!priv->phys[i]) 336c9999337SNeil Armstrong continue; 337c9999337SNeil Armstrong 3385174564cSNeil Armstrong if (!strstr(priv->drvdata->phy_names[i], "usb2")) 3395174564cSNeil Armstrong continue; 3405174564cSNeil Armstrong 3415b0ba0caSNeil Armstrong ret = priv->drvdata->usb2_init_phy(priv, i, mode); 34231306821SNeil Armstrong if (ret) 34331306821SNeil Armstrong return ret; 344c9999337SNeil Armstrong } 345c9999337SNeil Armstrong 346c9999337SNeil Armstrong return 0; 347c9999337SNeil Armstrong } 348c9999337SNeil Armstrong 349c9999337SNeil Armstrong static void dwc3_meson_g12a_usb3_init(struct dwc3_meson_g12a *priv) 350c9999337SNeil Armstrong { 351013af227SNeil Armstrong regmap_update_bits(priv->usb_glue_regmap, USB_R3, 352c9999337SNeil Armstrong USB_R3_P30_SSC_RANGE_MASK | 353c9999337SNeil Armstrong USB_R3_P30_REF_SSP_EN, 354c9999337SNeil Armstrong USB_R3_P30_SSC_ENABLE | 355c9999337SNeil Armstrong FIELD_PREP(USB_R3_P30_SSC_RANGE_MASK, 2) | 356c9999337SNeil Armstrong USB_R3_P30_REF_SSP_EN); 357c9999337SNeil Armstrong udelay(2); 358c9999337SNeil Armstrong 359013af227SNeil Armstrong regmap_update_bits(priv->usb_glue_regmap, USB_R2, 360c9999337SNeil Armstrong USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK, 361c9999337SNeil Armstrong FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK, 0x15)); 362c9999337SNeil Armstrong 363013af227SNeil Armstrong regmap_update_bits(priv->usb_glue_regmap, USB_R2, 364c9999337SNeil Armstrong USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK, 365c9999337SNeil Armstrong FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK, 0x20)); 366c9999337SNeil Armstrong 367c9999337SNeil Armstrong udelay(2); 368c9999337SNeil Armstrong 369013af227SNeil Armstrong regmap_update_bits(priv->usb_glue_regmap, USB_R1, 370c9999337SNeil Armstrong USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT, 371c9999337SNeil Armstrong USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT); 372c9999337SNeil Armstrong 373013af227SNeil Armstrong regmap_update_bits(priv->usb_glue_regmap, USB_R1, 374c9999337SNeil Armstrong USB_R1_P30_PCS_TX_SWING_FULL_MASK, 375c9999337SNeil Armstrong FIELD_PREP(USB_R1_P30_PCS_TX_SWING_FULL_MASK, 127)); 376c9999337SNeil Armstrong } 377c9999337SNeil Armstrong 3785b0ba0caSNeil Armstrong static void dwc3_meson_g12a_usb_otg_apply_mode(struct dwc3_meson_g12a *priv, 3795b0ba0caSNeil Armstrong enum phy_mode mode) 380c9999337SNeil Armstrong { 3815b0ba0caSNeil Armstrong if (mode == PHY_MODE_USB_DEVICE) { 382df7e3745SNeil Armstrong if (priv->otg_mode != USB_DR_MODE_OTG && 383df7e3745SNeil Armstrong priv->drvdata->otg_phy_host_port_disable) 384df7e3745SNeil Armstrong /* Isolate the OTG PHY port from the Host Controller */ 385df7e3745SNeil Armstrong regmap_update_bits(priv->usb_glue_regmap, USB_R1, 386df7e3745SNeil Armstrong USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK, 387df7e3745SNeil Armstrong FIELD_PREP(USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK, 388df7e3745SNeil Armstrong BIT(USB2_OTG_PHY))); 389df7e3745SNeil Armstrong 390013af227SNeil Armstrong regmap_update_bits(priv->usb_glue_regmap, USB_R0, 391c9999337SNeil Armstrong USB_R0_U2D_ACT, USB_R0_U2D_ACT); 392013af227SNeil Armstrong regmap_update_bits(priv->usb_glue_regmap, USB_R0, 393c9999337SNeil Armstrong USB_R0_U2D_SS_SCALEDOWN_MODE_MASK, 0); 394013af227SNeil Armstrong regmap_update_bits(priv->usb_glue_regmap, USB_R4, 395c9999337SNeil Armstrong USB_R4_P21_SLEEP_M0, USB_R4_P21_SLEEP_M0); 396c9999337SNeil Armstrong } else { 397df7e3745SNeil Armstrong if (priv->otg_mode != USB_DR_MODE_OTG && 398df7e3745SNeil Armstrong priv->drvdata->otg_phy_host_port_disable) { 399df7e3745SNeil Armstrong regmap_update_bits(priv->usb_glue_regmap, USB_R1, 400df7e3745SNeil Armstrong USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK, 0); 401df7e3745SNeil Armstrong msleep(500); 402df7e3745SNeil Armstrong } 403013af227SNeil Armstrong regmap_update_bits(priv->usb_glue_regmap, USB_R0, 404c9999337SNeil Armstrong USB_R0_U2D_ACT, 0); 405013af227SNeil Armstrong regmap_update_bits(priv->usb_glue_regmap, USB_R4, 406c9999337SNeil Armstrong USB_R4_P21_SLEEP_M0, 0); 407c9999337SNeil Armstrong } 408c9999337SNeil Armstrong } 409c9999337SNeil Armstrong 4105b0ba0caSNeil Armstrong static int dwc3_meson_g12a_usb_init_glue(struct dwc3_meson_g12a *priv, 4115b0ba0caSNeil Armstrong enum phy_mode mode) 412c9999337SNeil Armstrong { 413c9999337SNeil Armstrong int ret; 414c9999337SNeil Armstrong 4155b0ba0caSNeil Armstrong ret = dwc3_meson_g12a_usb2_init(priv, mode); 416c9999337SNeil Armstrong if (ret) 417c9999337SNeil Armstrong return ret; 418c9999337SNeil Armstrong 419013af227SNeil Armstrong regmap_update_bits(priv->usb_glue_regmap, USB_R1, 420c9999337SNeil Armstrong USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 421c9999337SNeil Armstrong FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20)); 422c9999337SNeil Armstrong 423013af227SNeil Armstrong regmap_update_bits(priv->usb_glue_regmap, USB_R5, 424c9999337SNeil Armstrong USB_R5_ID_DIG_EN_0, 425c9999337SNeil Armstrong USB_R5_ID_DIG_EN_0); 426013af227SNeil Armstrong regmap_update_bits(priv->usb_glue_regmap, USB_R5, 427c9999337SNeil Armstrong USB_R5_ID_DIG_EN_1, 428c9999337SNeil Armstrong USB_R5_ID_DIG_EN_1); 429013af227SNeil Armstrong regmap_update_bits(priv->usb_glue_regmap, USB_R5, 430c9999337SNeil Armstrong USB_R5_ID_DIG_TH_MASK, 431c9999337SNeil Armstrong FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff)); 432c9999337SNeil Armstrong 433c9999337SNeil Armstrong /* If we have an actual SuperSpeed port, initialize it */ 434c9999337SNeil Armstrong if (priv->usb3_ports) 435c9999337SNeil Armstrong dwc3_meson_g12a_usb3_init(priv); 436c9999337SNeil Armstrong 4375b0ba0caSNeil Armstrong dwc3_meson_g12a_usb_otg_apply_mode(priv, mode); 438c9999337SNeil Armstrong 439c9999337SNeil Armstrong return 0; 440c9999337SNeil Armstrong } 441c9999337SNeil Armstrong 442013af227SNeil Armstrong static const struct regmap_config phy_meson_g12a_usb_glue_regmap_conf = { 443013af227SNeil Armstrong .name = "usb-glue", 444c9999337SNeil Armstrong .reg_bits = 8, 445c9999337SNeil Armstrong .val_bits = 32, 446c9999337SNeil Armstrong .reg_stride = 4, 447c9999337SNeil Armstrong .max_register = USB_R5, 448c9999337SNeil Armstrong }; 449c9999337SNeil Armstrong 450c9999337SNeil Armstrong static int dwc3_meson_g12a_get_phys(struct dwc3_meson_g12a *priv) 451c9999337SNeil Armstrong { 4525174564cSNeil Armstrong const char *phy_name; 453c9999337SNeil Armstrong int i; 454c9999337SNeil Armstrong 4555174564cSNeil Armstrong for (i = 0 ; i < priv->drvdata->num_phys ; ++i) { 4565174564cSNeil Armstrong phy_name = priv->drvdata->phy_names[i]; 4575174564cSNeil Armstrong priv->phys[i] = devm_phy_optional_get(priv->dev, phy_name); 458c9999337SNeil Armstrong if (!priv->phys[i]) 459c9999337SNeil Armstrong continue; 460c9999337SNeil Armstrong 461c9999337SNeil Armstrong if (IS_ERR(priv->phys[i])) 462c9999337SNeil Armstrong return PTR_ERR(priv->phys[i]); 463c9999337SNeil Armstrong 4645174564cSNeil Armstrong if (strstr(phy_name, "usb3")) 465c9999337SNeil Armstrong priv->usb3_ports++; 466c9999337SNeil Armstrong else 467c9999337SNeil Armstrong priv->usb2_ports++; 468c9999337SNeil Armstrong } 469c9999337SNeil Armstrong 470c9999337SNeil Armstrong dev_info(priv->dev, "USB2 ports: %d\n", priv->usb2_ports); 471c9999337SNeil Armstrong dev_info(priv->dev, "USB3 ports: %d\n", priv->usb3_ports); 472c9999337SNeil Armstrong 473c9999337SNeil Armstrong return 0; 474c9999337SNeil Armstrong } 475c9999337SNeil Armstrong 476c9999337SNeil Armstrong static enum phy_mode dwc3_meson_g12a_get_id(struct dwc3_meson_g12a *priv) 477c9999337SNeil Armstrong { 478c9999337SNeil Armstrong u32 reg; 479c9999337SNeil Armstrong 480013af227SNeil Armstrong regmap_read(priv->usb_glue_regmap, USB_R5, ®); 481c9999337SNeil Armstrong 482c9999337SNeil Armstrong if (reg & (USB_R5_ID_DIG_SYNC | USB_R5_ID_DIG_REG)) 483c9999337SNeil Armstrong return PHY_MODE_USB_DEVICE; 484c9999337SNeil Armstrong 485c9999337SNeil Armstrong return PHY_MODE_USB_HOST; 486c9999337SNeil Armstrong } 487c9999337SNeil Armstrong 488c9999337SNeil Armstrong static int dwc3_meson_g12a_otg_mode_set(struct dwc3_meson_g12a *priv, 489c9999337SNeil Armstrong enum phy_mode mode) 490c9999337SNeil Armstrong { 491c9999337SNeil Armstrong int ret; 492c9999337SNeil Armstrong 4931e355f21SHanjie Lin if (!priv->drvdata->otg_switch_supported || !priv->phys[USB2_OTG_PHY]) 494c9999337SNeil Armstrong return -EINVAL; 495c9999337SNeil Armstrong 496c9999337SNeil Armstrong if (mode == PHY_MODE_USB_HOST) 497c9999337SNeil Armstrong dev_info(priv->dev, "switching to Host Mode\n"); 498c9999337SNeil Armstrong else 499c9999337SNeil Armstrong dev_info(priv->dev, "switching to Device Mode\n"); 500c9999337SNeil Armstrong 501c9999337SNeil Armstrong if (priv->vbus) { 502c9999337SNeil Armstrong if (mode == PHY_MODE_USB_DEVICE) 503c9999337SNeil Armstrong ret = regulator_disable(priv->vbus); 504c9999337SNeil Armstrong else 505c9999337SNeil Armstrong ret = regulator_enable(priv->vbus); 506c9999337SNeil Armstrong if (ret) 507c9999337SNeil Armstrong return ret; 508c9999337SNeil Armstrong } 509c9999337SNeil Armstrong 510c9999337SNeil Armstrong priv->otg_phy_mode = mode; 511c9999337SNeil Armstrong 51231306821SNeil Armstrong ret = priv->drvdata->set_phy_mode(priv, USB2_OTG_PHY, mode); 51331306821SNeil Armstrong if (ret) 51431306821SNeil Armstrong return ret; 515c9999337SNeil Armstrong 5165b0ba0caSNeil Armstrong dwc3_meson_g12a_usb_otg_apply_mode(priv, mode); 517c9999337SNeil Armstrong 518c9999337SNeil Armstrong return 0; 519c9999337SNeil Armstrong } 520c9999337SNeil Armstrong 521bce3052fSHeikki Krogerus static int dwc3_meson_g12a_role_set(struct usb_role_switch *sw, 522bce3052fSHeikki Krogerus enum usb_role role) 523c9999337SNeil Armstrong { 524bce3052fSHeikki Krogerus struct dwc3_meson_g12a *priv = usb_role_switch_get_drvdata(sw); 525c9999337SNeil Armstrong enum phy_mode mode; 526c9999337SNeil Armstrong 527c9999337SNeil Armstrong if (role == USB_ROLE_NONE) 528c9999337SNeil Armstrong return 0; 529c9999337SNeil Armstrong 530c9999337SNeil Armstrong mode = (role == USB_ROLE_HOST) ? PHY_MODE_USB_HOST 531c9999337SNeil Armstrong : PHY_MODE_USB_DEVICE; 532c9999337SNeil Armstrong 533c9999337SNeil Armstrong if (mode == priv->otg_phy_mode) 534c9999337SNeil Armstrong return 0; 535c9999337SNeil Armstrong 536df7e3745SNeil Armstrong if (priv->drvdata->otg_phy_host_port_disable) 537e5ee93d4SFelipe Balbi dev_warn_once(priv->dev, "Broken manual OTG switch\n"); 538df7e3745SNeil Armstrong 539c9999337SNeil Armstrong return dwc3_meson_g12a_otg_mode_set(priv, mode); 540c9999337SNeil Armstrong } 541c9999337SNeil Armstrong 542bce3052fSHeikki Krogerus static enum usb_role dwc3_meson_g12a_role_get(struct usb_role_switch *sw) 543c9999337SNeil Armstrong { 544bce3052fSHeikki Krogerus struct dwc3_meson_g12a *priv = usb_role_switch_get_drvdata(sw); 545c9999337SNeil Armstrong 546c9999337SNeil Armstrong return priv->otg_phy_mode == PHY_MODE_USB_HOST ? 547c9999337SNeil Armstrong USB_ROLE_HOST : USB_ROLE_DEVICE; 548c9999337SNeil Armstrong } 549c9999337SNeil Armstrong 550f90db107SNeil Armstrong static irqreturn_t dwc3_meson_g12a_irq_thread(int irq, void *data) 551f90db107SNeil Armstrong { 552f90db107SNeil Armstrong struct dwc3_meson_g12a *priv = data; 553f90db107SNeil Armstrong enum phy_mode otg_id; 554f90db107SNeil Armstrong 555f90db107SNeil Armstrong otg_id = dwc3_meson_g12a_get_id(priv); 556f90db107SNeil Armstrong if (otg_id != priv->otg_phy_mode) { 557f90db107SNeil Armstrong if (dwc3_meson_g12a_otg_mode_set(priv, otg_id)) 558f90db107SNeil Armstrong dev_warn(priv->dev, "Failed to switch OTG mode\n"); 559f90db107SNeil Armstrong } 560f90db107SNeil Armstrong 561013af227SNeil Armstrong regmap_update_bits(priv->usb_glue_regmap, USB_R5, 562013af227SNeil Armstrong USB_R5_ID_DIG_IRQ, 0); 563f90db107SNeil Armstrong 564f90db107SNeil Armstrong return IRQ_HANDLED; 565f90db107SNeil Armstrong } 566f90db107SNeil Armstrong 567c9999337SNeil Armstrong static struct device *dwc3_meson_g12_find_child(struct device *dev, 568c9999337SNeil Armstrong const char *compatible) 569c9999337SNeil Armstrong { 570c9999337SNeil Armstrong struct platform_device *pdev; 571c9999337SNeil Armstrong struct device_node *np; 572c9999337SNeil Armstrong 573c9999337SNeil Armstrong np = of_get_compatible_child(dev->of_node, compatible); 574c9999337SNeil Armstrong if (!np) 575c9999337SNeil Armstrong return NULL; 576c9999337SNeil Armstrong 577c9999337SNeil Armstrong pdev = of_find_device_by_node(np); 578c9999337SNeil Armstrong of_node_put(np); 579c9999337SNeil Armstrong if (!pdev) 580c9999337SNeil Armstrong return NULL; 581c9999337SNeil Armstrong 582c9999337SNeil Armstrong return &pdev->dev; 583c9999337SNeil Armstrong } 584c9999337SNeil Armstrong 5851e355f21SHanjie Lin static int dwc3_meson_g12a_otg_init(struct platform_device *pdev, 5861e355f21SHanjie Lin struct dwc3_meson_g12a *priv) 587c9999337SNeil Armstrong { 588c9999337SNeil Armstrong enum phy_mode otg_id; 5891e355f21SHanjie Lin int ret, irq; 5901e355f21SHanjie Lin struct device *dev = &pdev->dev; 591c9999337SNeil Armstrong 5921e355f21SHanjie Lin if (!priv->drvdata->otg_switch_supported) 5931e355f21SHanjie Lin return 0; 594c9999337SNeil Armstrong 595f90db107SNeil Armstrong if (priv->otg_mode == USB_DR_MODE_OTG) { 596f90db107SNeil Armstrong /* Ack irq before registering */ 597013af227SNeil Armstrong regmap_update_bits(priv->usb_glue_regmap, USB_R5, 598f90db107SNeil Armstrong USB_R5_ID_DIG_IRQ, 0); 599f90db107SNeil Armstrong 600f90db107SNeil Armstrong irq = platform_get_irq(pdev, 0); 601baa2986bSSergey Shtylyov if (irq < 0) 602baa2986bSSergey Shtylyov return irq; 603f90db107SNeil Armstrong ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, 604f90db107SNeil Armstrong dwc3_meson_g12a_irq_thread, 605f90db107SNeil Armstrong IRQF_ONESHOT, pdev->name, priv); 606f90db107SNeil Armstrong if (ret) 607f90db107SNeil Armstrong return ret; 608f90db107SNeil Armstrong } 609f90db107SNeil Armstrong 610c9999337SNeil Armstrong /* Setup OTG mode corresponding to the ID pin */ 611c9999337SNeil Armstrong if (priv->otg_mode == USB_DR_MODE_OTG) { 612c9999337SNeil Armstrong otg_id = dwc3_meson_g12a_get_id(priv); 613c9999337SNeil Armstrong if (otg_id != priv->otg_phy_mode) { 614c9999337SNeil Armstrong if (dwc3_meson_g12a_otg_mode_set(priv, otg_id)) 615c9999337SNeil Armstrong dev_warn(dev, "Failed to switch OTG mode\n"); 616c9999337SNeil Armstrong } 617c9999337SNeil Armstrong } 618c9999337SNeil Armstrong 619c9999337SNeil Armstrong /* Setup role switcher */ 620c9999337SNeil Armstrong priv->switch_desc.usb2_port = dwc3_meson_g12_find_child(dev, 621c9999337SNeil Armstrong "snps,dwc3"); 622c9999337SNeil Armstrong priv->switch_desc.udc = dwc3_meson_g12_find_child(dev, "snps,dwc2"); 623c9999337SNeil Armstrong priv->switch_desc.allow_userspace_control = true; 624c9999337SNeil Armstrong priv->switch_desc.set = dwc3_meson_g12a_role_set; 625c9999337SNeil Armstrong priv->switch_desc.get = dwc3_meson_g12a_role_get; 626bce3052fSHeikki Krogerus priv->switch_desc.driver_data = priv; 627c9999337SNeil Armstrong 628c9999337SNeil Armstrong priv->role_switch = usb_role_switch_register(dev, &priv->switch_desc); 629c9999337SNeil Armstrong if (IS_ERR(priv->role_switch)) 630c9999337SNeil Armstrong dev_warn(dev, "Unable to register Role Switch\n"); 631c9999337SNeil Armstrong 632238d7602SNathan Chancellor return 0; 6331e355f21SHanjie Lin } 6341e355f21SHanjie Lin 635a9fc15e0SNeil Armstrong static int dwc3_meson_gxl_setup_regmaps(struct dwc3_meson_g12a *priv, 636a9fc15e0SNeil Armstrong void __iomem *base) 637a9fc15e0SNeil Armstrong { 638a9fc15e0SNeil Armstrong /* GXL controls the PHY mode in the PHY registers unlike G12A */ 639a9fc15e0SNeil Armstrong priv->usb_glue_regmap = devm_regmap_init_mmio(priv->dev, base, 640a9fc15e0SNeil Armstrong &phy_meson_g12a_usb_glue_regmap_conf); 641a793cf81SFelipe Balbi return PTR_ERR_OR_ZERO(priv->usb_glue_regmap); 642a9fc15e0SNeil Armstrong } 643a9fc15e0SNeil Armstrong 644013af227SNeil Armstrong static int dwc3_meson_g12a_setup_regmaps(struct dwc3_meson_g12a *priv, 645013af227SNeil Armstrong void __iomem *base) 646013af227SNeil Armstrong { 647013af227SNeil Armstrong int i; 648013af227SNeil Armstrong 649013af227SNeil Armstrong priv->usb_glue_regmap = devm_regmap_init_mmio(priv->dev, 650013af227SNeil Armstrong base + G12A_GLUE_OFFSET, 651013af227SNeil Armstrong &phy_meson_g12a_usb_glue_regmap_conf); 652013af227SNeil Armstrong if (IS_ERR(priv->usb_glue_regmap)) 653013af227SNeil Armstrong return PTR_ERR(priv->usb_glue_regmap); 654013af227SNeil Armstrong 655013af227SNeil Armstrong /* Create a regmap for each USB2 PHY control register set */ 6564d2aa178SNeil Armstrong for (i = 0; i < priv->drvdata->num_phys; i++) { 657013af227SNeil Armstrong struct regmap_config u2p_regmap_config = { 658013af227SNeil Armstrong .reg_bits = 8, 659013af227SNeil Armstrong .val_bits = 32, 660013af227SNeil Armstrong .reg_stride = 4, 661013af227SNeil Armstrong .max_register = U2P_R1, 662013af227SNeil Armstrong }; 663013af227SNeil Armstrong 6644d2aa178SNeil Armstrong if (!strstr(priv->drvdata->phy_names[i], "usb2")) 6654d2aa178SNeil Armstrong continue; 6664d2aa178SNeil Armstrong 667013af227SNeil Armstrong u2p_regmap_config.name = devm_kasprintf(priv->dev, GFP_KERNEL, 668013af227SNeil Armstrong "u2p-%d", i); 669013af227SNeil Armstrong if (!u2p_regmap_config.name) 670013af227SNeil Armstrong return -ENOMEM; 671013af227SNeil Armstrong 672013af227SNeil Armstrong priv->u2p_regmap[i] = devm_regmap_init_mmio(priv->dev, 673013af227SNeil Armstrong base + (i * U2P_REG_SIZE), 674013af227SNeil Armstrong &u2p_regmap_config); 675013af227SNeil Armstrong if (IS_ERR(priv->u2p_regmap[i])) 676013af227SNeil Armstrong return PTR_ERR(priv->u2p_regmap[i]); 677013af227SNeil Armstrong } 678013af227SNeil Armstrong 679013af227SNeil Armstrong return 0; 680013af227SNeil Armstrong } 681013af227SNeil Armstrong 6825b0ba0caSNeil Armstrong static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv) 6835b0ba0caSNeil Armstrong { 6845b0ba0caSNeil Armstrong return dwc3_meson_g12a_usb_init_glue(priv, priv->otg_phy_mode); 6855b0ba0caSNeil Armstrong } 6865b0ba0caSNeil Armstrong 687a9fc15e0SNeil Armstrong static int dwc3_meson_gxl_usb_init(struct dwc3_meson_g12a *priv) 688a9fc15e0SNeil Armstrong { 689a9fc15e0SNeil Armstrong return dwc3_meson_g12a_usb_init_glue(priv, PHY_MODE_USB_DEVICE); 690a9fc15e0SNeil Armstrong } 691a9fc15e0SNeil Armstrong 692a9fc15e0SNeil Armstrong static int dwc3_meson_gxl_usb_post_init(struct dwc3_meson_g12a *priv) 693a9fc15e0SNeil Armstrong { 694a9fc15e0SNeil Armstrong int ret; 695a9fc15e0SNeil Armstrong 696a9fc15e0SNeil Armstrong ret = priv->drvdata->set_phy_mode(priv, USB2_OTG_PHY, 697a9fc15e0SNeil Armstrong priv->otg_phy_mode); 698a9fc15e0SNeil Armstrong if (ret) 699a9fc15e0SNeil Armstrong return ret; 700a9fc15e0SNeil Armstrong 701a9fc15e0SNeil Armstrong dwc3_meson_g12a_usb_otg_apply_mode(priv, priv->otg_phy_mode); 702a9fc15e0SNeil Armstrong 703a9fc15e0SNeil Armstrong return 0; 704a9fc15e0SNeil Armstrong } 705a9fc15e0SNeil Armstrong 7061e355f21SHanjie Lin static int dwc3_meson_g12a_probe(struct platform_device *pdev) 7071e355f21SHanjie Lin { 7081e355f21SHanjie Lin struct dwc3_meson_g12a *priv; 7091e355f21SHanjie Lin struct device *dev = &pdev->dev; 7101e355f21SHanjie Lin struct device_node *np = dev->of_node; 7111e355f21SHanjie Lin void __iomem *base; 7121e355f21SHanjie Lin int ret, i; 7131e355f21SHanjie Lin 7141e355f21SHanjie Lin priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 7151e355f21SHanjie Lin if (!priv) 7161e355f21SHanjie Lin return -ENOMEM; 7171e355f21SHanjie Lin 7181e355f21SHanjie Lin base = devm_platform_ioremap_resource(pdev, 0); 7191e355f21SHanjie Lin if (IS_ERR(base)) 7201e355f21SHanjie Lin return PTR_ERR(base); 7211e355f21SHanjie Lin 722013af227SNeil Armstrong priv->drvdata = of_device_get_match_data(&pdev->dev); 723013af227SNeil Armstrong priv->dev = dev; 7241e355f21SHanjie Lin 7251e355f21SHanjie Lin priv->vbus = devm_regulator_get_optional(dev, "vbus"); 7261e355f21SHanjie Lin if (IS_ERR(priv->vbus)) { 7271e355f21SHanjie Lin if (PTR_ERR(priv->vbus) == -EPROBE_DEFER) 7281e355f21SHanjie Lin return PTR_ERR(priv->vbus); 7291e355f21SHanjie Lin priv->vbus = NULL; 7301e355f21SHanjie Lin } 7311e355f21SHanjie Lin 7321e355f21SHanjie Lin ret = devm_clk_bulk_get(dev, 7331e355f21SHanjie Lin priv->drvdata->num_clks, 7341e355f21SHanjie Lin priv->drvdata->clks); 7351e355f21SHanjie Lin if (ret) 7361e355f21SHanjie Lin return ret; 7371e355f21SHanjie Lin 7381e355f21SHanjie Lin ret = clk_bulk_prepare_enable(priv->drvdata->num_clks, 7391e355f21SHanjie Lin priv->drvdata->clks); 7401e355f21SHanjie Lin if (ret) 7411e355f21SHanjie Lin return ret; 7421e355f21SHanjie Lin 7431e355f21SHanjie Lin platform_set_drvdata(pdev, priv); 7441e355f21SHanjie Lin 7456d9fa35aSNeil Armstrong priv->reset = devm_reset_control_get_shared(dev, NULL); 7461e355f21SHanjie Lin if (IS_ERR(priv->reset)) { 7471e355f21SHanjie Lin ret = PTR_ERR(priv->reset); 7481e355f21SHanjie Lin dev_err(dev, "failed to get device reset, err=%d\n", ret); 749be8c1001SMartin Blumenstingl goto err_disable_clks; 7501e355f21SHanjie Lin } 7511e355f21SHanjie Lin 752a6498d51SAmjad Ouled-Ameur ret = reset_control_reset(priv->reset); 7531e355f21SHanjie Lin if (ret) 754a6498d51SAmjad Ouled-Ameur goto err_disable_clks; 7551e355f21SHanjie Lin 7561e355f21SHanjie Lin ret = dwc3_meson_g12a_get_phys(priv); 7571e355f21SHanjie Lin if (ret) 7584ce3b457SAmjad Ouled-Ameur goto err_rearm; 7591e355f21SHanjie Lin 760347052e3SMartin Blumenstingl ret = priv->drvdata->setup_regmaps(priv, base); 761347052e3SMartin Blumenstingl if (ret) 7624ce3b457SAmjad Ouled-Ameur goto err_rearm; 763347052e3SMartin Blumenstingl 7641e355f21SHanjie Lin if (priv->vbus) { 7651e355f21SHanjie Lin ret = regulator_enable(priv->vbus); 7661e355f21SHanjie Lin if (ret) 7674ce3b457SAmjad Ouled-Ameur goto err_rearm; 7681e355f21SHanjie Lin } 7691e355f21SHanjie Lin 7701e355f21SHanjie Lin /* Get dr_mode */ 7711e355f21SHanjie Lin priv->otg_mode = usb_get_dr_mode(dev); 7721e355f21SHanjie Lin 7735b0ba0caSNeil Armstrong if (priv->otg_mode == USB_DR_MODE_PERIPHERAL) 7745b0ba0caSNeil Armstrong priv->otg_phy_mode = PHY_MODE_USB_DEVICE; 7755b0ba0caSNeil Armstrong else 7765b0ba0caSNeil Armstrong priv->otg_phy_mode = PHY_MODE_USB_HOST; 7775b0ba0caSNeil Armstrong 7785b0ba0caSNeil Armstrong ret = priv->drvdata->usb_init(priv); 7798f5bc1ecSNeil Armstrong if (ret) 7801d0d3d81SChristophe JAILLET goto err_disable_regulator; 7811e355f21SHanjie Lin 7821e355f21SHanjie Lin /* Init PHYs */ 7831e355f21SHanjie Lin for (i = 0 ; i < PHY_COUNT ; ++i) { 7841e355f21SHanjie Lin ret = phy_init(priv->phys[i]); 7851e355f21SHanjie Lin if (ret) 7861d0d3d81SChristophe JAILLET goto err_disable_regulator; 7871e355f21SHanjie Lin } 7881e355f21SHanjie Lin 7891e355f21SHanjie Lin /* Set PHY Power */ 7901e355f21SHanjie Lin for (i = 0 ; i < PHY_COUNT ; ++i) { 7911e355f21SHanjie Lin ret = phy_power_on(priv->phys[i]); 7921e355f21SHanjie Lin if (ret) 7931e355f21SHanjie Lin goto err_phys_exit; 7941e355f21SHanjie Lin } 7951e355f21SHanjie Lin 7965b0ba0caSNeil Armstrong if (priv->drvdata->usb_post_init) { 7975b0ba0caSNeil Armstrong ret = priv->drvdata->usb_post_init(priv); 7985b0ba0caSNeil Armstrong if (ret) 7995b0ba0caSNeil Armstrong goto err_phys_power; 8005b0ba0caSNeil Armstrong } 8015b0ba0caSNeil Armstrong 8021e355f21SHanjie Lin ret = of_platform_populate(np, NULL, NULL, dev); 8031e355f21SHanjie Lin if (ret) 8041e355f21SHanjie Lin goto err_phys_power; 8051e355f21SHanjie Lin 8061e355f21SHanjie Lin ret = dwc3_meson_g12a_otg_init(pdev, priv); 8071e355f21SHanjie Lin if (ret) 8081e355f21SHanjie Lin goto err_phys_power; 8091e355f21SHanjie Lin 810c9999337SNeil Armstrong pm_runtime_set_active(dev); 811c9999337SNeil Armstrong pm_runtime_enable(dev); 812c9999337SNeil Armstrong pm_runtime_get_sync(dev); 813c9999337SNeil Armstrong 814c9999337SNeil Armstrong return 0; 815c9999337SNeil Armstrong 816c9999337SNeil Armstrong err_phys_power: 817c9999337SNeil Armstrong for (i = 0 ; i < PHY_COUNT ; ++i) 818c9999337SNeil Armstrong phy_power_off(priv->phys[i]); 819c9999337SNeil Armstrong 820c9999337SNeil Armstrong err_phys_exit: 821c9999337SNeil Armstrong for (i = 0 ; i < PHY_COUNT ; ++i) 822c9999337SNeil Armstrong phy_exit(priv->phys[i]); 823c9999337SNeil Armstrong 8241d0d3d81SChristophe JAILLET err_disable_regulator: 8251d0d3d81SChristophe JAILLET if (priv->vbus) 8261d0d3d81SChristophe JAILLET regulator_disable(priv->vbus); 8271d0d3d81SChristophe JAILLET 8284ce3b457SAmjad Ouled-Ameur err_rearm: 8294ce3b457SAmjad Ouled-Ameur reset_control_rearm(priv->reset); 8304ce3b457SAmjad Ouled-Ameur 8311e355f21SHanjie Lin err_disable_clks: 8321e355f21SHanjie Lin clk_bulk_disable_unprepare(priv->drvdata->num_clks, 8331e355f21SHanjie Lin priv->drvdata->clks); 8341e355f21SHanjie Lin 835c9999337SNeil Armstrong return ret; 836c9999337SNeil Armstrong } 837c9999337SNeil Armstrong 838c9999337SNeil Armstrong static int dwc3_meson_g12a_remove(struct platform_device *pdev) 839c9999337SNeil Armstrong { 840c9999337SNeil Armstrong struct dwc3_meson_g12a *priv = platform_get_drvdata(pdev); 841c9999337SNeil Armstrong struct device *dev = &pdev->dev; 842c9999337SNeil Armstrong int i; 843c9999337SNeil Armstrong 8441e355f21SHanjie Lin if (priv->drvdata->otg_switch_supported) 845c9999337SNeil Armstrong usb_role_switch_unregister(priv->role_switch); 846c9999337SNeil Armstrong 847c9999337SNeil Armstrong of_platform_depopulate(dev); 848c9999337SNeil Armstrong 849c9999337SNeil Armstrong for (i = 0 ; i < PHY_COUNT ; ++i) { 850c9999337SNeil Armstrong phy_power_off(priv->phys[i]); 851c9999337SNeil Armstrong phy_exit(priv->phys[i]); 852c9999337SNeil Armstrong } 853c9999337SNeil Armstrong 854c9999337SNeil Armstrong pm_runtime_disable(dev); 855c9999337SNeil Armstrong pm_runtime_put_noidle(dev); 856c9999337SNeil Armstrong pm_runtime_set_suspended(dev); 857c9999337SNeil Armstrong 8584ce3b457SAmjad Ouled-Ameur reset_control_rearm(priv->reset); 8594ce3b457SAmjad Ouled-Ameur 8601e355f21SHanjie Lin clk_bulk_disable_unprepare(priv->drvdata->num_clks, 8611e355f21SHanjie Lin priv->drvdata->clks); 8621e355f21SHanjie Lin 863c9999337SNeil Armstrong return 0; 864c9999337SNeil Armstrong } 865c9999337SNeil Armstrong 866c9999337SNeil Armstrong static int __maybe_unused dwc3_meson_g12a_runtime_suspend(struct device *dev) 867c9999337SNeil Armstrong { 868c9999337SNeil Armstrong struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); 869c9999337SNeil Armstrong 8701e355f21SHanjie Lin clk_bulk_disable_unprepare(priv->drvdata->num_clks, 8711e355f21SHanjie Lin priv->drvdata->clks); 872c9999337SNeil Armstrong 873c9999337SNeil Armstrong return 0; 874c9999337SNeil Armstrong } 875c9999337SNeil Armstrong 876c9999337SNeil Armstrong static int __maybe_unused dwc3_meson_g12a_runtime_resume(struct device *dev) 877c9999337SNeil Armstrong { 878c9999337SNeil Armstrong struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); 879c9999337SNeil Armstrong 8801e355f21SHanjie Lin return clk_bulk_prepare_enable(priv->drvdata->num_clks, 8811e355f21SHanjie Lin priv->drvdata->clks); 882c9999337SNeil Armstrong } 883c9999337SNeil Armstrong 884c9999337SNeil Armstrong static int __maybe_unused dwc3_meson_g12a_suspend(struct device *dev) 885c9999337SNeil Armstrong { 886c9999337SNeil Armstrong struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); 8871cf084d1SNeil Armstrong int i, ret; 8881cf084d1SNeil Armstrong 8891cf084d1SNeil Armstrong if (priv->vbus && priv->otg_phy_mode == PHY_MODE_USB_HOST) { 8901cf084d1SNeil Armstrong ret = regulator_disable(priv->vbus); 8911cf084d1SNeil Armstrong if (ret) 8921cf084d1SNeil Armstrong return ret; 8931cf084d1SNeil Armstrong } 894c9999337SNeil Armstrong 895c9999337SNeil Armstrong for (i = 0 ; i < PHY_COUNT ; ++i) { 896c9999337SNeil Armstrong phy_power_off(priv->phys[i]); 897c9999337SNeil Armstrong phy_exit(priv->phys[i]); 898c9999337SNeil Armstrong } 899c9999337SNeil Armstrong 9004ce3b457SAmjad Ouled-Ameur reset_control_rearm(priv->reset); 901c9999337SNeil Armstrong 902c9999337SNeil Armstrong return 0; 903c9999337SNeil Armstrong } 904c9999337SNeil Armstrong 905c9999337SNeil Armstrong static int __maybe_unused dwc3_meson_g12a_resume(struct device *dev) 906c9999337SNeil Armstrong { 907c9999337SNeil Armstrong struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); 908c9999337SNeil Armstrong int i, ret; 909c9999337SNeil Armstrong 9104ce3b457SAmjad Ouled-Ameur ret = reset_control_reset(priv->reset); 9114ce3b457SAmjad Ouled-Ameur if (ret) 9124ce3b457SAmjad Ouled-Ameur return ret; 913c9999337SNeil Armstrong 9145b0ba0caSNeil Armstrong ret = priv->drvdata->usb_init(priv); 9155b0ba0caSNeil Armstrong if (ret) 9165b0ba0caSNeil Armstrong return ret; 917c9999337SNeil Armstrong 918c9999337SNeil Armstrong /* Init PHYs */ 919c9999337SNeil Armstrong for (i = 0 ; i < PHY_COUNT ; ++i) { 920c9999337SNeil Armstrong ret = phy_init(priv->phys[i]); 921c9999337SNeil Armstrong if (ret) 922c9999337SNeil Armstrong return ret; 923c9999337SNeil Armstrong } 924c9999337SNeil Armstrong 925c9999337SNeil Armstrong /* Set PHY Power */ 926c9999337SNeil Armstrong for (i = 0 ; i < PHY_COUNT ; ++i) { 927c9999337SNeil Armstrong ret = phy_power_on(priv->phys[i]); 928c9999337SNeil Armstrong if (ret) 929c9999337SNeil Armstrong return ret; 930c9999337SNeil Armstrong } 931c9999337SNeil Armstrong 9321cf084d1SNeil Armstrong if (priv->vbus && priv->otg_phy_mode == PHY_MODE_USB_HOST) { 9331cf084d1SNeil Armstrong ret = regulator_enable(priv->vbus); 9341cf084d1SNeil Armstrong if (ret) 9351cf084d1SNeil Armstrong return ret; 9361cf084d1SNeil Armstrong } 9371cf084d1SNeil Armstrong 938c9999337SNeil Armstrong return 0; 939c9999337SNeil Armstrong } 940c9999337SNeil Armstrong 941c9999337SNeil Armstrong static const struct dev_pm_ops dwc3_meson_g12a_dev_pm_ops = { 942c9999337SNeil Armstrong SET_SYSTEM_SLEEP_PM_OPS(dwc3_meson_g12a_suspend, dwc3_meson_g12a_resume) 943c9999337SNeil Armstrong SET_RUNTIME_PM_OPS(dwc3_meson_g12a_runtime_suspend, 944c9999337SNeil Armstrong dwc3_meson_g12a_runtime_resume, NULL) 945c9999337SNeil Armstrong }; 946c9999337SNeil Armstrong 947c9999337SNeil Armstrong static const struct of_device_id dwc3_meson_g12a_match[] = { 9481e355f21SHanjie Lin { 949a9fc15e0SNeil Armstrong .compatible = "amlogic,meson-gxl-usb-ctrl", 950a9fc15e0SNeil Armstrong .data = &gxl_drvdata, 951a9fc15e0SNeil Armstrong }, 952a9fc15e0SNeil Armstrong { 953a9fc15e0SNeil Armstrong .compatible = "amlogic,meson-gxm-usb-ctrl", 954a9fc15e0SNeil Armstrong .data = &gxm_drvdata, 955a9fc15e0SNeil Armstrong }, 956a9fc15e0SNeil Armstrong { 95765f3d449SNeil Armstrong .compatible = "amlogic,meson-axg-usb-ctrl", 95865f3d449SNeil Armstrong .data = &axg_drvdata, 95965f3d449SNeil Armstrong }, 96065f3d449SNeil Armstrong { 9611e355f21SHanjie Lin .compatible = "amlogic,meson-g12a-usb-ctrl", 9621e355f21SHanjie Lin .data = &g12a_drvdata, 9631e355f21SHanjie Lin }, 9641e355f21SHanjie Lin { 9651e355f21SHanjie Lin .compatible = "amlogic,meson-a1-usb-ctrl", 9661e355f21SHanjie Lin .data = &a1_drvdata, 9671e355f21SHanjie Lin }, 968c9999337SNeil Armstrong { /* Sentinel */ } 969c9999337SNeil Armstrong }; 970c9999337SNeil Armstrong MODULE_DEVICE_TABLE(of, dwc3_meson_g12a_match); 971c9999337SNeil Armstrong 972c9999337SNeil Armstrong static struct platform_driver dwc3_meson_g12a_driver = { 973c9999337SNeil Armstrong .probe = dwc3_meson_g12a_probe, 974c9999337SNeil Armstrong .remove = dwc3_meson_g12a_remove, 975c9999337SNeil Armstrong .driver = { 976c9999337SNeil Armstrong .name = "dwc3-meson-g12a", 977c9999337SNeil Armstrong .of_match_table = dwc3_meson_g12a_match, 978c9999337SNeil Armstrong .pm = &dwc3_meson_g12a_dev_pm_ops, 979c9999337SNeil Armstrong }, 980c9999337SNeil Armstrong }; 981c9999337SNeil Armstrong 982c9999337SNeil Armstrong module_platform_driver(dwc3_meson_g12a_driver); 983c9999337SNeil Armstrong MODULE_LICENSE("GPL v2"); 984c9999337SNeil Armstrong MODULE_DESCRIPTION("Amlogic Meson G12A USB Glue Layer"); 985c9999337SNeil Armstrong MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); 986