Lines Matching +full:parent +full:- +full:clk
1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2015-2020, NVIDIA CORPORATION. All rights reserved.
7 #include <linux/clk.h>
8 #include <linux/clk-provider.h>
9 #include <linux/clk/tegra.h>
15 #include "clk.h"
37 struct clk *parents[8];
57 value = readl_relaxed(emc->regs + CLK_SOURCE_EMC); in tegra210_clk_emc_get_parent()
70 * CCF assumes that neither the parent nor its rate will change during in tegra210_clk_emc_recalc_rate()
71 * ->set_rate(), so the parent rate passed in here was cached from the in tegra210_clk_emc_recalc_rate()
72 * parent before the ->set_rate() call. in tegra210_clk_emc_recalc_rate()
75 * the parent and/or parent rate have changed as part of the EMC rate in tegra210_clk_emc_recalc_rate()
76 * change sequence. Fix this by overriding the parent clock with what in tegra210_clk_emc_recalc_rate()
81 value = readl_relaxed(emc->regs + CLK_SOURCE_EMC); in tegra210_clk_emc_recalc_rate()
93 struct tegra210_clk_emc_provider *provider = emc->provider; in tegra210_clk_emc_round_rate()
96 if (!provider || !provider->configs || provider->num_configs == 0) in tegra210_clk_emc_round_rate()
99 for (i = 0; i < provider->num_configs; i++) { in tegra210_clk_emc_round_rate()
100 if (provider->configs[i].rate >= rate) in tegra210_clk_emc_round_rate()
101 return provider->configs[i].rate; in tegra210_clk_emc_round_rate()
104 return provider->configs[i - 1].rate; in tegra210_clk_emc_round_rate()
107 static struct clk *tegra210_clk_emc_find_parent(struct tegra210_clk_emc *emc, in tegra210_clk_emc_find_parent()
110 struct clk_hw *parent = clk_hw_get_parent_by_index(&emc->hw, index); in tegra210_clk_emc_find_parent() local
111 const char *name = clk_hw_get_name(parent); in tegra210_clk_emc_find_parent()
122 struct tegra210_clk_emc_provider *provider = emc->provider; in tegra210_clk_emc_set_rate()
124 struct device *dev = provider->dev; in tegra210_clk_emc_set_rate()
125 struct clk_hw *old, *new, *parent; in tegra210_clk_emc_set_rate() local
127 struct clk *clk; in tegra210_clk_emc_set_rate() local
131 if (!provider->configs || provider->num_configs == 0) in tegra210_clk_emc_set_rate()
132 return -EINVAL; in tegra210_clk_emc_set_rate()
134 for (i = 0; i < provider->num_configs; i++) { in tegra210_clk_emc_set_rate()
135 if (provider->configs[i].rate >= rate) { in tegra210_clk_emc_set_rate()
136 config = &provider->configs[i]; in tegra210_clk_emc_set_rate()
141 if (i == provider->num_configs) in tegra210_clk_emc_set_rate()
142 config = &provider->configs[i - 1]; in tegra210_clk_emc_set_rate()
145 new_idx = FIELD_GET(CLK_SOURCE_EMC_2X_CLK_SRC, config->value); in tegra210_clk_emc_set_rate()
151 if (config->parent_rate != clk_hw_get_rate(old)) { in tegra210_clk_emc_set_rate()
178 return -EINVAL; in tegra210_clk_emc_set_rate()
184 parent = new; in tegra210_clk_emc_set_rate()
187 parent = old; in tegra210_clk_emc_set_rate()
190 clk = tegra210_clk_emc_find_parent(emc, index); in tegra210_clk_emc_set_rate()
191 if (IS_ERR(clk)) { in tegra210_clk_emc_set_rate()
192 err = PTR_ERR(clk); in tegra210_clk_emc_set_rate()
193 dev_err(dev, "failed to get parent clock for index %u: %d\n", in tegra210_clk_emc_set_rate()
198 /* set the new parent clock to the required rate */ in tegra210_clk_emc_set_rate()
199 if (clk_get_rate(clk) != config->parent_rate) { in tegra210_clk_emc_set_rate()
200 err = clk_set_rate(clk, config->parent_rate); in tegra210_clk_emc_set_rate()
203 config->parent_rate, clk, err); in tegra210_clk_emc_set_rate()
208 /* enable the new parent clock */ in tegra210_clk_emc_set_rate()
209 if (parent != old) { in tegra210_clk_emc_set_rate()
210 err = clk_prepare_enable(clk); in tegra210_clk_emc_set_rate()
212 dev_err(dev, "failed to enable parent clock %pC: %d\n", in tegra210_clk_emc_set_rate()
213 clk, err); in tegra210_clk_emc_set_rate()
218 /* update the EMC source configuration to reflect the new parent */ in tegra210_clk_emc_set_rate()
219 config->value &= ~CLK_SOURCE_EMC_2X_CLK_SRC; in tegra210_clk_emc_set_rate()
220 config->value |= FIELD_PREP(CLK_SOURCE_EMC_2X_CLK_SRC, index); in tegra210_clk_emc_set_rate()
223 * Finally, switch the EMC programming with both old and new parent in tegra210_clk_emc_set_rate()
226 err = provider->set_rate(dev, config); in tegra210_clk_emc_set_rate()
233 * longer need the new parent to be enabled. in tegra210_clk_emc_set_rate()
235 if (parent != old) in tegra210_clk_emc_set_rate()
236 clk_disable_unprepare(clk); in tegra210_clk_emc_set_rate()
241 /* reparent to new parent clock and disable the old parent clock */ in tegra210_clk_emc_set_rate()
242 if (parent != old) { in tegra210_clk_emc_set_rate()
243 clk = tegra210_clk_emc_find_parent(emc, old_idx); in tegra210_clk_emc_set_rate()
244 if (IS_ERR(clk)) { in tegra210_clk_emc_set_rate()
245 err = PTR_ERR(clk); in tegra210_clk_emc_set_rate()
247 "failed to get parent clock for index %u: %d\n", in tegra210_clk_emc_set_rate()
252 clk_hw_reparent(hw, parent); in tegra210_clk_emc_set_rate()
253 clk_disable_unprepare(clk); in tegra210_clk_emc_set_rate()
266 struct clk *tegra210_clk_register_emc(struct device_node *np, in tegra210_clk_register_emc()
271 struct clk *clk; in tegra210_clk_register_emc() local
275 return ERR_PTR(-ENOMEM); in tegra210_clk_register_emc()
277 emc->regs = regs; in tegra210_clk_register_emc()
284 emc->hw.init = &init; in tegra210_clk_register_emc()
286 clk = clk_register(NULL, &emc->hw); in tegra210_clk_register_emc()
287 if (IS_ERR(clk)) { in tegra210_clk_register_emc()
289 return clk; in tegra210_clk_register_emc()
292 return clk; in tegra210_clk_register_emc()
295 int tegra210_clk_emc_attach(struct clk *clk, in tegra210_clk_emc_attach() argument
298 struct clk_hw *hw = __clk_get_hw(clk); in tegra210_clk_emc_attach()
300 struct device *dev = provider->dev; in tegra210_clk_emc_attach()
304 if (!try_module_get(provider->owner)) in tegra210_clk_emc_attach()
305 return -ENODEV; in tegra210_clk_emc_attach()
307 for (i = 0; i < provider->num_configs; i++) { in tegra210_clk_emc_attach()
308 struct tegra210_clk_emc_config *config = &provider->configs[i]; in tegra210_clk_emc_attach()
309 struct clk_hw *parent; in tegra210_clk_emc_attach() local
313 div = FIELD_GET(CLK_SOURCE_EMC_2X_CLK_DIVISOR, config->value); in tegra210_clk_emc_attach()
314 src = FIELD_GET(CLK_SOURCE_EMC_2X_CLK_SRC, config->value); in tegra210_clk_emc_attach()
319 div, config->rate); in tegra210_clk_emc_attach()
320 err = -EINVAL; in tegra210_clk_emc_attach()
324 same_freq = config->value & CLK_SOURCE_EMC_MC_EMC_SAME_FREQ; in tegra210_clk_emc_attach()
326 if (same_freq != config->same_freq) { in tegra210_clk_emc_attach()
329 config->rate); in tegra210_clk_emc_attach()
330 err = -EINVAL; in tegra210_clk_emc_attach()
334 parent = clk_hw_get_parent_by_index(hw, src); in tegra210_clk_emc_attach()
335 config->parent = src; in tegra210_clk_emc_attach()
338 config->parent_rate = config->rate * (1 + div / 2); in tegra210_clk_emc_attach()
340 unsigned long rate = config->rate * (1 + div / 2); in tegra210_clk_emc_attach()
342 config->parent_rate = clk_hw_get_rate(parent); in tegra210_clk_emc_attach()
344 if (config->parent_rate != rate) { in tegra210_clk_emc_attach()
347 config->rate); in tegra210_clk_emc_attach()
348 err = -EINVAL; in tegra210_clk_emc_attach()
354 emc->provider = provider; in tegra210_clk_emc_attach()
359 module_put(provider->owner); in tegra210_clk_emc_attach()
364 void tegra210_clk_emc_detach(struct clk *clk) in tegra210_clk_emc_detach() argument
366 struct tegra210_clk_emc *emc = to_tegra210_clk_emc(__clk_get_hw(clk)); in tegra210_clk_emc_detach()
368 module_put(emc->provider->owner); in tegra210_clk_emc_detach()
369 emc->provider = NULL; in tegra210_clk_emc_detach()