162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/delay.h> 762306a36Sopenharmony_ci#include <linux/io.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/of.h> 1062306a36Sopenharmony_ci#include <linux/phy/phy.h> 1162306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 1262306a36Sopenharmony_ci#include <linux/platform_device.h> 1362306a36Sopenharmony_ci#include <linux/clk.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <soc/tegra/fuse.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "xusb.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* FUSE USB_CALIB registers */ 2162306a36Sopenharmony_ci#define HS_CURR_LEVEL_PADX_SHIFT(x) ((x) ? (11 + (x - 1) * 6) : 0) 2262306a36Sopenharmony_ci#define HS_CURR_LEVEL_PAD_MASK 0x3f 2362306a36Sopenharmony_ci#define HS_TERM_RANGE_ADJ_SHIFT 7 2462306a36Sopenharmony_ci#define HS_TERM_RANGE_ADJ_MASK 0xf 2562306a36Sopenharmony_ci#define HS_SQUELCH_SHIFT 29 2662306a36Sopenharmony_ci#define HS_SQUELCH_MASK 0x7 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define RPD_CTRL_SHIFT 0 2962306a36Sopenharmony_ci#define RPD_CTRL_MASK 0x1f 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* XUSB PADCTL registers */ 3262306a36Sopenharmony_ci#define XUSB_PADCTL_USB2_PAD_MUX 0x4 3362306a36Sopenharmony_ci#define USB2_PORT_SHIFT(x) ((x) * 2) 3462306a36Sopenharmony_ci#define USB2_PORT_MASK 0x3 3562306a36Sopenharmony_ci#define PORT_XUSB 1 3662306a36Sopenharmony_ci#define HSIC_PORT_SHIFT(x) ((x) + 20) 3762306a36Sopenharmony_ci#define HSIC_PORT_MASK 0x1 3862306a36Sopenharmony_ci#define PORT_HSIC 0 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define XUSB_PADCTL_USB2_PORT_CAP 0x8 4162306a36Sopenharmony_ci#define XUSB_PADCTL_SS_PORT_CAP 0xc 4262306a36Sopenharmony_ci#define PORTX_CAP_SHIFT(x) ((x) * 4) 4362306a36Sopenharmony_ci#define PORT_CAP_MASK 0x3 4462306a36Sopenharmony_ci#define PORT_CAP_DISABLED 0x0 4562306a36Sopenharmony_ci#define PORT_CAP_HOST 0x1 4662306a36Sopenharmony_ci#define PORT_CAP_DEVICE 0x2 4762306a36Sopenharmony_ci#define PORT_CAP_OTG 0x3 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define XUSB_PADCTL_ELPG_PROGRAM 0x20 5062306a36Sopenharmony_ci#define USB2_PORT_WAKE_INTERRUPT_ENABLE(x) BIT(x) 5162306a36Sopenharmony_ci#define USB2_PORT_WAKEUP_EVENT(x) BIT((x) + 7) 5262306a36Sopenharmony_ci#define SS_PORT_WAKE_INTERRUPT_ENABLE(x) BIT((x) + 14) 5362306a36Sopenharmony_ci#define SS_PORT_WAKEUP_EVENT(x) BIT((x) + 21) 5462306a36Sopenharmony_ci#define USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(x) BIT((x) + 28) 5562306a36Sopenharmony_ci#define USB2_HSIC_PORT_WAKEUP_EVENT(x) BIT((x) + 30) 5662306a36Sopenharmony_ci#define ALL_WAKE_EVENTS \ 5762306a36Sopenharmony_ci (USB2_PORT_WAKEUP_EVENT(0) | USB2_PORT_WAKEUP_EVENT(1) | \ 5862306a36Sopenharmony_ci USB2_PORT_WAKEUP_EVENT(2) | SS_PORT_WAKEUP_EVENT(0) | \ 5962306a36Sopenharmony_ci SS_PORT_WAKEUP_EVENT(1) | SS_PORT_WAKEUP_EVENT(2) | \ 6062306a36Sopenharmony_ci USB2_HSIC_PORT_WAKEUP_EVENT(0)) 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#define XUSB_PADCTL_ELPG_PROGRAM_1 0x24 6362306a36Sopenharmony_ci#define SSPX_ELPG_CLAMP_EN(x) BIT(0 + (x) * 3) 6462306a36Sopenharmony_ci#define SSPX_ELPG_CLAMP_EN_EARLY(x) BIT(1 + (x) * 3) 6562306a36Sopenharmony_ci#define SSPX_ELPG_VCORE_DOWN(x) BIT(2 + (x) * 3) 6662306a36Sopenharmony_ci#define XUSB_PADCTL_SS_PORT_CFG 0x2c 6762306a36Sopenharmony_ci#define PORTX_SPEED_SUPPORT_SHIFT(x) ((x) * 4) 6862306a36Sopenharmony_ci#define PORTX_SPEED_SUPPORT_MASK (0x3) 6962306a36Sopenharmony_ci#define PORT_SPEED_SUPPORT_GEN1 (0x0) 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x) (0x88 + (x) * 0x40) 7262306a36Sopenharmony_ci#define HS_CURR_LEVEL(x) ((x) & 0x3f) 7362306a36Sopenharmony_ci#define TERM_SEL BIT(25) 7462306a36Sopenharmony_ci#define USB2_OTG_PD BIT(26) 7562306a36Sopenharmony_ci#define USB2_OTG_PD2 BIT(27) 7662306a36Sopenharmony_ci#define USB2_OTG_PD2_OVRD_EN BIT(28) 7762306a36Sopenharmony_ci#define USB2_OTG_PD_ZI BIT(29) 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci#define XUSB_PADCTL_USB2_OTG_PADX_CTL1(x) (0x8c + (x) * 0x40) 8062306a36Sopenharmony_ci#define USB2_OTG_PD_DR BIT(2) 8162306a36Sopenharmony_ci#define TERM_RANGE_ADJ(x) (((x) & 0xf) << 3) 8262306a36Sopenharmony_ci#define RPD_CTRL(x) (((x) & 0x1f) << 26) 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x284 8562306a36Sopenharmony_ci#define BIAS_PAD_PD BIT(11) 8662306a36Sopenharmony_ci#define HS_SQUELCH_LEVEL(x) (((x) & 0x7) << 0) 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#define XUSB_PADCTL_USB2_BIAS_PAD_CTL1 0x288 8962306a36Sopenharmony_ci#define USB2_TRK_START_TIMER(x) (((x) & 0x7f) << 12) 9062306a36Sopenharmony_ci#define USB2_TRK_DONE_RESET_TIMER(x) (((x) & 0x7f) << 19) 9162306a36Sopenharmony_ci#define USB2_PD_TRK BIT(26) 9262306a36Sopenharmony_ci#define USB2_TRK_COMPLETED BIT(31) 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci#define XUSB_PADCTL_USB2_BIAS_PAD_CTL2 0x28c 9562306a36Sopenharmony_ci#define USB2_TRK_HW_MODE BIT(0) 9662306a36Sopenharmony_ci#define CYA_TRK_CODE_UPDATE_ON_IDLE BIT(31) 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci#define XUSB_PADCTL_HSIC_PADX_CTL0(x) (0x300 + (x) * 0x20) 9962306a36Sopenharmony_ci#define HSIC_PD_TX_DATA0 BIT(1) 10062306a36Sopenharmony_ci#define HSIC_PD_TX_STROBE BIT(3) 10162306a36Sopenharmony_ci#define HSIC_PD_RX_DATA0 BIT(4) 10262306a36Sopenharmony_ci#define HSIC_PD_RX_STROBE BIT(6) 10362306a36Sopenharmony_ci#define HSIC_PD_ZI_DATA0 BIT(7) 10462306a36Sopenharmony_ci#define HSIC_PD_ZI_STROBE BIT(9) 10562306a36Sopenharmony_ci#define HSIC_RPD_DATA0 BIT(13) 10662306a36Sopenharmony_ci#define HSIC_RPD_STROBE BIT(15) 10762306a36Sopenharmony_ci#define HSIC_RPU_DATA0 BIT(16) 10862306a36Sopenharmony_ci#define HSIC_RPU_STROBE BIT(18) 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci#define XUSB_PADCTL_HSIC_PAD_TRK_CTL0 0x340 11162306a36Sopenharmony_ci#define HSIC_TRK_START_TIMER(x) (((x) & 0x7f) << 5) 11262306a36Sopenharmony_ci#define HSIC_TRK_DONE_RESET_TIMER(x) (((x) & 0x7f) << 12) 11362306a36Sopenharmony_ci#define HSIC_PD_TRK BIT(19) 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci#define USB2_VBUS_ID 0x360 11662306a36Sopenharmony_ci#define VBUS_OVERRIDE BIT(14) 11762306a36Sopenharmony_ci#define ID_OVERRIDE(x) (((x) & 0xf) << 18) 11862306a36Sopenharmony_ci#define ID_OVERRIDE_FLOATING ID_OVERRIDE(8) 11962306a36Sopenharmony_ci#define ID_OVERRIDE_GROUNDED ID_OVERRIDE(0) 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* XUSB AO registers */ 12262306a36Sopenharmony_ci#define XUSB_AO_USB_DEBOUNCE_DEL (0x4) 12362306a36Sopenharmony_ci#define UHSIC_LINE_DEB_CNT(x) (((x) & 0xf) << 4) 12462306a36Sopenharmony_ci#define UTMIP_LINE_DEB_CNT(x) ((x) & 0xf) 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci#define XUSB_AO_UTMIP_TRIGGERS(x) (0x40 + (x) * 4) 12762306a36Sopenharmony_ci#define CLR_WALK_PTR BIT(0) 12862306a36Sopenharmony_ci#define CAP_CFG BIT(1) 12962306a36Sopenharmony_ci#define CLR_WAKE_ALARM BIT(3) 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci#define XUSB_AO_UHSIC_TRIGGERS(x) (0x60 + (x) * 4) 13262306a36Sopenharmony_ci#define HSIC_CLR_WALK_PTR BIT(0) 13362306a36Sopenharmony_ci#define HSIC_CLR_WAKE_ALARM BIT(3) 13462306a36Sopenharmony_ci#define HSIC_CAP_CFG BIT(4) 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci#define XUSB_AO_UTMIP_SAVED_STATE(x) (0x70 + (x) * 4) 13762306a36Sopenharmony_ci#define SPEED(x) ((x) & 0x3) 13862306a36Sopenharmony_ci#define UTMI_HS SPEED(0) 13962306a36Sopenharmony_ci#define UTMI_FS SPEED(1) 14062306a36Sopenharmony_ci#define UTMI_LS SPEED(2) 14162306a36Sopenharmony_ci#define UTMI_RST SPEED(3) 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci#define XUSB_AO_UHSIC_SAVED_STATE(x) (0x90 + (x) * 4) 14462306a36Sopenharmony_ci#define MODE(x) ((x) & 0x1) 14562306a36Sopenharmony_ci#define MODE_HS MODE(0) 14662306a36Sopenharmony_ci#define MODE_RST MODE(1) 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci#define XUSB_AO_UTMIP_SLEEPWALK_STATUS(x) (0xa0 + (x) * 4) 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci#define XUSB_AO_UTMIP_SLEEPWALK_CFG(x) (0xd0 + (x) * 4) 15162306a36Sopenharmony_ci#define XUSB_AO_UHSIC_SLEEPWALK_CFG(x) (0xf0 + (x) * 4) 15262306a36Sopenharmony_ci#define FAKE_USBOP_VAL BIT(0) 15362306a36Sopenharmony_ci#define FAKE_USBON_VAL BIT(1) 15462306a36Sopenharmony_ci#define FAKE_USBOP_EN BIT(2) 15562306a36Sopenharmony_ci#define FAKE_USBON_EN BIT(3) 15662306a36Sopenharmony_ci#define FAKE_STROBE_VAL BIT(0) 15762306a36Sopenharmony_ci#define FAKE_DATA_VAL BIT(1) 15862306a36Sopenharmony_ci#define FAKE_STROBE_EN BIT(2) 15962306a36Sopenharmony_ci#define FAKE_DATA_EN BIT(3) 16062306a36Sopenharmony_ci#define WAKE_WALK_EN BIT(14) 16162306a36Sopenharmony_ci#define MASTER_ENABLE BIT(15) 16262306a36Sopenharmony_ci#define LINEVAL_WALK_EN BIT(16) 16362306a36Sopenharmony_ci#define WAKE_VAL(x) (((x) & 0xf) << 17) 16462306a36Sopenharmony_ci#define WAKE_VAL_NONE WAKE_VAL(12) 16562306a36Sopenharmony_ci#define WAKE_VAL_ANY WAKE_VAL(15) 16662306a36Sopenharmony_ci#define WAKE_VAL_DS10 WAKE_VAL(2) 16762306a36Sopenharmony_ci#define LINE_WAKEUP_EN BIT(21) 16862306a36Sopenharmony_ci#define MASTER_CFG_SEL BIT(22) 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci#define XUSB_AO_UTMIP_SLEEPWALK(x) (0x100 + (x) * 4) 17162306a36Sopenharmony_ci/* phase A */ 17262306a36Sopenharmony_ci#define USBOP_RPD_A BIT(0) 17362306a36Sopenharmony_ci#define USBON_RPD_A BIT(1) 17462306a36Sopenharmony_ci#define AP_A BIT(4) 17562306a36Sopenharmony_ci#define AN_A BIT(5) 17662306a36Sopenharmony_ci#define HIGHZ_A BIT(6) 17762306a36Sopenharmony_ci#define MASTER_ENABLE_A BIT(7) 17862306a36Sopenharmony_ci/* phase B */ 17962306a36Sopenharmony_ci#define USBOP_RPD_B BIT(8) 18062306a36Sopenharmony_ci#define USBON_RPD_B BIT(9) 18162306a36Sopenharmony_ci#define AP_B BIT(12) 18262306a36Sopenharmony_ci#define AN_B BIT(13) 18362306a36Sopenharmony_ci#define HIGHZ_B BIT(14) 18462306a36Sopenharmony_ci#define MASTER_ENABLE_B BIT(15) 18562306a36Sopenharmony_ci/* phase C */ 18662306a36Sopenharmony_ci#define USBOP_RPD_C BIT(16) 18762306a36Sopenharmony_ci#define USBON_RPD_C BIT(17) 18862306a36Sopenharmony_ci#define AP_C BIT(20) 18962306a36Sopenharmony_ci#define AN_C BIT(21) 19062306a36Sopenharmony_ci#define HIGHZ_C BIT(22) 19162306a36Sopenharmony_ci#define MASTER_ENABLE_C BIT(23) 19262306a36Sopenharmony_ci/* phase D */ 19362306a36Sopenharmony_ci#define USBOP_RPD_D BIT(24) 19462306a36Sopenharmony_ci#define USBON_RPD_D BIT(25) 19562306a36Sopenharmony_ci#define AP_D BIT(28) 19662306a36Sopenharmony_ci#define AN_D BIT(29) 19762306a36Sopenharmony_ci#define HIGHZ_D BIT(30) 19862306a36Sopenharmony_ci#define MASTER_ENABLE_D BIT(31) 19962306a36Sopenharmony_ci#define MASTER_ENABLE_B_C_D \ 20062306a36Sopenharmony_ci (MASTER_ENABLE_B | MASTER_ENABLE_C | MASTER_ENABLE_D) 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci#define XUSB_AO_UHSIC_SLEEPWALK(x) (0x120 + (x) * 4) 20362306a36Sopenharmony_ci/* phase A */ 20462306a36Sopenharmony_ci#define RPD_STROBE_A BIT(0) 20562306a36Sopenharmony_ci#define RPD_DATA0_A BIT(1) 20662306a36Sopenharmony_ci#define RPU_STROBE_A BIT(2) 20762306a36Sopenharmony_ci#define RPU_DATA0_A BIT(3) 20862306a36Sopenharmony_ci/* phase B */ 20962306a36Sopenharmony_ci#define RPD_STROBE_B BIT(8) 21062306a36Sopenharmony_ci#define RPD_DATA0_B BIT(9) 21162306a36Sopenharmony_ci#define RPU_STROBE_B BIT(10) 21262306a36Sopenharmony_ci#define RPU_DATA0_B BIT(11) 21362306a36Sopenharmony_ci/* phase C */ 21462306a36Sopenharmony_ci#define RPD_STROBE_C BIT(16) 21562306a36Sopenharmony_ci#define RPD_DATA0_C BIT(17) 21662306a36Sopenharmony_ci#define RPU_STROBE_C BIT(18) 21762306a36Sopenharmony_ci#define RPU_DATA0_C BIT(19) 21862306a36Sopenharmony_ci/* phase D */ 21962306a36Sopenharmony_ci#define RPD_STROBE_D BIT(24) 22062306a36Sopenharmony_ci#define RPD_DATA0_D BIT(25) 22162306a36Sopenharmony_ci#define RPU_STROBE_D BIT(26) 22262306a36Sopenharmony_ci#define RPU_DATA0_D BIT(27) 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci#define XUSB_AO_UTMIP_PAD_CFG(x) (0x130 + (x) * 4) 22562306a36Sopenharmony_ci#define FSLS_USE_XUSB_AO BIT(3) 22662306a36Sopenharmony_ci#define TRK_CTRL_USE_XUSB_AO BIT(4) 22762306a36Sopenharmony_ci#define RPD_CTRL_USE_XUSB_AO BIT(5) 22862306a36Sopenharmony_ci#define RPU_USE_XUSB_AO BIT(6) 22962306a36Sopenharmony_ci#define VREG_USE_XUSB_AO BIT(7) 23062306a36Sopenharmony_ci#define USBOP_VAL_PD BIT(8) 23162306a36Sopenharmony_ci#define USBON_VAL_PD BIT(9) 23262306a36Sopenharmony_ci#define E_DPD_OVRD_EN BIT(10) 23362306a36Sopenharmony_ci#define E_DPD_OVRD_VAL BIT(11) 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci#define XUSB_AO_UHSIC_PAD_CFG(x) (0x150 + (x) * 4) 23662306a36Sopenharmony_ci#define STROBE_VAL_PD BIT(0) 23762306a36Sopenharmony_ci#define DATA0_VAL_PD BIT(1) 23862306a36Sopenharmony_ci#define USE_XUSB_AO BIT(4) 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci#define TEGRA186_LANE(_name, _offset, _shift, _mask, _type) \ 24162306a36Sopenharmony_ci { \ 24262306a36Sopenharmony_ci .name = _name, \ 24362306a36Sopenharmony_ci .offset = _offset, \ 24462306a36Sopenharmony_ci .shift = _shift, \ 24562306a36Sopenharmony_ci .mask = _mask, \ 24662306a36Sopenharmony_ci .num_funcs = ARRAY_SIZE(tegra186_##_type##_functions), \ 24762306a36Sopenharmony_ci .funcs = tegra186_##_type##_functions, \ 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistruct tegra_xusb_fuse_calibration { 25162306a36Sopenharmony_ci u32 *hs_curr_level; 25262306a36Sopenharmony_ci u32 hs_squelch; 25362306a36Sopenharmony_ci u32 hs_term_range_adj; 25462306a36Sopenharmony_ci u32 rpd_ctrl; 25562306a36Sopenharmony_ci}; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistruct tegra186_xusb_padctl_context { 25862306a36Sopenharmony_ci u32 vbus_id; 25962306a36Sopenharmony_ci u32 usb2_pad_mux; 26062306a36Sopenharmony_ci u32 usb2_port_cap; 26162306a36Sopenharmony_ci u32 ss_port_cap; 26262306a36Sopenharmony_ci}; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistruct tegra186_xusb_padctl { 26562306a36Sopenharmony_ci struct tegra_xusb_padctl base; 26662306a36Sopenharmony_ci void __iomem *ao_regs; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci struct tegra_xusb_fuse_calibration calib; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* UTMI bias and tracking */ 27162306a36Sopenharmony_ci struct clk *usb2_trk_clk; 27262306a36Sopenharmony_ci unsigned int bias_pad_enable; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* padctl context */ 27562306a36Sopenharmony_ci struct tegra186_xusb_padctl_context context; 27662306a36Sopenharmony_ci}; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic inline void ao_writel(struct tegra186_xusb_padctl *priv, u32 value, unsigned int offset) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci writel(value, priv->ao_regs + offset); 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic inline u32 ao_readl(struct tegra186_xusb_padctl *priv, unsigned int offset) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci return readl(priv->ao_regs + offset); 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic inline struct tegra186_xusb_padctl * 28962306a36Sopenharmony_cito_tegra186_xusb_padctl(struct tegra_xusb_padctl *padctl) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci return container_of(padctl, struct tegra186_xusb_padctl, base); 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci/* USB 2.0 UTMI PHY support */ 29562306a36Sopenharmony_cistatic struct tegra_xusb_lane * 29662306a36Sopenharmony_citegra186_usb2_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, 29762306a36Sopenharmony_ci unsigned int index) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct tegra_xusb_usb2_lane *usb2; 30062306a36Sopenharmony_ci int err; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL); 30362306a36Sopenharmony_ci if (!usb2) 30462306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci INIT_LIST_HEAD(&usb2->base.list); 30762306a36Sopenharmony_ci usb2->base.soc = &pad->soc->lanes[index]; 30862306a36Sopenharmony_ci usb2->base.index = index; 30962306a36Sopenharmony_ci usb2->base.pad = pad; 31062306a36Sopenharmony_ci usb2->base.np = np; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci err = tegra_xusb_lane_parse_dt(&usb2->base, np); 31362306a36Sopenharmony_ci if (err < 0) { 31462306a36Sopenharmony_ci kfree(usb2); 31562306a36Sopenharmony_ci return ERR_PTR(err); 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci return &usb2->base; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic void tegra186_usb2_lane_remove(struct tegra_xusb_lane *lane) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci kfree(usb2); 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic int tegra186_utmi_enable_phy_sleepwalk(struct tegra_xusb_lane *lane, 32962306a36Sopenharmony_ci enum usb_device_speed speed) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci struct tegra_xusb_padctl *padctl = lane->pad->padctl; 33262306a36Sopenharmony_ci struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl); 33362306a36Sopenharmony_ci unsigned int index = lane->index; 33462306a36Sopenharmony_ci u32 value; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci mutex_lock(&padctl->lock); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* ensure sleepwalk logic is disabled */ 33962306a36Sopenharmony_ci value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index)); 34062306a36Sopenharmony_ci value &= ~MASTER_ENABLE; 34162306a36Sopenharmony_ci ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index)); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* ensure sleepwalk logics are in low power mode */ 34462306a36Sopenharmony_ci value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index)); 34562306a36Sopenharmony_ci value |= MASTER_CFG_SEL; 34662306a36Sopenharmony_ci ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index)); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci /* set debounce time */ 34962306a36Sopenharmony_ci value = ao_readl(priv, XUSB_AO_USB_DEBOUNCE_DEL); 35062306a36Sopenharmony_ci value &= ~UTMIP_LINE_DEB_CNT(~0); 35162306a36Sopenharmony_ci value |= UTMIP_LINE_DEB_CNT(1); 35262306a36Sopenharmony_ci ao_writel(priv, value, XUSB_AO_USB_DEBOUNCE_DEL); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* ensure fake events of sleepwalk logic are desiabled */ 35562306a36Sopenharmony_ci value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index)); 35662306a36Sopenharmony_ci value &= ~(FAKE_USBOP_VAL | FAKE_USBON_VAL | 35762306a36Sopenharmony_ci FAKE_USBOP_EN | FAKE_USBON_EN); 35862306a36Sopenharmony_ci ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index)); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* ensure wake events of sleepwalk logic are not latched */ 36162306a36Sopenharmony_ci value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index)); 36262306a36Sopenharmony_ci value &= ~LINE_WAKEUP_EN; 36362306a36Sopenharmony_ci ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index)); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* disable wake event triggers of sleepwalk logic */ 36662306a36Sopenharmony_ci value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index)); 36762306a36Sopenharmony_ci value &= ~WAKE_VAL(~0); 36862306a36Sopenharmony_ci value |= WAKE_VAL_NONE; 36962306a36Sopenharmony_ci ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index)); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci /* power down the line state detectors of the pad */ 37262306a36Sopenharmony_ci value = ao_readl(priv, XUSB_AO_UTMIP_PAD_CFG(index)); 37362306a36Sopenharmony_ci value |= (USBOP_VAL_PD | USBON_VAL_PD); 37462306a36Sopenharmony_ci ao_writel(priv, value, XUSB_AO_UTMIP_PAD_CFG(index)); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* save state per speed */ 37762306a36Sopenharmony_ci value = ao_readl(priv, XUSB_AO_UTMIP_SAVED_STATE(index)); 37862306a36Sopenharmony_ci value &= ~SPEED(~0); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci switch (speed) { 38162306a36Sopenharmony_ci case USB_SPEED_HIGH: 38262306a36Sopenharmony_ci value |= UTMI_HS; 38362306a36Sopenharmony_ci break; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci case USB_SPEED_FULL: 38662306a36Sopenharmony_ci value |= UTMI_FS; 38762306a36Sopenharmony_ci break; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci case USB_SPEED_LOW: 39062306a36Sopenharmony_ci value |= UTMI_LS; 39162306a36Sopenharmony_ci break; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci default: 39462306a36Sopenharmony_ci value |= UTMI_RST; 39562306a36Sopenharmony_ci break; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci ao_writel(priv, value, XUSB_AO_UTMIP_SAVED_STATE(index)); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* enable the trigger of the sleepwalk logic */ 40162306a36Sopenharmony_ci value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index)); 40262306a36Sopenharmony_ci value |= LINEVAL_WALK_EN; 40362306a36Sopenharmony_ci value &= ~WAKE_WALK_EN; 40462306a36Sopenharmony_ci ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index)); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* reset the walk pointer and clear the alarm of the sleepwalk logic, 40762306a36Sopenharmony_ci * as well as capture the configuration of the USB2.0 pad 40862306a36Sopenharmony_ci */ 40962306a36Sopenharmony_ci value = ao_readl(priv, XUSB_AO_UTMIP_TRIGGERS(index)); 41062306a36Sopenharmony_ci value |= (CLR_WALK_PTR | CLR_WAKE_ALARM | CAP_CFG); 41162306a36Sopenharmony_ci ao_writel(priv, value, XUSB_AO_UTMIP_TRIGGERS(index)); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci /* setup the pull-ups and pull-downs of the signals during the four 41462306a36Sopenharmony_ci * stages of sleepwalk. 41562306a36Sopenharmony_ci * if device is connected, program sleepwalk logic to maintain a J and 41662306a36Sopenharmony_ci * keep driving K upon seeing remote wake. 41762306a36Sopenharmony_ci */ 41862306a36Sopenharmony_ci value = USBOP_RPD_A | USBOP_RPD_B | USBOP_RPD_C | USBOP_RPD_D; 41962306a36Sopenharmony_ci value |= USBON_RPD_A | USBON_RPD_B | USBON_RPD_C | USBON_RPD_D; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci switch (speed) { 42262306a36Sopenharmony_ci case USB_SPEED_HIGH: 42362306a36Sopenharmony_ci case USB_SPEED_FULL: 42462306a36Sopenharmony_ci /* J state: D+/D- = high/low, K state: D+/D- = low/high */ 42562306a36Sopenharmony_ci value |= HIGHZ_A; 42662306a36Sopenharmony_ci value |= AP_A; 42762306a36Sopenharmony_ci value |= AN_B | AN_C | AN_D; 42862306a36Sopenharmony_ci if (padctl->soc->supports_lp_cfg_en) 42962306a36Sopenharmony_ci value |= MASTER_ENABLE_B_C_D; 43062306a36Sopenharmony_ci break; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci case USB_SPEED_LOW: 43362306a36Sopenharmony_ci /* J state: D+/D- = low/high, K state: D+/D- = high/low */ 43462306a36Sopenharmony_ci value |= HIGHZ_A; 43562306a36Sopenharmony_ci value |= AN_A; 43662306a36Sopenharmony_ci value |= AP_B | AP_C | AP_D; 43762306a36Sopenharmony_ci if (padctl->soc->supports_lp_cfg_en) 43862306a36Sopenharmony_ci value |= MASTER_ENABLE_B_C_D; 43962306a36Sopenharmony_ci break; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci default: 44262306a36Sopenharmony_ci value |= HIGHZ_A | HIGHZ_B | HIGHZ_C | HIGHZ_D; 44362306a36Sopenharmony_ci break; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK(index)); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci /* power up the line state detectors of the pad */ 44962306a36Sopenharmony_ci value = ao_readl(priv, XUSB_AO_UTMIP_PAD_CFG(index)); 45062306a36Sopenharmony_ci value &= ~(USBOP_VAL_PD | USBON_VAL_PD); 45162306a36Sopenharmony_ci ao_writel(priv, value, XUSB_AO_UTMIP_PAD_CFG(index)); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci usleep_range(150, 200); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci /* switch the electric control of the USB2.0 pad to XUSB_AO */ 45662306a36Sopenharmony_ci value = ao_readl(priv, XUSB_AO_UTMIP_PAD_CFG(index)); 45762306a36Sopenharmony_ci value |= FSLS_USE_XUSB_AO | TRK_CTRL_USE_XUSB_AO | RPD_CTRL_USE_XUSB_AO | 45862306a36Sopenharmony_ci RPU_USE_XUSB_AO | VREG_USE_XUSB_AO; 45962306a36Sopenharmony_ci ao_writel(priv, value, XUSB_AO_UTMIP_PAD_CFG(index)); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci /* set the wake signaling trigger events */ 46262306a36Sopenharmony_ci value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index)); 46362306a36Sopenharmony_ci value &= ~WAKE_VAL(~0); 46462306a36Sopenharmony_ci value |= WAKE_VAL_ANY; 46562306a36Sopenharmony_ci ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index)); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci /* enable the wake detection */ 46862306a36Sopenharmony_ci value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index)); 46962306a36Sopenharmony_ci value |= MASTER_ENABLE | LINE_WAKEUP_EN; 47062306a36Sopenharmony_ci ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index)); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci mutex_unlock(&padctl->lock); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci return 0; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic int tegra186_utmi_disable_phy_sleepwalk(struct tegra_xusb_lane *lane) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci struct tegra_xusb_padctl *padctl = lane->pad->padctl; 48062306a36Sopenharmony_ci struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl); 48162306a36Sopenharmony_ci unsigned int index = lane->index; 48262306a36Sopenharmony_ci u32 value; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci mutex_lock(&padctl->lock); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci /* disable the wake detection */ 48762306a36Sopenharmony_ci value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index)); 48862306a36Sopenharmony_ci value &= ~(MASTER_ENABLE | LINE_WAKEUP_EN); 48962306a36Sopenharmony_ci ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index)); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* switch the electric control of the USB2.0 pad to XUSB vcore logic */ 49262306a36Sopenharmony_ci value = ao_readl(priv, XUSB_AO_UTMIP_PAD_CFG(index)); 49362306a36Sopenharmony_ci value &= ~(FSLS_USE_XUSB_AO | TRK_CTRL_USE_XUSB_AO | RPD_CTRL_USE_XUSB_AO | 49462306a36Sopenharmony_ci RPU_USE_XUSB_AO | VREG_USE_XUSB_AO); 49562306a36Sopenharmony_ci ao_writel(priv, value, XUSB_AO_UTMIP_PAD_CFG(index)); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci /* disable wake event triggers of sleepwalk logic */ 49862306a36Sopenharmony_ci value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index)); 49962306a36Sopenharmony_ci value &= ~WAKE_VAL(~0); 50062306a36Sopenharmony_ci value |= WAKE_VAL_NONE; 50162306a36Sopenharmony_ci ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index)); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci if (padctl->soc->supports_lp_cfg_en) { 50462306a36Sopenharmony_ci /* disable the four stages of sleepwalk */ 50562306a36Sopenharmony_ci value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK(index)); 50662306a36Sopenharmony_ci value &= ~(MASTER_ENABLE_A | MASTER_ENABLE_B_C_D); 50762306a36Sopenharmony_ci ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK(index)); 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci /* power down the line state detectors of the port */ 51162306a36Sopenharmony_ci value = ao_readl(priv, XUSB_AO_UTMIP_PAD_CFG(index)); 51262306a36Sopenharmony_ci value |= USBOP_VAL_PD | USBON_VAL_PD; 51362306a36Sopenharmony_ci ao_writel(priv, value, XUSB_AO_UTMIP_PAD_CFG(index)); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci /* clear alarm of the sleepwalk logic */ 51662306a36Sopenharmony_ci value = ao_readl(priv, XUSB_AO_UTMIP_TRIGGERS(index)); 51762306a36Sopenharmony_ci value |= CLR_WAKE_ALARM; 51862306a36Sopenharmony_ci ao_writel(priv, value, XUSB_AO_UTMIP_TRIGGERS(index)); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci mutex_unlock(&padctl->lock); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci return 0; 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cistatic int tegra186_utmi_enable_phy_wake(struct tegra_xusb_lane *lane) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci struct tegra_xusb_padctl *padctl = lane->pad->padctl; 52862306a36Sopenharmony_ci unsigned int index = lane->index; 52962306a36Sopenharmony_ci u32 value; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci mutex_lock(&padctl->lock); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); 53462306a36Sopenharmony_ci value &= ~ALL_WAKE_EVENTS; 53562306a36Sopenharmony_ci value |= USB2_PORT_WAKEUP_EVENT(index); 53662306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci usleep_range(10, 20); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); 54162306a36Sopenharmony_ci value &= ~ALL_WAKE_EVENTS; 54262306a36Sopenharmony_ci value |= USB2_PORT_WAKE_INTERRUPT_ENABLE(index); 54362306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci mutex_unlock(&padctl->lock); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci return 0; 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_cistatic int tegra186_utmi_disable_phy_wake(struct tegra_xusb_lane *lane) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci struct tegra_xusb_padctl *padctl = lane->pad->padctl; 55362306a36Sopenharmony_ci unsigned int index = lane->index; 55462306a36Sopenharmony_ci u32 value; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci mutex_lock(&padctl->lock); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); 55962306a36Sopenharmony_ci value &= ~ALL_WAKE_EVENTS; 56062306a36Sopenharmony_ci value &= ~USB2_PORT_WAKE_INTERRUPT_ENABLE(index); 56162306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci usleep_range(10, 20); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); 56662306a36Sopenharmony_ci value &= ~ALL_WAKE_EVENTS; 56762306a36Sopenharmony_ci value |= USB2_PORT_WAKEUP_EVENT(index); 56862306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci mutex_unlock(&padctl->lock); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci return 0; 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_cistatic bool tegra186_utmi_phy_remote_wake_detected(struct tegra_xusb_lane *lane) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci struct tegra_xusb_padctl *padctl = lane->pad->padctl; 57862306a36Sopenharmony_ci unsigned int index = lane->index; 57962306a36Sopenharmony_ci u32 value; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); 58262306a36Sopenharmony_ci if ((value & USB2_PORT_WAKE_INTERRUPT_ENABLE(index)) && 58362306a36Sopenharmony_ci (value & USB2_PORT_WAKEUP_EVENT(index))) 58462306a36Sopenharmony_ci return true; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci return false; 58762306a36Sopenharmony_ci} 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_cistatic const struct tegra_xusb_lane_ops tegra186_usb2_lane_ops = { 59062306a36Sopenharmony_ci .probe = tegra186_usb2_lane_probe, 59162306a36Sopenharmony_ci .remove = tegra186_usb2_lane_remove, 59262306a36Sopenharmony_ci .enable_phy_sleepwalk = tegra186_utmi_enable_phy_sleepwalk, 59362306a36Sopenharmony_ci .disable_phy_sleepwalk = tegra186_utmi_disable_phy_sleepwalk, 59462306a36Sopenharmony_ci .enable_phy_wake = tegra186_utmi_enable_phy_wake, 59562306a36Sopenharmony_ci .disable_phy_wake = tegra186_utmi_disable_phy_wake, 59662306a36Sopenharmony_ci .remote_wake_detected = tegra186_utmi_phy_remote_wake_detected, 59762306a36Sopenharmony_ci}; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic void tegra186_utmi_bias_pad_power_on(struct tegra_xusb_padctl *padctl) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl); 60262306a36Sopenharmony_ci struct device *dev = padctl->dev; 60362306a36Sopenharmony_ci u32 value; 60462306a36Sopenharmony_ci int err; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci mutex_lock(&padctl->lock); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci if (priv->bias_pad_enable++ > 0) { 60962306a36Sopenharmony_ci mutex_unlock(&padctl->lock); 61062306a36Sopenharmony_ci return; 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci err = clk_prepare_enable(priv->usb2_trk_clk); 61462306a36Sopenharmony_ci if (err < 0) 61562306a36Sopenharmony_ci dev_warn(dev, "failed to enable USB2 trk clock: %d\n", err); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); 61862306a36Sopenharmony_ci value &= ~USB2_TRK_START_TIMER(~0); 61962306a36Sopenharmony_ci value |= USB2_TRK_START_TIMER(0x1e); 62062306a36Sopenharmony_ci value &= ~USB2_TRK_DONE_RESET_TIMER(~0); 62162306a36Sopenharmony_ci value |= USB2_TRK_DONE_RESET_TIMER(0xa); 62262306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); 62562306a36Sopenharmony_ci value &= ~BIAS_PAD_PD; 62662306a36Sopenharmony_ci value &= ~HS_SQUELCH_LEVEL(~0); 62762306a36Sopenharmony_ci value |= HS_SQUELCH_LEVEL(priv->calib.hs_squelch); 62862306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci udelay(1); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); 63362306a36Sopenharmony_ci value &= ~USB2_PD_TRK; 63462306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (padctl->soc->poll_trk_completed) { 63762306a36Sopenharmony_ci err = padctl_readl_poll(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1, 63862306a36Sopenharmony_ci USB2_TRK_COMPLETED, USB2_TRK_COMPLETED, 100); 63962306a36Sopenharmony_ci if (err) { 64062306a36Sopenharmony_ci /* The failure with polling on trk complete will not 64162306a36Sopenharmony_ci * cause the failure of powering on the bias pad. 64262306a36Sopenharmony_ci */ 64362306a36Sopenharmony_ci dev_warn(dev, "failed to poll USB2 trk completed: %d\n", err); 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); 64762306a36Sopenharmony_ci value |= USB2_TRK_COMPLETED; 64862306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); 64962306a36Sopenharmony_ci } else { 65062306a36Sopenharmony_ci udelay(100); 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci if (padctl->soc->trk_hw_mode) { 65462306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL2); 65562306a36Sopenharmony_ci value |= USB2_TRK_HW_MODE; 65662306a36Sopenharmony_ci value &= ~CYA_TRK_CODE_UPDATE_ON_IDLE; 65762306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL2); 65862306a36Sopenharmony_ci } else { 65962306a36Sopenharmony_ci clk_disable_unprepare(priv->usb2_trk_clk); 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci mutex_unlock(&padctl->lock); 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_cistatic void tegra186_utmi_bias_pad_power_off(struct tegra_xusb_padctl *padctl) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl); 66862306a36Sopenharmony_ci u32 value; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci mutex_lock(&padctl->lock); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (WARN_ON(priv->bias_pad_enable == 0)) { 67362306a36Sopenharmony_ci mutex_unlock(&padctl->lock); 67462306a36Sopenharmony_ci return; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci if (--priv->bias_pad_enable > 0) { 67862306a36Sopenharmony_ci mutex_unlock(&padctl->lock); 67962306a36Sopenharmony_ci return; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); 68362306a36Sopenharmony_ci value |= USB2_PD_TRK; 68462306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (padctl->soc->trk_hw_mode) { 68762306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL2); 68862306a36Sopenharmony_ci value &= ~USB2_TRK_HW_MODE; 68962306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL2); 69062306a36Sopenharmony_ci clk_disable_unprepare(priv->usb2_trk_clk); 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci mutex_unlock(&padctl->lock); 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_cistatic void tegra186_utmi_pad_power_on(struct phy *phy) 69762306a36Sopenharmony_ci{ 69862306a36Sopenharmony_ci struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 69962306a36Sopenharmony_ci struct tegra_xusb_padctl *padctl = lane->pad->padctl; 70062306a36Sopenharmony_ci struct tegra_xusb_usb2_port *port; 70162306a36Sopenharmony_ci struct device *dev = padctl->dev; 70262306a36Sopenharmony_ci unsigned int index = lane->index; 70362306a36Sopenharmony_ci u32 value; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci if (!phy) 70662306a36Sopenharmony_ci return; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci port = tegra_xusb_find_usb2_port(padctl, index); 70962306a36Sopenharmony_ci if (!port) { 71062306a36Sopenharmony_ci dev_err(dev, "no port found for USB2 lane %u\n", index); 71162306a36Sopenharmony_ci return; 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci dev_dbg(dev, "power on UTMI pad %u\n", index); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci tegra186_utmi_bias_pad_power_on(padctl); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci udelay(2); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); 72162306a36Sopenharmony_ci value &= ~USB2_OTG_PD; 72262306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); 72562306a36Sopenharmony_ci value &= ~USB2_OTG_PD_DR; 72662306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); 72762306a36Sopenharmony_ci} 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_cistatic void tegra186_utmi_pad_power_down(struct phy *phy) 73062306a36Sopenharmony_ci{ 73162306a36Sopenharmony_ci struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 73262306a36Sopenharmony_ci struct tegra_xusb_padctl *padctl = lane->pad->padctl; 73362306a36Sopenharmony_ci unsigned int index = lane->index; 73462306a36Sopenharmony_ci u32 value; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if (!phy) 73762306a36Sopenharmony_ci return; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci dev_dbg(padctl->dev, "power down UTMI pad %u\n", index); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); 74262306a36Sopenharmony_ci value |= USB2_OTG_PD; 74362306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); 74662306a36Sopenharmony_ci value |= USB2_OTG_PD_DR; 74762306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci udelay(2); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci tegra186_utmi_bias_pad_power_off(padctl); 75262306a36Sopenharmony_ci} 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_cistatic int tegra186_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl, 75562306a36Sopenharmony_ci bool status) 75662306a36Sopenharmony_ci{ 75762306a36Sopenharmony_ci u32 value; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear"); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci value = padctl_readl(padctl, USB2_VBUS_ID); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (status) { 76462306a36Sopenharmony_ci value |= VBUS_OVERRIDE; 76562306a36Sopenharmony_ci value &= ~ID_OVERRIDE(~0); 76662306a36Sopenharmony_ci value |= ID_OVERRIDE_FLOATING; 76762306a36Sopenharmony_ci } else { 76862306a36Sopenharmony_ci value &= ~VBUS_OVERRIDE; 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci padctl_writel(padctl, value, USB2_VBUS_ID); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci return 0; 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cistatic int tegra186_xusb_padctl_id_override(struct tegra_xusb_padctl *padctl, 77762306a36Sopenharmony_ci bool status) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci u32 value; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci dev_dbg(padctl->dev, "%s id override\n", status ? "set" : "clear"); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci value = padctl_readl(padctl, USB2_VBUS_ID); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci if (status) { 78662306a36Sopenharmony_ci if (value & VBUS_OVERRIDE) { 78762306a36Sopenharmony_ci value &= ~VBUS_OVERRIDE; 78862306a36Sopenharmony_ci padctl_writel(padctl, value, USB2_VBUS_ID); 78962306a36Sopenharmony_ci usleep_range(1000, 2000); 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci value = padctl_readl(padctl, USB2_VBUS_ID); 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci value &= ~ID_OVERRIDE(~0); 79562306a36Sopenharmony_ci value |= ID_OVERRIDE_GROUNDED; 79662306a36Sopenharmony_ci } else { 79762306a36Sopenharmony_ci value &= ~ID_OVERRIDE(~0); 79862306a36Sopenharmony_ci value |= ID_OVERRIDE_FLOATING; 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci padctl_writel(padctl, value, USB2_VBUS_ID); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci return 0; 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_cistatic int tegra186_utmi_phy_set_mode(struct phy *phy, enum phy_mode mode, 80762306a36Sopenharmony_ci int submode) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 81062306a36Sopenharmony_ci struct tegra_xusb_padctl *padctl = lane->pad->padctl; 81162306a36Sopenharmony_ci struct tegra_xusb_usb2_port *port = tegra_xusb_find_usb2_port(padctl, 81262306a36Sopenharmony_ci lane->index); 81362306a36Sopenharmony_ci int err = 0; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci mutex_lock(&padctl->lock); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci dev_dbg(&port->base.dev, "%s: mode %d", __func__, mode); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci if (mode == PHY_MODE_USB_OTG) { 82062306a36Sopenharmony_ci if (submode == USB_ROLE_HOST) { 82162306a36Sopenharmony_ci tegra186_xusb_padctl_id_override(padctl, true); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci err = regulator_enable(port->supply); 82462306a36Sopenharmony_ci } else if (submode == USB_ROLE_DEVICE) { 82562306a36Sopenharmony_ci tegra186_xusb_padctl_vbus_override(padctl, true); 82662306a36Sopenharmony_ci } else if (submode == USB_ROLE_NONE) { 82762306a36Sopenharmony_ci /* 82862306a36Sopenharmony_ci * When port is peripheral only or role transitions to 82962306a36Sopenharmony_ci * USB_ROLE_NONE from USB_ROLE_DEVICE, regulator is not 83062306a36Sopenharmony_ci * enabled. 83162306a36Sopenharmony_ci */ 83262306a36Sopenharmony_ci if (regulator_is_enabled(port->supply)) 83362306a36Sopenharmony_ci regulator_disable(port->supply); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci tegra186_xusb_padctl_id_override(padctl, false); 83662306a36Sopenharmony_ci tegra186_xusb_padctl_vbus_override(padctl, false); 83762306a36Sopenharmony_ci } 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci mutex_unlock(&padctl->lock); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci return err; 84362306a36Sopenharmony_ci} 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_cistatic int tegra186_utmi_phy_power_on(struct phy *phy) 84662306a36Sopenharmony_ci{ 84762306a36Sopenharmony_ci struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 84862306a36Sopenharmony_ci struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane); 84962306a36Sopenharmony_ci struct tegra_xusb_padctl *padctl = lane->pad->padctl; 85062306a36Sopenharmony_ci struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl); 85162306a36Sopenharmony_ci struct tegra_xusb_usb2_port *port; 85262306a36Sopenharmony_ci unsigned int index = lane->index; 85362306a36Sopenharmony_ci struct device *dev = padctl->dev; 85462306a36Sopenharmony_ci u32 value; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci port = tegra_xusb_find_usb2_port(padctl, index); 85762306a36Sopenharmony_ci if (!port) { 85862306a36Sopenharmony_ci dev_err(dev, "no port found for USB2 lane %u\n", index); 85962306a36Sopenharmony_ci return -ENODEV; 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX); 86362306a36Sopenharmony_ci value &= ~(USB2_PORT_MASK << USB2_PORT_SHIFT(index)); 86462306a36Sopenharmony_ci value |= (PORT_XUSB << USB2_PORT_SHIFT(index)); 86562306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP); 86862306a36Sopenharmony_ci value &= ~(PORT_CAP_MASK << PORTX_CAP_SHIFT(index)); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci if (port->mode == USB_DR_MODE_UNKNOWN) 87162306a36Sopenharmony_ci value |= (PORT_CAP_DISABLED << PORTX_CAP_SHIFT(index)); 87262306a36Sopenharmony_ci else if (port->mode == USB_DR_MODE_PERIPHERAL) 87362306a36Sopenharmony_ci value |= (PORT_CAP_DEVICE << PORTX_CAP_SHIFT(index)); 87462306a36Sopenharmony_ci else if (port->mode == USB_DR_MODE_HOST) 87562306a36Sopenharmony_ci value |= (PORT_CAP_HOST << PORTX_CAP_SHIFT(index)); 87662306a36Sopenharmony_ci else if (port->mode == USB_DR_MODE_OTG) 87762306a36Sopenharmony_ci value |= (PORT_CAP_OTG << PORTX_CAP_SHIFT(index)); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_USB2_PORT_CAP); 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); 88262306a36Sopenharmony_ci value &= ~USB2_OTG_PD_ZI; 88362306a36Sopenharmony_ci value |= TERM_SEL; 88462306a36Sopenharmony_ci value &= ~HS_CURR_LEVEL(~0); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci if (usb2->hs_curr_level_offset) { 88762306a36Sopenharmony_ci int hs_current_level; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci hs_current_level = (int)priv->calib.hs_curr_level[index] + 89062306a36Sopenharmony_ci usb2->hs_curr_level_offset; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci if (hs_current_level < 0) 89362306a36Sopenharmony_ci hs_current_level = 0; 89462306a36Sopenharmony_ci if (hs_current_level > 0x3f) 89562306a36Sopenharmony_ci hs_current_level = 0x3f; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci value |= HS_CURR_LEVEL(hs_current_level); 89862306a36Sopenharmony_ci } else { 89962306a36Sopenharmony_ci value |= HS_CURR_LEVEL(priv->calib.hs_curr_level[index]); 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); 90562306a36Sopenharmony_ci value &= ~TERM_RANGE_ADJ(~0); 90662306a36Sopenharmony_ci value |= TERM_RANGE_ADJ(priv->calib.hs_term_range_adj); 90762306a36Sopenharmony_ci value &= ~RPD_CTRL(~0); 90862306a36Sopenharmony_ci value |= RPD_CTRL(priv->calib.rpd_ctrl); 90962306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci tegra186_utmi_pad_power_on(phy); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci return 0; 91462306a36Sopenharmony_ci} 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_cistatic int tegra186_utmi_phy_power_off(struct phy *phy) 91762306a36Sopenharmony_ci{ 91862306a36Sopenharmony_ci tegra186_utmi_pad_power_down(phy); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci return 0; 92162306a36Sopenharmony_ci} 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_cistatic int tegra186_utmi_phy_init(struct phy *phy) 92462306a36Sopenharmony_ci{ 92562306a36Sopenharmony_ci struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 92662306a36Sopenharmony_ci struct tegra_xusb_padctl *padctl = lane->pad->padctl; 92762306a36Sopenharmony_ci struct tegra_xusb_usb2_port *port; 92862306a36Sopenharmony_ci unsigned int index = lane->index; 92962306a36Sopenharmony_ci struct device *dev = padctl->dev; 93062306a36Sopenharmony_ci int err; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci port = tegra_xusb_find_usb2_port(padctl, index); 93362306a36Sopenharmony_ci if (!port) { 93462306a36Sopenharmony_ci dev_err(dev, "no port found for USB2 lane %u\n", index); 93562306a36Sopenharmony_ci return -ENODEV; 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci if (port->supply && port->mode == USB_DR_MODE_HOST) { 93962306a36Sopenharmony_ci err = regulator_enable(port->supply); 94062306a36Sopenharmony_ci if (err) { 94162306a36Sopenharmony_ci dev_err(dev, "failed to enable port %u VBUS: %d\n", 94262306a36Sopenharmony_ci index, err); 94362306a36Sopenharmony_ci return err; 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci } 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci return 0; 94862306a36Sopenharmony_ci} 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_cistatic int tegra186_utmi_phy_exit(struct phy *phy) 95162306a36Sopenharmony_ci{ 95262306a36Sopenharmony_ci struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 95362306a36Sopenharmony_ci struct tegra_xusb_padctl *padctl = lane->pad->padctl; 95462306a36Sopenharmony_ci struct tegra_xusb_usb2_port *port; 95562306a36Sopenharmony_ci unsigned int index = lane->index; 95662306a36Sopenharmony_ci struct device *dev = padctl->dev; 95762306a36Sopenharmony_ci int err; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci port = tegra_xusb_find_usb2_port(padctl, index); 96062306a36Sopenharmony_ci if (!port) { 96162306a36Sopenharmony_ci dev_err(dev, "no port found for USB2 lane %u\n", index); 96262306a36Sopenharmony_ci return -ENODEV; 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci if (port->supply && port->mode == USB_DR_MODE_HOST) { 96662306a36Sopenharmony_ci err = regulator_disable(port->supply); 96762306a36Sopenharmony_ci if (err) { 96862306a36Sopenharmony_ci dev_err(dev, "failed to disable port %u VBUS: %d\n", 96962306a36Sopenharmony_ci index, err); 97062306a36Sopenharmony_ci return err; 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci return 0; 97562306a36Sopenharmony_ci} 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_cistatic const struct phy_ops utmi_phy_ops = { 97862306a36Sopenharmony_ci .init = tegra186_utmi_phy_init, 97962306a36Sopenharmony_ci .exit = tegra186_utmi_phy_exit, 98062306a36Sopenharmony_ci .power_on = tegra186_utmi_phy_power_on, 98162306a36Sopenharmony_ci .power_off = tegra186_utmi_phy_power_off, 98262306a36Sopenharmony_ci .set_mode = tegra186_utmi_phy_set_mode, 98362306a36Sopenharmony_ci .owner = THIS_MODULE, 98462306a36Sopenharmony_ci}; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_cistatic struct tegra_xusb_pad * 98762306a36Sopenharmony_citegra186_usb2_pad_probe(struct tegra_xusb_padctl *padctl, 98862306a36Sopenharmony_ci const struct tegra_xusb_pad_soc *soc, 98962306a36Sopenharmony_ci struct device_node *np) 99062306a36Sopenharmony_ci{ 99162306a36Sopenharmony_ci struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl); 99262306a36Sopenharmony_ci struct tegra_xusb_usb2_pad *usb2; 99362306a36Sopenharmony_ci struct tegra_xusb_pad *pad; 99462306a36Sopenharmony_ci int err; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL); 99762306a36Sopenharmony_ci if (!usb2) 99862306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci pad = &usb2->base; 100162306a36Sopenharmony_ci pad->ops = &tegra186_usb2_lane_ops; 100262306a36Sopenharmony_ci pad->soc = soc; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci err = tegra_xusb_pad_init(pad, padctl, np); 100562306a36Sopenharmony_ci if (err < 0) { 100662306a36Sopenharmony_ci kfree(usb2); 100762306a36Sopenharmony_ci goto out; 100862306a36Sopenharmony_ci } 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci priv->usb2_trk_clk = devm_clk_get(&pad->dev, "trk"); 101162306a36Sopenharmony_ci if (IS_ERR(priv->usb2_trk_clk)) { 101262306a36Sopenharmony_ci err = PTR_ERR(priv->usb2_trk_clk); 101362306a36Sopenharmony_ci dev_dbg(&pad->dev, "failed to get usb2 trk clock: %d\n", err); 101462306a36Sopenharmony_ci goto unregister; 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci err = tegra_xusb_pad_register(pad, &utmi_phy_ops); 101862306a36Sopenharmony_ci if (err < 0) 101962306a36Sopenharmony_ci goto unregister; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci dev_set_drvdata(&pad->dev, pad); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci return pad; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ciunregister: 102662306a36Sopenharmony_ci device_unregister(&pad->dev); 102762306a36Sopenharmony_ciout: 102862306a36Sopenharmony_ci return ERR_PTR(err); 102962306a36Sopenharmony_ci} 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_cistatic void tegra186_usb2_pad_remove(struct tegra_xusb_pad *pad) 103262306a36Sopenharmony_ci{ 103362306a36Sopenharmony_ci struct tegra_xusb_usb2_pad *usb2 = to_usb2_pad(pad); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci kfree(usb2); 103662306a36Sopenharmony_ci} 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_cistatic const struct tegra_xusb_pad_ops tegra186_usb2_pad_ops = { 103962306a36Sopenharmony_ci .probe = tegra186_usb2_pad_probe, 104062306a36Sopenharmony_ci .remove = tegra186_usb2_pad_remove, 104162306a36Sopenharmony_ci}; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_cistatic const char * const tegra186_usb2_functions[] = { 104462306a36Sopenharmony_ci "xusb", 104562306a36Sopenharmony_ci}; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_cistatic int tegra186_usb2_port_enable(struct tegra_xusb_port *port) 104862306a36Sopenharmony_ci{ 104962306a36Sopenharmony_ci return 0; 105062306a36Sopenharmony_ci} 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_cistatic void tegra186_usb2_port_disable(struct tegra_xusb_port *port) 105362306a36Sopenharmony_ci{ 105462306a36Sopenharmony_ci} 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_cistatic struct tegra_xusb_lane * 105762306a36Sopenharmony_citegra186_usb2_port_map(struct tegra_xusb_port *port) 105862306a36Sopenharmony_ci{ 105962306a36Sopenharmony_ci return tegra_xusb_find_lane(port->padctl, "usb2", port->index); 106062306a36Sopenharmony_ci} 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_cistatic const struct tegra_xusb_port_ops tegra186_usb2_port_ops = { 106362306a36Sopenharmony_ci .release = tegra_xusb_usb2_port_release, 106462306a36Sopenharmony_ci .remove = tegra_xusb_usb2_port_remove, 106562306a36Sopenharmony_ci .enable = tegra186_usb2_port_enable, 106662306a36Sopenharmony_ci .disable = tegra186_usb2_port_disable, 106762306a36Sopenharmony_ci .map = tegra186_usb2_port_map, 106862306a36Sopenharmony_ci}; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci/* SuperSpeed PHY support */ 107162306a36Sopenharmony_cistatic struct tegra_xusb_lane * 107262306a36Sopenharmony_citegra186_usb3_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, 107362306a36Sopenharmony_ci unsigned int index) 107462306a36Sopenharmony_ci{ 107562306a36Sopenharmony_ci struct tegra_xusb_usb3_lane *usb3; 107662306a36Sopenharmony_ci int err; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci usb3 = kzalloc(sizeof(*usb3), GFP_KERNEL); 107962306a36Sopenharmony_ci if (!usb3) 108062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci INIT_LIST_HEAD(&usb3->base.list); 108362306a36Sopenharmony_ci usb3->base.soc = &pad->soc->lanes[index]; 108462306a36Sopenharmony_ci usb3->base.index = index; 108562306a36Sopenharmony_ci usb3->base.pad = pad; 108662306a36Sopenharmony_ci usb3->base.np = np; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci err = tegra_xusb_lane_parse_dt(&usb3->base, np); 108962306a36Sopenharmony_ci if (err < 0) { 109062306a36Sopenharmony_ci kfree(usb3); 109162306a36Sopenharmony_ci return ERR_PTR(err); 109262306a36Sopenharmony_ci } 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci return &usb3->base; 109562306a36Sopenharmony_ci} 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_cistatic void tegra186_usb3_lane_remove(struct tegra_xusb_lane *lane) 109862306a36Sopenharmony_ci{ 109962306a36Sopenharmony_ci struct tegra_xusb_usb3_lane *usb3 = to_usb3_lane(lane); 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci kfree(usb3); 110262306a36Sopenharmony_ci} 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_cistatic int tegra186_usb3_enable_phy_sleepwalk(struct tegra_xusb_lane *lane, 110562306a36Sopenharmony_ci enum usb_device_speed speed) 110662306a36Sopenharmony_ci{ 110762306a36Sopenharmony_ci struct tegra_xusb_padctl *padctl = lane->pad->padctl; 110862306a36Sopenharmony_ci unsigned int index = lane->index; 110962306a36Sopenharmony_ci u32 value; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci mutex_lock(&padctl->lock); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1); 111462306a36Sopenharmony_ci value |= SSPX_ELPG_CLAMP_EN_EARLY(index); 111562306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1); 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci usleep_range(100, 200); 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1); 112062306a36Sopenharmony_ci value |= SSPX_ELPG_CLAMP_EN(index); 112162306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1); 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci usleep_range(250, 350); 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci mutex_unlock(&padctl->lock); 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci return 0; 112862306a36Sopenharmony_ci} 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_cistatic int tegra186_usb3_disable_phy_sleepwalk(struct tegra_xusb_lane *lane) 113162306a36Sopenharmony_ci{ 113262306a36Sopenharmony_ci struct tegra_xusb_padctl *padctl = lane->pad->padctl; 113362306a36Sopenharmony_ci unsigned int index = lane->index; 113462306a36Sopenharmony_ci u32 value; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci mutex_lock(&padctl->lock); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1); 113962306a36Sopenharmony_ci value &= ~SSPX_ELPG_CLAMP_EN_EARLY(index); 114062306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci usleep_range(100, 200); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1); 114562306a36Sopenharmony_ci value &= ~SSPX_ELPG_CLAMP_EN(index); 114662306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1); 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci mutex_unlock(&padctl->lock); 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci return 0; 115162306a36Sopenharmony_ci} 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_cistatic int tegra186_usb3_enable_phy_wake(struct tegra_xusb_lane *lane) 115462306a36Sopenharmony_ci{ 115562306a36Sopenharmony_ci struct tegra_xusb_padctl *padctl = lane->pad->padctl; 115662306a36Sopenharmony_ci unsigned int index = lane->index; 115762306a36Sopenharmony_ci u32 value; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci mutex_lock(&padctl->lock); 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); 116262306a36Sopenharmony_ci value &= ~ALL_WAKE_EVENTS; 116362306a36Sopenharmony_ci value |= SS_PORT_WAKEUP_EVENT(index); 116462306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci usleep_range(10, 20); 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); 116962306a36Sopenharmony_ci value &= ~ALL_WAKE_EVENTS; 117062306a36Sopenharmony_ci value |= SS_PORT_WAKE_INTERRUPT_ENABLE(index); 117162306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci mutex_unlock(&padctl->lock); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci return 0; 117662306a36Sopenharmony_ci} 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_cistatic int tegra186_usb3_disable_phy_wake(struct tegra_xusb_lane *lane) 117962306a36Sopenharmony_ci{ 118062306a36Sopenharmony_ci struct tegra_xusb_padctl *padctl = lane->pad->padctl; 118162306a36Sopenharmony_ci unsigned int index = lane->index; 118262306a36Sopenharmony_ci u32 value; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci mutex_lock(&padctl->lock); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); 118762306a36Sopenharmony_ci value &= ~ALL_WAKE_EVENTS; 118862306a36Sopenharmony_ci value &= ~SS_PORT_WAKE_INTERRUPT_ENABLE(index); 118962306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci usleep_range(10, 20); 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); 119462306a36Sopenharmony_ci value &= ~ALL_WAKE_EVENTS; 119562306a36Sopenharmony_ci value |= SS_PORT_WAKEUP_EVENT(index); 119662306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci mutex_unlock(&padctl->lock); 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci return 0; 120162306a36Sopenharmony_ci} 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_cistatic bool tegra186_usb3_phy_remote_wake_detected(struct tegra_xusb_lane *lane) 120462306a36Sopenharmony_ci{ 120562306a36Sopenharmony_ci struct tegra_xusb_padctl *padctl = lane->pad->padctl; 120662306a36Sopenharmony_ci unsigned int index = lane->index; 120762306a36Sopenharmony_ci u32 value; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); 121062306a36Sopenharmony_ci if ((value & SS_PORT_WAKE_INTERRUPT_ENABLE(index)) && (value & SS_PORT_WAKEUP_EVENT(index))) 121162306a36Sopenharmony_ci return true; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci return false; 121462306a36Sopenharmony_ci} 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_cistatic const struct tegra_xusb_lane_ops tegra186_usb3_lane_ops = { 121762306a36Sopenharmony_ci .probe = tegra186_usb3_lane_probe, 121862306a36Sopenharmony_ci .remove = tegra186_usb3_lane_remove, 121962306a36Sopenharmony_ci .enable_phy_sleepwalk = tegra186_usb3_enable_phy_sleepwalk, 122062306a36Sopenharmony_ci .disable_phy_sleepwalk = tegra186_usb3_disable_phy_sleepwalk, 122162306a36Sopenharmony_ci .enable_phy_wake = tegra186_usb3_enable_phy_wake, 122262306a36Sopenharmony_ci .disable_phy_wake = tegra186_usb3_disable_phy_wake, 122362306a36Sopenharmony_ci .remote_wake_detected = tegra186_usb3_phy_remote_wake_detected, 122462306a36Sopenharmony_ci}; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_cistatic int tegra186_usb3_port_enable(struct tegra_xusb_port *port) 122762306a36Sopenharmony_ci{ 122862306a36Sopenharmony_ci return 0; 122962306a36Sopenharmony_ci} 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_cistatic void tegra186_usb3_port_disable(struct tegra_xusb_port *port) 123262306a36Sopenharmony_ci{ 123362306a36Sopenharmony_ci} 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_cistatic struct tegra_xusb_lane * 123662306a36Sopenharmony_citegra186_usb3_port_map(struct tegra_xusb_port *port) 123762306a36Sopenharmony_ci{ 123862306a36Sopenharmony_ci return tegra_xusb_find_lane(port->padctl, "usb3", port->index); 123962306a36Sopenharmony_ci} 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_cistatic const struct tegra_xusb_port_ops tegra186_usb3_port_ops = { 124262306a36Sopenharmony_ci .release = tegra_xusb_usb3_port_release, 124362306a36Sopenharmony_ci .enable = tegra186_usb3_port_enable, 124462306a36Sopenharmony_ci .disable = tegra186_usb3_port_disable, 124562306a36Sopenharmony_ci .map = tegra186_usb3_port_map, 124662306a36Sopenharmony_ci}; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_cistatic int tegra186_usb3_phy_power_on(struct phy *phy) 124962306a36Sopenharmony_ci{ 125062306a36Sopenharmony_ci struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 125162306a36Sopenharmony_ci struct tegra_xusb_padctl *padctl = lane->pad->padctl; 125262306a36Sopenharmony_ci struct tegra_xusb_usb3_port *port; 125362306a36Sopenharmony_ci struct tegra_xusb_usb2_port *usb2; 125462306a36Sopenharmony_ci unsigned int index = lane->index; 125562306a36Sopenharmony_ci struct device *dev = padctl->dev; 125662306a36Sopenharmony_ci u32 value; 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci port = tegra_xusb_find_usb3_port(padctl, index); 125962306a36Sopenharmony_ci if (!port) { 126062306a36Sopenharmony_ci dev_err(dev, "no port found for USB3 lane %u\n", index); 126162306a36Sopenharmony_ci return -ENODEV; 126262306a36Sopenharmony_ci } 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci usb2 = tegra_xusb_find_usb2_port(padctl, port->port); 126562306a36Sopenharmony_ci if (!usb2) { 126662306a36Sopenharmony_ci dev_err(dev, "no companion port found for USB3 lane %u\n", 126762306a36Sopenharmony_ci index); 126862306a36Sopenharmony_ci return -ENODEV; 126962306a36Sopenharmony_ci } 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci mutex_lock(&padctl->lock); 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_CAP); 127462306a36Sopenharmony_ci value &= ~(PORT_CAP_MASK << PORTX_CAP_SHIFT(index)); 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci if (usb2->mode == USB_DR_MODE_UNKNOWN) 127762306a36Sopenharmony_ci value |= (PORT_CAP_DISABLED << PORTX_CAP_SHIFT(index)); 127862306a36Sopenharmony_ci else if (usb2->mode == USB_DR_MODE_PERIPHERAL) 127962306a36Sopenharmony_ci value |= (PORT_CAP_DEVICE << PORTX_CAP_SHIFT(index)); 128062306a36Sopenharmony_ci else if (usb2->mode == USB_DR_MODE_HOST) 128162306a36Sopenharmony_ci value |= (PORT_CAP_HOST << PORTX_CAP_SHIFT(index)); 128262306a36Sopenharmony_ci else if (usb2->mode == USB_DR_MODE_OTG) 128362306a36Sopenharmony_ci value |= (PORT_CAP_OTG << PORTX_CAP_SHIFT(index)); 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_CAP); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci if (padctl->soc->supports_gen2 && port->disable_gen2) { 128862306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_CFG); 128962306a36Sopenharmony_ci value &= ~(PORTX_SPEED_SUPPORT_MASK << 129062306a36Sopenharmony_ci PORTX_SPEED_SUPPORT_SHIFT(index)); 129162306a36Sopenharmony_ci value |= (PORT_SPEED_SUPPORT_GEN1 << 129262306a36Sopenharmony_ci PORTX_SPEED_SUPPORT_SHIFT(index)); 129362306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_CFG); 129462306a36Sopenharmony_ci } 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1); 129762306a36Sopenharmony_ci value &= ~SSPX_ELPG_VCORE_DOWN(index); 129862306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci usleep_range(100, 200); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1); 130362306a36Sopenharmony_ci value &= ~SSPX_ELPG_CLAMP_EN_EARLY(index); 130462306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci usleep_range(100, 200); 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1); 130962306a36Sopenharmony_ci value &= ~SSPX_ELPG_CLAMP_EN(index); 131062306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1); 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci mutex_unlock(&padctl->lock); 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci return 0; 131562306a36Sopenharmony_ci} 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_cistatic int tegra186_usb3_phy_power_off(struct phy *phy) 131862306a36Sopenharmony_ci{ 131962306a36Sopenharmony_ci struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 132062306a36Sopenharmony_ci struct tegra_xusb_padctl *padctl = lane->pad->padctl; 132162306a36Sopenharmony_ci struct tegra_xusb_usb3_port *port; 132262306a36Sopenharmony_ci unsigned int index = lane->index; 132362306a36Sopenharmony_ci struct device *dev = padctl->dev; 132462306a36Sopenharmony_ci u32 value; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci port = tegra_xusb_find_usb3_port(padctl, index); 132762306a36Sopenharmony_ci if (!port) { 132862306a36Sopenharmony_ci dev_err(dev, "no port found for USB3 lane %u\n", index); 132962306a36Sopenharmony_ci return -ENODEV; 133062306a36Sopenharmony_ci } 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci mutex_lock(&padctl->lock); 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1); 133562306a36Sopenharmony_ci value |= SSPX_ELPG_CLAMP_EN_EARLY(index); 133662306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1); 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci usleep_range(100, 200); 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1); 134162306a36Sopenharmony_ci value |= SSPX_ELPG_CLAMP_EN(index); 134262306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1); 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci usleep_range(250, 350); 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1); 134762306a36Sopenharmony_ci value |= SSPX_ELPG_VCORE_DOWN(index); 134862306a36Sopenharmony_ci padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1); 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci mutex_unlock(&padctl->lock); 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci return 0; 135362306a36Sopenharmony_ci} 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_cistatic int tegra186_usb3_phy_init(struct phy *phy) 135662306a36Sopenharmony_ci{ 135762306a36Sopenharmony_ci return 0; 135862306a36Sopenharmony_ci} 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_cistatic int tegra186_usb3_phy_exit(struct phy *phy) 136162306a36Sopenharmony_ci{ 136262306a36Sopenharmony_ci return 0; 136362306a36Sopenharmony_ci} 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_cistatic const struct phy_ops usb3_phy_ops = { 136662306a36Sopenharmony_ci .init = tegra186_usb3_phy_init, 136762306a36Sopenharmony_ci .exit = tegra186_usb3_phy_exit, 136862306a36Sopenharmony_ci .power_on = tegra186_usb3_phy_power_on, 136962306a36Sopenharmony_ci .power_off = tegra186_usb3_phy_power_off, 137062306a36Sopenharmony_ci .owner = THIS_MODULE, 137162306a36Sopenharmony_ci}; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_cistatic struct tegra_xusb_pad * 137462306a36Sopenharmony_citegra186_usb3_pad_probe(struct tegra_xusb_padctl *padctl, 137562306a36Sopenharmony_ci const struct tegra_xusb_pad_soc *soc, 137662306a36Sopenharmony_ci struct device_node *np) 137762306a36Sopenharmony_ci{ 137862306a36Sopenharmony_ci struct tegra_xusb_usb3_pad *usb3; 137962306a36Sopenharmony_ci struct tegra_xusb_pad *pad; 138062306a36Sopenharmony_ci int err; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci usb3 = kzalloc(sizeof(*usb3), GFP_KERNEL); 138362306a36Sopenharmony_ci if (!usb3) 138462306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci pad = &usb3->base; 138762306a36Sopenharmony_ci pad->ops = &tegra186_usb3_lane_ops; 138862306a36Sopenharmony_ci pad->soc = soc; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci err = tegra_xusb_pad_init(pad, padctl, np); 139162306a36Sopenharmony_ci if (err < 0) { 139262306a36Sopenharmony_ci kfree(usb3); 139362306a36Sopenharmony_ci goto out; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci err = tegra_xusb_pad_register(pad, &usb3_phy_ops); 139762306a36Sopenharmony_ci if (err < 0) 139862306a36Sopenharmony_ci goto unregister; 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci dev_set_drvdata(&pad->dev, pad); 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci return pad; 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ciunregister: 140562306a36Sopenharmony_ci device_unregister(&pad->dev); 140662306a36Sopenharmony_ciout: 140762306a36Sopenharmony_ci return ERR_PTR(err); 140862306a36Sopenharmony_ci} 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_cistatic void tegra186_usb3_pad_remove(struct tegra_xusb_pad *pad) 141162306a36Sopenharmony_ci{ 141262306a36Sopenharmony_ci struct tegra_xusb_usb2_pad *usb2 = to_usb2_pad(pad); 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci kfree(usb2); 141562306a36Sopenharmony_ci} 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_cistatic const struct tegra_xusb_pad_ops tegra186_usb3_pad_ops = { 141862306a36Sopenharmony_ci .probe = tegra186_usb3_pad_probe, 141962306a36Sopenharmony_ci .remove = tegra186_usb3_pad_remove, 142062306a36Sopenharmony_ci}; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_cistatic const char * const tegra186_usb3_functions[] = { 142362306a36Sopenharmony_ci "xusb", 142462306a36Sopenharmony_ci}; 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_cistatic int 142762306a36Sopenharmony_citegra186_xusb_read_fuse_calibration(struct tegra186_xusb_padctl *padctl) 142862306a36Sopenharmony_ci{ 142962306a36Sopenharmony_ci struct device *dev = padctl->base.dev; 143062306a36Sopenharmony_ci unsigned int i, count; 143162306a36Sopenharmony_ci u32 value, *level; 143262306a36Sopenharmony_ci int err; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci count = padctl->base.soc->ports.usb2.count; 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci level = devm_kcalloc(dev, count, sizeof(u32), GFP_KERNEL); 143762306a36Sopenharmony_ci if (!level) 143862306a36Sopenharmony_ci return -ENOMEM; 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value); 144162306a36Sopenharmony_ci if (err) 144262306a36Sopenharmony_ci return dev_err_probe(dev, err, 144362306a36Sopenharmony_ci "failed to read calibration fuse\n"); 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci dev_dbg(dev, "FUSE_USB_CALIB_0 %#x\n", value); 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci for (i = 0; i < count; i++) 144862306a36Sopenharmony_ci level[i] = (value >> HS_CURR_LEVEL_PADX_SHIFT(i)) & 144962306a36Sopenharmony_ci HS_CURR_LEVEL_PAD_MASK; 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci padctl->calib.hs_curr_level = level; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci padctl->calib.hs_squelch = (value >> HS_SQUELCH_SHIFT) & 145462306a36Sopenharmony_ci HS_SQUELCH_MASK; 145562306a36Sopenharmony_ci padctl->calib.hs_term_range_adj = (value >> HS_TERM_RANGE_ADJ_SHIFT) & 145662306a36Sopenharmony_ci HS_TERM_RANGE_ADJ_MASK; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci err = tegra_fuse_readl(TEGRA_FUSE_USB_CALIB_EXT_0, &value); 145962306a36Sopenharmony_ci if (err) { 146062306a36Sopenharmony_ci dev_err(dev, "failed to read calibration fuse: %d\n", err); 146162306a36Sopenharmony_ci return err; 146262306a36Sopenharmony_ci } 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci dev_dbg(dev, "FUSE_USB_CALIB_EXT_0 %#x\n", value); 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci padctl->calib.rpd_ctrl = (value >> RPD_CTRL_SHIFT) & RPD_CTRL_MASK; 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci return 0; 146962306a36Sopenharmony_ci} 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_cistatic struct tegra_xusb_padctl * 147262306a36Sopenharmony_citegra186_xusb_padctl_probe(struct device *dev, 147362306a36Sopenharmony_ci const struct tegra_xusb_padctl_soc *soc) 147462306a36Sopenharmony_ci{ 147562306a36Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 147662306a36Sopenharmony_ci struct tegra186_xusb_padctl *priv; 147762306a36Sopenharmony_ci struct resource *res; 147862306a36Sopenharmony_ci int err; 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 148162306a36Sopenharmony_ci if (!priv) 148262306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci priv->base.dev = dev; 148562306a36Sopenharmony_ci priv->base.soc = soc; 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ao"); 148862306a36Sopenharmony_ci priv->ao_regs = devm_ioremap_resource(dev, res); 148962306a36Sopenharmony_ci if (IS_ERR(priv->ao_regs)) 149062306a36Sopenharmony_ci return ERR_CAST(priv->ao_regs); 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci err = tegra186_xusb_read_fuse_calibration(priv); 149362306a36Sopenharmony_ci if (err < 0) 149462306a36Sopenharmony_ci return ERR_PTR(err); 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci return &priv->base; 149762306a36Sopenharmony_ci} 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_cistatic void tegra186_xusb_padctl_save(struct tegra_xusb_padctl *padctl) 150062306a36Sopenharmony_ci{ 150162306a36Sopenharmony_ci struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl); 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci priv->context.vbus_id = padctl_readl(padctl, USB2_VBUS_ID); 150462306a36Sopenharmony_ci priv->context.usb2_pad_mux = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX); 150562306a36Sopenharmony_ci priv->context.usb2_port_cap = padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP); 150662306a36Sopenharmony_ci priv->context.ss_port_cap = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_CAP); 150762306a36Sopenharmony_ci} 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_cistatic void tegra186_xusb_padctl_restore(struct tegra_xusb_padctl *padctl) 151062306a36Sopenharmony_ci{ 151162306a36Sopenharmony_ci struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl); 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci padctl_writel(padctl, priv->context.usb2_pad_mux, XUSB_PADCTL_USB2_PAD_MUX); 151462306a36Sopenharmony_ci padctl_writel(padctl, priv->context.usb2_port_cap, XUSB_PADCTL_USB2_PORT_CAP); 151562306a36Sopenharmony_ci padctl_writel(padctl, priv->context.ss_port_cap, XUSB_PADCTL_SS_PORT_CAP); 151662306a36Sopenharmony_ci padctl_writel(padctl, priv->context.vbus_id, USB2_VBUS_ID); 151762306a36Sopenharmony_ci} 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_cistatic int tegra186_xusb_padctl_suspend_noirq(struct tegra_xusb_padctl *padctl) 152062306a36Sopenharmony_ci{ 152162306a36Sopenharmony_ci tegra186_xusb_padctl_save(padctl); 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci return 0; 152462306a36Sopenharmony_ci} 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_cistatic int tegra186_xusb_padctl_resume_noirq(struct tegra_xusb_padctl *padctl) 152762306a36Sopenharmony_ci{ 152862306a36Sopenharmony_ci tegra186_xusb_padctl_restore(padctl); 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci return 0; 153162306a36Sopenharmony_ci} 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_cistatic void tegra186_xusb_padctl_remove(struct tegra_xusb_padctl *padctl) 153462306a36Sopenharmony_ci{ 153562306a36Sopenharmony_ci} 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_cistatic const struct tegra_xusb_padctl_ops tegra186_xusb_padctl_ops = { 153862306a36Sopenharmony_ci .probe = tegra186_xusb_padctl_probe, 153962306a36Sopenharmony_ci .remove = tegra186_xusb_padctl_remove, 154062306a36Sopenharmony_ci .suspend_noirq = tegra186_xusb_padctl_suspend_noirq, 154162306a36Sopenharmony_ci .resume_noirq = tegra186_xusb_padctl_resume_noirq, 154262306a36Sopenharmony_ci .vbus_override = tegra186_xusb_padctl_vbus_override, 154362306a36Sopenharmony_ci .utmi_pad_power_on = tegra186_utmi_pad_power_on, 154462306a36Sopenharmony_ci .utmi_pad_power_down = tegra186_utmi_pad_power_down, 154562306a36Sopenharmony_ci}; 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) 154862306a36Sopenharmony_cistatic const char * const tegra186_xusb_padctl_supply_names[] = { 154962306a36Sopenharmony_ci "avdd-pll-erefeut", 155062306a36Sopenharmony_ci "avdd-usb", 155162306a36Sopenharmony_ci "vclamp-usb", 155262306a36Sopenharmony_ci "vddio-hsic", 155362306a36Sopenharmony_ci}; 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_cistatic const struct tegra_xusb_lane_soc tegra186_usb2_lanes[] = { 155662306a36Sopenharmony_ci TEGRA186_LANE("usb2-0", 0, 0, 0, usb2), 155762306a36Sopenharmony_ci TEGRA186_LANE("usb2-1", 0, 0, 0, usb2), 155862306a36Sopenharmony_ci TEGRA186_LANE("usb2-2", 0, 0, 0, usb2), 155962306a36Sopenharmony_ci}; 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_cistatic const struct tegra_xusb_pad_soc tegra186_usb2_pad = { 156262306a36Sopenharmony_ci .name = "usb2", 156362306a36Sopenharmony_ci .num_lanes = ARRAY_SIZE(tegra186_usb2_lanes), 156462306a36Sopenharmony_ci .lanes = tegra186_usb2_lanes, 156562306a36Sopenharmony_ci .ops = &tegra186_usb2_pad_ops, 156662306a36Sopenharmony_ci}; 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_cistatic const struct tegra_xusb_lane_soc tegra186_usb3_lanes[] = { 156962306a36Sopenharmony_ci TEGRA186_LANE("usb3-0", 0, 0, 0, usb3), 157062306a36Sopenharmony_ci TEGRA186_LANE("usb3-1", 0, 0, 0, usb3), 157162306a36Sopenharmony_ci TEGRA186_LANE("usb3-2", 0, 0, 0, usb3), 157262306a36Sopenharmony_ci}; 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_cistatic const struct tegra_xusb_pad_soc tegra186_usb3_pad = { 157562306a36Sopenharmony_ci .name = "usb3", 157662306a36Sopenharmony_ci .num_lanes = ARRAY_SIZE(tegra186_usb3_lanes), 157762306a36Sopenharmony_ci .lanes = tegra186_usb3_lanes, 157862306a36Sopenharmony_ci .ops = &tegra186_usb3_pad_ops, 157962306a36Sopenharmony_ci}; 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_cistatic const struct tegra_xusb_pad_soc * const tegra186_pads[] = { 158262306a36Sopenharmony_ci &tegra186_usb2_pad, 158362306a36Sopenharmony_ci &tegra186_usb3_pad, 158462306a36Sopenharmony_ci#if 0 /* TODO implement */ 158562306a36Sopenharmony_ci &tegra186_hsic_pad, 158662306a36Sopenharmony_ci#endif 158762306a36Sopenharmony_ci}; 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ciconst struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc = { 159062306a36Sopenharmony_ci .num_pads = ARRAY_SIZE(tegra186_pads), 159162306a36Sopenharmony_ci .pads = tegra186_pads, 159262306a36Sopenharmony_ci .ports = { 159362306a36Sopenharmony_ci .usb2 = { 159462306a36Sopenharmony_ci .ops = &tegra186_usb2_port_ops, 159562306a36Sopenharmony_ci .count = 3, 159662306a36Sopenharmony_ci }, 159762306a36Sopenharmony_ci#if 0 /* TODO implement */ 159862306a36Sopenharmony_ci .hsic = { 159962306a36Sopenharmony_ci .ops = &tegra186_hsic_port_ops, 160062306a36Sopenharmony_ci .count = 1, 160162306a36Sopenharmony_ci }, 160262306a36Sopenharmony_ci#endif 160362306a36Sopenharmony_ci .usb3 = { 160462306a36Sopenharmony_ci .ops = &tegra186_usb3_port_ops, 160562306a36Sopenharmony_ci .count = 3, 160662306a36Sopenharmony_ci }, 160762306a36Sopenharmony_ci }, 160862306a36Sopenharmony_ci .ops = &tegra186_xusb_padctl_ops, 160962306a36Sopenharmony_ci .supply_names = tegra186_xusb_padctl_supply_names, 161062306a36Sopenharmony_ci .num_supplies = ARRAY_SIZE(tegra186_xusb_padctl_supply_names), 161162306a36Sopenharmony_ci}; 161262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tegra186_xusb_padctl_soc); 161362306a36Sopenharmony_ci#endif 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \ 161662306a36Sopenharmony_ci IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) 161762306a36Sopenharmony_cistatic const char * const tegra194_xusb_padctl_supply_names[] = { 161862306a36Sopenharmony_ci "avdd-usb", 161962306a36Sopenharmony_ci "vclamp-usb", 162062306a36Sopenharmony_ci}; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_cistatic const struct tegra_xusb_lane_soc tegra194_usb2_lanes[] = { 162362306a36Sopenharmony_ci TEGRA186_LANE("usb2-0", 0, 0, 0, usb2), 162462306a36Sopenharmony_ci TEGRA186_LANE("usb2-1", 0, 0, 0, usb2), 162562306a36Sopenharmony_ci TEGRA186_LANE("usb2-2", 0, 0, 0, usb2), 162662306a36Sopenharmony_ci TEGRA186_LANE("usb2-3", 0, 0, 0, usb2), 162762306a36Sopenharmony_ci}; 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_cistatic const struct tegra_xusb_pad_soc tegra194_usb2_pad = { 163062306a36Sopenharmony_ci .name = "usb2", 163162306a36Sopenharmony_ci .num_lanes = ARRAY_SIZE(tegra194_usb2_lanes), 163262306a36Sopenharmony_ci .lanes = tegra194_usb2_lanes, 163362306a36Sopenharmony_ci .ops = &tegra186_usb2_pad_ops, 163462306a36Sopenharmony_ci}; 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_cistatic const struct tegra_xusb_lane_soc tegra194_usb3_lanes[] = { 163762306a36Sopenharmony_ci TEGRA186_LANE("usb3-0", 0, 0, 0, usb3), 163862306a36Sopenharmony_ci TEGRA186_LANE("usb3-1", 0, 0, 0, usb3), 163962306a36Sopenharmony_ci TEGRA186_LANE("usb3-2", 0, 0, 0, usb3), 164062306a36Sopenharmony_ci TEGRA186_LANE("usb3-3", 0, 0, 0, usb3), 164162306a36Sopenharmony_ci}; 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_cistatic const struct tegra_xusb_pad_soc tegra194_usb3_pad = { 164462306a36Sopenharmony_ci .name = "usb3", 164562306a36Sopenharmony_ci .num_lanes = ARRAY_SIZE(tegra194_usb3_lanes), 164662306a36Sopenharmony_ci .lanes = tegra194_usb3_lanes, 164762306a36Sopenharmony_ci .ops = &tegra186_usb3_pad_ops, 164862306a36Sopenharmony_ci}; 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_cistatic const struct tegra_xusb_pad_soc * const tegra194_pads[] = { 165162306a36Sopenharmony_ci &tegra194_usb2_pad, 165262306a36Sopenharmony_ci &tegra194_usb3_pad, 165362306a36Sopenharmony_ci}; 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ciconst struct tegra_xusb_padctl_soc tegra194_xusb_padctl_soc = { 165662306a36Sopenharmony_ci .num_pads = ARRAY_SIZE(tegra194_pads), 165762306a36Sopenharmony_ci .pads = tegra194_pads, 165862306a36Sopenharmony_ci .ports = { 165962306a36Sopenharmony_ci .usb2 = { 166062306a36Sopenharmony_ci .ops = &tegra186_usb2_port_ops, 166162306a36Sopenharmony_ci .count = 4, 166262306a36Sopenharmony_ci }, 166362306a36Sopenharmony_ci .usb3 = { 166462306a36Sopenharmony_ci .ops = &tegra186_usb3_port_ops, 166562306a36Sopenharmony_ci .count = 4, 166662306a36Sopenharmony_ci }, 166762306a36Sopenharmony_ci }, 166862306a36Sopenharmony_ci .ops = &tegra186_xusb_padctl_ops, 166962306a36Sopenharmony_ci .supply_names = tegra194_xusb_padctl_supply_names, 167062306a36Sopenharmony_ci .num_supplies = ARRAY_SIZE(tegra194_xusb_padctl_supply_names), 167162306a36Sopenharmony_ci .supports_gen2 = true, 167262306a36Sopenharmony_ci .poll_trk_completed = true, 167362306a36Sopenharmony_ci}; 167462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tegra194_xusb_padctl_soc); 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ciconst struct tegra_xusb_padctl_soc tegra234_xusb_padctl_soc = { 167762306a36Sopenharmony_ci .num_pads = ARRAY_SIZE(tegra194_pads), 167862306a36Sopenharmony_ci .pads = tegra194_pads, 167962306a36Sopenharmony_ci .ports = { 168062306a36Sopenharmony_ci .usb2 = { 168162306a36Sopenharmony_ci .ops = &tegra186_usb2_port_ops, 168262306a36Sopenharmony_ci .count = 4, 168362306a36Sopenharmony_ci }, 168462306a36Sopenharmony_ci .usb3 = { 168562306a36Sopenharmony_ci .ops = &tegra186_usb3_port_ops, 168662306a36Sopenharmony_ci .count = 4, 168762306a36Sopenharmony_ci }, 168862306a36Sopenharmony_ci }, 168962306a36Sopenharmony_ci .ops = &tegra186_xusb_padctl_ops, 169062306a36Sopenharmony_ci .supply_names = tegra194_xusb_padctl_supply_names, 169162306a36Sopenharmony_ci .num_supplies = ARRAY_SIZE(tegra194_xusb_padctl_supply_names), 169262306a36Sopenharmony_ci .supports_gen2 = true, 169362306a36Sopenharmony_ci .poll_trk_completed = true, 169462306a36Sopenharmony_ci .trk_hw_mode = true, 169562306a36Sopenharmony_ci .supports_lp_cfg_en = true, 169662306a36Sopenharmony_ci}; 169762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tegra234_xusb_padctl_soc); 169862306a36Sopenharmony_ci#endif 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ciMODULE_AUTHOR("JC Kuo <jckuo@nvidia.com>"); 170162306a36Sopenharmony_ciMODULE_DESCRIPTION("NVIDIA Tegra186 XUSB Pad Controller driver"); 170262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1703