Commit 5beb1e60 authored by Miquel Raynal's avatar Miquel Raynal Committed by Stephen Boyd
Browse files

clk: mvebu: armada-37xx-periph: add suspend/resume support



Add suspend/resume hooks in Armada 37xx peripheral clocks driver to
handle S2RAM operations.

One can think that these hooks are useless by comparing the register
values before and after a suspend/resume cycle: they will look the same
anyway. This is because of some scripts executed by the Cortex-M3 core
during ATF operations to init both the clocks and the DDR. These values
could be modified by the BL33 stage or by Linux itself and should be
preserved.

Signed-off-by: default avatarMiquel Raynal <miquel.raynal@bootlin.com>
Signed-off-by: default avatarStephen Boyd <sboyd@kernel.org>
parent d9d95e78
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
@@ -57,6 +57,14 @@ struct clk_periph_driver_data {
	struct clk_hw_onecell_data *hw_data;
	spinlock_t lock;
	void __iomem *reg;

	/* Storage registers for suspend/resume operations */
	u32 tbg_sel;
	u32 div_sel0;
	u32 div_sel1;
	u32 div_sel2;
	u32 clk_sel;
	u32 clk_dis;
};

struct clk_double_div {
@@ -673,6 +681,40 @@ static int armada_3700_add_composite_clk(const struct clk_periph_data *data,
	return PTR_ERR_OR_ZERO(*hw);
}

static int __maybe_unused armada_3700_periph_clock_suspend(struct device *dev)
{
	struct clk_periph_driver_data *data = dev_get_drvdata(dev);

	data->tbg_sel = readl(data->reg + TBG_SEL);
	data->div_sel0 = readl(data->reg + DIV_SEL0);
	data->div_sel1 = readl(data->reg + DIV_SEL1);
	data->div_sel2 = readl(data->reg + DIV_SEL2);
	data->clk_sel = readl(data->reg + CLK_SEL);
	data->clk_dis = readl(data->reg + CLK_DIS);

	return 0;
}

static int __maybe_unused armada_3700_periph_clock_resume(struct device *dev)
{
	struct clk_periph_driver_data *data = dev_get_drvdata(dev);

	/* Follow the same order than what the Cortex-M3 does (ATF code) */
	writel(data->clk_dis, data->reg + CLK_DIS);
	writel(data->div_sel0, data->reg + DIV_SEL0);
	writel(data->div_sel1, data->reg + DIV_SEL1);
	writel(data->div_sel2, data->reg + DIV_SEL2);
	writel(data->tbg_sel, data->reg + TBG_SEL);
	writel(data->clk_sel, data->reg + CLK_SEL);

	return 0;
}

static const struct dev_pm_ops armada_3700_periph_clock_pm_ops = {
	SET_SYSTEM_SLEEP_PM_OPS(armada_3700_periph_clock_suspend,
				armada_3700_periph_clock_resume)
};

static int armada_3700_periph_clock_probe(struct platform_device *pdev)
{
	struct clk_periph_driver_data *driver_data;
@@ -748,6 +790,7 @@ static struct platform_driver armada_3700_periph_clock_driver = {
	.driver		= {
		.name	= "marvell-armada-3700-periph-clock",
		.of_match_table = armada_3700_periph_clock_of_match,
		.pm	= &armada_3700_periph_clock_pm_ops,
	},
};