Skip to content

Commit 49d46e3

Browse files
Nagarjuna Kristamthierryreding
authored andcommitted
phy: tegra: xusb: Add set_mode support for UTMI phy on Tegra186
Add support for set_mode on UTMI phy. This allow XUSB host/device mode drivers to configure the hardware to corresponding modes. Signed-off-by: Nagarjuna Kristam <[email protected]> Acked-by: Kishon Vijay Abraham I <[email protected]> Signed-off-by: Thierry Reding <[email protected]>
1 parent de792a6 commit 49d46e3

File tree

1 file changed

+92
-22
lines changed

1 file changed

+92
-22
lines changed

drivers/phy/tegra/xusb-tegra186.c

Lines changed: 92 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,97 @@ static void tegra_phy_xusb_utmi_pad_power_down(struct phy *phy)
301301
tegra186_utmi_bias_pad_power_off(padctl);
302302
}
303303

304+
static int tegra186_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
305+
bool status)
306+
{
307+
u32 value;
308+
309+
dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear");
310+
311+
value = padctl_readl(padctl, USB2_VBUS_ID);
312+
313+
if (status) {
314+
value |= VBUS_OVERRIDE;
315+
value &= ~ID_OVERRIDE(~0);
316+
value |= ID_OVERRIDE_FLOATING;
317+
} else {
318+
value &= ~VBUS_OVERRIDE;
319+
}
320+
321+
padctl_writel(padctl, value, USB2_VBUS_ID);
322+
323+
return 0;
324+
}
325+
326+
static int tegra186_xusb_padctl_id_override(struct tegra_xusb_padctl *padctl,
327+
bool status)
328+
{
329+
u32 value;
330+
331+
dev_dbg(padctl->dev, "%s id override\n", status ? "set" : "clear");
332+
333+
value = padctl_readl(padctl, USB2_VBUS_ID);
334+
335+
if (status) {
336+
if (value & VBUS_OVERRIDE) {
337+
value &= ~VBUS_OVERRIDE;
338+
padctl_writel(padctl, value, USB2_VBUS_ID);
339+
usleep_range(1000, 2000);
340+
341+
value = padctl_readl(padctl, USB2_VBUS_ID);
342+
}
343+
344+
value &= ~ID_OVERRIDE(~0);
345+
value |= ID_OVERRIDE_GROUNDED;
346+
} else {
347+
value &= ~ID_OVERRIDE(~0);
348+
value |= ID_OVERRIDE_FLOATING;
349+
}
350+
351+
padctl_writel(padctl, value, USB2_VBUS_ID);
352+
353+
return 0;
354+
}
355+
356+
static int tegra186_utmi_phy_set_mode(struct phy *phy, enum phy_mode mode,
357+
int submode)
358+
{
359+
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
360+
struct tegra_xusb_padctl *padctl = lane->pad->padctl;
361+
struct tegra_xusb_usb2_port *port = tegra_xusb_find_usb2_port(padctl,
362+
lane->index);
363+
int err = 0;
364+
365+
mutex_lock(&padctl->lock);
366+
367+
dev_dbg(&port->base.dev, "%s: mode %d", __func__, mode);
368+
369+
if (mode == PHY_MODE_USB_OTG) {
370+
if (submode == USB_ROLE_HOST) {
371+
tegra186_xusb_padctl_id_override(padctl, true);
372+
373+
err = regulator_enable(port->supply);
374+
} else if (submode == USB_ROLE_DEVICE) {
375+
tegra186_xusb_padctl_vbus_override(padctl, true);
376+
} else if (submode == USB_ROLE_NONE) {
377+
/*
378+
* When port is peripheral only or role transitions to
379+
* USB_ROLE_NONE from USB_ROLE_DEVICE, regulator is not
380+
* enabled.
381+
*/
382+
if (regulator_is_enabled(port->supply))
383+
regulator_disable(port->supply);
384+
385+
tegra186_xusb_padctl_id_override(padctl, false);
386+
tegra186_xusb_padctl_vbus_override(padctl, false);
387+
}
388+
}
389+
390+
mutex_unlock(&padctl->lock);
391+
392+
return err;
393+
}
394+
304395
static int tegra186_utmi_phy_power_on(struct phy *phy)
305396
{
306397
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
@@ -439,6 +530,7 @@ static const struct phy_ops utmi_phy_ops = {
439530
.exit = tegra186_utmi_phy_exit,
440531
.power_on = tegra186_utmi_phy_power_on,
441532
.power_off = tegra186_utmi_phy_power_off,
533+
.set_mode = tegra186_utmi_phy_set_mode,
442534
.owner = THIS_MODULE,
443535
};
444536

@@ -857,28 +949,6 @@ static void tegra186_xusb_padctl_remove(struct tegra_xusb_padctl *padctl)
857949
{
858950
}
859951

860-
static int tegra186_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
861-
bool status)
862-
{
863-
u32 value;
864-
865-
dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear");
866-
867-
value = padctl_readl(padctl, USB2_VBUS_ID);
868-
869-
if (status) {
870-
value |= VBUS_OVERRIDE;
871-
value &= ~ID_OVERRIDE(~0);
872-
value |= ID_OVERRIDE_FLOATING;
873-
} else {
874-
value &= ~VBUS_OVERRIDE;
875-
}
876-
877-
padctl_writel(padctl, value, USB2_VBUS_ID);
878-
879-
return 0;
880-
}
881-
882952
static const struct tegra_xusb_padctl_ops tegra186_xusb_padctl_ops = {
883953
.probe = tegra186_xusb_padctl_probe,
884954
.remove = tegra186_xusb_padctl_remove,

0 commit comments

Comments
 (0)