[PATCH v2 3/9] clk: stm32: add STM32H7RS RCC driver
Liu Changjie
liucj1228 at outlook.com
Sun Aug 9 03:09:37 PDT 2026
Register the active STM32H7RS system, bus and selected peripheral
clocks without reprogramming the PLLs used for execute-in-place.
Decode the PLL2 S and T outputs used by SDMMC from PLL2DIVR2.
Expose gates for TIM5, UART4, GPIO banks A-H and M-P, and SDMMC1.
Signed-off-by: Liu Changjie <liucj1228 at outlook.com>
---
Changes in v2:
- Register as a builtin platform driver with a probe instead of
CLK_OF_DECLARE_DRIVER (Brian Masney).
- Use devm_of_iomap(), devm_clk_get() and the devm clock registration /
provider helpers, and drop the hand-written failure unwinding
(Brian Masney).
- Register the peripheral gates with struct clk_parent_data via
devm_clk_hw_register_gate_parent_data() instead of parent_name
(Brian Masney).
- Register the RCC reset controller from probe using reset_simple_ops
(select RESET_SIMPLE) instead of relying on a separate reset-simple
bind to a shared compatible.
- Drop the unused <linux/slab.h> include (Brian Masney).
- Reorder the stm32h7rs_pll_rate() locals in reverse-Christmas-tree
order and add the missing blank line before the return (Brian Masney).
drivers/clk/Kconfig | 6 +
drivers/clk/Makefile | 1 +
drivers/clk/clk-stm32h7rs.c | 521 ++++++++++++++++++++++++++++++++++++
3 files changed, 528 insertions(+)
create mode 100644 drivers/clk/clk-stm32h7rs.c
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 1717ce75a..666d92a7d 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -448,6 +448,12 @@ config COMMON_CLK_STM32H7
help
Support for stm32h7 SoC family clocks
+config COMMON_CLK_STM32H7RS
+ def_bool COMMON_CLK && MACH_STM32H7R7
+ select RESET_SIMPLE
+ help
+ Support for STM32H7RS SoC family clocks
+
config COMMON_CLK_MMP2
def_bool COMMON_CLK && (MACH_MMP2_DT || MACH_MMP3_DT)
help
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index cc108a75a..3dcb2f525 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -98,6 +98,7 @@ obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o
obj-$(CONFIG_COMMON_CLK_SP7021) += clk-sp7021.o
obj-$(CONFIG_COMMON_CLK_STM32F) += clk-stm32f4.o
obj-$(CONFIG_COMMON_CLK_STM32H7) += clk-stm32h7.o
+obj-$(CONFIG_COMMON_CLK_STM32H7RS) += clk-stm32h7rs.o
obj-$(CONFIG_COMMON_CLK_TPS68470) += clk-tps68470.o
obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o
obj-$(CONFIG_CLK_TWL) += clk-twl.o
diff --git a/drivers/clk/clk-stm32h7rs.c b/drivers/clk/clk-stm32h7rs.c
new file mode 100644
index 000000000..8d94953d2
--- /dev/null
+++ b/drivers/clk/clk-stm32h7rs.c
@@ -0,0 +1,521 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Clock driver for the STM32H7RS Reset and Clock Controller.
+ *
+ * The first-stage firmware configures the oscillators and PLLs before Linux
+ * starts executing from external NOR. The driver reconstructs that running
+ * clock tree from RCC registers and gives Linux ownership of peripheral clock
+ * gates without disturbing the XIP-critical PLL configuration.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/reset/reset-simple.h>
+#include <linux/spinlock.h>
+
+#include <dt-bindings/clock/stm32h7rs-clks.h>
+
+#define RCC_CR 0x000
+#define RCC_CFGR 0x010
+#define RCC_CDCFGR 0x018
+#define RCC_BMCFGR 0x01c
+#define RCC_APBCFGR 0x020
+#define RCC_PLLCKSELR 0x028
+#define RCC_PLLCFGR 0x02c
+#define RCC_PLL1DIVR1 0x030
+#define RCC_PLL1FRACR 0x034
+#define RCC_PLL2DIVR1 0x038
+#define RCC_PLL2FRACR 0x03c
+#define RCC_PLL3DIVR1 0x040
+#define RCC_PLL3FRACR 0x044
+#define RCC_CCIPR1 0x04c
+#define RCC_CCIPR2 0x050
+#define RCC_PLL2DIVR2 0x0c4
+#define RCC_AHB5ENR 0x134
+#define RCC_AHB4ENR 0x140
+#define RCC_APB1ENR1 0x148
+
+#define RCC_CR_HSIDIV_SHIFT 3
+#define RCC_CFGR_SWS_SHIFT 3
+#define RCC_CFGR_TIMPRE BIT(15)
+#define RCC_PLLCFGR_FRACEN(_pll) BIT(((_pll) - 1) * 11)
+#define RCC_PLL_ON(_pll) BIT(24 + (((_pll) - 1) * 2))
+
+#define RCC_CDCFGR_CPRE_SHIFT 0
+#define RCC_BMCFGR_BMPRE_SHIFT 0
+#define RCC_APBCFGR_PPRE1_SHIFT 0
+#define RCC_APBCFGR_PPRE2_SHIFT 4
+#define RCC_APBCFGR_PPRE4_SHIFT 8
+#define RCC_APBCFGR_PPRE5_SHIFT 12
+
+#define RCC_CCIPR1_SDMMC12SEL BIT(2)
+#define RCC_CCIPR2_UARTSEL_MASK GENMASK(2, 0)
+
+#define HSI_RATE 64000000UL
+#define CSI_RATE 4000000UL
+
+static DEFINE_SPINLOCK(stm32h7rs_rcc_lock);
+
+static const u16 pll_divr_offset[] = {
+ RCC_PLL1DIVR1, RCC_PLL2DIVR1, RCC_PLL3DIVR1,
+};
+
+static const u16 pll_fracr_offset[] = {
+ RCC_PLL1FRACR, RCC_PLL2FRACR, RCC_PLL3FRACR,
+};
+
+static const u8 pll_m_shift[] = { 4, 12, 20 };
+
+enum stm32h7rs_pll_output {
+ PLL_P,
+ PLL_Q,
+ PLL_R,
+ PLL_S,
+ PLL_T,
+};
+
+static unsigned long stm32h7rs_hsi_rate(void __iomem *base)
+{
+ u32 div = (readl_relaxed(base + RCC_CR) >> RCC_CR_HSIDIV_SHIFT) & 0x3;
+
+ return HSI_RATE >> div;
+}
+
+static unsigned long stm32h7rs_pll_rate(void __iomem *base, unsigned int pll,
+ unsigned int output,
+ unsigned long hse_rate)
+{
+ static const u8 output_shift[] = { 9, 16, 24 };
+ u32 divr1, frac = 0, m, n, out_div, source;
+ unsigned long parent_rate;
+ u64 numerator;
+
+ if (pll < 1 || pll > ARRAY_SIZE(pll_divr_offset) || output > PLL_T)
+ return 0;
+
+ if (output > PLL_R && pll != 2)
+ return 0;
+
+ if (!(readl_relaxed(base + RCC_CR) & RCC_PLL_ON(pll)))
+ return 0;
+
+ source = readl_relaxed(base + RCC_PLLCKSELR) & GENMASK(1, 0);
+ switch (source) {
+ case 0:
+ parent_rate = stm32h7rs_hsi_rate(base);
+ break;
+ case 1:
+ parent_rate = CSI_RATE;
+ break;
+ case 2:
+ parent_rate = hse_rate;
+ break;
+ default:
+ return 0;
+ }
+
+ m = (readl_relaxed(base + RCC_PLLCKSELR) >> pll_m_shift[pll - 1]) & 0x3f;
+ if (!m || !parent_rate)
+ return 0;
+
+ divr1 = readl_relaxed(base + pll_divr_offset[pll - 1]);
+ n = (divr1 & GENMASK(8, 0)) + 1;
+ if (readl_relaxed(base + RCC_PLLCFGR) & RCC_PLLCFGR_FRACEN(pll))
+ frac = (readl_relaxed(base + pll_fracr_offset[pll - 1]) >> 3) &
+ GENMASK(12, 0);
+
+ if (output <= PLL_R) {
+ out_div = ((divr1 >> output_shift[output]) &
+ GENMASK(6, 0)) + 1;
+ } else {
+ u32 divr2 = readl_relaxed(base + RCC_PLL2DIVR2);
+ u8 shift = output == PLL_S ? 0 : 8;
+
+ out_div = ((divr2 >> shift) & GENMASK(2, 0)) + 1;
+ }
+
+ numerator = (u64)parent_rate * (n * 8192ULL + frac);
+
+ return div64_u64(numerator, (u64)m * 8192ULL * out_div);
+}
+
+static unsigned long stm32h7rs_ahb_rate(unsigned long parent_rate, u32 val)
+{
+ static const u16 div_table[] = { 2, 4, 8, 16, 64, 128, 256, 512 };
+
+ if (val < 8)
+ return parent_rate;
+
+ return parent_rate / div_table[val - 8];
+}
+
+static unsigned long stm32h7rs_sys_rate(void __iomem *base,
+ unsigned long hse_rate)
+{
+ unsigned long rate;
+ u32 cpre, source;
+
+ source = (readl_relaxed(base + RCC_CFGR) >> RCC_CFGR_SWS_SHIFT) & 0x7;
+ switch (source) {
+ case 0:
+ rate = stm32h7rs_hsi_rate(base);
+ break;
+ case 1:
+ rate = CSI_RATE;
+ break;
+ case 2:
+ rate = hse_rate;
+ break;
+ case 3:
+ rate = stm32h7rs_pll_rate(base, 1, PLL_P, hse_rate);
+ break;
+ default:
+ return 0;
+ }
+
+ cpre = (readl_relaxed(base + RCC_CDCFGR) >> RCC_CDCFGR_CPRE_SHIFT) & 0xf;
+ return stm32h7rs_ahb_rate(rate, cpre);
+}
+
+static unsigned long stm32h7rs_apb_rate(void __iomem *base,
+ unsigned long hclk_rate, u8 shift)
+{
+ u32 prescaler = (readl_relaxed(base + RCC_APBCFGR) >> shift) & 0x7;
+
+ if (prescaler < 4)
+ return hclk_rate;
+
+ return hclk_rate >> (prescaler - 3);
+}
+
+static unsigned long stm32h7rs_timer_rate(void __iomem *base,
+ unsigned long hclk_rate,
+ unsigned long pclk_rate)
+{
+ u32 prescaler = (readl_relaxed(base + RCC_APBCFGR) >>
+ RCC_APBCFGR_PPRE1_SHIFT) & 0x7;
+
+ if (prescaler < 4)
+ return pclk_rate;
+
+ if (!(readl_relaxed(base + RCC_CFGR) & RCC_CFGR_TIMPRE))
+ return pclk_rate * 2;
+
+ return prescaler < 6 ? hclk_rate : pclk_rate * 4;
+}
+
+static unsigned long stm32h7rs_uart4_rate(void __iomem *base,
+ unsigned long hse_rate,
+ unsigned long lse_rate,
+ unsigned long pclk1_rate)
+{
+ u32 source = readl_relaxed(base + RCC_CCIPR2) & RCC_CCIPR2_UARTSEL_MASK;
+
+ switch (source) {
+ case 0:
+ return pclk1_rate;
+ case 1:
+ return stm32h7rs_pll_rate(base, 2, PLL_Q, hse_rate);
+ case 2:
+ return stm32h7rs_pll_rate(base, 3, PLL_Q, hse_rate);
+ case 3:
+ return stm32h7rs_hsi_rate(base);
+ case 4:
+ return CSI_RATE;
+ case 5:
+ return lse_rate;
+ default:
+ return 0;
+ }
+}
+
+static unsigned long stm32h7rs_sdmmc1_rate(void __iomem *base,
+ unsigned long hse_rate)
+{
+ if (readl_relaxed(base + RCC_CCIPR1) & RCC_CCIPR1_SDMMC12SEL)
+ return stm32h7rs_pll_rate(base, 2, PLL_T, hse_rate);
+
+ return stm32h7rs_pll_rate(base, 2, PLL_S, hse_rate);
+}
+
+static int h7rs_register_fixed(struct device *dev,
+ struct clk_hw_onecell_data *data,
+ unsigned int id, const char *name,
+ unsigned long rate)
+{
+ struct clk_hw *hw;
+
+ hw = devm_clk_hw_register_fixed_rate(dev, name, NULL, CLK_IS_CRITICAL,
+ rate);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ data->hws[id] = hw;
+
+ return 0;
+}
+
+enum stm32h7rs_parent {
+ STM32H7RS_PARENT_HCLK,
+ STM32H7RS_PARENT_TIM5,
+ STM32H7RS_PARENT_UART4,
+ STM32H7RS_PARENT_SDMMC1,
+ STM32H7RS_PARENT_COUNT,
+};
+
+struct stm32h7rs_gate {
+ const char *name;
+ u16 offset;
+ u8 id;
+ u8 parent;
+ u8 bit_idx;
+};
+
+static const struct stm32h7rs_gate stm32h7rs_gates[] = {
+ { "tim5", RCC_APB1ENR1, STM32H7RS_TIM5_CK,
+ STM32H7RS_PARENT_TIM5, 3 },
+ { "uart4", RCC_APB1ENR1, STM32H7RS_UART4_CK,
+ STM32H7RS_PARENT_UART4, 19 },
+ { "gpioa", RCC_AHB4ENR, STM32H7RS_GPIOA_CK,
+ STM32H7RS_PARENT_HCLK, 0 },
+ { "gpiob", RCC_AHB4ENR, STM32H7RS_GPIOB_CK,
+ STM32H7RS_PARENT_HCLK, 1 },
+ { "gpioc", RCC_AHB4ENR, STM32H7RS_GPIOC_CK,
+ STM32H7RS_PARENT_HCLK, 2 },
+ { "gpiod", RCC_AHB4ENR, STM32H7RS_GPIOD_CK,
+ STM32H7RS_PARENT_HCLK, 3 },
+ { "gpioe", RCC_AHB4ENR, STM32H7RS_GPIOE_CK,
+ STM32H7RS_PARENT_HCLK, 4 },
+ { "gpiof", RCC_AHB4ENR, STM32H7RS_GPIOF_CK,
+ STM32H7RS_PARENT_HCLK, 5 },
+ { "gpiog", RCC_AHB4ENR, STM32H7RS_GPIOG_CK,
+ STM32H7RS_PARENT_HCLK, 6 },
+ { "gpioh", RCC_AHB4ENR, STM32H7RS_GPIOH_CK,
+ STM32H7RS_PARENT_HCLK, 7 },
+ { "gpiom", RCC_AHB4ENR, STM32H7RS_GPIOM_CK,
+ STM32H7RS_PARENT_HCLK, 12 },
+ { "gpion", RCC_AHB4ENR, STM32H7RS_GPION_CK,
+ STM32H7RS_PARENT_HCLK, 13 },
+ { "gpioo", RCC_AHB4ENR, STM32H7RS_GPIOO_CK,
+ STM32H7RS_PARENT_HCLK, 14 },
+ { "gpiop", RCC_AHB4ENR, STM32H7RS_GPIOP_CK,
+ STM32H7RS_PARENT_HCLK, 15 },
+ { "sdmmc1", RCC_AHB5ENR, STM32H7RS_SDMMC1_CK,
+ STM32H7RS_PARENT_SDMMC1, 8 },
+};
+
+static int h7rs_register_gate(struct device *dev,
+ struct clk_hw_onecell_data *data,
+ const struct stm32h7rs_gate *gate,
+ const struct clk_hw *parent_hw,
+ void __iomem *base)
+{
+ const struct clk_parent_data parent_data = { .hw = parent_hw };
+ struct clk_hw *hw;
+
+ hw = devm_clk_hw_register_gate_parent_data(dev, gate->name,
+ &parent_data,
+ CLK_IGNORE_UNUSED,
+ base + gate->offset,
+ gate->bit_idx, 0,
+ &stm32h7rs_rcc_lock);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ data->hws[gate->id] = hw;
+
+ return 0;
+}
+
+static int stm32h7rs_rcc_probe(struct platform_device *pdev)
+{
+ struct clk_hw *parent_hws[STM32H7RS_PARENT_COUNT];
+ struct clk_hw_onecell_data *clk_data;
+ struct reset_simple_data *reset;
+ struct device *dev = &pdev->dev;
+ unsigned long sdmmc1_rate;
+ unsigned long uart4_rate;
+ unsigned long timer_rate;
+ unsigned long pclk5_rate;
+ unsigned long pclk4_rate;
+ unsigned long pclk2_rate;
+ unsigned long pclk1_rate;
+ unsigned long hclk_rate;
+ unsigned long sys_rate;
+ unsigned long lse_rate;
+ unsigned long hse_rate;
+ resource_size_t size;
+ struct clk *input;
+ void __iomem *base;
+ unsigned int i;
+ u32 bmpre;
+ int ret;
+
+ base = devm_of_iomap(dev, dev->of_node, 0, &size);
+ if (IS_ERR(base))
+ return dev_err_probe(dev, PTR_ERR(base),
+ "unable to map RCC registers\n");
+
+ input = devm_clk_get(dev, "hse");
+ if (IS_ERR(input))
+ return dev_err_probe(dev, PTR_ERR(input),
+ "unable to get HSE input clock\n");
+ hse_rate = clk_get_rate(input);
+
+ input = devm_clk_get(dev, "lse");
+ if (IS_ERR(input))
+ return dev_err_probe(dev, PTR_ERR(input),
+ "unable to get LSE input clock\n");
+ lse_rate = clk_get_rate(input);
+
+ reset = devm_kzalloc(dev, sizeof(*reset), GFP_KERNEL);
+ if (!reset)
+ return -ENOMEM;
+
+ spin_lock_init(&reset->lock);
+ reset->membase = base;
+ reset->rcdev.owner = THIS_MODULE;
+ reset->rcdev.nr_resets = size * BITS_PER_BYTE;
+ reset->rcdev.ops = &reset_simple_ops;
+ reset->rcdev.of_node = dev->of_node;
+
+ ret = devm_reset_controller_register(dev, &reset->rcdev);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to register reset controller\n");
+
+ clk_data = devm_kzalloc(dev,
+ struct_size(clk_data, hws, STM32H7RS_MAX_CLKS),
+ GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ clk_data->num = STM32H7RS_MAX_CLKS;
+ for (i = 0; i < clk_data->num; i++)
+ clk_data->hws[i] = ERR_PTR(-ENOENT);
+
+ sys_rate = stm32h7rs_sys_rate(base, hse_rate);
+ bmpre = (readl_relaxed(base + RCC_BMCFGR) >>
+ RCC_BMCFGR_BMPRE_SHIFT) & 0xf;
+ hclk_rate = stm32h7rs_ahb_rate(sys_rate, bmpre);
+ pclk1_rate = stm32h7rs_apb_rate(base, hclk_rate,
+ RCC_APBCFGR_PPRE1_SHIFT);
+ pclk2_rate = stm32h7rs_apb_rate(base, hclk_rate,
+ RCC_APBCFGR_PPRE2_SHIFT);
+ pclk4_rate = stm32h7rs_apb_rate(base, hclk_rate,
+ RCC_APBCFGR_PPRE4_SHIFT);
+ pclk5_rate = stm32h7rs_apb_rate(base, hclk_rate,
+ RCC_APBCFGR_PPRE5_SHIFT);
+ timer_rate = stm32h7rs_timer_rate(base, hclk_rate, pclk1_rate);
+ uart4_rate = stm32h7rs_uart4_rate(base, hse_rate, lse_rate, pclk1_rate);
+ sdmmc1_rate = stm32h7rs_sdmmc1_rate(base, hse_rate);
+
+ if (!sys_rate || !hclk_rate || !pclk1_rate || !pclk2_rate ||
+ !pclk4_rate || !pclk5_rate || !timer_rate || !uart4_rate ||
+ !sdmmc1_rate)
+ return dev_err_probe(dev, -EINVAL,
+ "invalid boot clock configuration\n");
+
+ ret = h7rs_register_fixed(dev, clk_data, STM32H7RS_SYS_CK,
+ "h7rs_sys_ck", sys_rate);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to register system clock\n");
+
+ ret = h7rs_register_fixed(dev, clk_data, STM32H7RS_HCLK,
+ "h7rs_hclk", hclk_rate);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to register HCLK\n");
+
+ ret = h7rs_register_fixed(dev, clk_data, STM32H7RS_PCLK1,
+ "h7rs_pclk1", pclk1_rate);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to register PCLK1\n");
+
+ ret = h7rs_register_fixed(dev, clk_data, STM32H7RS_PCLK2,
+ "h7rs_pclk2", pclk2_rate);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to register PCLK2\n");
+
+ ret = h7rs_register_fixed(dev, clk_data, STM32H7RS_PCLK4,
+ "h7rs_pclk4", pclk4_rate);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to register PCLK4\n");
+
+ ret = h7rs_register_fixed(dev, clk_data, STM32H7RS_PCLK5,
+ "h7rs_pclk5", pclk5_rate);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to register PCLK5\n");
+
+ parent_hws[STM32H7RS_PARENT_HCLK] = clk_data->hws[STM32H7RS_HCLK];
+ parent_hws[STM32H7RS_PARENT_TIM5] =
+ devm_clk_hw_register_fixed_rate(dev, "tim5_ker", NULL,
+ CLK_IS_CRITICAL, timer_rate);
+ parent_hws[STM32H7RS_PARENT_UART4] =
+ devm_clk_hw_register_fixed_rate(dev, "uart4_ker", NULL,
+ CLK_IS_CRITICAL, uart4_rate);
+ parent_hws[STM32H7RS_PARENT_SDMMC1] =
+ devm_clk_hw_register_fixed_rate(dev, "sdmmc1_ker", NULL,
+ CLK_IS_CRITICAL, sdmmc1_rate);
+
+ for (i = STM32H7RS_PARENT_TIM5; i < STM32H7RS_PARENT_COUNT; i++) {
+ if (IS_ERR(parent_hws[i]))
+ return dev_err_probe(dev, PTR_ERR(parent_hws[i]),
+ "failed to register parent clock %u\n",
+ i);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(stm32h7rs_gates); i++) {
+ const struct stm32h7rs_gate *gate = &stm32h7rs_gates[i];
+
+ ret = h7rs_register_gate(dev, clk_data, gate,
+ parent_hws[gate->parent], base);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to register %s clock\n",
+ gate->name);
+ }
+
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to add clock provider\n");
+
+ dev_info(dev,
+ "sys=%lu hclk=%lu pclk1=%lu tim5=%lu uart4=%lu sdmmc1=%lu\n",
+ sys_rate, hclk_rate, pclk1_rate, timer_rate, uart4_rate,
+ sdmmc1_rate);
+
+ return 0;
+}
+
+static const struct of_device_id stm32h7rs_rcc_match[] = {
+ { .compatible = "st,stm32h7rs-rcc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, stm32h7rs_rcc_match);
+
+static struct platform_driver stm32h7rs_rcc_driver = {
+ .probe = stm32h7rs_rcc_probe,
+ .driver = {
+ .name = "stm32h7rs-rcc",
+ .of_match_table = stm32h7rs_rcc_match,
+ },
+};
+builtin_platform_driver(stm32h7rs_rcc_driver);
+
+MODULE_DESCRIPTION("STM32H7RS Reset and Clock Controller driver");
+MODULE_LICENSE("GPL");
--
2.55.0
More information about the linux-arm-kernel
mailing list