[U-Boot] [PATCH v2 08/22] STM32: clock: provide dts-accessible clock driver
Benjamin Tietz
uboot at dresden.micronet24.de
Mon Jun 20 20:26:41 CEST 2016
From: Benjamin Tietz <benjamin at micronet24.de>
This implements an basic clock driver for the RCC-part of STM32 MCUs.
Currently, only enabling and disabling of peripheral clocks and retrieving main frequency is implemented.
---
drivers/clk/Kconfig | 4 ++
drivers/clk/Makefile | 1
drivers/clk/clk_stm32.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 117 insertions(+)
create mode 100644 drivers/clk/clk_stm32.c
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 6eee8eb..ebef031 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -23,4 +23,8 @@ config SPL_CLK
source "drivers/clk/uniphier/Kconfig"
source "drivers/clk/exynos/Kconfig"
+config CLK_STM32
+ bool "Enable clock driver for STM32 devices"
+ depends on CLK
+
endmenu
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 81fe600..e7fd05a 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_SANDBOX) += clk_sandbox.o
obj-$(CONFIG_MACH_PIC32) += clk_pic32.o
obj-$(CONFIG_CLK_UNIPHIER) += uniphier/
obj-$(CONFIG_CLK_EXYNOS) += exynos/
+obj-$(CONFIG_CLK_STM32) += clk_stm32.o
diff --git a/drivers/clk/clk_stm32.c b/drivers/clk/clk_stm32.c
new file mode 100644
index 0000000..b9f6e11
--- /dev/null
+++ b/drivers/clk/clk_stm32.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2016 Benjamin Tietz <uboot at dresden.micronet24.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ */
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <asm/io.h>
+#include <asm/arch/stm32.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct stm32_rcc_clk_priv {
+ struct stm32_rcc_regs *regs;
+};
+
+#define PLLCFGR_PLLN(reg) (((reg)>>6)&0x1ff)
+#define PLLCFGR_PLLM(reg) (((reg)>>0)&0x3f)
+#define PLLCFGR_PLLP(reg) (((reg)>>16)&0x3)
+#define PLLCFGR_PLLQ(reg) (((reg)>>24)&0x0f)
+#define PLLCFGR_HSE(reg) (reg & (1<<22))
+
+static long stm32_rcc_get_vco_rate(struct udevice *dev, u32 *regptr) {
+ struct stm32_rcc_clk_priv *data = dev_get_priv(dev);
+ long freq = 16000000;
+ if(!(data && data->regs))
+ return -EINVAL;
+ u32 reg = readl(&data->regs->pllcfgr);
+ if(regptr) *regptr = reg;
+ if(PLLCFGR_HSE(reg)) {
+ struct udevice *pclk;
+ int ret;
+ if((ret = clk_get_by_index(dev, 0, &pclk)) < 0)
+ return ret;
+
+ freq = clk_get_rate(pclk);
+ }
+ if(freq < 0) return freq;
+ return freq * PLLCFGR_PLLN(reg) / PLLCFGR_PLLM(reg);
+}
+
+static ulong stm32_rcc_get_rate(struct udevice *dev) {
+ u32 reg = 0;
+ long freq = stm32_rcc_get_vco_rate(dev, ®);
+ if(freq < 0) return freq;
+ return freq / ( 2 + 2 * PLLCFGR_PLLP(reg));
+}
+
+static int stm32_rcc_xxable(struct udevice *dev, int periph, int on) {
+ struct stm32_rcc_clk_priv *data = dev_get_priv(dev);
+ if(!(data && data->regs))
+ return -EINVAL;
+
+ int port = periph >> 5;
+ int bit = periph & 0x1f;
+ if(port >= 8)
+ return -ENOSYS;
+
+ u32 *enr = &data->regs->ahb1enr;
+ on ?
+ setbits_le32(&enr[port], 1<<bit):
+ clrbits_le32(&enr[port], 1<<bit);
+ return 0;
+}
+
+static int stm32_rcc_enable(struct udevice *dev, int periph) {
+ return stm32_rcc_xxable(dev, periph, 1);
+}
+
+static int stm32_rcc_disable(struct udevice *dev, int periph) {
+ return stm32_rcc_xxable(dev, periph, 0);
+}
+
+static struct clk_ops stm32_rcc_clk_ops = {
+ .get_rate = stm32_rcc_get_rate,
+ .enable = stm32_rcc_enable,
+ .disable = stm32_rcc_disable,
+};
+
+static int stm32_rcc_clk_probe(struct udevice *dev) {
+ struct stm32_rcc_clk_priv *priv = dev_get_priv(dev);
+ fdt_addr_t addr;
+ fdt_size_t size;
+
+ addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg", &size);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ if(size < sizeof(*priv->regs))
+ return -EINVAL;
+
+ priv->regs = (struct stm32_rcc_regs *) addr;
+
+ return 0;
+}
+
+static const struct udevice_id stm32_rcc_clk_ids[] = {
+ { .compatible = "st,stm32f42xx-rcc", },
+ {}
+};
+
+U_BOOT_DRIVER(stm32_rcc_clk) = {
+ .name = "stm32_rcc_clk",
+ .id = UCLASS_CLK,
+ .of_match = stm32_rcc_clk_ids,
+ .flags = DM_FLAG_PRE_RELOC,
+ .ops = &stm32_rcc_clk_ops,
+ .probe = stm32_rcc_clk_probe,
+ .priv_auto_alloc_size = sizeof(struct stm32_rcc_clk_priv),
+};
More information about the U-Boot
mailing list