summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiquel Raynal <miquel.raynal@bootlin.com>2018-07-13 15:44:46 +0200
committerStephen Boyd <sboyd@kernel.org>2018-08-31 10:47:48 -0700
commit5beb1e60dba973e0b9cfb54d9735d5d4385b9d90 (patch)
tree1ebebd94ce6910f5c481613bb6ef3a43335ea060
parentd9d95e78cff80c3fe43e757ba90644cd766302ac (diff)
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: Miquel Raynal <miquel.raynal@bootlin.com> Signed-off-by: Stephen Boyd <sboyd@kernel.org>
-rw-r--r--drivers/clk/mvebu/armada-37xx-periph.c43
1 files changed, 43 insertions, 0 deletions
diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c
index 78048c2e3774..1f1cff428d78 100644
--- a/drivers/clk/mvebu/armada-37xx-periph.c
+++ b/drivers/clk/mvebu/armada-37xx-periph.c
@@ -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,
},
};