aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/clk/tegra/clk-tegra124-emc.c
diff options
context:
space:
mode:
authorDmitry Osipenko <digetx@gmail.com>2020-12-28 18:49:16 +0300
committerKrzysztof Kozlowski <krzk@kernel.org>2021-01-05 18:00:09 +0100
commit281462e593483350d8072a118c6e072c550a80fa (patch)
treeaedb622d4b8e73213c869eae85999fe03cced566 /drivers/clk/tegra/clk-tegra124-emc.c
parentLinux 5.11-rc1 (diff)
downloadwireguard-linux-281462e593483350d8072a118c6e072c550a80fa.tar.xz
wireguard-linux-281462e593483350d8072a118c6e072c550a80fa.zip
memory: tegra124-emc: Make driver modular
Add modularization support to the Tegra124 EMC driver, which now can be compiled as a loadable kernel module. Note that EMC clock must be registered at clk-init time, otherwise PLLM will be disabled as unused clock at boot time if EMC driver is compiled as a module. Hence add a prepare/complete callbacks. similarly to what is done for the Tegra20/30 EMC drivers. Tested-by: Nicolas Chauvet <kwizart@gmail.com> Signed-off-by: Dmitry Osipenko <digetx@gmail.com> Link: https://lore.kernel.org/r/20201228154920.18846-2-digetx@gmail.com Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
Diffstat (limited to 'drivers/clk/tegra/clk-tegra124-emc.c')
-rw-r--r--drivers/clk/tegra/clk-tegra124-emc.c41
1 files changed, 36 insertions, 5 deletions
diff --git a/drivers/clk/tegra/clk-tegra124-emc.c b/drivers/clk/tegra/clk-tegra124-emc.c
index 745f9faa98d8..bdf6f4a51617 100644
--- a/drivers/clk/tegra/clk-tegra124-emc.c
+++ b/drivers/clk/tegra/clk-tegra124-emc.c
@@ -11,7 +11,9 @@
#include <linux/clk-provider.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
+#include <linux/clk/tegra.h>
#include <linux/delay.h>
+#include <linux/export.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_address.h>
@@ -21,7 +23,6 @@
#include <linux/string.h>
#include <soc/tegra/fuse.h>
-#include <soc/tegra/emc.h>
#include "clk.h"
@@ -80,6 +81,9 @@ struct tegra_clk_emc {
int num_timings;
struct emc_timing *timings;
spinlock_t *lock;
+
+ tegra124_emc_prepare_timing_change_cb *prepare_timing_change;
+ tegra124_emc_complete_timing_change_cb *complete_timing_change;
};
/* Common clock framework callback implementations */
@@ -176,6 +180,9 @@ static struct tegra_emc *emc_ensure_emc_driver(struct tegra_clk_emc *tegra)
if (tegra->emc)
return tegra->emc;
+ if (!tegra->prepare_timing_change || !tegra->complete_timing_change)
+ return NULL;
+
if (!tegra->emc_node)
return NULL;
@@ -241,7 +248,7 @@ static int emc_set_timing(struct tegra_clk_emc *tegra,
div = timing->parent_rate / (timing->rate / 2) - 2;
- err = tegra_emc_prepare_timing_change(emc, timing->rate);
+ err = tegra->prepare_timing_change(emc, timing->rate);
if (err)
return err;
@@ -259,7 +266,7 @@ static int emc_set_timing(struct tegra_clk_emc *tegra,
spin_unlock_irqrestore(tegra->lock, flags);
- tegra_emc_complete_timing_change(emc, timing->rate);
+ tegra->complete_timing_change(emc, timing->rate);
clk_hw_reparent(&tegra->hw, __clk_get_hw(timing->parent));
clk_disable_unprepare(tegra->prev_parent);
@@ -473,8 +480,8 @@ static const struct clk_ops tegra_clk_emc_ops = {
.get_parent = emc_get_parent,
};
-struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np,
- spinlock_t *lock)
+struct clk *tegra124_clk_register_emc(void __iomem *base, struct device_node *np,
+ spinlock_t *lock)
{
struct tegra_clk_emc *tegra;
struct clk_init_data init;
@@ -538,3 +545,27 @@ struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np,
return clk;
};
+
+void tegra124_clk_set_emc_callbacks(tegra124_emc_prepare_timing_change_cb *prep_cb,
+ tegra124_emc_complete_timing_change_cb *complete_cb)
+{
+ struct clk *clk = __clk_lookup("emc");
+ struct tegra_clk_emc *tegra;
+ struct clk_hw *hw;
+
+ if (clk) {
+ hw = __clk_get_hw(clk);
+ tegra = container_of(hw, struct tegra_clk_emc, hw);
+
+ tegra->prepare_timing_change = prep_cb;
+ tegra->complete_timing_change = complete_cb;
+ }
+}
+EXPORT_SYMBOL_GPL(tegra124_clk_set_emc_callbacks);
+
+bool tegra124_clk_emc_driver_available(struct clk_hw *hw)
+{
+ struct tegra_clk_emc *tegra = container_of(hw, struct tegra_clk_emc, hw);
+
+ return tegra->prepare_timing_change && tegra->complete_timing_change;
+}