blob: 51f033688b9686289b6d1f4ee6a7943f9906149a [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
2 *
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)
106 clk_disable(clock->clk);
107 clk_set_rate(clock->clk, clock->rate);
108 }
109 return rc;
110 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700111 }
Matt Wagantallb82a5132011-12-12 22:26:41 -0800112 /*
113 * Some clocks are for reset purposes only. These clocks will
114 * fail to enable. Ignore the failures but keep track of them so
115 * we don't try to disable them later and crash due to
116 * unbalanced calls.
117 */
118 clock->enabled = !clk_enable(clock->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700119 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700120
Matt Wagantallb82a5132011-12-12 22:26:41 -0800121 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700122}
123
124static void restore_clocks(struct footswitch *fs)
125{
Matt Wagantallb82a5132011-12-12 22:26:41 -0800126 struct clk_data *clock;
127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128 /* Restore clocks to their orignal states before setup_clocks(). */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800129 for (clock = fs->clk_data; clock->clk; clock++) {
130 if (clock->enabled)
131 clk_disable(clock->clk);
132 if (clock->rate && clk_set_rate(clock->clk, clock->rate))
133 pr_err("Failed to restore %s rate to %lu Hz.\n",
134 clock->name, clock->rate);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700135 }
136}
137
138static int footswitch_is_enabled(struct regulator_dev *rdev)
139{
140 struct footswitch *fs = rdev_get_drvdata(rdev);
141
142 return fs->is_enabled;
143}
144
145static int footswitch_enable(struct regulator_dev *rdev)
146{
147 struct footswitch *fs = rdev_get_drvdata(rdev);
Matt Wagantallb82a5132011-12-12 22:26:41 -0800148 struct clk_data *clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149 uint32_t regval, rc = 0;
150
151 mutex_lock(&claim_lock);
152 fs->is_claimed = true;
153 mutex_unlock(&claim_lock);
154
Matt Wagantall88edea92011-07-21 10:29:56 -0700155 /* Return early if already enabled. */
156 regval = readl_relaxed(fs->gfs_ctl_reg);
157 if ((regval & (ENABLE_BIT | CLAMP_BIT)) == ENABLE_BIT)
158 return 0;
159
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160 /* Make sure required clocks are on at the correct rates. */
161 rc = setup_clocks(fs);
162 if (rc)
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800163 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700164
165 /* Un-halt all bus ports in the power domain. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800166 if (fs->bus_port0) {
167 rc = msm_bus_axi_portunhalt(fs->bus_port0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700168 if (rc) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800169 pr_err("Port 0 unhalt failed.\n");
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800170 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700171 }
172 }
Matt Wagantallb82a5132011-12-12 22:26:41 -0800173 if (fs->bus_port1) {
174 rc = msm_bus_axi_portunhalt(fs->bus_port1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700175 if (rc) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800176 pr_err("Port 1 unhalt failed.\n");
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800177 goto err_port2_halt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700178 }
179 }
180
181 /*
182 * (Re-)Assert resets for all clocks in the clock domain, since
183 * footswitch_enable() is first called before footswitch_disable()
184 * and resets should be asserted before power is restored.
185 */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800186 for (clock = fs->clk_data; clock->clk; clock++)
187 clk_reset(clock->clk, CLK_RESET_ASSERT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700188 /* Wait for synchronous resets to propagate. */
189 udelay(RESET_DELAY_US);
190
191 /* Enable the power rail at the footswitch. */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700192 regval |= ENABLE_BIT;
193 writel_relaxed(regval, fs->gfs_ctl_reg);
194 /* Wait for the rail to fully charge. */
195 mb();
196 udelay(1);
197
198 /* Un-clamp the I/O ports. */
199 regval &= ~CLAMP_BIT;
200 writel_relaxed(regval, fs->gfs_ctl_reg);
201
202 /* Deassert resets for all clocks in the power domain. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800203 for (clock = fs->clk_data; clock->clk; clock++)
204 clk_reset(clock->clk, CLK_RESET_DEASSERT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700205 /* Toggle core reset again after first power-on (required for GFX3D). */
206 if (fs->desc.id == FS_GFX3D) {
207 clk_reset(fs->core_clk, CLK_RESET_ASSERT);
208 udelay(RESET_DELAY_US);
209 clk_reset(fs->core_clk, CLK_RESET_DEASSERT);
210 udelay(RESET_DELAY_US);
211 }
212
213 /* Return clocks to their state before this function. */
214 restore_clocks(fs);
215
216 fs->is_enabled = true;
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800217 return 0;
218
219err_port2_halt:
Matt Wagantallb82a5132011-12-12 22:26:41 -0800220 msm_bus_axi_porthalt(fs->bus_port0);
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800221err:
222 restore_clocks(fs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700223 return rc;
224}
225
226static int footswitch_disable(struct regulator_dev *rdev)
227{
228 struct footswitch *fs = rdev_get_drvdata(rdev);
Matt Wagantallb82a5132011-12-12 22:26:41 -0800229 struct clk_data *clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700230 uint32_t regval, rc = 0;
231
Matt Wagantall88edea92011-07-21 10:29:56 -0700232 /* Return early if already disabled. */
233 regval = readl_relaxed(fs->gfs_ctl_reg);
234 if ((regval & ENABLE_BIT) == 0)
235 return 0;
236
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700237 /* Make sure required clocks are on at the correct rates. */
238 rc = setup_clocks(fs);
239 if (rc)
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800240 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700241
242 /* Halt all bus ports in the power domain. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800243 if (fs->bus_port0) {
244 rc = msm_bus_axi_porthalt(fs->bus_port0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245 if (rc) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800246 pr_err("Port 0 halt failed.\n");
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800247 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248 }
249 }
Matt Wagantallb82a5132011-12-12 22:26:41 -0800250 if (fs->bus_port1) {
251 rc = msm_bus_axi_porthalt(fs->bus_port1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700252 if (rc) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800253 pr_err("Port 1 halt failed.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254 goto err_port2_halt;
255 }
256 }
257
258 /*
259 * Assert resets for all clocks in the clock domain so that
260 * outputs settle prior to clamping.
261 */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800262 for (clock = fs->clk_data; clock->clk; clock++)
263 clk_reset(clock->clk, CLK_RESET_ASSERT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700264 /* Wait for synchronous resets to propagate. */
265 udelay(RESET_DELAY_US);
266
267 /*
Matt Wagantall1ab7d942011-12-02 17:59:57 -0800268 * Return clocks to their state before this function. For robustness
269 * if memory-retention across collapses is required, clocks should
270 * be disabled before asserting the clamps. Assuming clocks were off
271 * before entering footswitch_disable(), this will be true.
272 */
273 restore_clocks(fs);
274
275 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700276 * Clamp the I/O ports of the core to ensure the values
277 * remain fixed while the core is collapsed.
278 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700279 regval |= CLAMP_BIT;
280 writel_relaxed(regval, fs->gfs_ctl_reg);
281
282 /* Collapse the power rail at the footswitch. */
283 regval &= ~ENABLE_BIT;
284 writel_relaxed(regval, fs->gfs_ctl_reg);
285
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700286 fs->is_enabled = false;
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800287 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700288
289err_port2_halt:
Matt Wagantallb82a5132011-12-12 22:26:41 -0800290 msm_bus_axi_portunhalt(fs->bus_port0);
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800291err:
292 restore_clocks(fs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700293 return rc;
294}
295
296static int gfx2d_footswitch_enable(struct regulator_dev *rdev)
297{
298 struct footswitch *fs = rdev_get_drvdata(rdev);
Matt Wagantallb82a5132011-12-12 22:26:41 -0800299 struct clk_data *clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700300 uint32_t regval, rc = 0;
301
302 mutex_lock(&claim_lock);
303 fs->is_claimed = true;
304 mutex_unlock(&claim_lock);
305
Matt Wagantall88edea92011-07-21 10:29:56 -0700306 /* Return early if already enabled. */
307 regval = readl_relaxed(fs->gfs_ctl_reg);
308 if ((regval & (ENABLE_BIT | CLAMP_BIT)) == ENABLE_BIT)
309 return 0;
310
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700311 /* Make sure required clocks are on at the correct rates. */
312 rc = setup_clocks(fs);
313 if (rc)
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800314 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315
316 /* Un-halt all bus ports in the power domain. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800317 if (fs->bus_port0) {
318 rc = msm_bus_axi_portunhalt(fs->bus_port0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319 if (rc) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800320 pr_err("Port 0 unhalt failed.\n");
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800321 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700322 }
323 }
324
325 /* Disable core clock. */
326 clk_disable(fs->core_clk);
327
328 /*
329 * (Re-)Assert resets for all clocks in the clock domain, since
330 * footswitch_enable() is first called before footswitch_disable()
331 * and resets should be asserted before power is restored.
332 */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800333 for (clock = fs->clk_data; clock->clk; clock++)
334 clk_reset(clock->clk, CLK_RESET_ASSERT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700335 /* Wait for synchronous resets to propagate. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800336 udelay(RESET_DELAY_US);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700337
338 /* Enable the power rail at the footswitch. */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700339 regval |= ENABLE_BIT;
340 writel_relaxed(regval, fs->gfs_ctl_reg);
341 mb();
342 udelay(1);
343
344 /* Un-clamp the I/O ports. */
345 regval &= ~CLAMP_BIT;
346 writel_relaxed(regval, fs->gfs_ctl_reg);
347
348 /* Deassert resets for all clocks in the power domain. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800349 for (clock = fs->clk_data; clock->clk; clock++)
350 clk_reset(clock->clk, CLK_RESET_DEASSERT);
351 udelay(RESET_DELAY_US);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700352
353 /* Re-enable core clock. */
354 clk_enable(fs->core_clk);
355
356 /* Return clocks to their state before this function. */
357 restore_clocks(fs);
358
359 fs->is_enabled = true;
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800360 return 0;
361
362err:
363 restore_clocks(fs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700364 return rc;
365}
366
367static int gfx2d_footswitch_disable(struct regulator_dev *rdev)
368{
369 struct footswitch *fs = rdev_get_drvdata(rdev);
Matt Wagantallb82a5132011-12-12 22:26:41 -0800370 struct clk_data *clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700371 uint32_t regval, rc = 0;
372
Matt Wagantall88edea92011-07-21 10:29:56 -0700373 /* Return early if already disabled. */
374 regval = readl_relaxed(fs->gfs_ctl_reg);
375 if ((regval & ENABLE_BIT) == 0)
376 return 0;
377
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700378 /* Make sure required clocks are on at the correct rates. */
379 rc = setup_clocks(fs);
380 if (rc)
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800381 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700382
383 /* Halt all bus ports in the power domain. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800384 if (fs->bus_port0) {
385 rc = msm_bus_axi_porthalt(fs->bus_port0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700386 if (rc) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800387 pr_err("Port 0 halt failed.\n");
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800388 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700389 }
390 }
391
392 /* Disable core clock. */
393 clk_disable(fs->core_clk);
394
395 /*
396 * Assert resets for all clocks in the clock domain so that
397 * outputs settle prior to clamping.
398 */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800399 for (clock = fs->clk_data; clock->clk; clock++)
400 clk_reset(clock->clk, CLK_RESET_ASSERT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401 /* Wait for synchronous resets to propagate. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800402 udelay(5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700403
404 /*
405 * Clamp the I/O ports of the core to ensure the values
406 * remain fixed while the core is collapsed.
407 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700408 regval |= CLAMP_BIT;
409 writel_relaxed(regval, fs->gfs_ctl_reg);
410
411 /* Collapse the power rail at the footswitch. */
412 regval &= ~ENABLE_BIT;
413 writel_relaxed(regval, fs->gfs_ctl_reg);
414
415 /* Re-enable core clock. */
416 clk_enable(fs->core_clk);
417
418 /* Return clocks to their state before this function. */
419 restore_clocks(fs);
420
421 fs->is_enabled = false;
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800422 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700423
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800424err:
425 restore_clocks(fs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700426 return rc;
427}
428
429static struct regulator_ops standard_fs_ops = {
430 .is_enabled = footswitch_is_enabled,
431 .enable = footswitch_enable,
432 .disable = footswitch_disable,
433};
434
435static struct regulator_ops gfx2d_fs_ops = {
436 .is_enabled = footswitch_is_enabled,
437 .enable = gfx2d_footswitch_enable,
438 .disable = gfx2d_footswitch_disable,
439};
440
Matt Wagantallb82a5132011-12-12 22:26:41 -0800441/*
442 * Lists of required clocks for the collapse and restore sequences.
443 *
444 * Order matters here. Clocks are listed in the same order as their
445 * resets will be de-asserted when the core is restored. Also, rate-
446 * settable clocks must be listed before any of the branches that
447 * are derived from them. Otherwise, the branches may fail to enable
448 * if their parent's rate is not yet set.
449 */
450
451static struct clk_data gfx2d0_clks[] = {
452 { .name = "core_clk" },
453 { .name = "iface_clk" },
454 { 0 }
455};
456
457static struct clk_data gfx2d1_clks[] = {
458 { .name = "core_clk" },
459 { .name = "iface_clk" },
460 { 0 }
461};
462
463static struct clk_data gfx3d_clks[] = {
464 { .name = "core_clk", .reset_rate = 27000000 },
465 { .name = "iface_clk" },
466 { 0 }
467};
468
469
470static struct clk_data ijpeg_clks[] = {
471 { .name = "core_clk" },
472 { .name = "iface_clk" },
473 { .name = "bus_clk" },
474 { 0 }
475};
476
477static struct clk_data mdp_8960_clks[] = {
478 { .name = "core_clk" },
479 { .name = "iface_clk" },
480 { .name = "bus_clk" },
481 { .name = "vsync_clk" },
482 { .name = "lut_clk" },
483 { .name = "tv_src_clk" },
484 { .name = "tv_clk" },
485 { 0 }
486};
487
488static struct clk_data mdp_8660_clks[] = {
489 { .name = "core_clk" },
490 { .name = "iface_clk" },
491 { .name = "bus_clk" },
492 { .name = "vsync_clk" },
493 { .name = "tv_src_clk" },
494 { .name = "tv_clk" },
495 { .name = "pixel_mdp_clk" },
496 { .name = "pixel_lcdc_clk" },
497 { 0 }
498};
499
500static struct clk_data rot_clks[] = {
501 { .name = "core_clk" },
502 { .name = "iface_clk" },
503 { .name = "bus_clk" },
504 { 0 }
505};
506
507static struct clk_data ved_clks[] = {
508 { .name = "core_clk" },
509 { .name = "iface_clk" },
510 { .name = "bus_clk" },
511 { 0 }
512};
513
514static struct clk_data vfe_clks[] = {
515 { .name = "core_clk" },
516 { .name = "iface_clk" },
517 { .name = "bus_clk" },
518 { 0 }
519};
520
521static struct clk_data vpe_clks[] = {
522 { .name = "core_clk" },
523 { .name = "iface_clk" },
524 { .name = "bus_clk" },
525 { 0 }
526};
527
528static struct clk_data vcap_clks[] = {
529 { .name = "core_clk" },
530 { .name = "iface_clk" },
531 { .name = "bus_clk" },
532 { 0 }
533};
534
535#define FOOTSWITCH(_id, _name, _ops, _gfs_ctl_reg, _dc, _clk_data, \
536 _bp1, _bp2) \
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700537 [(_id)] = { \
538 .desc = { \
539 .id = (_id), \
540 .name = (_name), \
541 .ops = (_ops), \
542 .type = REGULATOR_VOLTAGE, \
543 .owner = THIS_MODULE, \
544 }, \
545 .gfs_ctl_reg = (_gfs_ctl_reg), \
546 .gfs_delay_cnt = (_dc), \
Matt Wagantallb82a5132011-12-12 22:26:41 -0800547 .clk_data = (_clk_data), \
548 .bus_port0 = (_bp1), \
549 .bus_port1 = (_bp2), \
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700550 }
551static struct footswitch footswitches[] = {
552 FOOTSWITCH(FS_GFX2D0, "fs_gfx2d0", &gfx2d_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800553 GFX2D0_GFS_CTL_REG, 31, gfx2d0_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700554 MSM_BUS_MASTER_GRAPHICS_2D_CORE0, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700555 FOOTSWITCH(FS_GFX2D1, "fs_gfx2d1", &gfx2d_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800556 GFX2D1_GFS_CTL_REG, 31, gfx2d1_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700557 MSM_BUS_MASTER_GRAPHICS_2D_CORE1, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700558 FOOTSWITCH(FS_GFX3D, "fs_gfx3d", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800559 GFX3D_GFS_CTL_REG, 31, gfx3d_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700560 MSM_BUS_MASTER_GRAPHICS_3D, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700561 FOOTSWITCH(FS_IJPEG, "fs_ijpeg", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800562 GEMINI_GFS_CTL_REG, 31, ijpeg_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700563 MSM_BUS_MASTER_JPEG_ENC, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700564 FOOTSWITCH(FS_MDP, "fs_mdp", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800565 MDP_GFS_CTL_REG, 31, NULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700566 MSM_BUS_MASTER_MDP_PORT0,
Matt Wagantall49722712011-08-17 18:50:53 -0700567 MSM_BUS_MASTER_MDP_PORT1),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700568 FOOTSWITCH(FS_ROT, "fs_rot", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800569 ROT_GFS_CTL_REG, 31, rot_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700570 MSM_BUS_MASTER_ROTATOR, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700571 FOOTSWITCH(FS_VED, "fs_ved", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800572 VED_GFS_CTL_REG, 31, ved_clks,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700573 MSM_BUS_MASTER_HD_CODEC_PORT0,
Matt Wagantall49722712011-08-17 18:50:53 -0700574 MSM_BUS_MASTER_HD_CODEC_PORT1),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700575 FOOTSWITCH(FS_VFE, "fs_vfe", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800576 VFE_GFS_CTL_REG, 31, vfe_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700577 MSM_BUS_MASTER_VFE, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700578 FOOTSWITCH(FS_VPE, "fs_vpe", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800579 VPE_GFS_CTL_REG, 31, vpe_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700580 MSM_BUS_MASTER_VPE, 0),
Matt Wagantall37f34b32011-08-23 18:14:47 -0700581 FOOTSWITCH(FS_VCAP, "fs_vcap", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800582 VCAP_GFS_CTL_REG, 31, vcap_clks,
Matt Wagantall37f34b32011-08-23 18:14:47 -0700583 MSM_BUS_MASTER_VIDEO_CAP, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700584};
585
586static int footswitch_probe(struct platform_device *pdev)
587{
588 struct footswitch *fs;
589 struct regulator_init_data *init_data;
Matt Wagantallb82a5132011-12-12 22:26:41 -0800590 struct clk_data *clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700591 uint32_t regval, rc = 0;
592
593 if (pdev == NULL)
594 return -EINVAL;
595
596 if (pdev->id >= MAX_FS)
597 return -ENODEV;
598
599 fs = &footswitches[pdev->id];
600 init_data = pdev->dev.platform_data;
601
Matt Wagantallb82a5132011-12-12 22:26:41 -0800602 if (pdev->id == FS_MDP) {
603 if (cpu_is_msm8960() || cpu_is_msm8930())
604 fs->clk_data = mdp_8960_clks;
605 else if (cpu_is_msm8x60())
606 fs->clk_data = mdp_8660_clks;
607 else
608 BUG();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700609 }
610
Matt Wagantallb82a5132011-12-12 22:26:41 -0800611 for (clock = fs->clk_data; clock->name; clock++) {
612 clock->clk = clk_get(&pdev->dev, clock->name);
613 if (IS_ERR(clock->clk)) {
614 rc = PTR_ERR(clock->clk);
615 pr_err("clk_get(%s) failed\n", clock->name);
616 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700617 }
Matt Wagantallb82a5132011-12-12 22:26:41 -0800618 if (!strncmp(clock->name, "core_clk", 8))
619 fs->core_clk = clock->clk;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700620 }
621
622 /*
623 * Set number of AHB_CLK cycles to delay the assertion of gfs_en_all
624 * after enabling the footswitch. Also ensure the retention bit is
625 * clear so disabling the footswitch will power-collapse the core.
626 */
627 regval = readl_relaxed(fs->gfs_ctl_reg);
628 regval |= fs->gfs_delay_cnt;
629 regval &= ~RETENTION_BIT;
630 writel_relaxed(regval, fs->gfs_ctl_reg);
631
632 fs->rdev = regulator_register(&fs->desc, &pdev->dev, init_data, fs);
633 if (IS_ERR(footswitches[pdev->id].rdev)) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800634 pr_err("regulator_register(\"%s\") failed\n",
635 fs->desc.name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700636 rc = PTR_ERR(footswitches[pdev->id].rdev);
Matt Wagantallb82a5132011-12-12 22:26:41 -0800637 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700638 }
639
640 return 0;
641
Matt Wagantallb82a5132011-12-12 22:26:41 -0800642err:
643 for (clock = fs->clk_data; clock->clk; clock++)
644 clk_put(clock->clk);
645
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700646 return rc;
647}
648
649static int __devexit footswitch_remove(struct platform_device *pdev)
650{
651 struct footswitch *fs = &footswitches[pdev->id];
Matt Wagantallb82a5132011-12-12 22:26:41 -0800652 struct clk_data *clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700653
Matt Wagantallb82a5132011-12-12 22:26:41 -0800654 for (clock = fs->clk_data; clock->clk; clock++)
655 clk_put(clock->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700656 regulator_unregister(fs->rdev);
657
658 return 0;
659}
660
661static struct platform_driver footswitch_driver = {
662 .probe = footswitch_probe,
663 .remove = __devexit_p(footswitch_remove),
664 .driver = {
Matt Wagantall49722712011-08-17 18:50:53 -0700665 .name = "footswitch-8x60",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700666 .owner = THIS_MODULE,
667 },
668};
669
670static int __init late_footswitch_init(void)
671{
672 int i;
673
674 mutex_lock(&claim_lock);
675 /* Turn off all registered but unused footswitches. */
676 for (i = 0; i < ARRAY_SIZE(footswitches); i++)
677 if (footswitches[i].rdev && !footswitches[i].is_claimed)
Matt Wagantall7a261362011-07-14 19:07:10 -0700678 footswitches[i].rdev->desc->ops->
679 disable(footswitches[i].rdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700680 mutex_unlock(&claim_lock);
681
682 return 0;
683}
684late_initcall(late_footswitch_init);
685
686static int __init footswitch_init(void)
687{
688 return platform_driver_register(&footswitch_driver);
689}
690subsys_initcall(footswitch_init);
691
692static void __exit footswitch_exit(void)
693{
694 platform_driver_unregister(&footswitch_driver);
695}
696module_exit(footswitch_exit);
697
698MODULE_LICENSE("GPL v2");
699MODULE_DESCRIPTION("MSM8x60 rail footswitch");
700MODULE_ALIAS("platform:footswitch-msm8x60");