Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bd92c12e authored by Mayank Rana's avatar Mayank Rana Committed by Azhar Shaikh
Browse files

usb: phy-msm-qusb: Support low power mode



Enables support for low power mode for QUSB2 PHY.
Allows XO shutdown during bus suspend.

Change-Id: I5ee42112f7c63c957d00889acb26931d2b555f9e
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
Signed-off-by: default avatarAzhar Shaikh <azhars@codeaurora.org>
parent f1a9f6d4
Loading
Loading
Loading
Loading
+40 −17
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/usb/phy.h>
#include <linux/usb/msm_hsusb.h>

#define QUSB2PHY_PORT_POWERDOWN		0xB4
#define CLAMP_N_EN			BIT(5)
@@ -34,6 +35,13 @@
#define QUSB2PHY_PORT_TUNE3             0x88
#define QUSB2PHY_PORT_TUNE4             0x8C

#define QUSB2PHY_PORT_INTR_CTRL         0xBC
#define CHG_DET_INTR_EN                 BIT(4)
#define DMSE_INTR_HIGH_SEL              BIT(3)
#define DMSE_INTR_EN                    BIT(2)
#define DPSE_INTR_HIGH_SEL              BIT(1)
#define DPSE_INTR_EN                    BIT(0)

#define UTMI_OTG_VBUS_VALID             BIT(20)
#define SW_SESSVLD_SEL                  BIT(28)

@@ -246,6 +254,7 @@ static void qusb_write_readback(void *base, u32 offset,
static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend)
{
	struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
	u32 intr_mask = 0;

	if (!qphy->clocks_enabled) {
		dev_dbg(phy->dev, "clocks not enabled yet\n");
@@ -259,26 +268,44 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend)
	}

	if (suspend) {
		/* Suspend case */
		if (qphy->cable_connected) {
			return -EAGAIN;
		/* Bus suspend case */
		if (qphy->cable_connected ||
			(qphy->phy.flags & PHY_HOST_MODE)) {
			/* Clear all interrupts */
			writel_relaxed(0x00,
				qphy->base + QUSB2PHY_PORT_INTR_CTRL);

			/* Enable D+ interrupt */
			intr_mask |= DPSE_INTR_EN;

			/* Select D+ falling edge as the trigger */
			intr_mask &= ~DPSE_INTR_HIGH_SEL;

			writel_relaxed(intr_mask,
				qphy->base + QUSB2PHY_PORT_INTR_CTRL);

			clk_disable_unprepare(qphy->cfg_ahb_clk);
			clk_disable_unprepare(qphy->ref_clk);
		} else { /* Disconnect case */
			/* Disable the PHY */
			writel_relaxed(CLAMP_N_EN | FREEZIO_N | POWER_DOWN,
				qphy->base + QUSB2PHY_PORT_POWERDOWN);
			clk_disable_unprepare(qphy->cfg_ahb_clk);
			clk_disable_unprepare(qphy->ref_clk);
			qusb_phy_enable_power(qphy, false);
		}
		qphy->suspended = true;
	} else {
		/* Bus suspend case */
		if (qphy->cable_connected ||
			(qphy->phy.flags & PHY_HOST_MODE)) {
			clk_prepare_enable(qphy->ref_clk);
			clk_prepare_enable(qphy->cfg_ahb_clk);
			/* Clear all interrupts on resume */
			writel_relaxed(0x00,
				qphy->base + QUSB2PHY_PORT_INTR_CTRL);
		} else {
			qusb_phy_enable_power(qphy, true);
			clk_prepare_enable(qphy->ref_clk);
			clk_prepare_enable(qphy->cfg_ahb_clk);
		/* Enable the PHY */
		writel_relaxed(CLAMP_N_EN | FREEZIO_N,
			qphy->base + QUSB2PHY_PORT_POWERDOWN);
		/* Caller needs to call qusb_phy_init to apply tuning params */
		}
		qphy->suspended = false;
	}

@@ -411,10 +438,6 @@ static int qusb_phy_probe(struct platform_device *pdev)
	if (ret)
		return ret;

	clk_prepare_enable(qphy->ref_clk);
	clk_prepare_enable(qphy->cfg_ahb_clk);
	qphy->clocks_enabled = true;

	platform_set_drvdata(pdev, qphy);

	qphy->phy.label			= "msm-qusb-phy";