Commit 2b8cfd6b authored by Sowjanya Komatineni's avatar Sowjanya Komatineni Committed by Thierry Reding

clk: tegra: periph: Add restore_context support

This patch implements restore_context support for clk-periph and
clk-sdmmc-mux clock operations to restore clock parent and rates
on system resume.

During system suspend, core power goes off and looses the context
of the Tegra clock controller registers.

So on system resume, clocks parent and rate are restored back to
the context before suspend based on cached data.
Acked-by: default avatarThierry Reding <treding@nvidia.com>
Signed-off-by: default avatarSowjanya Komatineni <skomatineni@nvidia.com>
Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
parent 50d4da9b
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*/ */
#include <linux/clk.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -99,6 +100,23 @@ static void clk_periph_disable(struct clk_hw *hw) ...@@ -99,6 +100,23 @@ static void clk_periph_disable(struct clk_hw *hw)
gate_ops->disable(gate_hw); gate_ops->disable(gate_hw);
} }
static void clk_periph_restore_context(struct clk_hw *hw)
{
struct tegra_clk_periph *periph = to_clk_periph(hw);
const struct clk_ops *div_ops = periph->div_ops;
struct clk_hw *div_hw = &periph->divider.hw;
int parent_id;
parent_id = clk_hw_get_parent_index(hw);
if (WARN_ON(parent_id < 0))
return;
if (!(periph->gate.flags & TEGRA_PERIPH_NO_DIV))
div_ops->restore_context(div_hw);
clk_periph_set_parent(hw, parent_id);
}
const struct clk_ops tegra_clk_periph_ops = { const struct clk_ops tegra_clk_periph_ops = {
.get_parent = clk_periph_get_parent, .get_parent = clk_periph_get_parent,
.set_parent = clk_periph_set_parent, .set_parent = clk_periph_set_parent,
...@@ -108,6 +126,7 @@ const struct clk_ops tegra_clk_periph_ops = { ...@@ -108,6 +126,7 @@ const struct clk_ops tegra_clk_periph_ops = {
.is_enabled = clk_periph_is_enabled, .is_enabled = clk_periph_is_enabled,
.enable = clk_periph_enable, .enable = clk_periph_enable,
.disable = clk_periph_disable, .disable = clk_periph_disable,
.restore_context = clk_periph_restore_context,
}; };
static const struct clk_ops tegra_clk_periph_nodiv_ops = { static const struct clk_ops tegra_clk_periph_nodiv_ops = {
...@@ -116,6 +135,7 @@ static const struct clk_ops tegra_clk_periph_nodiv_ops = { ...@@ -116,6 +135,7 @@ static const struct clk_ops tegra_clk_periph_nodiv_ops = {
.is_enabled = clk_periph_is_enabled, .is_enabled = clk_periph_is_enabled,
.enable = clk_periph_enable, .enable = clk_periph_enable,
.disable = clk_periph_disable, .disable = clk_periph_disable,
.restore_context = clk_periph_restore_context,
}; };
static const struct clk_ops tegra_clk_periph_no_gate_ops = { static const struct clk_ops tegra_clk_periph_no_gate_ops = {
...@@ -124,6 +144,7 @@ static const struct clk_ops tegra_clk_periph_no_gate_ops = { ...@@ -124,6 +144,7 @@ static const struct clk_ops tegra_clk_periph_no_gate_ops = {
.recalc_rate = clk_periph_recalc_rate, .recalc_rate = clk_periph_recalc_rate,
.round_rate = clk_periph_round_rate, .round_rate = clk_periph_round_rate,
.set_rate = clk_periph_set_rate, .set_rate = clk_periph_set_rate,
.restore_context = clk_periph_restore_context,
}; };
static struct clk *_tegra_clk_register_periph(const char *name, static struct clk *_tegra_clk_register_periph(const char *name,
......
...@@ -194,6 +194,21 @@ static void clk_sdmmc_mux_disable(struct clk_hw *hw) ...@@ -194,6 +194,21 @@ static void clk_sdmmc_mux_disable(struct clk_hw *hw)
gate_ops->disable(gate_hw); gate_ops->disable(gate_hw);
} }
static void clk_sdmmc_mux_restore_context(struct clk_hw *hw)
{
struct clk_hw *parent = clk_hw_get_parent(hw);
unsigned long parent_rate = clk_hw_get_rate(parent);
unsigned long rate = clk_hw_get_rate(hw);
int parent_id;
parent_id = clk_hw_get_parent_index(hw);
if (WARN_ON(parent_id < 0))
return;
clk_sdmmc_mux_set_parent(hw, parent_id);
clk_sdmmc_mux_set_rate(hw, rate, parent_rate);
}
static const struct clk_ops tegra_clk_sdmmc_mux_ops = { static const struct clk_ops tegra_clk_sdmmc_mux_ops = {
.get_parent = clk_sdmmc_mux_get_parent, .get_parent = clk_sdmmc_mux_get_parent,
.set_parent = clk_sdmmc_mux_set_parent, .set_parent = clk_sdmmc_mux_set_parent,
...@@ -203,6 +218,7 @@ static const struct clk_ops tegra_clk_sdmmc_mux_ops = { ...@@ -203,6 +218,7 @@ static const struct clk_ops tegra_clk_sdmmc_mux_ops = {
.is_enabled = clk_sdmmc_mux_is_enabled, .is_enabled = clk_sdmmc_mux_is_enabled,
.enable = clk_sdmmc_mux_enable, .enable = clk_sdmmc_mux_enable,
.disable = clk_sdmmc_mux_disable, .disable = clk_sdmmc_mux_disable,
.restore_context = clk_sdmmc_mux_restore_context,
}; };
struct clk *tegra_clk_register_sdmmc_mux_div(const char *name, struct clk *tegra_clk_register_sdmmc_mux_div(const char *name,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment