blob: 5c10463f155c24ede919d1e43b4fecef6f636e11 [file] [log] [blame]
Matt Wagantall1a7ee892012-01-17 18:56:28 -08001/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
Matt Wagantallb82a5132011-12-12 22:26:41 -080013#define pr_fmt(fmt) "%s: " fmt, __func__
14
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070015#include <linux/kernel.h>
16#include <linux/io.h>
17#include <linux/delay.h>
18#include <linux/platform_device.h>
19#include <linux/err.h>
20#include <linux/regulator/driver.h>
21#include <linux/regulator/machine.h>
22#include <linux/clk.h>
23#include <mach/msm_iomap.h>
24#include <mach/msm_bus_board.h>
25#include <mach/msm_bus.h>
26#include <mach/scm-io.h>
Matt Wagantallb82a5132011-12-12 22:26:41 -080027#include <mach/socinfo.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070028#include "clock.h"
29#include "footswitch.h"
30
31#ifdef CONFIG_MSM_SECURE_IO
32#undef readl_relaxed
33#undef writel_relaxed
34#define readl_relaxed secure_readl
35#define writel_relaxed secure_writel
36#endif
37
38#define REG(off) (MSM_MMSS_CLK_CTL_BASE + (off))
39#define GEMINI_GFS_CTL_REG REG(0x01A0)
40#define GFX2D0_GFS_CTL_REG REG(0x0180)
41#define GFX2D1_GFS_CTL_REG REG(0x0184)
42#define GFX3D_GFS_CTL_REG REG(0x0188)
43#define MDP_GFS_CTL_REG REG(0x0190)
44#define ROT_GFS_CTL_REG REG(0x018C)
45#define VED_GFS_CTL_REG REG(0x0194)
46#define VFE_GFS_CTL_REG REG(0x0198)
47#define VPE_GFS_CTL_REG REG(0x019C)
Matt Wagantall37f34b32011-08-23 18:14:47 -070048#define VCAP_GFS_CTL_REG REG(0x0254)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070049
50#define CLAMP_BIT BIT(5)
51#define ENABLE_BIT BIT(8)
52#define RETENTION_BIT BIT(9)
53
54#define RESET_DELAY_US 1
Matt Wagantallb82a5132011-12-12 22:26:41 -080055/* Clock rate to use if one has not previously been set. */
56#define DEFAULT_RATE 27000000
57#define MAX_CLKS 10
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070058
59/*
60 * Lock is only needed to protect against the first footswitch_enable()
61 * call occuring concurrently with late_footswitch_init().
62 */
63static DEFINE_MUTEX(claim_lock);
64
Matt Wagantallb82a5132011-12-12 22:26:41 -080065struct clk_data {
66 const char *name;
67 struct clk *clk;
68 unsigned long rate;
69 unsigned long reset_rate;
70 bool enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071};
72
73struct footswitch {
74 struct regulator_dev *rdev;
75 struct regulator_desc desc;
76 void *gfs_ctl_reg;
Matt Wagantallb82a5132011-12-12 22:26:41 -080077 int bus_port0, bus_port1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070078 bool is_enabled;
79 bool is_claimed;
Matt Wagantallb82a5132011-12-12 22:26:41 -080080 struct clk_data *clk_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070081 struct clk *core_clk;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070082 unsigned int gfs_delay_cnt:5;
83};
84
85static int setup_clocks(struct footswitch *fs)
86{
87 int rc = 0;
Matt Wagantallb82a5132011-12-12 22:26:41 -080088 struct clk_data *clock;
89 long rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070090
91 /*
Matt Wagantallb82a5132011-12-12 22:26:41 -080092 * Enable all clocks in the power domain. If a specific clock rate is
93 * required for reset timing, set that rate before enabling the clocks.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070094 */
Matt Wagantallb82a5132011-12-12 22:26:41 -080095 for (clock = fs->clk_data; clock->clk; clock++) {
96 clock->rate = clk_get_rate(clock->clk);
97 if (!clock->rate || clock->reset_rate) {
98 rate = clock->reset_rate ?
99 clock->reset_rate : DEFAULT_RATE;
100 rc = clk_set_rate(clock->clk, rate);
101 if (rc && rc != -ENOSYS) {
102 pr_err("Failed to set %s rate to %lu Hz.\n",
103 clock->name, clock->rate);
104 for (clock--; clock >= fs->clk_data; clock--) {
105 if (clock->enabled)
Matt Wagantall1a7ee892012-01-17 18:56:28 -0800106 clk_disable_unprepare(
107 clock->clk);
Matt Wagantallb82a5132011-12-12 22:26:41 -0800108 clk_set_rate(clock->clk, clock->rate);
109 }
110 return rc;
111 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700112 }
Matt Wagantallb82a5132011-12-12 22:26:41 -0800113 /*
114 * Some clocks are for reset purposes only. These clocks will
115 * fail to enable. Ignore the failures but keep track of them so
116 * we don't try to disable them later and crash due to
117 * unbalanced calls.
118 */
Matt Wagantall1a7ee892012-01-17 18:56:28 -0800119 clock->enabled = !clk_prepare_enable(clock->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700120 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700121
Matt Wagantallb82a5132011-12-12 22:26:41 -0800122 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700123}
124
125static void restore_clocks(struct footswitch *fs)
126{
Matt Wagantallb82a5132011-12-12 22:26:41 -0800127 struct clk_data *clock;
128
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700129 /* Restore clocks to their orignal states before setup_clocks(). */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800130 for (clock = fs->clk_data; clock->clk; clock++) {
131 if (clock->enabled)
Matt Wagantall1a7ee892012-01-17 18:56:28 -0800132 clk_disable_unprepare(clock->clk);
Matt Wagantallb82a5132011-12-12 22:26:41 -0800133 if (clock->rate && clk_set_rate(clock->clk, clock->rate))
134 pr_err("Failed to restore %s rate to %lu Hz.\n",
135 clock->name, clock->rate);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700136 }
137}
138
139static int footswitch_is_enabled(struct regulator_dev *rdev)
140{
141 struct footswitch *fs = rdev_get_drvdata(rdev);
142
143 return fs->is_enabled;
144}
145
146static int footswitch_enable(struct regulator_dev *rdev)
147{
148 struct footswitch *fs = rdev_get_drvdata(rdev);
Matt Wagantallb82a5132011-12-12 22:26:41 -0800149 struct clk_data *clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700150 uint32_t regval, rc = 0;
151
152 mutex_lock(&claim_lock);
153 fs->is_claimed = true;
154 mutex_unlock(&claim_lock);
155
Matt Wagantall88edea92011-07-21 10:29:56 -0700156 /* Return early if already enabled. */
157 regval = readl_relaxed(fs->gfs_ctl_reg);
158 if ((regval & (ENABLE_BIT | CLAMP_BIT)) == ENABLE_BIT)
159 return 0;
160
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700161 /* Make sure required clocks are on at the correct rates. */
162 rc = setup_clocks(fs);
163 if (rc)
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800164 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700165
166 /* Un-halt all bus ports in the power domain. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800167 if (fs->bus_port0) {
168 rc = msm_bus_axi_portunhalt(fs->bus_port0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700169 if (rc) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800170 pr_err("Port 0 unhalt failed.\n");
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800171 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700172 }
173 }
Matt Wagantallb82a5132011-12-12 22:26:41 -0800174 if (fs->bus_port1) {
175 rc = msm_bus_axi_portunhalt(fs->bus_port1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700176 if (rc) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800177 pr_err("Port 1 unhalt failed.\n");
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800178 goto err_port2_halt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700179 }
180 }
181
182 /*
183 * (Re-)Assert resets for all clocks in the clock domain, since
184 * footswitch_enable() is first called before footswitch_disable()
185 * and resets should be asserted before power is restored.
186 */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800187 for (clock = fs->clk_data; clock->clk; clock++)
Stephen Boyd0c629382011-12-28 19:15:57 -0800188 ; /* Do nothing */
189 for (clock--; clock >= fs->clk_data; clock--)
Matt Wagantallb82a5132011-12-12 22:26:41 -0800190 clk_reset(clock->clk, CLK_RESET_ASSERT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700191 /* Wait for synchronous resets to propagate. */
192 udelay(RESET_DELAY_US);
193
194 /* Enable the power rail at the footswitch. */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700195 regval |= ENABLE_BIT;
196 writel_relaxed(regval, fs->gfs_ctl_reg);
197 /* Wait for the rail to fully charge. */
198 mb();
199 udelay(1);
200
201 /* Un-clamp the I/O ports. */
202 regval &= ~CLAMP_BIT;
203 writel_relaxed(regval, fs->gfs_ctl_reg);
204
205 /* Deassert resets for all clocks in the power domain. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800206 for (clock = fs->clk_data; clock->clk; clock++)
207 clk_reset(clock->clk, CLK_RESET_DEASSERT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208 /* Toggle core reset again after first power-on (required for GFX3D). */
209 if (fs->desc.id == FS_GFX3D) {
210 clk_reset(fs->core_clk, CLK_RESET_ASSERT);
211 udelay(RESET_DELAY_US);
212 clk_reset(fs->core_clk, CLK_RESET_DEASSERT);
213 udelay(RESET_DELAY_US);
214 }
215
Matt Wagantall8bec3662012-01-25 11:06:13 -0800216 /* Prevent core memory from collapsing when its clock is gated. */
217 clk_set_flags(fs->core_clk, CLKFLAG_RETAIN);
218
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700219 /* Return clocks to their state before this function. */
220 restore_clocks(fs);
221
222 fs->is_enabled = true;
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800223 return 0;
224
225err_port2_halt:
Matt Wagantallb82a5132011-12-12 22:26:41 -0800226 msm_bus_axi_porthalt(fs->bus_port0);
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800227err:
228 restore_clocks(fs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700229 return rc;
230}
231
232static int footswitch_disable(struct regulator_dev *rdev)
233{
234 struct footswitch *fs = rdev_get_drvdata(rdev);
Matt Wagantallb82a5132011-12-12 22:26:41 -0800235 struct clk_data *clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700236 uint32_t regval, rc = 0;
237
Matt Wagantall88edea92011-07-21 10:29:56 -0700238 /* Return early if already disabled. */
239 regval = readl_relaxed(fs->gfs_ctl_reg);
240 if ((regval & ENABLE_BIT) == 0)
241 return 0;
242
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700243 /* Make sure required clocks are on at the correct rates. */
244 rc = setup_clocks(fs);
245 if (rc)
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800246 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700247
Matt Wagantall8bec3662012-01-25 11:06:13 -0800248 /* Allow core memory to collapse when its clock is gated. */
249 clk_set_flags(fs->core_clk, CLKFLAG_NORETAIN);
250
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251 /* Halt all bus ports in the power domain. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800252 if (fs->bus_port0) {
253 rc = msm_bus_axi_porthalt(fs->bus_port0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254 if (rc) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800255 pr_err("Port 0 halt failed.\n");
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800256 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700257 }
258 }
Matt Wagantallb82a5132011-12-12 22:26:41 -0800259 if (fs->bus_port1) {
260 rc = msm_bus_axi_porthalt(fs->bus_port1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700261 if (rc) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800262 pr_err("Port 1 halt failed.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263 goto err_port2_halt;
264 }
265 }
266
267 /*
268 * Assert resets for all clocks in the clock domain so that
269 * outputs settle prior to clamping.
270 */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800271 for (clock = fs->clk_data; clock->clk; clock++)
Stephen Boyd0c629382011-12-28 19:15:57 -0800272 ; /* Do nothing */
273 for (clock--; clock >= fs->clk_data; clock--)
Matt Wagantallb82a5132011-12-12 22:26:41 -0800274 clk_reset(clock->clk, CLK_RESET_ASSERT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275 /* Wait for synchronous resets to propagate. */
276 udelay(RESET_DELAY_US);
277
278 /*
Matt Wagantall1ab7d942011-12-02 17:59:57 -0800279 * Return clocks to their state before this function. For robustness
280 * if memory-retention across collapses is required, clocks should
281 * be disabled before asserting the clamps. Assuming clocks were off
282 * before entering footswitch_disable(), this will be true.
283 */
284 restore_clocks(fs);
285
286 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700287 * Clamp the I/O ports of the core to ensure the values
288 * remain fixed while the core is collapsed.
289 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290 regval |= CLAMP_BIT;
291 writel_relaxed(regval, fs->gfs_ctl_reg);
292
293 /* Collapse the power rail at the footswitch. */
294 regval &= ~ENABLE_BIT;
295 writel_relaxed(regval, fs->gfs_ctl_reg);
296
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700297 fs->is_enabled = false;
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800298 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700299
300err_port2_halt:
Matt Wagantallb82a5132011-12-12 22:26:41 -0800301 msm_bus_axi_portunhalt(fs->bus_port0);
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800302err:
Matt Wagantall8bec3662012-01-25 11:06:13 -0800303 clk_set_flags(fs->core_clk, CLKFLAG_RETAIN);
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800304 restore_clocks(fs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700305 return rc;
306}
307
308static int gfx2d_footswitch_enable(struct regulator_dev *rdev)
309{
310 struct footswitch *fs = rdev_get_drvdata(rdev);
Matt Wagantallb82a5132011-12-12 22:26:41 -0800311 struct clk_data *clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700312 uint32_t regval, rc = 0;
313
314 mutex_lock(&claim_lock);
315 fs->is_claimed = true;
316 mutex_unlock(&claim_lock);
317
Matt Wagantall88edea92011-07-21 10:29:56 -0700318 /* Return early if already enabled. */
319 regval = readl_relaxed(fs->gfs_ctl_reg);
320 if ((regval & (ENABLE_BIT | CLAMP_BIT)) == ENABLE_BIT)
321 return 0;
322
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700323 /* Make sure required clocks are on at the correct rates. */
324 rc = setup_clocks(fs);
325 if (rc)
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800326 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700327
328 /* Un-halt all bus ports in the power domain. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800329 if (fs->bus_port0) {
330 rc = msm_bus_axi_portunhalt(fs->bus_port0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700331 if (rc) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800332 pr_err("Port 0 unhalt failed.\n");
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800333 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700334 }
335 }
336
337 /* Disable core clock. */
Matt Wagantall1a7ee892012-01-17 18:56:28 -0800338 clk_disable_unprepare(fs->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700339
340 /*
341 * (Re-)Assert resets for all clocks in the clock domain, since
342 * footswitch_enable() is first called before footswitch_disable()
343 * and resets should be asserted before power is restored.
344 */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800345 for (clock = fs->clk_data; clock->clk; clock++)
Stephen Boyd0c629382011-12-28 19:15:57 -0800346 ; /* Do nothing */
347 for (clock--; clock >= fs->clk_data; clock--)
Matt Wagantallb82a5132011-12-12 22:26:41 -0800348 clk_reset(clock->clk, CLK_RESET_ASSERT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700349 /* Wait for synchronous resets to propagate. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800350 udelay(RESET_DELAY_US);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700351
352 /* Enable the power rail at the footswitch. */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700353 regval |= ENABLE_BIT;
354 writel_relaxed(regval, fs->gfs_ctl_reg);
355 mb();
356 udelay(1);
357
358 /* Un-clamp the I/O ports. */
359 regval &= ~CLAMP_BIT;
360 writel_relaxed(regval, fs->gfs_ctl_reg);
361
362 /* Deassert resets for all clocks in the power domain. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800363 for (clock = fs->clk_data; clock->clk; clock++)
364 clk_reset(clock->clk, CLK_RESET_DEASSERT);
365 udelay(RESET_DELAY_US);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700366
367 /* Re-enable core clock. */
Matt Wagantall1a7ee892012-01-17 18:56:28 -0800368 clk_prepare_enable(fs->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700369
Matt Wagantall8bec3662012-01-25 11:06:13 -0800370 /* Prevent core memory from collapsing when its clock is gated. */
371 clk_set_flags(fs->core_clk, CLKFLAG_RETAIN);
372
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700373 /* Return clocks to their state before this function. */
374 restore_clocks(fs);
375
376 fs->is_enabled = true;
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800377 return 0;
378
379err:
380 restore_clocks(fs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700381 return rc;
382}
383
384static int gfx2d_footswitch_disable(struct regulator_dev *rdev)
385{
386 struct footswitch *fs = rdev_get_drvdata(rdev);
Matt Wagantallb82a5132011-12-12 22:26:41 -0800387 struct clk_data *clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388 uint32_t regval, rc = 0;
389
Matt Wagantall88edea92011-07-21 10:29:56 -0700390 /* Return early if already disabled. */
391 regval = readl_relaxed(fs->gfs_ctl_reg);
392 if ((regval & ENABLE_BIT) == 0)
393 return 0;
394
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700395 /* Make sure required clocks are on at the correct rates. */
396 rc = setup_clocks(fs);
397 if (rc)
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800398 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700399
Matt Wagantall8bec3662012-01-25 11:06:13 -0800400 /* Allow core memory to collapse when its clock is gated. */
401 clk_set_flags(fs->core_clk, CLKFLAG_NORETAIN);
402
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700403 /* Halt all bus ports in the power domain. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800404 if (fs->bus_port0) {
405 rc = msm_bus_axi_porthalt(fs->bus_port0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700406 if (rc) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800407 pr_err("Port 0 halt failed.\n");
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800408 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700409 }
410 }
411
412 /* Disable core clock. */
Matt Wagantall1a7ee892012-01-17 18:56:28 -0800413 clk_disable_unprepare(fs->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700414
415 /*
416 * Assert resets for all clocks in the clock domain so that
417 * outputs settle prior to clamping.
418 */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800419 for (clock = fs->clk_data; clock->clk; clock++)
Stephen Boyd0c629382011-12-28 19:15:57 -0800420 ; /* Do nothing */
421 for (clock--; clock >= fs->clk_data; clock--)
Matt Wagantallb82a5132011-12-12 22:26:41 -0800422 clk_reset(clock->clk, CLK_RESET_ASSERT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700423 /* Wait for synchronous resets to propagate. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800424 udelay(5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425
426 /*
427 * Clamp the I/O ports of the core to ensure the values
428 * remain fixed while the core is collapsed.
429 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700430 regval |= CLAMP_BIT;
431 writel_relaxed(regval, fs->gfs_ctl_reg);
432
433 /* Collapse the power rail at the footswitch. */
434 regval &= ~ENABLE_BIT;
435 writel_relaxed(regval, fs->gfs_ctl_reg);
436
437 /* Re-enable core clock. */
Matt Wagantall1a7ee892012-01-17 18:56:28 -0800438 clk_prepare_enable(fs->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700439
440 /* Return clocks to their state before this function. */
441 restore_clocks(fs);
442
443 fs->is_enabled = false;
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800444 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700445
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800446err:
Matt Wagantall8bec3662012-01-25 11:06:13 -0800447 clk_set_flags(fs->core_clk, CLKFLAG_RETAIN);
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800448 restore_clocks(fs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700449 return rc;
450}
451
452static struct regulator_ops standard_fs_ops = {
453 .is_enabled = footswitch_is_enabled,
454 .enable = footswitch_enable,
455 .disable = footswitch_disable,
456};
457
458static struct regulator_ops gfx2d_fs_ops = {
459 .is_enabled = footswitch_is_enabled,
460 .enable = gfx2d_footswitch_enable,
461 .disable = gfx2d_footswitch_disable,
462};
463
Matt Wagantallb82a5132011-12-12 22:26:41 -0800464/*
465 * Lists of required clocks for the collapse and restore sequences.
466 *
467 * Order matters here. Clocks are listed in the same order as their
468 * resets will be de-asserted when the core is restored. Also, rate-
469 * settable clocks must be listed before any of the branches that
470 * are derived from them. Otherwise, the branches may fail to enable
471 * if their parent's rate is not yet set.
472 */
473
474static struct clk_data gfx2d0_clks[] = {
475 { .name = "core_clk" },
476 { .name = "iface_clk" },
477 { 0 }
478};
479
480static struct clk_data gfx2d1_clks[] = {
481 { .name = "core_clk" },
482 { .name = "iface_clk" },
483 { 0 }
484};
485
486static struct clk_data gfx3d_clks[] = {
487 { .name = "core_clk", .reset_rate = 27000000 },
488 { .name = "iface_clk" },
489 { 0 }
490};
491
492
493static struct clk_data ijpeg_clks[] = {
494 { .name = "core_clk" },
495 { .name = "iface_clk" },
496 { .name = "bus_clk" },
497 { 0 }
498};
499
500static struct clk_data mdp_8960_clks[] = {
501 { .name = "core_clk" },
502 { .name = "iface_clk" },
503 { .name = "bus_clk" },
504 { .name = "vsync_clk" },
505 { .name = "lut_clk" },
506 { .name = "tv_src_clk" },
507 { .name = "tv_clk" },
508 { 0 }
509};
510
511static struct clk_data mdp_8660_clks[] = {
512 { .name = "core_clk" },
513 { .name = "iface_clk" },
514 { .name = "bus_clk" },
515 { .name = "vsync_clk" },
516 { .name = "tv_src_clk" },
517 { .name = "tv_clk" },
518 { .name = "pixel_mdp_clk" },
519 { .name = "pixel_lcdc_clk" },
520 { 0 }
521};
522
523static struct clk_data rot_clks[] = {
524 { .name = "core_clk" },
525 { .name = "iface_clk" },
526 { .name = "bus_clk" },
527 { 0 }
528};
529
Gopikrishnaiah Anandan83b6e852012-01-05 17:47:02 -0800530static struct clk_data ved_clks[] = {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800531 { .name = "core_clk" },
532 { .name = "iface_clk" },
533 { .name = "bus_clk" },
534 { 0 }
535};
536
537static struct clk_data vfe_clks[] = {
538 { .name = "core_clk" },
539 { .name = "iface_clk" },
540 { .name = "bus_clk" },
541 { 0 }
542};
543
544static struct clk_data vpe_clks[] = {
545 { .name = "core_clk" },
546 { .name = "iface_clk" },
547 { .name = "bus_clk" },
548 { 0 }
549};
550
551static struct clk_data vcap_clks[] = {
552 { .name = "core_clk" },
553 { .name = "iface_clk" },
554 { .name = "bus_clk" },
555 { 0 }
556};
557
558#define FOOTSWITCH(_id, _name, _ops, _gfs_ctl_reg, _dc, _clk_data, \
559 _bp1, _bp2) \
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700560 [(_id)] = { \
561 .desc = { \
562 .id = (_id), \
563 .name = (_name), \
564 .ops = (_ops), \
565 .type = REGULATOR_VOLTAGE, \
566 .owner = THIS_MODULE, \
567 }, \
568 .gfs_ctl_reg = (_gfs_ctl_reg), \
569 .gfs_delay_cnt = (_dc), \
Matt Wagantallb82a5132011-12-12 22:26:41 -0800570 .clk_data = (_clk_data), \
571 .bus_port0 = (_bp1), \
572 .bus_port1 = (_bp2), \
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700573 }
574static struct footswitch footswitches[] = {
575 FOOTSWITCH(FS_GFX2D0, "fs_gfx2d0", &gfx2d_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800576 GFX2D0_GFS_CTL_REG, 31, gfx2d0_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700577 MSM_BUS_MASTER_GRAPHICS_2D_CORE0, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700578 FOOTSWITCH(FS_GFX2D1, "fs_gfx2d1", &gfx2d_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800579 GFX2D1_GFS_CTL_REG, 31, gfx2d1_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700580 MSM_BUS_MASTER_GRAPHICS_2D_CORE1, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700581 FOOTSWITCH(FS_GFX3D, "fs_gfx3d", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800582 GFX3D_GFS_CTL_REG, 31, gfx3d_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700583 MSM_BUS_MASTER_GRAPHICS_3D, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700584 FOOTSWITCH(FS_IJPEG, "fs_ijpeg", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800585 GEMINI_GFS_CTL_REG, 31, ijpeg_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700586 MSM_BUS_MASTER_JPEG_ENC, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700587 FOOTSWITCH(FS_MDP, "fs_mdp", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800588 MDP_GFS_CTL_REG, 31, NULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700589 MSM_BUS_MASTER_MDP_PORT0,
Matt Wagantall49722712011-08-17 18:50:53 -0700590 MSM_BUS_MASTER_MDP_PORT1),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700591 FOOTSWITCH(FS_ROT, "fs_rot", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800592 ROT_GFS_CTL_REG, 31, rot_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700593 MSM_BUS_MASTER_ROTATOR, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700594 FOOTSWITCH(FS_VED, "fs_ved", &standard_fs_ops,
Gopikrishnaiah Anandan83b6e852012-01-05 17:47:02 -0800595 VED_GFS_CTL_REG, 31, ved_clks,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700596 MSM_BUS_MASTER_HD_CODEC_PORT0,
Matt Wagantall49722712011-08-17 18:50:53 -0700597 MSM_BUS_MASTER_HD_CODEC_PORT1),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700598 FOOTSWITCH(FS_VFE, "fs_vfe", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800599 VFE_GFS_CTL_REG, 31, vfe_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700600 MSM_BUS_MASTER_VFE, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700601 FOOTSWITCH(FS_VPE, "fs_vpe", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800602 VPE_GFS_CTL_REG, 31, vpe_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700603 MSM_BUS_MASTER_VPE, 0),
Matt Wagantall37f34b32011-08-23 18:14:47 -0700604 FOOTSWITCH(FS_VCAP, "fs_vcap", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800605 VCAP_GFS_CTL_REG, 31, vcap_clks,
Matt Wagantall37f34b32011-08-23 18:14:47 -0700606 MSM_BUS_MASTER_VIDEO_CAP, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700607};
608
609static int footswitch_probe(struct platform_device *pdev)
610{
611 struct footswitch *fs;
612 struct regulator_init_data *init_data;
Matt Wagantallb82a5132011-12-12 22:26:41 -0800613 struct clk_data *clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700614 uint32_t regval, rc = 0;
615
616 if (pdev == NULL)
617 return -EINVAL;
618
619 if (pdev->id >= MAX_FS)
620 return -ENODEV;
621
622 fs = &footswitches[pdev->id];
623 init_data = pdev->dev.platform_data;
624
Matt Wagantallb82a5132011-12-12 22:26:41 -0800625 if (pdev->id == FS_MDP) {
Stepan Moskovchenko3e907262012-02-10 13:59:01 -0800626 if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_apq8064())
Matt Wagantallb82a5132011-12-12 22:26:41 -0800627 fs->clk_data = mdp_8960_clks;
628 else if (cpu_is_msm8x60())
629 fs->clk_data = mdp_8660_clks;
630 else
631 BUG();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700632 }
633
Matt Wagantallb82a5132011-12-12 22:26:41 -0800634 for (clock = fs->clk_data; clock->name; clock++) {
635 clock->clk = clk_get(&pdev->dev, clock->name);
636 if (IS_ERR(clock->clk)) {
637 rc = PTR_ERR(clock->clk);
638 pr_err("clk_get(%s) failed\n", clock->name);
639 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700640 }
Matt Wagantallb82a5132011-12-12 22:26:41 -0800641 if (!strncmp(clock->name, "core_clk", 8))
642 fs->core_clk = clock->clk;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700643 }
644
645 /*
646 * Set number of AHB_CLK cycles to delay the assertion of gfs_en_all
647 * after enabling the footswitch. Also ensure the retention bit is
648 * clear so disabling the footswitch will power-collapse the core.
649 */
650 regval = readl_relaxed(fs->gfs_ctl_reg);
651 regval |= fs->gfs_delay_cnt;
652 regval &= ~RETENTION_BIT;
653 writel_relaxed(regval, fs->gfs_ctl_reg);
654
655 fs->rdev = regulator_register(&fs->desc, &pdev->dev, init_data, fs);
656 if (IS_ERR(footswitches[pdev->id].rdev)) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800657 pr_err("regulator_register(\"%s\") failed\n",
658 fs->desc.name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700659 rc = PTR_ERR(footswitches[pdev->id].rdev);
Matt Wagantallb82a5132011-12-12 22:26:41 -0800660 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700661 }
662
663 return 0;
664
Matt Wagantallb82a5132011-12-12 22:26:41 -0800665err:
666 for (clock = fs->clk_data; clock->clk; clock++)
667 clk_put(clock->clk);
668
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700669 return rc;
670}
671
672static int __devexit footswitch_remove(struct platform_device *pdev)
673{
674 struct footswitch *fs = &footswitches[pdev->id];
Matt Wagantallb82a5132011-12-12 22:26:41 -0800675 struct clk_data *clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700676
Matt Wagantallb82a5132011-12-12 22:26:41 -0800677 for (clock = fs->clk_data; clock->clk; clock++)
678 clk_put(clock->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700679 regulator_unregister(fs->rdev);
680
681 return 0;
682}
683
684static struct platform_driver footswitch_driver = {
685 .probe = footswitch_probe,
686 .remove = __devexit_p(footswitch_remove),
687 .driver = {
Matt Wagantall49722712011-08-17 18:50:53 -0700688 .name = "footswitch-8x60",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700689 .owner = THIS_MODULE,
690 },
691};
692
693static int __init late_footswitch_init(void)
694{
695 int i;
696
697 mutex_lock(&claim_lock);
698 /* Turn off all registered but unused footswitches. */
699 for (i = 0; i < ARRAY_SIZE(footswitches); i++)
700 if (footswitches[i].rdev && !footswitches[i].is_claimed)
Matt Wagantall7a261362011-07-14 19:07:10 -0700701 footswitches[i].rdev->desc->ops->
702 disable(footswitches[i].rdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700703 mutex_unlock(&claim_lock);
704
705 return 0;
706}
707late_initcall(late_footswitch_init);
708
709static int __init footswitch_init(void)
710{
711 return platform_driver_register(&footswitch_driver);
712}
713subsys_initcall(footswitch_init);
714
715static void __exit footswitch_exit(void)
716{
717 platform_driver_unregister(&footswitch_driver);
718}
719module_exit(footswitch_exit);
720
721MODULE_LICENSE("GPL v2");
722MODULE_DESCRIPTION("MSM8x60 rail footswitch");
723MODULE_ALIAS("platform:footswitch-msm8x60");