blob: 8bb2576f577b80beb3f5411d32ca0857874eb6d0 [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
13#include <linux/kernel.h>
14#include <linux/io.h>
15#include <linux/delay.h>
16#include <linux/platform_device.h>
17#include <linux/err.h>
18#include <linux/regulator/driver.h>
19#include <linux/regulator/machine.h>
20#include <linux/clk.h>
21#include <mach/msm_iomap.h>
22#include <mach/msm_bus_board.h>
23#include <mach/msm_bus.h>
24#include <mach/scm-io.h>
25#include "clock.h"
26#include "footswitch.h"
27
28#ifdef CONFIG_MSM_SECURE_IO
29#undef readl_relaxed
30#undef writel_relaxed
31#define readl_relaxed secure_readl
32#define writel_relaxed secure_writel
33#endif
34
35#define REG(off) (MSM_MMSS_CLK_CTL_BASE + (off))
36#define GEMINI_GFS_CTL_REG REG(0x01A0)
37#define GFX2D0_GFS_CTL_REG REG(0x0180)
38#define GFX2D1_GFS_CTL_REG REG(0x0184)
39#define GFX3D_GFS_CTL_REG REG(0x0188)
40#define MDP_GFS_CTL_REG REG(0x0190)
41#define ROT_GFS_CTL_REG REG(0x018C)
42#define VED_GFS_CTL_REG REG(0x0194)
43#define VFE_GFS_CTL_REG REG(0x0198)
44#define VPE_GFS_CTL_REG REG(0x019C)
45
46#define CLAMP_BIT BIT(5)
47#define ENABLE_BIT BIT(8)
48#define RETENTION_BIT BIT(9)
49
50#define RESET_DELAY_US 1
51/* Core clock rate to use if one has not previously been set. */
52#define DEFAULT_CLK_RATE 27000000
53
54/*
55 * Lock is only needed to protect against the first footswitch_enable()
56 * call occuring concurrently with late_footswitch_init().
57 */
58static DEFINE_MUTEX(claim_lock);
59
60struct clock_state {
61 int ahb_clk_en;
62 int axi_clk_en;
63 int core_clk_rate;
64};
65
66struct footswitch {
67 struct regulator_dev *rdev;
68 struct regulator_desc desc;
69 void *gfs_ctl_reg;
70 int bus_port1, bus_port2;
71 bool is_enabled;
72 bool is_claimed;
73 const char *core_clk_name;
74 const char *ahb_clk_name;
75 const char *axi_clk_name;
76 struct clk *core_clk;
77 struct clk *ahb_clk;
78 struct clk *axi_clk;
79 unsigned int reset_rate;
80 struct clock_state clk_state;
81 unsigned int gfs_delay_cnt:5;
82};
83
84static int setup_clocks(struct footswitch *fs)
85{
86 int rc = 0;
87
88 /*
89 * Enable all clocks in the power domain. If a core requires a
90 * specific clock rate when being reset, apply it.
91 */
92 fs->clk_state.core_clk_rate = clk_get_rate(fs->core_clk);
93 if (!fs->clk_state.core_clk_rate || fs->reset_rate) {
94 int rate = fs->reset_rate ? fs->reset_rate : DEFAULT_CLK_RATE;
95 rc = clk_set_rate(fs->core_clk, rate);
96 if (rc) {
97 pr_err("%s: Failed to set %s rate to %d Hz.\n",
98 __func__, fs->core_clk_name,
99 fs->reset_rate);
100 return rc;
101 }
102 }
103 clk_enable(fs->core_clk);
104
105 /*
106 * Some AHB and AXI clocks are for reset purposes only. These clocks
107 * will fail to enable. Keep track of them so we don't try to disable
108 * them later and crash.
109 */
110 fs->clk_state.ahb_clk_en = !clk_enable(fs->ahb_clk);
111 if (fs->axi_clk)
112 fs->clk_state.axi_clk_en = !clk_enable(fs->axi_clk);
113
114 return rc;
115}
116
117static void restore_clocks(struct footswitch *fs)
118{
119 /* Restore clocks to their orignal states before setup_clocks(). */
120 if (fs->axi_clk && fs->clk_state.axi_clk_en)
121 clk_disable(fs->axi_clk);
122 if (fs->clk_state.ahb_clk_en)
123 clk_disable(fs->ahb_clk);
124 clk_disable(fs->core_clk);
125 if (fs->clk_state.core_clk_rate) {
126 if (clk_set_rate(fs->core_clk, fs->clk_state.core_clk_rate))
127 pr_err("%s: Failed to restore %s rate.\n",
128 __func__, fs->core_clk_name);
129 }
130}
131
132static int footswitch_is_enabled(struct regulator_dev *rdev)
133{
134 struct footswitch *fs = rdev_get_drvdata(rdev);
135
136 return fs->is_enabled;
137}
138
139static int footswitch_enable(struct regulator_dev *rdev)
140{
141 struct footswitch *fs = rdev_get_drvdata(rdev);
142 uint32_t regval, rc = 0;
143
144 mutex_lock(&claim_lock);
145 fs->is_claimed = true;
146 mutex_unlock(&claim_lock);
147
Matt Wagantall88edea92011-07-21 10:29:56 -0700148 /* Return early if already enabled. */
149 regval = readl_relaxed(fs->gfs_ctl_reg);
150 if ((regval & (ENABLE_BIT | CLAMP_BIT)) == ENABLE_BIT)
151 return 0;
152
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700153 /* Make sure required clocks are on at the correct rates. */
154 rc = setup_clocks(fs);
155 if (rc)
156 goto out;
157
158 /* Un-halt all bus ports in the power domain. */
159 if (fs->bus_port1) {
160 rc = msm_bus_axi_portunhalt(fs->bus_port1);
161 if (rc) {
162 pr_err("%s: Port 1 unhalt failed.\n", __func__);
163 goto out;
164 }
165 }
166 if (fs->bus_port2) {
167 rc = msm_bus_axi_portunhalt(fs->bus_port2);
168 if (rc) {
169 pr_err("%s: Port 2 unhalt failed.\n", __func__);
170 goto out;
171 }
172 }
173
174 /*
175 * (Re-)Assert resets for all clocks in the clock domain, since
176 * footswitch_enable() is first called before footswitch_disable()
177 * and resets should be asserted before power is restored.
178 */
179 if (fs->axi_clk)
180 clk_reset(fs->axi_clk, CLK_RESET_ASSERT);
181 clk_reset(fs->ahb_clk, CLK_RESET_ASSERT);
182 clk_reset(fs->core_clk, CLK_RESET_ASSERT);
183 /* Wait for synchronous resets to propagate. */
184 udelay(RESET_DELAY_US);
185
186 /* Enable the power rail at the footswitch. */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700187 regval |= ENABLE_BIT;
188 writel_relaxed(regval, fs->gfs_ctl_reg);
189 /* Wait for the rail to fully charge. */
190 mb();
191 udelay(1);
192
193 /* Un-clamp the I/O ports. */
194 regval &= ~CLAMP_BIT;
195 writel_relaxed(regval, fs->gfs_ctl_reg);
196
197 /* Deassert resets for all clocks in the power domain. */
198 clk_reset(fs->core_clk, CLK_RESET_DEASSERT);
199 clk_reset(fs->ahb_clk, CLK_RESET_DEASSERT);
200 if (fs->axi_clk)
201 clk_reset(fs->axi_clk, CLK_RESET_DEASSERT);
202 /* Toggle core reset again after first power-on (required for GFX3D). */
203 if (fs->desc.id == FS_GFX3D) {
204 clk_reset(fs->core_clk, CLK_RESET_ASSERT);
205 udelay(RESET_DELAY_US);
206 clk_reset(fs->core_clk, CLK_RESET_DEASSERT);
207 udelay(RESET_DELAY_US);
208 }
209
210 /* Return clocks to their state before this function. */
211 restore_clocks(fs);
212
213 fs->is_enabled = true;
214out:
215 return rc;
216}
217
218static int footswitch_disable(struct regulator_dev *rdev)
219{
220 struct footswitch *fs = rdev_get_drvdata(rdev);
221 uint32_t regval, rc = 0;
222
Matt Wagantall88edea92011-07-21 10:29:56 -0700223 /* Return early if already disabled. */
224 regval = readl_relaxed(fs->gfs_ctl_reg);
225 if ((regval & ENABLE_BIT) == 0)
226 return 0;
227
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700228 /* Make sure required clocks are on at the correct rates. */
229 rc = setup_clocks(fs);
230 if (rc)
231 goto out;
232
233 /* Halt all bus ports in the power domain. */
234 if (fs->bus_port1) {
235 rc = msm_bus_axi_porthalt(fs->bus_port1);
236 if (rc) {
237 pr_err("%s: Port 1 halt failed.\n", __func__);
238 goto out;
239 }
240 }
241 if (fs->bus_port2) {
242 rc = msm_bus_axi_porthalt(fs->bus_port2);
243 if (rc) {
244 pr_err("%s: Port 1 halt failed.\n", __func__);
245 goto err_port2_halt;
246 }
247 }
248
249 /*
250 * Assert resets for all clocks in the clock domain so that
251 * outputs settle prior to clamping.
252 */
253 if (fs->axi_clk)
254 clk_reset(fs->axi_clk, CLK_RESET_ASSERT);
255 clk_reset(fs->ahb_clk, CLK_RESET_ASSERT);
256 clk_reset(fs->core_clk, CLK_RESET_ASSERT);
257 /* Wait for synchronous resets to propagate. */
258 udelay(RESET_DELAY_US);
259
260 /*
261 * Clamp the I/O ports of the core to ensure the values
262 * remain fixed while the core is collapsed.
263 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700264 regval |= CLAMP_BIT;
265 writel_relaxed(regval, fs->gfs_ctl_reg);
266
267 /* Collapse the power rail at the footswitch. */
268 regval &= ~ENABLE_BIT;
269 writel_relaxed(regval, fs->gfs_ctl_reg);
270
271 /* Return clocks to their state before this function. */
272 restore_clocks(fs);
273
274 fs->is_enabled = false;
275
276 return rc;
277
278err_port2_halt:
279 msm_bus_axi_portunhalt(fs->bus_port1);
280out:
281 return rc;
282}
283
284static int gfx2d_footswitch_enable(struct regulator_dev *rdev)
285{
286 struct footswitch *fs = rdev_get_drvdata(rdev);
287 uint32_t regval, rc = 0;
288
289 mutex_lock(&claim_lock);
290 fs->is_claimed = true;
291 mutex_unlock(&claim_lock);
292
Matt Wagantall88edea92011-07-21 10:29:56 -0700293 /* Return early if already enabled. */
294 regval = readl_relaxed(fs->gfs_ctl_reg);
295 if ((regval & (ENABLE_BIT | CLAMP_BIT)) == ENABLE_BIT)
296 return 0;
297
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298 /* Make sure required clocks are on at the correct rates. */
299 rc = setup_clocks(fs);
300 if (rc)
301 goto out;
302
303 /* Un-halt all bus ports in the power domain. */
304 if (fs->bus_port1) {
305 rc = msm_bus_axi_portunhalt(fs->bus_port1);
306 if (rc) {
307 pr_err("%s: Port 1 unhalt failed.\n", __func__);
308 goto out;
309 }
310 }
311
312 /* Disable core clock. */
313 clk_disable(fs->core_clk);
314
315 /*
316 * (Re-)Assert resets for all clocks in the clock domain, since
317 * footswitch_enable() is first called before footswitch_disable()
318 * and resets should be asserted before power is restored.
319 */
320 if (fs->axi_clk)
321 clk_reset(fs->axi_clk, CLK_RESET_ASSERT);
322 clk_reset(fs->ahb_clk, CLK_RESET_ASSERT);
323 clk_reset(fs->core_clk, CLK_RESET_ASSERT);
324 /* Wait for synchronous resets to propagate. */
325 udelay(20);
326
327 /* Enable the power rail at the footswitch. */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700328 regval |= ENABLE_BIT;
329 writel_relaxed(regval, fs->gfs_ctl_reg);
330 mb();
331 udelay(1);
332
333 /* Un-clamp the I/O ports. */
334 regval &= ~CLAMP_BIT;
335 writel_relaxed(regval, fs->gfs_ctl_reg);
336
337 /* Deassert resets for all clocks in the power domain. */
338 if (fs->axi_clk)
339 clk_reset(fs->axi_clk, CLK_RESET_DEASSERT);
340 clk_reset(fs->ahb_clk, CLK_RESET_DEASSERT);
341 clk_reset(fs->core_clk, CLK_RESET_DEASSERT);
342 udelay(20);
343
344 /* Re-enable core clock. */
345 clk_enable(fs->core_clk);
346
347 /* Return clocks to their state before this function. */
348 restore_clocks(fs);
349
350 fs->is_enabled = true;
351out:
352 return rc;
353}
354
355static int gfx2d_footswitch_disable(struct regulator_dev *rdev)
356{
357 struct footswitch *fs = rdev_get_drvdata(rdev);
358 uint32_t regval, rc = 0;
359
Matt Wagantall88edea92011-07-21 10:29:56 -0700360 /* Return early if already disabled. */
361 regval = readl_relaxed(fs->gfs_ctl_reg);
362 if ((regval & ENABLE_BIT) == 0)
363 return 0;
364
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700365 /* Make sure required clocks are on at the correct rates. */
366 rc = setup_clocks(fs);
367 if (rc)
368 goto out;
369
370 /* Halt all bus ports in the power domain. */
371 if (fs->bus_port1) {
372 rc = msm_bus_axi_porthalt(fs->bus_port1);
373 if (rc) {
374 pr_err("%s: Port 1 halt failed.\n", __func__);
375 goto out;
376 }
377 }
378
379 /* Disable core clock. */
380 clk_disable(fs->core_clk);
381
382 /*
383 * Assert resets for all clocks in the clock domain so that
384 * outputs settle prior to clamping.
385 */
386 if (fs->axi_clk)
387 clk_reset(fs->axi_clk, CLK_RESET_ASSERT);
388 clk_reset(fs->ahb_clk, CLK_RESET_ASSERT);
389 clk_reset(fs->core_clk, CLK_RESET_ASSERT);
390 /* Wait for synchronous resets to propagate. */
391 udelay(20);
392
393 /*
394 * Clamp the I/O ports of the core to ensure the values
395 * remain fixed while the core is collapsed.
396 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700397 regval |= CLAMP_BIT;
398 writel_relaxed(regval, fs->gfs_ctl_reg);
399
400 /* Collapse the power rail at the footswitch. */
401 regval &= ~ENABLE_BIT;
402 writel_relaxed(regval, fs->gfs_ctl_reg);
403
404 /* Re-enable core clock. */
405 clk_enable(fs->core_clk);
406
407 /* Return clocks to their state before this function. */
408 restore_clocks(fs);
409
410 fs->is_enabled = false;
411
412out:
413 return rc;
414}
415
416static struct regulator_ops standard_fs_ops = {
417 .is_enabled = footswitch_is_enabled,
418 .enable = footswitch_enable,
419 .disable = footswitch_disable,
420};
421
422static struct regulator_ops gfx2d_fs_ops = {
423 .is_enabled = footswitch_is_enabled,
424 .enable = gfx2d_footswitch_enable,
425 .disable = gfx2d_footswitch_disable,
426};
427
428#define FOOTSWITCH(_id, _name, _ops, _gfs_ctl_reg, _dc, _bp1, _bp2, \
429 _core_clk, _ahb_clk, _axi_clk, _reset_rate) \
430 [(_id)] = { \
431 .desc = { \
432 .id = (_id), \
433 .name = (_name), \
434 .ops = (_ops), \
435 .type = REGULATOR_VOLTAGE, \
436 .owner = THIS_MODULE, \
437 }, \
438 .gfs_ctl_reg = (_gfs_ctl_reg), \
439 .gfs_delay_cnt = (_dc), \
440 .bus_port1 = (_bp1), \
441 .bus_port2 = (_bp2), \
442 .core_clk_name = (_core_clk), \
443 .ahb_clk_name = (_ahb_clk), \
444 .axi_clk_name = (_axi_clk), \
445 .reset_rate = (_reset_rate), \
446 }
447static struct footswitch footswitches[] = {
448 FOOTSWITCH(FS_GFX2D0, "fs_gfx2d0", &gfx2d_fs_ops,
449 GFX2D0_GFS_CTL_REG, 31,
450 MSM_BUS_MASTER_GRAPHICS_2D_CORE0, 0,
451 "gfx2d0_clk", "gfx2d0_pclk", NULL, 0),
452 FOOTSWITCH(FS_GFX2D1, "fs_gfx2d1", &gfx2d_fs_ops,
453 GFX2D1_GFS_CTL_REG, 31,
454 MSM_BUS_MASTER_GRAPHICS_2D_CORE1, 0,
455 "gfx2d1_clk", "gfx2d1_pclk", NULL, 0),
456 FOOTSWITCH(FS_GFX3D, "fs_gfx3d", &standard_fs_ops,
457 GFX3D_GFS_CTL_REG, 31,
458 MSM_BUS_MASTER_GRAPHICS_3D, 0,
459 "gfx3d_clk", "gfx3d_pclk", NULL, 27000000),
460 FOOTSWITCH(FS_IJPEG, "fs_ijpeg", &standard_fs_ops,
461 GEMINI_GFS_CTL_REG, 31,
462 MSM_BUS_MASTER_JPEG_ENC, 0,
463 "ijpeg_clk", "ijpeg_pclk", "ijpeg_axi_clk", 0),
464 FOOTSWITCH(FS_MDP, "fs_mdp", &standard_fs_ops,
465 MDP_GFS_CTL_REG, 31,
466 MSM_BUS_MASTER_MDP_PORT0,
467 MSM_BUS_MASTER_MDP_PORT1,
468 "mdp_clk", "mdp_pclk", "mdp_axi_clk", 0),
469 FOOTSWITCH(FS_ROT, "fs_rot", &standard_fs_ops,
470 ROT_GFS_CTL_REG, 31,
471 MSM_BUS_MASTER_ROTATOR, 0,
472 "rot_clk", "rotator_pclk", "rot_axi_clk", 0),
473 FOOTSWITCH(FS_VED, "fs_ved", &standard_fs_ops,
474 VED_GFS_CTL_REG, 31,
475 MSM_BUS_MASTER_HD_CODEC_PORT0,
476 MSM_BUS_MASTER_HD_CODEC_PORT1,
477 "vcodec_clk", "vcodec_pclk", "vcodec_axi_clk", 0),
478 FOOTSWITCH(FS_VFE, "fs_vfe", &standard_fs_ops,
479 VFE_GFS_CTL_REG, 31,
480 MSM_BUS_MASTER_VFE, 0,
481 "vfe_clk", "vfe_pclk", "vfe_axi_clk", 0),
482 FOOTSWITCH(FS_VPE, "fs_vpe", &standard_fs_ops,
483 VPE_GFS_CTL_REG, 31,
484 MSM_BUS_MASTER_VPE, 0,
485 "vpe_clk", "vpe_pclk", "vpe_axi_clk", 0),
486};
487
488static int footswitch_probe(struct platform_device *pdev)
489{
490 struct footswitch *fs;
491 struct regulator_init_data *init_data;
492 uint32_t regval, rc = 0;
493
494 if (pdev == NULL)
495 return -EINVAL;
496
497 if (pdev->id >= MAX_FS)
498 return -ENODEV;
499
500 fs = &footswitches[pdev->id];
501 init_data = pdev->dev.platform_data;
502
503 /* Setup core clock. */
504 fs->core_clk = clk_get(NULL, fs->core_clk_name);
505 if (IS_ERR(fs->core_clk)) {
506 pr_err("%s: clk_get(\"%s\") failed\n", __func__,
507 fs->core_clk_name);
508 rc = PTR_ERR(fs->core_clk);
509 goto err_core_clk;
510 }
511
512 /* Setup AHB clock. */
513 fs->ahb_clk = clk_get(NULL, fs->ahb_clk_name);
514 if (IS_ERR(fs->ahb_clk)) {
515 pr_err("%s: clk_get(\"%s\") failed\n", __func__,
516 fs->ahb_clk_name);
517 rc = PTR_ERR(fs->ahb_clk);
518 goto err_ahb_clk;
519 }
520
521 /* Setup AXI clock. */
522 if (fs->axi_clk_name) {
523 fs->axi_clk = clk_get(NULL, fs->axi_clk_name);
524 if (IS_ERR(fs->axi_clk)) {
525 pr_err("%s: clk_get(\"%s\") failed\n", __func__,
526 fs->axi_clk_name);
527 rc = PTR_ERR(fs->axi_clk);
528 goto err_axi_clk;
529 }
530 }
531
532 /*
533 * Set number of AHB_CLK cycles to delay the assertion of gfs_en_all
534 * after enabling the footswitch. Also ensure the retention bit is
535 * clear so disabling the footswitch will power-collapse the core.
536 */
537 regval = readl_relaxed(fs->gfs_ctl_reg);
538 regval |= fs->gfs_delay_cnt;
539 regval &= ~RETENTION_BIT;
540 writel_relaxed(regval, fs->gfs_ctl_reg);
541
542 fs->rdev = regulator_register(&fs->desc, &pdev->dev, init_data, fs);
543 if (IS_ERR(footswitches[pdev->id].rdev)) {
544 pr_err("%s: regulator_register(\"%s\") failed\n",
545 __func__, fs->desc.name);
546 rc = PTR_ERR(footswitches[pdev->id].rdev);
547 goto err_register;
548 }
549
550 return 0;
551
552err_register:
553 if (fs->axi_clk_name)
554 clk_put(fs->axi_clk);
555err_axi_clk:
556 clk_put(fs->ahb_clk);
557err_ahb_clk:
558 clk_put(fs->core_clk);
559err_core_clk:
560 return rc;
561}
562
563static int __devexit footswitch_remove(struct platform_device *pdev)
564{
565 struct footswitch *fs = &footswitches[pdev->id];
566
567 clk_put(fs->core_clk);
568 clk_put(fs->ahb_clk);
569 if (fs->axi_clk)
570 clk_put(fs->axi_clk);
571
572 regulator_unregister(fs->rdev);
573
574 return 0;
575}
576
577static struct platform_driver footswitch_driver = {
578 .probe = footswitch_probe,
579 .remove = __devexit_p(footswitch_remove),
580 .driver = {
581 .name = "footswitch-msm8x60",
582 .owner = THIS_MODULE,
583 },
584};
585
586static int __init late_footswitch_init(void)
587{
588 int i;
589
590 mutex_lock(&claim_lock);
591 /* Turn off all registered but unused footswitches. */
592 for (i = 0; i < ARRAY_SIZE(footswitches); i++)
593 if (footswitches[i].rdev && !footswitches[i].is_claimed)
Matt Wagantall7a261362011-07-14 19:07:10 -0700594 footswitches[i].rdev->desc->ops->
595 disable(footswitches[i].rdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700596 mutex_unlock(&claim_lock);
597
598 return 0;
599}
600late_initcall(late_footswitch_init);
601
602static int __init footswitch_init(void)
603{
604 return platform_driver_register(&footswitch_driver);
605}
606subsys_initcall(footswitch_init);
607
608static void __exit footswitch_exit(void)
609{
610 platform_driver_unregister(&footswitch_driver);
611}
612module_exit(footswitch_exit);
613
614MODULE_LICENSE("GPL v2");
615MODULE_DESCRIPTION("MSM8x60 rail footswitch");
616MODULE_ALIAS("platform:footswitch-msm8x60");