]>
Commit | Line | Data |
---|---|---|
da15797e HK |
1 | /* |
2 | * Clock framework for Telechips SoCs | |
3 | * Based on arch/arm/plat-mxc/clock.c | |
4 | * | |
5 | * Copyright (C) 2004 - 2005 Nokia corporation | |
6 | * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> | |
7 | * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com> | |
8 | * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. | |
9 | * Copyright 2008 Juergen Beisert, kernel@pengutronix.de | |
10 | * Copyright 2010 Hans J. Koch, hjk@linutronix.de | |
11 | * | |
12 | * Licensed under the terms of the GPL v2. | |
13 | */ | |
14 | ||
15 | #include <linux/clk.h> | |
16 | #include <linux/err.h> | |
17 | #include <linux/errno.h> | |
18 | #include <linux/module.h> | |
19 | #include <linux/mutex.h> | |
20 | #include <linux/string.h> | |
21 | ||
22 | #include <mach/clock.h> | |
23 | #include <mach/hardware.h> | |
24 | ||
25 | static DEFINE_MUTEX(clocks_mutex); | |
26 | ||
27 | /*------------------------------------------------------------------------- | |
28 | * Standard clock functions defined in include/linux/clk.h | |
29 | *-------------------------------------------------------------------------*/ | |
30 | ||
31 | static void __clk_disable(struct clk *clk) | |
32 | { | |
33 | BUG_ON(clk->refcount == 0); | |
34 | ||
35 | if (!(--clk->refcount) && clk->disable) { | |
36 | /* Unconditionally disable the clock in hardware */ | |
37 | clk->disable(clk); | |
38 | /* recursively disable parents */ | |
39 | if (clk->parent) | |
40 | __clk_disable(clk->parent); | |
41 | } | |
42 | } | |
43 | ||
44 | static int __clk_enable(struct clk *clk) | |
45 | { | |
46 | int ret = 0; | |
47 | ||
48 | if (clk->refcount++ == 0 && clk->enable) { | |
49 | if (clk->parent) | |
50 | ret = __clk_enable(clk->parent); | |
51 | if (ret) | |
52 | return ret; | |
53 | else | |
54 | return clk->enable(clk); | |
55 | } | |
56 | ||
57 | return 0; | |
58 | } | |
59 | ||
60 | /* This function increments the reference count on the clock and enables the | |
61 | * clock if not already enabled. The parent clock tree is recursively enabled | |
62 | */ | |
63 | int clk_enable(struct clk *clk) | |
64 | { | |
65 | int ret = 0; | |
66 | ||
67 | if (!clk) | |
68 | return -EINVAL; | |
69 | ||
70 | mutex_lock(&clocks_mutex); | |
71 | ret = __clk_enable(clk); | |
72 | mutex_unlock(&clocks_mutex); | |
73 | ||
74 | return ret; | |
75 | } | |
76 | EXPORT_SYMBOL_GPL(clk_enable); | |
77 | ||
78 | /* This function decrements the reference count on the clock and disables | |
79 | * the clock when reference count is 0. The parent clock tree is | |
80 | * recursively disabled | |
81 | */ | |
82 | void clk_disable(struct clk *clk) | |
83 | { | |
84 | if (!clk) | |
85 | return; | |
86 | ||
87 | mutex_lock(&clocks_mutex); | |
88 | __clk_disable(clk); | |
89 | mutex_unlock(&clocks_mutex); | |
90 | } | |
91 | EXPORT_SYMBOL_GPL(clk_disable); | |
92 | ||
93 | /* Retrieve the *current* clock rate. If the clock itself | |
94 | * does not provide a special calculation routine, ask | |
95 | * its parent and so on, until one is able to return | |
96 | * a valid clock rate | |
97 | */ | |
98 | unsigned long clk_get_rate(struct clk *clk) | |
99 | { | |
100 | if (!clk) | |
101 | return 0UL; | |
102 | ||
103 | if (clk->get_rate) | |
104 | return clk->get_rate(clk); | |
105 | ||
106 | return clk_get_rate(clk->parent); | |
107 | } | |
108 | EXPORT_SYMBOL_GPL(clk_get_rate); | |
109 | ||
110 | /* Round the requested clock rate to the nearest supported | |
111 | * rate that is less than or equal to the requested rate. | |
112 | * This is dependent on the clock's current parent. | |
113 | */ | |
114 | long clk_round_rate(struct clk *clk, unsigned long rate) | |
115 | { | |
116 | if (!clk) | |
117 | return 0; | |
118 | if (!clk->round_rate) | |
119 | return 0; | |
120 | ||
121 | return clk->round_rate(clk, rate); | |
122 | } | |
123 | EXPORT_SYMBOL_GPL(clk_round_rate); | |
124 | ||
125 | /* Set the clock to the requested clock rate. The rate must | |
126 | * match a supported rate exactly based on what clk_round_rate returns | |
127 | */ | |
128 | int clk_set_rate(struct clk *clk, unsigned long rate) | |
129 | { | |
130 | int ret = -EINVAL; | |
131 | ||
132 | if (!clk) | |
133 | return ret; | |
134 | if (!clk->set_rate || !rate) | |
135 | return ret; | |
136 | ||
137 | mutex_lock(&clocks_mutex); | |
138 | ret = clk->set_rate(clk, rate); | |
139 | mutex_unlock(&clocks_mutex); | |
140 | ||
141 | return ret; | |
142 | } | |
143 | EXPORT_SYMBOL_GPL(clk_set_rate); | |
144 | ||
145 | /* Set the clock's parent to another clock source */ | |
146 | int clk_set_parent(struct clk *clk, struct clk *parent) | |
147 | { | |
148 | struct clk *old; | |
149 | int ret = -EINVAL; | |
150 | ||
151 | if (!clk) | |
152 | return ret; | |
153 | if (!clk->set_parent || !parent) | |
154 | return ret; | |
155 | ||
156 | mutex_lock(&clocks_mutex); | |
157 | old = clk->parent; | |
158 | if (clk->refcount) | |
159 | __clk_enable(parent); | |
160 | ret = clk->set_parent(clk, parent); | |
161 | if (ret) | |
162 | old = parent; | |
163 | if (clk->refcount) | |
164 | __clk_disable(old); | |
165 | mutex_unlock(&clocks_mutex); | |
166 | ||
167 | return ret; | |
168 | } | |
169 | EXPORT_SYMBOL_GPL(clk_set_parent); | |
170 | ||
171 | /* Retrieve the clock's parent clock source */ | |
172 | struct clk *clk_get_parent(struct clk *clk) | |
173 | { | |
174 | if (!clk) | |
175 | return NULL; | |
176 | ||
177 | return clk->parent; | |
178 | } | |
179 | EXPORT_SYMBOL_GPL(clk_get_parent); |