1e6e505b9SAlexander Graf /* 2e6e505b9SAlexander Graf * Sunxi usb-phy code 3e6e505b9SAlexander Graf * 4e6e505b9SAlexander Graf * Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com> 5e6e505b9SAlexander Graf * Copyright (C) 2014 Roman Byshko <rbyshko@gmail.com> 6e6e505b9SAlexander Graf * 7e6e505b9SAlexander Graf * Based on code from 8e6e505b9SAlexander Graf * Allwinner Technology Co., Ltd. <www.allwinnertech.com> 9e6e505b9SAlexander Graf * 10e6e505b9SAlexander Graf * SPDX-License-Identifier: GPL-2.0+ 11e6e505b9SAlexander Graf */ 12e6e505b9SAlexander Graf 13e6e505b9SAlexander Graf #include <common.h> 14e6e505b9SAlexander Graf #include <asm/arch/clock.h> 15e6e505b9SAlexander Graf #include <asm/arch/cpu.h> 16e6e505b9SAlexander Graf #include <asm/arch/usb_phy.h> 17e6e505b9SAlexander Graf #include <asm/gpio.h> 18e6e505b9SAlexander Graf #include <asm/io.h> 19e6e505b9SAlexander Graf #include <errno.h> 20e6e505b9SAlexander Graf 21e6e505b9SAlexander Graf #define SUNXI_USB_PMU_IRQ_ENABLE 0x800 22e6e505b9SAlexander Graf #ifdef CONFIG_MACH_SUN8I_A33 23e6e505b9SAlexander Graf #define SUNXI_USB_CSR 0x410 24e6e505b9SAlexander Graf #else 25e6e505b9SAlexander Graf #define SUNXI_USB_CSR 0x404 26e6e505b9SAlexander Graf #endif 27e6e505b9SAlexander Graf #define SUNXI_USB_PASSBY_EN 1 28e6e505b9SAlexander Graf 29e6e505b9SAlexander Graf #define SUNXI_EHCI_AHB_ICHR8_EN (1 << 10) 30e6e505b9SAlexander Graf #define SUNXI_EHCI_AHB_INCR4_BURST_EN (1 << 9) 31e6e505b9SAlexander Graf #define SUNXI_EHCI_AHB_INCRX_ALIGN_EN (1 << 8) 32e6e505b9SAlexander Graf #define SUNXI_EHCI_ULPI_BYPASS_EN (1 << 0) 33e6e505b9SAlexander Graf 34e6e505b9SAlexander Graf #define REG_PHY_UNK_H3 0x420 35e6e505b9SAlexander Graf #define REG_PMU_UNK_H3 0x810 36e6e505b9SAlexander Graf 37e6e505b9SAlexander Graf /* A83T specific control bits for PHY0 */ 38e6e505b9SAlexander Graf #define SUNXI_PHY_CTL_VBUSVLDEXT BIT(5) 39e6e505b9SAlexander Graf #define SUNXI_PHY_CTL_SIDDQ BIT(3) 40e6e505b9SAlexander Graf 41e6e505b9SAlexander Graf /* A83T HSIC specific bits */ 42e6e505b9SAlexander Graf #define SUNXI_EHCI_HS_FORCE BIT(20) 43e6e505b9SAlexander Graf #define SUNXI_EHCI_CONNECT_DET BIT(17) 44e6e505b9SAlexander Graf #define SUNXI_EHCI_CONNECT_INT BIT(16) 45e6e505b9SAlexander Graf #define SUNXI_EHCI_HSIC BIT(1) 46e6e505b9SAlexander Graf 47e6e505b9SAlexander Graf static struct sunxi_usb_phy { 48e6e505b9SAlexander Graf int usb_rst_mask; 49e6e505b9SAlexander Graf int gpio_vbus; 50e6e505b9SAlexander Graf int gpio_vbus_det; 51e6e505b9SAlexander Graf int gpio_id_det; 52e6e505b9SAlexander Graf int id; 53e6e505b9SAlexander Graf int init_count; 54e6e505b9SAlexander Graf int power_on_count; 55*0ea5a04fSAlexander Graf ulong base; 56e6e505b9SAlexander Graf } sunxi_usb_phy[] = { 57e6e505b9SAlexander Graf { 58e6e505b9SAlexander Graf .usb_rst_mask = CCM_USB_CTRL_PHY0_RST | CCM_USB_CTRL_PHY0_CLK, 59e6e505b9SAlexander Graf .id = 0, 60e6e505b9SAlexander Graf .base = SUNXI_USB0_BASE, 61e6e505b9SAlexander Graf }, 62e6e505b9SAlexander Graf { 63e6e505b9SAlexander Graf .usb_rst_mask = CCM_USB_CTRL_PHY1_RST | CCM_USB_CTRL_PHY1_CLK, 64e6e505b9SAlexander Graf .id = 1, 65e6e505b9SAlexander Graf .base = SUNXI_USB1_BASE, 66e6e505b9SAlexander Graf }, 67e6e505b9SAlexander Graf #if CONFIG_SUNXI_USB_PHYS >= 3 68e6e505b9SAlexander Graf { 69e6e505b9SAlexander Graf #ifdef CONFIG_MACH_SUN8I_A83T 70e6e505b9SAlexander Graf .usb_rst_mask = CCM_USB_CTRL_HSIC_RST | CCM_USB_CTRL_HSIC_CLK | 71e6e505b9SAlexander Graf CCM_USB_CTRL_12M_CLK, 72e6e505b9SAlexander Graf #else 73e6e505b9SAlexander Graf .usb_rst_mask = CCM_USB_CTRL_PHY2_RST | CCM_USB_CTRL_PHY2_CLK, 74e6e505b9SAlexander Graf #endif 75e6e505b9SAlexander Graf .id = 2, 76e6e505b9SAlexander Graf .base = SUNXI_USB2_BASE, 77e6e505b9SAlexander Graf }, 78e6e505b9SAlexander Graf #endif 79e6e505b9SAlexander Graf #if CONFIG_SUNXI_USB_PHYS >= 4 80e6e505b9SAlexander Graf { 81e6e505b9SAlexander Graf .usb_rst_mask = CCM_USB_CTRL_PHY3_RST | CCM_USB_CTRL_PHY3_CLK, 82e6e505b9SAlexander Graf .id = 3, 83e6e505b9SAlexander Graf .base = SUNXI_USB3_BASE, 84e6e505b9SAlexander Graf } 85e6e505b9SAlexander Graf #endif 86e6e505b9SAlexander Graf }; 87e6e505b9SAlexander Graf 88e6e505b9SAlexander Graf static int get_vbus_gpio(int index) 89e6e505b9SAlexander Graf { 90e6e505b9SAlexander Graf switch (index) { 91e6e505b9SAlexander Graf case 0: return sunxi_name_to_gpio(CONFIG_USB0_VBUS_PIN); 92e6e505b9SAlexander Graf case 1: return sunxi_name_to_gpio(CONFIG_USB1_VBUS_PIN); 93e6e505b9SAlexander Graf case 2: return sunxi_name_to_gpio(CONFIG_USB2_VBUS_PIN); 94e6e505b9SAlexander Graf case 3: return sunxi_name_to_gpio(CONFIG_USB3_VBUS_PIN); 95e6e505b9SAlexander Graf } 96e6e505b9SAlexander Graf return -EINVAL; 97e6e505b9SAlexander Graf } 98e6e505b9SAlexander Graf 99e6e505b9SAlexander Graf static int get_vbus_detect_gpio(int index) 100e6e505b9SAlexander Graf { 101e6e505b9SAlexander Graf switch (index) { 102e6e505b9SAlexander Graf case 0: return sunxi_name_to_gpio(CONFIG_USB0_VBUS_DET); 103e6e505b9SAlexander Graf } 104e6e505b9SAlexander Graf return -EINVAL; 105e6e505b9SAlexander Graf } 106e6e505b9SAlexander Graf 107e6e505b9SAlexander Graf static int get_id_detect_gpio(int index) 108e6e505b9SAlexander Graf { 109e6e505b9SAlexander Graf switch (index) { 110e6e505b9SAlexander Graf case 0: return sunxi_name_to_gpio(CONFIG_USB0_ID_DET); 111e6e505b9SAlexander Graf } 112e6e505b9SAlexander Graf return -EINVAL; 113e6e505b9SAlexander Graf } 114e6e505b9SAlexander Graf 115e6e505b9SAlexander Graf __maybe_unused static void usb_phy_write(struct sunxi_usb_phy *phy, int addr, 116e6e505b9SAlexander Graf int data, int len) 117e6e505b9SAlexander Graf { 118e6e505b9SAlexander Graf int j = 0, usbc_bit = 0; 119e6e505b9SAlexander Graf void *dest = (void *)SUNXI_USB0_BASE + SUNXI_USB_CSR; 120e6e505b9SAlexander Graf 121e6e505b9SAlexander Graf #ifdef CONFIG_MACH_SUN8I_A33 122e6e505b9SAlexander Graf /* CSR needs to be explicitly initialized to 0 on A33 */ 123e6e505b9SAlexander Graf writel(0, dest); 124e6e505b9SAlexander Graf #endif 125e6e505b9SAlexander Graf 126e6e505b9SAlexander Graf usbc_bit = 1 << (phy->id * 2); 127e6e505b9SAlexander Graf for (j = 0; j < len; j++) { 128e6e505b9SAlexander Graf /* set the bit address to be written */ 129e6e505b9SAlexander Graf clrbits_le32(dest, 0xff << 8); 130e6e505b9SAlexander Graf setbits_le32(dest, (addr + j) << 8); 131e6e505b9SAlexander Graf 132e6e505b9SAlexander Graf clrbits_le32(dest, usbc_bit); 133e6e505b9SAlexander Graf /* set data bit */ 134e6e505b9SAlexander Graf if (data & 0x1) 135e6e505b9SAlexander Graf setbits_le32(dest, 1 << 7); 136e6e505b9SAlexander Graf else 137e6e505b9SAlexander Graf clrbits_le32(dest, 1 << 7); 138e6e505b9SAlexander Graf 139e6e505b9SAlexander Graf setbits_le32(dest, usbc_bit); 140e6e505b9SAlexander Graf 141e6e505b9SAlexander Graf clrbits_le32(dest, usbc_bit); 142e6e505b9SAlexander Graf 143e6e505b9SAlexander Graf data >>= 1; 144e6e505b9SAlexander Graf } 145e6e505b9SAlexander Graf } 146e6e505b9SAlexander Graf 147e6e505b9SAlexander Graf #if defined CONFIG_MACH_SUN8I_H3 148e6e505b9SAlexander Graf static void sunxi_usb_phy_config(struct sunxi_usb_phy *phy) 149e6e505b9SAlexander Graf { 150e6e505b9SAlexander Graf if (phy->id == 0) 151e6e505b9SAlexander Graf clrbits_le32(SUNXI_USBPHY_BASE + REG_PHY_UNK_H3, 0x01); 152e6e505b9SAlexander Graf 153e6e505b9SAlexander Graf clrbits_le32(phy->base + REG_PMU_UNK_H3, 0x02); 154e6e505b9SAlexander Graf } 155e6e505b9SAlexander Graf #elif defined CONFIG_MACH_SUN8I_A83T 156e6e505b9SAlexander Graf static void sunxi_usb_phy_config(struct sunxi_usb_phy *phy) 157e6e505b9SAlexander Graf { 158e6e505b9SAlexander Graf } 159e6e505b9SAlexander Graf #else 160e6e505b9SAlexander Graf static void sunxi_usb_phy_config(struct sunxi_usb_phy *phy) 161e6e505b9SAlexander Graf { 162e6e505b9SAlexander Graf /* The following comments are machine 163e6e505b9SAlexander Graf * translated from Chinese, you have been warned! 164e6e505b9SAlexander Graf */ 165e6e505b9SAlexander Graf 166e6e505b9SAlexander Graf /* Regulation 45 ohms */ 167e6e505b9SAlexander Graf if (phy->id == 0) 168e6e505b9SAlexander Graf usb_phy_write(phy, 0x0c, 0x01, 1); 169e6e505b9SAlexander Graf 170e6e505b9SAlexander Graf /* adjust PHY's magnitude and rate */ 171e6e505b9SAlexander Graf usb_phy_write(phy, 0x20, 0x14, 5); 172e6e505b9SAlexander Graf 173e6e505b9SAlexander Graf /* threshold adjustment disconnect */ 174e6e505b9SAlexander Graf #if defined CONFIG_MACH_SUN5I || defined CONFIG_MACH_SUN7I 175e6e505b9SAlexander Graf usb_phy_write(phy, 0x2a, 2, 2); 176e6e505b9SAlexander Graf #else 177e6e505b9SAlexander Graf usb_phy_write(phy, 0x2a, 3, 2); 178e6e505b9SAlexander Graf #endif 179e6e505b9SAlexander Graf 180e6e505b9SAlexander Graf return; 181e6e505b9SAlexander Graf } 182e6e505b9SAlexander Graf #endif 183e6e505b9SAlexander Graf 184e6e505b9SAlexander Graf static void sunxi_usb_phy_passby(struct sunxi_usb_phy *phy, int enable) 185e6e505b9SAlexander Graf { 186e6e505b9SAlexander Graf unsigned long bits = 0; 187e6e505b9SAlexander Graf void *addr; 188e6e505b9SAlexander Graf 189e6e505b9SAlexander Graf addr = (void *)phy->base + SUNXI_USB_PMU_IRQ_ENABLE; 190e6e505b9SAlexander Graf 191e6e505b9SAlexander Graf bits = SUNXI_EHCI_AHB_ICHR8_EN | 192e6e505b9SAlexander Graf SUNXI_EHCI_AHB_INCR4_BURST_EN | 193e6e505b9SAlexander Graf SUNXI_EHCI_AHB_INCRX_ALIGN_EN | 194e6e505b9SAlexander Graf SUNXI_EHCI_ULPI_BYPASS_EN; 195e6e505b9SAlexander Graf 196e6e505b9SAlexander Graf #ifdef CONFIG_MACH_SUN8I_A83T 197e6e505b9SAlexander Graf if (phy->id == 2) 198e6e505b9SAlexander Graf bits |= SUNXI_EHCI_HS_FORCE | 199e6e505b9SAlexander Graf SUNXI_EHCI_CONNECT_INT | 200e6e505b9SAlexander Graf SUNXI_EHCI_HSIC; 201e6e505b9SAlexander Graf #endif 202e6e505b9SAlexander Graf 203e6e505b9SAlexander Graf if (enable) 204e6e505b9SAlexander Graf setbits_le32(addr, bits); 205e6e505b9SAlexander Graf else 206e6e505b9SAlexander Graf clrbits_le32(addr, bits); 207e6e505b9SAlexander Graf 208e6e505b9SAlexander Graf return; 209e6e505b9SAlexander Graf } 210e6e505b9SAlexander Graf 211e6e505b9SAlexander Graf void sunxi_usb_phy_enable_squelch_detect(int index, int enable) 212e6e505b9SAlexander Graf { 213e6e505b9SAlexander Graf #ifndef CONFIG_MACH_SUN8I_A83T 214e6e505b9SAlexander Graf struct sunxi_usb_phy *phy = &sunxi_usb_phy[index]; 215e6e505b9SAlexander Graf 216e6e505b9SAlexander Graf usb_phy_write(phy, 0x3c, enable ? 0 : 2, 2); 217e6e505b9SAlexander Graf #endif 218e6e505b9SAlexander Graf } 219e6e505b9SAlexander Graf 220e6e505b9SAlexander Graf void sunxi_usb_phy_init(int index) 221e6e505b9SAlexander Graf { 222e6e505b9SAlexander Graf struct sunxi_usb_phy *phy = &sunxi_usb_phy[index]; 223e6e505b9SAlexander Graf struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 224e6e505b9SAlexander Graf 225e6e505b9SAlexander Graf phy->init_count++; 226e6e505b9SAlexander Graf if (phy->init_count != 1) 227e6e505b9SAlexander Graf return; 228e6e505b9SAlexander Graf 229e6e505b9SAlexander Graf setbits_le32(&ccm->usb_clk_cfg, phy->usb_rst_mask); 230e6e505b9SAlexander Graf 231e6e505b9SAlexander Graf sunxi_usb_phy_config(phy); 232e6e505b9SAlexander Graf 233e6e505b9SAlexander Graf if (phy->id != 0) 234e6e505b9SAlexander Graf sunxi_usb_phy_passby(phy, SUNXI_USB_PASSBY_EN); 235e6e505b9SAlexander Graf 236e6e505b9SAlexander Graf #ifdef CONFIG_MACH_SUN8I_A83T 237e6e505b9SAlexander Graf if (phy->id == 0) { 238e6e505b9SAlexander Graf setbits_le32(SUNXI_USB0_BASE + SUNXI_USB_CSR, 239e6e505b9SAlexander Graf SUNXI_PHY_CTL_VBUSVLDEXT); 240e6e505b9SAlexander Graf clrbits_le32(SUNXI_USB0_BASE + SUNXI_USB_CSR, 241e6e505b9SAlexander Graf SUNXI_PHY_CTL_SIDDQ); 242e6e505b9SAlexander Graf } 243e6e505b9SAlexander Graf #endif 244e6e505b9SAlexander Graf } 245e6e505b9SAlexander Graf 246e6e505b9SAlexander Graf void sunxi_usb_phy_exit(int index) 247e6e505b9SAlexander Graf { 248e6e505b9SAlexander Graf struct sunxi_usb_phy *phy = &sunxi_usb_phy[index]; 249e6e505b9SAlexander Graf struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 250e6e505b9SAlexander Graf 251e6e505b9SAlexander Graf phy->init_count--; 252e6e505b9SAlexander Graf if (phy->init_count != 0) 253e6e505b9SAlexander Graf return; 254e6e505b9SAlexander Graf 255e6e505b9SAlexander Graf if (phy->id != 0) 256e6e505b9SAlexander Graf sunxi_usb_phy_passby(phy, !SUNXI_USB_PASSBY_EN); 257e6e505b9SAlexander Graf 258e6e505b9SAlexander Graf #ifdef CONFIG_MACH_SUN8I_A83T 259e6e505b9SAlexander Graf if (phy->id == 0) { 260e6e505b9SAlexander Graf setbits_le32(SUNXI_USB0_BASE + SUNXI_USB_CSR, 261e6e505b9SAlexander Graf SUNXI_PHY_CTL_SIDDQ); 262e6e505b9SAlexander Graf } 263e6e505b9SAlexander Graf #endif 264e6e505b9SAlexander Graf 265e6e505b9SAlexander Graf clrbits_le32(&ccm->usb_clk_cfg, phy->usb_rst_mask); 266e6e505b9SAlexander Graf } 267e6e505b9SAlexander Graf 268e6e505b9SAlexander Graf void sunxi_usb_phy_power_on(int index) 269e6e505b9SAlexander Graf { 270e6e505b9SAlexander Graf struct sunxi_usb_phy *phy = &sunxi_usb_phy[index]; 271e6e505b9SAlexander Graf 272e6e505b9SAlexander Graf phy->power_on_count++; 273e6e505b9SAlexander Graf if (phy->power_on_count != 1) 274e6e505b9SAlexander Graf return; 275e6e505b9SAlexander Graf 276e6e505b9SAlexander Graf if (phy->gpio_vbus >= 0) 277e6e505b9SAlexander Graf gpio_set_value(phy->gpio_vbus, 1); 278e6e505b9SAlexander Graf } 279e6e505b9SAlexander Graf 280e6e505b9SAlexander Graf void sunxi_usb_phy_power_off(int index) 281e6e505b9SAlexander Graf { 282e6e505b9SAlexander Graf struct sunxi_usb_phy *phy = &sunxi_usb_phy[index]; 283e6e505b9SAlexander Graf 284e6e505b9SAlexander Graf phy->power_on_count--; 285e6e505b9SAlexander Graf if (phy->power_on_count != 0) 286e6e505b9SAlexander Graf return; 287e6e505b9SAlexander Graf 288e6e505b9SAlexander Graf if (phy->gpio_vbus >= 0) 289e6e505b9SAlexander Graf gpio_set_value(phy->gpio_vbus, 0); 290e6e505b9SAlexander Graf } 291e6e505b9SAlexander Graf 292e6e505b9SAlexander Graf int sunxi_usb_phy_power_is_on(int index) 293e6e505b9SAlexander Graf { 294e6e505b9SAlexander Graf struct sunxi_usb_phy *phy = &sunxi_usb_phy[index]; 295e6e505b9SAlexander Graf 296e6e505b9SAlexander Graf return phy->power_on_count > 0; 297e6e505b9SAlexander Graf } 298e6e505b9SAlexander Graf 299e6e505b9SAlexander Graf int sunxi_usb_phy_vbus_detect(int index) 300e6e505b9SAlexander Graf { 301e6e505b9SAlexander Graf struct sunxi_usb_phy *phy = &sunxi_usb_phy[index]; 302e6e505b9SAlexander Graf int err, retries = 3; 303e6e505b9SAlexander Graf 304e6e505b9SAlexander Graf if (phy->gpio_vbus_det < 0) 305e6e505b9SAlexander Graf return phy->gpio_vbus_det; 306e6e505b9SAlexander Graf 307e6e505b9SAlexander Graf err = gpio_get_value(phy->gpio_vbus_det); 308e6e505b9SAlexander Graf /* 309e6e505b9SAlexander Graf * Vbus may have been provided by the board and just been turned of 310e6e505b9SAlexander Graf * some milliseconds ago on reset, what we're measuring then is a 311e6e505b9SAlexander Graf * residual charge on Vbus, sleep a bit and try again. 312e6e505b9SAlexander Graf */ 313e6e505b9SAlexander Graf while (err > 0 && retries--) { 314e6e505b9SAlexander Graf mdelay(100); 315e6e505b9SAlexander Graf err = gpio_get_value(phy->gpio_vbus_det); 316e6e505b9SAlexander Graf } 317e6e505b9SAlexander Graf 318e6e505b9SAlexander Graf return err; 319e6e505b9SAlexander Graf } 320e6e505b9SAlexander Graf 321e6e505b9SAlexander Graf int sunxi_usb_phy_id_detect(int index) 322e6e505b9SAlexander Graf { 323e6e505b9SAlexander Graf struct sunxi_usb_phy *phy = &sunxi_usb_phy[index]; 324e6e505b9SAlexander Graf 325e6e505b9SAlexander Graf if (phy->gpio_id_det < 0) 326e6e505b9SAlexander Graf return phy->gpio_id_det; 327e6e505b9SAlexander Graf 328e6e505b9SAlexander Graf return gpio_get_value(phy->gpio_id_det); 329e6e505b9SAlexander Graf } 330e6e505b9SAlexander Graf 331e6e505b9SAlexander Graf int sunxi_usb_phy_probe(void) 332e6e505b9SAlexander Graf { 333e6e505b9SAlexander Graf struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 334e6e505b9SAlexander Graf struct sunxi_usb_phy *phy; 335e6e505b9SAlexander Graf int i, ret = 0; 336e6e505b9SAlexander Graf 337e6e505b9SAlexander Graf for (i = 0; i < CONFIG_SUNXI_USB_PHYS; i++) { 338e6e505b9SAlexander Graf phy = &sunxi_usb_phy[i]; 339e6e505b9SAlexander Graf 340e6e505b9SAlexander Graf phy->gpio_vbus = get_vbus_gpio(i); 341e6e505b9SAlexander Graf if (phy->gpio_vbus >= 0) { 342e6e505b9SAlexander Graf ret = gpio_request(phy->gpio_vbus, "usb_vbus"); 343e6e505b9SAlexander Graf if (ret) 344e6e505b9SAlexander Graf return ret; 345e6e505b9SAlexander Graf ret = gpio_direction_output(phy->gpio_vbus, 0); 346e6e505b9SAlexander Graf if (ret) 347e6e505b9SAlexander Graf return ret; 348e6e505b9SAlexander Graf } 349e6e505b9SAlexander Graf 350e6e505b9SAlexander Graf phy->gpio_vbus_det = get_vbus_detect_gpio(i); 351e6e505b9SAlexander Graf if (phy->gpio_vbus_det >= 0) { 352e6e505b9SAlexander Graf ret = gpio_request(phy->gpio_vbus_det, "usb_vbus_det"); 353e6e505b9SAlexander Graf if (ret) 354e6e505b9SAlexander Graf return ret; 355e6e505b9SAlexander Graf ret = gpio_direction_input(phy->gpio_vbus_det); 356e6e505b9SAlexander Graf if (ret) 357e6e505b9SAlexander Graf return ret; 358e6e505b9SAlexander Graf } 359e6e505b9SAlexander Graf 360e6e505b9SAlexander Graf phy->gpio_id_det = get_id_detect_gpio(i); 361e6e505b9SAlexander Graf if (phy->gpio_id_det >= 0) { 362e6e505b9SAlexander Graf ret = gpio_request(phy->gpio_id_det, "usb_id_det"); 363e6e505b9SAlexander Graf if (ret) 364e6e505b9SAlexander Graf return ret; 365e6e505b9SAlexander Graf ret = gpio_direction_input(phy->gpio_id_det); 366e6e505b9SAlexander Graf if (ret) 367e6e505b9SAlexander Graf return ret; 368e6e505b9SAlexander Graf sunxi_gpio_set_pull(phy->gpio_id_det, 369e6e505b9SAlexander Graf SUNXI_GPIO_PULL_UP); 370e6e505b9SAlexander Graf } 371e6e505b9SAlexander Graf } 372e6e505b9SAlexander Graf 373e6e505b9SAlexander Graf setbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE); 374e6e505b9SAlexander Graf 375e6e505b9SAlexander Graf return 0; 376e6e505b9SAlexander Graf } 377e6e505b9SAlexander Graf 378e6e505b9SAlexander Graf int sunxi_usb_phy_remove(void) 379e6e505b9SAlexander Graf { 380e6e505b9SAlexander Graf struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 381e6e505b9SAlexander Graf struct sunxi_usb_phy *phy; 382e6e505b9SAlexander Graf int i; 383e6e505b9SAlexander Graf 384e6e505b9SAlexander Graf clrbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE); 385e6e505b9SAlexander Graf 386e6e505b9SAlexander Graf for (i = 0; i < CONFIG_SUNXI_USB_PHYS; i++) { 387e6e505b9SAlexander Graf phy = &sunxi_usb_phy[i]; 388e6e505b9SAlexander Graf 389e6e505b9SAlexander Graf if (phy->gpio_vbus >= 0) 390e6e505b9SAlexander Graf gpio_free(phy->gpio_vbus); 391e6e505b9SAlexander Graf 392e6e505b9SAlexander Graf if (phy->gpio_vbus_det >= 0) 393e6e505b9SAlexander Graf gpio_free(phy->gpio_vbus_det); 394e6e505b9SAlexander Graf 395e6e505b9SAlexander Graf if (phy->gpio_id_det >= 0) 396e6e505b9SAlexander Graf gpio_free(phy->gpio_id_det); 397e6e505b9SAlexander Graf } 398e6e505b9SAlexander Graf 399e6e505b9SAlexander Graf return 0; 400e6e505b9SAlexander Graf } 401