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

Commit 6e738432 authored by Roger Quadros's avatar Roger Quadros Committed by Kishon Vijay Abraham I
Browse files

phy: ti-pipe3: Disable clocks on system suspend



On system suspend, the runtime_suspend() driver hook doesn't get
called for USB phy and so the clocks are not disabled in the driver.
This causes the L3INIT_960M_GFCLK and L3INIT_480M_GFCLK to remain
active on the DRA7 platform while in system suspend.

In case of pcie-phy, the runtime_suspend hook gets called after
the suspend hook so we introduce a flag phy->enabled to keep
track if our clocks are enabled or not to prevent multiple
enable/disables.

Add suspend/resume hooks to the driver.
Move enabling/disabling clock code into helper functions.

Reported-by: default avatarNishant Menon <nm@ti.com>
Signed-off-by: default avatarRoger Quadros <rogerq@ti.com>
Signed-off-by: default avatarKishon Vijay Abraham I <kishon@ti.com>
parent ec6f34e5
Loading
Loading
Loading
Loading
+77 −22
Original line number Original line Diff line number Diff line
@@ -28,6 +28,7 @@
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/phy/omap_control_phy.h>
#include <linux/phy/omap_control_phy.h>
#include <linux/of_platform.h>
#include <linux/of_platform.h>
#include <linux/spinlock.h>


#define	PLL_STATUS		0x00000004
#define	PLL_STATUS		0x00000004
#define	PLL_GO			0x00000008
#define	PLL_GO			0x00000008
@@ -82,6 +83,8 @@ struct ti_pipe3 {
	struct clk		*refclk;
	struct clk		*refclk;
	struct clk		*div_clk;
	struct clk		*div_clk;
	struct pipe3_dpll_map	*dpll_map;
	struct pipe3_dpll_map	*dpll_map;
	bool			enabled;
	spinlock_t		lock;	/* serialize clock enable/disable */
};
};


static struct pipe3_dpll_map dpll_map_usb[] = {
static struct pipe3_dpll_map dpll_map_usb[] = {
@@ -307,6 +310,7 @@ static int ti_pipe3_probe(struct platform_device *pdev)
		return -ENOMEM;
		return -ENOMEM;


	phy->dev		= &pdev->dev;
	phy->dev		= &pdev->dev;
	spin_lock_init(&phy->lock);


	if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
	if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
		match = of_match_device(of_match_ptr(ti_pipe3_id_table),
		match = of_match_device(of_match_ptr(ti_pipe3_id_table),
@@ -427,24 +431,14 @@ static int ti_pipe3_remove(struct platform_device *pdev)


#ifdef CONFIG_PM
#ifdef CONFIG_PM


static int ti_pipe3_runtime_suspend(struct device *dev)
static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy)
{
{
	struct ti_pipe3	*phy = dev_get_drvdata(dev);
	int ret = 0;

	unsigned long flags;
	if (!IS_ERR(phy->wkupclk))
		clk_disable_unprepare(phy->wkupclk);
	if (!IS_ERR(phy->refclk))
		clk_disable_unprepare(phy->refclk);
	if (!IS_ERR(phy->div_clk))
		clk_disable_unprepare(phy->div_clk);

	return 0;
}


static int ti_pipe3_runtime_resume(struct device *dev)
	spin_lock_irqsave(&phy->lock, flags);
{
	if (phy->enabled)
	u32 ret = 0;
		goto err1;
	struct ti_pipe3	*phy = dev_get_drvdata(dev);


	if (!IS_ERR(phy->refclk)) {
	if (!IS_ERR(phy->refclk)) {
		ret = clk_prepare_enable(phy->refclk);
		ret = clk_prepare_enable(phy->refclk);
@@ -469,6 +463,9 @@ static int ti_pipe3_runtime_resume(struct device *dev)
			goto err3;
			goto err3;
		}
		}
	}
	}

	phy->enabled = true;
	spin_unlock_irqrestore(&phy->lock, flags);
	return 0;
	return 0;


err3:
err3:
@@ -480,19 +477,77 @@ err2:
		clk_disable_unprepare(phy->refclk);
		clk_disable_unprepare(phy->refclk);


err1:
err1:
	spin_unlock_irqrestore(&phy->lock, flags);
	return ret;
}

static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy)
{
	unsigned long flags;

	spin_lock_irqsave(&phy->lock, flags);
	if (!phy->enabled) {
		spin_unlock_irqrestore(&phy->lock, flags);
		return;
	}

	if (!IS_ERR(phy->wkupclk))
		clk_disable_unprepare(phy->wkupclk);
	if (!IS_ERR(phy->refclk))
		clk_disable_unprepare(phy->refclk);
	if (!IS_ERR(phy->div_clk))
		clk_disable_unprepare(phy->div_clk);
	phy->enabled = false;
	spin_unlock_irqrestore(&phy->lock, flags);
}

static int ti_pipe3_runtime_suspend(struct device *dev)
{
	struct ti_pipe3	*phy = dev_get_drvdata(dev);

	ti_pipe3_disable_clocks(phy);
	return 0;
}

static int ti_pipe3_runtime_resume(struct device *dev)
{
	struct ti_pipe3	*phy = dev_get_drvdata(dev);
	int ret = 0;

	ret = ti_pipe3_enable_clocks(phy);
	return ret;
	return ret;
}
}


static int ti_pipe3_suspend(struct device *dev)
{
	struct ti_pipe3	*phy = dev_get_drvdata(dev);

	ti_pipe3_disable_clocks(phy);
	return 0;
}

static int ti_pipe3_resume(struct device *dev)
{
	struct ti_pipe3	*phy = dev_get_drvdata(dev);
	int ret;

	ret = ti_pipe3_enable_clocks(phy);
	if (ret)
		return ret;

	pm_runtime_disable(dev);
	pm_runtime_set_active(dev);
	pm_runtime_enable(dev);
	return 0;
}
#endif

static const struct dev_pm_ops ti_pipe3_pm_ops = {
static const struct dev_pm_ops ti_pipe3_pm_ops = {
	SET_RUNTIME_PM_OPS(ti_pipe3_runtime_suspend,
	SET_RUNTIME_PM_OPS(ti_pipe3_runtime_suspend,
			   ti_pipe3_runtime_resume, NULL)
			   ti_pipe3_runtime_resume, NULL)
	SET_SYSTEM_SLEEP_PM_OPS(ti_pipe3_suspend, ti_pipe3_resume)
};
};


#define DEV_PM_OPS     (&ti_pipe3_pm_ops)
#else
#define DEV_PM_OPS     NULL
#endif

#ifdef CONFIG_OF
#ifdef CONFIG_OF
static const struct of_device_id ti_pipe3_id_table[] = {
static const struct of_device_id ti_pipe3_id_table[] = {
	{
	{
@@ -520,7 +575,7 @@ static struct platform_driver ti_pipe3_driver = {
	.remove		= ti_pipe3_remove,
	.remove		= ti_pipe3_remove,
	.driver		= {
	.driver		= {
		.name	= "ti-pipe3",
		.name	= "ti-pipe3",
		.pm	= DEV_PM_OPS,
		.pm	= &ti_pipe3_pm_ops,
		.of_match_table = of_match_ptr(ti_pipe3_id_table),
		.of_match_table = of_match_ptr(ti_pipe3_id_table),
	},
	},
};
};