ARM: tegra: usb: enable pmu vbus interrupts
Krishna Yarlagadda [Fri, 1 Jun 2012 11:16:43 +0000 (16:16 +0530)]
Enable pmu vbus interrupt for Enterprise and Whistler
to save power by turning off controller clock

Change-Id: I691bdd76ca71d63d98f83e2a3a18bbfcfc16a473
Signed-off-by: Krishna Yarlagadda <kyarlagadda@nvidia.com>
Reviewed-on: http://git-master/r/105150
Reviewed-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
Tested-by: Rohan Somvanshi <rsomvanshi@nvidia.com>

Conflicts:

drivers/usb/otg/tegra-otg.c

arch/arm/mach-tegra/board-enterprise.c
arch/arm/mach-tegra/board-whistler.c
arch/arm/mach-tegra/tegra_usb_phy.h
arch/arm/mach-tegra/usb_phy.c
drivers/usb/otg/tegra-otg.c

index 201c367..33c05f3 100644 (file)
@@ -689,7 +689,8 @@ static struct tegra_usb_platform_data tegra_udc_pdata = {
        .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
        .op_mode = TEGRA_USB_OPMODE_DEVICE,
        .u_data.dev = {
-               .vbus_pmu_irq = 0,
+               .vbus_pmu_irq = ENT_TPS80031_IRQ_BASE +
+                               TPS80031_INT_VBUS_DET,
                .vbus_gpio = -1,
                .charging_supported = false,
                .remote_wakeup_supported = false,
index bfcb27a..5f19597 100644 (file)
@@ -447,7 +447,7 @@ static struct tegra_usb_platform_data tegra_udc_pdata = {
        .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
        .op_mode = TEGRA_USB_OPMODE_DEVICE,
        .u_data.dev = {
-               .vbus_pmu_irq = 0,
+               .vbus_pmu_irq = MAX8907C_INT_BASE + MAX8907C_IRQ_VCHG_DC_R,
                .vbus_gpio = -1,
                .charging_supported = false,
                .remote_wakeup_supported = false,
index 607ccf2..92ab927 100644 (file)
@@ -89,6 +89,7 @@ struct tegra_usb_phy {
        void __iomem *regs;
        int inst;
        bool phy_clk_on;
+       bool ctrl_clk_on; /* used only for pmu irq */
        bool phy_power_on;
        bool remote_wakeup;
        bool hw_accessible;
index 6b0c2cb..5011bd6 100644 (file)
@@ -135,15 +135,24 @@ int tegra_usb_phy_init_ops(struct tegra_usb_phy *phy)
 
 static irqreturn_t usb_phy_dev_vbus_pmu_irq_thr(int irq, void *pdata)
 {
-       /* FIXME : Need to enable pmu vbus handling */
+       struct tegra_usb_phy *phy = pdata;
 
-       return IRQ_NONE;
+       /* clk is disabled during phy power off and not here*/
+       if (!phy->ctrl_clk_on) {
+               clk_enable(phy->ctrlr_clk);
+               phy->ctrl_clk_on = true;
+       }
+
+       return IRQ_HANDLED;
 }
 
 static void tegra_usb_phy_release_clocks(struct tegra_usb_phy *phy)
 {
        clk_put(phy->emc_clk);
        clk_put(phy->sys_clk);
+       if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST &&
+               phy->pdata->u_data.host.hot_plug)
+               clk_disable(phy->ctrlr_clk);
        clk_put(phy->ctrlr_clk);
        clk_disable(phy->pllu_clk);
        clk_put(phy->pllu_clk);
@@ -168,6 +177,10 @@ static int tegra_usb_phy_get_clocks(struct tegra_usb_phy *phy)
                goto fail_ctrlr_clk;
        }
 
+       if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST &&
+               phy->pdata->u_data.host.hot_plug)
+               clk_enable(phy->ctrlr_clk);
+
        phy->sys_clk = clk_get(&phy->pdev->dev, "sclk");
        if (IS_ERR(phy->sys_clk)) {
                dev_err(&phy->pdev->dev, "Can't get sclk clock\n");
@@ -277,6 +290,8 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct platform_device *pdev)
                                                                phy->inst);
                                goto fail_init;
                        }
+               } else {
+                       clk_enable(phy->ctrlr_clk);
                }
        } else {
                if (phy->pdata->u_data.host.vbus_reg) {
@@ -368,6 +383,8 @@ void tegra_usb_phy_close(struct tegra_usb_phy *phy)
        if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) {
                if (phy->pdata->u_data.dev.vbus_pmu_irq)
                        free_irq(phy->pdata->u_data.dev.vbus_pmu_irq, phy);
+               else
+                       clk_disable(phy->ctrlr_clk);
        } else {
                usb_host_vbus_enable(phy, false);
 
@@ -443,7 +460,18 @@ int tegra_usb_phy_power_off(struct tegra_usb_phy *phy)
 
        clk_disable(phy->emc_clk);
        clk_disable(phy->sys_clk);
-       clk_disable(phy->ctrlr_clk);
+       if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) {
+               if (!phy->pdata->u_data.host.hot_plug)
+                       clk_disable(phy->ctrlr_clk);
+       } else {
+               /* In device mode clock is turned on by pmu irq handler
+                * if pmu irq is not available clocks will not be turned off/on
+                */
+               if (phy->pdata->u_data.dev.vbus_pmu_irq) {
+                       clk_disable(phy->ctrlr_clk);
+                       phy->ctrl_clk_on = false;
+               }
+       }
 
        phy->phy_power_on = false;
 
@@ -459,7 +487,19 @@ int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
        if (phy->phy_power_on)
                return status;
 
-       clk_enable(phy->ctrlr_clk);
+       /* In device mode clock is turned on by pmu irq handler
+        * if pmu irq is not available clocks will not be turned off/on
+        */
+       if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) {
+               if (!phy->pdata->u_data.host.hot_plug)
+                       clk_enable(phy->ctrlr_clk);
+       } else {
+               if (phy->pdata->u_data.dev.vbus_pmu_irq &&
+                       !phy->ctrl_clk_on) {
+                       clk_enable(phy->ctrlr_clk);
+                       phy->ctrl_clk_on = true;
+               }
+       }
        clk_enable(phy->sys_clk);
        clk_enable(phy->emc_clk);
 
index 408cbe9..2229f6b 100644 (file)
@@ -464,6 +464,7 @@ static int tegra_otg_probe(struct platform_device *pdev)
 
        tegra->pdev = pdev;
        tegra->pdata = pdev->dev.platform_data;
+       clk_disable(tegra->clk);
 
        dev_info(&pdev->dev, "otg transceiver registered\n");
        return 0;