From 282f46697e5809932fad5e1fb04d19883f3aa0d4 Mon Sep 17 00:00:00 2001 From: Russ Dill Date: Mon, 26 Nov 2012 11:20:09 -0800 Subject: clk: Don't mark shared helper functions as inline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The helper functions that access the opaque struct clk should not be marked inline since they are contained in clk.c, but expected to be used by other compilation units. This causes compile errors under gcc-4.7 In file included from arch/arm/mach-omap2/clockdomain.c:25:0: arch/arm/mach-omap2/clockdomain.c: In function ‘clkdm_clk_disable’: include/linux/clk-provider.h:338:12: error: inlining failed in call to always_inline ‘__clk_get_enable_count’: function body not available arch/arm/mach-omap2/clockdomain.c:1001:28: error: called from here make[1]: *** [arch/arm/mach-omap2/clockdomain.o] Error 1 make: *** [arch/arm/mach-omap2] Error 2 Signed-off-by: Russ Dill Signed-off-by: Mike Turquette [mturquette@linaro.org: removed fixes made redundant by commit 93532c8a] [mturquette@linaro.org: improved $SUBJECT] --- drivers/clk/clk.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 251e45d6024d..9777466b81b9 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -259,32 +259,32 @@ late_initcall(clk_disable_unused); /*** helper functions ***/ -inline const char *__clk_get_name(struct clk *clk) +const char *__clk_get_name(struct clk *clk) { return !clk ? NULL : clk->name; } -inline struct clk_hw *__clk_get_hw(struct clk *clk) +struct clk_hw *__clk_get_hw(struct clk *clk) { return !clk ? NULL : clk->hw; } -inline u8 __clk_get_num_parents(struct clk *clk) +u8 __clk_get_num_parents(struct clk *clk) { return !clk ? 0 : clk->num_parents; } -inline struct clk *__clk_get_parent(struct clk *clk) +struct clk *__clk_get_parent(struct clk *clk) { return !clk ? NULL : clk->parent; } -inline unsigned int __clk_get_enable_count(struct clk *clk) +unsigned int __clk_get_enable_count(struct clk *clk) { return !clk ? 0 : clk->enable_count; } -inline unsigned int __clk_get_prepare_count(struct clk *clk) +unsigned int __clk_get_prepare_count(struct clk *clk) { return !clk ? 0 : clk->prepare_count; } @@ -310,7 +310,7 @@ out: return ret; } -inline unsigned long __clk_get_flags(struct clk *clk) +unsigned long __clk_get_flags(struct clk *clk) { return !clk ? 0 : clk->flags; } -- cgit v1.2.3 From 07326cea8dfb594dc62406cb591fee8af136182a Mon Sep 17 00:00:00 2001 From: Niels de Vos Date: Thu, 13 Dec 2012 13:12:25 +0100 Subject: clk: export __clk_get_name for re-use in imx-ipu-v3 and others This fixes the following error when building for arm-imx: > ERROR: "__clk_get_name" [drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.ko] undefined! > make[1]: *** [__modpost] Error 1 > make: *** [modules] Error 2 There are valid usecases to get the name of a clock, be it for debugging purposes or to register a children of a clock like done in this IPU driver. Therefore exporting __clk_get_name() and make it available for others makes sense. Reported-by: Peter Robinson CC: Sascha Hauer CC: Mike Turquette Signed-off-by: Niels de Vos Signed-off-by: Mike Turquette [mturquette@linaro.org: removal of inline made redundant by 65800b2] --- drivers/clk/clk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 9777466b81b9..eea70da02500 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -263,6 +263,7 @@ const char *__clk_get_name(struct clk *clk) { return !clk ? NULL : clk->name; } +EXPORT_SYMBOL_GPL(__clk_get_name); struct clk_hw *__clk_get_hw(struct clk *clk) { -- cgit v1.2.3 From fdb5363b312af9d6e671d45185c1a4b89312e44c Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Wed, 26 Dec 2012 19:16:22 +0530 Subject: clk: human-readable debugfs clock tree summary Adds debug file "clk_summary" in /sys/kernel/debug/clk dir. It helps to view all the clock registered in human-readable format. For example: clock enable_cnt prepare_cnt rate --------------------------------------------------------------------- i2s0_sync 0 0 24000000 spdif_in_sync 0 0 24000000 spdif_mux 0 0 24000000 spdif 0 0 24000000 spdif_doubler 0 0 48000000 spdif_div 0 0 48000000 spdif_2x 0 0 48000000 clk_32k 2 2 32768 blink_override 1 1 32768 blink 1 1 32768 clk_m 2 2 12000000 clk_out_3_mux 0 0 12000000 clk_out_3 0 0 12000000 pll_ref 3 3 12000000 pll_e_mux 0 0 12000000 pll_e 0 0 100000000 cml0 0 0 100000000 cml1 0 0 100000000 pciex 0 0 100000000 pll_d2 0 0 1000000 pll_d2_out0 0 0 500000 pll_d 0 0 1000000 pll_d_out0 0 0 500000 dsib_mux 0 0 500000 dsib 0 0 500000 dsia 0 0 500000 Signed-off-by: Prashant Gaikwad Signed-off-by: Mike Turquette --- drivers/clk/clk.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index eea70da02500..8622b9de7302 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -35,6 +35,67 @@ static struct dentry *rootdir; static struct dentry *orphandir; static int inited = 0; +static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level) +{ + if (!c) + return; + + seq_printf(s, "%*s%-*s %-11d %-12d %-10lu", + level * 3 + 1, "", + 30 - level * 3, c->name, + c->enable_count, c->prepare_count, c->rate); + seq_printf(s, "\n"); +} + +static void clk_summary_show_subtree(struct seq_file *s, struct clk *c, + int level) +{ + struct clk *child; + struct hlist_node *tmp; + + if (!c) + return; + + clk_summary_show_one(s, c, level); + + hlist_for_each_entry(child, tmp, &c->children, child_node) + clk_summary_show_subtree(s, child, level + 1); +} + +static int clk_summary_show(struct seq_file *s, void *data) +{ + struct clk *c; + struct hlist_node *tmp; + + seq_printf(s, " clock enable_cnt prepare_cnt rate\n"); + seq_printf(s, "---------------------------------------------------------------------\n"); + + mutex_lock(&prepare_lock); + + hlist_for_each_entry(c, tmp, &clk_root_list, child_node) + clk_summary_show_subtree(s, c, 0); + + hlist_for_each_entry(c, tmp, &clk_orphan_list, child_node) + clk_summary_show_subtree(s, c, 0); + + mutex_unlock(&prepare_lock); + + return 0; +} + + +static int clk_summary_open(struct inode *inode, struct file *file) +{ + return single_open(file, clk_summary_show, inode->i_private); +} + +static const struct file_operations clk_summary_fops = { + .open = clk_summary_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /* caller must hold prepare_lock */ static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry) { @@ -168,12 +229,18 @@ static int __init clk_debug_init(void) { struct clk *clk; struct hlist_node *tmp; + struct dentry *d; rootdir = debugfs_create_dir("clk", NULL); if (!rootdir) return -ENOMEM; + d = debugfs_create_file("clk_summary", S_IRUGO, rootdir, NULL, + &clk_summary_fops); + if (!d) + return -ENOMEM; + orphandir = debugfs_create_dir("orphans", rootdir); if (!orphandir) -- cgit v1.2.3 From 7f0b242a45fee8abc8e2568f2d1c27442ef656ef Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Wed, 26 Dec 2012 19:16:23 +0530 Subject: clk: JSON debugfs clock tree summary Clock information is dumped in JSON format which is easy for machines to parse. Each clock is represented as an object which has same name as clock and following properties - enable_count - prepare_count - rate Output is verified using online JSON editor. Signed-off-by: Prashant Gaikwad Signed-off-by: Mike Turquette --- drivers/clk/clk.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 8622b9de7302..593a2e42d4af 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -96,6 +96,76 @@ static const struct file_operations clk_summary_fops = { .release = single_release, }; +static void clk_dump_one(struct seq_file *s, struct clk *c, int level) +{ + if (!c) + return; + + seq_printf(s, "\"%s\": { ", c->name); + seq_printf(s, "\"enable_count\": %d,", c->enable_count); + seq_printf(s, "\"prepare_count\": %d,", c->prepare_count); + seq_printf(s, "\"rate\": %lu", c->rate); +} + +static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level) +{ + struct clk *child; + struct hlist_node *tmp; + + if (!c) + return; + + clk_dump_one(s, c, level); + + hlist_for_each_entry(child, tmp, &c->children, child_node) { + seq_printf(s, ","); + clk_dump_subtree(s, child, level + 1); + } + + seq_printf(s, "}"); +} + +static int clk_dump(struct seq_file *s, void *data) +{ + struct clk *c; + struct hlist_node *tmp; + bool first_node = true; + + seq_printf(s, "{"); + + mutex_lock(&prepare_lock); + + hlist_for_each_entry(c, tmp, &clk_root_list, child_node) { + if (!first_node) + seq_printf(s, ","); + first_node = false; + clk_dump_subtree(s, c, 0); + } + + hlist_for_each_entry(c, tmp, &clk_orphan_list, child_node) { + seq_printf(s, ","); + clk_dump_subtree(s, c, 0); + } + + mutex_unlock(&prepare_lock); + + seq_printf(s, "}"); + return 0; +} + + +static int clk_dump_open(struct inode *inode, struct file *file) +{ + return single_open(file, clk_dump, inode->i_private); +} + +static const struct file_operations clk_dump_fops = { + .open = clk_dump_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /* caller must hold prepare_lock */ static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry) { @@ -241,6 +311,11 @@ static int __init clk_debug_init(void) if (!d) return -ENOMEM; + d = debugfs_create_file("clk_dump", S_IRUGO, rootdir, NULL, + &clk_dump_fops); + if (!d) + return -ENOMEM; + orphandir = debugfs_create_dir("orphans", rootdir); if (!orphandir) -- cgit v1.2.3 From 5f6e700f103e9011f2c67de8f06760a392ed8927 Mon Sep 17 00:00:00 2001 From: Denis Efremov Date: Sun, 6 Jan 2013 18:21:43 +0400 Subject: clk: remove exported function from __init section The symbol of_fixed_clk_setup is exported and annotated __init. This looks like section mismatch. Fix this by removing the __init annotation of of_fixed_clk_setup. Signed-off-by: Denis Efremov Signed-off-by: Mike Turquette --- drivers/clk/clk-fixed-rate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c index af78ed6b67ef..a53b53be3d65 100644 --- a/drivers/clk/clk-fixed-rate.c +++ b/drivers/clk/clk-fixed-rate.c @@ -85,7 +85,7 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name, /** * of_fixed_clk_setup() - Setup function for simple fixed rate clock */ -void __init of_fixed_clk_setup(struct device_node *node) +void of_fixed_clk_setup(struct device_node *node) { struct clk *clk; const char *clk_name = node->name; -- cgit v1.2.3 From 2c11836f726da82400d07ab73a2b9f5956a12583 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 15 Jan 2013 10:28:05 +0000 Subject: clk-divider: fix macros The macro is_power_of_two() in clk-divider.c was defined as !(i & ~i) which is always true. Instead use is_power_of_2() from log2.h. Also add brackets around the macro arguments in div_mask to avoid any future operator precedence problems. Signed-off-by: James Hogan Cc: Joe Perches Signed-off-by: Mike Turquette [mturquette@linaro.org: use log2.h per Joe Perches; update changelog] --- drivers/clk/clk-divider.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index a9204c69148d..68b402101170 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -16,6 +16,7 @@ #include #include #include +#include /* * DOC: basic adjustable divider clock that cannot gate @@ -29,8 +30,7 @@ #define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) -#define div_mask(d) ((1 << (d->width)) - 1) -#define is_power_of_two(i) !(i & ~i) +#define div_mask(d) ((1 << ((d)->width)) - 1) static unsigned int _get_table_maxdiv(const struct clk_div_table *table) { @@ -137,7 +137,7 @@ static bool _is_valid_table_div(const struct clk_div_table *table, static bool _is_valid_div(struct clk_divider *divider, unsigned int div) { if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) - return is_power_of_two(div); + return is_power_of_2(div); if (divider->table) return _is_valid_table_div(divider->table, div); return true; -- cgit v1.2.3 From 77a58029fccd7845a122bf1652d5896b64eaef7e Mon Sep 17 00:00:00 2001 From: Mike Turquette Date: Fri, 18 Jan 2013 13:00:05 -0800 Subject: clk: beautify Makefile The list of common clock types was getting a bit unmanageable. This patch puts only one file on each line and reorders the object files alphabetically. Also a newline is added to separate the sections. Reported-by: Stephen Boyd Cc: Prashant Gaikwad Signed-off-by: Mike Turquette --- drivers/clk/Makefile | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 554ec53bc6e0..6845432ae71b 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -1,8 +1,13 @@ # common clock types obj-$(CONFIG_HAVE_CLK) += clk-devres.o obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o -obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \ - clk-mux.o clk-divider.o clk-fixed-factor.o +obj-$(CONFIG_COMMON_CLK) += clk.o +obj-$(CONFIG_COMMON_CLK) += clk-divider.o +obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o +obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o +obj-$(CONFIG_COMMON_CLK) += clk-gate.o +obj-$(CONFIG_COMMON_CLK) += clk-mux.o + # SoCs specific obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o -- cgit v1.2.3 From 18a816f854ca325d6ad529be1eb2f02c5cd61fe6 Mon Sep 17 00:00:00 2001 From: Nestor Ovroy Date: Fri, 18 Jan 2013 17:07:39 +0100 Subject: clk: Deduplicate exit code in clk_set_rate On non-out case 'return ret;' is equivalent to 'return 0;' as the ret variable is initialized at 0 and never changed. Signed-off-by: Nestor Ovroy --- drivers/clk/clk.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 593a2e42d4af..ad2ac94fede8 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1093,9 +1093,6 @@ int clk_set_rate(struct clk *clk, unsigned long rate) /* change the rates */ clk_change_rate(top); - mutex_unlock(&prepare_lock); - - return 0; out: mutex_unlock(&prepare_lock); -- cgit v1.2.3 From 9091fd475ce4b693168ac1f6adcbf79fe4d7f45c Mon Sep 17 00:00:00 2001 From: Prashant Gaikwad Date: Fri, 4 Jan 2013 12:30:52 +0530 Subject: clk: add common of_clk_init() function Modify of_clk_init function so that it will determine which driver to initialize based on device tree instead of each driver registering to it. Based on a similar patch for drivers/irqchip by Thomas Petazzoni and drivers/clocksource by Stephen Warren. Signed-off-by: Prashant Gaikwad Tested-by: Tony Prisk Tested-by: Pawel Moll Tested-by: Rob Herring Tested-by: Josh Cartwright Reviewed-by: Josh Cartwright Acked-by: Maxime Ripard Signed-off-by: Mike Turquette [mturquette@linaro.org: merge conflict from missing CLKSRC_OF_TABLES()] Signed-off-by: Mike Turquette --- drivers/clk/clk-fixed-rate.c | 1 + drivers/clk/clk.c | 9 +++++++++ include/asm-generic/vmlinux.lds.h | 10 ++++++++++ include/linux/clk-provider.h | 6 ++++++ 4 files changed, 26 insertions(+) diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c index a53b53be3d65..dc58fbd8516f 100644 --- a/drivers/clk/clk-fixed-rate.c +++ b/drivers/clk/clk-fixed-rate.c @@ -101,4 +101,5 @@ void of_fixed_clk_setup(struct device_node *node) of_clk_add_provider(node, of_clk_src_simple_get, clk); } EXPORT_SYMBOL_GPL(of_fixed_clk_setup); +CLK_OF_DECLARE(fixed_clk, "fixed-clock", of_fixed_clk_setup); #endif diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index ad2ac94fede8..fabbfe1a9253 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -18,6 +18,7 @@ #include #include #include +#include static DEFINE_SPINLOCK(enable_lock); static DEFINE_MUTEX(prepare_lock); @@ -1803,6 +1804,11 @@ struct of_clk_provider { void *data; }; +extern struct of_device_id __clk_of_table[]; + +static const struct of_device_id __clk_of_table_sentinel + __used __section(__clk_of_table_end); + static LIST_HEAD(of_clk_providers); static DEFINE_MUTEX(of_clk_lock); @@ -1931,6 +1937,9 @@ void __init of_clk_init(const struct of_device_id *matches) { struct device_node *np; + if (!matches) + matches = __clk_of_table; + for_each_matching_node(np, matches) { const struct of_device_id *match = of_match_node(matches, np); of_clk_init_cb_t clk_init_cb = match->data; diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index d1ea7ce0b4cb..c1fe60ad1540 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -150,6 +150,15 @@ #endif +#ifdef CONFIG_COMMON_CLK +#define CLK_OF_TABLES() . = ALIGN(8); \ + VMLINUX_SYMBOL(__clk_of_table) = .; \ + *(__clk_of_table) \ + *(__clk_of_table_end) +#else +#define CLK_OF_TABLES() +#endif + #define KERNEL_DTB() \ STRUCT_ALIGN(); \ VMLINUX_SYMBOL(__dtb_start) = .; \ @@ -493,6 +502,7 @@ DEV_DISCARD(init.rodata) \ CPU_DISCARD(init.rodata) \ MEM_DISCARD(init.rodata) \ + CLK_OF_TABLES() \ KERNEL_DTB() #define INIT_TEXT \ diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 4989b8a7bed1..7f197d7addb0 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -379,7 +379,13 @@ struct clk_onecell_data { }; struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data); const char *of_clk_get_parent_name(struct device_node *np, int index); + void of_clk_init(const struct of_device_id *matches); +#define CLK_OF_DECLARE(name, compat, fn) \ + static const struct of_device_id __clk_of_table_##name \ + __used __section(__clk_of_table) \ + = { .compatible = compat, .data = fn }; + #endif /* CONFIG_COMMON_CLK */ #endif /* CLK_PROVIDER_H */ -- cgit v1.2.3 From 45387e17ff74efbc7f6fd39149d18dd7bf439517 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Tue, 19 Mar 2013 15:05:53 +0800 Subject: clk: sync hi3xxx clk driver with 3.10 Signed-off-by: Haojian Zhuang --- arch/arm/mach-hs/hs-dt.c | 3 +- drivers/clk/Makefile | 2 +- drivers/clk/clk-hi3xxx.c | 643 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 646 insertions(+), 2 deletions(-) create mode 100644 drivers/clk/clk-hi3xxx.c diff --git a/arch/arm/mach-hs/hs-dt.c b/arch/arm/mach-hs/hs-dt.c index e66a482e7f1a..0ad473d82c67 100644 --- a/arch/arm/mach-hs/hs-dt.c +++ b/arch/arm/mach-hs/hs-dt.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -69,7 +70,7 @@ static void __init hs_timer_init(void) void __iomem *base; int irq; - hs_init_clocks(); + of_clk_init(NULL); node = of_find_matching_node(NULL, hs_timer_match); WARN_ON(!node); diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 6845432ae71b..e33911624624 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -12,7 +12,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-mux.o obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o -obj-$(CONFIG_ARCH_HS) += clk-hs.o +obj-$(CONFIG_ARCH_HS) += clk-hi3xxx.o obj-$(CONFIG_ARCH_MXS) += mxs/ obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ obj-$(CONFIG_PLAT_SPEAR) += spear/ diff --git a/drivers/clk/clk-hi3xxx.c b/drivers/clk/clk-hi3xxx.c new file mode 100644 index 000000000000..ac1520b49729 --- /dev/null +++ b/drivers/clk/clk-hi3xxx.c @@ -0,0 +1,643 @@ +/* + * Hisilicon clock driver + * + * Copyright (c) 2012-2013 Hisilicon Limited. + * Copyright (c) 2012-2013 Linaro Limited. + * + * Author: Haojian Zhuang + * Xin Li + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HI3620_DISABLE_OFF 0x4 +#define HI3620_STATUS_OFF 0x8 + +#define WIDTH_TO_MASK(width) ((1 << (width)) - 1) + +/* + * The reverse of DIV_ROUND_UP: The maximum number which + * divided by m is r + */ +#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1) + +struct hi3620_periclk { + struct clk_hw hw; + void __iomem *enable; /* enable register */ + void __iomem *reset; /* reset register */ + u32 ebits; /* bits in enable/disable register */ + u32 rbits; /* bits in reset/unreset register */ + spinlock_t *lock; +}; + +struct hi3620_muxclk { + struct clk_hw hw; + void __iomem *reg; /* mux register */ + u8 shift; + u8 width; + u32 mbits; /* mask bits in mux register */ + spinlock_t *lock; +}; + +struct hi3620_divclk { + struct clk_hw hw; + void __iomem *reg; /* divider register */ + u8 shift; + u8 width; + u32 mbits; /* mask bits in divider register */ + const struct clk_div_table *table; + spinlock_t *lock; +}; + +struct hs_clk { + void __iomem *pmctrl; + void __iomem *sctrl; + spinlock_t lock; +}; + +static void __init hs_init_clocks(void); + +static struct hs_clk hs_clk; + +static int hi3620_clkgate_prepare(struct clk_hw *hw) +{ + struct hi3620_periclk *pclk; + unsigned long flags = 0; + + pclk = container_of(hw, struct hi3620_periclk, hw); + + if (pclk->lock) + spin_lock_irqsave(pclk->lock, flags); + writel_relaxed(pclk->ebits, pclk->enable + HI3620_DISABLE_OFF); + writel_relaxed(pclk->rbits, pclk->reset + HI3620_DISABLE_OFF); + readl_relaxed(pclk->reset + HI3620_STATUS_OFF); + if (pclk->lock) + spin_unlock_irqrestore(pclk->lock, flags); + return 0; +} + +static int hi3620_clkgate_enable(struct clk_hw *hw) +{ + struct hi3620_periclk *pclk; + unsigned long flags = 0; + + pclk = container_of(hw, struct hi3620_periclk, hw); + if (pclk->lock) + spin_lock_irqsave(pclk->lock, flags); + writel_relaxed(pclk->ebits, pclk->enable); + readl_relaxed(pclk->enable + HI3620_STATUS_OFF); + if (pclk->lock) + spin_unlock_irqrestore(pclk->lock, flags); + return 0; +} + +static void hi3620_clkgate_disable(struct clk_hw *hw) +{ + struct hi3620_periclk *pclk; + unsigned long flags = 0; + + pclk = container_of(hw, struct hi3620_periclk, hw); + if (pclk->lock) + spin_lock_irqsave(pclk->lock, flags); + writel_relaxed(pclk->ebits, pclk->enable + HI3620_DISABLE_OFF); + readl_relaxed(pclk->enable + HI3620_STATUS_OFF); + if (pclk->lock) + spin_unlock_irqrestore(pclk->lock, flags); +} + +static struct clk_ops hi3620_clkgate_ops = { + .prepare = hi3620_clkgate_prepare, + .enable = hi3620_clkgate_enable, + .disable = hi3620_clkgate_disable, +}; + +static void __init hi3620_clkgate_setup(struct device_node *np) +{ + struct hi3620_periclk *pclk; + struct clk_init_data *init; + struct clk *clk; + const char *clk_name, *name, **parent_names; + u32 rdata[2], gdata[2]; + + if (!hs_clk.sctrl) + return; + + if (of_property_read_string(np, "clock-output-names", &clk_name)) + return; + if (of_property_read_u32_array(np, "hisilicon,hi3620-clkreset", + &rdata[0], 2)) + return; + if (of_property_read_u32_array(np, "hisilicon,hi3620-clkgate", + &gdata[0], 2)) + return; + + /* gate only has the fixed parent */ + parent_names = kzalloc(sizeof(char *), GFP_KERNEL); + if (!parent_names) + return; + parent_names[0] = of_clk_get_parent_name(np, 0); + + pclk = kzalloc(sizeof(*pclk), GFP_KERNEL); + if (!pclk) + goto err_pclk; + + init = kzalloc(sizeof(*init), GFP_KERNEL); + if (!init) + goto err_init; + init->name = kstrdup(clk_name, GFP_KERNEL); + init->ops = &hi3620_clkgate_ops; + init->flags = CLK_SET_RATE_PARENT; + init->parent_names = parent_names; + init->num_parents = 1; + + pclk->reset = hs_clk.sctrl + rdata[0]; + pclk->rbits = rdata[1]; + pclk->enable = hs_clk.sctrl + gdata[0]; + pclk->ebits = gdata[1]; + pclk->lock = &hs_clk.lock; + pclk->hw.init = init; + + clk = clk_register(NULL, &pclk->hw); + if (IS_ERR(clk)) + goto err_clk; + if (!of_property_read_string(np, "clock-names", &name)) + clk_register_clkdev(clk, name, NULL); + of_clk_add_provider(np, of_clk_src_simple_get, clk); + return; +err_clk: + kfree(init); +err_init: + kfree(pclk); +err_pclk: + kfree(parent_names); +} + +static u8 hi3620_clk_get_parent(struct clk_hw *hw) +{ + struct hi3620_muxclk *mclk; + u32 data; + unsigned long flags = 0; + + mclk = container_of(hw, struct hi3620_muxclk, hw); + + if (mclk->lock) + spin_lock_irqsave(mclk->lock, flags); + + data = readl_relaxed(mclk->reg) >> mclk->shift; + data &= WIDTH_TO_MASK(mclk->width); + + if (mclk->lock) + spin_unlock_irqrestore(mclk->lock, flags); + + if (data >= __clk_get_num_parents(hw->clk)) + return -EINVAL; + + return (u8)data; +} + +static int hi3620_clk_set_parent(struct clk_hw *hw, u8 index) +{ + struct hi3620_muxclk *mclk; + u32 data; + unsigned long flags = 0; + + mclk = container_of(hw, struct hi3620_muxclk, hw); + + if (mclk->lock) + spin_lock_irqsave(mclk->lock, flags); + + data = readl_relaxed(mclk->reg); + data &= ~(WIDTH_TO_MASK(mclk->width) << mclk->shift); + data |= index << mclk->shift; + writel_relaxed(data, mclk->reg); + /* set mask enable bits */ + data |= mclk->mbits; + writel_relaxed(data, mclk->reg); + + if (mclk->lock) + spin_unlock_irqrestore(mclk->lock, flags); + + return 0; +} + +static struct clk_ops hi3620_clkmux_ops = { + .get_parent = hi3620_clk_get_parent, + .set_parent = hi3620_clk_set_parent, +}; + +static void __init hi3620_clkmux_setup(struct device_node *np) +{ + struct hi3620_muxclk *mclk; + struct clk_init_data *init; + struct clk *clk; + const char *clk_name, **parent_names; + u32 rdata[2]; + u8 num_parents; + int i; + + hs_init_clocks(); + if (!hs_clk.sctrl) + return; + + if (of_property_read_string(np, "clock-output-names", &clk_name)) + return; + if (of_property_read_u32_array(np, "hisilicon,hi3620-clkmux", + &rdata[0], 2)) + return; + /* get the count of items in mux */ + for (i = 0; ; i++) { + /* parent's #clock-cells property is always 0 */ + if (!of_parse_phandle(np, "clocks", i)) + break; + } + parent_names = kzalloc(sizeof(char *) * i, GFP_KERNEL); + if (!parent_names) + return; + + for (num_parents = i, i = 0; i < num_parents; i++) + parent_names[i] = of_clk_get_parent_name(np, i); + + mclk = kzalloc(sizeof(*mclk), GFP_KERNEL); + if (!mclk) + goto err_mclk; + init = kzalloc(sizeof(*init), GFP_KERNEL); + if (!init) + goto err_init; + init->name = kstrdup(clk_name, GFP_KERNEL); + init->ops = &hi3620_clkmux_ops; + init->flags = CLK_SET_RATE_PARENT; + init->parent_names = parent_names; + init->num_parents = num_parents; + + mclk->reg = hs_clk.sctrl + rdata[0]; + /* enable_mask bits are in higher 16bits */ + mclk->mbits = rdata[1] << 16; + mclk->shift = ffs(rdata[1]) - 1; + mclk->width = fls(rdata[1]) - ffs(rdata[1]) + 1; + mclk->lock = &hs_clk.lock; + mclk->hw.init = init; + + clk = clk_register(NULL, &mclk->hw); + if (IS_ERR(clk)) + goto err_clk; + of_clk_add_provider(np, of_clk_src_simple_get, clk); + + return; +err_clk: + kfree(init); +err_init: + kfree(mclk); +err_mclk: + kfree(parent_names); +} + +static void __init hs_clkgate_setup(struct device_node *np) +{ + struct clk *clk; + const char *clk_name, **parent_names, *name; + unsigned long flags = 0; + u32 data[2]; + + hs_init_clocks(); + if (!hs_clk.sctrl) + return; + if (of_property_read_string(np, "clock-output-names", &clk_name)) + return; + if (of_property_read_u32_array(np, "hisilicon,clkgate", + &data[0], 2)) + return; + if (of_property_read_bool(np, "hisilicon,clkgate-inverted")) + flags = CLK_GATE_SET_TO_DISABLE; + /* gate only has the fixed parent */ + parent_names = kzalloc(sizeof(char *), GFP_KERNEL); + if (!parent_names) + return; + parent_names[0] = of_clk_get_parent_name(np, 0); + + clk = clk_register_gate(NULL, clk_name, parent_names[0], 0, + hs_clk.sctrl + data[0], (u8)data[1], flags, + &hs_clk.lock); + if (IS_ERR(clk)) + goto err; + if (!of_property_read_string(np, "clock-names", &name)) + clk_register_clkdev(clk, name, NULL); + of_clk_add_provider(np, of_clk_src_simple_get, clk); + return; +err: + kfree(parent_names); +} + +void __init hs_fixed_factor_setup(struct device_node *np) +{ + struct clk *clk; + const char *clk_name, **parent_names; + u32 data[2]; + + if (of_property_read_string(np, "clock-output-names", &clk_name)) + return; + if (of_property_read_u32_array(np, "hisilicon,fixed-factor", + data, 2)) + return ; + /* gate only has the fixed parent */ + parent_names = kzalloc(sizeof(char *), GFP_KERNEL); + if (!parent_names) + return; + parent_names[0] = of_clk_get_parent_name(np, 0); + + clk = clk_register_fixed_factor(NULL, clk_name, parent_names[0], 0, + data[0], data[1]); + if (IS_ERR(clk)) + goto err; + of_clk_add_provider(np, of_clk_src_simple_get, clk); + return; +err: + kfree(parent_names); +} + +static unsigned int hi3620_get_table_maxdiv(const struct clk_div_table *table) +{ + unsigned int maxdiv = 0; + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->div > maxdiv) + maxdiv = clkt->div; + return maxdiv; +} + +static unsigned int hi3620_get_table_div(const struct clk_div_table *table, + unsigned int val) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->val == val) + return clkt->div; + return 0; +} + +static unsigned int hi3620_get_table_val(const struct clk_div_table *table, + unsigned int div) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->div == div) + return clkt->val; + return 0; +} + +static unsigned long hi3620_clkdiv_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct hi3620_divclk *dclk = container_of(hw, struct hi3620_divclk, hw); + unsigned int div, val; + + val = readl_relaxed(dclk->reg) >> dclk->shift; + val &= WIDTH_TO_MASK(dclk->width); + + div = hi3620_get_table_div(dclk->table, val); + if (!div) { + pr_warning("%s: Invalid divisor for clock %s\n", __func__, + __clk_get_name(hw->clk)); + return parent_rate; + } + + return parent_rate / div; +} + +static bool hi3620_is_valid_table_div(const struct clk_div_table *table, + unsigned int div) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->div == div) + return true; + return false; +} + +static int hi3620_clkdiv_bestdiv(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate) +{ + struct hi3620_divclk *dclk = container_of(hw, struct hi3620_divclk, hw); + struct clk *clk_parent = __clk_get_parent(hw->clk); + int i, bestdiv = 0; + unsigned long parent_rate, best = 0, now, maxdiv; + + maxdiv = hi3620_get_table_maxdiv(dclk->table); + + if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) { + parent_rate = *best_parent_rate; + bestdiv = DIV_ROUND_UP(parent_rate, rate); + bestdiv = bestdiv == 0 ? 1 : bestdiv; + bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; + return bestdiv; + } + + /* + * The maximum divider we can use without overflowing + * unsigned long in rate * i below + */ + maxdiv = min(ULONG_MAX / rate, maxdiv); + + for (i = 1; i <= maxdiv; i++) { + if (!hi3620_is_valid_table_div(dclk->table, i)) + continue; + parent_rate = __clk_round_rate(clk_parent, + MULT_ROUND_UP(rate, i)); + now = parent_rate / i; + if (now <= rate && now > best) { + bestdiv = i; + best = now; + *best_parent_rate = parent_rate; + } + } + + if (!bestdiv) { + bestdiv = hi3620_get_table_maxdiv(dclk->table); + *best_parent_rate = __clk_round_rate(clk_parent, 1); + } + + return bestdiv; +} + +static long hi3620_clkdiv_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + int div; + + if (!rate) + rate = 1; + div = hi3620_clkdiv_bestdiv(hw, rate, prate); + + return *prate / div; +} + +static int hi3620_clkdiv_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct hi3620_divclk *dclk = container_of(hw, struct hi3620_divclk, hw); + unsigned int div, value; + unsigned long flags = 0; + u32 data; + + div = parent_rate / rate; + value = hi3620_get_table_val(dclk->table, div); + + if (value > WIDTH_TO_MASK(dclk->width)) + value = WIDTH_TO_MASK(dclk->width); + + if (dclk->lock) + spin_lock_irqsave(dclk->lock, flags); + + data = readl_relaxed(dclk->reg); + data &= ~(WIDTH_TO_MASK(dclk->width) << dclk->shift); + data |= value << dclk->shift; + data |= dclk->mbits; + writel_relaxed(data, dclk->reg); + + if (dclk->lock) + spin_unlock_irqrestore(dclk->lock, flags); + + return 0; +} + +static struct clk_ops hi3620_clkdiv_ops = { + .recalc_rate = hi3620_clkdiv_recalc_rate, + .round_rate = hi3620_clkdiv_round_rate, + .set_rate = hi3620_clkdiv_set_rate, +}; + +void __init hi3620_clkdiv_setup(struct device_node *np) +{ + struct clk *clk; + const char *clk_name, **parent_names; + struct clk_init_data *init; + struct clk_div_table *table; + struct hi3620_divclk *dclk; + unsigned int table_num; + int i; + u32 data[2]; + const char *propname = "hisilicon,clkdiv-table"; + const char *cellname = "#hisilicon,clkdiv-table-cells"; + struct of_phandle_args div_table; + + hs_init_clocks(); + if (!hs_clk.sctrl) + return; + + if (of_property_read_string(np, "clock-output-names", &clk_name)) + return; + if (of_property_read_u32_array(np, "hisilicon,clkdiv", + &data[0], 2)) + return; + + /*process the div_table*/ + for (i = 0; ; i++) { + if (of_parse_phandle_with_args(np, propname, cellname, + i, &div_table)) + 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++) { + if (of_parse_phandle_with_args(np, propname, cellname, + i, &div_table)) + break; + + table[i].val = div_table.args[0]; + table[i].div = div_table.args[1]; + } + + /* gate only has the fixed parent */ + parent_names = kzalloc(sizeof(char *), GFP_KERNEL); + if (!parent_names) + goto err_par; + parent_names[0] = of_clk_get_parent_name(np, 0); + + dclk = kzalloc(sizeof(*dclk), GFP_KERNEL); + if (!dclk) + goto err_dclk; + init = kzalloc(sizeof(*init), GFP_KERNEL); + if (!init) + goto err_init; + init->name = kstrdup(clk_name, GFP_KERNEL); + init->ops = &hi3620_clkdiv_ops; + init->parent_names = parent_names; + init->num_parents = 1; + + dclk->reg = hs_clk.sctrl + data[0]; + dclk->shift = ffs(data[1]) - 1; + dclk->width = fls(data[1]) - ffs(data[1]) + 1; + dclk->mbits = data[1] << 16; + dclk->lock = &hs_clk.lock; + dclk->hw.init = init; + dclk->table = table; + clk = clk_register(NULL, &dclk->hw); + if (IS_ERR(clk)) + goto err_clk; + of_clk_add_provider(np, of_clk_src_simple_get, clk); + return; +err_clk: + kfree(init); +err_init: + kfree(dclk); +err_dclk: + kfree(parent_names); +err_par: + kfree(table); +} +CLK_OF_DECLARE(hi3620_mux, "hisilicon,hi3620-clk-mux", hi3620_clkmux_setup) +CLK_OF_DECLARE(hi3620_gate, "hisilicon,hi3620-clk-gate", hi3620_clkgate_setup) +CLK_OF_DECLARE(hi3620_div, "hisilicon,hi3620-clk-div", hi3620_clkdiv_setup) +CLK_OF_DECLARE(hs_gate, "hisilicon,clk-gate", hs_clkgate_setup) +CLK_OF_DECLARE(hs_fixed, "hisilicon,clk-fixed-factor", hs_fixed_factor_setup) + +static void __init hs_init_clocks(void) +{ + struct device_node *node = NULL; + + if (!hs_clk.pmctrl) { + /* map pmctrl registers */ + node = of_find_compatible_node(NULL, NULL, "hisilicon,pmctrl"); + hs_clk.pmctrl = of_iomap(node, 0); + WARN_ON(!hs_clk.pmctrl); + } + + if (!hs_clk.sctrl) { + node = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl"); + hs_clk.sctrl = of_iomap(node, 0); + } +} -- cgit v1.2.3 From 806a98af2fa0784a9c3756d0329ad9381fc975b1 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Fri, 22 Mar 2013 23:46:19 +0800 Subject: clk: hi3xxx: set clkgate reset as optional There are not reset registers for all Hi3620 clock gate. So set reset registers as optional. Signed-off-by: Haojian Zhuang --- drivers/clk/clk-hi3xxx.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/clk/clk-hi3xxx.c b/drivers/clk/clk-hi3xxx.c index ac1520b49729..11dfb1b6e025 100644 --- a/drivers/clk/clk-hi3xxx.c +++ b/drivers/clk/clk-hi3xxx.c @@ -94,8 +94,10 @@ static int hi3620_clkgate_prepare(struct clk_hw *hw) if (pclk->lock) spin_lock_irqsave(pclk->lock, flags); writel_relaxed(pclk->ebits, pclk->enable + HI3620_DISABLE_OFF); - writel_relaxed(pclk->rbits, pclk->reset + HI3620_DISABLE_OFF); - readl_relaxed(pclk->reset + HI3620_STATUS_OFF); + if (pclk->reset) { + writel_relaxed(pclk->rbits, pclk->reset + HI3620_DISABLE_OFF); + readl_relaxed(pclk->reset + HI3620_STATUS_OFF); + } if (pclk->lock) spin_unlock_irqrestore(pclk->lock, flags); return 0; @@ -149,9 +151,6 @@ static void __init hi3620_clkgate_setup(struct device_node *np) if (of_property_read_string(np, "clock-output-names", &clk_name)) return; - if (of_property_read_u32_array(np, "hisilicon,hi3620-clkreset", - &rdata[0], 2)) - return; if (of_property_read_u32_array(np, "hisilicon,hi3620-clkgate", &gdata[0], 2)) return; @@ -175,8 +174,14 @@ static void __init hi3620_clkgate_setup(struct device_node *np) init->parent_names = parent_names; init->num_parents = 1; - pclk->reset = hs_clk.sctrl + rdata[0]; - pclk->rbits = rdata[1]; + if (of_property_read_u32_array(np, "hisilicon,hi3620-clkreset", + &rdata[0], 2)) { + pclk->reset = 0; + pclk->rbits = 0; + } else { + pclk->reset = hs_clk.sctrl + rdata[0]; + pclk->rbits = rdata[1]; + } pclk->enable = hs_clk.sctrl + gdata[0]; pclk->ebits = gdata[1]; pclk->lock = &hs_clk.lock; -- cgit v1.2.3 From 1c897b79798217b81a4e6c850fe74ab7fe511bd7 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Sat, 23 Mar 2013 18:15:11 +0800 Subject: clk: hi3xxx: remove sctrl in clk ops Avoid to reference sctrl in clk ops. Make hs_init_clocks() always return register base address. It could make code more portable for more silicons. Signed-off-by: Haojian Zhuang --- drivers/clk/clk-hi3xxx.c | 87 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 61 insertions(+), 26 deletions(-) diff --git a/drivers/clk/clk-hi3xxx.c b/drivers/clk/clk-hi3xxx.c index 11dfb1b6e025..ce13c3907b61 100644 --- a/drivers/clk/clk-hi3xxx.c +++ b/drivers/clk/clk-hi3xxx.c @@ -46,6 +46,11 @@ */ #define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1) +enum { + HS_PMCTRL, + HS_SYSCTRL, +}; + struct hi3620_periclk { struct clk_hw hw; void __iomem *enable; /* enable register */ @@ -80,7 +85,7 @@ struct hs_clk { spinlock_t lock; }; -static void __init hs_init_clocks(void); +static void __iomem __init *hs_init_clocks(struct device_node *np); static struct hs_clk hs_clk; @@ -144,9 +149,11 @@ static void __init hi3620_clkgate_setup(struct device_node *np) struct clk_init_data *init; struct clk *clk; const char *clk_name, *name, **parent_names; + void __iomem *reg_base; u32 rdata[2], gdata[2]; - if (!hs_clk.sctrl) + reg_base = hs_init_clocks(np); + if (!reg_base) return; if (of_property_read_string(np, "clock-output-names", &clk_name)) @@ -179,10 +186,10 @@ static void __init hi3620_clkgate_setup(struct device_node *np) pclk->reset = 0; pclk->rbits = 0; } else { - pclk->reset = hs_clk.sctrl + rdata[0]; + pclk->reset = reg_base + rdata[0]; pclk->rbits = rdata[1]; } - pclk->enable = hs_clk.sctrl + gdata[0]; + pclk->enable = reg_base + gdata[0]; pclk->ebits = gdata[1]; pclk->lock = &hs_clk.lock; pclk->hw.init = init; @@ -261,12 +268,13 @@ static void __init hi3620_clkmux_setup(struct device_node *np) struct clk_init_data *init; struct clk *clk; const char *clk_name, **parent_names; + void __iomem *reg_base; u32 rdata[2]; u8 num_parents; int i; - hs_init_clocks(); - if (!hs_clk.sctrl) + reg_base = hs_init_clocks(np); + if (!reg_base) return; if (of_property_read_string(np, "clock-output-names", &clk_name)) @@ -299,7 +307,7 @@ static void __init hi3620_clkmux_setup(struct device_node *np) init->parent_names = parent_names; init->num_parents = num_parents; - mclk->reg = hs_clk.sctrl + rdata[0]; + mclk->reg = reg_base + rdata[0]; /* enable_mask bits are in higher 16bits */ mclk->mbits = rdata[1] << 16; mclk->shift = ffs(rdata[1]) - 1; @@ -326,10 +334,11 @@ static void __init hs_clkgate_setup(struct device_node *np) struct clk *clk; const char *clk_name, **parent_names, *name; unsigned long flags = 0; + void __iomem *reg_base; u32 data[2]; - hs_init_clocks(); - if (!hs_clk.sctrl) + reg_base = hs_init_clocks(np); + if (!reg_base) return; if (of_property_read_string(np, "clock-output-names", &clk_name)) return; @@ -345,7 +354,7 @@ static void __init hs_clkgate_setup(struct device_node *np) parent_names[0] = of_clk_get_parent_name(np, 0); clk = clk_register_gate(NULL, clk_name, parent_names[0], 0, - hs_clk.sctrl + data[0], (u8)data[1], flags, + reg_base + data[0], (u8)data[1], flags, &hs_clk.lock); if (IS_ERR(clk)) goto err; @@ -546,6 +555,7 @@ void __init hi3620_clkdiv_setup(struct device_node *np) struct clk_init_data *init; struct clk_div_table *table; struct hi3620_divclk *dclk; + void __iomem *reg_base; unsigned int table_num; int i; u32 data[2]; @@ -553,8 +563,8 @@ void __init hi3620_clkdiv_setup(struct device_node *np) const char *cellname = "#hisilicon,clkdiv-table-cells"; struct of_phandle_args div_table; - hs_init_clocks(); - if (!hs_clk.sctrl) + reg_base = hs_init_clocks(np); + if (!reg_base) return; if (of_property_read_string(np, "clock-output-names", &clk_name)) @@ -603,7 +613,7 @@ void __init hi3620_clkdiv_setup(struct device_node *np) init->parent_names = parent_names; init->num_parents = 1; - dclk->reg = hs_clk.sctrl + data[0]; + dclk->reg = reg_base + data[0]; dclk->shift = ffs(data[1]) - 1; dclk->width = fls(data[1]) - ffs(data[1]) + 1; dclk->mbits = data[1] << 16; @@ -624,25 +634,50 @@ err_dclk: err_par: kfree(table); } + CLK_OF_DECLARE(hi3620_mux, "hisilicon,hi3620-clk-mux", hi3620_clkmux_setup) CLK_OF_DECLARE(hi3620_gate, "hisilicon,hi3620-clk-gate", hi3620_clkgate_setup) CLK_OF_DECLARE(hi3620_div, "hisilicon,hi3620-clk-div", hi3620_clkdiv_setup) CLK_OF_DECLARE(hs_gate, "hisilicon,clk-gate", hs_clkgate_setup) CLK_OF_DECLARE(hs_fixed, "hisilicon,clk-fixed-factor", hs_fixed_factor_setup) -static void __init hs_init_clocks(void) -{ - struct device_node *node = NULL; - - if (!hs_clk.pmctrl) { - /* map pmctrl registers */ - node = of_find_compatible_node(NULL, NULL, "hisilicon,pmctrl"); - hs_clk.pmctrl = of_iomap(node, 0); - WARN_ON(!hs_clk.pmctrl); - } +static const struct of_device_id hs_of_match[] = { + { .compatible = "hisilicon,pmctrl", .data = (void *)HS_PMCTRL, }, + { .compatible = "hisilicon,sysctrl", .data = (void *)HS_SYSCTRL, }, +}; - if (!hs_clk.sctrl) { - node = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl"); - hs_clk.sctrl = of_iomap(node, 0); +static void __iomem __init *hs_init_clocks(struct device_node *np) +{ + struct device_node *parent; + const struct of_device_id *match; + void __iomem *ret = NULL; + + parent = of_get_parent(np); + if (!parent) + goto out; + match = of_match_node(hs_of_match, parent); + if (!match) + goto out; + switch ((unsigned int)match->data) { + case HS_PMCTRL: + if (!hs_clk.pmctrl) { + ret = of_iomap(parent, 0); + WARN_ON(!ret); + hs_clk.pmctrl = ret; + } else { + ret = hs_clk.pmctrl; + } + break; + case HS_SYSCTRL: + if (!hs_clk.sctrl) { + ret = of_iomap(parent, 0); + WARN_ON(!ret); + hs_clk.sctrl = ret; + } else { + ret = hs_clk.sctrl; + } + break; } +out: + return ret; } -- cgit v1.2.3 From e488e27a105eda32ea5503bc1784dcc677ad089e Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Sun, 24 Mar 2013 10:58:53 +0800 Subject: clk: hi3xxx: move driver into hisilicon directory Since more code will be appended, creating a directory is better. Signed-off-by: Haojian Zhuang --- drivers/clk/Kconfig | 1 + drivers/clk/Makefile | 2 +- drivers/clk/clk-hi3xxx.c | 683 ------------------------------------- drivers/clk/hisilicon/Kconfig | 3 + drivers/clk/hisilicon/Makefile | 1 + drivers/clk/hisilicon/clk-hi3xxx.c | 683 +++++++++++++++++++++++++++++++++++++ 6 files changed, 689 insertions(+), 684 deletions(-) delete mode 100644 drivers/clk/clk-hi3xxx.c create mode 100644 drivers/clk/hisilicon/Kconfig create mode 100644 drivers/clk/hisilicon/Makefile create mode 100644 drivers/clk/hisilicon/clk-hi3xxx.c diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index a47e6ee98b8c..a18280ad62fb 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -65,4 +65,5 @@ config CLK_TWL6040 endmenu +source "drivers/clk/hisilicon/Kconfig" source "drivers/clk/mvebu/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index e33911624624..4190b55fa456 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -12,7 +12,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-mux.o obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o -obj-$(CONFIG_ARCH_HS) += clk-hi3xxx.o +obj-$(CONFIG_ARCH_HS) += hisilicon/ obj-$(CONFIG_ARCH_MXS) += mxs/ obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ obj-$(CONFIG_PLAT_SPEAR) += spear/ diff --git a/drivers/clk/clk-hi3xxx.c b/drivers/clk/clk-hi3xxx.c deleted file mode 100644 index ce13c3907b61..000000000000 --- a/drivers/clk/clk-hi3xxx.c +++ /dev/null @@ -1,683 +0,0 @@ -/* - * Hisilicon clock driver - * - * Copyright (c) 2012-2013 Hisilicon Limited. - * Copyright (c) 2012-2013 Linaro Limited. - * - * Author: Haojian Zhuang - * Xin Li - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define HI3620_DISABLE_OFF 0x4 -#define HI3620_STATUS_OFF 0x8 - -#define WIDTH_TO_MASK(width) ((1 << (width)) - 1) - -/* - * The reverse of DIV_ROUND_UP: The maximum number which - * divided by m is r - */ -#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1) - -enum { - HS_PMCTRL, - HS_SYSCTRL, -}; - -struct hi3620_periclk { - struct clk_hw hw; - void __iomem *enable; /* enable register */ - void __iomem *reset; /* reset register */ - u32 ebits; /* bits in enable/disable register */ - u32 rbits; /* bits in reset/unreset register */ - spinlock_t *lock; -}; - -struct hi3620_muxclk { - struct clk_hw hw; - void __iomem *reg; /* mux register */ - u8 shift; - u8 width; - u32 mbits; /* mask bits in mux register */ - spinlock_t *lock; -}; - -struct hi3620_divclk { - struct clk_hw hw; - void __iomem *reg; /* divider register */ - u8 shift; - u8 width; - u32 mbits; /* mask bits in divider register */ - const struct clk_div_table *table; - spinlock_t *lock; -}; - -struct hs_clk { - void __iomem *pmctrl; - void __iomem *sctrl; - spinlock_t lock; -}; - -static void __iomem __init *hs_init_clocks(struct device_node *np); - -static struct hs_clk hs_clk; - -static int hi3620_clkgate_prepare(struct clk_hw *hw) -{ - struct hi3620_periclk *pclk; - unsigned long flags = 0; - - pclk = container_of(hw, struct hi3620_periclk, hw); - - if (pclk->lock) - spin_lock_irqsave(pclk->lock, flags); - writel_relaxed(pclk->ebits, pclk->enable + HI3620_DISABLE_OFF); - if (pclk->reset) { - writel_relaxed(pclk->rbits, pclk->reset + HI3620_DISABLE_OFF); - readl_relaxed(pclk->reset + HI3620_STATUS_OFF); - } - if (pclk->lock) - spin_unlock_irqrestore(pclk->lock, flags); - return 0; -} - -static int hi3620_clkgate_enable(struct clk_hw *hw) -{ - struct hi3620_periclk *pclk; - unsigned long flags = 0; - - pclk = container_of(hw, struct hi3620_periclk, hw); - if (pclk->lock) - spin_lock_irqsave(pclk->lock, flags); - writel_relaxed(pclk->ebits, pclk->enable); - readl_relaxed(pclk->enable + HI3620_STATUS_OFF); - if (pclk->lock) - spin_unlock_irqrestore(pclk->lock, flags); - return 0; -} - -static void hi3620_clkgate_disable(struct clk_hw *hw) -{ - struct hi3620_periclk *pclk; - unsigned long flags = 0; - - pclk = container_of(hw, struct hi3620_periclk, hw); - if (pclk->lock) - spin_lock_irqsave(pclk->lock, flags); - writel_relaxed(pclk->ebits, pclk->enable + HI3620_DISABLE_OFF); - readl_relaxed(pclk->enable + HI3620_STATUS_OFF); - if (pclk->lock) - spin_unlock_irqrestore(pclk->lock, flags); -} - -static struct clk_ops hi3620_clkgate_ops = { - .prepare = hi3620_clkgate_prepare, - .enable = hi3620_clkgate_enable, - .disable = hi3620_clkgate_disable, -}; - -static void __init hi3620_clkgate_setup(struct device_node *np) -{ - struct hi3620_periclk *pclk; - struct clk_init_data *init; - struct clk *clk; - const char *clk_name, *name, **parent_names; - void __iomem *reg_base; - u32 rdata[2], gdata[2]; - - reg_base = hs_init_clocks(np); - if (!reg_base) - return; - - if (of_property_read_string(np, "clock-output-names", &clk_name)) - return; - if (of_property_read_u32_array(np, "hisilicon,hi3620-clkgate", - &gdata[0], 2)) - return; - - /* gate only has the fixed parent */ - parent_names = kzalloc(sizeof(char *), GFP_KERNEL); - if (!parent_names) - return; - parent_names[0] = of_clk_get_parent_name(np, 0); - - pclk = kzalloc(sizeof(*pclk), GFP_KERNEL); - if (!pclk) - goto err_pclk; - - init = kzalloc(sizeof(*init), GFP_KERNEL); - if (!init) - goto err_init; - init->name = kstrdup(clk_name, GFP_KERNEL); - init->ops = &hi3620_clkgate_ops; - init->flags = CLK_SET_RATE_PARENT; - init->parent_names = parent_names; - init->num_parents = 1; - - if (of_property_read_u32_array(np, "hisilicon,hi3620-clkreset", - &rdata[0], 2)) { - pclk->reset = 0; - pclk->rbits = 0; - } else { - pclk->reset = reg_base + rdata[0]; - pclk->rbits = rdata[1]; - } - pclk->enable = reg_base + gdata[0]; - pclk->ebits = gdata[1]; - pclk->lock = &hs_clk.lock; - pclk->hw.init = init; - - clk = clk_register(NULL, &pclk->hw); - if (IS_ERR(clk)) - goto err_clk; - if (!of_property_read_string(np, "clock-names", &name)) - clk_register_clkdev(clk, name, NULL); - of_clk_add_provider(np, of_clk_src_simple_get, clk); - return; -err_clk: - kfree(init); -err_init: - kfree(pclk); -err_pclk: - kfree(parent_names); -} - -static u8 hi3620_clk_get_parent(struct clk_hw *hw) -{ - struct hi3620_muxclk *mclk; - u32 data; - unsigned long flags = 0; - - mclk = container_of(hw, struct hi3620_muxclk, hw); - - if (mclk->lock) - spin_lock_irqsave(mclk->lock, flags); - - data = readl_relaxed(mclk->reg) >> mclk->shift; - data &= WIDTH_TO_MASK(mclk->width); - - if (mclk->lock) - spin_unlock_irqrestore(mclk->lock, flags); - - if (data >= __clk_get_num_parents(hw->clk)) - return -EINVAL; - - return (u8)data; -} - -static int hi3620_clk_set_parent(struct clk_hw *hw, u8 index) -{ - struct hi3620_muxclk *mclk; - u32 data; - unsigned long flags = 0; - - mclk = container_of(hw, struct hi3620_muxclk, hw); - - if (mclk->lock) - spin_lock_irqsave(mclk->lock, flags); - - data = readl_relaxed(mclk->reg); - data &= ~(WIDTH_TO_MASK(mclk->width) << mclk->shift); - data |= index << mclk->shift; - writel_relaxed(data, mclk->reg); - /* set mask enable bits */ - data |= mclk->mbits; - writel_relaxed(data, mclk->reg); - - if (mclk->lock) - spin_unlock_irqrestore(mclk->lock, flags); - - return 0; -} - -static struct clk_ops hi3620_clkmux_ops = { - .get_parent = hi3620_clk_get_parent, - .set_parent = hi3620_clk_set_parent, -}; - -static void __init hi3620_clkmux_setup(struct device_node *np) -{ - struct hi3620_muxclk *mclk; - struct clk_init_data *init; - struct clk *clk; - const char *clk_name, **parent_names; - void __iomem *reg_base; - u32 rdata[2]; - u8 num_parents; - int i; - - reg_base = hs_init_clocks(np); - if (!reg_base) - return; - - if (of_property_read_string(np, "clock-output-names", &clk_name)) - return; - if (of_property_read_u32_array(np, "hisilicon,hi3620-clkmux", - &rdata[0], 2)) - return; - /* get the count of items in mux */ - for (i = 0; ; i++) { - /* parent's #clock-cells property is always 0 */ - if (!of_parse_phandle(np, "clocks", i)) - break; - } - parent_names = kzalloc(sizeof(char *) * i, GFP_KERNEL); - if (!parent_names) - return; - - for (num_parents = i, i = 0; i < num_parents; i++) - parent_names[i] = of_clk_get_parent_name(np, i); - - mclk = kzalloc(sizeof(*mclk), GFP_KERNEL); - if (!mclk) - goto err_mclk; - init = kzalloc(sizeof(*init), GFP_KERNEL); - if (!init) - goto err_init; - init->name = kstrdup(clk_name, GFP_KERNEL); - init->ops = &hi3620_clkmux_ops; - init->flags = CLK_SET_RATE_PARENT; - init->parent_names = parent_names; - init->num_parents = num_parents; - - mclk->reg = reg_base + rdata[0]; - /* enable_mask bits are in higher 16bits */ - mclk->mbits = rdata[1] << 16; - mclk->shift = ffs(rdata[1]) - 1; - mclk->width = fls(rdata[1]) - ffs(rdata[1]) + 1; - mclk->lock = &hs_clk.lock; - mclk->hw.init = init; - - clk = clk_register(NULL, &mclk->hw); - if (IS_ERR(clk)) - goto err_clk; - of_clk_add_provider(np, of_clk_src_simple_get, clk); - - return; -err_clk: - kfree(init); -err_init: - kfree(mclk); -err_mclk: - kfree(parent_names); -} - -static void __init hs_clkgate_setup(struct device_node *np) -{ - struct clk *clk; - const char *clk_name, **parent_names, *name; - unsigned long flags = 0; - void __iomem *reg_base; - u32 data[2]; - - reg_base = hs_init_clocks(np); - if (!reg_base) - return; - if (of_property_read_string(np, "clock-output-names", &clk_name)) - return; - if (of_property_read_u32_array(np, "hisilicon,clkgate", - &data[0], 2)) - return; - if (of_property_read_bool(np, "hisilicon,clkgate-inverted")) - flags = CLK_GATE_SET_TO_DISABLE; - /* gate only has the fixed parent */ - parent_names = kzalloc(sizeof(char *), GFP_KERNEL); - if (!parent_names) - return; - parent_names[0] = of_clk_get_parent_name(np, 0); - - clk = clk_register_gate(NULL, clk_name, parent_names[0], 0, - reg_base + data[0], (u8)data[1], flags, - &hs_clk.lock); - if (IS_ERR(clk)) - goto err; - if (!of_property_read_string(np, "clock-names", &name)) - clk_register_clkdev(clk, name, NULL); - of_clk_add_provider(np, of_clk_src_simple_get, clk); - return; -err: - kfree(parent_names); -} - -void __init hs_fixed_factor_setup(struct device_node *np) -{ - struct clk *clk; - const char *clk_name, **parent_names; - u32 data[2]; - - if (of_property_read_string(np, "clock-output-names", &clk_name)) - return; - if (of_property_read_u32_array(np, "hisilicon,fixed-factor", - data, 2)) - return ; - /* gate only has the fixed parent */ - parent_names = kzalloc(sizeof(char *), GFP_KERNEL); - if (!parent_names) - return; - parent_names[0] = of_clk_get_parent_name(np, 0); - - clk = clk_register_fixed_factor(NULL, clk_name, parent_names[0], 0, - data[0], data[1]); - if (IS_ERR(clk)) - goto err; - of_clk_add_provider(np, of_clk_src_simple_get, clk); - return; -err: - kfree(parent_names); -} - -static unsigned int hi3620_get_table_maxdiv(const struct clk_div_table *table) -{ - unsigned int maxdiv = 0; - const struct clk_div_table *clkt; - - for (clkt = table; clkt->div; clkt++) - if (clkt->div > maxdiv) - maxdiv = clkt->div; - return maxdiv; -} - -static unsigned int hi3620_get_table_div(const struct clk_div_table *table, - unsigned int val) -{ - const struct clk_div_table *clkt; - - for (clkt = table; clkt->div; clkt++) - if (clkt->val == val) - return clkt->div; - return 0; -} - -static unsigned int hi3620_get_table_val(const struct clk_div_table *table, - unsigned int div) -{ - const struct clk_div_table *clkt; - - for (clkt = table; clkt->div; clkt++) - if (clkt->div == div) - return clkt->val; - return 0; -} - -static unsigned long hi3620_clkdiv_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct hi3620_divclk *dclk = container_of(hw, struct hi3620_divclk, hw); - unsigned int div, val; - - val = readl_relaxed(dclk->reg) >> dclk->shift; - val &= WIDTH_TO_MASK(dclk->width); - - div = hi3620_get_table_div(dclk->table, val); - if (!div) { - pr_warning("%s: Invalid divisor for clock %s\n", __func__, - __clk_get_name(hw->clk)); - return parent_rate; - } - - return parent_rate / div; -} - -static bool hi3620_is_valid_table_div(const struct clk_div_table *table, - unsigned int div) -{ - const struct clk_div_table *clkt; - - for (clkt = table; clkt->div; clkt++) - if (clkt->div == div) - return true; - return false; -} - -static int hi3620_clkdiv_bestdiv(struct clk_hw *hw, unsigned long rate, - unsigned long *best_parent_rate) -{ - struct hi3620_divclk *dclk = container_of(hw, struct hi3620_divclk, hw); - struct clk *clk_parent = __clk_get_parent(hw->clk); - int i, bestdiv = 0; - unsigned long parent_rate, best = 0, now, maxdiv; - - maxdiv = hi3620_get_table_maxdiv(dclk->table); - - if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) { - parent_rate = *best_parent_rate; - bestdiv = DIV_ROUND_UP(parent_rate, rate); - bestdiv = bestdiv == 0 ? 1 : bestdiv; - bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; - return bestdiv; - } - - /* - * The maximum divider we can use without overflowing - * unsigned long in rate * i below - */ - maxdiv = min(ULONG_MAX / rate, maxdiv); - - for (i = 1; i <= maxdiv; i++) { - if (!hi3620_is_valid_table_div(dclk->table, i)) - continue; - parent_rate = __clk_round_rate(clk_parent, - MULT_ROUND_UP(rate, i)); - now = parent_rate / i; - if (now <= rate && now > best) { - bestdiv = i; - best = now; - *best_parent_rate = parent_rate; - } - } - - if (!bestdiv) { - bestdiv = hi3620_get_table_maxdiv(dclk->table); - *best_parent_rate = __clk_round_rate(clk_parent, 1); - } - - return bestdiv; -} - -static long hi3620_clkdiv_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - int div; - - if (!rate) - rate = 1; - div = hi3620_clkdiv_bestdiv(hw, rate, prate); - - return *prate / div; -} - -static int hi3620_clkdiv_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct hi3620_divclk *dclk = container_of(hw, struct hi3620_divclk, hw); - unsigned int div, value; - unsigned long flags = 0; - u32 data; - - div = parent_rate / rate; - value = hi3620_get_table_val(dclk->table, div); - - if (value > WIDTH_TO_MASK(dclk->width)) - value = WIDTH_TO_MASK(dclk->width); - - if (dclk->lock) - spin_lock_irqsave(dclk->lock, flags); - - data = readl_relaxed(dclk->reg); - data &= ~(WIDTH_TO_MASK(dclk->width) << dclk->shift); - data |= value << dclk->shift; - data |= dclk->mbits; - writel_relaxed(data, dclk->reg); - - if (dclk->lock) - spin_unlock_irqrestore(dclk->lock, flags); - - return 0; -} - -static struct clk_ops hi3620_clkdiv_ops = { - .recalc_rate = hi3620_clkdiv_recalc_rate, - .round_rate = hi3620_clkdiv_round_rate, - .set_rate = hi3620_clkdiv_set_rate, -}; - -void __init hi3620_clkdiv_setup(struct device_node *np) -{ - struct clk *clk; - const char *clk_name, **parent_names; - struct clk_init_data *init; - struct clk_div_table *table; - struct hi3620_divclk *dclk; - void __iomem *reg_base; - unsigned int table_num; - int i; - u32 data[2]; - const char *propname = "hisilicon,clkdiv-table"; - const char *cellname = "#hisilicon,clkdiv-table-cells"; - struct of_phandle_args div_table; - - reg_base = hs_init_clocks(np); - if (!reg_base) - return; - - if (of_property_read_string(np, "clock-output-names", &clk_name)) - return; - if (of_property_read_u32_array(np, "hisilicon,clkdiv", - &data[0], 2)) - return; - - /*process the div_table*/ - for (i = 0; ; i++) { - if (of_parse_phandle_with_args(np, propname, cellname, - i, &div_table)) - 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++) { - if (of_parse_phandle_with_args(np, propname, cellname, - i, &div_table)) - break; - - table[i].val = div_table.args[0]; - table[i].div = div_table.args[1]; - } - - /* gate only has the fixed parent */ - parent_names = kzalloc(sizeof(char *), GFP_KERNEL); - if (!parent_names) - goto err_par; - parent_names[0] = of_clk_get_parent_name(np, 0); - - dclk = kzalloc(sizeof(*dclk), GFP_KERNEL); - if (!dclk) - goto err_dclk; - init = kzalloc(sizeof(*init), GFP_KERNEL); - if (!init) - goto err_init; - init->name = kstrdup(clk_name, GFP_KERNEL); - init->ops = &hi3620_clkdiv_ops; - init->parent_names = parent_names; - init->num_parents = 1; - - dclk->reg = reg_base + data[0]; - dclk->shift = ffs(data[1]) - 1; - dclk->width = fls(data[1]) - ffs(data[1]) + 1; - dclk->mbits = data[1] << 16; - dclk->lock = &hs_clk.lock; - dclk->hw.init = init; - dclk->table = table; - clk = clk_register(NULL, &dclk->hw); - if (IS_ERR(clk)) - goto err_clk; - of_clk_add_provider(np, of_clk_src_simple_get, clk); - return; -err_clk: - kfree(init); -err_init: - kfree(dclk); -err_dclk: - kfree(parent_names); -err_par: - kfree(table); -} - -CLK_OF_DECLARE(hi3620_mux, "hisilicon,hi3620-clk-mux", hi3620_clkmux_setup) -CLK_OF_DECLARE(hi3620_gate, "hisilicon,hi3620-clk-gate", hi3620_clkgate_setup) -CLK_OF_DECLARE(hi3620_div, "hisilicon,hi3620-clk-div", hi3620_clkdiv_setup) -CLK_OF_DECLARE(hs_gate, "hisilicon,clk-gate", hs_clkgate_setup) -CLK_OF_DECLARE(hs_fixed, "hisilicon,clk-fixed-factor", hs_fixed_factor_setup) - -static const struct of_device_id hs_of_match[] = { - { .compatible = "hisilicon,pmctrl", .data = (void *)HS_PMCTRL, }, - { .compatible = "hisilicon,sysctrl", .data = (void *)HS_SYSCTRL, }, -}; - -static void __iomem __init *hs_init_clocks(struct device_node *np) -{ - struct device_node *parent; - const struct of_device_id *match; - void __iomem *ret = NULL; - - parent = of_get_parent(np); - if (!parent) - goto out; - match = of_match_node(hs_of_match, parent); - if (!match) - goto out; - switch ((unsigned int)match->data) { - case HS_PMCTRL: - if (!hs_clk.pmctrl) { - ret = of_iomap(parent, 0); - WARN_ON(!ret); - hs_clk.pmctrl = ret; - } else { - ret = hs_clk.pmctrl; - } - break; - case HS_SYSCTRL: - if (!hs_clk.sctrl) { - ret = of_iomap(parent, 0); - WARN_ON(!ret); - hs_clk.sctrl = ret; - } else { - ret = hs_clk.sctrl; - } - break; - } -out: - return ret; -} diff --git a/drivers/clk/hisilicon/Kconfig b/drivers/clk/hisilicon/Kconfig new file mode 100644 index 000000000000..344ddb764c1f --- /dev/null +++ b/drivers/clk/hisilicon/Kconfig @@ -0,0 +1,3 @@ +config HI3xxx_CLK_CORE + bool "Core clock driver of Hi3xxx Soc" + default y if COMMON_CLK diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile new file mode 100644 index 000000000000..d5be1b002e5f --- /dev/null +++ b/drivers/clk/hisilicon/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_HI3xxx_CLK_CORE) += clk-hi3xxx.o diff --git a/drivers/clk/hisilicon/clk-hi3xxx.c b/drivers/clk/hisilicon/clk-hi3xxx.c new file mode 100644 index 000000000000..ce13c3907b61 --- /dev/null +++ b/drivers/clk/hisilicon/clk-hi3xxx.c @@ -0,0 +1,683 @@ +/* + * Hisilicon clock driver + * + * Copyright (c) 2012-2013 Hisilicon Limited. + * Copyright (c) 2012-2013 Linaro Limited. + * + * Author: Haojian Zhuang + * Xin Li + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HI3620_DISABLE_OFF 0x4 +#define HI3620_STATUS_OFF 0x8 + +#define WIDTH_TO_MASK(width) ((1 << (width)) - 1) + +/* + * The reverse of DIV_ROUND_UP: The maximum number which + * divided by m is r + */ +#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1) + +enum { + HS_PMCTRL, + HS_SYSCTRL, +}; + +struct hi3620_periclk { + struct clk_hw hw; + void __iomem *enable; /* enable register */ + void __iomem *reset; /* reset register */ + u32 ebits; /* bits in enable/disable register */ + u32 rbits; /* bits in reset/unreset register */ + spinlock_t *lock; +}; + +struct hi3620_muxclk { + struct clk_hw hw; + void __iomem *reg; /* mux register */ + u8 shift; + u8 width; + u32 mbits; /* mask bits in mux register */ + spinlock_t *lock; +}; + +struct hi3620_divclk { + struct clk_hw hw; + void __iomem *reg; /* divider register */ + u8 shift; + u8 width; + u32 mbits; /* mask bits in divider register */ + const struct clk_div_table *table; + spinlock_t *lock; +}; + +struct hs_clk { + void __iomem *pmctrl; + void __iomem *sctrl; + spinlock_t lock; +}; + +static void __iomem __init *hs_init_clocks(struct device_node *np); + +static struct hs_clk hs_clk; + +static int hi3620_clkgate_prepare(struct clk_hw *hw) +{ + struct hi3620_periclk *pclk; + unsigned long flags = 0; + + pclk = container_of(hw, struct hi3620_periclk, hw); + + if (pclk->lock) + spin_lock_irqsave(pclk->lock, flags); + writel_relaxed(pclk->ebits, pclk->enable + HI3620_DISABLE_OFF); + if (pclk->reset) { + writel_relaxed(pclk->rbits, pclk->reset + HI3620_DISABLE_OFF); + readl_relaxed(pclk->reset + HI3620_STATUS_OFF); + } + if (pclk->lock) + spin_unlock_irqrestore(pclk->lock, flags); + return 0; +} + +static int hi3620_clkgate_enable(struct clk_hw *hw) +{ + struct hi3620_periclk *pclk; + unsigned long flags = 0; + + pclk = container_of(hw, struct hi3620_periclk, hw); + if (pclk->lock) + spin_lock_irqsave(pclk->lock, flags); + writel_relaxed(pclk->ebits, pclk->enable); + readl_relaxed(pclk->enable + HI3620_STATUS_OFF); + if (pclk->lock) + spin_unlock_irqrestore(pclk->lock, flags); + return 0; +} + +static void hi3620_clkgate_disable(struct clk_hw *hw) +{ + struct hi3620_periclk *pclk; + unsigned long flags = 0; + + pclk = container_of(hw, struct hi3620_periclk, hw); + if (pclk->lock) + spin_lock_irqsave(pclk->lock, flags); + writel_relaxed(pclk->ebits, pclk->enable + HI3620_DISABLE_OFF); + readl_relaxed(pclk->enable + HI3620_STATUS_OFF); + if (pclk->lock) + spin_unlock_irqrestore(pclk->lock, flags); +} + +static struct clk_ops hi3620_clkgate_ops = { + .prepare = hi3620_clkgate_prepare, + .enable = hi3620_clkgate_enable, + .disable = hi3620_clkgate_disable, +}; + +static void __init hi3620_clkgate_setup(struct device_node *np) +{ + struct hi3620_periclk *pclk; + struct clk_init_data *init; + struct clk *clk; + const char *clk_name, *name, **parent_names; + void __iomem *reg_base; + u32 rdata[2], gdata[2]; + + reg_base = hs_init_clocks(np); + if (!reg_base) + return; + + if (of_property_read_string(np, "clock-output-names", &clk_name)) + return; + if (of_property_read_u32_array(np, "hisilicon,hi3620-clkgate", + &gdata[0], 2)) + return; + + /* gate only has the fixed parent */ + parent_names = kzalloc(sizeof(char *), GFP_KERNEL); + if (!parent_names) + return; + parent_names[0] = of_clk_get_parent_name(np, 0); + + pclk = kzalloc(sizeof(*pclk), GFP_KERNEL); + if (!pclk) + goto err_pclk; + + init = kzalloc(sizeof(*init), GFP_KERNEL); + if (!init) + goto err_init; + init->name = kstrdup(clk_name, GFP_KERNEL); + init->ops = &hi3620_clkgate_ops; + init->flags = CLK_SET_RATE_PARENT; + init->parent_names = parent_names; + init->num_parents = 1; + + if (of_property_read_u32_array(np, "hisilicon,hi3620-clkreset", + &rdata[0], 2)) { + pclk->reset = 0; + pclk->rbits = 0; + } else { + pclk->reset = reg_base + rdata[0]; + pclk->rbits = rdata[1]; + } + pclk->enable = reg_base + gdata[0]; + pclk->ebits = gdata[1]; + pclk->lock = &hs_clk.lock; + pclk->hw.init = init; + + clk = clk_register(NULL, &pclk->hw); + if (IS_ERR(clk)) + goto err_clk; + if (!of_property_read_string(np, "clock-names", &name)) + clk_register_clkdev(clk, name, NULL); + of_clk_add_provider(np, of_clk_src_simple_get, clk); + return; +err_clk: + kfree(init); +err_init: + kfree(pclk); +err_pclk: + kfree(parent_names); +} + +static u8 hi3620_clk_get_parent(struct clk_hw *hw) +{ + struct hi3620_muxclk *mclk; + u32 data; + unsigned long flags = 0; + + mclk = container_of(hw, struct hi3620_muxclk, hw); + + if (mclk->lock) + spin_lock_irqsave(mclk->lock, flags); + + data = readl_relaxed(mclk->reg) >> mclk->shift; + data &= WIDTH_TO_MASK(mclk->width); + + if (mclk->lock) + spin_unlock_irqrestore(mclk->lock, flags); + + if (data >= __clk_get_num_parents(hw->clk)) + return -EINVAL; + + return (u8)data; +} + +static int hi3620_clk_set_parent(struct clk_hw *hw, u8 index) +{ + struct hi3620_muxclk *mclk; + u32 data; + unsigned long flags = 0; + + mclk = container_of(hw, struct hi3620_muxclk, hw); + + if (mclk->lock) + spin_lock_irqsave(mclk->lock, flags); + + data = readl_relaxed(mclk->reg); + data &= ~(WIDTH_TO_MASK(mclk->width) << mclk->shift); + data |= index << mclk->shift; + writel_relaxed(data, mclk->reg); + /* set mask enable bits */ + data |= mclk->mbits; + writel_relaxed(data, mclk->reg); + + if (mclk->lock) + spin_unlock_irqrestore(mclk->lock, flags); + + return 0; +} + +static struct clk_ops hi3620_clkmux_ops = { + .get_parent = hi3620_clk_get_parent, + .set_parent = hi3620_clk_set_parent, +}; + +static void __init hi3620_clkmux_setup(struct device_node *np) +{ + struct hi3620_muxclk *mclk; + struct clk_init_data *init; + struct clk *clk; + const char *clk_name, **parent_names; + void __iomem *reg_base; + u32 rdata[2]; + u8 num_parents; + int i; + + reg_base = hs_init_clocks(np); + if (!reg_base) + return; + + if (of_property_read_string(np, "clock-output-names", &clk_name)) + return; + if (of_property_read_u32_array(np, "hisilicon,hi3620-clkmux", + &rdata[0], 2)) + return; + /* get the count of items in mux */ + for (i = 0; ; i++) { + /* parent's #clock-cells property is always 0 */ + if (!of_parse_phandle(np, "clocks", i)) + break; + } + parent_names = kzalloc(sizeof(char *) * i, GFP_KERNEL); + if (!parent_names) + return; + + for (num_parents = i, i = 0; i < num_parents; i++) + parent_names[i] = of_clk_get_parent_name(np, i); + + mclk = kzalloc(sizeof(*mclk), GFP_KERNEL); + if (!mclk) + goto err_mclk; + init = kzalloc(sizeof(*init), GFP_KERNEL); + if (!init) + goto err_init; + init->name = kstrdup(clk_name, GFP_KERNEL); + init->ops = &hi3620_clkmux_ops; + init->flags = CLK_SET_RATE_PARENT; + init->parent_names = parent_names; + init->num_parents = num_parents; + + mclk->reg = reg_base + rdata[0]; + /* enable_mask bits are in higher 16bits */ + mclk->mbits = rdata[1] << 16; + mclk->shift = ffs(rdata[1]) - 1; + mclk->width = fls(rdata[1]) - ffs(rdata[1]) + 1; + mclk->lock = &hs_clk.lock; + mclk->hw.init = init; + + clk = clk_register(NULL, &mclk->hw); + if (IS_ERR(clk)) + goto err_clk; + of_clk_add_provider(np, of_clk_src_simple_get, clk); + + return; +err_clk: + kfree(init); +err_init: + kfree(mclk); +err_mclk: + kfree(parent_names); +} + +static void __init hs_clkgate_setup(struct device_node *np) +{ + struct clk *clk; + const char *clk_name, **parent_names, *name; + unsigned long flags = 0; + void __iomem *reg_base; + u32 data[2]; + + reg_base = hs_init_clocks(np); + if (!reg_base) + return; + if (of_property_read_string(np, "clock-output-names", &clk_name)) + return; + if (of_property_read_u32_array(np, "hisilicon,clkgate", + &data[0], 2)) + return; + if (of_property_read_bool(np, "hisilicon,clkgate-inverted")) + flags = CLK_GATE_SET_TO_DISABLE; + /* gate only has the fixed parent */ + parent_names = kzalloc(sizeof(char *), GFP_KERNEL); + if (!parent_names) + return; + parent_names[0] = of_clk_get_parent_name(np, 0); + + clk = clk_register_gate(NULL, clk_name, parent_names[0], 0, + reg_base + data[0], (u8)data[1], flags, + &hs_clk.lock); + if (IS_ERR(clk)) + goto err; + if (!of_property_read_string(np, "clock-names", &name)) + clk_register_clkdev(clk, name, NULL); + of_clk_add_provider(np, of_clk_src_simple_get, clk); + return; +err: + kfree(parent_names); +} + +void __init hs_fixed_factor_setup(struct device_node *np) +{ + struct clk *clk; + const char *clk_name, **parent_names; + u32 data[2]; + + if (of_property_read_string(np, "clock-output-names", &clk_name)) + return; + if (of_property_read_u32_array(np, "hisilicon,fixed-factor", + data, 2)) + return ; + /* gate only has the fixed parent */ + parent_names = kzalloc(sizeof(char *), GFP_KERNEL); + if (!parent_names) + return; + parent_names[0] = of_clk_get_parent_name(np, 0); + + clk = clk_register_fixed_factor(NULL, clk_name, parent_names[0], 0, + data[0], data[1]); + if (IS_ERR(clk)) + goto err; + of_clk_add_provider(np, of_clk_src_simple_get, clk); + return; +err: + kfree(parent_names); +} + +static unsigned int hi3620_get_table_maxdiv(const struct clk_div_table *table) +{ + unsigned int maxdiv = 0; + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->div > maxdiv) + maxdiv = clkt->div; + return maxdiv; +} + +static unsigned int hi3620_get_table_div(const struct clk_div_table *table, + unsigned int val) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->val == val) + return clkt->div; + return 0; +} + +static unsigned int hi3620_get_table_val(const struct clk_div_table *table, + unsigned int div) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->div == div) + return clkt->val; + return 0; +} + +static unsigned long hi3620_clkdiv_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct hi3620_divclk *dclk = container_of(hw, struct hi3620_divclk, hw); + unsigned int div, val; + + val = readl_relaxed(dclk->reg) >> dclk->shift; + val &= WIDTH_TO_MASK(dclk->width); + + div = hi3620_get_table_div(dclk->table, val); + if (!div) { + pr_warning("%s: Invalid divisor for clock %s\n", __func__, + __clk_get_name(hw->clk)); + return parent_rate; + } + + return parent_rate / div; +} + +static bool hi3620_is_valid_table_div(const struct clk_div_table *table, + unsigned int div) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->div == div) + return true; + return false; +} + +static int hi3620_clkdiv_bestdiv(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate) +{ + struct hi3620_divclk *dclk = container_of(hw, struct hi3620_divclk, hw); + struct clk *clk_parent = __clk_get_parent(hw->clk); + int i, bestdiv = 0; + unsigned long parent_rate, best = 0, now, maxdiv; + + maxdiv = hi3620_get_table_maxdiv(dclk->table); + + if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) { + parent_rate = *best_parent_rate; + bestdiv = DIV_ROUND_UP(parent_rate, rate); + bestdiv = bestdiv == 0 ? 1 : bestdiv; + bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; + return bestdiv; + } + + /* + * The maximum divider we can use without overflowing + * unsigned long in rate * i below + */ + maxdiv = min(ULONG_MAX / rate, maxdiv); + + for (i = 1; i <= maxdiv; i++) { + if (!hi3620_is_valid_table_div(dclk->table, i)) + continue; + parent_rate = __clk_round_rate(clk_parent, + MULT_ROUND_UP(rate, i)); + now = parent_rate / i; + if (now <= rate && now > best) { + bestdiv = i; + best = now; + *best_parent_rate = parent_rate; + } + } + + if (!bestdiv) { + bestdiv = hi3620_get_table_maxdiv(dclk->table); + *best_parent_rate = __clk_round_rate(clk_parent, 1); + } + + return bestdiv; +} + +static long hi3620_clkdiv_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + int div; + + if (!rate) + rate = 1; + div = hi3620_clkdiv_bestdiv(hw, rate, prate); + + return *prate / div; +} + +static int hi3620_clkdiv_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct hi3620_divclk *dclk = container_of(hw, struct hi3620_divclk, hw); + unsigned int div, value; + unsigned long flags = 0; + u32 data; + + div = parent_rate / rate; + value = hi3620_get_table_val(dclk->table, div); + + if (value > WIDTH_TO_MASK(dclk->width)) + value = WIDTH_TO_MASK(dclk->width); + + if (dclk->lock) + spin_lock_irqsave(dclk->lock, flags); + + data = readl_relaxed(dclk->reg); + data &= ~(WIDTH_TO_MASK(dclk->width) << dclk->shift); + data |= value << dclk->shift; + data |= dclk->mbits; + writel_relaxed(data, dclk->reg); + + if (dclk->lock) + spin_unlock_irqrestore(dclk->lock, flags); + + return 0; +} + +static struct clk_ops hi3620_clkdiv_ops = { + .recalc_rate = hi3620_clkdiv_recalc_rate, + .round_rate = hi3620_clkdiv_round_rate, + .set_rate = hi3620_clkdiv_set_rate, +}; + +void __init hi3620_clkdiv_setup(struct device_node *np) +{ + struct clk *clk; + const char *clk_name, **parent_names; + struct clk_init_data *init; + struct clk_div_table *table; + struct hi3620_divclk *dclk; + void __iomem *reg_base; + unsigned int table_num; + int i; + u32 data[2]; + const char *propname = "hisilicon,clkdiv-table"; + const char *cellname = "#hisilicon,clkdiv-table-cells"; + struct of_phandle_args div_table; + + reg_base = hs_init_clocks(np); + if (!reg_base) + return; + + if (of_property_read_string(np, "clock-output-names", &clk_name)) + return; + if (of_property_read_u32_array(np, "hisilicon,clkdiv", + &data[0], 2)) + return; + + /*process the div_table*/ + for (i = 0; ; i++) { + if (of_parse_phandle_with_args(np, propname, cellname, + i, &div_table)) + 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++) { + if (of_parse_phandle_with_args(np, propname, cellname, + i, &div_table)) + break; + + table[i].val = div_table.args[0]; + table[i].div = div_table.args[1]; + } + + /* gate only has the fixed parent */ + parent_names = kzalloc(sizeof(char *), GFP_KERNEL); + if (!parent_names) + goto err_par; + parent_names[0] = of_clk_get_parent_name(np, 0); + + dclk = kzalloc(sizeof(*dclk), GFP_KERNEL); + if (!dclk) + goto err_dclk; + init = kzalloc(sizeof(*init), GFP_KERNEL); + if (!init) + goto err_init; + init->name = kstrdup(clk_name, GFP_KERNEL); + init->ops = &hi3620_clkdiv_ops; + init->parent_names = parent_names; + init->num_parents = 1; + + dclk->reg = reg_base + data[0]; + dclk->shift = ffs(data[1]) - 1; + dclk->width = fls(data[1]) - ffs(data[1]) + 1; + dclk->mbits = data[1] << 16; + dclk->lock = &hs_clk.lock; + dclk->hw.init = init; + dclk->table = table; + clk = clk_register(NULL, &dclk->hw); + if (IS_ERR(clk)) + goto err_clk; + of_clk_add_provider(np, of_clk_src_simple_get, clk); + return; +err_clk: + kfree(init); +err_init: + kfree(dclk); +err_dclk: + kfree(parent_names); +err_par: + kfree(table); +} + +CLK_OF_DECLARE(hi3620_mux, "hisilicon,hi3620-clk-mux", hi3620_clkmux_setup) +CLK_OF_DECLARE(hi3620_gate, "hisilicon,hi3620-clk-gate", hi3620_clkgate_setup) +CLK_OF_DECLARE(hi3620_div, "hisilicon,hi3620-clk-div", hi3620_clkdiv_setup) +CLK_OF_DECLARE(hs_gate, "hisilicon,clk-gate", hs_clkgate_setup) +CLK_OF_DECLARE(hs_fixed, "hisilicon,clk-fixed-factor", hs_fixed_factor_setup) + +static const struct of_device_id hs_of_match[] = { + { .compatible = "hisilicon,pmctrl", .data = (void *)HS_PMCTRL, }, + { .compatible = "hisilicon,sysctrl", .data = (void *)HS_SYSCTRL, }, +}; + +static void __iomem __init *hs_init_clocks(struct device_node *np) +{ + struct device_node *parent; + const struct of_device_id *match; + void __iomem *ret = NULL; + + parent = of_get_parent(np); + if (!parent) + goto out; + match = of_match_node(hs_of_match, parent); + if (!match) + goto out; + switch ((unsigned int)match->data) { + case HS_PMCTRL: + if (!hs_clk.pmctrl) { + ret = of_iomap(parent, 0); + WARN_ON(!ret); + hs_clk.pmctrl = ret; + } else { + ret = hs_clk.pmctrl; + } + break; + case HS_SYSCTRL: + if (!hs_clk.sctrl) { + ret = of_iomap(parent, 0); + WARN_ON(!ret); + hs_clk.sctrl = ret; + } else { + ret = hs_clk.sctrl; + } + break; + } +out: + return ret; +} -- cgit v1.2.3 From 43a5a88fb984c0bd3fc331a46cace8290af5687f Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Wed, 3 Apr 2013 23:31:39 +0800 Subject: ARM: dts: update clk on hi3620 dts Since hi3620 clock driver is synced to 3.10, the DTS code should be updated also. Signed-off-by: Haojian Zhuang --- arch/arm/boot/dts/hi3620.dtsi | 1587 +++++++++++++++++++++++------------------ 1 file changed, 890 insertions(+), 697 deletions(-) diff --git a/arch/arm/boot/dts/hi3620.dtsi b/arch/arm/boot/dts/hi3620.dtsi index c8bbdc42224c..b768d2b0dbdd 100644 --- a/arch/arm/boot/dts/hi3620.dtsi +++ b/arch/arm/boot/dts/hi3620.dtsi @@ -21,6 +21,67 @@ mshc3 = &dwmmc_3; }; + osc32k: osc@0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + clock-output-names = "osc32khz"; + }; + osc26m: osc@1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <26000000>; + clock-output-names = "osc26mhz"; + }; + pclk: clk@0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <26000000>; + clock-output-names = "apb_pclk"; + }; + pll_arm0: clk@1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1600000000>; + clock-output-names = "armpll0"; + }; + pll_arm1: clk@2 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1600000000>; + clock-output-names = "armpll1"; + }; + pll_peri: clk@3 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1440000000>; + clock-output-names = "armpll2"; + }; + pll_usb: clk@4 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1440000000>; + clock-output-names = "armpll3"; + }; + pll_hdmi: clk@5 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1188000000>; + clock-output-names = "armpll4"; + }; + pll_gpu: clk@6 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1300000000>; + clock-output-names = "armpll5"; + }; + test_sd_clk: clk@7 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "testsdclk"; + }; + amba { #address-cells = <1>; #size-cells = <1>; @@ -32,7 +93,7 @@ compatible = "arm,cortex-a9-twd-timer"; reg = <0xfc000600 0x20>; interrupts = <1 13 0xf01>; - clocks = <&armpll0>; + clocks = <&pll_arm0>; }; pmctrl: pmctrl@fca08000 { @@ -55,678 +116,817 @@ reg = <0xfcd00000 0x2000>; }; - /*clocks begins*/ - clocks { - #address-cells = <1>; - #size-cells = <0>; - - osc32k: osc@0 { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <32768>; - clock-output-names = "osc32khz"; - }; - - osc26m: osc@1 { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <26000000>; - clock-output-names = "osc26mhz"; - }; - - pclk: clk@0 { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <26000000>; - clock-output-names = "apb_pclk"; - }; - - timclk0: clk@1 { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <60000000>; - clock-output-names = "timer0"; - }; - - timclk1: clk@2 { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <60000000>; - clock-output-names = "timer1"; - }; - - /*------pll clk------*/ - armpll0: pll0 { - compatible = "hisilicon,pll"; - #clock-cells = <0>; - clocks = <&osc26m>; - clock-frequency = <1600000000>; - clock-output-names = "clk_armpll0"; - }; - armpll1: pll1 { - compatible = "hisilicon,pll"; - #clock-cells = <0>; - clocks = <&osc26m>; - clock-frequency = <1600000000>; - clock-output-names = "clk_armpll1"; - }; - peripll: pll2 { - compatible = "hisilicon,pll"; - #clock-cells = <0>; - clocks = <&osc26m>; - clock-frequency = <1440000000>; - clock-output-names = "clk_armpll2"; - }; - testsdclk: testsd { - compatible = "hisilicon,pll"; - #clock-cells = <0>; - clocks = <&peripll>; - clock-frequency = <100000000>; - }; - usbpll: pll3 { - compatible = "hisilicon,pll"; - #clock-cells = <0>; - clocks = <&osc26m>; - clock-frequency = <1440000000>; - clock-output-names = "clk_armpll3"; - }; - - hdmipll: pll4 { - compatible = "hisilicon,pll"; - #clock-cells = <0>; - clocks = <&osc26m>; - clock-frequency = <1188000000>; - clock-output-names = "clk_armpll4"; - }; - - gpupll: pll5 { - compatible = "hisilicon,pll"; - #clock-cells = <0>; - clocks = <&osc26m>; - clock-frequency = <1300000000>; - clock-output-names = "clk_armpll5"; - }; + sysctrl@fc802000 { + compatible = "hisilicon,sysctrl"; + reg = <0xfc802000 0x1000>; + smp_reg = <0x31c>; + reboot_reg = <0x4>; - /*--------------cfgaxi clock--------------------*/ - clk_cfgaxi: cfgaxi { - compatible = "hisilicon,cfgaxi"; - #clock-cells = <0>; - clocks = <&peripll>; + refclk_uart0: refclk@0 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&osc26m &pclk>; + clock-output-names = "rclk_uart0"; + /* reg_offset, enable_bits */ + hisilicon,hi3620-clkmux = <0x100 0x80>; + }; + refclk_uart1: refclk@1 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&osc26m &pclk>; + clock-output-names = "rclk_uart1"; + hisilicon,hi3620-clkmux = <0x100 0x100>; + }; + refclk_uart2: refclk@2 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&osc26m &pclk>; + clock-output-names = "rclk_uart2"; + hisilicon,hi3620-clkmux = <0x100 0x200>; + }; + refclk_uart3: refclk@3 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&osc26m &pclk>; + clock-output-names = "rclk_uart3"; + hisilicon,hi3620-clkmux = <0x100 0x400>; + }; + refclk_uart4: refclk@4 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&osc26m &pclk>; + clock-output-names = "rclk_uart4"; + hisilicon,hi3620-clkmux = <0x100 0x800>; + }; + refclk_cfgaxi: refclk@5 { + compatible = "hisilicon,clk-fixed-factor"; + #clock-cells = <0>; + clocks = <&pll_peri>; + clock-output-names = "rclk_cfgaxi"; /*mult, div*/ hisilicon,fixed-factor = <1 30>; + }; + refclk_spi0: refclk@6 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&osc26m &refclk_cfgaxi>; + clock-output-names = "rclk_spi0"; + hisilicon,hi3620-clkmux = <0x100 0x1000>; + }; + refclk_spi1: refclk@7 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&osc26m &refclk_cfgaxi>; + clock-output-names = "rclk_spi1"; + hisilicon,hi3620-clkmux = <0x100 0x2000>; + }; + refclk_spi2: refclk@8 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&osc26m &refclk_cfgaxi>; + clock-output-names = "rclk_spi2"; + hisilicon,hi3620-clkmux = <0x100 0x4000>; + }; + refclk_pwm0: refclk@9 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&osc32k &osc26m>; + clock-output-names = "rclk_pwm0"; + hisilicon,hi3620-clkmux = <0x104 0x400>; + }; + refclk_pwm1: refclk@10 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&osc32k &osc26m>; + clock-output-names = "rclk_pwm1"; + hisilicon,hi3620-clkmux = <0x104 0x800>; + }; + refclk_tcxo: refclk@11 { + compatible = "hisilicon,clk-fixed-factor"; + #clock-cells = <0>; + clocks = <&osc26m>; + clock-output-names = "rclk_tcxo"; + hisilicon,fixed-factor = <1 4>; + }; + refclk_timer0: refclk@12 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&osc32k &timerclk01>; + clock-output-names = "rclk_tim0"; + hisilicon,hi3620-clkmux = <0 0x8000>; + }; + refclk_timer1: refclk@13 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&osc32k &timerclk01>; + clock-output-names = "rclk_tim1"; + hisilicon,hi3620-clkmux = <0 0x20000>; + }; + refclk_timer2: refclk@14 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&osc32k &timerclk23>; + clock-output-names = "rclk_tim2"; + hisilicon,hi3620-clkmux = <0 0x80000>; + }; + refclk_timer3: refclk@15 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&osc32k &timerclk23>; + clock-output-names = "rclk_tim3"; + hisilicon,hi3620-clkmux = <0 0x200000>; + }; + refclk_timer4: refclk@16 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&osc32k &timerclk45>; + clock-output-names = "rclk_tim4"; + hisilicon,hi3620-clkmux = <0x18 0x1>; + }; + refclk_timer5: refclk@17 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&osc32k &timerclk45>; + clock-output-names = "rclk_tim5"; + hisilicon,hi3620-clkmux = <0x18 0x4>; + }; + refclk_timer6: refclk@18 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&osc32k &timerclk67>; + clock-output-names = "rclk_tim6"; + hisilicon,hi3620-clkmux = <0x18 0x10>; + }; + refclk_timer7: refclk@19 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&osc32k &timerclk67>; + clock-output-names = "rclk_tim7"; + hisilicon,hi3620-clkmux = <0x18 0x40>; + }; + refclk_timer8: refclk@20 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&osc32k &timerclk89>; + clock-output-names = "rclk_tim8"; + hisilicon,hi3620-clkmux = <0x18 0x100>; + }; + refclk_timer9: refclk@21 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&osc32k &timerclk89>; + clock-output-names = "rclk_tim9"; + hisilicon,hi3620-clkmux = <0x18 0x400>; + }; + refclk_shareAXI: refclk@22 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&pll_usb &pll_peri>; + clock-output-names = "rclk_shareAXI"; + hisilicon,hi3620-clkmux = <0x24 0x8000>; + }; + refclk_mmc1: refclk@23 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&pll_peri &pll_usb>; + hisilicon,hi3620-clkmux = <0x108 0x200>; }; - - /*-------------------mux clock-------------------*/ - clk_uart0_mux: uart0_mux { - compatible = "hisilicon,muxclock"; - #clock-cells = <0>; - clocks = <&osc26m &clk_cfgaxi>; - /*select register offset, mask*/ - hisilicon,hi3620-clkmux = <0x100 0x80>; - }; - - clk_uart1_mux: uart1_mux { - compatible = "hisilicon,muxclock"; - #clock-cells = <0>; - clocks = <&osc26m &clk_cfgaxi>; - hisilicon,hi3620-clkmux = <0x100 0x100>; - }; - - clk_uart2_mux: uart2_mux { - compatible = "hisilicon,muxclock"; - #clock-cells = <0>; - clocks = <&osc26m &clk_cfgaxi>; - hisilicon,hi3620-clkmux = <0x100 0x200>; - }; - - clk_uart3_mux: uart3_mux { - compatible = "hisilicon,muxclock"; - #clock-cells = <0>; - clocks = <&osc26m &clk_cfgaxi>; - hisilicon,hi3620-clkmux = <0x100 0x400>; - }; - - clk_uart4_mux: uart4_mux { - compatible = "hisilicon,muxclock"; - #clock-cells = <0>; - clocks = <&osc26m &clk_cfgaxi>; - hisilicon,hi3620-clkmux = <0x100 0x800>; - }; - - /*---------------------gate clock-------------------*/ - clk_uart0: uart0 { - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&clk_uart0_mux>; - /*enable register, enable bit*/ - hisilicon,hi3620-clkgate = <0x40 16>; - clock-output-names = "clk_uart0"; - }; - - clk_uart1: uart1 { - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&clk_uart1_mux>; - hisilicon,hi3620-clkgate = <0x40 17>; - clock-output-names = "clk_uart1"; - }; - - clk_uart2: uart2 { - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&clk_uart2_mux>; - hisilicon,hi3620-clkgate = <0x40 18>; - clock-output-names = "clk_uart2"; - }; - - clk_uart3: uart3 { - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&clk_uart3_mux>; - hisilicon,hi3620-clkgate = <0x40 19>; - clock-output-names = "clk_uart3"; - }; - - clk_uart4: uart4 { - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&clk_uart4_mux>; - hisilicon,hi3620-clkgate = <0x40 20>; - clock-output-names = "clk_uart4"; - }; - - /*-------------------spi clock----------------*/ - - clk_spi0_mux: spi0_mux { - compatible = "hisilicon,muxclock"; - #clock-cells = <0>; - clocks = <&osc26m &clk_cfgaxi>; - hisilicon,hi3620-clkmux = <0x100 0x1000>; - }; - - clk_spi1_mux: spi1_mux { - compatible = "hisilicon,muxclock"; - #clock-cells = <0>; - clocks = <&osc26m &clk_cfgaxi>; - hisilicon,hi3620-clkmux = <0x100 0x2000>; - }; - - clk_spi2_mux: spi2_mux { - compatible = "hisilicon,muxclock"; - #clock-cells = <0>; - clocks = <&osc26m &clk_cfgaxi>; - hisilicon,hi3620-clkmux = <0x100 0x4000>; - }; - - clk_spi0: spi0 { - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&clk_spi0_mux>; - hisilicon,hi3620-clkgate = <0x40 21>; - clock-output-names = "clk_spi0"; + refclk_mmc2: refclk@24 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&pll_peri &pll_usb>; + hisilicon,hi3620-clkmux = <0x140 0x10>; }; - - clk_spi1: spi1 { - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&clk_spi1_mux>; - hisilicon,hi3620-clkgate = <0x40 22>; - clock-output-names = "clk_spi1"; + refclk_mmc3: refclk@25 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&pll_peri &pll_usb>; + hisilicon,hi3620-clkmux = <0x140 0x200>; }; - - clk_spi2: spi2 { - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&clk_spi2_mux>; - hisilicon,hi3620-clkgate = <0x40 23>; - clock-output-names = "clk_spi2"; + refclk_sd: refclk@26 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&pll_peri &pll_usb>; + hisilicon,hi3620-clkmux = <0x108 0x10>; }; - - /*-------------------mux clock----------------*/ - clk_pwm0_mux: pwm0_mux{ - compatible = "hisilicon,muxclock"; - #clock-cells = <0>; - clocks = <&osc32k &osc26m>; - hisilicon,hi3620-clkmux = <0x104 0x400>; + refclk_mmc1_parent: refclk@27 { + compatible = "hisilicon,hi3620-clk-mux"; + #clock-cells = <0>; + clocks = <&osc26m &div_mmc1>; + hisilicon,hi3620-clkmux = <0x108 0x400>; }; - - clk_venc_mux: venc_mux{ - compatible = "hisilicon,muxclock"; - #clock-cells = <0>; - clocks = <&peripll &usbpll>; + refclk_venc: refclk@28 { + #clock-cells = <0>; + clocks = <&pll_peri &pll_usb>; hisilicon,hi3620-clkmux = <0x10c 0x800>; }; - - clk_g2d_mux: g2d_mux{ - compatible = "hisilicon,muxclock"; - #clock-cells = <0>; - clocks = <&peripll &usbpll>; + refclk_g2d: refclk@29 { + #clock-cells = <0>; + clocks = <&pll_peri &pll_usb>; hisilicon,hi3620-clkmux = <0x10c 0x20>; }; - - clk_vdec_mux: vdec_mux{ - compatible = "hisilicon,muxclock"; - #clock-cells = <0>; - clocks = <&peripll &usbpll>; + refclk_vdec: refclk@30 { + #clock-cells = <0>; + clocks = <&pll_peri &pll_usb>; hisilicon,hi3620-clkmux = <0x110 0x20>; }; - - clk_vpp_mux: vpp_mux{ - compatible = "hisilicon,muxclock"; - #clock-cells = <0>; - clocks = <&peripll &usbpll>; + refclk_vpp: refclk@31 { + #clock-cells = <0>; + clocks = <&pll_peri &pll_usb>; hisilicon,hi3620-clkmux = <0x110 0x800>; }; - - clk_ldi0_mux: ldi0_mux{ - compatible = "hisilicon,muxclock"; - #clock-cells = <0>; - clocks = <&peripll &usbpll &hdmipll>; + refclk_ldi0: refclk@32 { + #clock-cells = <0>; + clocks = <&pll_peri &pll_usb &pll_hdmi>; hisilicon,hi3620-clkmux = <0x114 0x6000>; }; - - clk_ldi1_mux: ldi1_mux{ - compatible = "hisilicon,muxclock"; - #clock-cells = <0>; - clocks = <&peripll &usbpll &hdmipll>; + refclk_ldi1: refclk@33 { + #clock-cells = <0>; + clocks = <&pll_peri &pll_usb &pll_hdmi>; hisilicon,hi3620-clkmux = <0x118 0xc000>; }; - /*----periclock: gate clk, reg offset to sctrl-----*/ - - clk_sci: sci { - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&osc26m>; - /*enable register, enable bit*/ - hisilicon,hi3620-clkgate = <0x40 26>; - clock-output-names = "clk_sci"; - }; - - clk_dphy0: dphy0 { - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&osc26m>; - hisilicon,hi3620-clkgate = <0x30 15>; - clock-output-names = "clk_dphy0"; - }; - - clk_dphy1: dphy1 { - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&osc26m>; - hisilicon,hi3620-clkgate = <0x30 16>; - }; - - clk_dphy2: dphy2 { - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&osc26m>; - hisilicon,hi3620-clkgate = <0x30 17>; - }; - - clk_kpc: kpc { - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&osc32k>; - hisilicon,hi3620-clkgate = <0x20 6>; - }; - - clk_pwm0_gate: pwm0_gate { - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&osc32k &osc26m>; - hisilicon,hi3620-clkgate = <0x40 7>; - }; - - /*gpio0-----gpio21 gate clock*/ - clk_gpio0: gpio0{ - compatible = "hisilicon,periclock"; - hisilicon,hi3620-clkgate = <0x20 8>; - clock-output-names = "clk_gpio0"; - }; - clk_gpio1: gpio1{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - hisilicon,hi3620-clkgate = <0x20 9>; - clock-output-names = "clk_gpio1"; - }; - clk_gpio2: gpio2{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - hisilicon,hi3620-clkgate = <0x20 10>; - clock-output-names = "clk_gpio2"; - }; - clk_gpio3: gpio3{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - hisilicon,hi3620-clkgate = <0x20 11>; - clock-output-names = "clk_gpio3"; - }; - clk_gpio4: gpio4{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - hisilicon,hi3620-clkgate = <0x20 12>; - clock-output-names = "clk_gpio4"; - }; - clk_gpio5: gpio5{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - hisilicon,hi3620-clkgate = <0x20 13>; - clock-output-names = "clk_gpio5"; - }; - clk_gpio6: gpio6{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - hisilicon,hi3620-clkgate = <0x20 14>; - clock-output-names = "clk_gpio6"; - }; - - clk_gpio7: gpio7{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - hisilicon,hi3620-clkgate = <0x20 15>; - clock-output-names = "clk_gpio7"; - }; - clk_gpio8: gpio8{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - hisilicon,hi3620-clkgate = <0x20 16>; - clock-output-names = "clk_gpio8"; - }; - clk_gpio9: gpio9{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - hisilicon,hi3620-clkgate = <0x20 17>; - clock-output-names = "clk_gpio9"; - }; - clk_gpio10: gpio10{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - hisilicon,hi3620-clkgate = <0x20 18>; - clock-output-names = "clk_gpio10"; - }; - clk_gpio11: gpio11{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - hisilicon,hi3620-clkgate = <0x20 19>; - clock-output-names = "clk_gpio11"; - }; - clk_gpio12: gpio12{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - hisilicon,hi3620-clkgate = <0x20 20>; - clock-output-names = "clk_gpio12"; - }; - clk_gpio13: gpio13{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - hisilicon,hi3620-clkgate = <0x20 21>; - clock-output-names = "clk_gpio13"; - }; - clk_gpio14: gpio14{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - hisilicon,hi3620-clkgate = <0x20 22>; - clock-output-names = "clk_gpio14"; - }; - clk_gpio15: gpio15{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - hisilicon,hi3620-clkgate = <0x20 23>; - clock-output-names = "clk_gpio15"; - }; - clk_gpio16: gpio16{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - hisilicon,hi3620-clkgate = <0x20 24>; - clock-output-names = "clk_gpio16"; - }; - clk_gpio17: gpio17{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - hisilicon,hi3620-clkgate = <0x20 25>; - clock-output-names = "clk_gpio17"; - }; - clk_gpio18: gpio18{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - hisilicon,hi3620-clkgate = <0x20 26>; - clock-output-names = "clk_gpio18"; - }; - clk_gpio19: gpio19{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - hisilicon,hi3620-clkgate = <0x20 27>; - clock-output-names = "clk_gpio19"; - }; - clk_gpio20: gpio20{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - hisilicon,hi3620-clkgate = <0x20 28>; - clock-output-names = "clk_gpio20"; - }; - clk_gpio21: gpio21{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - hisilicon,hi3620-clkgate = <0x20 29>; - clock-output-names = "clk_gpio21"; - }; - - /*i2c clk*/ - clk_i2c0: i2c0{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&clk_cfgaxi>; - hisilicon,hi3620-clkgate = <0x40 24>; + uartclk0: clkgate@0 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_uart0>; + clock-output-names = "uartclk0"; + hisilicon,hi3620-clkreset = <0x98 0x10000>; + hisilicon,hi3620-clkgate = <0x40 0x10000>; + }; + uartclk1: clkgate@1 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_uart1>; + clock-output-names = "uartclk1"; + hisilicon,hi3620-clkreset = <0x98 0x20000>; + hisilicon,hi3620-clkgate = <0x40 0x20000>; + }; + uartclk2: clkgate@2 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_uart2>; + clock-output-names = "uartclk2"; + hisilicon,hi3620-clkreset = <0x98 0x40000>; + hisilicon,hi3620-clkgate = <0x40 0x40000>; + }; + uartclk3: clkgate@3 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_uart3>; + clock-output-names = "uartclk3"; + hisilicon,hi3620-clkreset = <0x98 0x80000>; + hisilicon,hi3620-clkgate = <0x40 0x80000>; + }; + uartclk4: clkgate@4 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_uart4>; + clock-output-names = "uartclk4"; + hisilicon,hi3620-clkreset = <0x98 0x100000>; + hisilicon,hi3620-clkgate = <0x40 0x100000>; + }; + gpioclk0: clkgate@5 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "gpioclk0"; + hisilicon,hi3620-clkreset = <0x80 0x100>; + hisilicon,hi3620-clkgate = <0x20 0x100>; + }; + gpioclk1: clkgate@6 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "gpioclk1"; + hisilicon,hi3620-clkreset = <0x80 0x200>; + hisilicon,hi3620-clkgate = <0x20 0x200>; + }; + gpioclk2: clkgate@7 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "gpioclk2"; + hisilicon,hi3620-clkreset = <0x80 0x400>; + hisilicon,hi3620-clkgate = <0x20 0x400>; + }; + gpioclk3: clkgate@8 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "gpioclk3"; + hisilicon,hi3620-clkreset = <0x80 0x800>; + hisilicon,hi3620-clkgate = <0x20 0x800>; + }; + gpioclk4: clkgate@9 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "gpioclk4"; + hisilicon,hi3620-clkreset = <0x80 0x1000>; + hisilicon,hi3620-clkgate = <0x20 0x1000>; + }; + gpioclk5: clkgate@10 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "gpioclk5"; + hisilicon,hi3620-clkreset = <0x80 0x2000>; + hisilicon,hi3620-clkgate = <0x20 0x2000>; + }; + gpioclk6: clkgate@11 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "gpioclk6"; + hisilicon,hi3620-clkreset = <0x80 0x4000>; + hisilicon,hi3620-clkgate = <0x20 0x4000>; + }; + gpioclk7: clkgate@12 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "gpioclk7"; + hisilicon,hi3620-clkreset = <0x80 0x8000>; + hisilicon,hi3620-clkgate = <0x20 0x8000>; + }; + gpioclk8: clkgate@13 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "gpioclk8"; + hisilicon,hi3620-clkreset = <0x80 0x10000>; + hisilicon,hi3620-clkgate = <0x20 0x10000>; + }; + gpioclk9: clkgate@14 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "gpioclk9"; + hisilicon,hi3620-clkreset = <0x80 0x20000>; + hisilicon,hi3620-clkgate = <0x20 0x20000>; + }; + gpioclk10: clkgate@15 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "gpioclk10"; + hisilicon,hi3620-clkreset = <0x80 0x40000>; + hisilicon,hi3620-clkgate = <0x20 0x40000>; + }; + gpioclk11: clkgate@16 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "gpioclk11"; + hisilicon,hi3620-clkreset = <0x80 0x80000>; + hisilicon,hi3620-clkgate = <0x20 0x80000>; + }; + gpioclk12: clkgate@17 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "gpioclk12"; + hisilicon,hi3620-clkreset = <0x80 0x100000>; + hisilicon,hi3620-clkgate = <0x20 0x100000>; + }; + gpioclk13: clkgate@18 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "gpioclk13"; + hisilicon,hi3620-clkreset = <0x80 0x200000>; + hisilicon,hi3620-clkgate = <0x20 0x200000>; + }; + gpioclk14: clkgate@19 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "gpioclk14"; + hisilicon,hi3620-clkreset = <0x80 0x400000>; + hisilicon,hi3620-clkgate = <0x20 0x400000>; + }; + gpioclk15: clkgate@20 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "gpioclk15"; + hisilicon,hi3620-clkreset = <0x80 0x800000>; + hisilicon,hi3620-clkgate = <0x20 0x800000>; + }; + gpioclk16: clkgate@21 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "gpioclk16"; + hisilicon,hi3620-clkreset = <0x80 0x1000000>; + hisilicon,hi3620-clkgate = <0x20 0x1000000>; + }; + gpioclk17: clkgate@22 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "gpioclk17"; + hisilicon,hi3620-clkreset = <0x80 0x2000000>; + hisilicon,hi3620-clkgate = <0x20 0x2000000>; + }; + gpioclk18: clkgate@23 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "gpioclk18"; + hisilicon,hi3620-clkreset = <0x80 0x4000000>; + hisilicon,hi3620-clkgate = <0x20 0x4000000>; + }; + gpioclk19: clkgate@24 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "gpioclk19"; + hisilicon,hi3620-clkreset = <0x80 0x8000000>; + hisilicon,hi3620-clkgate = <0x20 0x8000000>; + }; + gpioclk20: clkgate@25 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "gpioclk20"; + hisilicon,hi3620-clkreset = <0x80 0x10000000>; + hisilicon,hi3620-clkgate = <0x20 0x10000000>; + }; + gpioclk21: clkgate@26 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "gpioclk21"; + hisilicon,hi3620-clkreset = <0x80 0x20000000>; + hisilicon,hi3620-clkgate = <0x20 0x20000000>; + }; + spiclk0: clkgate@27 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_spi0>; + clock-output-names = "spiclk0"; + hisilicon,hi3620-clkreset = <0x98 0x200000>; + hisilicon,hi3620-clkgate = <0x40 0x200000>; + }; + spiclk1: clkgate@28 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_spi1>; + clock-output-names = "spiclk1"; + hisilicon,hi3620-clkreset = <0x98 0x400000>; + hisilicon,hi3620-clkgate = <0x40 0x400000>; + }; + spiclk2: clkgate@29 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_spi2>; + clock-output-names = "spiclk2"; + hisilicon,hi3620-clkreset = <0x98 0x800000>; + hisilicon,hi3620-clkgate = <0x40 0x800000>; + }; + pwmclk0: clkgate@30 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_pwm0>; + clock-output-names = "pwmclk0"; + hisilicon,hi3620-clkreset = <0x98 0x80>; + hisilicon,hi3620-clkgate = <0x40 0x80>; + }; + pwmclk1: clkgate@31 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_pwm1>; + clock-output-names = "pwmclk1"; + hisilicon,hi3620-clkreset = <0x98 0x100>; + hisilicon,hi3620-clkgate = <0x40 0x100>; + }; + timerclk01: clkgate@32 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_tcxo>; + clock-output-names = "timerclk01"; + hisilicon,hi3620-clkreset = <0x80 0x1>; + hisilicon,hi3620-clkgate = <0x20 0x3>; + }; + timerclk23: clkgate@33 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_tcxo>; + clock-output-names = "timerclk23"; + hisilicon,hi3620-clkreset = <0x80 0x2>; + hisilicon,hi3620-clkgate = <0x20 0xc>; + }; + timerclk45: clkgate@34 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_tcxo>; + clock-output-names = "timerclk45"; + hisilicon,hi3620-clkreset = <0x98 0x8>; + hisilicon,hi3620-clkgate = <0x40 0x8>; + }; + timerclk67: clkgate@35 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_tcxo>; + clock-output-names = "timerclk67"; + hisilicon,hi3620-clkreset = <0x98 0x10>; + hisilicon,hi3620-clkgate = <0x40 0x10>; + }; + timerclk89: clkgate@36 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_tcxo>; + clock-output-names = "timerclk89"; + hisilicon,hi3620-clkreset = <0x98 0x20>; + hisilicon,hi3620-clkgate = <0x40 0x20>; + }; + timclk0: clkgate@37 { + compatible = "hisilicon,clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_timer0>; + clock-output-names = "timclk0"; + hisilicon,clkgate-inverted; + hisilicon,clkgate = <0 16>; + }; + timclk1: clkgate@38 { + compatible = "hisilicon,clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_timer1>; + clock-output-names = "timclk1"; + hisilicon,clkgate-inverted; + hisilicon,clkgate = <0 18>; + }; + timclk2: clkgate@39 { + compatible = "hisilicon,clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_timer2>; + clock-output-names = "timclk2"; + hisilicon,clkgate-inverted; + hisilicon,clkgate = <0 20>; + }; + timclk3: clkgate@40 { + compatible = "hisilicon,clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_timer3>; + clock-output-names = "timclk3"; + hisilicon,clkgate-inverted; + hisilicon,clkgate = <0 22>; + }; + timclk4: clkgate@41 { + compatible = "hisilicon,clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_timer4>; + clock-output-names = "timclk4"; + hisilicon,clkgate-inverted; + hisilicon,clkgate = <0x18 0>; + }; + timclk5: clkgate@42 { + compatible = "hisilicon,clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_timer5>; + clock-output-names = "timclk5"; + hisilicon,clkgate-inverted; + hisilicon,clkgate = <0x18 2>; + }; + timclk6: clkgate@43 { + compatible = "hisilicon,clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_timer6>; + clock-output-names = "timclk6"; + hisilicon,clkgate-inverted; + hisilicon,clkgate = <0x18 4>; + }; + timclk7: clkgate@44 { + compatible = "hisilicon,clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_timer7>; + clock-output-names = "timclk7"; + hisilicon,clkgate-inverted; + hisilicon,clkgate = <0x18 6>; + }; + timclk8: clkgate@45 { + compatible = "hisilicon,clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_timer8>; + clock-output-names = "timclk8"; + hisilicon,clkgate-inverted; + hisilicon,clkgate = <0x18 8>; + }; + timclk9: clkgate@46 { + compatible = "hisilicon,clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_timer9>; + clock-output-names = "timclk9"; + hisilicon,clkgate-inverted; + hisilicon,clkgate = <0x18 10>; + }; + rtcclk: clkgate@47 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; + clock-output-names = "clk_rtc"; + hisilicon,hi3620-clkgate = <0x20 0x20>; + }; + i2cclk0: clkgate@48 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; clock-output-names = "clk_i2c0"; - }; - clk_i2c1: i2c1{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&clk_cfgaxi>; - hisilicon,hi3620-clkgate = <0x40 25>; + hisilicon,hi3620-clkgate = <0x40 0x1000000>; + }; + i2cclk1: clkgate@49 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; clock-output-names = "clk_i2c1"; - }; - clk_i2c2: i2c2{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&clk_cfgaxi>; - hisilicon,hi3620-clkgate = <0x40 28>; + hisilicon,hi3620-clkgate = <0x40 0x2000000>; + }; + i2cclk2: clkgate@50 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; clock-output-names = "clk_i2c2"; - }; - clk_i2c3: i2c3{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&clk_cfgaxi>; - hisilicon,hi3620-clkgate = <0x40 29>; + hisilicon,hi3620-clkgate = <0x40 0x10000000>; + }; + i2cclk3: clkgate@51 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&pclk>; clock-output-names = "clk_i2c3"; - }; - - /* clk_acp */ - clk_acp: acp{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&clk_cfgaxi>; - hisilicon,hi3620-clkgate = <0x30 28>; - }; - - /*dmac clk*/ - clk_dmac: dmac{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&clk_acp>; - hisilicon,hi3620-clkgate = <0x50 10>; + hisilicon,hi3620-clkgate = <0x40 0x20000000>; + }; + dmaclk: clkgate@52 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&acpclk>; clock-output-names = "clk_dmac"; + hisilicon,hi3620-clkgate = <0x50 0x400>; + }; + mcuclk: clkgate@53 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_cfgaxi>; + clock-output-names = "clk_mcu"; + hisilicon,hi3620-clkgate = <0x50 0x1000000>; + }; + ddrcperclk: clkgate@54 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_cfgaxi>; + clock-output-names = "clk_ddrc_per"; + hisilicon,hi3620-clkgate = <0x50 0x200>; + }; + acpclk: clkgate@55 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&refclk_cfgaxi>; + clock-output-names = "clk_apc"; + hisilicon,hi3620-clkgate = <0x30 0x10000000>; + }; + mmcclk1: clkgate@56 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&test_sd_clk>; + clock-output-names = "clk_mmc1"; + hisilicon,hi3620-clkgate = <0x50 0x200000>; + }; + mmcclk2: clkgate@57 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&div_mmc2>; + clock-output-names = "clk_mmc2"; + hisilicon,hi3620-clkgate = <0x50 0x400000>; + }; + mmcclk3: clkgate@58 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&div_mmc3>; + clock-output-names = "clk_mmc3"; + hisilicon,hi3620-clkgate = <0x50 0x800000>; + }; + sdclk: clkgate@59 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&test_sd_clk>; + clock-output-names = "clk_sd"; + hisilicon,hi3620-clkgate = <0x50 0x100000>; + }; + kpcclk: clkgate@60 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&osc32k>; + clock-output-names = "clk_kpc"; + hisilicon,hi3620-clkgate = <0x20 0x40>; }; - - /*mmc clk*/ - clk_mmc1_mux: mmc1_mux{ - compatible = "hisilicon,muxclock"; - #clock-cells = <0>; - clocks = <&peripll &usbpll>; - hisilicon,hi3620-clkmux = <0x108 0x200>; - }; - - clk_mmc2_mux: mmc2_mux{ - compatible = "hisilicon,muxclock"; - #clock-cells = <0>; - clocks = <&peripll &usbpll>; - hisilicon,hi3620-clkmux = <0x140 0x010>; - }; - - clk_mmc3_mux: mmc3_mux{ - compatible = "hisilicon,muxclock"; - #clock-cells = <0>; - clocks = <&peripll &usbpll>; - hisilicon,hi3620-clkmux = <0x140 0x200>; - }; - - clk_sd_mux: sd_mux{ - compatible = "hisilicon,muxclock"; - #clock-cells = <0>; - clocks = <&peripll &usbpll>; - hisilicon,hi3620-clkmux = <0x108 0x010>; - }; - - - /*-----------divider table clk---------------------*/ - clk_div_mmc1: div_mmc1{ - compatible = "hisilicon,divclock"; - #clock-cells = <0>; - clocks = <&clk_mmc1_mux>; - hisilicon,clkdiv-table = <&divtable 0x0f 16 &divtable 0x0e 15 &divtable 0x0d 14 - &divtable 0x0c 13 &divtable 0x0b 12 &divtable 0x0a 11 - &divtable 0x09 10 &divtable 0x08 9 &divtable 0x07 8 - &divtable 0x06 7 &divtable 0x05 6 &divtable 0x04 5 - &divtable 0x03 4 &divtable 0x02 3 &divtable 0x01 2 - &divtable 0x00 1>; - /*divider register offset, shift, width*/ - hisilicon,hi3620-clkdiv = <0x108 5 4>; - }; - - clk_div_mmc2: div_mmc2{ - compatible = "hisilicon,divclock"; - #clock-cells = <0>; - clocks = <&clk_mmc2_mux>; - hisilicon,clkdiv-table = <&divtable 0x0f 16 &divtable 0x0e 15 &divtable 0x0d 14 - &divtable 0x0c 13 &divtable 0x0b 12 &divtable 0x0a 11 - &divtable 0x09 10 &divtable 0x08 9 &divtable 0x07 8 - &divtable 0x06 7 &divtable 0x05 6 &divtable 0x04 5 - &divtable 0x03 4 &divtable 0x02 3 &divtable 0x01 2 - &divtable 0x00 1>; - /*divider register offset, shift, width*/ - hisilicon,hi3620-clkdiv = <0x140 0 4>; - }; - - clk_div_mmc3: div_mmc3{ - compatible = "hisilicon,divclock"; - #clock-cells = <0>; - clocks = <&clk_mmc3_mux>; - hisilicon,clkdiv-table = <&divtable 0x0f 16 &divtable 0x0e 15 &divtable 0x0d 14 - &divtable 0x0c 13 &divtable 0x0b 12 &divtable 0x0a 11 - &divtable 0x09 10 &divtable 0x08 9 &divtable 0x07 8 - &divtable 0x06 7 &divtable 0x05 6 &divtable 0x04 5 - &divtable 0x03 4 &divtable 0x02 3 &divtable 0x01 2 - &divtable 0x00 1>; - /*divider register offset, shift, width*/ - hisilicon,hi3620-clkdiv = <0x140 5 4>; - }; - - clk_div_sd: div_sd{ - compatible = "hisilicon,divclock"; - #clock-cells = <0>; - clocks = <&clk_sd_mux>; - hisilicon,clkdiv-table = <&divtable 0x0f 16 &divtable 0x0e 15 &divtable 0x0d 14&divtable 0x0c 13 - &divtable 0x0b 12 &divtable 0x0a 11 &divtable 0x09 10 &divtable 0x08 9 - &divtable 0x07 8 &divtable 0x06 7 &divtable 0x05 6 &divtable 0x04 5 - &divtable 0x03 4 &divtable 0x02 3 &divtable 0x01 2 &divtable 0x00 1>; - /*divider register offset, shift, width*/ - hisilicon,hi3620-clkdiv = <0x108 0 4>; - }; - - /*---------------gate--------------------*/ - clk_mmc1_parent: mmc1_parent{ - compatible = "hisilicon,muxclock"; - #clock-cells = <0>; - clocks = <&osc26m &clk_div_mmc1>; - hisilicon,hi3620-clkmux = <0x108 0x400>; - }; - - clk_mmc1: mmc1 { - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&testsdclk>; - /* clocks = <&clk_mmc1_parent>; */ - hisilicon,hi3620-clkgate = <0x50 21>; - }; - - clk_mmc2: mmc2 { - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&clk_div_mmc2>; - hisilicon,hi3620-clkgate = <0x50 22>; - }; - - clk_mmc3: mmc3 { - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&clk_div_mmc3>; - hisilicon,hi3620-clkgate = <0x50 23>; - }; - - clk_sd: sd { - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - /* clocks = <&clk_div_sd>; */ - clocks = <&testsdclk>; - hisilicon,hi3620-clkgate = <0x50 20>; + sciclk: clkgate@61 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&osc26m>; + clock-output-names = "clk_sci"; + hisilicon,hi3620-clkgate = <0x40 0x4000000>; }; - - clk_ddrc_per: ddrc_per { - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&clk_cfgaxi>; - hisilicon,hi3620-clkgate = <0x50 9>; + dphyclk0: clkgate@62 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&osc26m>; + clock-output-names = "clk_dphy0"; + hisilicon,hi3620-clkgate = <0x30 0x8000>; }; - - clk_mcu: mcu{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&clk_cfgaxi>; - hisilicon,hi3620-clkgate = <0x50 24>; - clock-output-names = "clk_mcu"; + dphyclk1: clkgate@63 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&osc26m>; + clock-output-names = "clk_dphy1"; + hisilicon,hi3620-clkgate = <0x30 0x10000>; }; - - /*rtc clk*/ - clk_rtc: rtc{ - compatible = "hisilicon,periclock"; - #clock-cells = <0>; - clocks = <&pclk>; - hisilicon,hi3620-clkgate = <0x20 5>; - clock-output-names = "clk_rtc"; + dphyclk2: clkgate@64 { + compatible = "hisilicon,hi3620-clk-gate"; + #clock-cells = <0>; + clocks = <&osc26m>; + clock-output-names = "clk_dphy2"; + hisilicon,hi3620-clkgate = <0x30 0x20000>; }; - - /*--------------------divider clock -------------------*/ - divtable: clkdiv { + dtable: clkdiv@0 { #hisilicon,clkdiv-table-cells = <2>; - }; - - clk_div_shaxi: div_shaxi{ - compatible = "hisilicon,divclock"; - #clock-cells = <0>; - clocks = <&peripll>; - hisilicon,clkdiv-table = <&divtable 0x04 5>; - /*divider register offset, shift, width*/ - hisilicon,hi3620-clkdiv = <0x100 0 5>; - }; - - clk_div_cfgaxi: div_cfgaxi{ - compatible = "hisilicon,divclock"; - #clock-cells = <0>; - clocks = <&clk_div_shaxi>; - hisilicon,clkdiv-table = <&divtable 0x01 2>; - hisilicon,hi3620-clkdiv = <0x100 5 2>; + }; + div_shareaxi: clkdiv@1 { + compatible = "hisilicon,hi3620-clk-div"; + #clock-cells = <0>; + clocks = <&refclk_shareAXI>; + clock-output-names = "shareAXI_div"; + hisilicon,clkdiv-table = < + &dtable 0 1 &dtable 1 2 &dtable 2 3 &dtable 3 4 + &dtable 4 5 &dtable 5 6 &dtable 6 7 &dtable 7 8 + &dtable 8 9 &dtable 9 10 &dtable 10 11 &dtable 11 12 + &dtable 12 13 &dtable 13 14 &dtable 14 15 &dtable 15 16 + &dtable 16 17 &dtable 17 18 &dtable 18 19 &dtable 19 20 + &dtable 20 21 &dtable 21 22 &dtable 22 23 &dtable 23 24 + &dtable 24 25 &dtable 25 26 &dtable 26 27 &dtable 27 28 + &dtable 28 29 &dtable 29 30 &dtable 30 31 &dtable 31 32>; + /* divider register offset, mask */ + hisilicon,clkdiv = <0x100 0x1f>; + }; + div_cfgaxi: clkdiv@2 { + compatible = "hisilicon,hi3620-clk-div"; + #clock-cells = <0>; + clocks = <&div_shareaxi>; + clock-output-names = "cfgAXI_div"; + hisilicon,clkdiv-table = <&dtable 0x01 2>; + hisilicon,clkdiv = <0x100 0x60>; + }; + div_mmc1: clkdiv@3 { + compatible = "hisilicon,hi3620-clk-div"; + #clock-cells = <0>; + clocks = <&refclk_mmc1>; + hisilicon,clkdiv-table = < + &dtable 0xf 16 &dtable 0xe 15 &dtable 0xd 14 + &dtable 0xc 13 &dtable 0xb 12 &dtable 0xa 11 + &dtable 9 10 &dtable 8 9 &dtable 7 8 + &dtable 6 7 &dtable 5 6 &dtable 4 5 + &dtable 3 4 &dtable 2 3 &dtable 1 2 + &dtable 0 1>; + hisilicon,clkdiv = <0x108 0x1e0>; + }; + div_mmc2: clkdiv@4 { + compatible = "hisilicon,hi3620-clk-div"; + #clock-cells = <0>; + clocks = <&refclk_mmc2>; + hisilicon,clkdiv-table = < + &dtable 0xf 16 &dtable 0xe 15 &dtable 0xd 14 + &dtable 0xc 13 &dtable 0xb 12 &dtable 0xa 11 + &dtable 9 10 &dtable 8 9 &dtable 7 8 + &dtable 6 7 &dtable 5 6 &dtable 4 5 + &dtable 3 4 &dtable 2 3 &dtable 1 2 + &dtable 0 1>; + hisilicon,clkdiv = <0x140 0xf>; + }; + div_mmc3: clkdiv@5 { + compatible = "hisilicon,hi3620-clk-div"; + #clock-cells = <0>; + clocks = <&refclk_mmc3>; + hisilicon,clkdiv-table = < + &dtable 0xf 16 &dtable 0xe 15 &dtable 0xd 14 + &dtable 0xc 13 &dtable 0xb 12 &dtable 0xa 11 + &dtable 9 10 &dtable 8 9 &dtable 7 8 + &dtable 6 7 &dtable 5 6 &dtable 4 5 + &dtable 3 4 &dtable 2 3 &dtable 1 2 + &dtable 0 1>; + hisilicon,clkdiv = <0x140 0x1e0>; + }; + div_sd: clkdiv@6 { + compatible = "hisilicon,hi3620-clk-div"; + #clock-cells = <0>; + clocks = <&refclk_sd>; + hisilicon,clkdiv-table = < + &dtable 0xf 16 &dtable 0xe 15 &dtable 0xd 14 + &dtable 0xc 13 &dtable 0xb 12 &dtable 0xa 11 + &dtable 9 10 &dtable 8 9 &dtable 7 8 + &dtable 6 7 &dtable 5 6 &dtable 4 5 + &dtable 3 4 &dtable 2 3 &dtable 1 2 + &dtable 0 1>; + hisilicon,clkdiv = <0x108 0xf>; }; }; @@ -734,7 +934,7 @@ compatible = "arm,rtc-pl031", "arm,primecell"; reg = <0xfc804000 0x1000>; interrupts = <0 9 0x4>; - clocks = <&clk_rtc>; + clocks = <&rtcclk>; clock-names = "apb_pclk"; status = "disabled"; }; @@ -762,8 +962,8 @@ reg = <0xfc800000 0x1000>; /* timer00 & timer01 */ interrupts = <0 0 4>, <0 1 4>; - clocks = <&timclk0 &timclk1 &pclk>; - clock-names = "timer0", "timer1", "apb_pclk"; + clocks = <&timclk0 &timclk1>; + clock-names = "apb_pclk"; status = "disabled"; }; @@ -777,8 +977,8 @@ reg = <0xfc801000 0x1000>; /* timer10 & timer11 */ interrupts = <0 2 4>, <0 3 4>; - clocks = <&timclk0 &timclk1 &pclk>; - clock-names = "timer0", "timer1", "apb_pclk"; + clocks = <&timclk2 &timclk3>; + clock-names = "apb_pclk"; status = "disabled"; }; @@ -787,8 +987,8 @@ reg = <0xfca01000 0x1000>; /* timer20 & timer21 */ interrupts = <0 4 4>, <0 5 4>; - clocks = <&timclk0 &timclk1 &pclk>; - clock-names = "timer0", "timer1", "apb_pclk"; + clocks = <&timclk4 &timclk5>; + clock-names = "apb_pclk"; status = "disabled"; }; @@ -797,8 +997,8 @@ reg = <0xfca02000 0x1000>; /* timer30 & timer31 */ interrupts = <0 6 4>, <0 7 4>; - clocks = <&timclk0 &timclk1 &pclk>; - clock-names = "timer0", "timer1", "apb_pclk"; + clocks = <&timclk6 &timclk7>; + clock-names = "apb_pclk"; status = "disabled"; }; @@ -807,8 +1007,8 @@ reg = <0xfca03000 0x1000>; /* timer40 & timer41 */ interrupts = <0 96 4>, <0 97 4>; - clocks = <&timclk0 &timclk1 &pclk>; - clock-names = "timer0", "timer1", "apb_pclk"; + clocks = <&timclk8 &timclk9>; + clock-names = "apb_pclk"; status = "disabled"; }; @@ -816,7 +1016,7 @@ compatible = "arm,pl011", "arm,primecell"; reg = <0xfcb00000 0x1000>; interrupts = <0 20 4>; - clocks = <&clk_uart0>; + clocks = <&uartclk0>; clock-names = "apb_pclk"; status = "disabled"; }; @@ -825,7 +1025,7 @@ compatible = "arm,pl011", "arm,primecell"; reg = <0xfcb01000 0x1000>; interrupts = <0 21 4>; - clocks = <&clk_uart1>; + clocks = <&uartclk1>; clock-names = "apb_pclk"; status = "disabled"; }; @@ -834,7 +1034,7 @@ compatible = "arm,pl011", "arm,primecell"; reg = <0xfcb02000 0x1000>; interrupts = <0 22 4>; - clocks = <&clk_uart2>; + clocks = <&uartclk2>; clock-names = "apb_pclk"; status = "disabled"; }; @@ -843,7 +1043,7 @@ compatible = "arm,pl011", "arm,primecell"; reg = <0xfcb03000 0x1000>; interrupts = <0 23 4>; - clocks = <&clk_uart3>; + clocks = <&uartclk3>; clock-names = "apb_pclk"; status = "disabled"; }; @@ -852,7 +1052,7 @@ compatible = "arm,pl011", "arm,primecell"; reg = <0xfcb04000 0x1000>; interrupts = <0 24 4>; - clocks = <&clk_uart4>; + clocks = <&uartclk4>; clock-names = "apb_pclk"; status = "disabled"; }; @@ -867,7 +1067,7 @@ &pmx0 5 0 1 &pmx0 6 1 1 &pmx0 7 2 1>; interrupt-controller; #interrupt-cells = <2>; - clocks = <&pclk>; + clocks = <&gpioclk0>; clock-names = "apb_pclk"; status = "disable"; }; @@ -883,7 +1083,7 @@ &pmx0 6 5 1 &pmx0 7 6 1>; interrupt-controller; #interrupt-cells = <2>; - clocks = <&pclk>; + clocks = <&gpioclk1>; clock-names = "apb_pclk"; status = "disable"; }; @@ -899,7 +1099,7 @@ &pmx0 6 3 1 &pmx0 7 3 1>; interrupt-controller; #interrupt-cells = <2>; - clocks = <&pclk>; + clocks = <&gpioclk2>; clock-names = "apb_pclk"; status = "disable"; }; @@ -915,7 +1115,7 @@ &pmx0 6 11 1 &pmx0 7 11 1>; interrupt-controller; #interrupt-cells = <2>; - clocks = <&pclk>; + clocks = <&gpioclk3>; clock-names = "apb_pclk"; status = "disable"; }; @@ -931,7 +1131,7 @@ &pmx0 6 13 1 &pmx0 7 13 1>; interrupt-controller; #interrupt-cells = <2>; - clocks = <&pclk>; + clocks = <&gpioclk4>; clock-names = "apb_pclk"; status = "disable"; }; @@ -947,7 +1147,7 @@ &pmx0 6 16 1 &pmx0 7 16 1>; interrupt-controller; #interrupt-cells = <2>; - clocks = <&pclk>; + clocks = <&gpioclk5>; clock-names = "apb_pclk"; status = "disable"; }; @@ -963,7 +1163,7 @@ &pmx0 6 18 1 &pmx0 7 19 1>; interrupt-controller; #interrupt-cells = <2>; - clocks = <&pclk>; + clocks = <&gpioclk6>; clock-names = "apb_pclk"; status = "disable"; }; @@ -979,7 +1179,7 @@ &pmx0 6 25 1 &pmx0 7 26 1>; interrupt-controller; #interrupt-cells = <2>; - clocks = <&pclk>; + clocks = <&gpioclk7>; clock-names = "apb_pclk"; status = "disable"; }; @@ -995,7 +1195,7 @@ &pmx0 6 33 1 &pmx0 7 34 1>; interrupt-controller; #interrupt-cells = <2>; - clocks = <&pclk>; + clocks = <&gpioclk8>; clock-names = "apb_pclk"; status = "disable"; }; @@ -1011,7 +1211,7 @@ &pmx0 6 41 1>; interrupt-controller; #interrupt-cells = <2>; - clocks = <&pclk>; + clocks = <&gpioclk9>; clock-names = "apb_pclk"; status = "disable"; }; @@ -1026,7 +1226,7 @@ &pmx0 5 45 1 &pmx0 6 46 1 &pmx0 7 46 1>; interrupt-controller; #interrupt-cells = <2>; - clocks = <&pclk>; + clocks = <&gpioclk10>; clock-names = "apb_pclk"; status = "disable"; }; @@ -1042,7 +1242,7 @@ &pmx0 6 49 1 &pmx0 7 49 1>; interrupt-controller; #interrupt-cells = <2>; - clocks = <&pclk>; + clocks = <&gpioclk11>; clock-names = "apb_pclk"; status = "disable"; }; @@ -1058,7 +1258,7 @@ &pmx0 6 51 1 &pmx0 7 52 1>; interrupt-controller; #interrupt-cells = <2>; - clocks = <&pclk>; + clocks = <&gpioclk12>; clock-names = "apb_pclk"; status = "disable"; }; @@ -1074,7 +1274,7 @@ &pmx0 6 55 1 &pmx0 7 56 1>; interrupt-controller; #interrupt-cells = <2>; - clocks = <&pclk>; + clocks = <&gpioclk13>; clock-names = "apb_pclk"; status = "disable"; }; @@ -1090,7 +1290,7 @@ &pmx0 6 60 1 &pmx0 7 61 1>; interrupt-controller; #interrupt-cells = <2>; - clocks = <&pclk>; + clocks = <&gpioclk14>; clock-names = "apb_pclk"; status = "disable"; }; @@ -1106,7 +1306,7 @@ &pmx0 6 64 1 &pmx0 7 65 1>; interrupt-controller; #interrupt-cells = <2>; - clocks = <&pclk>; + clocks = <&gpioclk15>; clock-names = "apb_pclk"; status = "disable"; }; @@ -1122,7 +1322,7 @@ &pmx0 6 72 1 &pmx0 7 73 1>; interrupt-controller; #interrupt-cells = <2>; - clocks = <&pclk>; + clocks = <&gpioclk16>; clock-names = "apb_pclk"; status = "disable"; }; @@ -1138,7 +1338,7 @@ &pmx0 6 80 1 &pmx0 7 81 1>; interrupt-controller; #interrupt-cells = <2>; - clocks = <&pclk>; + clocks = <&gpioclk17>; clock-names = "apb_pclk"; status = "disable"; }; @@ -1154,7 +1354,7 @@ &pmx0 6 86 1 &pmx0 7 87 1>; interrupt-controller; #interrupt-cells = <2>; - clocks = <&pclk>; + clocks = <&gpioclk18>; clock-names = "apb_pclk"; status = "disable"; }; @@ -1169,7 +1369,7 @@ &pmx0 3 88 1>; interrupt-controller; #interrupt-cells = <2>; - clocks = <&pclk>; + clocks = <&gpioclk19>; clock-names = "apb_pclk"; status = "disable"; }; @@ -1184,7 +1384,7 @@ &pmx0 3 90 1 &pmx0 4 91 1 &pmx0 5 92 1>; interrupt-controller; #interrupt-cells = <2>; - clocks = <&pclk>; + clocks = <&gpioclk20>; clock-names = "apb_pclk"; status = "disable"; }; @@ -1198,7 +1398,7 @@ gpio-ranges = < &pmx0 3 94 1 &pmx0 7 96 1>; interrupt-controller; #interrupt-cells = <2>; - clocks = <&pclk>; + clocks = <&gpioclk21>; clock-names = "apb_pclk"; status = "disable"; }; @@ -1234,20 +1434,13 @@ pinctrl-single,register-width = <32>; }; - sysctrl@fc802000 { - compatible = "hisilicon,sysctrl"; - reg = <0xfc802000 0x1000>; - smp_reg = <0x31c>; - reboot_reg = <0x4>; - }; - dma0: dma@fcd02000 { compatible = "hisilicon,k3-dma-1.0"; reg = <0xfcd02000 0x1000>; #dma-cells = <1>; dma-channels = <27>; interrupts = <0 12 4>; - clocks = <&clk_dmac>; + clocks = <&dmaclk>; status = "disable"; }; @@ -1257,7 +1450,7 @@ #size-cells = <0>; reg = <0xfcb08000 0x1000>; interrupts = <0 28 4>; - clocks = <&clk_i2c0>; + clocks = <&i2cclk0>; dmas = <&dma0 18 /* read channel */ &dma0 19>; /* write channel */ dma-names = "rx", "tx"; @@ -1271,7 +1464,7 @@ #size-cells = <0>; reg = <0xfcb09000 0x1000>; interrupts = <0 29 4>; - clocks = <&clk_i2c1>; + clocks = <&i2cclk1>; dmas = <&dma0 20 /* read channel */ &dma0 21>; /* write channel */ dma-names = "rx", "tx"; @@ -1283,7 +1476,7 @@ compatible = "hisilicon,designware-i2c"; reg = <0xfcb0c000 0x1000>; interrupts = <0 62 4>; - clocks = <&clk_i2c2>; + clocks = <&i2cclk2>; delay-reg = <0xc 4>; status = "disabled"; }; @@ -1292,7 +1485,7 @@ compatible = "hisilicon,designware-i2c"; reg = <0xfcb0d000 0x1000>; interrupts = <0 63 4>; - clocks = <&clk_i2c3>; + clocks = <&i2cclk3>; delay-reg = <0xc 5>; status = "disabled"; }; @@ -1301,7 +1494,7 @@ compatible = "hisilicon,hi3620-mcu"; reg = <0xfd000000 0x00010000>; interrupts = <0 89 4>; - clocks = <&clk_mcu>; + clocks = <&mcuclk>; status = "disabled"; }; @@ -1312,7 +1505,7 @@ interrupts = <0 17 4>; #address-cells = <1>; #size-cells = <0>; - clocks = <&clk_mmc1>, <&clk_ddrc_per>; + clocks = <&mmcclk1>, <&ddrcperclk>; clock-names = "ciu", "biu"; }; @@ -1323,7 +1516,7 @@ interrupts = <0 16 4>; #address-cells = <1>; #size-cells = <0>; - clocks = <&clk_sd>, <&clk_ddrc_per>; + clocks = <&sdclk>, <&ddrcperclk>; clock-names = "ciu", "biu"; }; @@ -1333,7 +1526,7 @@ interrupts = <0 18 4>; #address-cells = <1>; #size-cells = <0>; - clocks = <&clk_mmc2>; + clocks = <&mmcclk2>; }; dwmmc_3: dwmmc3@fcd06000 { @@ -1342,13 +1535,13 @@ interrupts = <0 19 4>; #address-cells = <1>; #size-cells = <0>; - clocks = <&clk_mmc3>; + clocks = <&mmcclk3>; }; kpc: kpc@fc805000 { compatible = "hisilicon,k3_keypad"; reg = <0xfc805000 0x1000>; interrupts = <0 10 4>; - clocks = <&clk_kpc>; + clocks = <&kpcclk>; status = "disabled"; }; }; -- cgit v1.2.3 From 2c037e1c7da4c473c39b02e61a4b1f114f4d20bf Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Thu, 28 Mar 2013 18:05:49 +0800 Subject: clk: hi3xxx: support clocks in EDC domain Some hw clocks are defined in EDC register domain. And the operations on those clocks are same with other hi3xxx clocks. So append the support in clk-hi3xxx driver. Signed-off-by: Haojian Zhuang --- drivers/clk/hisilicon/clk-hi3xxx.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/clk/hisilicon/clk-hi3xxx.c b/drivers/clk/hisilicon/clk-hi3xxx.c index ce13c3907b61..c61041a3b49c 100644 --- a/drivers/clk/hisilicon/clk-hi3xxx.c +++ b/drivers/clk/hisilicon/clk-hi3xxx.c @@ -49,6 +49,7 @@ enum { HS_PMCTRL, HS_SYSCTRL, + HS_EDC, }; struct hi3620_periclk { @@ -82,6 +83,7 @@ struct hi3620_divclk { struct hs_clk { void __iomem *pmctrl; void __iomem *sctrl; + void __iomem *edc; spinlock_t lock; }; @@ -383,7 +385,8 @@ void __init hs_fixed_factor_setup(struct device_node *np) return; parent_names[0] = of_clk_get_parent_name(np, 0); - clk = clk_register_fixed_factor(NULL, clk_name, parent_names[0], 0, + clk = clk_register_fixed_factor(NULL, clk_name, parent_names[0], + CLK_SET_RATE_PARENT, data[0], data[1]); if (IS_ERR(clk)) goto err; @@ -644,6 +647,7 @@ CLK_OF_DECLARE(hs_fixed, "hisilicon,clk-fixed-factor", hs_fixed_factor_setup) static const struct of_device_id hs_of_match[] = { { .compatible = "hisilicon,pmctrl", .data = (void *)HS_PMCTRL, }, { .compatible = "hisilicon,sysctrl", .data = (void *)HS_SYSCTRL, }, + { .compatible = "hisilicon,hi3620-fb", .data = (void *)HS_EDC, }, }; static void __iomem __init *hs_init_clocks(struct device_node *np) @@ -677,6 +681,15 @@ static void __iomem __init *hs_init_clocks(struct device_node *np) ret = hs_clk.sctrl; } break; + case HS_EDC: + if (!hs_clk.edc) { + ret = of_iomap(parent, 0); + WARN_ON(!ret); + hs_clk.edc = ret; + } else { + ret = hs_clk.edc; + } + break; } out: return ret; -- cgit v1.2.3 From 3c5835bc28f5e1bd3e80da0daf7c55ca8d8e859e Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Thu, 4 Apr 2013 00:10:08 +0800 Subject: clk: hi3xxx: not disable clock for clkgate prepare If hi3xxx clock gate is disabled in prepare stage, the uart console can't output anything until it's enabled. It makes debugging kernel harder in kernel boot stage. Signed-off-by: Haojian Zhuang --- drivers/clk/hisilicon/clk-hi3xxx.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/clk/hisilicon/clk-hi3xxx.c b/drivers/clk/hisilicon/clk-hi3xxx.c index c61041a3b49c..9682517edfd4 100644 --- a/drivers/clk/hisilicon/clk-hi3xxx.c +++ b/drivers/clk/hisilicon/clk-hi3xxx.c @@ -100,7 +100,6 @@ static int hi3620_clkgate_prepare(struct clk_hw *hw) if (pclk->lock) spin_lock_irqsave(pclk->lock, flags); - writel_relaxed(pclk->ebits, pclk->enable + HI3620_DISABLE_OFF); if (pclk->reset) { writel_relaxed(pclk->rbits, pclk->reset + HI3620_DISABLE_OFF); readl_relaxed(pclk->reset + HI3620_STATUS_OFF); -- cgit v1.2.3 From 44546ea041c71a9c646c292515e27aed4213eee8 Mon Sep 17 00:00:00 2001 From: Steffen Trumtrar Date: Mon, 17 Dec 2012 14:20:17 +0100 Subject: video: add display_timing and videomode Add display_timing structure and the according helper functions. This allows the description of a display via its supported timing parameters. Also, add helper functions to convert from display timings to a generic videomode structure. The struct display_timing specifies all needed parameters to describe the signal properties of a display in one mode. This includes - ranges for signals that may have min-, max- and typical values - single integers for signals that can be on, off or are ignored - booleans for signals that are either on or off As a display may support multiple modes like this, a struct display_timings is added, that holds all given struct display_timing pointers and declares the native mode of the display. Although a display may state that a signal can be in a range, it is driven with fixed values that indicate a videomode. Therefore graphic drivers don't need all the information of struct display_timing, but would generate a videomode from the given set of supported signal timings and work with that. The video subsystems all define their own structs that describe a mode and work with that (e.g. fb_videomode or drm_display_mode). To slowly replace all those various structures and allow code reuse across those subsystems, add struct videomode as a generic description. This patch only includes the most basic fields in struct videomode. All missing fields that are needed to have a really generic video mode description can be added at a later stage. Signed-off-by: Steffen Trumtrar Reviewed-by: Thierry Reding Acked-by: Thierry Reding Tested-by: Thierry Reding Tested-by: Philipp Zabel Reviewed-by: Laurent Pinchart Acked-by: Laurent Pinchart Tested-by: Afzal Mohammed Tested-by: Rob Clark Tested-by: Leela Krishna Amudala --- drivers/video/Kconfig | 6 ++ drivers/video/Makefile | 2 + drivers/video/display_timing.c | 24 ++++++++ drivers/video/videomode.c | 39 +++++++++++++ include/video/display_timing.h | 124 +++++++++++++++++++++++++++++++++++++++++ include/video/videomode.h | 48 ++++++++++++++++ 6 files changed, 243 insertions(+) create mode 100644 drivers/video/display_timing.c create mode 100644 drivers/video/videomode.c create mode 100644 include/video/display_timing.h create mode 100644 include/video/videomode.h diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index e7068c508800..09a8f0d8a3d4 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -33,6 +33,12 @@ config VIDEO_OUTPUT_CONTROL This framework adds support for low-level control of the video output switch. +config DISPLAY_TIMING + bool + +config VIDEOMODE + bool + menuconfig FB tristate "Support for frame buffer devices" ---help--- diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 768a137a1bac..e0dd8202365f 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -168,3 +168,5 @@ obj-$(CONFIG_FB_VIRTUAL) += vfb.o #video output switch sysfs driver obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o +obj-$(CONFIG_DISPLAY_TIMING) += display_timing.o +obj-$(CONFIG_VIDEOMODE) += videomode.o diff --git a/drivers/video/display_timing.c b/drivers/video/display_timing.c new file mode 100644 index 000000000000..5e1822cef571 --- /dev/null +++ b/drivers/video/display_timing.c @@ -0,0 +1,24 @@ +/* + * generic display timing functions + * + * Copyright (c) 2012 Steffen Trumtrar , Pengutronix + * + * This file is released under the GPLv2 + */ + +#include +#include +#include