blob: cd6e582c4497e572975cbfe03e340855d0ac67eb [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
216 /* Return clocks to their state before this function. */
217 restore_clocks(fs);
218
219 fs->is_enabled = true;
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800220 return 0;
221
222err_port2_halt:
Matt Wagantallb82a5132011-12-12 22:26:41 -0800223 msm_bus_axi_porthalt(fs->bus_port0);
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800224err:
225 restore_clocks(fs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700226 return rc;
227}
228
229static int footswitch_disable(struct regulator_dev *rdev)
230{
231 struct footswitch *fs = rdev_get_drvdata(rdev);
Matt Wagantallb82a5132011-12-12 22:26:41 -0800232 struct clk_data *clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700233 uint32_t regval, rc = 0;
234
Matt Wagantall88edea92011-07-21 10:29:56 -0700235 /* Return early if already disabled. */
236 regval = readl_relaxed(fs->gfs_ctl_reg);
237 if ((regval & ENABLE_BIT) == 0)
238 return 0;
239
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700240 /* Make sure required clocks are on at the correct rates. */
241 rc = setup_clocks(fs);
242 if (rc)
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800243 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700244
245 /* Halt all bus ports in the power domain. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800246 if (fs->bus_port0) {
247 rc = msm_bus_axi_porthalt(fs->bus_port0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248 if (rc) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800249 pr_err("Port 0 halt failed.\n");
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800250 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251 }
252 }
Matt Wagantallb82a5132011-12-12 22:26:41 -0800253 if (fs->bus_port1) {
254 rc = msm_bus_axi_porthalt(fs->bus_port1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700255 if (rc) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800256 pr_err("Port 1 halt failed.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700257 goto err_port2_halt;
258 }
259 }
260
261 /*
262 * Assert resets for all clocks in the clock domain so that
263 * outputs settle prior to clamping.
264 */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800265 for (clock = fs->clk_data; clock->clk; clock++)
Stephen Boyd0c629382011-12-28 19:15:57 -0800266 ; /* Do nothing */
267 for (clock--; clock >= fs->clk_data; clock--)
Matt Wagantallb82a5132011-12-12 22:26:41 -0800268 clk_reset(clock->clk, CLK_RESET_ASSERT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269 /* Wait for synchronous resets to propagate. */
270 udelay(RESET_DELAY_US);
271
272 /*
Matt Wagantall1ab7d942011-12-02 17:59:57 -0800273 * Return clocks to their state before this function. For robustness
274 * if memory-retention across collapses is required, clocks should
275 * be disabled before asserting the clamps. Assuming clocks were off
276 * before entering footswitch_disable(), this will be true.
277 */
278 restore_clocks(fs);
279
280 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700281 * Clamp the I/O ports of the core to ensure the values
282 * remain fixed while the core is collapsed.
283 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700284 regval |= CLAMP_BIT;
285 writel_relaxed(regval, fs->gfs_ctl_reg);
286
287 /* Collapse the power rail at the footswitch. */
288 regval &= ~ENABLE_BIT;
289 writel_relaxed(regval, fs->gfs_ctl_reg);
290
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700291 fs->is_enabled = false;
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800292 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700293
294err_port2_halt:
Matt Wagantallb82a5132011-12-12 22:26:41 -0800295 msm_bus_axi_portunhalt(fs->bus_port0);
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800296err:
297 restore_clocks(fs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298 return rc;
299}
300
301static int gfx2d_footswitch_enable(struct regulator_dev *rdev)
302{
303 struct footswitch *fs = rdev_get_drvdata(rdev);
Matt Wagantallb82a5132011-12-12 22:26:41 -0800304 struct clk_data *clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700305 uint32_t regval, rc = 0;
306
307 mutex_lock(&claim_lock);
308 fs->is_claimed = true;
309 mutex_unlock(&claim_lock);
310
Matt Wagantall88edea92011-07-21 10:29:56 -0700311 /* Return early if already enabled. */
312 regval = readl_relaxed(fs->gfs_ctl_reg);
313 if ((regval & (ENABLE_BIT | CLAMP_BIT)) == ENABLE_BIT)
314 return 0;
315
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700316 /* Make sure required clocks are on at the correct rates. */
317 rc = setup_clocks(fs);
318 if (rc)
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800319 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700320
321 /* Un-halt all bus ports in the power domain. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800322 if (fs->bus_port0) {
323 rc = msm_bus_axi_portunhalt(fs->bus_port0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700324 if (rc) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800325 pr_err("Port 0 unhalt failed.\n");
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800326 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700327 }
328 }
329
330 /* Disable core clock. */
Matt Wagantall1a7ee892012-01-17 18:56:28 -0800331 clk_disable_unprepare(fs->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700332
333 /*
334 * (Re-)Assert resets for all clocks in the clock domain, since
335 * footswitch_enable() is first called before footswitch_disable()
336 * and resets should be asserted before power is restored.
337 */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800338 for (clock = fs->clk_data; clock->clk; clock++)
Stephen Boyd0c629382011-12-28 19:15:57 -0800339 ; /* Do nothing */
340 for (clock--; clock >= fs->clk_data; clock--)
Matt Wagantallb82a5132011-12-12 22:26:41 -0800341 clk_reset(clock->clk, CLK_RESET_ASSERT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700342 /* Wait for synchronous resets to propagate. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800343 udelay(RESET_DELAY_US);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700344
345 /* Enable the power rail at the footswitch. */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700346 regval |= ENABLE_BIT;
347 writel_relaxed(regval, fs->gfs_ctl_reg);
348 mb();
349 udelay(1);
350
351 /* Un-clamp the I/O ports. */
352 regval &= ~CLAMP_BIT;
353 writel_relaxed(regval, fs->gfs_ctl_reg);
354
355 /* Deassert resets for all clocks in the power domain. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800356 for (clock = fs->clk_data; clock->clk; clock++)
357 clk_reset(clock->clk, CLK_RESET_DEASSERT);
358 udelay(RESET_DELAY_US);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700359
360 /* Re-enable core clock. */
Matt Wagantall1a7ee892012-01-17 18:56:28 -0800361 clk_prepare_enable(fs->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700362
363 /* Return clocks to their state before this function. */
364 restore_clocks(fs);
365
366 fs->is_enabled = true;
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800367 return 0;
368
369err:
370 restore_clocks(fs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700371 return rc;
372}
373
374static int gfx2d_footswitch_disable(struct regulator_dev *rdev)
375{
376 struct footswitch *fs = rdev_get_drvdata(rdev);
Matt Wagantallb82a5132011-12-12 22:26:41 -0800377 struct clk_data *clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700378 uint32_t regval, rc = 0;
379
Matt Wagantall88edea92011-07-21 10:29:56 -0700380 /* Return early if already disabled. */
381 regval = readl_relaxed(fs->gfs_ctl_reg);
382 if ((regval & ENABLE_BIT) == 0)
383 return 0;
384
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385 /* Make sure required clocks are on at the correct rates. */
386 rc = setup_clocks(fs);
387 if (rc)
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800388 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700389
390 /* Halt all bus ports in the power domain. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800391 if (fs->bus_port0) {
392 rc = msm_bus_axi_porthalt(fs->bus_port0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700393 if (rc) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800394 pr_err("Port 0 halt failed.\n");
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800395 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700396 }
397 }
398
399 /* Disable core clock. */
Matt Wagantall1a7ee892012-01-17 18:56:28 -0800400 clk_disable_unprepare(fs->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401
402 /*
403 * Assert resets for all clocks in the clock domain so that
404 * outputs settle prior to clamping.
405 */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800406 for (clock = fs->clk_data; clock->clk; clock++)
Stephen Boyd0c629382011-12-28 19:15:57 -0800407 ; /* Do nothing */
408 for (clock--; clock >= fs->clk_data; clock--)
Matt Wagantallb82a5132011-12-12 22:26:41 -0800409 clk_reset(clock->clk, CLK_RESET_ASSERT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700410 /* Wait for synchronous resets to propagate. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800411 udelay(5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700412
413 /*
414 * Clamp the I/O ports of the core to ensure the values
415 * remain fixed while the core is collapsed.
416 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700417 regval |= CLAMP_BIT;
418 writel_relaxed(regval, fs->gfs_ctl_reg);
419
420 /* Collapse the power rail at the footswitch. */
421 regval &= ~ENABLE_BIT;
422 writel_relaxed(regval, fs->gfs_ctl_reg);
423
424 /* Re-enable core clock. */
Matt Wagantall1a7ee892012-01-17 18:56:28 -0800425 clk_prepare_enable(fs->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700426
427 /* Return clocks to their state before this function. */
428 restore_clocks(fs);
429
430 fs->is_enabled = false;
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800431 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700432
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800433err:
434 restore_clocks(fs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700435 return rc;
436}
437
438static struct regulator_ops standard_fs_ops = {
439 .is_enabled = footswitch_is_enabled,
440 .enable = footswitch_enable,
441 .disable = footswitch_disable,
442};
443
444static struct regulator_ops gfx2d_fs_ops = {
445 .is_enabled = footswitch_is_enabled,
446 .enable = gfx2d_footswitch_enable,
447 .disable = gfx2d_footswitch_disable,
448};
449
Matt Wagantallb82a5132011-12-12 22:26:41 -0800450/*
451 * Lists of required clocks for the collapse and restore sequences.
452 *
453 * Order matters here. Clocks are listed in the same order as their
454 * resets will be de-asserted when the core is restored. Also, rate-
455 * settable clocks must be listed before any of the branches that
456 * are derived from them. Otherwise, the branches may fail to enable
457 * if their parent's rate is not yet set.
458 */
459
460static struct clk_data gfx2d0_clks[] = {
461 { .name = "core_clk" },
462 { .name = "iface_clk" },
463 { 0 }
464};
465
466static struct clk_data gfx2d1_clks[] = {
467 { .name = "core_clk" },
468 { .name = "iface_clk" },
469 { 0 }
470};
471
472static struct clk_data gfx3d_clks[] = {
473 { .name = "core_clk", .reset_rate = 27000000 },
474 { .name = "iface_clk" },
475 { 0 }
476};
477
478
479static struct clk_data ijpeg_clks[] = {
480 { .name = "core_clk" },
481 { .name = "iface_clk" },
482 { .name = "bus_clk" },
483 { 0 }
484};
485
486static struct clk_data mdp_8960_clks[] = {
487 { .name = "core_clk" },
488 { .name = "iface_clk" },
489 { .name = "bus_clk" },
490 { .name = "vsync_clk" },
491 { .name = "lut_clk" },
492 { .name = "tv_src_clk" },
493 { .name = "tv_clk" },
494 { 0 }
495};
496
497static struct clk_data mdp_8660_clks[] = {
498 { .name = "core_clk" },
499 { .name = "iface_clk" },
500 { .name = "bus_clk" },
501 { .name = "vsync_clk" },
502 { .name = "tv_src_clk" },
503 { .name = "tv_clk" },
504 { .name = "pixel_mdp_clk" },
505 { .name = "pixel_lcdc_clk" },
506 { 0 }
507};
508
509static struct clk_data rot_clks[] = {
510 { .name = "core_clk" },
511 { .name = "iface_clk" },
512 { .name = "bus_clk" },
513 { 0 }
514};
515
Gopikrishnaiah Anandan83b6e852012-01-05 17:47:02 -0800516static struct clk_data ved_clks[] = {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800517 { .name = "core_clk" },
518 { .name = "iface_clk" },
519 { .name = "bus_clk" },
520 { 0 }
521};
522
523static struct clk_data vfe_clks[] = {
524 { .name = "core_clk" },
525 { .name = "iface_clk" },
526 { .name = "bus_clk" },
527 { 0 }
528};
529
530static struct clk_data vpe_clks[] = {
531 { .name = "core_clk" },
532 { .name = "iface_clk" },
533 { .name = "bus_clk" },
534 { 0 }
535};
536
537static struct clk_data vcap_clks[] = {
538 { .name = "core_clk" },
539 { .name = "iface_clk" },
540 { .name = "bus_clk" },
541 { 0 }
542};
543
544#define FOOTSWITCH(_id, _name, _ops, _gfs_ctl_reg, _dc, _clk_data, \
545 _bp1, _bp2) \
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700546 [(_id)] = { \
547 .desc = { \
548 .id = (_id), \
549 .name = (_name), \
550 .ops = (_ops), \
551 .type = REGULATOR_VOLTAGE, \
552 .owner = THIS_MODULE, \
553 }, \
554 .gfs_ctl_reg = (_gfs_ctl_reg), \
555 .gfs_delay_cnt = (_dc), \
Matt Wagantallb82a5132011-12-12 22:26:41 -0800556 .clk_data = (_clk_data), \
557 .bus_port0 = (_bp1), \
558 .bus_port1 = (_bp2), \
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700559 }
560static struct footswitch footswitches[] = {
561 FOOTSWITCH(FS_GFX2D0, "fs_gfx2d0", &gfx2d_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800562 GFX2D0_GFS_CTL_REG, 31, gfx2d0_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700563 MSM_BUS_MASTER_GRAPHICS_2D_CORE0, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700564 FOOTSWITCH(FS_GFX2D1, "fs_gfx2d1", &gfx2d_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800565 GFX2D1_GFS_CTL_REG, 31, gfx2d1_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700566 MSM_BUS_MASTER_GRAPHICS_2D_CORE1, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700567 FOOTSWITCH(FS_GFX3D, "fs_gfx3d", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800568 GFX3D_GFS_CTL_REG, 31, gfx3d_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700569 MSM_BUS_MASTER_GRAPHICS_3D, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700570 FOOTSWITCH(FS_IJPEG, "fs_ijpeg", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800571 GEMINI_GFS_CTL_REG, 31, ijpeg_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700572 MSM_BUS_MASTER_JPEG_ENC, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700573 FOOTSWITCH(FS_MDP, "fs_mdp", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800574 MDP_GFS_CTL_REG, 31, NULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700575 MSM_BUS_MASTER_MDP_PORT0,
Matt Wagantall49722712011-08-17 18:50:53 -0700576 MSM_BUS_MASTER_MDP_PORT1),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700577 FOOTSWITCH(FS_ROT, "fs_rot", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800578 ROT_GFS_CTL_REG, 31, rot_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700579 MSM_BUS_MASTER_ROTATOR, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700580 FOOTSWITCH(FS_VED, "fs_ved", &standard_fs_ops,
Gopikrishnaiah Anandan83b6e852012-01-05 17:47:02 -0800581 VED_GFS_CTL_REG, 31, ved_clks,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700582 MSM_BUS_MASTER_HD_CODEC_PORT0,
Matt Wagantall49722712011-08-17 18:50:53 -0700583 MSM_BUS_MASTER_HD_CODEC_PORT1),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700584 FOOTSWITCH(FS_VFE, "fs_vfe", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800585 VFE_GFS_CTL_REG, 31, vfe_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700586 MSM_BUS_MASTER_VFE, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700587 FOOTSWITCH(FS_VPE, "fs_vpe", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800588 VPE_GFS_CTL_REG, 31, vpe_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700589 MSM_BUS_MASTER_VPE, 0),
Matt Wagantall37f34b32011-08-23 18:14:47 -0700590 FOOTSWITCH(FS_VCAP, "fs_vcap", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800591 VCAP_GFS_CTL_REG, 31, vcap_clks,
Matt Wagantall37f34b32011-08-23 18:14:47 -0700592 MSM_BUS_MASTER_VIDEO_CAP, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700593};
594
595static int footswitch_probe(struct platform_device *pdev)
596{
597 struct footswitch *fs;
598 struct regulator_init_data *init_data;
Matt Wagantallb82a5132011-12-12 22:26:41 -0800599 struct clk_data *clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700600 uint32_t regval, rc = 0;
601
602 if (pdev == NULL)
603 return -EINVAL;
604
605 if (pdev->id >= MAX_FS)
606 return -ENODEV;
607
608 fs = &footswitches[pdev->id];
609 init_data = pdev->dev.platform_data;
610
Matt Wagantallb82a5132011-12-12 22:26:41 -0800611 if (pdev->id == FS_MDP) {
612 if (cpu_is_msm8960() || cpu_is_msm8930())
613 fs->clk_data = mdp_8960_clks;
614 else if (cpu_is_msm8x60())
615 fs->clk_data = mdp_8660_clks;
616 else
617 BUG();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700618 }
619
Matt Wagantallb82a5132011-12-12 22:26:41 -0800620 for (clock = fs->clk_data; clock->name; clock++) {
621 clock->clk = clk_get(&pdev->dev, clock->name);
622 if (IS_ERR(clock->clk)) {
623 rc = PTR_ERR(clock->clk);
624 pr_err("clk_get(%s) failed\n", clock->name);
625 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700626 }
Matt Wagantallb82a5132011-12-12 22:26:41 -0800627 if (!strncmp(clock->name, "core_clk", 8))
628 fs->core_clk = clock->clk;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700629 }
630
631 /*
632 * Set number of AHB_CLK cycles to delay the assertion of gfs_en_all
633 * after enabling the footswitch. Also ensure the retention bit is
634 * clear so disabling the footswitch will power-collapse the core.
635 */
636 regval = readl_relaxed(fs->gfs_ctl_reg);
637 regval |= fs->gfs_delay_cnt;
638 regval &= ~RETENTION_BIT;
639 writel_relaxed(regval, fs->gfs_ctl_reg);
640
641 fs->rdev = regulator_register(&fs->desc, &pdev->dev, init_data, fs);
642 if (IS_ERR(footswitches[pdev->id].rdev)) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800643 pr_err("regulator_register(\"%s\") failed\n",
644 fs->desc.name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700645 rc = PTR_ERR(footswitches[pdev->id].rdev);
Matt Wagantallb82a5132011-12-12 22:26:41 -0800646 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700647 }
648
649 return 0;
650
Matt Wagantallb82a5132011-12-12 22:26:41 -0800651err:
652 for (clock = fs->clk_data; clock->clk; clock++)
653 clk_put(clock->clk);
654
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700655 return rc;
656}
657
658static int __devexit footswitch_remove(struct platform_device *pdev)
659{
660 struct footswitch *fs = &footswitches[pdev->id];
Matt Wagantallb82a5132011-12-12 22:26:41 -0800661 struct clk_data *clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700662
Matt Wagantallb82a5132011-12-12 22:26:41 -0800663 for (clock = fs->clk_data; clock->clk; clock++)
664 clk_put(clock->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700665 regulator_unregister(fs->rdev);
666
667 return 0;
668}
669
670static struct platform_driver footswitch_driver = {
671 .probe = footswitch_probe,
672 .remove = __devexit_p(footswitch_remove),
673 .driver = {
Matt Wagantall49722712011-08-17 18:50:53 -0700674 .name = "footswitch-8x60",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700675 .owner = THIS_MODULE,
676 },
677};
678
679static int __init late_footswitch_init(void)
680{
681 int i;
682
683 mutex_lock(&claim_lock);
684 /* Turn off all registered but unused footswitches. */
685 for (i = 0; i < ARRAY_SIZE(footswitches); i++)
686 if (footswitches[i].rdev && !footswitches[i].is_claimed)
Matt Wagantall7a261362011-07-14 19:07:10 -0700687 footswitches[i].rdev->desc->ops->
688 disable(footswitches[i].rdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700689 mutex_unlock(&claim_lock);
690
691 return 0;
692}
693late_initcall(late_footswitch_init);
694
695static int __init footswitch_init(void)
696{
697 return platform_driver_register(&footswitch_driver);
698}
699subsys_initcall(footswitch_init);
700
701static void __exit footswitch_exit(void)
702{
703 platform_driver_unregister(&footswitch_driver);
704}
705module_exit(footswitch_exit);
706
707MODULE_LICENSE("GPL v2");
708MODULE_DESCRIPTION("MSM8x60 rail footswitch");
709MODULE_ALIAS("platform:footswitch-msm8x60");