Merge branch 'for-5.7/phy' into for-5.7/usb

This commit is contained in:
Thierry Reding 2020-03-19 14:18:32 +01:00
commit 80525cc238
8 changed files with 609 additions and 91 deletions

View File

@ -2,6 +2,8 @@
config PHY_TEGRA_XUSB config PHY_TEGRA_XUSB
tristate "NVIDIA Tegra XUSB pad controller driver" tristate "NVIDIA Tegra XUSB pad controller driver"
depends on ARCH_TEGRA depends on ARCH_TEGRA
select USB_CONN_GPIO
select USB_PHY
help help
Choose this option if you have an NVIDIA Tegra SoC. Choose this option if you have an NVIDIA Tegra SoC.

View File

@ -6,4 +6,5 @@ phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_124_SOC) += xusb-tegra124.o
phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_132_SOC) += xusb-tegra124.o phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_132_SOC) += xusb-tegra124.o
phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_210_SOC) += xusb-tegra210.o phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_210_SOC) += xusb-tegra210.o
phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_186_SOC) += xusb-tegra186.o phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_186_SOC) += xusb-tegra186.o
phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_194_SOC) += xusb-tegra186.o
obj-$(CONFIG_PHY_TEGRA194_P2U) += phy-tegra194-p2u.o obj-$(CONFIG_PHY_TEGRA194_P2U) += phy-tegra194-p2u.o

View File

@ -1422,6 +1422,8 @@ tegra124_usb2_port_map(struct tegra_xusb_port *port)
} }
static const struct tegra_xusb_port_ops tegra124_usb2_port_ops = { static const struct tegra_xusb_port_ops tegra124_usb2_port_ops = {
.release = tegra_xusb_usb2_port_release,
.remove = tegra_xusb_usb2_port_remove,
.enable = tegra124_usb2_port_enable, .enable = tegra124_usb2_port_enable,
.disable = tegra124_usb2_port_disable, .disable = tegra124_usb2_port_disable,
.map = tegra124_usb2_port_map, .map = tegra124_usb2_port_map,
@ -1443,6 +1445,7 @@ tegra124_ulpi_port_map(struct tegra_xusb_port *port)
} }
static const struct tegra_xusb_port_ops tegra124_ulpi_port_ops = { static const struct tegra_xusb_port_ops tegra124_ulpi_port_ops = {
.release = tegra_xusb_ulpi_port_release,
.enable = tegra124_ulpi_port_enable, .enable = tegra124_ulpi_port_enable,
.disable = tegra124_ulpi_port_disable, .disable = tegra124_ulpi_port_disable,
.map = tegra124_ulpi_port_map, .map = tegra124_ulpi_port_map,
@ -1464,6 +1467,7 @@ tegra124_hsic_port_map(struct tegra_xusb_port *port)
} }
static const struct tegra_xusb_port_ops tegra124_hsic_port_ops = { static const struct tegra_xusb_port_ops tegra124_hsic_port_ops = {
.release = tegra_xusb_hsic_port_release,
.enable = tegra124_hsic_port_enable, .enable = tegra124_hsic_port_enable,
.disable = tegra124_hsic_port_disable, .disable = tegra124_hsic_port_disable,
.map = tegra124_hsic_port_map, .map = tegra124_hsic_port_map,
@ -1647,6 +1651,8 @@ tegra124_usb3_port_map(struct tegra_xusb_port *port)
} }
static const struct tegra_xusb_port_ops tegra124_usb3_port_ops = { static const struct tegra_xusb_port_ops tegra124_usb3_port_ops = {
.release = tegra_xusb_usb3_port_release,
.remove = tegra_xusb_usb3_port_remove,
.enable = tegra124_usb3_port_enable, .enable = tegra124_usb3_port_enable,
.disable = tegra124_usb3_port_disable, .disable = tegra124_usb3_port_disable,
.map = tegra124_usb3_port_map, .map = tegra124_usb3_port_map,

View File

@ -63,6 +63,10 @@
#define SSPX_ELPG_CLAMP_EN(x) BIT(0 + (x) * 3) #define SSPX_ELPG_CLAMP_EN(x) BIT(0 + (x) * 3)
#define SSPX_ELPG_CLAMP_EN_EARLY(x) BIT(1 + (x) * 3) #define SSPX_ELPG_CLAMP_EN_EARLY(x) BIT(1 + (x) * 3)
#define SSPX_ELPG_VCORE_DOWN(x) BIT(2 + (x) * 3) #define SSPX_ELPG_VCORE_DOWN(x) BIT(2 + (x) * 3)
#define XUSB_PADCTL_SS_PORT_CFG 0x2c
#define PORTX_SPEED_SUPPORT_SHIFT(x) ((x) * 4)
#define PORTX_SPEED_SUPPORT_MASK (0x3)
#define PORT_SPEED_SUPPORT_GEN1 (0x0)
#define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x) (0x88 + (x) * 0x40) #define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x) (0x88 + (x) * 0x40)
#define HS_CURR_LEVEL(x) ((x) & 0x3f) #define HS_CURR_LEVEL(x) ((x) & 0x3f)
@ -301,6 +305,97 @@ static void tegra_phy_xusb_utmi_pad_power_down(struct phy *phy)
tegra186_utmi_bias_pad_power_off(padctl); tegra186_utmi_bias_pad_power_off(padctl);
} }
static int tegra186_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
bool status)
{
u32 value;
dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear");
value = padctl_readl(padctl, USB2_VBUS_ID);
if (status) {
value |= VBUS_OVERRIDE;
value &= ~ID_OVERRIDE(~0);
value |= ID_OVERRIDE_FLOATING;
} else {
value &= ~VBUS_OVERRIDE;
}
padctl_writel(padctl, value, USB2_VBUS_ID);
return 0;
}
static int tegra186_xusb_padctl_id_override(struct tegra_xusb_padctl *padctl,
bool status)
{
u32 value;
dev_dbg(padctl->dev, "%s id override\n", status ? "set" : "clear");
value = padctl_readl(padctl, USB2_VBUS_ID);
if (status) {
if (value & VBUS_OVERRIDE) {
value &= ~VBUS_OVERRIDE;
padctl_writel(padctl, value, USB2_VBUS_ID);
usleep_range(1000, 2000);
value = padctl_readl(padctl, USB2_VBUS_ID);
}
value &= ~ID_OVERRIDE(~0);
value |= ID_OVERRIDE_GROUNDED;
} else {
value &= ~ID_OVERRIDE(~0);
value |= ID_OVERRIDE_FLOATING;
}
padctl_writel(padctl, value, USB2_VBUS_ID);
return 0;
}
static int tegra186_utmi_phy_set_mode(struct phy *phy, enum phy_mode mode,
int submode)
{
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
struct tegra_xusb_padctl *padctl = lane->pad->padctl;
struct tegra_xusb_usb2_port *port = tegra_xusb_find_usb2_port(padctl,
lane->index);
int err = 0;
mutex_lock(&padctl->lock);
dev_dbg(&port->base.dev, "%s: mode %d", __func__, mode);
if (mode == PHY_MODE_USB_OTG) {
if (submode == USB_ROLE_HOST) {
tegra186_xusb_padctl_id_override(padctl, true);
err = regulator_enable(port->supply);
} else if (submode == USB_ROLE_DEVICE) {
tegra186_xusb_padctl_vbus_override(padctl, true);
} else if (submode == USB_ROLE_NONE) {
/*
* When port is peripheral only or role transitions to
* USB_ROLE_NONE from USB_ROLE_DEVICE, regulator is not
* enabled.
*/
if (regulator_is_enabled(port->supply))
regulator_disable(port->supply);
tegra186_xusb_padctl_id_override(padctl, false);
tegra186_xusb_padctl_vbus_override(padctl, false);
}
}
mutex_unlock(&padctl->lock);
return err;
}
static int tegra186_utmi_phy_power_on(struct phy *phy) static int tegra186_utmi_phy_power_on(struct phy *phy)
{ {
struct tegra_xusb_lane *lane = phy_get_drvdata(phy); struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
@ -439,6 +534,7 @@ static const struct phy_ops utmi_phy_ops = {
.exit = tegra186_utmi_phy_exit, .exit = tegra186_utmi_phy_exit,
.power_on = tegra186_utmi_phy_power_on, .power_on = tegra186_utmi_phy_power_on,
.power_off = tegra186_utmi_phy_power_off, .power_off = tegra186_utmi_phy_power_off,
.set_mode = tegra186_utmi_phy_set_mode,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
@ -503,19 +599,6 @@ static const char * const tegra186_usb2_functions[] = {
"xusb", "xusb",
}; };
static const struct tegra_xusb_lane_soc tegra186_usb2_lanes[] = {
TEGRA186_LANE("usb2-0", 0, 0, 0, usb2),
TEGRA186_LANE("usb2-1", 0, 0, 0, usb2),
TEGRA186_LANE("usb2-2", 0, 0, 0, usb2),
};
static const struct tegra_xusb_pad_soc tegra186_usb2_pad = {
.name = "usb2",
.num_lanes = ARRAY_SIZE(tegra186_usb2_lanes),
.lanes = tegra186_usb2_lanes,
.ops = &tegra186_usb2_pad_ops,
};
static int tegra186_usb2_port_enable(struct tegra_xusb_port *port) static int tegra186_usb2_port_enable(struct tegra_xusb_port *port)
{ {
return 0; return 0;
@ -532,6 +615,8 @@ tegra186_usb2_port_map(struct tegra_xusb_port *port)
} }
static const struct tegra_xusb_port_ops tegra186_usb2_port_ops = { static const struct tegra_xusb_port_ops tegra186_usb2_port_ops = {
.release = tegra_xusb_usb2_port_release,
.remove = tegra_xusb_usb2_port_remove,
.enable = tegra186_usb2_port_enable, .enable = tegra186_usb2_port_enable,
.disable = tegra186_usb2_port_disable, .disable = tegra186_usb2_port_disable,
.map = tegra186_usb2_port_map, .map = tegra186_usb2_port_map,
@ -591,6 +676,8 @@ tegra186_usb3_port_map(struct tegra_xusb_port *port)
} }
static const struct tegra_xusb_port_ops tegra186_usb3_port_ops = { static const struct tegra_xusb_port_ops tegra186_usb3_port_ops = {
.release = tegra_xusb_usb3_port_release,
.remove = tegra_xusb_usb3_port_remove,
.enable = tegra186_usb3_port_enable, .enable = tegra186_usb3_port_enable,
.disable = tegra186_usb3_port_disable, .disable = tegra186_usb3_port_disable,
.map = tegra186_usb3_port_map, .map = tegra186_usb3_port_map,
@ -635,6 +722,15 @@ static int tegra186_usb3_phy_power_on(struct phy *phy)
padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_CAP); padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_CAP);
if (padctl->soc->supports_gen2 && port->disable_gen2) {
value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_CFG);
value &= ~(PORTX_SPEED_SUPPORT_MASK <<
PORTX_SPEED_SUPPORT_SHIFT(index));
value |= (PORT_SPEED_SUPPORT_GEN1 <<
PORTX_SPEED_SUPPORT_SHIFT(index));
padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_CFG);
}
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1); value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
value &= ~SSPX_ELPG_VCORE_DOWN(index); value &= ~SSPX_ELPG_VCORE_DOWN(index);
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1); padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
@ -765,27 +861,6 @@ static const char * const tegra186_usb3_functions[] = {
"xusb", "xusb",
}; };
static const struct tegra_xusb_lane_soc tegra186_usb3_lanes[] = {
TEGRA186_LANE("usb3-0", 0, 0, 0, usb3),
TEGRA186_LANE("usb3-1", 0, 0, 0, usb3),
TEGRA186_LANE("usb3-2", 0, 0, 0, usb3),
};
static const struct tegra_xusb_pad_soc tegra186_usb3_pad = {
.name = "usb3",
.num_lanes = ARRAY_SIZE(tegra186_usb3_lanes),
.lanes = tegra186_usb3_lanes,
.ops = &tegra186_usb3_pad_ops,
};
static const struct tegra_xusb_pad_soc * const tegra186_pads[] = {
&tegra186_usb2_pad,
&tegra186_usb3_pad,
#if 0 /* TODO implement */
&tegra186_hsic_pad,
#endif
};
static int static int
tegra186_xusb_read_fuse_calibration(struct tegra186_xusb_padctl *padctl) tegra186_xusb_read_fuse_calibration(struct tegra186_xusb_padctl *padctl)
{ {
@ -802,7 +877,9 @@ tegra186_xusb_read_fuse_calibration(struct tegra186_xusb_padctl *padctl)
err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value); err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value);
if (err) { if (err) {
dev_err(dev, "failed to read calibration fuse: %d\n", err); if (err != -EPROBE_DEFER)
dev_err(dev, "failed to read calibration fuse: %d\n",
err);
return err; return err;
} }
@ -857,34 +934,13 @@ static void tegra186_xusb_padctl_remove(struct tegra_xusb_padctl *padctl)
{ {
} }
static int tegra186_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
bool status)
{
u32 value;
dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear");
value = padctl_readl(padctl, USB2_VBUS_ID);
if (status) {
value |= VBUS_OVERRIDE;
value &= ~ID_OVERRIDE(~0);
value |= ID_OVERRIDE_FLOATING;
} else {
value &= ~VBUS_OVERRIDE;
}
padctl_writel(padctl, value, USB2_VBUS_ID);
return 0;
}
static const struct tegra_xusb_padctl_ops tegra186_xusb_padctl_ops = { static const struct tegra_xusb_padctl_ops tegra186_xusb_padctl_ops = {
.probe = tegra186_xusb_padctl_probe, .probe = tegra186_xusb_padctl_probe,
.remove = tegra186_xusb_padctl_remove, .remove = tegra186_xusb_padctl_remove,
.vbus_override = tegra186_xusb_padctl_vbus_override, .vbus_override = tegra186_xusb_padctl_vbus_override,
}; };
#if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC)
static const char * const tegra186_xusb_padctl_supply_names[] = { static const char * const tegra186_xusb_padctl_supply_names[] = {
"avdd-pll-erefeut", "avdd-pll-erefeut",
"avdd-usb", "avdd-usb",
@ -892,6 +948,40 @@ static const char * const tegra186_xusb_padctl_supply_names[] = {
"vddio-hsic", "vddio-hsic",
}; };
static const struct tegra_xusb_lane_soc tegra186_usb2_lanes[] = {
TEGRA186_LANE("usb2-0", 0, 0, 0, usb2),
TEGRA186_LANE("usb2-1", 0, 0, 0, usb2),
TEGRA186_LANE("usb2-2", 0, 0, 0, usb2),
};
static const struct tegra_xusb_pad_soc tegra186_usb2_pad = {
.name = "usb2",
.num_lanes = ARRAY_SIZE(tegra186_usb2_lanes),
.lanes = tegra186_usb2_lanes,
.ops = &tegra186_usb2_pad_ops,
};
static const struct tegra_xusb_lane_soc tegra186_usb3_lanes[] = {
TEGRA186_LANE("usb3-0", 0, 0, 0, usb3),
TEGRA186_LANE("usb3-1", 0, 0, 0, usb3),
TEGRA186_LANE("usb3-2", 0, 0, 0, usb3),
};
static const struct tegra_xusb_pad_soc tegra186_usb3_pad = {
.name = "usb3",
.num_lanes = ARRAY_SIZE(tegra186_usb3_lanes),
.lanes = tegra186_usb3_lanes,
.ops = &tegra186_usb3_pad_ops,
};
static const struct tegra_xusb_pad_soc * const tegra186_pads[] = {
&tegra186_usb2_pad,
&tegra186_usb3_pad,
#if 0 /* TODO implement */
&tegra186_hsic_pad,
#endif
};
const struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc = { const struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc = {
.num_pads = ARRAY_SIZE(tegra186_pads), .num_pads = ARRAY_SIZE(tegra186_pads),
.pads = tegra186_pads, .pads = tegra186_pads,
@ -916,6 +1006,67 @@ const struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc = {
.num_supplies = ARRAY_SIZE(tegra186_xusb_padctl_supply_names), .num_supplies = ARRAY_SIZE(tegra186_xusb_padctl_supply_names),
}; };
EXPORT_SYMBOL_GPL(tegra186_xusb_padctl_soc); EXPORT_SYMBOL_GPL(tegra186_xusb_padctl_soc);
#endif
#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC)
static const char * const tegra194_xusb_padctl_supply_names[] = {
"avdd-usb",
"vclamp-usb",
};
static const struct tegra_xusb_lane_soc tegra194_usb2_lanes[] = {
TEGRA186_LANE("usb2-0", 0, 0, 0, usb2),
TEGRA186_LANE("usb2-1", 0, 0, 0, usb2),
TEGRA186_LANE("usb2-2", 0, 0, 0, usb2),
TEGRA186_LANE("usb2-3", 0, 0, 0, usb2),
};
static const struct tegra_xusb_pad_soc tegra194_usb2_pad = {
.name = "usb2",
.num_lanes = ARRAY_SIZE(tegra194_usb2_lanes),
.lanes = tegra194_usb2_lanes,
.ops = &tegra186_usb2_pad_ops,
};
static const struct tegra_xusb_lane_soc tegra194_usb3_lanes[] = {
TEGRA186_LANE("usb3-0", 0, 0, 0, usb3),
TEGRA186_LANE("usb3-1", 0, 0, 0, usb3),
TEGRA186_LANE("usb3-2", 0, 0, 0, usb3),
TEGRA186_LANE("usb3-3", 0, 0, 0, usb3),
};
static const struct tegra_xusb_pad_soc tegra194_usb3_pad = {
.name = "usb3",
.num_lanes = ARRAY_SIZE(tegra194_usb3_lanes),
.lanes = tegra194_usb3_lanes,
.ops = &tegra186_usb3_pad_ops,
};
static const struct tegra_xusb_pad_soc * const tegra194_pads[] = {
&tegra194_usb2_pad,
&tegra194_usb3_pad,
};
const struct tegra_xusb_padctl_soc tegra194_xusb_padctl_soc = {
.num_pads = ARRAY_SIZE(tegra194_pads),
.pads = tegra194_pads,
.ports = {
.usb2 = {
.ops = &tegra186_usb2_port_ops,
.count = 4,
},
.usb3 = {
.ops = &tegra186_usb3_port_ops,
.count = 4,
},
},
.ops = &tegra186_xusb_padctl_ops,
.supply_names = tegra194_xusb_padctl_supply_names,
.num_supplies = ARRAY_SIZE(tegra194_xusb_padctl_supply_names),
.supports_gen2 = true,
};
EXPORT_SYMBOL_GPL(tegra194_xusb_padctl_soc);
#endif
MODULE_AUTHOR("JC Kuo <jckuo@nvidia.com>"); MODULE_AUTHOR("JC Kuo <jckuo@nvidia.com>");
MODULE_DESCRIPTION("NVIDIA Tegra186 XUSB Pad Controller driver"); MODULE_DESCRIPTION("NVIDIA Tegra186 XUSB Pad Controller driver");

View File

@ -236,6 +236,7 @@
#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT 18 #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT 18
#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK 0xf #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK 0xf
#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING 8 #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING 8
#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED 0
struct tegra210_xusb_fuse_calibration { struct tegra210_xusb_fuse_calibration {
u32 hs_curr_level[4]; u32 hs_curr_level[4];
@ -935,6 +936,103 @@ static int tegra210_usb2_phy_exit(struct phy *phy)
return tegra210_xusb_padctl_disable(lane->pad->padctl); return tegra210_xusb_padctl_disable(lane->pad->padctl);
} }
static int tegra210_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
bool status)
{
u32 value;
dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear");
value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);
if (status) {
value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING <<
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
} else {
value &= ~XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
}
padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);
return 0;
}
static int tegra210_xusb_padctl_id_override(struct tegra_xusb_padctl *padctl,
bool status)
{
u32 value;
dev_dbg(padctl->dev, "%s id override\n", status ? "set" : "clear");
value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);
if (status) {
if (value & XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON) {
value &= ~XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);
usleep_range(1000, 2000);
value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);
}
value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED <<
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
} else {
value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING <<
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
}
padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);
return 0;
}
static int tegra210_usb2_phy_set_mode(struct phy *phy, enum phy_mode mode,
int submode)
{
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
struct tegra_xusb_padctl *padctl = lane->pad->padctl;
struct tegra_xusb_usb2_port *port = tegra_xusb_find_usb2_port(padctl,
lane->index);
int err = 0;
mutex_lock(&padctl->lock);
dev_dbg(&port->base.dev, "%s: mode %d", __func__, mode);
if (mode == PHY_MODE_USB_OTG) {
if (submode == USB_ROLE_HOST) {
tegra210_xusb_padctl_id_override(padctl, true);
err = regulator_enable(port->supply);
} else if (submode == USB_ROLE_DEVICE) {
tegra210_xusb_padctl_vbus_override(padctl, true);
} else if (submode == USB_ROLE_NONE) {
/*
* When port is peripheral only or role transitions to
* USB_ROLE_NONE from USB_ROLE_DEVICE, regulator is not
* be enabled.
*/
if (regulator_is_enabled(port->supply))
regulator_disable(port->supply);
tegra210_xusb_padctl_id_override(padctl, false);
tegra210_xusb_padctl_vbus_override(padctl, false);
}
}
mutex_unlock(&padctl->lock);
return err;
}
static int tegra210_usb2_phy_power_on(struct phy *phy) static int tegra210_usb2_phy_power_on(struct phy *phy)
{ {
struct tegra_xusb_lane *lane = phy_get_drvdata(phy); struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
@ -1048,9 +1146,11 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
padctl_writel(padctl, value, padctl_writel(padctl, value,
XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index)); XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index));
err = regulator_enable(port->supply); if (port->supply && port->mode == USB_DR_MODE_HOST) {
if (err) err = regulator_enable(port->supply);
return err; if (err)
return err;
}
mutex_lock(&padctl->lock); mutex_lock(&padctl->lock);
@ -1164,6 +1264,7 @@ static const struct phy_ops tegra210_usb2_phy_ops = {
.exit = tegra210_usb2_phy_exit, .exit = tegra210_usb2_phy_exit,
.power_on = tegra210_usb2_phy_power_on, .power_on = tegra210_usb2_phy_power_on,
.power_off = tegra210_usb2_phy_power_off, .power_off = tegra210_usb2_phy_power_off,
.set_mode = tegra210_usb2_phy_set_mode,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
@ -1852,6 +1953,8 @@ tegra210_usb2_port_map(struct tegra_xusb_port *port)
} }
static const struct tegra_xusb_port_ops tegra210_usb2_port_ops = { static const struct tegra_xusb_port_ops tegra210_usb2_port_ops = {
.release = tegra_xusb_usb2_port_release,
.remove = tegra_xusb_usb2_port_remove,
.enable = tegra210_usb2_port_enable, .enable = tegra210_usb2_port_enable,
.disable = tegra210_usb2_port_disable, .disable = tegra210_usb2_port_disable,
.map = tegra210_usb2_port_map, .map = tegra210_usb2_port_map,
@ -1873,6 +1976,7 @@ tegra210_hsic_port_map(struct tegra_xusb_port *port)
} }
static const struct tegra_xusb_port_ops tegra210_hsic_port_ops = { static const struct tegra_xusb_port_ops tegra210_hsic_port_ops = {
.release = tegra_xusb_hsic_port_release,
.enable = tegra210_hsic_port_enable, .enable = tegra210_hsic_port_enable,
.disable = tegra210_hsic_port_disable, .disable = tegra210_hsic_port_disable,
.map = tegra210_hsic_port_map, .map = tegra210_hsic_port_map,
@ -2018,35 +2122,13 @@ tegra210_usb3_port_map(struct tegra_xusb_port *port)
} }
static const struct tegra_xusb_port_ops tegra210_usb3_port_ops = { static const struct tegra_xusb_port_ops tegra210_usb3_port_ops = {
.release = tegra_xusb_usb3_port_release,
.remove = tegra_xusb_usb3_port_remove,
.enable = tegra210_usb3_port_enable, .enable = tegra210_usb3_port_enable,
.disable = tegra210_usb3_port_disable, .disable = tegra210_usb3_port_disable,
.map = tegra210_usb3_port_map, .map = tegra210_usb3_port_map,
}; };
static int tegra210_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
bool status)
{
u32 value;
dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear");
value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);
if (status) {
value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING <<
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
} else {
value &= ~XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
}
padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);
return 0;
}
static int tegra210_utmi_port_reset(struct phy *phy) static int tegra210_utmi_port_reset(struct phy *phy)
{ {
struct tegra_xusb_padctl *padctl; struct tegra_xusb_padctl *padctl;

View File

@ -65,6 +65,12 @@ static const struct of_device_id tegra_xusb_padctl_of_match[] = {
.compatible = "nvidia,tegra186-xusb-padctl", .compatible = "nvidia,tegra186-xusb-padctl",
.data = &tegra186_xusb_padctl_soc, .data = &tegra186_xusb_padctl_soc,
}, },
#endif
#if defined(CONFIG_ARCH_TEGRA_194_SOC)
{
.compatible = "nvidia,tegra194-xusb-padctl",
.data = &tegra194_xusb_padctl_soc,
},
#endif #endif
{ } { }
}; };
@ -501,6 +507,10 @@ tegra_xusb_find_usb3_port(struct tegra_xusb_padctl *padctl, unsigned int index)
static void tegra_xusb_port_release(struct device *dev) static void tegra_xusb_port_release(struct device *dev)
{ {
struct tegra_xusb_port *port = to_tegra_xusb_port(dev);
if (port->ops->release)
port->ops->release(port);
} }
static struct device_type tegra_xusb_port_type = { static struct device_type tegra_xusb_port_type = {
@ -541,6 +551,16 @@ unregister:
static void tegra_xusb_port_unregister(struct tegra_xusb_port *port) static void tegra_xusb_port_unregister(struct tegra_xusb_port *port)
{ {
if (!IS_ERR_OR_NULL(port->usb_role_sw)) {
of_platform_depopulate(&port->dev);
usb_role_switch_unregister(port->usb_role_sw);
cancel_work_sync(&port->usb_phy_work);
usb_remove_phy(&port->usb_phy);
}
if (port->ops->remove)
port->ops->remove(port);
device_unregister(&port->dev); device_unregister(&port->dev);
} }
@ -551,11 +571,146 @@ static const char *const modes[] = {
[USB_DR_MODE_OTG] = "otg", [USB_DR_MODE_OTG] = "otg",
}; };
static const char * const usb_roles[] = {
[USB_ROLE_NONE] = "none",
[USB_ROLE_HOST] = "host",
[USB_ROLE_DEVICE] = "device",
};
static enum usb_phy_events to_usb_phy_event(enum usb_role role)
{
switch (role) {
case USB_ROLE_DEVICE:
return USB_EVENT_VBUS;
case USB_ROLE_HOST:
return USB_EVENT_ID;
default:
return USB_EVENT_NONE;
}
}
static void tegra_xusb_usb_phy_work(struct work_struct *work)
{
struct tegra_xusb_port *port = container_of(work,
struct tegra_xusb_port,
usb_phy_work);
enum usb_role role = usb_role_switch_get_role(port->usb_role_sw);
usb_phy_set_event(&port->usb_phy, to_usb_phy_event(role));
dev_dbg(&port->dev, "%s(): calling notifier for role %s\n", __func__,
usb_roles[role]);
atomic_notifier_call_chain(&port->usb_phy.notifier, 0, &port->usb_phy);
}
static int tegra_xusb_role_sw_set(struct usb_role_switch *sw,
enum usb_role role)
{
struct tegra_xusb_port *port = usb_role_switch_get_drvdata(sw);
dev_dbg(&port->dev, "%s(): role %s\n", __func__, usb_roles[role]);
schedule_work(&port->usb_phy_work);
return 0;
}
static int tegra_xusb_set_peripheral(struct usb_otg *otg,
struct usb_gadget *gadget)
{
struct tegra_xusb_port *port = container_of(otg->usb_phy,
struct tegra_xusb_port,
usb_phy);
if (gadget != NULL)
schedule_work(&port->usb_phy_work);
return 0;
}
static int tegra_xusb_set_host(struct usb_otg *otg, struct usb_bus *host)
{
struct tegra_xusb_port *port = container_of(otg->usb_phy,
struct tegra_xusb_port,
usb_phy);
if (host != NULL)
schedule_work(&port->usb_phy_work);
return 0;
}
static int tegra_xusb_setup_usb_role_switch(struct tegra_xusb_port *port)
{
struct tegra_xusb_lane *lane;
struct usb_role_switch_desc role_sx_desc = {
.fwnode = dev_fwnode(&port->dev),
.set = tegra_xusb_role_sw_set,
};
int err = 0;
/*
* USB role switch driver needs parent driver owner info. This is a
* suboptimal solution. TODO: Need to revisit this in a follow-up patch
* where an optimal solution is possible with changes to USB role
* switch driver.
*/
port->dev.driver = devm_kzalloc(&port->dev,
sizeof(struct device_driver),
GFP_KERNEL);
port->dev.driver->owner = THIS_MODULE;
port->usb_role_sw = usb_role_switch_register(&port->dev,
&role_sx_desc);
if (IS_ERR(port->usb_role_sw)) {
err = PTR_ERR(port->usb_role_sw);
dev_err(&port->dev, "failed to register USB role switch: %d",
err);
return err;
}
INIT_WORK(&port->usb_phy_work, tegra_xusb_usb_phy_work);
usb_role_switch_set_drvdata(port->usb_role_sw, port);
port->usb_phy.otg = devm_kzalloc(&port->dev, sizeof(struct usb_otg),
GFP_KERNEL);
if (!port->usb_phy.otg)
return -ENOMEM;
lane = tegra_xusb_find_lane(port->padctl, "usb2", port->index);
/*
* Assign phy dev to usb-phy dev. Host/device drivers can use phy
* reference to retrieve usb-phy details.
*/
port->usb_phy.dev = &lane->pad->lanes[port->index]->dev;
port->usb_phy.dev->driver = port->padctl->dev->driver;
port->usb_phy.otg->usb_phy = &port->usb_phy;
port->usb_phy.otg->set_peripheral = tegra_xusb_set_peripheral;
port->usb_phy.otg->set_host = tegra_xusb_set_host;
err = usb_add_phy_dev(&port->usb_phy);
if (err < 0) {
dev_err(&port->dev, "Failed to add USB PHY: %d\n", err);
return err;
}
/* populate connector entry */
of_platform_populate(port->dev.of_node, NULL, NULL, &port->dev);
return err;
}
static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2) static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2)
{ {
struct tegra_xusb_port *port = &usb2->base; struct tegra_xusb_port *port = &usb2->base;
struct device_node *np = port->dev.of_node; struct device_node *np = port->dev.of_node;
const char *mode; const char *mode;
int err;
usb2->internal = of_property_read_bool(np, "nvidia,internal"); usb2->internal = of_property_read_bool(np, "nvidia,internal");
@ -572,7 +727,21 @@ static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2)
usb2->mode = USB_DR_MODE_HOST; usb2->mode = USB_DR_MODE_HOST;
} }
usb2->supply = devm_regulator_get(&port->dev, "vbus"); /* usb-role-switch property is mandatory for OTG/Peripheral modes */
if (usb2->mode == USB_DR_MODE_PERIPHERAL ||
usb2->mode == USB_DR_MODE_OTG) {
if (of_property_read_bool(np, "usb-role-switch")) {
err = tegra_xusb_setup_usb_role_switch(port);
if (err < 0)
return err;
} else {
dev_err(&port->dev, "usb-role-switch not found for %s mode",
modes[usb2->mode]);
return -EINVAL;
}
}
usb2->supply = regulator_get(&port->dev, "vbus");
return PTR_ERR_OR_ZERO(usb2->supply); return PTR_ERR_OR_ZERO(usb2->supply);
} }
@ -591,7 +760,7 @@ static int tegra_xusb_add_usb2_port(struct tegra_xusb_padctl *padctl,
if (!np || !of_device_is_available(np)) if (!np || !of_device_is_available(np))
goto out; goto out;
usb2 = devm_kzalloc(padctl->dev, sizeof(*usb2), GFP_KERNEL); usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL);
if (!usb2) { if (!usb2) {
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
@ -622,6 +791,20 @@ out:
return err; return err;
} }
void tegra_xusb_usb2_port_release(struct tegra_xusb_port *port)
{
struct tegra_xusb_usb2_port *usb2 = to_usb2_port(port);
kfree(usb2);
}
void tegra_xusb_usb2_port_remove(struct tegra_xusb_port *port)
{
struct tegra_xusb_usb2_port *usb2 = to_usb2_port(port);
regulator_put(usb2->supply);
}
static int tegra_xusb_ulpi_port_parse_dt(struct tegra_xusb_ulpi_port *ulpi) static int tegra_xusb_ulpi_port_parse_dt(struct tegra_xusb_ulpi_port *ulpi)
{ {
struct tegra_xusb_port *port = &ulpi->base; struct tegra_xusb_port *port = &ulpi->base;
@ -643,7 +826,7 @@ static int tegra_xusb_add_ulpi_port(struct tegra_xusb_padctl *padctl,
if (!np || !of_device_is_available(np)) if (!np || !of_device_is_available(np))
goto out; goto out;
ulpi = devm_kzalloc(padctl->dev, sizeof(*ulpi), GFP_KERNEL); ulpi = kzalloc(sizeof(*ulpi), GFP_KERNEL);
if (!ulpi) { if (!ulpi) {
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
@ -674,6 +857,13 @@ out:
return err; return err;
} }
void tegra_xusb_ulpi_port_release(struct tegra_xusb_port *port)
{
struct tegra_xusb_ulpi_port *ulpi = to_ulpi_port(port);
kfree(ulpi);
}
static int tegra_xusb_hsic_port_parse_dt(struct tegra_xusb_hsic_port *hsic) static int tegra_xusb_hsic_port_parse_dt(struct tegra_xusb_hsic_port *hsic)
{ {
/* XXX */ /* XXX */
@ -691,7 +881,7 @@ static int tegra_xusb_add_hsic_port(struct tegra_xusb_padctl *padctl,
if (!np || !of_device_is_available(np)) if (!np || !of_device_is_available(np))
goto out; goto out;
hsic = devm_kzalloc(padctl->dev, sizeof(*hsic), GFP_KERNEL); hsic = kzalloc(sizeof(*hsic), GFP_KERNEL);
if (!hsic) { if (!hsic) {
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
@ -722,10 +912,18 @@ out:
return err; return err;
} }
void tegra_xusb_hsic_port_release(struct tegra_xusb_port *port)
{
struct tegra_xusb_hsic_port *hsic = to_hsic_port(port);
kfree(hsic);
}
static int tegra_xusb_usb3_port_parse_dt(struct tegra_xusb_usb3_port *usb3) static int tegra_xusb_usb3_port_parse_dt(struct tegra_xusb_usb3_port *usb3)
{ {
struct tegra_xusb_port *port = &usb3->base; struct tegra_xusb_port *port = &usb3->base;
struct device_node *np = port->dev.of_node; struct device_node *np = port->dev.of_node;
enum usb_device_speed maximum_speed;
u32 value; u32 value;
int err; int err;
@ -739,7 +937,17 @@ static int tegra_xusb_usb3_port_parse_dt(struct tegra_xusb_usb3_port *usb3)
usb3->internal = of_property_read_bool(np, "nvidia,internal"); usb3->internal = of_property_read_bool(np, "nvidia,internal");
usb3->supply = devm_regulator_get(&port->dev, "vbus"); if (device_property_present(&port->dev, "maximum-speed")) {
maximum_speed = usb_get_maximum_speed(&port->dev);
if (maximum_speed == USB_SPEED_SUPER)
usb3->disable_gen2 = true;
else if (maximum_speed == USB_SPEED_SUPER_PLUS)
usb3->disable_gen2 = false;
else
return -EINVAL;
}
usb3->supply = regulator_get(&port->dev, "vbus");
return PTR_ERR_OR_ZERO(usb3->supply); return PTR_ERR_OR_ZERO(usb3->supply);
} }
@ -759,7 +967,7 @@ static int tegra_xusb_add_usb3_port(struct tegra_xusb_padctl *padctl,
if (!np || !of_device_is_available(np)) if (!np || !of_device_is_available(np))
goto out; goto out;
usb3 = devm_kzalloc(padctl->dev, sizeof(*usb3), GFP_KERNEL); usb3 = kzalloc(sizeof(*usb3), GFP_KERNEL);
if (!usb3) { if (!usb3) {
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
@ -790,6 +998,20 @@ out:
return err; return err;
} }
void tegra_xusb_usb3_port_release(struct tegra_xusb_port *port)
{
struct tegra_xusb_usb3_port *usb3 = to_usb3_port(port);
kfree(usb3);
}
void tegra_xusb_usb3_port_remove(struct tegra_xusb_port *port)
{
struct tegra_xusb_usb3_port *usb3 = to_usb3_port(port);
regulator_put(usb3->supply);
}
static void __tegra_xusb_remove_ports(struct tegra_xusb_padctl *padctl) static void __tegra_xusb_remove_ports(struct tegra_xusb_padctl *padctl)
{ {
struct tegra_xusb_port *port, *tmp; struct tegra_xusb_port *port, *tmp;
@ -1001,7 +1223,13 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
err = tegra_xusb_setup_ports(padctl); err = tegra_xusb_setup_ports(padctl);
if (err) { if (err) {
dev_err(&pdev->dev, "failed to setup XUSB ports: %d\n", err); const char *level = KERN_ERR;
if (err == -EPROBE_DEFER)
level = KERN_DEBUG;
dev_printk(level, &pdev->dev,
dev_fmt("failed to setup XUSB ports: %d\n"), err);
goto remove_pads; goto remove_pads;
} }
@ -1143,6 +1371,27 @@ int tegra_phy_xusb_utmi_port_reset(struct phy *phy)
} }
EXPORT_SYMBOL_GPL(tegra_phy_xusb_utmi_port_reset); EXPORT_SYMBOL_GPL(tegra_phy_xusb_utmi_port_reset);
int tegra_xusb_padctl_get_usb3_companion(struct tegra_xusb_padctl *padctl,
unsigned int port)
{
struct tegra_xusb_usb2_port *usb2;
struct tegra_xusb_usb3_port *usb3;
int i;
usb2 = tegra_xusb_find_usb2_port(padctl, port);
if (!usb2)
return -EINVAL;
for (i = 0; i < padctl->soc->ports.usb3.count; i++) {
usb3 = tegra_xusb_find_usb3_port(padctl, i);
if (usb3 && usb3->port == usb2->base.index)
return usb3->base.index;
}
return -ENODEV;
}
EXPORT_SYMBOL_GPL(tegra_xusb_padctl_get_usb3_companion);
MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
MODULE_DESCRIPTION("Tegra XUSB Pad Controller driver"); MODULE_DESCRIPTION("Tegra XUSB Pad Controller driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");

View File

@ -12,6 +12,7 @@
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/usb/otg.h> #include <linux/usb/otg.h>
#include <linux/usb/role.h>
/* legacy entry points for backwards-compatibility */ /* legacy entry points for backwards-compatibility */
int tegra_xusb_padctl_legacy_probe(struct platform_device *pdev); int tegra_xusb_padctl_legacy_probe(struct platform_device *pdev);
@ -266,9 +267,18 @@ struct tegra_xusb_port {
struct list_head list; struct list_head list;
struct device dev; struct device dev;
struct usb_role_switch *usb_role_sw;
struct work_struct usb_phy_work;
struct usb_phy usb_phy;
const struct tegra_xusb_port_ops *ops; const struct tegra_xusb_port_ops *ops;
}; };
static inline struct tegra_xusb_port *to_tegra_xusb_port(struct device *dev)
{
return container_of(dev, struct tegra_xusb_port, dev);
}
struct tegra_xusb_lane_map { struct tegra_xusb_lane_map {
unsigned int port; unsigned int port;
const char *type; const char *type;
@ -303,6 +313,8 @@ to_usb2_port(struct tegra_xusb_port *port)
struct tegra_xusb_usb2_port * struct tegra_xusb_usb2_port *
tegra_xusb_find_usb2_port(struct tegra_xusb_padctl *padctl, tegra_xusb_find_usb2_port(struct tegra_xusb_padctl *padctl,
unsigned int index); unsigned int index);
void tegra_xusb_usb2_port_release(struct tegra_xusb_port *port);
void tegra_xusb_usb2_port_remove(struct tegra_xusb_port *port);
struct tegra_xusb_ulpi_port { struct tegra_xusb_ulpi_port {
struct tegra_xusb_port base; struct tegra_xusb_port base;
@ -317,6 +329,8 @@ to_ulpi_port(struct tegra_xusb_port *port)
return container_of(port, struct tegra_xusb_ulpi_port, base); return container_of(port, struct tegra_xusb_ulpi_port, base);
} }
void tegra_xusb_ulpi_port_release(struct tegra_xusb_port *port);
struct tegra_xusb_hsic_port { struct tegra_xusb_hsic_port {
struct tegra_xusb_port base; struct tegra_xusb_port base;
}; };
@ -327,12 +341,15 @@ to_hsic_port(struct tegra_xusb_port *port)
return container_of(port, struct tegra_xusb_hsic_port, base); return container_of(port, struct tegra_xusb_hsic_port, base);
} }
void tegra_xusb_hsic_port_release(struct tegra_xusb_port *port);
struct tegra_xusb_usb3_port { struct tegra_xusb_usb3_port {
struct tegra_xusb_port base; struct tegra_xusb_port base;
struct regulator *supply; struct regulator *supply;
bool context_saved; bool context_saved;
unsigned int port; unsigned int port;
bool internal; bool internal;
bool disable_gen2;
u32 tap1; u32 tap1;
u32 amp; u32 amp;
@ -349,8 +366,12 @@ to_usb3_port(struct tegra_xusb_port *port)
struct tegra_xusb_usb3_port * struct tegra_xusb_usb3_port *
tegra_xusb_find_usb3_port(struct tegra_xusb_padctl *padctl, tegra_xusb_find_usb3_port(struct tegra_xusb_padctl *padctl,
unsigned int index); unsigned int index);
void tegra_xusb_usb3_port_release(struct tegra_xusb_port *port);
void tegra_xusb_usb3_port_remove(struct tegra_xusb_port *port);
struct tegra_xusb_port_ops { struct tegra_xusb_port_ops {
void (*release)(struct tegra_xusb_port *port);
void (*remove)(struct tegra_xusb_port *port);
int (*enable)(struct tegra_xusb_port *port); int (*enable)(struct tegra_xusb_port *port);
void (*disable)(struct tegra_xusb_port *port); void (*disable)(struct tegra_xusb_port *port);
struct tegra_xusb_lane *(*map)(struct tegra_xusb_port *port); struct tegra_xusb_lane *(*map)(struct tegra_xusb_port *port);
@ -392,6 +413,7 @@ struct tegra_xusb_padctl_soc {
const char * const *supply_names; const char * const *supply_names;
unsigned int num_supplies; unsigned int num_supplies;
bool supports_gen2;
bool need_fake_usb3_port; bool need_fake_usb3_port;
}; };
@ -448,5 +470,8 @@ extern const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc;
#if defined(CONFIG_ARCH_TEGRA_186_SOC) #if defined(CONFIG_ARCH_TEGRA_186_SOC)
extern const struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc; extern const struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc;
#endif #endif
#if defined(CONFIG_ARCH_TEGRA_194_SOC)
extern const struct tegra_xusb_padctl_soc tegra194_xusb_padctl_soc;
#endif
#endif /* __PHY_TEGRA_XUSB_H */ #endif /* __PHY_TEGRA_XUSB_H */

View File

@ -21,4 +21,6 @@ int tegra_xusb_padctl_usb3_set_lfps_detect(struct tegra_xusb_padctl *padctl,
int tegra_xusb_padctl_set_vbus_override(struct tegra_xusb_padctl *padctl, int tegra_xusb_padctl_set_vbus_override(struct tegra_xusb_padctl *padctl,
bool val); bool val);
int tegra_phy_xusb_utmi_port_reset(struct phy *phy); int tegra_phy_xusb_utmi_port_reset(struct phy *phy);
int tegra_xusb_padctl_get_usb3_companion(struct tegra_xusb_padctl *padctl,
unsigned int port);
#endif /* PHY_TEGRA_XUSB_H */ #endif /* PHY_TEGRA_XUSB_H */