blob: 79fe662376afbdb2d711aa36fe92d57d9464fe53 [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
Matt Wagantall9de3bfb2011-11-03 20:13:12 -070077static int pc_clk_set_rate(struct clk *clk, unsigned long 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 */
Matt Wagantall9de3bfb2011-11-03 20:13:12 -070083 unsigned r = rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070084 int id = to_pcom_clk(clk)->id;
Matt Wagantall9de3bfb2011-11-03 20:13:12 -070085 int rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_RATE, &id, &r);
Daniel Walker5e96da52010-05-12 13:43:28 -070086 if (rc < 0)
87 return rc;
88 else
89 return (int)id < 0 ? -EINVAL : 0;
90}
91
Matt Wagantall9de3bfb2011-11-03 20:13:12 -070092static int pc_clk_set_min_rate(struct clk *clk, unsigned long rate)
Daniel Walker5e96da52010-05-12 13:43:28 -070093{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070094 int rc;
95 int id = to_pcom_clk(clk)->id;
96 bool ignore_error = (cpu_is_msm7x27() && id == P_EBI1_CLK &&
97 rate >= INT_MAX);
Matt Wagantall9de3bfb2011-11-03 20:13:12 -070098 unsigned r = rate;
99 rc = msm_proc_comm(PCOM_CLKCTL_RPC_MIN_RATE, &id, &r);
Daniel Walker5e96da52010-05-12 13:43:28 -0700100 if (rc < 0)
101 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700102 else if (ignore_error)
103 return 0;
Daniel Walker5e96da52010-05-12 13:43:28 -0700104 else
105 return (int)id < 0 ? -EINVAL : 0;
106}
107
Matt Wagantall9de3bfb2011-11-03 20:13:12 -0700108static int pc_clk_set_max_rate(struct clk *clk, unsigned long rate)
Daniel Walker5e96da52010-05-12 13:43:28 -0700109{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700110 int id = to_pcom_clk(clk)->id;
Matt Wagantall9de3bfb2011-11-03 20:13:12 -0700111 unsigned r = rate;
112 int rc = msm_proc_comm(PCOM_CLKCTL_RPC_MAX_RATE, &id, &r);
Daniel Walker5e96da52010-05-12 13:43:28 -0700113 if (rc < 0)
114 return rc;
115 else
116 return (int)id < 0 ? -EINVAL : 0;
117}
118
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700119static int pc_clk_set_flags(struct clk *clk, unsigned flags)
Daniel Walker5e96da52010-05-12 13:43:28 -0700120{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700121 int id = to_pcom_clk(clk)->id;
Daniel Walker5e96da52010-05-12 13:43:28 -0700122 int rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_FLAGS, &id, &flags);
123 if (rc < 0)
124 return rc;
125 else
126 return (int)id < 0 ? -EINVAL : 0;
127}
128
Matt Wagantall9de3bfb2011-11-03 20:13:12 -0700129static int pc_clk_set_ext_config(struct clk *clk, unsigned long config)
Daniel Walker5e96da52010-05-12 13:43:28 -0700130{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131 int id = to_pcom_clk(clk)->id;
Matt Wagantall9de3bfb2011-11-03 20:13:12 -0700132 unsigned c = config;
133 int rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_EXT_CONFIG, &id, &c);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700134 if (rc < 0)
135 return rc;
136 else
137 return (int)id < 0 ? -EINVAL : 0;
138}
139
Matt Wagantall9de3bfb2011-11-03 20:13:12 -0700140static unsigned long pc_clk_get_rate(struct clk *clk)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700141{
142 int id = to_pcom_clk(clk)->id;
Daniel Walker5e96da52010-05-12 13:43:28 -0700143 if (msm_proc_comm(PCOM_CLKCTL_RPC_RATE, &id, NULL))
144 return 0;
145 else
146 return id;
147}
148
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149static int pc_clk_is_enabled(struct clk *clk)
Daniel Walker5e96da52010-05-12 13:43:28 -0700150{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700151 int id = to_pcom_clk(clk)->id;
Daniel Walker5e96da52010-05-12 13:43:28 -0700152 if (msm_proc_comm(PCOM_CLKCTL_RPC_ENABLED, &id, NULL))
153 return 0;
154 else
155 return id;
156}
157
Matt Wagantall9de3bfb2011-11-03 20:13:12 -0700158static long pc_clk_round_rate(struct clk *clk, unsigned long rate)
Daniel Walker5e96da52010-05-12 13:43:28 -0700159{
160
161 /* Not really supported; pc_clk_set_rate() does rounding on it's own. */
162 return rate;
163}
164
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700165static bool pc_clk_is_local(struct clk *clk)
Stephen Boyd2a522202011-02-23 09:37:41 -0800166{
167 return false;
168}
169
Daniel Walker5e96da52010-05-12 13:43:28 -0700170struct clk_ops clk_ops_pcom = {
171 .enable = pc_clk_enable,
172 .disable = pc_clk_disable,
173 .auto_off = pc_clk_disable,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700174 .reset = pc_reset,
Daniel Walker5e96da52010-05-12 13:43:28 -0700175 .set_rate = pc_clk_set_rate,
176 .set_min_rate = pc_clk_set_min_rate,
177 .set_max_rate = pc_clk_set_max_rate,
178 .set_flags = pc_clk_set_flags,
179 .get_rate = pc_clk_get_rate,
180 .is_enabled = pc_clk_is_enabled,
181 .round_rate = pc_clk_round_rate,
Stephen Boyd2a522202011-02-23 09:37:41 -0800182 .is_local = pc_clk_is_local,
Daniel Walker5e96da52010-05-12 13:43:28 -0700183};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700184
185struct clk_ops clk_ops_pcom_ext_config = {
186 .enable = pc_clk_enable,
187 .disable = pc_clk_disable,
188 .auto_off = pc_clk_disable,
189 .reset = pc_reset,
190 .set_rate = pc_clk_set_ext_config,
191 .set_min_rate = pc_clk_set_min_rate,
192 .set_max_rate = pc_clk_set_max_rate,
193 .set_flags = pc_clk_set_flags,
194 .get_rate = pc_clk_get_rate,
195 .is_enabled = pc_clk_is_enabled,
196 .round_rate = pc_clk_round_rate,
197 .is_local = pc_clk_is_local,
198};
199