aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLiXin <li.xin@linaro.org>2013-01-31 17:25:07 +0800
committerGuodong Xu <guodong.xu@linaro.org>2013-02-21 16:12:30 +0800
commit548aec90f8d38329d919bd439c3595e529c24d79 (patch)
tree3a9a3760952dedee2c80b3a4dd1aee465f93d0f6 /drivers
parent4cc6a78feb17038b49f50bb0eb6e709ec953a0ec (diff)
ARM: hs: add clock driver to hi4511
Add clock driver based on common clock framework to hi4511. Signed-off-by: LiXin <li.xin@linaro.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/clk-hs.c194
1 files changed, 190 insertions, 4 deletions
diff --git a/drivers/clk/clk-hs.c b/drivers/clk/clk-hs.c
index 99f907f0d23..88ad41c59fa 100644
--- a/drivers/clk/clk-hs.c
+++ b/drivers/clk/clk-hs.c
@@ -23,23 +23,209 @@
#include <linux/kernel.h>
#include <linux/clk-provider.h>
+#include <linux/clk-private.h>
#include <linux/clkdev.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_device.h>
#include <linux/slab.h>
+#include <linux/clk.h>
+
+static DEFINE_SPINLOCK(_lock);
+
+
+void __iomem *pmctrl_base;
+void __iomem *sctrl_base;
+
+
+void __init of_gate_clk_setup(struct device_node *node)
+{
+ struct clk *clk;
+ const char *clk_name = node->name;
+ const char *clk_parnet;
+ int err;
+ u32 data[2];
+ void __iomem *reg;
+ u8 enable_bit;
+
+ err = of_property_read_u32_array(node, "hisilicon,hi3620-clkgate", &data[0], 2);
+ if (err) {
+ printk("[%s] cann't values form hisilicon,hi3620-clkgate property! \n", node->name);
+ return ;
+ }
+
+ reg = sctrl_base + data[0];
+ enable_bit = (u8)data[1];
+
+ clk_parnet = of_clk_get_parent_name(node, 0);
+
+ clk = clk_register_gate(NULL, clk_name, clk_parnet, CLK_IS_BASIC,
+ reg, enable_bit, 1, &_lock);
+ if (!IS_ERR(clk))
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+
+
+void __init of_fixed_factor_clk_setup(struct device_node *node)
+{
+ struct clk *clk;
+ const char *clk_name = node->name;
+ const char *clk_parnet;
+ int err;
+ unsigned long rate;
+ u32 vals[2];
+
+ clk_parnet = of_clk_get_parent_name(node, 0);
+
+ err = of_property_read_u32_array(node, "hisilicon,fixed-factor", vals, 2);
+ if (err) {
+ printk("[%s] cann't values form hisilicon,fixed_factor property! \n", node->name);
+ return ;
+ }
+
+ clk = clk_register_fixed_factor(NULL, clk_name, clk_parnet, CLK_IS_BASIC, vals[0], vals[1]);
+ if (!IS_ERR(clk))
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+
+void __init of_divider_clk_setup(struct device_node *node)
+{
+ struct clk *clk;
+ const char *clk_name = node->name;
+ const char *clk_parnet;
+ struct clk_div_table *table;
+ int err;
+ void __iomem *reg;
+ u8 shift,width;
+ unsigned int table_num;
+ int i;
+ u32 data[3];
+ char *propname = "hisilicon,clkdiv-table";
+ char *cellname = "#hisilicon,clkdiv-table-cells";
+ struct of_phandle_args div_table;
+
+ /*process the div_table*/
+ for (i = 0; ; i++) {
+ err = of_parse_phandle_with_args(node, propname, cellname, i, &div_table);
+ if (err)
+ break;
+ }
+
+ /*table ends with <0, 0>, so plus one to table_num*/
+ table_num = i + 1;
+
+ table = kzalloc(sizeof(struct clk_div_table) * table_num, GFP_KERNEL);
+ if (!table)
+ return ;
+
+ for (i = 0; ; i++) {
+ err = of_parse_phandle_with_args(node, propname, cellname, i, &div_table);
+ if (err)
+ break;
+
+ table[i].val = div_table.args[0];
+ table[i].div = div_table.args[1];
+ }
+
+ err = of_property_read_u32_array(node, "hisilicon,hi3620-clkdiv", &data[0], 3);
+ if (err) {
+ printk("[%s] cann't values form hisilicon,hi3620-clkdiv property! \n", node->name);
+ kfree(table);
+ return ;
+ }
+
+ reg = sctrl_base + data[0];
+ shift = (u8)data[1];
+ width = (u8)data[2];
+
+ clk_parnet = of_clk_get_parent_name(node, 0);
+
+ clk = clk_register_divider_table(NULL, clk_name, clk_parnet, CLK_IS_BASIC, reg,
+ shift, width, 0, table, &_lock);
+ if (!IS_ERR(clk))
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ else
+ kfree(table);
+}
+
+
+static void __init of_mux_clk_setup(struct device_node *node)
+{
+ int i, err;
+ void __iomem *clk_sel;
+ u8 num_parents;
+ const char *clk_name = node->name;
+ const char **parent_names;
+ struct clk *clk;
+ unsigned int shift,width;
+ u32 vals[2];
+
+ /* get the count of items in mux */
+ for (i = 0; ; i++) {
+ /* parent's #clock-cells property is always 0 */
+ if (!of_parse_phandle(node, "clocks", i))
+ break;
+ }
+
+ num_parents = i;
+
+ if (!num_parents)
+ return;
+
+ err = of_property_read_u32_array(node, "hisilicon,hi3620-clkmux", &vals[0], 2);
+ if (err) {
+ printk("cann't values form hisilicon,hi3620-clkmux property!\n");
+ return;
+ }
+ clk_sel = sctrl_base + vals[0];
+
+ shift = ffs(vals[1]) - 1;
+ width = fls(vals[1]) - ffs(vals[1]) + 1;
+
+ parent_names = kzalloc(sizeof(char *) * num_parents, GFP_KERNEL);
+ if (!parent_names)
+ return;
+
+ for (i = 0; i < num_parents; i++) {
+ parent_names[i] = of_clk_get_parent_name(node, i);
+ }
+ clk = clk_register_mux(NULL, clk_name, parent_names, num_parents,
+ CLK_SET_RATE_PARENT,
+ clk_sel, shift, width, 0, &_lock);
+ if (IS_ERR(clk))
+ goto err_mux;
+
+ clk_register_clkdev(clk, clk_name, NULL);
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+ return;
+err_mux:
+ kfree(parent_names);
+}
static const __initconst struct of_device_id hs_clk_match[] = {
- {
- .compatible = "fixed-clock",
- .data = of_fixed_clk_setup,
- },
+ { .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
+ { .compatible = "hisilicon,pll", .data = of_fixed_clk_setup, },
+ { .compatible = "hisilicon,muxclock", .data = of_mux_clk_setup, },
+ { .compatible = "hisilicon,periclock", .data = of_gate_clk_setup, },
+ { .compatible = "hisilicon,divclock", .data = of_divider_clk_setup, },
+ { .compatible = "hisilicon,cfgaxi", .data = of_fixed_factor_clk_setup,},
+ {}
};
void __init hs_init_clocks(void)
{
struct device_node *node;
+ /*map pmctrl registers*/
+ node = of_find_compatible_node(NULL, NULL, "hisilicon,pmctrl");
+ pmctrl_base = of_iomap(node, 0);
+ WARN_ON(!pmctrl_base);
+
+ node = of_find_compatible_node(NULL, NULL, "hisilicon,sctrl");
+ sctrl_base = of_iomap(node, 0);
+
of_clk_init(hs_clk_match);
}