diff options
author | Prashant Gaikwad <pgaikwad@nvidia.com> | 2012-08-06 02:27:42 -0400 |
---|---|---|
committer | Stephen Warren <swarren@nvidia.com> | 2012-09-06 13:47:20 -0400 |
commit | 96a1bd1e11ade7be969d275edd4c06749684cdba (patch) | |
tree | d76dde0eb30d5dab8cb81ad8d27fc5554e0cbe03 | |
parent | 23fc5b246119f665cfa075ce7567f31a017b11b8 (diff) |
ARM: tegra: Add clk_tegra structure and helper functions
Add Tegra platform specific clock structure clk_tegra and
some helper functions for generic clock framework.
struct clk_tegra is the single strcture used for all types of
clocks. reset and cfg_ex ops moved to clk_tegra from clk_ops.
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
-rw-r--r-- | arch/arm/mach-tegra/clock.c | 126 | ||||
-rw-r--r-- | arch/arm/mach-tegra/clock.h | 90 | ||||
-rw-r--r-- | arch/arm/mach-tegra/common.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/mach/clk.h | 3 |
4 files changed, 210 insertions, 11 deletions
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index 58f981c0819c..ef9b494f961a 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * | 2 | * |
3 | * Copyright (C) 2010 Google, Inc. | 3 | * Copyright (C) 2010 Google, Inc. |
4 | * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved. | ||
4 | * | 5 | * |
5 | * Author: | 6 | * Author: |
6 | * Colin Cross <ccross@google.com> | 7 | * Colin Cross <ccross@google.com> |
@@ -62,6 +63,7 @@ | |||
62 | static DEFINE_MUTEX(clock_list_lock); | 63 | static DEFINE_MUTEX(clock_list_lock); |
63 | static LIST_HEAD(clocks); | 64 | static LIST_HEAD(clocks); |
64 | 65 | ||
66 | #ifndef CONFIG_COMMON_CLK | ||
65 | struct clk *tegra_get_clock_by_name(const char *name) | 67 | struct clk *tegra_get_clock_by_name(const char *name) |
66 | { | 68 | { |
67 | struct clk *c; | 69 | struct clk *c; |
@@ -668,5 +670,127 @@ err_out: | |||
668 | debugfs_remove_recursive(clk_debugfs_root); | 670 | debugfs_remove_recursive(clk_debugfs_root); |
669 | return err; | 671 | return err; |
670 | } | 672 | } |
671 | |||
672 | #endif | 673 | #endif |
674 | #else | ||
675 | |||
676 | void tegra_clk_add(struct clk *clk) | ||
677 | { | ||
678 | struct clk_tegra *c = to_clk_tegra(__clk_get_hw(clk)); | ||
679 | |||
680 | mutex_lock(&clock_list_lock); | ||
681 | list_add(&c->node, &clocks); | ||
682 | mutex_unlock(&clock_list_lock); | ||
683 | } | ||
684 | |||
685 | struct clk *tegra_get_clock_by_name(const char *name) | ||
686 | { | ||
687 | struct clk_tegra *c; | ||
688 | struct clk *ret = NULL; | ||
689 | mutex_lock(&clock_list_lock); | ||
690 | list_for_each_entry(c, &clocks, node) { | ||
691 | if (strcmp(__clk_get_name(c->hw.clk), name) == 0) { | ||
692 | ret = c->hw.clk; | ||
693 | break; | ||
694 | } | ||
695 | } | ||
696 | mutex_unlock(&clock_list_lock); | ||
697 | return ret; | ||
698 | } | ||
699 | |||
700 | static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table) | ||
701 | { | ||
702 | struct clk *c; | ||
703 | struct clk *p; | ||
704 | struct clk *parent; | ||
705 | |||
706 | int ret = 0; | ||
707 | |||
708 | c = tegra_get_clock_by_name(table->name); | ||
709 | |||
710 | if (!c) { | ||
711 | pr_warn("Unable to initialize clock %s\n", | ||
712 | table->name); | ||
713 | return -ENODEV; | ||
714 | } | ||
715 | |||
716 | parent = clk_get_parent(c); | ||
717 | |||
718 | if (table->parent) { | ||
719 | p = tegra_get_clock_by_name(table->parent); | ||
720 | if (!p) { | ||
721 | pr_warn("Unable to find parent %s of clock %s\n", | ||
722 | table->parent, table->name); | ||
723 | return -ENODEV; | ||
724 | } | ||
725 | |||
726 | if (parent != p) { | ||
727 | ret = clk_set_parent(c, p); | ||
728 | if (ret) { | ||
729 | pr_warn("Unable to set parent %s of clock %s: %d\n", | ||
730 | table->parent, table->name, ret); | ||
731 | return -EINVAL; | ||
732 | } | ||
733 | } | ||
734 | } | ||
735 | |||
736 | if (table->rate && table->rate != clk_get_rate(c)) { | ||
737 | ret = clk_set_rate(c, table->rate); | ||
738 | if (ret) { | ||
739 | pr_warn("Unable to set clock %s to rate %lu: %d\n", | ||
740 | table->name, table->rate, ret); | ||
741 | return -EINVAL; | ||
742 | } | ||
743 | } | ||
744 | |||
745 | if (table->enabled) { | ||
746 | ret = clk_prepare_enable(c); | ||
747 | if (ret) { | ||
748 | pr_warn("Unable to enable clock %s: %d\n", | ||
749 | table->name, ret); | ||
750 | return -EINVAL; | ||
751 | } | ||
752 | } | ||
753 | |||
754 | return 0; | ||
755 | } | ||
756 | |||
757 | void tegra_clk_init_from_table(struct tegra_clk_init_table *table) | ||
758 | { | ||
759 | for (; table->name; table++) | ||
760 | tegra_clk_init_one_from_table(table); | ||
761 | } | ||
762 | |||
763 | void tegra_periph_reset_deassert(struct clk *c) | ||
764 | { | ||
765 | struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c)); | ||
766 | BUG_ON(!clk->reset); | ||
767 | clk->reset(__clk_get_hw(c), false); | ||
768 | } | ||
769 | EXPORT_SYMBOL(tegra_periph_reset_deassert); | ||
770 | |||
771 | void tegra_periph_reset_assert(struct clk *c) | ||
772 | { | ||
773 | struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c)); | ||
774 | BUG_ON(!clk->reset); | ||
775 | clk->reset(__clk_get_hw(c), true); | ||
776 | } | ||
777 | EXPORT_SYMBOL(tegra_periph_reset_assert); | ||
778 | |||
779 | /* Several extended clock configuration bits (e.g., clock routing, clock | ||
780 | * phase control) are included in PLL and peripheral clock source | ||
781 | * registers. */ | ||
782 | int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting) | ||
783 | { | ||
784 | int ret = 0; | ||
785 | struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c)); | ||
786 | |||
787 | if (!clk->clk_cfg_ex) { | ||
788 | ret = -ENOSYS; | ||
789 | goto out; | ||
790 | } | ||
791 | ret = clk->clk_cfg_ex(__clk_get_hw(c), p, setting); | ||
792 | |||
793 | out: | ||
794 | return ret; | ||
795 | } | ||
796 | #endif /* !CONFIG_COMMON_CLK */ | ||
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h index bc300657deba..f4d32ba56027 100644 --- a/arch/arm/mach-tegra/clock.h +++ b/arch/arm/mach-tegra/clock.h | |||
@@ -2,6 +2,7 @@ | |||
2 | * arch/arm/mach-tegra/include/mach/clock.h | 2 | * arch/arm/mach-tegra/include/mach/clock.h |
3 | * | 3 | * |
4 | * Copyright (C) 2010 Google, Inc. | 4 | * Copyright (C) 2010 Google, Inc. |
5 | * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved. | ||
5 | * | 6 | * |
6 | * Author: | 7 | * Author: |
7 | * Colin Cross <ccross@google.com> | 8 | * Colin Cross <ccross@google.com> |
@@ -20,6 +21,7 @@ | |||
20 | #ifndef __MACH_TEGRA_CLOCK_H | 21 | #ifndef __MACH_TEGRA_CLOCK_H |
21 | #define __MACH_TEGRA_CLOCK_H | 22 | #define __MACH_TEGRA_CLOCK_H |
22 | 23 | ||
24 | #include <linux/clk-provider.h> | ||
23 | #include <linux/clkdev.h> | 25 | #include <linux/clkdev.h> |
24 | #include <linux/list.h> | 26 | #include <linux/list.h> |
25 | #include <linux/spinlock.h> | 27 | #include <linux/spinlock.h> |
@@ -54,6 +56,11 @@ | |||
54 | 56 | ||
55 | struct clk; | 57 | struct clk; |
56 | 58 | ||
59 | #ifdef CONFIG_COMMON_CLK | ||
60 | struct clk_tegra; | ||
61 | #define to_clk_tegra(_hw) container_of(_hw, struct clk_tegra, hw) | ||
62 | #endif | ||
63 | |||
57 | struct clk_mux_sel { | 64 | struct clk_mux_sel { |
58 | struct clk *input; | 65 | struct clk *input; |
59 | u32 value; | 66 | u32 value; |
@@ -68,6 +75,13 @@ struct clk_pll_freq_table { | |||
68 | u8 cpcon; | 75 | u8 cpcon; |
69 | }; | 76 | }; |
70 | 77 | ||
78 | enum clk_state { | ||
79 | UNINITIALIZED = 0, | ||
80 | ON, | ||
81 | OFF, | ||
82 | }; | ||
83 | |||
84 | #ifndef CONFIG_COMMON_CLK | ||
71 | struct clk_ops { | 85 | struct clk_ops { |
72 | void (*init)(struct clk *); | 86 | void (*init)(struct clk *); |
73 | int (*enable)(struct clk *); | 87 | int (*enable)(struct clk *); |
@@ -80,12 +94,6 @@ struct clk_ops { | |||
80 | enum tegra_clk_ex_param, u32); | 94 | enum tegra_clk_ex_param, u32); |
81 | }; | 95 | }; |
82 | 96 | ||
83 | enum clk_state { | ||
84 | UNINITIALIZED = 0, | ||
85 | ON, | ||
86 | OFF, | ||
87 | }; | ||
88 | |||
89 | struct clk { | 97 | struct clk { |
90 | /* node for master clocks list */ | 98 | /* node for master clocks list */ |
91 | struct list_head node; /* node for list of all clocks */ | 99 | struct list_head node; /* node for list of all clocks */ |
@@ -147,6 +155,65 @@ struct clk { | |||
147 | spinlock_t spinlock; | 155 | spinlock_t spinlock; |
148 | }; | 156 | }; |
149 | 157 | ||
158 | #else | ||
159 | |||
160 | struct clk_tegra { | ||
161 | /* node for master clocks list */ | ||
162 | struct list_head node; /* node for list of all clocks */ | ||
163 | struct clk_lookup lookup; | ||
164 | struct clk_hw hw; | ||
165 | |||
166 | bool set; | ||
167 | unsigned long fixed_rate; | ||
168 | unsigned long max_rate; | ||
169 | unsigned long min_rate; | ||
170 | u32 flags; | ||
171 | const char *name; | ||
172 | |||
173 | enum clk_state state; | ||
174 | u32 div; | ||
175 | u32 mul; | ||
176 | |||
177 | u32 reg; | ||
178 | u32 reg_shift; | ||
179 | |||
180 | struct list_head shared_bus_list; | ||
181 | |||
182 | union { | ||
183 | struct { | ||
184 | unsigned int clk_num; | ||
185 | } periph; | ||
186 | struct { | ||
187 | unsigned long input_min; | ||
188 | unsigned long input_max; | ||
189 | unsigned long cf_min; | ||
190 | unsigned long cf_max; | ||
191 | unsigned long vco_min; | ||
192 | unsigned long vco_max; | ||
193 | const struct clk_pll_freq_table *freq_table; | ||
194 | int lock_delay; | ||
195 | unsigned long fixed_rate; | ||
196 | } pll; | ||
197 | struct { | ||
198 | u32 sel; | ||
199 | u32 reg_mask; | ||
200 | } mux; | ||
201 | struct { | ||
202 | struct clk *main; | ||
203 | struct clk *backup; | ||
204 | } cpu; | ||
205 | struct { | ||
206 | struct list_head node; | ||
207 | bool enabled; | ||
208 | unsigned long rate; | ||
209 | } shared_bus_user; | ||
210 | } u; | ||
211 | |||
212 | void (*reset)(struct clk_hw *, bool); | ||
213 | int (*clk_cfg_ex)(struct clk_hw *, enum tegra_clk_ex_param, u32); | ||
214 | }; | ||
215 | #endif /* !CONFIG_COMMON_CLK */ | ||
216 | |||
150 | struct clk_duplicate { | 217 | struct clk_duplicate { |
151 | const char *name; | 218 | const char *name; |
152 | struct clk_lookup lookup; | 219 | struct clk_lookup lookup; |
@@ -159,13 +226,16 @@ struct tegra_clk_init_table { | |||
159 | bool enabled; | 226 | bool enabled; |
160 | }; | 227 | }; |
161 | 228 | ||
229 | #ifndef CONFIG_COMMON_CLK | ||
230 | void clk_init(struct clk *clk); | ||
231 | unsigned long clk_get_rate_locked(struct clk *c); | ||
232 | int clk_set_rate_locked(struct clk *c, unsigned long rate); | ||
233 | int clk_reparent(struct clk *c, struct clk *parent); | ||
234 | #endif /* !CONFIG_COMMON_CLK */ | ||
235 | |||
162 | void tegra2_init_clocks(void); | 236 | void tegra2_init_clocks(void); |
163 | void tegra30_init_clocks(void); | 237 | void tegra30_init_clocks(void); |
164 | void clk_init(struct clk *clk); | ||
165 | struct clk *tegra_get_clock_by_name(const char *name); | 238 | struct clk *tegra_get_clock_by_name(const char *name); |
166 | int clk_reparent(struct clk *c, struct clk *parent); | ||
167 | void tegra_clk_init_from_table(struct tegra_clk_init_table *table); | 239 | void tegra_clk_init_from_table(struct tegra_clk_init_table *table); |
168 | unsigned long clk_get_rate_locked(struct clk *c); | ||
169 | int clk_set_rate_locked(struct clk *c, unsigned long rate); | ||
170 | 240 | ||
171 | #endif | 241 | #endif |
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 96fef6bcc651..ef7d6f3cff82 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c | |||
@@ -152,6 +152,8 @@ void __init tegra30_init_early(void) | |||
152 | 152 | ||
153 | void __init tegra_init_late(void) | 153 | void __init tegra_init_late(void) |
154 | { | 154 | { |
155 | #ifndef CONFIG_COMMON_CLK | ||
155 | tegra_clk_debugfs_init(); | 156 | tegra_clk_debugfs_init(); |
157 | #endif | ||
156 | tegra_powergate_debugfs_init(); | 158 | tegra_powergate_debugfs_init(); |
157 | } | 159 | } |
diff --git a/arch/arm/mach-tegra/include/mach/clk.h b/arch/arm/mach-tegra/include/mach/clk.h index d97e403303a0..95f3a547c770 100644 --- a/arch/arm/mach-tegra/include/mach/clk.h +++ b/arch/arm/mach-tegra/include/mach/clk.h | |||
@@ -34,7 +34,10 @@ enum tegra_clk_ex_param { | |||
34 | void tegra_periph_reset_deassert(struct clk *c); | 34 | void tegra_periph_reset_deassert(struct clk *c); |
35 | void tegra_periph_reset_assert(struct clk *c); | 35 | void tegra_periph_reset_assert(struct clk *c); |
36 | 36 | ||
37 | #ifndef CONFIG_COMMON_CLK | ||
37 | unsigned long clk_get_rate_all_locked(struct clk *c); | 38 | unsigned long clk_get_rate_all_locked(struct clk *c); |
39 | #endif | ||
40 | |||
38 | void tegra2_sdmmc_tap_delay(struct clk *c, int delay); | 41 | void tegra2_sdmmc_tap_delay(struct clk *c, int delay); |
39 | int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting); | 42 | int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting); |
40 | 43 | ||