blob: f7f3666616e29e39c2f75827d61e4c384588c741 [file] [log] [blame]
Daniel Walker5e96da52010-05-12 13:43:28 -07001/*
2 * Copyright (C) 2007 Google, Inc.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003 * Copyright (c) 2007-2011, Code Aurora Forum. All rights reserved.
Daniel Walker5e96da52010-05-12 13:43:28 -07004 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070016#include <linux/kernel.h>
Daniel Walker5e96da52010-05-12 13:43:28 -070017#include <linux/err.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070018
Daniel Walker5e96da52010-05-12 13:43:28 -070019#include <mach/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070020#include <mach/socinfo.h>
Daniel Walker5e96da52010-05-12 13:43:28 -070021
22#include "proc_comm.h"
23#include "clock.h"
Stephen Boydce1c80f2011-01-26 16:20:53 -080024#include "clock-pcom.h"
Daniel Walker5e96da52010-05-12 13:43:28 -070025
26/*
27 * glue for the proc_comm interface
28 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070029static int pc_clk_enable(struct clk *clk)
Daniel Walker5e96da52010-05-12 13:43:28 -070030{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070031 int rc;
32 int id = to_pcom_clk(clk)->id;
33
34 /* Ignore clocks that are always on */
35 if (id == P_EBI1_CLK || id == P_EBI1_FIXED_CLK)
36 return 0;
37
38 rc = msm_proc_comm(PCOM_CLKCTL_RPC_ENABLE, &id, NULL);
Daniel Walker5e96da52010-05-12 13:43:28 -070039 if (rc < 0)
40 return rc;
41 else
42 return (int)id < 0 ? -EINVAL : 0;
43}
44
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070045static void pc_clk_disable(struct clk *clk)
Daniel Walker5e96da52010-05-12 13:43:28 -070046{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070047 int id = to_pcom_clk(clk)->id;
48
49 /* Ignore clocks that are always on */
50 if (id == P_EBI1_CLK || id == P_EBI1_FIXED_CLK)
51 return;
52
Daniel Walker5e96da52010-05-12 13:43:28 -070053 msm_proc_comm(PCOM_CLKCTL_RPC_DISABLE, &id, NULL);
54}
55
56int pc_clk_reset(unsigned id, enum clk_reset_action action)
57{
58 int rc;
59
60 if (action == CLK_RESET_ASSERT)
61 rc = msm_proc_comm(PCOM_CLKCTL_RPC_RESET_ASSERT, &id, NULL);
62 else
63 rc = msm_proc_comm(PCOM_CLKCTL_RPC_RESET_DEASSERT, &id, NULL);
64
65 if (rc < 0)
66 return rc;
67 else
68 return (int)id < 0 ? -EINVAL : 0;
69}
70
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071static int pc_reset(struct clk *clk, enum clk_reset_action action)
72{
73 int id = to_pcom_clk(clk)->id;
74 return pc_clk_reset(id, action);
75}
76
77static int pc_clk_set_rate(struct clk *clk, unsigned rate)
Daniel Walker5e96da52010-05-12 13:43:28 -070078{
79 /* The rate _might_ be rounded off to the nearest KHz value by the
80 * remote function. So a return value of 0 doesn't necessarily mean
81 * that the exact rate was set successfully.
82 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070083 int id = to_pcom_clk(clk)->id;
Daniel Walker5e96da52010-05-12 13:43:28 -070084 int rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_RATE, &id, &rate);
85 if (rc < 0)
86 return rc;
87 else
88 return (int)id < 0 ? -EINVAL : 0;
89}
90
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091static int pc_clk_set_min_rate(struct clk *clk, unsigned rate)
Daniel Walker5e96da52010-05-12 13:43:28 -070092{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070093 int rc;
94 int id = to_pcom_clk(clk)->id;
95 bool ignore_error = (cpu_is_msm7x27() && id == P_EBI1_CLK &&
96 rate >= INT_MAX);
97
98 rc = msm_proc_comm(PCOM_CLKCTL_RPC_MIN_RATE, &id, &rate);
Daniel Walker5e96da52010-05-12 13:43:28 -070099 if (rc < 0)
100 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700101 else if (ignore_error)
102 return 0;
Daniel Walker5e96da52010-05-12 13:43:28 -0700103 else
104 return (int)id < 0 ? -EINVAL : 0;
105}
106
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700107static int pc_clk_set_max_rate(struct clk *clk, unsigned rate)
Daniel Walker5e96da52010-05-12 13:43:28 -0700108{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109 int id = to_pcom_clk(clk)->id;
Daniel Walker5e96da52010-05-12 13:43:28 -0700110 int rc = msm_proc_comm(PCOM_CLKCTL_RPC_MAX_RATE, &id, &rate);
111 if (rc < 0)
112 return rc;
113 else
114 return (int)id < 0 ? -EINVAL : 0;
115}
116
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700117static int pc_clk_set_flags(struct clk *clk, unsigned flags)
Daniel Walker5e96da52010-05-12 13:43:28 -0700118{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700119 int id = to_pcom_clk(clk)->id;
Daniel Walker5e96da52010-05-12 13:43:28 -0700120 int rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_FLAGS, &id, &flags);
121 if (rc < 0)
122 return rc;
123 else
124 return (int)id < 0 ? -EINVAL : 0;
125}
126
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700127static int pc_clk_set_ext_config(struct clk *clk, unsigned config)
Daniel Walker5e96da52010-05-12 13:43:28 -0700128{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700129 int id = to_pcom_clk(clk)->id;
130 int rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_EXT_CONFIG, &id, &config);
131 if (rc < 0)
132 return rc;
133 else
134 return (int)id < 0 ? -EINVAL : 0;
135}
136
137static unsigned pc_clk_get_rate(struct clk *clk)
138{
139 int id = to_pcom_clk(clk)->id;
Daniel Walker5e96da52010-05-12 13:43:28 -0700140 if (msm_proc_comm(PCOM_CLKCTL_RPC_RATE, &id, NULL))
141 return 0;
142 else
143 return id;
144}
145
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700146static int pc_clk_is_enabled(struct clk *clk)
Daniel Walker5e96da52010-05-12 13:43:28 -0700147{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148 int id = to_pcom_clk(clk)->id;
Daniel Walker5e96da52010-05-12 13:43:28 -0700149 if (msm_proc_comm(PCOM_CLKCTL_RPC_ENABLED, &id, NULL))
150 return 0;
151 else
152 return id;
153}
154
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700155static long pc_clk_round_rate(struct clk *clk, unsigned rate)
Daniel Walker5e96da52010-05-12 13:43:28 -0700156{
157
158 /* Not really supported; pc_clk_set_rate() does rounding on it's own. */
159 return rate;
160}
161
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700162static bool pc_clk_is_local(struct clk *clk)
Stephen Boyd2a522202011-02-23 09:37:41 -0800163{
164 return false;
165}
166
Daniel Walker5e96da52010-05-12 13:43:28 -0700167struct clk_ops clk_ops_pcom = {
168 .enable = pc_clk_enable,
169 .disable = pc_clk_disable,
170 .auto_off = pc_clk_disable,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700171 .reset = pc_reset,
Daniel Walker5e96da52010-05-12 13:43:28 -0700172 .set_rate = pc_clk_set_rate,
173 .set_min_rate = pc_clk_set_min_rate,
174 .set_max_rate = pc_clk_set_max_rate,
175 .set_flags = pc_clk_set_flags,
176 .get_rate = pc_clk_get_rate,
177 .is_enabled = pc_clk_is_enabled,
178 .round_rate = pc_clk_round_rate,
Stephen Boyd2a522202011-02-23 09:37:41 -0800179 .is_local = pc_clk_is_local,
Daniel Walker5e96da52010-05-12 13:43:28 -0700180};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700181
182struct clk_ops clk_ops_pcom_ext_config = {
183 .enable = pc_clk_enable,
184 .disable = pc_clk_disable,
185 .auto_off = pc_clk_disable,
186 .reset = pc_reset,
187 .set_rate = pc_clk_set_ext_config,
188 .set_min_rate = pc_clk_set_min_rate,
189 .set_max_rate = pc_clk_set_max_rate,
190 .set_flags = pc_clk_set_flags,
191 .get_rate = pc_clk_get_rate,
192 .is_enabled = pc_clk_is_enabled,
193 .round_rate = pc_clk_round_rate,
194 .is_local = pc_clk_is_local,
195};
196