Lines Matching +full:clk +full:- +full:source

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()
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()
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()
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()
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()
152 /* ... but the clock source remains the same ... */ in tegra210_clk_emc_set_rate()
154 /* ... switch to the alternative clock source. */ in tegra210_clk_emc_set_rate()
178 return -EINVAL; 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()
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()
210 err = clk_prepare_enable(clk); 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()
226 err = provider->set_rate(dev, config); in tegra210_clk_emc_set_rate()
236 clk_disable_unprepare(clk); 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()
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()
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()
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()