2 * Copyright (C) 2012 ARM Limited
3 * Copyright (C) 2012 Linaro
5 * Author: Viresh Kumar <viresh.kumar@linaro.org>
7 * This file is licensed under the terms of the GNU General Public
8 * License version 2. This program is licensed "as is" without any
9 * warranty of any kind, whether express or implied.
12 /* SPC clock programming interface for Vexpress cpus */
14 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
16 #include <linux/clk-provider.h>
17 #include <linux/clkdev.h>
18 #include <linux/err.h>
21 #include <linux/slab.h>
22 #include <linux/types.h>
23 #include <linux/vexpress.h>
31 #define to_clk_spc(spc) container_of(spc, struct clk_spc, hw)
33 static unsigned long spc_recalc_rate(struct clk_hw *hw,
34 unsigned long parent_rate)
36 struct clk_spc *spc = to_clk_spc(hw);
39 if (vexpress_spc_get_performance(spc->cluster, &freq)) {
41 pr_err("%s: Failed", __func__);
47 static long spc_round_rate(struct clk_hw *hw, unsigned long drate,
48 unsigned long *parent_rate)
53 static int spc_set_rate(struct clk_hw *hw, unsigned long rate,
54 unsigned long parent_rate)
56 struct clk_spc *spc = to_clk_spc(hw);
58 return vexpress_spc_set_performance(spc->cluster, rate / 1000);
61 static struct clk_ops clk_spc_ops = {
62 .recalc_rate = spc_recalc_rate,
63 .round_rate = spc_round_rate,
64 .set_rate = spc_set_rate,
67 struct clk *vexpress_clk_register_spc(const char *name, int cluster_id)
69 struct clk_init_data init;
74 pr_err("Invalid name passed");
75 return ERR_PTR(-EINVAL);
78 spc = kzalloc(sizeof(*spc), GFP_KERNEL);
80 pr_err("could not allocate spc clk\n");
81 return ERR_PTR(-ENOMEM);
85 spc->cluster = cluster_id;
88 init.ops = &clk_spc_ops;
89 init.flags = CLK_IS_ROOT | CLK_GET_RATE_NOCACHE;
92 clk = clk_register(NULL, &spc->hw);
93 if (!IS_ERR_OR_NULL(clk))
96 pr_err("clk register failed\n");
102 #if defined(CONFIG_OF)
103 void __init vexpress_clk_of_register_spc(void)
105 char name[14] = "cpu-cluster.X";
106 struct device_node *node = NULL;
109 int cluster_id = 0, len;
111 if (!of_find_compatible_node(NULL, NULL, "arm,vexpress-spc")) {
112 pr_debug("%s: No SPC found, Exiting!!\n", __func__);
116 while ((node = of_find_node_by_name(node, "cluster"))) {
117 val = of_get_property(node, "reg", &len);
119 cluster_id = be32_to_cpup(val);
121 name[12] = cluster_id + '0';
122 clk = vexpress_clk_register_spc(name, cluster_id);
126 pr_debug("Registered clock '%s'\n", name);
127 clk_register_clkdev(clk, NULL, name);
130 CLK_OF_DECLARE(spc, "arm,vexpress-spc", vexpress_clk_of_register_spc);