Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Thierry Reding <treding@nvidia.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>

authored by

Sowjanya Komatineni and committed by
Thierry Reding
2b8cfd6b 50d4da9b

+37
+21
drivers/clk/tegra/clk-periph.c
··· 3 3 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. 4 4 */ 5 5 6 + #include <linux/clk.h> 6 7 #include <linux/clk-provider.h> 7 8 #include <linux/export.h> 8 9 #include <linux/slab.h> ··· 100 99 gate_ops->disable(gate_hw); 101 100 } 102 101 102 + static void clk_periph_restore_context(struct clk_hw *hw) 103 + { 104 + struct tegra_clk_periph *periph = to_clk_periph(hw); 105 + const struct clk_ops *div_ops = periph->div_ops; 106 + struct clk_hw *div_hw = &periph->divider.hw; 107 + int parent_id; 108 + 109 + parent_id = clk_hw_get_parent_index(hw); 110 + if (WARN_ON(parent_id < 0)) 111 + return; 112 + 113 + if (!(periph->gate.flags & TEGRA_PERIPH_NO_DIV)) 114 + div_ops->restore_context(div_hw); 115 + 116 + clk_periph_set_parent(hw, parent_id); 117 + } 118 + 103 119 const struct clk_ops tegra_clk_periph_ops = { 104 120 .get_parent = clk_periph_get_parent, 105 121 .set_parent = clk_periph_set_parent, ··· 126 108 .is_enabled = clk_periph_is_enabled, 127 109 .enable = clk_periph_enable, 128 110 .disable = clk_periph_disable, 111 + .restore_context = clk_periph_restore_context, 129 112 }; 130 113 131 114 static const struct clk_ops tegra_clk_periph_nodiv_ops = { ··· 135 116 .is_enabled = clk_periph_is_enabled, 136 117 .enable = clk_periph_enable, 137 118 .disable = clk_periph_disable, 119 + .restore_context = clk_periph_restore_context, 138 120 }; 139 121 140 122 static const struct clk_ops tegra_clk_periph_no_gate_ops = { ··· 144 124 .recalc_rate = clk_periph_recalc_rate, 145 125 .round_rate = clk_periph_round_rate, 146 126 .set_rate = clk_periph_set_rate, 127 + .restore_context = clk_periph_restore_context, 147 128 }; 148 129 149 130 static struct clk *_tegra_clk_register_periph(const char *name,
+16
drivers/clk/tegra/clk-sdmmc-mux.c
··· 194 194 gate_ops->disable(gate_hw); 195 195 } 196 196 197 + static void clk_sdmmc_mux_restore_context(struct clk_hw *hw) 198 + { 199 + struct clk_hw *parent = clk_hw_get_parent(hw); 200 + unsigned long parent_rate = clk_hw_get_rate(parent); 201 + unsigned long rate = clk_hw_get_rate(hw); 202 + int parent_id; 203 + 204 + parent_id = clk_hw_get_parent_index(hw); 205 + if (WARN_ON(parent_id < 0)) 206 + return; 207 + 208 + clk_sdmmc_mux_set_parent(hw, parent_id); 209 + clk_sdmmc_mux_set_rate(hw, rate, parent_rate); 210 + } 211 + 197 212 static const struct clk_ops tegra_clk_sdmmc_mux_ops = { 198 213 .get_parent = clk_sdmmc_mux_get_parent, 199 214 .set_parent = clk_sdmmc_mux_set_parent, ··· 218 203 .is_enabled = clk_sdmmc_mux_is_enabled, 219 204 .enable = clk_sdmmc_mux_enable, 220 205 .disable = clk_sdmmc_mux_disable, 206 + .restore_context = clk_sdmmc_mux_restore_context, 221 207 }; 222 208 223 209 struct clk *tegra_clk_register_sdmmc_mux_div(const char *name,