diff options
author | Tero Kristo <t-kristo@ti.com> | 2013-10-22 04:39:36 -0400 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2014-01-17 15:34:52 -0500 |
commit | 819b4861c18d602463cfe815041d11fd81002654 (patch) | |
tree | b9b83374a962896f3d3903dc16345a9dfa53ecca | |
parent | a8aceccb4d5db0acb476b74051525fb26f57f8ae (diff) |
CLK: ti: add init support for clock IP blocks
ti_dt_clk_init_provider() can now be used to initialize the contents of
a single clock IP block. This parses all the clocks under the IP block
and calls the corresponding init function for them.
This patch also introduces a helper function for the TI clock drivers
to get register info from DT and append the master IP info to this.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Acked-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Mike Turquette <mturquette@linaro.org>
-rw-r--r-- | drivers/clk/clk.c | 4 | ||||
-rw-r--r-- | drivers/clk/ti/clk.c | 112 | ||||
-rw-r--r-- | include/linux/clk-provider.h | 2 | ||||
-rw-r--r-- | include/linux/clk/ti.h | 35 |
4 files changed, 150 insertions, 3 deletions
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 2b38dc99063f..077106732550 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c | |||
@@ -2373,8 +2373,6 @@ struct of_clk_provider { | |||
2373 | void *data; | 2373 | void *data; |
2374 | }; | 2374 | }; |
2375 | 2375 | ||
2376 | extern struct of_device_id __clk_of_table[]; | ||
2377 | |||
2378 | static const struct of_device_id __clk_of_table_sentinel | 2376 | static const struct of_device_id __clk_of_table_sentinel |
2379 | __used __section(__clk_of_table_end); | 2377 | __used __section(__clk_of_table_end); |
2380 | 2378 | ||
@@ -2534,7 +2532,7 @@ void __init of_clk_init(const struct of_device_id *matches) | |||
2534 | struct device_node *np; | 2532 | struct device_node *np; |
2535 | 2533 | ||
2536 | if (!matches) | 2534 | if (!matches) |
2537 | matches = __clk_of_table; | 2535 | matches = &__clk_of_table; |
2538 | 2536 | ||
2539 | for_each_matching_node_and_match(np, matches, &match) { | 2537 | for_each_matching_node_and_match(np, matches, &match) { |
2540 | of_clk_init_cb_t clk_init_cb = match->data; | 2538 | of_clk_init_cb_t clk_init_cb = match->data; |
diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index ef1a7cdecfd9..b1a6f7144f3f 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c | |||
@@ -19,10 +19,15 @@ | |||
19 | #include <linux/clkdev.h> | 19 | #include <linux/clkdev.h> |
20 | #include <linux/clk/ti.h> | 20 | #include <linux/clk/ti.h> |
21 | #include <linux/of.h> | 21 | #include <linux/of.h> |
22 | #include <linux/of_address.h> | ||
23 | #include <linux/list.h> | ||
22 | 24 | ||
23 | #undef pr_fmt | 25 | #undef pr_fmt |
24 | #define pr_fmt(fmt) "%s: " fmt, __func__ | 26 | #define pr_fmt(fmt) "%s: " fmt, __func__ |
25 | 27 | ||
28 | static int ti_dt_clk_memmap_index; | ||
29 | struct ti_clk_ll_ops *ti_clk_ll_ops; | ||
30 | |||
26 | /** | 31 | /** |
27 | * ti_dt_clocks_register - register DT alias clocks during boot | 32 | * ti_dt_clocks_register - register DT alias clocks during boot |
28 | * @oclks: list of clocks to register | 33 | * @oclks: list of clocks to register |
@@ -53,3 +58,110 @@ void __init ti_dt_clocks_register(struct ti_dt_clk oclks[]) | |||
53 | } | 58 | } |
54 | } | 59 | } |
55 | } | 60 | } |
61 | |||
62 | struct clk_init_item { | ||
63 | struct device_node *node; | ||
64 | struct clk_hw *hw; | ||
65 | ti_of_clk_init_cb_t func; | ||
66 | struct list_head link; | ||
67 | }; | ||
68 | |||
69 | static LIST_HEAD(retry_list); | ||
70 | |||
71 | /** | ||
72 | * ti_clk_retry_init - retries a failed clock init at later phase | ||
73 | * @node: device not for the clock | ||
74 | * @hw: partially initialized clk_hw struct for the clock | ||
75 | * @func: init function to be called for the clock | ||
76 | * | ||
77 | * Adds a failed clock init to the retry list. The retry list is parsed | ||
78 | * once all the other clocks have been initialized. | ||
79 | */ | ||
80 | int __init ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, | ||
81 | ti_of_clk_init_cb_t func) | ||
82 | { | ||
83 | struct clk_init_item *retry; | ||
84 | |||
85 | pr_debug("%s: adding to retry list...\n", node->name); | ||
86 | retry = kzalloc(sizeof(*retry), GFP_KERNEL); | ||
87 | if (!retry) | ||
88 | return -ENOMEM; | ||
89 | |||
90 | retry->node = node; | ||
91 | retry->func = func; | ||
92 | retry->hw = hw; | ||
93 | list_add(&retry->link, &retry_list); | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | /** | ||
99 | * ti_clk_get_reg_addr - get register address for a clock register | ||
100 | * @node: device node for the clock | ||
101 | * @index: register index from the clock node | ||
102 | * | ||
103 | * Builds clock register address from device tree information. This | ||
104 | * is a struct of type clk_omap_reg. | ||
105 | */ | ||
106 | void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index) | ||
107 | { | ||
108 | struct clk_omap_reg *reg; | ||
109 | u32 val; | ||
110 | u32 tmp; | ||
111 | |||
112 | reg = (struct clk_omap_reg *)&tmp; | ||
113 | reg->index = ti_dt_clk_memmap_index; | ||
114 | |||
115 | if (of_property_read_u32_index(node, "reg", index, &val)) { | ||
116 | pr_err("%s must have reg[%d]!\n", node->name, index); | ||
117 | return NULL; | ||
118 | } | ||
119 | |||
120 | reg->offset = val; | ||
121 | |||
122 | return (void __iomem *)tmp; | ||
123 | } | ||
124 | |||
125 | /** | ||
126 | * ti_dt_clk_init_provider - init master clock provider | ||
127 | * @parent: master node | ||
128 | * @index: internal index for clk_reg_ops | ||
129 | * | ||
130 | * Initializes a master clock IP block and its child clock nodes. | ||
131 | * Regmap is provided for accessing the register space for the | ||
132 | * IP block and all the clocks under it. | ||
133 | */ | ||
134 | void ti_dt_clk_init_provider(struct device_node *parent, int index) | ||
135 | { | ||
136 | const struct of_device_id *match; | ||
137 | struct device_node *np; | ||
138 | struct device_node *clocks; | ||
139 | of_clk_init_cb_t clk_init_cb; | ||
140 | struct clk_init_item *retry; | ||
141 | struct clk_init_item *tmp; | ||
142 | |||
143 | ti_dt_clk_memmap_index = index; | ||
144 | |||
145 | /* get clocks for this parent */ | ||
146 | clocks = of_get_child_by_name(parent, "clocks"); | ||
147 | if (!clocks) { | ||
148 | pr_err("%s missing 'clocks' child node.\n", parent->name); | ||
149 | return; | ||
150 | } | ||
151 | |||
152 | for_each_child_of_node(clocks, np) { | ||
153 | match = of_match_node(&__clk_of_table, np); | ||
154 | if (!match) | ||
155 | continue; | ||
156 | clk_init_cb = (of_clk_init_cb_t)match->data; | ||
157 | pr_debug("%s: initializing: %s\n", __func__, np->name); | ||
158 | clk_init_cb(np); | ||
159 | } | ||
160 | |||
161 | list_for_each_entry_safe(retry, tmp, &retry_list, link) { | ||
162 | pr_debug("retry-init: %s\n", retry->node->name); | ||
163 | retry->func(retry->hw, retry->node); | ||
164 | list_del(&retry->link); | ||
165 | kfree(retry); | ||
166 | } | ||
167 | } | ||
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 999b28ba38f7..448b2294820f 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h | |||
@@ -488,6 +488,8 @@ struct clk_onecell_data { | |||
488 | unsigned int clk_num; | 488 | unsigned int clk_num; |
489 | }; | 489 | }; |
490 | 490 | ||
491 | extern struct of_device_id __clk_of_table; | ||
492 | |||
491 | #define CLK_OF_DECLARE(name, compat, fn) \ | 493 | #define CLK_OF_DECLARE(name, compat, fn) \ |
492 | static const struct of_device_id __clk_of_table_##name \ | 494 | static const struct of_device_id __clk_of_table_##name \ |
493 | __used __section(__clk_of_table) \ | 495 | __used __section(__clk_of_table) \ |
diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index df94c243205e..c6eded5eea76 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h | |||
@@ -36,7 +36,42 @@ struct ti_dt_clk { | |||
36 | .node_name = name, \ | 36 | .node_name = name, \ |
37 | } | 37 | } |
38 | 38 | ||
39 | /* Maximum number of clock memmaps */ | ||
40 | #define CLK_MAX_MEMMAPS 4 | ||
39 | 41 | ||
42 | typedef void (*ti_of_clk_init_cb_t)(struct clk_hw *, struct device_node *); | ||
43 | |||
44 | /** | ||
45 | * struct clk_omap_reg - OMAP register declaration | ||
46 | * @offset: offset from the master IP module base address | ||
47 | * @index: index of the master IP module | ||
48 | */ | ||
49 | struct clk_omap_reg { | ||
50 | u16 offset; | ||
51 | u16 index; | ||
52 | }; | ||
53 | |||
54 | /** | ||
55 | * struct ti_clk_ll_ops - low-level register access ops for a clock | ||
56 | * @clk_readl: pointer to register read function | ||
57 | * @clk_writel: pointer to register write function | ||
58 | * | ||
59 | * Low-level register access ops are generally used by the basic clock types | ||
60 | * (clk-gate, clk-mux, clk-divider etc.) to provide support for various | ||
61 | * low-level hardware interfaces (direct MMIO, regmap etc.), but can also be | ||
62 | * used by other hardware-specific clock drivers if needed. | ||
63 | */ | ||
64 | struct ti_clk_ll_ops { | ||
65 | u32 (*clk_readl)(void __iomem *reg); | ||
66 | void (*clk_writel)(u32 val, void __iomem *reg); | ||
67 | }; | ||
68 | |||
69 | extern struct ti_clk_ll_ops *ti_clk_ll_ops; | ||
70 | |||
71 | void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index); | ||
40 | void ti_dt_clocks_register(struct ti_dt_clk *oclks); | 72 | void ti_dt_clocks_register(struct ti_dt_clk *oclks); |
73 | void ti_dt_clk_init_provider(struct device_node *np, int index); | ||
74 | int ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, | ||
75 | ti_of_clk_init_cb_t func); | ||
41 | 76 | ||
42 | #endif | 77 | #endif |