summaryrefslogtreecommitdiff
path: root/drivers/clk/stm32/clk-stm32-core.c
diff options
context:
space:
mode:
authorGabriel Fernandez <gabriel.fernandez@foss.st.com>2022-05-16 09:05:48 +0200
committerStephen Boyd <sboyd@kernel.org>2022-05-20 21:07:48 -0700
commit637cee5ffc71698eecf014a794e8d24a213b3c07 (patch)
tree56e4474ba6c5ba3743e441780c72487162320840 /drivers/clk/stm32/clk-stm32-core.c
parent722dc8a1d5c8691ab9923b723db4354537206f97 (diff)
downloadlinux-637cee5ffc71698eecf014a794e8d24a213b3c07.tar.gz
linux-637cee5ffc71698eecf014a794e8d24a213b3c07.tar.bz2
linux-637cee5ffc71698eecf014a794e8d24a213b3c07.zip
clk: stm32: Introduce STM32MP13 RCC drivers (Reset Clock Controller)
This driver manages Reset and Clock of STM32MP13 soc. It uses a clk-stm32-core module to manage stm32 gate, mux and divider for STM32MP13 and for new future soc. All gates, muxes, dividers are identify by an index and information are stored in array (register address, shift, with, flags...) This is useful when we have two clocks with the same gate or when one mux manages two output clocks. Signed-off-by: Gabriel Fernandez <gabriel.fernandez@foss.st.com> Link: https://lore.kernel.org/r/20220516070600.7692-3-gabriel.fernandez@foss.st.com Signed-off-by: Stephen Boyd <sboyd@kernel.org>
Diffstat (limited to 'drivers/clk/stm32/clk-stm32-core.c')
-rw-r--r--drivers/clk/stm32/clk-stm32-core.c93
1 files changed, 93 insertions, 0 deletions
diff --git a/drivers/clk/stm32/clk-stm32-core.c b/drivers/clk/stm32/clk-stm32-core.c
new file mode 100644
index 000000000000..0fab4a5a8c66
--- /dev/null
+++ b/drivers/clk/stm32/clk-stm32-core.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics 2022 - All Rights Reserved
+ * Author: Gabriel Fernandez <gabriel.fernandez@foss.st.com> for STMicroelectronics.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "clk-stm32-core.h"
+#include "reset-stm32.h"
+
+static DEFINE_SPINLOCK(rlock);
+
+static int stm32_rcc_clock_init(struct device *dev,
+ const struct of_device_id *match,
+ void __iomem *base)
+{
+ const struct stm32_rcc_match_data *data = match->data;
+ struct clk_hw_onecell_data *clk_data = data->hw_clks;
+ struct device_node *np = dev_of_node(dev);
+ struct clk_hw **hws;
+ int n, max_binding;
+
+ max_binding = data->maxbinding;
+
+ clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, max_binding), GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ clk_data->num = max_binding;
+
+ hws = clk_data->hws;
+
+ for (n = 0; n < max_binding; n++)
+ hws[n] = ERR_PTR(-ENOENT);
+
+ for (n = 0; n < data->num_clocks; n++) {
+ const struct clock_config *cfg_clock = &data->tab_clocks[n];
+ struct clk_hw *hw = ERR_PTR(-ENOENT);
+
+ if (cfg_clock->func)
+ hw = (*cfg_clock->func)(dev, data, base, &rlock,
+ cfg_clock);
+
+ if (IS_ERR(hw)) {
+ dev_err(dev, "Can't register clk %d: %ld\n", n,
+ PTR_ERR(hw));
+ return PTR_ERR(hw);
+ }
+
+ if (cfg_clock->id != NO_ID)
+ hws[cfg_clock->id] = hw;
+ }
+
+ return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
+}
+
+int stm32_rcc_init(struct device *dev, const struct of_device_id *match_data,
+ void __iomem *base)
+{
+ const struct of_device_id *match;
+ int err;
+
+ match = of_match_node(match_data, dev_of_node(dev));
+ if (!match) {
+ dev_err(dev, "match data not found\n");
+ return -ENODEV;
+ }
+
+ /* RCC Reset Configuration */
+ err = stm32_rcc_reset_init(dev, match, base);
+ if (err) {
+ pr_err("stm32 reset failed to initialize\n");
+ return err;
+ }
+
+ /* RCC Clock Configuration */
+ err = stm32_rcc_clock_init(dev, match, base);
+ if (err) {
+ pr_err("stm32 clock failed to initialize\n");
+ return err;
+ }
+
+ return 0;
+}