1 /* arch/arm/mach-msm/clock.c
3 * Copyright (C) 2007 Google, Inc.
4 * Copyright (c) 2007 QUALCOMM Incorporated
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
17 #include <linux/version.h>
18 #include <linux/kernel.h>
19 #include <linux/init.h>
20 #include <linux/module.h>
21 #include <linux/list.h>
22 #include <linux/err.h>
23 #include <linux/clk.h>
24 #include <linux/spinlock.h>
27 #include "proc_comm.h"
29 static DEFINE_MUTEX(clocks_mutex
);
30 static DEFINE_SPINLOCK(clocks_lock
);
31 static LIST_HEAD(clocks
);
34 * glue for the proc_comm interface
36 static inline int pc_clk_enable(unsigned id
)
38 return msm_proc_comm(PCOM_CLKCTL_RPC_ENABLE
, &id
, NULL
);
41 static inline void pc_clk_disable(unsigned id
)
43 msm_proc_comm(PCOM_CLKCTL_RPC_DISABLE
, &id
, NULL
);
46 static inline int pc_clk_set_rate(unsigned id
, unsigned rate
)
48 return msm_proc_comm(PCOM_CLKCTL_RPC_SET_RATE
, &id
, &rate
);
51 static inline int pc_clk_set_min_rate(unsigned id
, unsigned rate
)
53 return msm_proc_comm(PCOM_CLKCTL_RPC_MIN_RATE
, &id
, &rate
);
56 static inline int pc_clk_set_max_rate(unsigned id
, unsigned rate
)
58 return msm_proc_comm(PCOM_CLKCTL_RPC_MAX_RATE
, &id
, &rate
);
61 static inline int pc_clk_set_flags(unsigned id
, unsigned flags
)
63 return msm_proc_comm(PCOM_CLKCTL_RPC_SET_FLAGS
, &id
, &flags
);
66 static inline unsigned pc_clk_get_rate(unsigned id
)
68 if (msm_proc_comm(PCOM_CLKCTL_RPC_RATE
, &id
, NULL
))
74 static inline unsigned pc_clk_is_enabled(unsigned id
)
76 if (msm_proc_comm(PCOM_CLKCTL_RPC_ENABLED
, &id
, NULL
))
82 static inline int pc_pll_request(unsigned id
, unsigned on
)
85 return msm_proc_comm(PCOM_CLKCTL_RPC_PLL_REQUEST
, &id
, &on
);
89 * Standard clock functions defined in include/linux/clk.h
91 struct clk
*clk_get(struct device
*dev
, const char *id
)
95 mutex_lock(&clocks_mutex
);
97 list_for_each_entry(clk
, &clocks
, list
)
98 if (!strcmp(id
, clk
->name
) && clk
->dev
== dev
)
101 list_for_each_entry(clk
, &clocks
, list
)
102 if (!strcmp(id
, clk
->name
) && clk
->dev
== NULL
)
105 clk
= ERR_PTR(-ENOENT
);
107 mutex_unlock(&clocks_mutex
);
110 EXPORT_SYMBOL(clk_get
);
112 void clk_put(struct clk
*clk
)
115 EXPORT_SYMBOL(clk_put
);
117 int clk_enable(struct clk
*clk
)
120 spin_lock_irqsave(&clocks_lock
, flags
);
123 pc_clk_enable(clk
->id
);
124 spin_unlock_irqrestore(&clocks_lock
, flags
);
127 EXPORT_SYMBOL(clk_enable
);
129 void clk_disable(struct clk
*clk
)
132 spin_lock_irqsave(&clocks_lock
, flags
);
133 BUG_ON(clk
->count
== 0);
136 pc_clk_disable(clk
->id
);
137 spin_unlock_irqrestore(&clocks_lock
, flags
);
139 EXPORT_SYMBOL(clk_disable
);
141 unsigned long clk_get_rate(struct clk
*clk
)
143 return pc_clk_get_rate(clk
->id
);
145 EXPORT_SYMBOL(clk_get_rate
);
147 int clk_set_rate(struct clk
*clk
, unsigned long rate
)
150 if (clk
->flags
& CLKFLAG_USE_MIN_MAX_TO_SET
) {
151 ret
= pc_clk_set_max_rate(clk
->id
, rate
);
154 return pc_clk_set_min_rate(clk
->id
, rate
);
156 return pc_clk_set_rate(clk
->id
, rate
);
158 EXPORT_SYMBOL(clk_set_rate
);
160 int clk_set_parent(struct clk
*clk
, struct clk
*parent
)
164 EXPORT_SYMBOL(clk_set_parent
);
166 struct clk
*clk_get_parent(struct clk
*clk
)
168 return ERR_PTR(-ENOSYS
);
170 EXPORT_SYMBOL(clk_get_parent
);
172 int clk_set_flags(struct clk
*clk
, unsigned long flags
)
174 if (clk
== NULL
|| IS_ERR(clk
))
176 return pc_clk_set_flags(clk
->id
, flags
);
178 EXPORT_SYMBOL(clk_set_flags
);
181 void __init
msm_clock_init(void)
185 spin_lock_init(&clocks_lock
);
186 mutex_lock(&clocks_mutex
);
187 for (n
= 0; n
< msm_num_clocks
; n
++)
188 list_add_tail(&msm_clocks
[n
].list
, &clocks
);
189 mutex_unlock(&clocks_mutex
);
192 /* The bootloader and/or AMSS may have left various clocks enabled.
193 * Disable any clocks that belong to us (CLKFLAG_AUTO_OFF) but have
194 * not been explicitly enabled by a clk_enable() call.
196 static int __init
clock_late_init(void)
202 mutex_lock(&clocks_mutex
);
203 list_for_each_entry(clk
, &clocks
, list
) {
204 if (clk
->flags
& CLKFLAG_AUTO_OFF
) {
205 spin_lock_irqsave(&clocks_lock
, flags
);
208 pc_clk_disable(clk
->id
);
210 spin_unlock_irqrestore(&clocks_lock
, flags
);
213 mutex_unlock(&clocks_mutex
);
214 pr_info("clock_late_init() disabled %d unused clocks\n", count
);
218 late_initcall(clock_late_init
);