Skip to content

Commit

Permalink
CHROMIUM: USB: tegra: turn off usb1/usb3 vbus in suspend
Browse files Browse the repository at this point in the history
Turn off usb1/usb3 vbus in system suspend if the flag
power_down_on_bus_suspend is set, this save ~2mW in suspend.

BUG=chrome-os-partner:4856
TEST=Plug in USB optical mouse in suspend to see if the light
is off, or compare the total power difference in suspend,
it saves ~2mW.

Change-Id: I25cf33e728781a73b68e187bb3adf041708846ff
Signed-off-by: Bill Huang <bilhuang@nvidia.com>
Reviewed-on: http://gerrit.chromium.org/gerrit/4718
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
Tested-by: Vincent Palatin <vpalatin@chromium.org>
  • Loading branch information
Bill Huang authored and vpalatin committed Aug 12, 2011
1 parent c37a91c commit ad2c6fe
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 16 deletions.
3 changes: 2 additions & 1 deletion arch/arm/mach-tegra/board-seaboard-pinmux.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ static __initdata struct tegra_pingroup_config seaboard_pinmux[] = {
{TEGRA_PINGROUP_SDD, TEGRA_MUX_SDIO3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_SDIO1, TEGRA_MUX_SDIO1, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_SLXA, TEGRA_MUX_PCIE, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
{TEGRA_PINGROUP_SLXC, TEGRA_MUX_SPDIF, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
{TEGRA_PINGROUP_SLXC, TEGRA_MUX_SPDIF, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_SLXD, TEGRA_MUX_SPDIF, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_SLXK, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_SPDI, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
Expand Down Expand Up @@ -203,6 +203,7 @@ static struct tegra_gpio_table common_gpio_table[] = {
{ .gpio = TEGRA_GPIO_POWERKEY, .enable = true },
{ .gpio = TEGRA_GPIO_ISL29018_IRQ, .enable = true },
{ .gpio = TEGRA_GPIO_USB1, .enable = true },
{ .gpio = TEGRA_GPIO_USB3, .enable = true },
{ .gpio = TEGRA_GPIO_NCT1008_THERM2_IRQ,.enable = true },
{ .gpio = TEGRA_GPIO_WLAN_POWER, .enable = true },
{ .gpio = TEGRA_GPIO_BACKLIGHT, .enable = true },
Expand Down
21 changes: 8 additions & 13 deletions arch/arm/mach-tegra/board-seaboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ static struct tegra_utmip_config utmi_phy_config[] = {
.xcvr_setup = 15,
.xcvr_lsfslew = 2,
.xcvr_lsrslew = 2,
.vbus_gpio = TEGRA_GPIO_USB1,
},
[1] = {
.hssync_start_delay = 0,
Expand All @@ -118,6 +119,8 @@ static struct tegra_utmip_config utmi_phy_config[] = {
.xcvr_setup = 8,
.xcvr_lsfslew = 2,
.xcvr_lsrslew = 2,
.vbus_gpio = TEGRA_GPIO_USB3,
.shared_pin_vbus_en_oc = true,
},
};

Expand Down Expand Up @@ -774,24 +777,16 @@ static void register_ehci_device(struct platform_device *pdev)

static int seaboard_ehci_init(void)
{
int gpio_status;

/* If we ever have a derivative that doesn't use USB1, make the code
* below conditional
*/
BUG_ON(!tegra_ehci1_device.dev.platform_data);
gpio_status = gpio_request(TEGRA_GPIO_USB1, "VBUS_USB1");
if (gpio_status < 0) {
pr_err("VBUS_USB1 request GPIO FAILED\n");
WARN_ON(1);
}

gpio_status = gpio_direction_output(TEGRA_GPIO_USB1, 1);
if (gpio_status < 0) {
pr_err("VBUS_USB1 request GPIO DIRECTION FAILED\n");
WARN_ON(1);
}
gpio_set_value(TEGRA_GPIO_USB1, 1);
if (utmi_phy_config[0].vbus_gpio)
tegra_usb_phy_utmi_vbus_init(&utmi_phy_config[0], "VBUS_USB1");

if (utmi_phy_config[1].vbus_gpio)
tegra_usb_phy_utmi_vbus_init(&utmi_phy_config[1], "VBUS_USB3");

register_ehci_device(&tegra_ehci1_device);
register_ehci_device(&tegra_ehci2_device);
Expand Down
1 change: 1 addition & 0 deletions arch/arm/mach-tegra/board-seaboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

#define TEGRA_GPIO_LIDSWITCH TEGRA_GPIO_PC7
#define TEGRA_GPIO_USB1 TEGRA_GPIO_PD0
#define TEGRA_GPIO_USB3 TEGRA_GPIO_PD3
#define TEGRA_GPIO_POWERKEY TEGRA_GPIO_PV2
#define TEGRA_GPIO_BACKLIGHT TEGRA_GPIO_PD4
#define TEGRA_GPIO_LVDS_SHUTDOWN TEGRA_GPIO_PB2
Expand Down
9 changes: 9 additions & 0 deletions arch/arm/mach-tegra/include/mach/usb_phy.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ struct tegra_utmip_config {
u8 xcvr_setup;
u8 xcvr_lsfslew;
u8 xcvr_lsrslew;
u8 vbus_gpio;
bool shared_pin_vbus_en_oc;
};

struct tegra_ulpi_config {
Expand Down Expand Up @@ -73,6 +75,13 @@ void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy);

void tegra_usb_phy_power_off(struct tegra_usb_phy *phy);

void tegra_usb_phy_utmi_vbus_init(struct tegra_utmip_config *utmi_config,
const char *label);

void tegra_usb_phy_vbus_on(struct tegra_usb_phy *phy);

void tegra_usb_phy_vbus_off(struct tegra_usb_phy *phy);

void tegra_usb_phy_preresume(struct tegra_usb_phy *phy);

void tegra_usb_phy_postresume(struct tegra_usb_phy *phy);
Expand Down
87 changes: 87 additions & 0 deletions arch/arm/mach-tegra/usb_phy.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,11 @@ static inline bool phy_is_ulpi(struct tegra_usb_phy *phy)
return (phy->instance == 1);
}

static inline bool phy_is_utmi(struct tegra_usb_phy *phy)
{
return (phy->instance != 1);
}

static int utmip_pad_open(struct tegra_usb_phy *phy)
{
phy->pad_clk = clk_get_sys("utmip-pad", NULL);
Expand Down Expand Up @@ -286,6 +291,44 @@ static int utmip_pad_power_off(struct tegra_usb_phy *phy)
return 0;
}

void utmi_phy_vbus_on(struct tegra_usb_phy *phy)
{
struct tegra_utmip_config *config = phy->config;

if (config->vbus_gpio) {
/*
* For those platforms vbus_en and oc are shared, we
* need to change that gpio back to input signal
* for handling the over current event.
*/
if (config->shared_pin_vbus_en_oc)
gpio_direction_input(config->vbus_gpio);
else
gpio_set_value(config->vbus_gpio, 1);
}
}

void utmi_phy_vbus_off(struct tegra_usb_phy *phy)
{
struct tegra_utmip_config *config = phy->config;

if (config->vbus_gpio) {
/*
* For those platforms vbus_en and oc are shared, the default
* state of the signal should be logic '1' meaning it works
* as host port and the over current event should be active
* low. In order to turn off vbus in suspend and also support
* over current event in USB working state, that gpio direction
* should be programmed as input signal except when turning off
* vbus in suspend.
*/
if (config->shared_pin_vbus_en_oc)
gpio_direction_output(config->vbus_gpio, 0);
else
gpio_set_value(config->vbus_gpio, 0);
}
}

static int utmi_wait_register(void __iomem *reg, u32 mask, u32 result)
{
unsigned long timeout = 2000;
Expand Down Expand Up @@ -762,6 +805,50 @@ void tegra_usb_phy_power_off(struct tegra_usb_phy *phy)
utmi_phy_power_off(phy);
}

void tegra_usb_phy_utmi_vbus_init(struct tegra_utmip_config *utmi_config,
const char *label)
{
int gpio_status;

gpio_status = gpio_request(utmi_config->vbus_gpio, label);
if (gpio_status < 0) {
pr_err("%s request GPIO FAILED\n", label);
goto vbus_gpio_init_exit;
}

if (utmi_config->shared_pin_vbus_en_oc)
gpio_status = gpio_direction_input(utmi_config->vbus_gpio);
else
gpio_status = gpio_direction_output(utmi_config->vbus_gpio, 1);

if (gpio_status < 0) {
pr_err("%s request GPIO DIRECTION FAILED\n", label);
gpio_free(utmi_config->vbus_gpio);
goto vbus_gpio_init_exit;
}

if (!utmi_config->shared_pin_vbus_en_oc)
gpio_set_value(utmi_config->vbus_gpio, 1);

vbus_gpio_init_exit:
if (gpio_status < 0) {
WARN_ON(1);
utmi_config->vbus_gpio = 0;
}
}

void tegra_usb_phy_vbus_on(struct tegra_usb_phy *phy)
{
if (phy_is_utmi(phy))
utmi_phy_vbus_on(phy);
}

void tegra_usb_phy_vbus_off(struct tegra_usb_phy *phy)
{
if (phy_is_utmi(phy))
utmi_phy_vbus_off(phy);
}

void tegra_usb_phy_preresume(struct tegra_usb_phy *phy)
{
if (!phy_is_ulpi(phy))
Expand Down
13 changes: 11 additions & 2 deletions drivers/usb/host/ehci-tegra.c
Original file line number Diff line number Diff line change
Expand Up @@ -738,8 +738,10 @@ static int tegra_ehci_resume(struct platform_device *pdev)
struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev);
struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci);

if (tegra->bus_suspended)
if (tegra->bus_suspended) {
tegra_usb_phy_vbus_on(tegra->phy);
return 0;
}

return tegra_usb_resume(hcd);
}
Expand All @@ -749,8 +751,15 @@ static int tegra_ehci_suspend(struct platform_device *pdev, pm_message_t state)
struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev);
struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci);

if (tegra->bus_suspended)
if (tegra->bus_suspended) {
/*
* We turn off vbus for those platforms which are really care
* about USB power consumption, i.e. for those have the flag
* power_down_on_bus_suspend set.
*/
tegra_usb_phy_vbus_off(tegra->phy);
return 0;
}

if (time_before(jiffies, tegra->ehci->next_statechange))
msleep(10);
Expand Down

0 comments on commit ad2c6fe

Please sign in to comment.