blob: e00f6a040ad57b127cf781e0df61ff16f18f885c [file] [log] [blame]
Brian Swetland600f7cf2008-09-09 11:04:14 -07001/* arch/arm/mach-msm/clock.c
2 *
3 * Copyright (C) 2007 Google, Inc.
Daniel Walker5e96da52010-05-12 13:43:28 -07004 * Copyright (c) 2007-2010, Code Aurora Forum. All rights reserved.
Brian Swetland600f7cf2008-09-09 11:04:14 -07005 *
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.
9 *
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.
14 *
15 */
16
Brian Swetland600f7cf2008-09-09 11:04:14 -070017#include <linux/kernel.h>
Brian Swetland600f7cf2008-09-09 11:04:14 -070018#include <linux/list.h>
19#include <linux/err.h>
Brian Swetland600f7cf2008-09-09 11:04:14 -070020#include <linux/spinlock.h>
Daniel Walker5e96da52010-05-12 13:43:28 -070021#include <linux/pm_qos_params.h>
Brian Swetland600f7cf2008-09-09 11:04:14 -070022
23#include "clock.h"
Brian Swetland600f7cf2008-09-09 11:04:14 -070024
25static DEFINE_MUTEX(clocks_mutex);
26static DEFINE_SPINLOCK(clocks_lock);
27static LIST_HEAD(clocks);
28
29/*
Brian Swetland600f7cf2008-09-09 11:04:14 -070030 * Standard clock functions defined in include/linux/clk.h
31 */
32struct clk *clk_get(struct device *dev, const char *id)
33{
34 struct clk *clk;
35
36 mutex_lock(&clocks_mutex);
37
38 list_for_each_entry(clk, &clocks, list)
39 if (!strcmp(id, clk->name) && clk->dev == dev)
40 goto found_it;
41
42 list_for_each_entry(clk, &clocks, list)
43 if (!strcmp(id, clk->name) && clk->dev == NULL)
44 goto found_it;
45
46 clk = ERR_PTR(-ENOENT);
47found_it:
48 mutex_unlock(&clocks_mutex);
49 return clk;
50}
51EXPORT_SYMBOL(clk_get);
52
53void clk_put(struct clk *clk)
54{
55}
56EXPORT_SYMBOL(clk_put);
57
58int clk_enable(struct clk *clk)
59{
60 unsigned long flags;
61 spin_lock_irqsave(&clocks_lock, flags);
62 clk->count++;
Stephen Boyd437f6292011-01-26 16:20:52 -080063 if (clk->count == 1)
Daniel Walker5e96da52010-05-12 13:43:28 -070064 clk->ops->enable(clk->id);
Brian Swetland600f7cf2008-09-09 11:04:14 -070065 spin_unlock_irqrestore(&clocks_lock, flags);
66 return 0;
67}
68EXPORT_SYMBOL(clk_enable);
69
70void clk_disable(struct clk *clk)
71{
72 unsigned long flags;
73 spin_lock_irqsave(&clocks_lock, flags);
74 BUG_ON(clk->count == 0);
75 clk->count--;
Stephen Boyd437f6292011-01-26 16:20:52 -080076 if (clk->count == 0)
Daniel Walker5e96da52010-05-12 13:43:28 -070077 clk->ops->disable(clk->id);
Brian Swetland600f7cf2008-09-09 11:04:14 -070078 spin_unlock_irqrestore(&clocks_lock, flags);
79}
80EXPORT_SYMBOL(clk_disable);
81
Daniel Walker5e96da52010-05-12 13:43:28 -070082int clk_reset(struct clk *clk, enum clk_reset_action action)
83{
Daniel Walker5e96da52010-05-12 13:43:28 -070084 return clk->ops->reset(clk->remote_id, action);
85}
86EXPORT_SYMBOL(clk_reset);
87
Brian Swetland600f7cf2008-09-09 11:04:14 -070088unsigned long clk_get_rate(struct clk *clk)
89{
Daniel Walker5e96da52010-05-12 13:43:28 -070090 return clk->ops->get_rate(clk->id);
Brian Swetland600f7cf2008-09-09 11:04:14 -070091}
92EXPORT_SYMBOL(clk_get_rate);
93
94int clk_set_rate(struct clk *clk, unsigned long rate)
95{
Daniel Walker3a790bb2010-12-13 14:35:10 -080096 int ret;
97 if (clk->flags & CLKFLAG_MAX) {
98 ret = clk->ops->set_max_rate(clk->id, rate);
99 if (ret)
100 return ret;
101 }
102 if (clk->flags & CLKFLAG_MIN) {
103 ret = clk->ops->set_min_rate(clk->id, rate);
104 if (ret)
105 return ret;
106 }
107
108 if (clk->flags & CLKFLAG_MAX || clk->flags & CLKFLAG_MIN)
109 return ret;
110
Daniel Walker5e96da52010-05-12 13:43:28 -0700111 return clk->ops->set_rate(clk->id, rate);
Brian Swetland600f7cf2008-09-09 11:04:14 -0700112}
113EXPORT_SYMBOL(clk_set_rate);
114
Daniel Walker5e96da52010-05-12 13:43:28 -0700115long clk_round_rate(struct clk *clk, unsigned long rate)
116{
117 return clk->ops->round_rate(clk->id, rate);
118}
119EXPORT_SYMBOL(clk_round_rate);
120
121int clk_set_min_rate(struct clk *clk, unsigned long rate)
122{
123 return clk->ops->set_min_rate(clk->id, rate);
124}
125EXPORT_SYMBOL(clk_set_min_rate);
126
127int clk_set_max_rate(struct clk *clk, unsigned long rate)
128{
129 return clk->ops->set_max_rate(clk->id, rate);
130}
131EXPORT_SYMBOL(clk_set_max_rate);
132
Brian Swetland600f7cf2008-09-09 11:04:14 -0700133int clk_set_parent(struct clk *clk, struct clk *parent)
134{
135 return -ENOSYS;
136}
137EXPORT_SYMBOL(clk_set_parent);
138
139struct clk *clk_get_parent(struct clk *clk)
140{
141 return ERR_PTR(-ENOSYS);
142}
143EXPORT_SYMBOL(clk_get_parent);
144
145int clk_set_flags(struct clk *clk, unsigned long flags)
146{
147 if (clk == NULL || IS_ERR(clk))
148 return -EINVAL;
Daniel Walker5e96da52010-05-12 13:43:28 -0700149 return clk->ops->set_flags(clk->id, flags);
Brian Swetland600f7cf2008-09-09 11:04:14 -0700150}
151EXPORT_SYMBOL(clk_set_flags);
152
Daniel Walker5e96da52010-05-12 13:43:28 -0700153/* EBI1 is the only shared clock that several clients want to vote on as of
154 * this commit. If this changes in the future, then it might be better to
155 * make clk_min_rate handle the voting or make ebi1_clk_set_min_rate more
156 * generic to support different clocks.
157 */
158static struct clk *ebi1_clk;
Brian Swetland600f7cf2008-09-09 11:04:14 -0700159
Daniel Walker5e96da52010-05-12 13:43:28 -0700160void __init msm_clock_init(struct clk *clock_tbl, unsigned num_clocks)
Brian Swetland600f7cf2008-09-09 11:04:14 -0700161{
162 unsigned n;
163
Brian Swetland600f7cf2008-09-09 11:04:14 -0700164 mutex_lock(&clocks_mutex);
Stephen Boyd2a522202011-02-23 09:37:41 -0800165 for (n = 0; n < num_clocks; n++)
Matt Wagantalld64560fe2011-01-26 16:20:54 -0800166 list_add_tail(&clock_tbl[n].list, &clocks);
Brian Swetland600f7cf2008-09-09 11:04:14 -0700167 mutex_unlock(&clocks_mutex);
Daniel Walker5e96da52010-05-12 13:43:28 -0700168
169 ebi1_clk = clk_get(NULL, "ebi1_clk");
170 BUG_ON(ebi1_clk == NULL);
171
Brian Swetland600f7cf2008-09-09 11:04:14 -0700172}
173
174/* The bootloader and/or AMSS may have left various clocks enabled.
175 * Disable any clocks that belong to us (CLKFLAG_AUTO_OFF) but have
176 * not been explicitly enabled by a clk_enable() call.
177 */
178static int __init clock_late_init(void)
179{
180 unsigned long flags;
181 struct clk *clk;
182 unsigned count = 0;
183
Matt Wagantalld64560fe2011-01-26 16:20:54 -0800184 clock_debug_init();
Brian Swetland600f7cf2008-09-09 11:04:14 -0700185 mutex_lock(&clocks_mutex);
186 list_for_each_entry(clk, &clocks, list) {
Matt Wagantalld64560fe2011-01-26 16:20:54 -0800187 clock_debug_add(clk);
Brian Swetland600f7cf2008-09-09 11:04:14 -0700188 if (clk->flags & CLKFLAG_AUTO_OFF) {
189 spin_lock_irqsave(&clocks_lock, flags);
190 if (!clk->count) {
191 count++;
Daniel Walker5e96da52010-05-12 13:43:28 -0700192 clk->ops->auto_off(clk->id);
Brian Swetland600f7cf2008-09-09 11:04:14 -0700193 }
194 spin_unlock_irqrestore(&clocks_lock, flags);
195 }
196 }
197 mutex_unlock(&clocks_mutex);
198 pr_info("clock_late_init() disabled %d unused clocks\n", count);
199 return 0;
200}
201
202late_initcall(clock_late_init);
Daniel Walker5e96da52010-05-12 13:43:28 -0700203