blob: 6ba396298f906bb640fe26d1fb71fe11da455739 [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
148 /* Make sure required clocks are on at the correct rates. */
149 rc = setup_clocks(fs);
150 if (rc)
151 goto out;
152
153 /* Un-halt all bus ports in the power domain. */
154 if (fs->bus_port1) {
155 rc = msm_bus_axi_portunhalt(fs->bus_port1);
156 if (rc) {
157 pr_err("%s: Port 1 unhalt failed.\n", __func__);
158 goto out;
159 }
160 }
161 if (fs->bus_port2) {
162 rc = msm_bus_axi_portunhalt(fs->bus_port2);
163 if (rc) {
164 pr_err("%s: Port 2 unhalt failed.\n", __func__);
165 goto out;
166 }
167 }
168
169 /*
170 * (Re-)Assert resets for all clocks in the clock domain, since
171 * footswitch_enable() is first called before footswitch_disable()
172 * and resets should be asserted before power is restored.
173 */
174 if (fs->axi_clk)
175 clk_reset(fs->axi_clk, CLK_RESET_ASSERT);
176 clk_reset(fs->ahb_clk, CLK_RESET_ASSERT);
177 clk_reset(fs->core_clk, CLK_RESET_ASSERT);
178 /* Wait for synchronous resets to propagate. */
179 udelay(RESET_DELAY_US);
180
181 /* Enable the power rail at the footswitch. */
182 regval = readl_relaxed(fs->gfs_ctl_reg);
183 regval |= ENABLE_BIT;
184 writel_relaxed(regval, fs->gfs_ctl_reg);
185 /* Wait for the rail to fully charge. */
186 mb();
187 udelay(1);
188
189 /* Un-clamp the I/O ports. */
190 regval &= ~CLAMP_BIT;
191 writel_relaxed(regval, fs->gfs_ctl_reg);
192
193 /* Deassert resets for all clocks in the power domain. */
194 clk_reset(fs->core_clk, CLK_RESET_DEASSERT);
195 clk_reset(fs->ahb_clk, CLK_RESET_DEASSERT);
196 if (fs->axi_clk)
197 clk_reset(fs->axi_clk, CLK_RESET_DEASSERT);
198 /* Toggle core reset again after first power-on (required for GFX3D). */
199 if (fs->desc.id == FS_GFX3D) {
200 clk_reset(fs->core_clk, CLK_RESET_ASSERT);
201 udelay(RESET_DELAY_US);
202 clk_reset(fs->core_clk, CLK_RESET_DEASSERT);
203 udelay(RESET_DELAY_US);
204 }
205
206 /* Return clocks to their state before this function. */
207 restore_clocks(fs);
208
209 fs->is_enabled = true;
210out:
211 return rc;
212}
213
214static int footswitch_disable(struct regulator_dev *rdev)
215{
216 struct footswitch *fs = rdev_get_drvdata(rdev);
217 uint32_t regval, rc = 0;
218
219 /* Make sure required clocks are on at the correct rates. */
220 rc = setup_clocks(fs);
221 if (rc)
222 goto out;
223
224 /* Halt all bus ports in the power domain. */
225 if (fs->bus_port1) {
226 rc = msm_bus_axi_porthalt(fs->bus_port1);
227 if (rc) {
228 pr_err("%s: Port 1 halt failed.\n", __func__);
229 goto out;
230 }
231 }
232 if (fs->bus_port2) {
233 rc = msm_bus_axi_porthalt(fs->bus_port2);
234 if (rc) {
235 pr_err("%s: Port 1 halt failed.\n", __func__);
236 goto err_port2_halt;
237 }
238 }
239
240 /*
241 * Assert resets for all clocks in the clock domain so that
242 * outputs settle prior to clamping.
243 */
244 if (fs->axi_clk)
245 clk_reset(fs->axi_clk, CLK_RESET_ASSERT);
246 clk_reset(fs->ahb_clk, CLK_RESET_ASSERT);
247 clk_reset(fs->core_clk, CLK_RESET_ASSERT);
248 /* Wait for synchronous resets to propagate. */
249 udelay(RESET_DELAY_US);
250
251 /*
252 * Clamp the I/O ports of the core to ensure the values
253 * remain fixed while the core is collapsed.
254 */
255 regval = readl_relaxed(fs->gfs_ctl_reg);
256 regval |= CLAMP_BIT;
257 writel_relaxed(regval, fs->gfs_ctl_reg);
258
259 /* Collapse the power rail at the footswitch. */
260 regval &= ~ENABLE_BIT;
261 writel_relaxed(regval, fs->gfs_ctl_reg);
262
263 /* Return clocks to their state before this function. */
264 restore_clocks(fs);
265
266 fs->is_enabled = false;
267
268 return rc;
269
270err_port2_halt:
271 msm_bus_axi_portunhalt(fs->bus_port1);
272out:
273 return rc;
274}
275
276static int gfx2d_footswitch_enable(struct regulator_dev *rdev)
277{
278 struct footswitch *fs = rdev_get_drvdata(rdev);
279 uint32_t regval, rc = 0;
280
281 mutex_lock(&claim_lock);
282 fs->is_claimed = true;
283 mutex_unlock(&claim_lock);
284
285 /* Make sure required clocks are on at the correct rates. */
286 rc = setup_clocks(fs);
287 if (rc)
288 goto out;
289
290 /* Un-halt all bus ports in the power domain. */
291 if (fs->bus_port1) {
292 rc = msm_bus_axi_portunhalt(fs->bus_port1);
293 if (rc) {
294 pr_err("%s: Port 1 unhalt failed.\n", __func__);
295 goto out;
296 }
297 }
298
299 /* Disable core clock. */
300 clk_disable(fs->core_clk);
301
302 /*
303 * (Re-)Assert resets for all clocks in the clock domain, since
304 * footswitch_enable() is first called before footswitch_disable()
305 * and resets should be asserted before power is restored.
306 */
307 if (fs->axi_clk)
308 clk_reset(fs->axi_clk, CLK_RESET_ASSERT);
309 clk_reset(fs->ahb_clk, CLK_RESET_ASSERT);
310 clk_reset(fs->core_clk, CLK_RESET_ASSERT);
311 /* Wait for synchronous resets to propagate. */
312 udelay(20);
313
314 /* Enable the power rail at the footswitch. */
315 regval = readl_relaxed(fs->gfs_ctl_reg);
316 regval |= ENABLE_BIT;
317 writel_relaxed(regval, fs->gfs_ctl_reg);
318 mb();
319 udelay(1);
320
321 /* Un-clamp the I/O ports. */
322 regval &= ~CLAMP_BIT;
323 writel_relaxed(regval, fs->gfs_ctl_reg);
324
325 /* Deassert resets for all clocks in the power domain. */
326 if (fs->axi_clk)
327 clk_reset(fs->axi_clk, CLK_RESET_DEASSERT);
328 clk_reset(fs->ahb_clk, CLK_RESET_DEASSERT);
329 clk_reset(fs->core_clk, CLK_RESET_DEASSERT);
330 udelay(20);
331
332 /* Re-enable core clock. */
333 clk_enable(fs->core_clk);
334
335 /* Return clocks to their state before this function. */
336 restore_clocks(fs);
337
338 fs->is_enabled = true;
339out:
340 return rc;
341}
342
343static int gfx2d_footswitch_disable(struct regulator_dev *rdev)
344{
345 struct footswitch *fs = rdev_get_drvdata(rdev);
346 uint32_t regval, rc = 0;
347
348 /* Make sure required clocks are on at the correct rates. */
349 rc = setup_clocks(fs);
350 if (rc)
351 goto out;
352
353 /* Halt all bus ports in the power domain. */
354 if (fs->bus_port1) {
355 rc = msm_bus_axi_porthalt(fs->bus_port1);
356 if (rc) {
357 pr_err("%s: Port 1 halt failed.\n", __func__);
358 goto out;
359 }
360 }
361
362 /* Disable core clock. */
363 clk_disable(fs->core_clk);
364
365 /*
366 * Assert resets for all clocks in the clock domain so that
367 * outputs settle prior to clamping.
368 */
369 if (fs->axi_clk)
370 clk_reset(fs->axi_clk, CLK_RESET_ASSERT);
371 clk_reset(fs->ahb_clk, CLK_RESET_ASSERT);
372 clk_reset(fs->core_clk, CLK_RESET_ASSERT);
373 /* Wait for synchronous resets to propagate. */
374 udelay(20);
375
376 /*
377 * Clamp the I/O ports of the core to ensure the values
378 * remain fixed while the core is collapsed.
379 */
380 regval = readl_relaxed(fs->gfs_ctl_reg);
381 regval |= CLAMP_BIT;
382 writel_relaxed(regval, fs->gfs_ctl_reg);
383
384 /* Collapse the power rail at the footswitch. */
385 regval &= ~ENABLE_BIT;
386 writel_relaxed(regval, fs->gfs_ctl_reg);
387
388 /* Re-enable core clock. */
389 clk_enable(fs->core_clk);
390
391 /* Return clocks to their state before this function. */
392 restore_clocks(fs);
393
394 fs->is_enabled = false;
395
396out:
397 return rc;
398}
399
400static struct regulator_ops standard_fs_ops = {
401 .is_enabled = footswitch_is_enabled,
402 .enable = footswitch_enable,
403 .disable = footswitch_disable,
404};
405
406static struct regulator_ops gfx2d_fs_ops = {
407 .is_enabled = footswitch_is_enabled,
408 .enable = gfx2d_footswitch_enable,
409 .disable = gfx2d_footswitch_disable,
410};
411
412#define FOOTSWITCH(_id, _name, _ops, _gfs_ctl_reg, _dc, _bp1, _bp2, \
413 _core_clk, _ahb_clk, _axi_clk, _reset_rate) \
414 [(_id)] = { \
415 .desc = { \
416 .id = (_id), \
417 .name = (_name), \
418 .ops = (_ops), \
419 .type = REGULATOR_VOLTAGE, \
420 .owner = THIS_MODULE, \
421 }, \
422 .gfs_ctl_reg = (_gfs_ctl_reg), \
423 .gfs_delay_cnt = (_dc), \
424 .bus_port1 = (_bp1), \
425 .bus_port2 = (_bp2), \
426 .core_clk_name = (_core_clk), \
427 .ahb_clk_name = (_ahb_clk), \
428 .axi_clk_name = (_axi_clk), \
429 .reset_rate = (_reset_rate), \
430 }
431static struct footswitch footswitches[] = {
432 FOOTSWITCH(FS_GFX2D0, "fs_gfx2d0", &gfx2d_fs_ops,
433 GFX2D0_GFS_CTL_REG, 31,
434 MSM_BUS_MASTER_GRAPHICS_2D_CORE0, 0,
435 "gfx2d0_clk", "gfx2d0_pclk", NULL, 0),
436 FOOTSWITCH(FS_GFX2D1, "fs_gfx2d1", &gfx2d_fs_ops,
437 GFX2D1_GFS_CTL_REG, 31,
438 MSM_BUS_MASTER_GRAPHICS_2D_CORE1, 0,
439 "gfx2d1_clk", "gfx2d1_pclk", NULL, 0),
440 FOOTSWITCH(FS_GFX3D, "fs_gfx3d", &standard_fs_ops,
441 GFX3D_GFS_CTL_REG, 31,
442 MSM_BUS_MASTER_GRAPHICS_3D, 0,
443 "gfx3d_clk", "gfx3d_pclk", NULL, 27000000),
444 FOOTSWITCH(FS_IJPEG, "fs_ijpeg", &standard_fs_ops,
445 GEMINI_GFS_CTL_REG, 31,
446 MSM_BUS_MASTER_JPEG_ENC, 0,
447 "ijpeg_clk", "ijpeg_pclk", "ijpeg_axi_clk", 0),
448 FOOTSWITCH(FS_MDP, "fs_mdp", &standard_fs_ops,
449 MDP_GFS_CTL_REG, 31,
450 MSM_BUS_MASTER_MDP_PORT0,
451 MSM_BUS_MASTER_MDP_PORT1,
452 "mdp_clk", "mdp_pclk", "mdp_axi_clk", 0),
453 FOOTSWITCH(FS_ROT, "fs_rot", &standard_fs_ops,
454 ROT_GFS_CTL_REG, 31,
455 MSM_BUS_MASTER_ROTATOR, 0,
456 "rot_clk", "rotator_pclk", "rot_axi_clk", 0),
457 FOOTSWITCH(FS_VED, "fs_ved", &standard_fs_ops,
458 VED_GFS_CTL_REG, 31,
459 MSM_BUS_MASTER_HD_CODEC_PORT0,
460 MSM_BUS_MASTER_HD_CODEC_PORT1,
461 "vcodec_clk", "vcodec_pclk", "vcodec_axi_clk", 0),
462 FOOTSWITCH(FS_VFE, "fs_vfe", &standard_fs_ops,
463 VFE_GFS_CTL_REG, 31,
464 MSM_BUS_MASTER_VFE, 0,
465 "vfe_clk", "vfe_pclk", "vfe_axi_clk", 0),
466 FOOTSWITCH(FS_VPE, "fs_vpe", &standard_fs_ops,
467 VPE_GFS_CTL_REG, 31,
468 MSM_BUS_MASTER_VPE, 0,
469 "vpe_clk", "vpe_pclk", "vpe_axi_clk", 0),
470};
471
472static int footswitch_probe(struct platform_device *pdev)
473{
474 struct footswitch *fs;
475 struct regulator_init_data *init_data;
476 uint32_t regval, rc = 0;
477
478 if (pdev == NULL)
479 return -EINVAL;
480
481 if (pdev->id >= MAX_FS)
482 return -ENODEV;
483
484 fs = &footswitches[pdev->id];
485 init_data = pdev->dev.platform_data;
486
487 /* Setup core clock. */
488 fs->core_clk = clk_get(NULL, fs->core_clk_name);
489 if (IS_ERR(fs->core_clk)) {
490 pr_err("%s: clk_get(\"%s\") failed\n", __func__,
491 fs->core_clk_name);
492 rc = PTR_ERR(fs->core_clk);
493 goto err_core_clk;
494 }
495
496 /* Setup AHB clock. */
497 fs->ahb_clk = clk_get(NULL, fs->ahb_clk_name);
498 if (IS_ERR(fs->ahb_clk)) {
499 pr_err("%s: clk_get(\"%s\") failed\n", __func__,
500 fs->ahb_clk_name);
501 rc = PTR_ERR(fs->ahb_clk);
502 goto err_ahb_clk;
503 }
504
505 /* Setup AXI clock. */
506 if (fs->axi_clk_name) {
507 fs->axi_clk = clk_get(NULL, fs->axi_clk_name);
508 if (IS_ERR(fs->axi_clk)) {
509 pr_err("%s: clk_get(\"%s\") failed\n", __func__,
510 fs->axi_clk_name);
511 rc = PTR_ERR(fs->axi_clk);
512 goto err_axi_clk;
513 }
514 }
515
516 /*
517 * Set number of AHB_CLK cycles to delay the assertion of gfs_en_all
518 * after enabling the footswitch. Also ensure the retention bit is
519 * clear so disabling the footswitch will power-collapse the core.
520 */
521 regval = readl_relaxed(fs->gfs_ctl_reg);
522 regval |= fs->gfs_delay_cnt;
523 regval &= ~RETENTION_BIT;
524 writel_relaxed(regval, fs->gfs_ctl_reg);
525
526 fs->rdev = regulator_register(&fs->desc, &pdev->dev, init_data, fs);
527 if (IS_ERR(footswitches[pdev->id].rdev)) {
528 pr_err("%s: regulator_register(\"%s\") failed\n",
529 __func__, fs->desc.name);
530 rc = PTR_ERR(footswitches[pdev->id].rdev);
531 goto err_register;
532 }
533
534 return 0;
535
536err_register:
537 if (fs->axi_clk_name)
538 clk_put(fs->axi_clk);
539err_axi_clk:
540 clk_put(fs->ahb_clk);
541err_ahb_clk:
542 clk_put(fs->core_clk);
543err_core_clk:
544 return rc;
545}
546
547static int __devexit footswitch_remove(struct platform_device *pdev)
548{
549 struct footswitch *fs = &footswitches[pdev->id];
550
551 clk_put(fs->core_clk);
552 clk_put(fs->ahb_clk);
553 if (fs->axi_clk)
554 clk_put(fs->axi_clk);
555
556 regulator_unregister(fs->rdev);
557
558 return 0;
559}
560
561static struct platform_driver footswitch_driver = {
562 .probe = footswitch_probe,
563 .remove = __devexit_p(footswitch_remove),
564 .driver = {
565 .name = "footswitch-msm8x60",
566 .owner = THIS_MODULE,
567 },
568};
569
570static int __init late_footswitch_init(void)
571{
572 int i;
573
574 mutex_lock(&claim_lock);
575 /* Turn off all registered but unused footswitches. */
576 for (i = 0; i < ARRAY_SIZE(footswitches); i++)
577 if (footswitches[i].rdev && !footswitches[i].is_claimed)
Matt Wagantall7a261362011-07-14 19:07:10 -0700578 footswitches[i].rdev->desc->ops->
579 disable(footswitches[i].rdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700580 mutex_unlock(&claim_lock);
581
582 return 0;
583}
584late_initcall(late_footswitch_init);
585
586static int __init footswitch_init(void)
587{
588 return platform_driver_register(&footswitch_driver);
589}
590subsys_initcall(footswitch_init);
591
592static void __exit footswitch_exit(void)
593{
594 platform_driver_unregister(&footswitch_driver);
595}
596module_exit(footswitch_exit);
597
598MODULE_LICENSE("GPL v2");
599MODULE_DESCRIPTION("MSM8x60 rail footswitch");
600MODULE_ALIAS("platform:footswitch-msm8x60");