[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, &reg);
+	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