xref: /openbmc/linux/drivers/clk/samsung/clk.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2721c42a3SThomas Abraham /*
3721c42a3SThomas Abraham  * Copyright (c) 2013 Samsung Electronics Co., Ltd.
4721c42a3SThomas Abraham  * Copyright (c) 2013 Linaro Ltd.
5721c42a3SThomas Abraham  * Author: Thomas Abraham <thomas.ab@samsung.com>
6721c42a3SThomas Abraham  *
7721c42a3SThomas Abraham  * This file includes utility functions to register clocks to common
8721c42a3SThomas Abraham  * clock framework for Samsung platforms.
9721c42a3SThomas Abraham */
10721c42a3SThomas Abraham 
116f1ed07aSStephen Boyd #include <linux/slab.h>
126f1ed07aSStephen Boyd #include <linux/clkdev.h>
136f1ed07aSStephen Boyd #include <linux/clk.h>
146f1ed07aSStephen Boyd #include <linux/clk-provider.h>
1562e59c4eSStephen Boyd #include <linux/io.h>
168b2f6360SPankaj Dubey #include <linux/of_address.h>
17721c42a3SThomas Abraham #include <linux/syscore_ops.h>
188b2f6360SPankaj Dubey 
19721c42a3SThomas Abraham #include "clk.h"
20721c42a3SThomas Abraham 
2116a9013bSNaveen Krishna Ch static LIST_HEAD(clock_reg_cache_list);
2216a9013bSNaveen Krishna Ch 
samsung_clk_save(void __iomem * base,struct samsung_clk_reg_dump * rd,unsigned int num_regs)233ccefbd2STomasz Figa void samsung_clk_save(void __iomem *base,
243ccefbd2STomasz Figa 				    struct samsung_clk_reg_dump *rd,
253ccefbd2STomasz Figa 				    unsigned int num_regs)
263ccefbd2STomasz Figa {
273ccefbd2STomasz Figa 	for (; num_regs > 0; --num_regs, ++rd)
283ccefbd2STomasz Figa 		rd->value = readl(base + rd->offset);
293ccefbd2STomasz Figa }
303ccefbd2STomasz Figa 
samsung_clk_restore(void __iomem * base,const struct samsung_clk_reg_dump * rd,unsigned int num_regs)313ccefbd2STomasz Figa void samsung_clk_restore(void __iomem *base,
323ccefbd2STomasz Figa 				      const struct samsung_clk_reg_dump *rd,
333ccefbd2STomasz Figa 				      unsigned int num_regs)
343ccefbd2STomasz Figa {
353ccefbd2STomasz Figa 	for (; num_regs > 0; --num_regs, ++rd)
363ccefbd2STomasz Figa 		writel(rd->value, base + rd->offset);
373ccefbd2STomasz Figa }
383ccefbd2STomasz Figa 
samsung_clk_alloc_reg_dump(const unsigned long * rdump,unsigned long nr_rdump)39c3b6c1d7STomasz Figa struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump(
40c3b6c1d7STomasz Figa 						const unsigned long *rdump,
413ccefbd2STomasz Figa 						unsigned long nr_rdump)
423ccefbd2STomasz Figa {
433ccefbd2STomasz Figa 	struct samsung_clk_reg_dump *rd;
443ccefbd2STomasz Figa 	unsigned int i;
453ccefbd2STomasz Figa 
463ccefbd2STomasz Figa 	rd = kcalloc(nr_rdump, sizeof(*rd), GFP_KERNEL);
473ccefbd2STomasz Figa 	if (!rd)
483ccefbd2STomasz Figa 		return NULL;
493ccefbd2STomasz Figa 
503ccefbd2STomasz Figa 	for (i = 0; i < nr_rdump; ++i)
513ccefbd2STomasz Figa 		rd[i].offset = rdump[i];
523ccefbd2STomasz Figa 
533ccefbd2STomasz Figa 	return rd;
543ccefbd2STomasz Figa }
553ccefbd2STomasz Figa 
56a4c78367SSam Protsenko /**
57a4c78367SSam Protsenko  * samsung_clk_init() - Create and initialize a clock provider object
58a4c78367SSam Protsenko  * @dev:	CMU device to enable runtime PM, or NULL if RPM is not needed
59a4c78367SSam Protsenko  * @base:	Start address (mapped) of CMU registers
60a4c78367SSam Protsenko  * @nr_clks:	Total clock count to allocate in clock provider object
61a4c78367SSam Protsenko  *
62a4c78367SSam Protsenko  * Setup the essentials required to support clock lookup using Common Clock
63a4c78367SSam Protsenko  * Framework.
64a4c78367SSam Protsenko  *
65a4c78367SSam Protsenko  * Return: Allocated and initialized clock provider object.
66a4c78367SSam Protsenko  */
samsung_clk_init(struct device * dev,void __iomem * base,unsigned long nr_clks)67a4c78367SSam Protsenko struct samsung_clk_provider * __init samsung_clk_init(struct device *dev,
68a4c78367SSam Protsenko 			void __iomem *base, unsigned long nr_clks)
69721c42a3SThomas Abraham {
70976face4SRahul Sharma 	struct samsung_clk_provider *ctx;
7191a1263fSTomasz Figa 	int i;
7291a1263fSTomasz Figa 
73e620a1e0SStephen Kitt 	ctx = kzalloc(struct_size(ctx, clk_data.hws, nr_clks), GFP_KERNEL);
74976face4SRahul Sharma 	if (!ctx)
75976face4SRahul Sharma 		panic("could not allocate clock provider context.\n");
76721c42a3SThomas Abraham 
7791a1263fSTomasz Figa 	for (i = 0; i < nr_clks; ++i)
78ecb1f1f7SMarek Szyprowski 		ctx->clk_data.hws[i] = ERR_PTR(-ENOENT);
7991a1263fSTomasz Figa 
80a4c78367SSam Protsenko 	ctx->dev = dev;
81976face4SRahul Sharma 	ctx->reg_base = base;
82ecb1f1f7SMarek Szyprowski 	ctx->clk_data.num = nr_clks;
83976face4SRahul Sharma 	spin_lock_init(&ctx->lock);
846e92bf5aSHeiko Stuebner 
85976face4SRahul Sharma 	return ctx;
86d5e136a2SSylwester Nawrocki }
87976face4SRahul Sharma 
samsung_clk_of_add_provider(struct device_node * np,struct samsung_clk_provider * ctx)88d5e136a2SSylwester Nawrocki void __init samsung_clk_of_add_provider(struct device_node *np,
89d5e136a2SSylwester Nawrocki 				struct samsung_clk_provider *ctx)
90d5e136a2SSylwester Nawrocki {
91d5e136a2SSylwester Nawrocki 	if (np) {
92ecb1f1f7SMarek Szyprowski 		if (of_clk_add_hw_provider(np, of_clk_hw_onecell_get,
93d5e136a2SSylwester Nawrocki 					&ctx->clk_data))
94d5e136a2SSylwester Nawrocki 			panic("could not register clk provider\n");
95d5e136a2SSylwester Nawrocki 	}
96721c42a3SThomas Abraham }
97721c42a3SThomas Abraham 
98721c42a3SThomas Abraham /* add a clock instance to the clock lookup table used for dt based lookup */
samsung_clk_add_lookup(struct samsung_clk_provider * ctx,struct clk_hw * clk_hw,unsigned int id)99ecb1f1f7SMarek Szyprowski void samsung_clk_add_lookup(struct samsung_clk_provider *ctx,
100ecb1f1f7SMarek Szyprowski 			    struct clk_hw *clk_hw, unsigned int id)
101721c42a3SThomas Abraham {
102ecb1f1f7SMarek Szyprowski 	if (id)
103ecb1f1f7SMarek Szyprowski 		ctx->clk_data.hws[id] = clk_hw;
104721c42a3SThomas Abraham }
105721c42a3SThomas Abraham 
1065e2e0195SHeiko Stuebner /* register a list of aliases */
samsung_clk_register_alias(struct samsung_clk_provider * ctx,const struct samsung_clock_alias * list,unsigned int nr_clk)107976face4SRahul Sharma void __init samsung_clk_register_alias(struct samsung_clk_provider *ctx,
1084a1caed3SUwe Kleine-König 				const struct samsung_clock_alias *list,
1095e2e0195SHeiko Stuebner 				unsigned int nr_clk)
1105e2e0195SHeiko Stuebner {
111ecb1f1f7SMarek Szyprowski 	struct clk_hw *clk_hw;
1125e2e0195SHeiko Stuebner 	unsigned int idx, ret;
1135e2e0195SHeiko Stuebner 
1145e2e0195SHeiko Stuebner 	for (idx = 0; idx < nr_clk; idx++, list++) {
1155e2e0195SHeiko Stuebner 		if (!list->id) {
1165e2e0195SHeiko Stuebner 			pr_err("%s: clock id missing for index %d\n", __func__,
1175e2e0195SHeiko Stuebner 				idx);
1185e2e0195SHeiko Stuebner 			continue;
1195e2e0195SHeiko Stuebner 		}
1205e2e0195SHeiko Stuebner 
121ecb1f1f7SMarek Szyprowski 		clk_hw = ctx->clk_data.hws[list->id];
122ecb1f1f7SMarek Szyprowski 		if (!clk_hw) {
1235e2e0195SHeiko Stuebner 			pr_err("%s: failed to find clock %d\n", __func__,
1245e2e0195SHeiko Stuebner 				list->id);
1255e2e0195SHeiko Stuebner 			continue;
1265e2e0195SHeiko Stuebner 		}
1275e2e0195SHeiko Stuebner 
128ecb1f1f7SMarek Szyprowski 		ret = clk_hw_register_clkdev(clk_hw, list->alias,
129ecb1f1f7SMarek Szyprowski 					     list->dev_name);
1305e2e0195SHeiko Stuebner 		if (ret)
1315e2e0195SHeiko Stuebner 			pr_err("%s: failed to register lookup %s\n",
1325e2e0195SHeiko Stuebner 					__func__, list->alias);
1335e2e0195SHeiko Stuebner 	}
1345e2e0195SHeiko Stuebner }
1355e2e0195SHeiko Stuebner 
136721c42a3SThomas Abraham /* register a list of fixed clocks */
samsung_clk_register_fixed_rate(struct samsung_clk_provider * ctx,const struct samsung_fixed_rate_clock * list,unsigned int nr_clk)137976face4SRahul Sharma void __init samsung_clk_register_fixed_rate(struct samsung_clk_provider *ctx,
1384a1caed3SUwe Kleine-König 		const struct samsung_fixed_rate_clock *list,
1394a1caed3SUwe Kleine-König 		unsigned int nr_clk)
140721c42a3SThomas Abraham {
141ecb1f1f7SMarek Szyprowski 	struct clk_hw *clk_hw;
142721c42a3SThomas Abraham 	unsigned int idx, ret;
143721c42a3SThomas Abraham 
144721c42a3SThomas Abraham 	for (idx = 0; idx < nr_clk; idx++, list++) {
145d2f18d7eSMarek Szyprowski 		clk_hw = clk_hw_register_fixed_rate(ctx->dev, list->name,
146721c42a3SThomas Abraham 			list->parent_name, list->flags, list->fixed_rate);
147ecb1f1f7SMarek Szyprowski 		if (IS_ERR(clk_hw)) {
148721c42a3SThomas Abraham 			pr_err("%s: failed to register clock %s\n", __func__,
149721c42a3SThomas Abraham 				list->name);
150721c42a3SThomas Abraham 			continue;
151721c42a3SThomas Abraham 		}
152721c42a3SThomas Abraham 
153ecb1f1f7SMarek Szyprowski 		samsung_clk_add_lookup(ctx, clk_hw, list->id);
154721c42a3SThomas Abraham 
155721c42a3SThomas Abraham 		/*
156721c42a3SThomas Abraham 		 * Unconditionally add a clock lookup for the fixed rate clocks.
157721c42a3SThomas Abraham 		 * There are not many of these on any of Samsung platforms.
158721c42a3SThomas Abraham 		 */
159ecb1f1f7SMarek Szyprowski 		ret = clk_hw_register_clkdev(clk_hw, list->name, NULL);
160721c42a3SThomas Abraham 		if (ret)
161721c42a3SThomas Abraham 			pr_err("%s: failed to register clock lookup for %s",
162721c42a3SThomas Abraham 				__func__, list->name);
163721c42a3SThomas Abraham 	}
164721c42a3SThomas Abraham }
165721c42a3SThomas Abraham 
166721c42a3SThomas Abraham /* register a list of fixed factor clocks */
samsung_clk_register_fixed_factor(struct samsung_clk_provider * ctx,const struct samsung_fixed_factor_clock * list,unsigned int nr_clk)167976face4SRahul Sharma void __init samsung_clk_register_fixed_factor(struct samsung_clk_provider *ctx,
1684a1caed3SUwe Kleine-König 		const struct samsung_fixed_factor_clock *list, unsigned int nr_clk)
169721c42a3SThomas Abraham {
170ecb1f1f7SMarek Szyprowski 	struct clk_hw *clk_hw;
171721c42a3SThomas Abraham 	unsigned int idx;
172721c42a3SThomas Abraham 
173721c42a3SThomas Abraham 	for (idx = 0; idx < nr_clk; idx++, list++) {
174d2f18d7eSMarek Szyprowski 		clk_hw = clk_hw_register_fixed_factor(ctx->dev, list->name,
175721c42a3SThomas Abraham 			list->parent_name, list->flags, list->mult, list->div);
176ecb1f1f7SMarek Szyprowski 		if (IS_ERR(clk_hw)) {
177721c42a3SThomas Abraham 			pr_err("%s: failed to register clock %s\n", __func__,
178721c42a3SThomas Abraham 				list->name);
179721c42a3SThomas Abraham 			continue;
180721c42a3SThomas Abraham 		}
181721c42a3SThomas Abraham 
182ecb1f1f7SMarek Szyprowski 		samsung_clk_add_lookup(ctx, clk_hw, list->id);
183721c42a3SThomas Abraham 	}
184721c42a3SThomas Abraham }
185721c42a3SThomas Abraham 
186721c42a3SThomas Abraham /* register a list of mux clocks */
samsung_clk_register_mux(struct samsung_clk_provider * ctx,const struct samsung_mux_clock * list,unsigned int nr_clk)187976face4SRahul Sharma void __init samsung_clk_register_mux(struct samsung_clk_provider *ctx,
1884a1caed3SUwe Kleine-König 				const struct samsung_mux_clock *list,
189721c42a3SThomas Abraham 				unsigned int nr_clk)
190721c42a3SThomas Abraham {
191ecb1f1f7SMarek Szyprowski 	struct clk_hw *clk_hw;
192a4f21e9cSMarek Szyprowski 	unsigned int idx;
193721c42a3SThomas Abraham 
194721c42a3SThomas Abraham 	for (idx = 0; idx < nr_clk; idx++, list++) {
195d2f18d7eSMarek Szyprowski 		clk_hw = clk_hw_register_mux(ctx->dev, list->name,
196ecb1f1f7SMarek Szyprowski 			list->parent_names, list->num_parents, list->flags,
197976face4SRahul Sharma 			ctx->reg_base + list->offset,
198976face4SRahul Sharma 			list->shift, list->width, list->mux_flags, &ctx->lock);
199ecb1f1f7SMarek Szyprowski 		if (IS_ERR(clk_hw)) {
200721c42a3SThomas Abraham 			pr_err("%s: failed to register clock %s\n", __func__,
201721c42a3SThomas Abraham 				list->name);
202721c42a3SThomas Abraham 			continue;
203721c42a3SThomas Abraham 		}
204721c42a3SThomas Abraham 
205ecb1f1f7SMarek Szyprowski 		samsung_clk_add_lookup(ctx, clk_hw, list->id);
206721c42a3SThomas Abraham 	}
207721c42a3SThomas Abraham }
208721c42a3SThomas Abraham 
209721c42a3SThomas Abraham /* register a list of div clocks */
samsung_clk_register_div(struct samsung_clk_provider * ctx,const struct samsung_div_clock * list,unsigned int nr_clk)210976face4SRahul Sharma void __init samsung_clk_register_div(struct samsung_clk_provider *ctx,
2114a1caed3SUwe Kleine-König 				const struct samsung_div_clock *list,
212721c42a3SThomas Abraham 				unsigned int nr_clk)
213721c42a3SThomas Abraham {
214ecb1f1f7SMarek Szyprowski 	struct clk_hw *clk_hw;
215a4f21e9cSMarek Szyprowski 	unsigned int idx;
216721c42a3SThomas Abraham 
217721c42a3SThomas Abraham 	for (idx = 0; idx < nr_clk; idx++, list++) {
218798ed613SHeiko Stuebner 		if (list->table)
219d2f18d7eSMarek Szyprowski 			clk_hw = clk_hw_register_divider_table(ctx->dev,
220ecb1f1f7SMarek Szyprowski 				list->name, list->parent_name, list->flags,
221976face4SRahul Sharma 				ctx->reg_base + list->offset,
222976face4SRahul Sharma 				list->shift, list->width, list->div_flags,
223976face4SRahul Sharma 				list->table, &ctx->lock);
224798ed613SHeiko Stuebner 		else
225d2f18d7eSMarek Szyprowski 			clk_hw = clk_hw_register_divider(ctx->dev, list->name,
226798ed613SHeiko Stuebner 				list->parent_name, list->flags,
227976face4SRahul Sharma 				ctx->reg_base + list->offset, list->shift,
228976face4SRahul Sharma 				list->width, list->div_flags, &ctx->lock);
229ecb1f1f7SMarek Szyprowski 		if (IS_ERR(clk_hw)) {
230721c42a3SThomas Abraham 			pr_err("%s: failed to register clock %s\n", __func__,
231721c42a3SThomas Abraham 				list->name);
232721c42a3SThomas Abraham 			continue;
233721c42a3SThomas Abraham 		}
234721c42a3SThomas Abraham 
235ecb1f1f7SMarek Szyprowski 		samsung_clk_add_lookup(ctx, clk_hw, list->id);
236721c42a3SThomas Abraham 	}
237721c42a3SThomas Abraham }
238721c42a3SThomas Abraham 
239721c42a3SThomas Abraham /* register a list of gate clocks */
samsung_clk_register_gate(struct samsung_clk_provider * ctx,const struct samsung_gate_clock * list,unsigned int nr_clk)240976face4SRahul Sharma void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx,
2414a1caed3SUwe Kleine-König 				const struct samsung_gate_clock *list,
242721c42a3SThomas Abraham 				unsigned int nr_clk)
243721c42a3SThomas Abraham {
244ecb1f1f7SMarek Szyprowski 	struct clk_hw *clk_hw;
245a4f21e9cSMarek Szyprowski 	unsigned int idx;
246721c42a3SThomas Abraham 
247721c42a3SThomas Abraham 	for (idx = 0; idx < nr_clk; idx++, list++) {
248d2f18d7eSMarek Szyprowski 		clk_hw = clk_hw_register_gate(ctx->dev, list->name, list->parent_name,
249976face4SRahul Sharma 				list->flags, ctx->reg_base + list->offset,
250976face4SRahul Sharma 				list->bit_idx, list->gate_flags, &ctx->lock);
251ecb1f1f7SMarek Szyprowski 		if (IS_ERR(clk_hw)) {
252721c42a3SThomas Abraham 			pr_err("%s: failed to register clock %s\n", __func__,
253721c42a3SThomas Abraham 				list->name);
254721c42a3SThomas Abraham 			continue;
255721c42a3SThomas Abraham 		}
256721c42a3SThomas Abraham 
257ecb1f1f7SMarek Szyprowski 		samsung_clk_add_lookup(ctx, clk_hw, list->id);
258721c42a3SThomas Abraham 	}
259721c42a3SThomas Abraham }
260721c42a3SThomas Abraham 
261721c42a3SThomas Abraham /*
262721c42a3SThomas Abraham  * obtain the clock speed of all external fixed clock sources from device
263721c42a3SThomas Abraham  * tree and register it
264721c42a3SThomas Abraham  */
samsung_clk_of_register_fixed_ext(struct samsung_clk_provider * ctx,struct samsung_fixed_rate_clock * fixed_rate_clk,unsigned int nr_fixed_rate_clk,const struct of_device_id * clk_matches)265976face4SRahul Sharma void __init samsung_clk_of_register_fixed_ext(struct samsung_clk_provider *ctx,
266721c42a3SThomas Abraham 			struct samsung_fixed_rate_clock *fixed_rate_clk,
267721c42a3SThomas Abraham 			unsigned int nr_fixed_rate_clk,
268305cfab0SKrzysztof Kozlowski 			const struct of_device_id *clk_matches)
269721c42a3SThomas Abraham {
270721c42a3SThomas Abraham 	const struct of_device_id *match;
271976face4SRahul Sharma 	struct device_node *clk_np;
272721c42a3SThomas Abraham 	u32 freq;
273721c42a3SThomas Abraham 
274976face4SRahul Sharma 	for_each_matching_node_and_match(clk_np, clk_matches, &match) {
275976face4SRahul Sharma 		if (of_property_read_u32(clk_np, "clock-frequency", &freq))
276721c42a3SThomas Abraham 			continue;
27742fb57c0SPankaj Dubey 		fixed_rate_clk[(unsigned long)match->data].fixed_rate = freq;
278721c42a3SThomas Abraham 	}
279976face4SRahul Sharma 	samsung_clk_register_fixed_rate(ctx, fixed_rate_clk, nr_fixed_rate_clk);
280721c42a3SThomas Abraham }
281721c42a3SThomas Abraham 
28216a9013bSNaveen Krishna Ch #ifdef CONFIG_PM_SLEEP
samsung_clk_suspend(void)28316a9013bSNaveen Krishna Ch static int samsung_clk_suspend(void)
28416a9013bSNaveen Krishna Ch {
28516a9013bSNaveen Krishna Ch 	struct samsung_clock_reg_cache *reg_cache;
28616a9013bSNaveen Krishna Ch 
2878bf27eaaSMarek Szyprowski 	list_for_each_entry(reg_cache, &clock_reg_cache_list, node) {
28816a9013bSNaveen Krishna Ch 		samsung_clk_save(reg_cache->reg_base, reg_cache->rdump,
28916a9013bSNaveen Krishna Ch 				reg_cache->rd_num);
2908bf27eaaSMarek Szyprowski 		samsung_clk_restore(reg_cache->reg_base, reg_cache->rsuspend,
2918bf27eaaSMarek Szyprowski 				reg_cache->rsuspend_num);
2928bf27eaaSMarek Szyprowski 	}
29316a9013bSNaveen Krishna Ch 	return 0;
29416a9013bSNaveen Krishna Ch }
29516a9013bSNaveen Krishna Ch 
samsung_clk_resume(void)29616a9013bSNaveen Krishna Ch static void samsung_clk_resume(void)
29716a9013bSNaveen Krishna Ch {
29816a9013bSNaveen Krishna Ch 	struct samsung_clock_reg_cache *reg_cache;
29916a9013bSNaveen Krishna Ch 
30016a9013bSNaveen Krishna Ch 	list_for_each_entry(reg_cache, &clock_reg_cache_list, node)
30116a9013bSNaveen Krishna Ch 		samsung_clk_restore(reg_cache->reg_base, reg_cache->rdump,
30216a9013bSNaveen Krishna Ch 				reg_cache->rd_num);
30316a9013bSNaveen Krishna Ch }
30416a9013bSNaveen Krishna Ch 
30516a9013bSNaveen Krishna Ch static struct syscore_ops samsung_clk_syscore_ops = {
30616a9013bSNaveen Krishna Ch 	.suspend = samsung_clk_suspend,
30716a9013bSNaveen Krishna Ch 	.resume = samsung_clk_resume,
30816a9013bSNaveen Krishna Ch };
30916a9013bSNaveen Krishna Ch 
samsung_clk_extended_sleep_init(void __iomem * reg_base,const unsigned long * rdump,unsigned long nr_rdump,const struct samsung_clk_reg_dump * rsuspend,unsigned long nr_rsuspend)3108bf27eaaSMarek Szyprowski void samsung_clk_extended_sleep_init(void __iomem *reg_base,
31116a9013bSNaveen Krishna Ch 			const unsigned long *rdump,
3128bf27eaaSMarek Szyprowski 			unsigned long nr_rdump,
3138bf27eaaSMarek Szyprowski 			const struct samsung_clk_reg_dump *rsuspend,
3148bf27eaaSMarek Szyprowski 			unsigned long nr_rsuspend)
31516a9013bSNaveen Krishna Ch {
31616a9013bSNaveen Krishna Ch 	struct samsung_clock_reg_cache *reg_cache;
31716a9013bSNaveen Krishna Ch 
31816a9013bSNaveen Krishna Ch 	reg_cache = kzalloc(sizeof(struct samsung_clock_reg_cache),
31916a9013bSNaveen Krishna Ch 			GFP_KERNEL);
32016a9013bSNaveen Krishna Ch 	if (!reg_cache)
32116a9013bSNaveen Krishna Ch 		panic("could not allocate register reg_cache.\n");
32216a9013bSNaveen Krishna Ch 	reg_cache->rdump = samsung_clk_alloc_reg_dump(rdump, nr_rdump);
32316a9013bSNaveen Krishna Ch 
32416a9013bSNaveen Krishna Ch 	if (!reg_cache->rdump)
32516a9013bSNaveen Krishna Ch 		panic("could not allocate register dump storage.\n");
32616a9013bSNaveen Krishna Ch 
32716a9013bSNaveen Krishna Ch 	if (list_empty(&clock_reg_cache_list))
32816a9013bSNaveen Krishna Ch 		register_syscore_ops(&samsung_clk_syscore_ops);
32916a9013bSNaveen Krishna Ch 
33016a9013bSNaveen Krishna Ch 	reg_cache->reg_base = reg_base;
33116a9013bSNaveen Krishna Ch 	reg_cache->rd_num = nr_rdump;
3328bf27eaaSMarek Szyprowski 	reg_cache->rsuspend = rsuspend;
3338bf27eaaSMarek Szyprowski 	reg_cache->rsuspend_num = nr_rsuspend;
33416a9013bSNaveen Krishna Ch 	list_add_tail(&reg_cache->node, &clock_reg_cache_list);
33516a9013bSNaveen Krishna Ch }
33616a9013bSNaveen Krishna Ch #endif
33716a9013bSNaveen Krishna Ch 
338*bed76f69SSam Protsenko /**
339*bed76f69SSam Protsenko  * samsung_cmu_register_clocks() - Register all clocks provided in CMU object
340*bed76f69SSam Protsenko  * @ctx: Clock provider object
341*bed76f69SSam Protsenko  * @cmu: CMU object with clocks to register
342*bed76f69SSam Protsenko  */
samsung_cmu_register_clocks(struct samsung_clk_provider * ctx,const struct samsung_cmu_info * cmu)343*bed76f69SSam Protsenko void __init samsung_cmu_register_clocks(struct samsung_clk_provider *ctx,
344*bed76f69SSam Protsenko 					const struct samsung_cmu_info *cmu)
345*bed76f69SSam Protsenko {
346*bed76f69SSam Protsenko 	if (cmu->pll_clks)
347*bed76f69SSam Protsenko 		samsung_clk_register_pll(ctx, cmu->pll_clks, cmu->nr_pll_clks);
348*bed76f69SSam Protsenko 	if (cmu->mux_clks)
349*bed76f69SSam Protsenko 		samsung_clk_register_mux(ctx, cmu->mux_clks, cmu->nr_mux_clks);
350*bed76f69SSam Protsenko 	if (cmu->div_clks)
351*bed76f69SSam Protsenko 		samsung_clk_register_div(ctx, cmu->div_clks, cmu->nr_div_clks);
352*bed76f69SSam Protsenko 	if (cmu->gate_clks)
353*bed76f69SSam Protsenko 		samsung_clk_register_gate(ctx, cmu->gate_clks,
354*bed76f69SSam Protsenko 					  cmu->nr_gate_clks);
355*bed76f69SSam Protsenko 	if (cmu->fixed_clks)
356*bed76f69SSam Protsenko 		samsung_clk_register_fixed_rate(ctx, cmu->fixed_clks,
357*bed76f69SSam Protsenko 						cmu->nr_fixed_clks);
358*bed76f69SSam Protsenko 	if (cmu->fixed_factor_clks)
359*bed76f69SSam Protsenko 		samsung_clk_register_fixed_factor(ctx, cmu->fixed_factor_clks,
360*bed76f69SSam Protsenko 						  cmu->nr_fixed_factor_clks);
361*bed76f69SSam Protsenko 	if (cmu->cpu_clks)
362*bed76f69SSam Protsenko 		samsung_clk_register_cpu(ctx, cmu->cpu_clks, cmu->nr_cpu_clks);
363*bed76f69SSam Protsenko }
364*bed76f69SSam Protsenko 
36516a9013bSNaveen Krishna Ch /*
36616a9013bSNaveen Krishna Ch  * Common function which registers plls, muxes, dividers and gates
36716a9013bSNaveen Krishna Ch  * for each CMU. It also add CMU register list to register cache.
36816a9013bSNaveen Krishna Ch  */
samsung_cmu_register_one(struct device_node * np,const struct samsung_cmu_info * cmu)369151d4d35SChanwoo Choi struct samsung_clk_provider * __init samsung_cmu_register_one(
370151d4d35SChanwoo Choi 			struct device_node *np,
3719f92c0baSKrzysztof Kozlowski 			const struct samsung_cmu_info *cmu)
37216a9013bSNaveen Krishna Ch {
37316a9013bSNaveen Krishna Ch 	void __iomem *reg_base;
37416a9013bSNaveen Krishna Ch 	struct samsung_clk_provider *ctx;
37516a9013bSNaveen Krishna Ch 
37616a9013bSNaveen Krishna Ch 	reg_base = of_iomap(np, 0);
377151d4d35SChanwoo Choi 	if (!reg_base) {
37816a9013bSNaveen Krishna Ch 		panic("%s: failed to map registers\n", __func__);
379151d4d35SChanwoo Choi 		return NULL;
380151d4d35SChanwoo Choi 	}
38116a9013bSNaveen Krishna Ch 
382a4c78367SSam Protsenko 	ctx = samsung_clk_init(NULL, reg_base, cmu->nr_clk_ids);
383*bed76f69SSam Protsenko 	samsung_cmu_register_clocks(ctx, cmu);
38416a9013bSNaveen Krishna Ch 
38516a9013bSNaveen Krishna Ch 	if (cmu->clk_regs)
3868bf27eaaSMarek Szyprowski 		samsung_clk_extended_sleep_init(reg_base,
3878bf27eaaSMarek Szyprowski 			cmu->clk_regs, cmu->nr_clk_regs,
3888bf27eaaSMarek Szyprowski 			cmu->suspend_regs, cmu->nr_suspend_regs);
38916a9013bSNaveen Krishna Ch 
39016a9013bSNaveen Krishna Ch 	samsung_clk_of_add_provider(np, ctx);
391151d4d35SChanwoo Choi 
392151d4d35SChanwoo Choi 	return ctx;
39316a9013bSNaveen Krishna Ch }
394