blob: 7f63dc82c2272abbc8991f296ff58128c99e9cac [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++)
Stephen Boyd0c629382011-12-28 19:15:57 -0800187 ; /* Do nothing */
188 for (clock--; clock >= fs->clk_data; clock--)
Matt Wagantallb82a5132011-12-12 22:26:41 -0800189 clk_reset(clock->clk, CLK_RESET_ASSERT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190 /* Wait for synchronous resets to propagate. */
191 udelay(RESET_DELAY_US);
192
193 /* Enable the power rail at the footswitch. */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700194 regval |= ENABLE_BIT;
195 writel_relaxed(regval, fs->gfs_ctl_reg);
196 /* Wait for the rail to fully charge. */
197 mb();
198 udelay(1);
199
200 /* Un-clamp the I/O ports. */
201 regval &= ~CLAMP_BIT;
202 writel_relaxed(regval, fs->gfs_ctl_reg);
203
204 /* Deassert resets for all clocks in the power domain. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800205 for (clock = fs->clk_data; clock->clk; clock++)
206 clk_reset(clock->clk, CLK_RESET_DEASSERT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700207 /* Toggle core reset again after first power-on (required for GFX3D). */
208 if (fs->desc.id == FS_GFX3D) {
209 clk_reset(fs->core_clk, CLK_RESET_ASSERT);
210 udelay(RESET_DELAY_US);
211 clk_reset(fs->core_clk, CLK_RESET_DEASSERT);
212 udelay(RESET_DELAY_US);
213 }
214
215 /* Return clocks to their state before this function. */
216 restore_clocks(fs);
217
218 fs->is_enabled = true;
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800219 return 0;
220
221err_port2_halt:
Matt Wagantallb82a5132011-12-12 22:26:41 -0800222 msm_bus_axi_porthalt(fs->bus_port0);
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800223err:
224 restore_clocks(fs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700225 return rc;
226}
227
228static int footswitch_disable(struct regulator_dev *rdev)
229{
230 struct footswitch *fs = rdev_get_drvdata(rdev);
Matt Wagantallb82a5132011-12-12 22:26:41 -0800231 struct clk_data *clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700232 uint32_t regval, rc = 0;
233
Matt Wagantall88edea92011-07-21 10:29:56 -0700234 /* Return early if already disabled. */
235 regval = readl_relaxed(fs->gfs_ctl_reg);
236 if ((regval & ENABLE_BIT) == 0)
237 return 0;
238
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700239 /* Make sure required clocks are on at the correct rates. */
240 rc = setup_clocks(fs);
241 if (rc)
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800242 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700243
244 /* Halt all bus ports in the power domain. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800245 if (fs->bus_port0) {
246 rc = msm_bus_axi_porthalt(fs->bus_port0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700247 if (rc) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800248 pr_err("Port 0 halt failed.\n");
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800249 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700250 }
251 }
Matt Wagantallb82a5132011-12-12 22:26:41 -0800252 if (fs->bus_port1) {
253 rc = msm_bus_axi_porthalt(fs->bus_port1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254 if (rc) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800255 pr_err("Port 1 halt failed.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700256 goto err_port2_halt;
257 }
258 }
259
260 /*
261 * Assert resets for all clocks in the clock domain so that
262 * outputs settle prior to clamping.
263 */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800264 for (clock = fs->clk_data; clock->clk; clock++)
Stephen Boyd0c629382011-12-28 19:15:57 -0800265 ; /* Do nothing */
266 for (clock--; clock >= fs->clk_data; clock--)
Matt Wagantallb82a5132011-12-12 22:26:41 -0800267 clk_reset(clock->clk, CLK_RESET_ASSERT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268 /* Wait for synchronous resets to propagate. */
269 udelay(RESET_DELAY_US);
270
271 /*
Matt Wagantall1ab7d942011-12-02 17:59:57 -0800272 * Return clocks to their state before this function. For robustness
273 * if memory-retention across collapses is required, clocks should
274 * be disabled before asserting the clamps. Assuming clocks were off
275 * before entering footswitch_disable(), this will be true.
276 */
277 restore_clocks(fs);
278
279 /*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700280 * Clamp the I/O ports of the core to ensure the values
281 * remain fixed while the core is collapsed.
282 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700283 regval |= CLAMP_BIT;
284 writel_relaxed(regval, fs->gfs_ctl_reg);
285
286 /* Collapse the power rail at the footswitch. */
287 regval &= ~ENABLE_BIT;
288 writel_relaxed(regval, fs->gfs_ctl_reg);
289
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290 fs->is_enabled = false;
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800291 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700292
293err_port2_halt:
Matt Wagantallb82a5132011-12-12 22:26:41 -0800294 msm_bus_axi_portunhalt(fs->bus_port0);
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800295err:
296 restore_clocks(fs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700297 return rc;
298}
299
300static int gfx2d_footswitch_enable(struct regulator_dev *rdev)
301{
302 struct footswitch *fs = rdev_get_drvdata(rdev);
Matt Wagantallb82a5132011-12-12 22:26:41 -0800303 struct clk_data *clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700304 uint32_t regval, rc = 0;
305
306 mutex_lock(&claim_lock);
307 fs->is_claimed = true;
308 mutex_unlock(&claim_lock);
309
Matt Wagantall88edea92011-07-21 10:29:56 -0700310 /* Return early if already enabled. */
311 regval = readl_relaxed(fs->gfs_ctl_reg);
312 if ((regval & (ENABLE_BIT | CLAMP_BIT)) == ENABLE_BIT)
313 return 0;
314
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315 /* Make sure required clocks are on at the correct rates. */
316 rc = setup_clocks(fs);
317 if (rc)
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800318 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319
320 /* Un-halt all bus ports in the power domain. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800321 if (fs->bus_port0) {
322 rc = msm_bus_axi_portunhalt(fs->bus_port0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700323 if (rc) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800324 pr_err("Port 0 unhalt failed.\n");
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800325 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700326 }
327 }
328
329 /* Disable core clock. */
330 clk_disable(fs->core_clk);
331
332 /*
333 * (Re-)Assert resets for all clocks in the clock domain, since
334 * footswitch_enable() is first called before footswitch_disable()
335 * and resets should be asserted before power is restored.
336 */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800337 for (clock = fs->clk_data; clock->clk; clock++)
Stephen Boyd0c629382011-12-28 19:15:57 -0800338 ; /* Do nothing */
339 for (clock--; clock >= fs->clk_data; clock--)
Matt Wagantallb82a5132011-12-12 22:26:41 -0800340 clk_reset(clock->clk, CLK_RESET_ASSERT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700341 /* Wait for synchronous resets to propagate. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800342 udelay(RESET_DELAY_US);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700343
344 /* Enable the power rail at the footswitch. */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700345 regval |= ENABLE_BIT;
346 writel_relaxed(regval, fs->gfs_ctl_reg);
347 mb();
348 udelay(1);
349
350 /* Un-clamp the I/O ports. */
351 regval &= ~CLAMP_BIT;
352 writel_relaxed(regval, fs->gfs_ctl_reg);
353
354 /* Deassert resets for all clocks in the power domain. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800355 for (clock = fs->clk_data; clock->clk; clock++)
356 clk_reset(clock->clk, CLK_RESET_DEASSERT);
357 udelay(RESET_DELAY_US);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700358
359 /* Re-enable core clock. */
360 clk_enable(fs->core_clk);
361
362 /* Return clocks to their state before this function. */
363 restore_clocks(fs);
364
365 fs->is_enabled = true;
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800366 return 0;
367
368err:
369 restore_clocks(fs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700370 return rc;
371}
372
373static int gfx2d_footswitch_disable(struct regulator_dev *rdev)
374{
375 struct footswitch *fs = rdev_get_drvdata(rdev);
Matt Wagantallb82a5132011-12-12 22:26:41 -0800376 struct clk_data *clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700377 uint32_t regval, rc = 0;
378
Matt Wagantall88edea92011-07-21 10:29:56 -0700379 /* Return early if already disabled. */
380 regval = readl_relaxed(fs->gfs_ctl_reg);
381 if ((regval & ENABLE_BIT) == 0)
382 return 0;
383
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384 /* Make sure required clocks are on at the correct rates. */
385 rc = setup_clocks(fs);
386 if (rc)
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800387 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388
389 /* Halt all bus ports in the power domain. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800390 if (fs->bus_port0) {
391 rc = msm_bus_axi_porthalt(fs->bus_port0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700392 if (rc) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800393 pr_err("Port 0 halt failed.\n");
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800394 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700395 }
396 }
397
398 /* Disable core clock. */
399 clk_disable(fs->core_clk);
400
401 /*
402 * Assert resets for all clocks in the clock domain so that
403 * outputs settle prior to clamping.
404 */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800405 for (clock = fs->clk_data; clock->clk; clock++)
Stephen Boyd0c629382011-12-28 19:15:57 -0800406 ; /* Do nothing */
407 for (clock--; clock >= fs->clk_data; clock--)
Matt Wagantallb82a5132011-12-12 22:26:41 -0800408 clk_reset(clock->clk, CLK_RESET_ASSERT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700409 /* Wait for synchronous resets to propagate. */
Matt Wagantallb82a5132011-12-12 22:26:41 -0800410 udelay(5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700411
412 /*
413 * Clamp the I/O ports of the core to ensure the values
414 * remain fixed while the core is collapsed.
415 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700416 regval |= CLAMP_BIT;
417 writel_relaxed(regval, fs->gfs_ctl_reg);
418
419 /* Collapse the power rail at the footswitch. */
420 regval &= ~ENABLE_BIT;
421 writel_relaxed(regval, fs->gfs_ctl_reg);
422
423 /* Re-enable core clock. */
424 clk_enable(fs->core_clk);
425
426 /* Return clocks to their state before this function. */
427 restore_clocks(fs);
428
429 fs->is_enabled = false;
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800430 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700431
Stephen Boyd2fc19e82011-12-07 17:38:38 -0800432err:
433 restore_clocks(fs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700434 return rc;
435}
436
437static struct regulator_ops standard_fs_ops = {
438 .is_enabled = footswitch_is_enabled,
439 .enable = footswitch_enable,
440 .disable = footswitch_disable,
441};
442
443static struct regulator_ops gfx2d_fs_ops = {
444 .is_enabled = footswitch_is_enabled,
445 .enable = gfx2d_footswitch_enable,
446 .disable = gfx2d_footswitch_disable,
447};
448
Matt Wagantallb82a5132011-12-12 22:26:41 -0800449/*
450 * Lists of required clocks for the collapse and restore sequences.
451 *
452 * Order matters here. Clocks are listed in the same order as their
453 * resets will be de-asserted when the core is restored. Also, rate-
454 * settable clocks must be listed before any of the branches that
455 * are derived from them. Otherwise, the branches may fail to enable
456 * if their parent's rate is not yet set.
457 */
458
459static struct clk_data gfx2d0_clks[] = {
460 { .name = "core_clk" },
461 { .name = "iface_clk" },
462 { 0 }
463};
464
465static struct clk_data gfx2d1_clks[] = {
466 { .name = "core_clk" },
467 { .name = "iface_clk" },
468 { 0 }
469};
470
471static struct clk_data gfx3d_clks[] = {
472 { .name = "core_clk", .reset_rate = 27000000 },
473 { .name = "iface_clk" },
474 { 0 }
475};
476
477
478static struct clk_data ijpeg_clks[] = {
479 { .name = "core_clk" },
480 { .name = "iface_clk" },
481 { .name = "bus_clk" },
482 { 0 }
483};
484
485static struct clk_data mdp_8960_clks[] = {
486 { .name = "core_clk" },
487 { .name = "iface_clk" },
488 { .name = "bus_clk" },
489 { .name = "vsync_clk" },
490 { .name = "lut_clk" },
491 { .name = "tv_src_clk" },
492 { .name = "tv_clk" },
493 { 0 }
494};
495
496static struct clk_data mdp_8660_clks[] = {
497 { .name = "core_clk" },
498 { .name = "iface_clk" },
499 { .name = "bus_clk" },
500 { .name = "vsync_clk" },
501 { .name = "tv_src_clk" },
502 { .name = "tv_clk" },
503 { .name = "pixel_mdp_clk" },
504 { .name = "pixel_lcdc_clk" },
505 { 0 }
506};
507
508static struct clk_data rot_clks[] = {
509 { .name = "core_clk" },
510 { .name = "iface_clk" },
511 { .name = "bus_clk" },
512 { 0 }
513};
514
Gopikrishnaiah Anandan83b6e852012-01-05 17:47:02 -0800515static struct clk_data ved_clks[] = {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800516 { .name = "core_clk" },
517 { .name = "iface_clk" },
518 { .name = "bus_clk" },
519 { 0 }
520};
521
522static struct clk_data vfe_clks[] = {
523 { .name = "core_clk" },
524 { .name = "iface_clk" },
525 { .name = "bus_clk" },
526 { 0 }
527};
528
529static struct clk_data vpe_clks[] = {
530 { .name = "core_clk" },
531 { .name = "iface_clk" },
532 { .name = "bus_clk" },
533 { 0 }
534};
535
536static struct clk_data vcap_clks[] = {
537 { .name = "core_clk" },
538 { .name = "iface_clk" },
539 { .name = "bus_clk" },
540 { 0 }
541};
542
543#define FOOTSWITCH(_id, _name, _ops, _gfs_ctl_reg, _dc, _clk_data, \
544 _bp1, _bp2) \
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700545 [(_id)] = { \
546 .desc = { \
547 .id = (_id), \
548 .name = (_name), \
549 .ops = (_ops), \
550 .type = REGULATOR_VOLTAGE, \
551 .owner = THIS_MODULE, \
552 }, \
553 .gfs_ctl_reg = (_gfs_ctl_reg), \
554 .gfs_delay_cnt = (_dc), \
Matt Wagantallb82a5132011-12-12 22:26:41 -0800555 .clk_data = (_clk_data), \
556 .bus_port0 = (_bp1), \
557 .bus_port1 = (_bp2), \
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700558 }
559static struct footswitch footswitches[] = {
560 FOOTSWITCH(FS_GFX2D0, "fs_gfx2d0", &gfx2d_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800561 GFX2D0_GFS_CTL_REG, 31, gfx2d0_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700562 MSM_BUS_MASTER_GRAPHICS_2D_CORE0, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700563 FOOTSWITCH(FS_GFX2D1, "fs_gfx2d1", &gfx2d_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800564 GFX2D1_GFS_CTL_REG, 31, gfx2d1_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700565 MSM_BUS_MASTER_GRAPHICS_2D_CORE1, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700566 FOOTSWITCH(FS_GFX3D, "fs_gfx3d", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800567 GFX3D_GFS_CTL_REG, 31, gfx3d_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700568 MSM_BUS_MASTER_GRAPHICS_3D, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700569 FOOTSWITCH(FS_IJPEG, "fs_ijpeg", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800570 GEMINI_GFS_CTL_REG, 31, ijpeg_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700571 MSM_BUS_MASTER_JPEG_ENC, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700572 FOOTSWITCH(FS_MDP, "fs_mdp", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800573 MDP_GFS_CTL_REG, 31, NULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700574 MSM_BUS_MASTER_MDP_PORT0,
Matt Wagantall49722712011-08-17 18:50:53 -0700575 MSM_BUS_MASTER_MDP_PORT1),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700576 FOOTSWITCH(FS_ROT, "fs_rot", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800577 ROT_GFS_CTL_REG, 31, rot_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700578 MSM_BUS_MASTER_ROTATOR, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700579 FOOTSWITCH(FS_VED, "fs_ved", &standard_fs_ops,
Gopikrishnaiah Anandan83b6e852012-01-05 17:47:02 -0800580 VED_GFS_CTL_REG, 31, ved_clks,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700581 MSM_BUS_MASTER_HD_CODEC_PORT0,
Matt Wagantall49722712011-08-17 18:50:53 -0700582 MSM_BUS_MASTER_HD_CODEC_PORT1),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700583 FOOTSWITCH(FS_VFE, "fs_vfe", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800584 VFE_GFS_CTL_REG, 31, vfe_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700585 MSM_BUS_MASTER_VFE, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700586 FOOTSWITCH(FS_VPE, "fs_vpe", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800587 VPE_GFS_CTL_REG, 31, vpe_clks,
Matt Wagantall49722712011-08-17 18:50:53 -0700588 MSM_BUS_MASTER_VPE, 0),
Matt Wagantall37f34b32011-08-23 18:14:47 -0700589 FOOTSWITCH(FS_VCAP, "fs_vcap", &standard_fs_ops,
Matt Wagantallb82a5132011-12-12 22:26:41 -0800590 VCAP_GFS_CTL_REG, 31, vcap_clks,
Matt Wagantall37f34b32011-08-23 18:14:47 -0700591 MSM_BUS_MASTER_VIDEO_CAP, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700592};
593
594static int footswitch_probe(struct platform_device *pdev)
595{
596 struct footswitch *fs;
597 struct regulator_init_data *init_data;
Matt Wagantallb82a5132011-12-12 22:26:41 -0800598 struct clk_data *clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700599 uint32_t regval, rc = 0;
600
601 if (pdev == NULL)
602 return -EINVAL;
603
604 if (pdev->id >= MAX_FS)
605 return -ENODEV;
606
607 fs = &footswitches[pdev->id];
608 init_data = pdev->dev.platform_data;
609
Matt Wagantallb82a5132011-12-12 22:26:41 -0800610 if (pdev->id == FS_MDP) {
611 if (cpu_is_msm8960() || cpu_is_msm8930())
612 fs->clk_data = mdp_8960_clks;
613 else if (cpu_is_msm8x60())
614 fs->clk_data = mdp_8660_clks;
615 else
616 BUG();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700617 }
618
Matt Wagantallb82a5132011-12-12 22:26:41 -0800619 for (clock = fs->clk_data; clock->name; clock++) {
620 clock->clk = clk_get(&pdev->dev, clock->name);
621 if (IS_ERR(clock->clk)) {
622 rc = PTR_ERR(clock->clk);
623 pr_err("clk_get(%s) failed\n", clock->name);
624 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700625 }
Matt Wagantallb82a5132011-12-12 22:26:41 -0800626 if (!strncmp(clock->name, "core_clk", 8))
627 fs->core_clk = clock->clk;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700628 }
629
630 /*
631 * Set number of AHB_CLK cycles to delay the assertion of gfs_en_all
632 * after enabling the footswitch. Also ensure the retention bit is
633 * clear so disabling the footswitch will power-collapse the core.
634 */
635 regval = readl_relaxed(fs->gfs_ctl_reg);
636 regval |= fs->gfs_delay_cnt;
637 regval &= ~RETENTION_BIT;
638 writel_relaxed(regval, fs->gfs_ctl_reg);
639
640 fs->rdev = regulator_register(&fs->desc, &pdev->dev, init_data, fs);
641 if (IS_ERR(footswitches[pdev->id].rdev)) {
Matt Wagantallb82a5132011-12-12 22:26:41 -0800642 pr_err("regulator_register(\"%s\") failed\n",
643 fs->desc.name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700644 rc = PTR_ERR(footswitches[pdev->id].rdev);
Matt Wagantallb82a5132011-12-12 22:26:41 -0800645 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700646 }
647
648 return 0;
649
Matt Wagantallb82a5132011-12-12 22:26:41 -0800650err:
651 for (clock = fs->clk_data; clock->clk; clock++)
652 clk_put(clock->clk);
653
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700654 return rc;
655}
656
657static int __devexit footswitch_remove(struct platform_device *pdev)
658{
659 struct footswitch *fs = &footswitches[pdev->id];
Matt Wagantallb82a5132011-12-12 22:26:41 -0800660 struct clk_data *clock;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700661
Matt Wagantallb82a5132011-12-12 22:26:41 -0800662 for (clock = fs->clk_data; clock->clk; clock++)
663 clk_put(clock->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700664 regulator_unregister(fs->rdev);
665
666 return 0;
667}
668
669static struct platform_driver footswitch_driver = {
670 .probe = footswitch_probe,
671 .remove = __devexit_p(footswitch_remove),
672 .driver = {
Matt Wagantall49722712011-08-17 18:50:53 -0700673 .name = "footswitch-8x60",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700674 .owner = THIS_MODULE,
675 },
676};
677
678static int __init late_footswitch_init(void)
679{
680 int i;
681
682 mutex_lock(&claim_lock);
683 /* Turn off all registered but unused footswitches. */
684 for (i = 0; i < ARRAY_SIZE(footswitches); i++)
685 if (footswitches[i].rdev && !footswitches[i].is_claimed)
Matt Wagantall7a261362011-07-14 19:07:10 -0700686 footswitches[i].rdev->desc->ops->
687 disable(footswitches[i].rdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700688 mutex_unlock(&claim_lock);
689
690 return 0;
691}
692late_initcall(late_footswitch_init);
693
694static int __init footswitch_init(void)
695{
696 return platform_driver_register(&footswitch_driver);
697}
698subsys_initcall(footswitch_init);
699
700static void __exit footswitch_exit(void)
701{
702 platform_driver_unregister(&footswitch_driver);
703}
704module_exit(footswitch_exit);
705
706MODULE_LICENSE("GPL v2");
707MODULE_DESCRIPTION("MSM8x60 rail footswitch");
708MODULE_ALIAS("platform:footswitch-msm8x60");