Skip to content

Commit c545a90

Browse files
jckuothierryreding
authored andcommitted
phy: tegra: xusb: Add sleepwalk and suspend/resume
This commit adds sleepwalk/wake and suspend/resume interfaces to Tegra XUSB PHY driver. Tegra XUSB host controller driver makes use of sleepwalk functions to enable/disable sleepwalk circuit which is in always-on partition and can respond to USB resume signals when controller is not powered. Sleepwalk can be enabled/disabled for any USB UPHY individually. - tegra_xusb_padctl_enable_phy_sleepwalk() - tegra_xusb_padctl_disable_phy_sleepwalk() Tegra XUSB host controller driver makes use of wake functions to enable/disable/query wake circuit which is in always-on partition can wake system up when USB resume happens. Wake circuit can be enabled/disabled for any USB PHY individually. - tegra_xusb_padctl_enable_phy_wake() - tegra_xusb_padctl_disable_phy_wake() - tegra_xusb_padctl_remote_wake_detected() This commit also adds two system suspend stubs that can be used to save and restore XUSB PADCTL context during system suspend and resume. - tegra_xusb_padctl_suspend_noirq() - tegra_xusb_padctl_resume_noirq() Signed-off-by: JC Kuo <[email protected]> Acked-By: Vinod Koul <[email protected]> Signed-off-by: Thierry Reding <[email protected]>
1 parent c339605 commit c545a90

File tree

3 files changed

+99
-1
lines changed

3 files changed

+99
-1
lines changed

drivers/phy/tegra/xusb.c

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1273,10 +1273,36 @@ static int tegra_xusb_padctl_remove(struct platform_device *pdev)
12731273
return err;
12741274
}
12751275

1276+
static int tegra_xusb_padctl_suspend_noirq(struct device *dev)
1277+
{
1278+
struct tegra_xusb_padctl *padctl = dev_get_drvdata(dev);
1279+
1280+
if (padctl->soc && padctl->soc->ops && padctl->soc->ops->suspend_noirq)
1281+
return padctl->soc->ops->suspend_noirq(padctl);
1282+
1283+
return 0;
1284+
}
1285+
1286+
static int tegra_xusb_padctl_resume_noirq(struct device *dev)
1287+
{
1288+
struct tegra_xusb_padctl *padctl = dev_get_drvdata(dev);
1289+
1290+
if (padctl->soc && padctl->soc->ops && padctl->soc->ops->resume_noirq)
1291+
return padctl->soc->ops->resume_noirq(padctl);
1292+
1293+
return 0;
1294+
}
1295+
1296+
static const struct dev_pm_ops tegra_xusb_padctl_pm_ops = {
1297+
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(tegra_xusb_padctl_suspend_noirq,
1298+
tegra_xusb_padctl_resume_noirq)
1299+
};
1300+
12761301
static struct platform_driver tegra_xusb_padctl_driver = {
12771302
.driver = {
12781303
.name = "tegra-xusb-padctl",
12791304
.of_match_table = tegra_xusb_padctl_of_match,
1305+
.pm = &tegra_xusb_padctl_pm_ops,
12801306
},
12811307
.probe = tegra_xusb_padctl_probe,
12821308
.remove = tegra_xusb_padctl_remove,
@@ -1343,6 +1369,62 @@ int tegra_xusb_padctl_hsic_set_idle(struct tegra_xusb_padctl *padctl,
13431369
}
13441370
EXPORT_SYMBOL_GPL(tegra_xusb_padctl_hsic_set_idle);
13451371

1372+
int tegra_xusb_padctl_enable_phy_sleepwalk(struct tegra_xusb_padctl *padctl, struct phy *phy,
1373+
enum usb_device_speed speed)
1374+
{
1375+
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
1376+
1377+
if (lane->pad->ops->enable_phy_sleepwalk)
1378+
return lane->pad->ops->enable_phy_sleepwalk(lane, speed);
1379+
1380+
return -EOPNOTSUPP;
1381+
}
1382+
EXPORT_SYMBOL_GPL(tegra_xusb_padctl_enable_phy_sleepwalk);
1383+
1384+
int tegra_xusb_padctl_disable_phy_sleepwalk(struct tegra_xusb_padctl *padctl, struct phy *phy)
1385+
{
1386+
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
1387+
1388+
if (lane->pad->ops->disable_phy_sleepwalk)
1389+
return lane->pad->ops->disable_phy_sleepwalk(lane);
1390+
1391+
return -EOPNOTSUPP;
1392+
}
1393+
EXPORT_SYMBOL_GPL(tegra_xusb_padctl_disable_phy_sleepwalk);
1394+
1395+
int tegra_xusb_padctl_enable_phy_wake(struct tegra_xusb_padctl *padctl, struct phy *phy)
1396+
{
1397+
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
1398+
1399+
if (lane->pad->ops->enable_phy_wake)
1400+
return lane->pad->ops->enable_phy_wake(lane);
1401+
1402+
return -EOPNOTSUPP;
1403+
}
1404+
EXPORT_SYMBOL_GPL(tegra_xusb_padctl_enable_phy_wake);
1405+
1406+
int tegra_xusb_padctl_disable_phy_wake(struct tegra_xusb_padctl *padctl, struct phy *phy)
1407+
{
1408+
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
1409+
1410+
if (lane->pad->ops->disable_phy_wake)
1411+
return lane->pad->ops->disable_phy_wake(lane);
1412+
1413+
return -EOPNOTSUPP;
1414+
}
1415+
EXPORT_SYMBOL_GPL(tegra_xusb_padctl_disable_phy_wake);
1416+
1417+
bool tegra_xusb_padctl_remote_wake_detected(struct tegra_xusb_padctl *padctl, struct phy *phy)
1418+
{
1419+
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
1420+
1421+
if (lane->pad->ops->remote_wake_detected)
1422+
return lane->pad->ops->remote_wake_detected(lane);
1423+
1424+
return false;
1425+
}
1426+
EXPORT_SYMBOL_GPL(tegra_xusb_padctl_remote_wake_detected);
1427+
13461428
int tegra_xusb_padctl_usb3_set_lfps_detect(struct tegra_xusb_padctl *padctl,
13471429
unsigned int port, bool enable)
13481430
{

drivers/phy/tegra/xusb.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/mutex.h>
1212
#include <linux/workqueue.h>
1313

14+
#include <linux/usb/ch9.h>
1415
#include <linux/usb/otg.h>
1516
#include <linux/usb/role.h>
1617

@@ -132,6 +133,11 @@ struct tegra_xusb_lane_ops {
132133
void (*remove)(struct tegra_xusb_lane *lane);
133134
void (*iddq_enable)(struct tegra_xusb_lane *lane);
134135
void (*iddq_disable)(struct tegra_xusb_lane *lane);
136+
int (*enable_phy_sleepwalk)(struct tegra_xusb_lane *lane, enum usb_device_speed speed);
137+
int (*disable_phy_sleepwalk)(struct tegra_xusb_lane *lane);
138+
int (*enable_phy_wake)(struct tegra_xusb_lane *lane);
139+
int (*disable_phy_wake)(struct tegra_xusb_lane *lane);
140+
bool (*remote_wake_detected)(struct tegra_xusb_lane *lane);
135141
};
136142

137143
bool tegra_xusb_lane_check(struct tegra_xusb_lane *lane, const char *function);
@@ -396,6 +402,8 @@ struct tegra_xusb_padctl_ops {
396402
const struct tegra_xusb_padctl_soc *soc);
397403
void (*remove)(struct tegra_xusb_padctl *padctl);
398404

405+
int (*suspend_noirq)(struct tegra_xusb_padctl *padctl);
406+
int (*resume_noirq)(struct tegra_xusb_padctl *padctl);
399407
int (*usb3_save_context)(struct tegra_xusb_padctl *padctl,
400408
unsigned int index);
401409
int (*hsic_set_idle)(struct tegra_xusb_padctl *padctl,

include/linux/phy/tegra/xusb.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
/* SPDX-License-Identifier: GPL-2.0-only */
22
/*
3-
* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3+
* Copyright (c) 2016-2020, NVIDIA CORPORATION. All rights reserved.
44
*/
55

66
#ifndef PHY_TEGRA_XUSB_H
77
#define PHY_TEGRA_XUSB_H
88

99
struct tegra_xusb_padctl;
1010
struct device;
11+
enum usb_device_speed;
1112

1213
struct tegra_xusb_padctl *tegra_xusb_padctl_get(struct device *dev);
1314
void tegra_xusb_padctl_put(struct tegra_xusb_padctl *padctl);
@@ -23,4 +24,11 @@ int tegra_xusb_padctl_set_vbus_override(struct tegra_xusb_padctl *padctl,
2324
int tegra_phy_xusb_utmi_port_reset(struct phy *phy);
2425
int tegra_xusb_padctl_get_usb3_companion(struct tegra_xusb_padctl *padctl,
2526
unsigned int port);
27+
int tegra_xusb_padctl_enable_phy_sleepwalk(struct tegra_xusb_padctl *padctl, struct phy *phy,
28+
enum usb_device_speed speed);
29+
int tegra_xusb_padctl_disable_phy_sleepwalk(struct tegra_xusb_padctl *padctl, struct phy *phy);
30+
int tegra_xusb_padctl_enable_phy_wake(struct tegra_xusb_padctl *padctl, struct phy *phy);
31+
int tegra_xusb_padctl_disable_phy_wake(struct tegra_xusb_padctl *padctl, struct phy *phy);
32+
bool tegra_xusb_padctl_remote_wake_detected(struct tegra_xusb_padctl *padctl, struct phy *phy);
33+
2634
#endif /* PHY_TEGRA_XUSB_H */

0 commit comments

Comments
 (0)