[PATCH v2 5/6] clk: mvebu: add AP806 core clock driver
Thomas Petazzoni
thomas.petazzoni at free-electrons.com
Wed Feb 24 07:14:25 PST 2016
This commit adds a new driver to handle the core clocks found in the
AP806 HW block, which is the core block of all Armada 7K and 8K
Marvell 64-bits processors. This core clock driver reads the
Sample-At-Reset register to determine the frequencies of several core
clocks: DDR, Ring and CPU clocks.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni at free-electrons.com>
---
drivers/clk/mvebu/Kconfig | 3 +
drivers/clk/mvebu/Makefile | 2 +-
drivers/clk/mvebu/ap806-core.c | 121 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 125 insertions(+), 1 deletion(-)
create mode 100644 drivers/clk/mvebu/ap806-core.c
diff --git a/drivers/clk/mvebu/Kconfig b/drivers/clk/mvebu/Kconfig
index 2769625..fd84172 100644
--- a/drivers/clk/mvebu/Kconfig
+++ b/drivers/clk/mvebu/Kconfig
@@ -42,3 +42,6 @@ config KIRKWOOD_CLK
config ORION_CLK
bool
select MVEBU_CLK_COMMON
+
+config ARMADA_AP806_CORE_CLK
+ bool
diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile
index 8866115..db5c28c 100644
--- a/drivers/clk/mvebu/Makefile
+++ b/drivers/clk/mvebu/Makefile
@@ -1,11 +1,11 @@
obj-$(CONFIG_MVEBU_CLK_COMMON) += common.o
obj-$(CONFIG_MVEBU_CLK_CPU) += clk-cpu.o
obj-$(CONFIG_MVEBU_CLK_COREDIV) += clk-corediv.o
-
obj-$(CONFIG_ARMADA_370_CLK) += armada-370.o
obj-$(CONFIG_ARMADA_375_CLK) += armada-375.o
obj-$(CONFIG_ARMADA_38X_CLK) += armada-38x.o
obj-$(CONFIG_ARMADA_39X_CLK) += armada-39x.o
+obj-$(CONFIG_ARMADA_AP806_CORE_CLK) += ap806-core.o
obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o
obj-$(CONFIG_DOVE_CLK) += dove.o dove-divider.o
obj-$(CONFIG_KIRKWOOD_CLK) += kirkwood.o
diff --git a/drivers/clk/mvebu/ap806-core.c b/drivers/clk/mvebu/ap806-core.c
new file mode 100644
index 0000000..b858d6b
--- /dev/null
+++ b/drivers/clk/mvebu/ap806-core.c
@@ -0,0 +1,121 @@
+/*
+ * Marvell Armada AP806 core clocks
+ *
+ * Copyright (C) 2016 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni at free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#define pr_fmt(fmt) "ap806-core-clk: " fmt
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+
+/*
+ * AP806 PLLs:
+ * 0 - DDR
+ * 1 - Ring
+ * 2 - CPU
+ */
+
+#define AP806_SAMPLE_AT_RESET_REG 0x204
+
+#define AP806_PLL_NUM 3
+#define AP806_PLL_FREQ 7
+
+/* SAR parameters to get the PLL data */
+struct apclk_sar {
+ int mask;
+ int offset;
+ const char *name;
+};
+
+static const struct apclk_sar
+ap806_core_clk_sar[AP806_PLL_NUM] __initconst = {
+ { .mask = 0x7, .offset = 21 },
+ { .mask = 0x7, .offset = 18 },
+ { .mask = 0x7, .offset = 15 },
+};
+
+static struct clk *ap806_core_clks[AP806_PLL_NUM];
+
+static struct clk_onecell_data ap806_core_clk_data = {
+ .clks = ap806_core_clks,
+ .clk_num = AP806_PLL_NUM,
+};
+
+/* mapping between SAR value to frequency */
+static const u32
+ap806_core_clk_freq[AP806_PLL_NUM][AP806_PLL_FREQ] __initconst = {
+ { 2400000000, 2100000000, 1800000000,
+ 1600000000, 1300000000, 1300000000,
+ 1300000000 },
+ { 2000000000, 1800000000, 1600000000,
+ 1400000000, 1200000000, 1200000000,
+ 1200000000 },
+ { 2500000000, 2200000000, 2000000000,
+ 1700000000, 1600000000, 1200000000,
+ 1200000000 },
+};
+
+static unsigned long __init ap806_core_clk_get_freq(u32 reg, int clk_idx)
+{
+ int freq_idx;
+ const struct apclk_sar *clk_info;
+
+ clk_info = &ap806_core_clk_sar[clk_idx];
+
+ freq_idx = (reg >> clk_info->offset) & clk_info->mask;
+ if (WARN_ON(freq_idx > AP806_PLL_FREQ))
+ return 0;
+ else
+ return ap806_core_clk_freq[clk_idx][freq_idx];
+}
+
+static void __init ap806_core_clk_init(struct device_node *np)
+{
+ struct regmap *regmap;
+ u32 reg;
+ int i;
+
+ regmap = syscon_node_to_regmap(np->parent);
+ if (IS_ERR(regmap)) {
+ pr_err("cannot get regmap\n");
+ return;
+ }
+
+ if (regmap_read(regmap, AP806_SAMPLE_AT_RESET_REG, ®)) {
+ pr_err("cannot read from regmap\n");
+ return;
+ }
+
+ for (i = 0; i < AP806_PLL_NUM; i++) {
+ unsigned long freq;
+ const char *name;
+
+ freq = ap806_core_clk_get_freq(reg, i);
+
+ of_property_read_string_index(np, "clock-output-names",
+ i, &name);
+
+ ap806_core_clks[i] =
+ clk_register_fixed_rate(NULL, name, NULL,
+ CLK_IS_ROOT, freq);
+ }
+
+ of_clk_add_provider(np, of_clk_src_onecell_get,
+ &ap806_core_clk_data);
+}
+
+CLK_OF_DECLARE(ap806_core_clk, "marvell,armada-ap806-core-clock",
+ ap806_core_clk_init);
--
2.6.4
More information about the linux-arm-kernel
mailing list