aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2
diff options
context:
space:
mode:
authorPaul Walmsley <paul@pwsan.com>2010-01-26 22:13:01 -0500
committerPaul Walmsley <paul@pwsan.com>2010-01-26 22:13:01 -0500
commit369d5614457384edcf62c5f39b03dd20be6ea1df (patch)
tree4ad04d48f3049ff2d88e8ddca35fb0ad8597d12c /arch/arm/mach-omap2
parente909d62a8afda7a224a7e322cf2f387d69ca771f (diff)
OMAP clockdomains: add usecounting for wakeup and sleep dependencies
Add usecounting for wakeup and sleep dependencies. In the current situation, if several functions add dependencies on the same clockdomains, when the first dependency removal function is called, the dependency will be incorrectly removed from the hardware. Add clkdm_clear_all_wkdeps() and clkdm_clear_all_sleepdeps(), which provide a fast and usecounting-consistent way to clear all hardware clockdomain dependencies, since accesses to these registers can be quite slow. pm{2,3}4xx.c has been updated to use these new functions. The original version of this patch did not touch these files, which previously wrote directly to the wkdep registers, and thus confused the usecounting code. This problem was found by Kevin Hilman <khilman@deeprootsystems.com>. N.B.: This patch introduces one significant functional difference over the previous pm34xx.c code: sleepdeps are now cleared during clockdomain initialization, whereas previously they were left untouched. This has been tested by Kevin and confirmed to work. The original version of this patch also did not take into consideration that some clockdomains do not have sleep or wakeup dependency sources, which caused NULL pointer dereferences. This problem was debugged and fixed by Kevin Hilman <khilman@deeprootsystems.com>. Signed-off-by: Paul Walmsley <paul@pwsan.com> Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com> Cc: Jouni Högander <jouni.hogander@nokia.com>
Diffstat (limited to 'arch/arm/mach-omap2')
-rw-r--r--arch/arm/mach-omap2/clockdomain.c216
-rw-r--r--arch/arm/mach-omap2/pm24xx.c49
-rw-r--r--arch/arm/mach-omap2/pm34xx.c3
3 files changed, 229 insertions, 39 deletions
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index 2af9996f010b..6eaa9314cd64 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -113,7 +113,6 @@ static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm,
113 return ERR_PTR(-EINVAL); 113 return ERR_PTR(-EINVAL);
114 114
115 for (cd = deps; cd->clkdm_name; cd++) { 115 for (cd = deps; cd->clkdm_name; cd++) {
116
117 if (!omap_chip_is(cd->omap_chip)) 116 if (!omap_chip_is(cd->omap_chip))
118 continue; 117 continue;
119 118
@@ -122,7 +121,6 @@ static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm,
122 121
123 if (cd->clkdm == clkdm) 122 if (cd->clkdm == clkdm)
124 break; 123 break;
125
126 } 124 }
127 125
128 if (!cd->clkdm_name) 126 if (!cd->clkdm_name)
@@ -254,6 +252,96 @@ static void _omap2_clkdm_set_hwsup(struct clockdomain *clkdm, int enable)
254 252
255} 253}
256 254
255/**
256 * _init_wkdep_usecount - initialize wkdep usecounts to match hardware
257 * @clkdm: clockdomain to initialize wkdep usecounts
258 *
259 * Initialize the wakeup dependency usecount variables for clockdomain @clkdm.
260 * If a wakeup dependency is present in the hardware, the usecount will be
261 * set to 1; otherwise, it will be set to 0. Software should clear all
262 * software wakeup dependencies prior to calling this function if it wishes
263 * to ensure that all usecounts start at 0. No return value.
264 */
265static void _init_wkdep_usecount(struct clockdomain *clkdm)
266{
267 u32 v;
268 struct clkdm_dep *cd;
269
270 if (!clkdm->wkdep_srcs)
271 return;
272
273 for (cd = clkdm->wkdep_srcs; cd->clkdm_name; cd++) {
274 if (!omap_chip_is(cd->omap_chip))
275 continue;
276
277 if (!cd->clkdm && cd->clkdm_name)
278 cd->clkdm = _clkdm_lookup(cd->clkdm_name);
279
280 if (!cd->clkdm) {
281 WARN(!cd->clkdm, "clockdomain: %s: wkdep clkdm %s not "
282 "found\n", clkdm->name, cd->clkdm_name);
283 continue;
284 }
285
286 v = prm_read_mod_bits_shift(clkdm->pwrdm.ptr->prcm_offs,
287 PM_WKDEP,
288 (1 << cd->clkdm->dep_bit));
289
290 if (v)
291 pr_debug("clockdomain: %s: wakeup dependency already "
292 "set to wake up when %s wakes\n",
293 clkdm->name, cd->clkdm->name);
294
295 atomic_set(&cd->wkdep_usecount, (v) ? 1 : 0);
296 }
297}
298
299/**
300 * _init_sleepdep_usecount - initialize sleepdep usecounts to match hardware
301 * @clkdm: clockdomain to initialize sleepdep usecounts
302 *
303 * Initialize the sleep dependency usecount variables for clockdomain @clkdm.
304 * If a sleep dependency is present in the hardware, the usecount will be
305 * set to 1; otherwise, it will be set to 0. Software should clear all
306 * software sleep dependencies prior to calling this function if it wishes
307 * to ensure that all usecounts start at 0. No return value.
308 */
309static void _init_sleepdep_usecount(struct clockdomain *clkdm)
310{
311 u32 v;
312 struct clkdm_dep *cd;
313
314 if (!cpu_is_omap34xx())
315 return;
316
317 if (!clkdm->sleepdep_srcs)
318 return;
319
320 for (cd = clkdm->sleepdep_srcs; cd->clkdm_name; cd++) {
321 if (!omap_chip_is(cd->omap_chip))
322 continue;
323
324 if (!cd->clkdm && cd->clkdm_name)
325 cd->clkdm = _clkdm_lookup(cd->clkdm_name);
326
327 if (!cd->clkdm) {
328 WARN(!cd->clkdm, "clockdomain: %s: sleepdep clkdm %s "
329 "not found\n", clkdm->name, cd->clkdm_name);
330 continue;
331 }
332
333 v = prm_read_mod_bits_shift(clkdm->pwrdm.ptr->prcm_offs,
334 OMAP3430_CM_SLEEPDEP,
335 (1 << cd->clkdm->dep_bit));
336
337 if (v)
338 pr_debug("clockdomain: %s: sleep dependency already "
339 "set to prevent from idling until %s "
340 "idles\n", clkdm->name, cd->clkdm->name);
341
342 atomic_set(&cd->sleepdep_usecount, (v) ? 1 : 0);
343 }
344};
257 345
258/* Public functions */ 346/* Public functions */
259 347
@@ -272,6 +360,7 @@ void clkdm_init(struct clockdomain **clkdms,
272 struct clkdm_autodep *init_autodeps) 360 struct clkdm_autodep *init_autodeps)
273{ 361{
274 struct clockdomain **c = NULL; 362 struct clockdomain **c = NULL;
363 struct clockdomain *clkdm;
275 struct clkdm_autodep *autodep = NULL; 364 struct clkdm_autodep *autodep = NULL;
276 365
277 if (clkdms) 366 if (clkdms)
@@ -282,6 +371,15 @@ void clkdm_init(struct clockdomain **clkdms,
282 if (autodeps) 371 if (autodeps)
283 for (autodep = autodeps; autodep->clkdm.ptr; autodep++) 372 for (autodep = autodeps; autodep->clkdm.ptr; autodep++)
284 _autodep_lookup(autodep); 373 _autodep_lookup(autodep);
374
375 /*
376 * Ensure that the *dep_usecount registers reflect the current
377 * state of the PRCM.
378 */
379 list_for_each_entry(clkdm, &clkdm_list, node) {
380 _init_wkdep_usecount(clkdm);
381 _init_sleepdep_usecount(clkdm);
382 }
285} 383}
286 384
287/** 385/**
@@ -387,11 +485,13 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
387 return PTR_ERR(cd); 485 return PTR_ERR(cd);
388 } 486 }
389 487
390 pr_debug("clockdomain: hardware will wake up %s when %s wakes up\n", 488 if (atomic_inc_return(&cd->wkdep_usecount) == 1) {
391 clkdm1->name, clkdm2->name); 489 pr_debug("clockdomain: hardware will wake up %s when %s wakes "
490 "up\n", clkdm1->name, clkdm2->name);
392 491
393 prm_set_mod_reg_bits((1 << clkdm2->dep_bit), 492 prm_set_mod_reg_bits((1 << clkdm2->dep_bit),
394 clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); 493 clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
494 }
395 495
396 return 0; 496 return 0;
397} 497}
@@ -420,11 +520,13 @@ int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
420 return PTR_ERR(cd); 520 return PTR_ERR(cd);
421 } 521 }
422 522
423 pr_debug("clockdomain: hardware will no longer wake up %s after %s " 523 if (atomic_dec_return(&cd->wkdep_usecount) == 0) {
424 "wakes up\n", clkdm1->name, clkdm2->name); 524 pr_debug("clockdomain: hardware will no longer wake up %s "
525 "after %s wakes up\n", clkdm1->name, clkdm2->name);
425 526
426 prm_clear_mod_reg_bits((1 << clkdm2->dep_bit), 527 prm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
427 clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); 528 clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
529 }
428 530
429 return 0; 531 return 0;
430} 532}
@@ -457,11 +559,44 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
457 return PTR_ERR(cd); 559 return PTR_ERR(cd);
458 } 560 }
459 561
562 /* XXX It's faster to return the atomic wkdep_usecount */
460 return prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP, 563 return prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP,
461 (1 << clkdm2->dep_bit)); 564 (1 << clkdm2->dep_bit));
462} 565}
463 566
464/** 567/**
568 * clkdm_clear_all_wkdeps - remove all wakeup dependencies from target clkdm
569 * @clkdm: struct clockdomain * to remove all wakeup dependencies from
570 *
571 * Remove all inter-clockdomain wakeup dependencies that could cause
572 * @clkdm to wake. Intended to be used during boot to initialize the
573 * PRCM to a known state, after all clockdomains are put into swsup idle
574 * and woken up. Returns -EINVAL if @clkdm pointer is invalid, or
575 * 0 upon success.
576 */
577int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
578{
579 struct clkdm_dep *cd;
580 u32 mask = 0;
581
582 if (!clkdm)
583 return -EINVAL;
584
585 for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
586 if (!omap_chip_is(cd->omap_chip))
587 continue;
588
589 /* PRM accesses are slow, so minimize them */
590 mask |= 1 << cd->clkdm->dep_bit;
591 atomic_set(&cd->wkdep_usecount, 0);
592 }
593
594 prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, PM_WKDEP);
595
596 return 0;
597}
598
599/**
465 * clkdm_add_sleepdep - add a sleep dependency from clkdm2 to clkdm1 600 * clkdm_add_sleepdep - add a sleep dependency from clkdm2 to clkdm1
466 * @clkdm1: prevent this struct clockdomain * from sleeping (dependent) 601 * @clkdm1: prevent this struct clockdomain * from sleeping (dependent)
467 * @clkdm2: when this struct clockdomain * is active (source) 602 * @clkdm2: when this struct clockdomain * is active (source)
@@ -491,12 +626,14 @@ int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
491 return PTR_ERR(cd); 626 return PTR_ERR(cd);
492 } 627 }
493 628
494 pr_debug("clockdomain: will prevent %s from sleeping if %s is active\n", 629 if (atomic_inc_return(&cd->sleepdep_usecount) == 1) {
495 clkdm1->name, clkdm2->name); 630 pr_debug("clockdomain: will prevent %s from sleeping if %s "
631 "is active\n", clkdm1->name, clkdm2->name);
496 632
497 cm_set_mod_reg_bits((1 << clkdm2->dep_bit), 633 cm_set_mod_reg_bits((1 << clkdm2->dep_bit),
498 clkdm1->pwrdm.ptr->prcm_offs, 634 clkdm1->pwrdm.ptr->prcm_offs,
499 OMAP3430_CM_SLEEPDEP); 635 OMAP3430_CM_SLEEPDEP);
636 }
500 637
501 return 0; 638 return 0;
502} 639}
@@ -531,12 +668,15 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
531 return PTR_ERR(cd); 668 return PTR_ERR(cd);
532 } 669 }
533 670
534 pr_debug("clockdomain: will no longer prevent %s from sleeping if " 671 if (atomic_dec_return(&cd->sleepdep_usecount) == 0) {
535 "%s is active\n", clkdm1->name, clkdm2->name); 672 pr_debug("clockdomain: will no longer prevent %s from "
673 "sleeping if %s is active\n", clkdm1->name,
674 clkdm2->name);
536 675
537 cm_clear_mod_reg_bits((1 << clkdm2->dep_bit), 676 cm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
538 clkdm1->pwrdm.ptr->prcm_offs, 677 clkdm1->pwrdm.ptr->prcm_offs,
539 OMAP3430_CM_SLEEPDEP); 678 OMAP3430_CM_SLEEPDEP);
679 }
540 680
541 return 0; 681 return 0;
542} 682}
@@ -575,11 +715,47 @@ int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
575 return PTR_ERR(cd); 715 return PTR_ERR(cd);
576 } 716 }
577 717
718 /* XXX It's faster to return the atomic sleepdep_usecount */
578 return prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, 719 return prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
579 OMAP3430_CM_SLEEPDEP, 720 OMAP3430_CM_SLEEPDEP,
580 (1 << clkdm2->dep_bit)); 721 (1 << clkdm2->dep_bit));
581} 722}
582 723
724/**
725 * clkdm_clear_all_sleepdeps - remove all sleep dependencies from target clkdm
726 * @clkdm: struct clockdomain * to remove all sleep dependencies from
727 *
728 * Remove all inter-clockdomain sleep dependencies that could prevent
729 * @clkdm from idling. Intended to be used during boot to initialize the
730 * PRCM to a known state, after all clockdomains are put into swsup idle
731 * and woken up. Returns -EINVAL if @clkdm pointer is invalid, or
732 * 0 upon success.
733 */
734int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
735{
736 struct clkdm_dep *cd;
737 u32 mask = 0;
738
739 if (!cpu_is_omap34xx())
740 return -EINVAL;
741
742 if (!clkdm)
743 return -EINVAL;
744
745 for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) {
746 if (!omap_chip_is(cd->omap_chip))
747 continue;
748
749 /* PRM accesses are slow, so minimize them */
750 mask |= 1 << cd->clkdm->dep_bit;
751 atomic_set(&cd->sleepdep_usecount, 0);
752 }
753
754 prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
755 OMAP3430_CM_SLEEPDEP);
756
757 return 0;
758}
583 759
584/** 760/**
585 * omap2_clkdm_clktrctrl_read - read the clkdm's current state transition mode 761 * omap2_clkdm_clktrctrl_read - read the clkdm's current state transition mode
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index 754381857cb6..374299ea7ade 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -57,11 +57,8 @@ static void (*omap2_sram_idle)(void);
57static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl, 57static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl,
58 void __iomem *sdrc_power); 58 void __iomem *sdrc_power);
59 59
60static struct powerdomain *mpu_pwrdm; 60static struct powerdomain *mpu_pwrdm, *core_pwrdm;
61static struct powerdomain *core_pwrdm; 61static struct clockdomain *dsp_clkdm, *mpu_clkdm, *wkup_clkdm, *gfx_clkdm;
62
63static struct clockdomain *dsp_clkdm;
64static struct clockdomain *gfx_clkdm;
65 62
66static struct clk *osc_ck, *emul_ck; 63static struct clk *osc_ck, *emul_ck;
67 64
@@ -334,9 +331,17 @@ static struct platform_suspend_ops omap_pm_ops = {
334 .valid = suspend_valid_only_mem, 331 .valid = suspend_valid_only_mem,
335}; 332};
336 333
337static int _pm_clkdm_enable_hwsup(struct clockdomain *clkdm, void *unused) 334/* XXX This function should be shareable between OMAP2xxx and OMAP3 */
335static int __init clkdms_setup(struct clockdomain *clkdm, void *unused)
338{ 336{
339 omap2_clkdm_allow_idle(clkdm); 337 clkdm_clear_all_wkdeps(clkdm);
338 clkdm_clear_all_sleepdeps(clkdm);
339
340 if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
341 omap2_clkdm_allow_idle(clkdm);
342 else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
343 atomic_read(&clkdm->usecount) == 0)
344 omap2_clkdm_sleep(clkdm);
340 return 0; 345 return 0;
341} 346}
342 347
@@ -349,14 +354,6 @@ static void __init prcm_setup_regs(void)
349 prm_write_mod_reg(OMAP24XX_AUTOIDLE, OCP_MOD, 354 prm_write_mod_reg(OMAP24XX_AUTOIDLE, OCP_MOD,
350 OMAP2_PRCM_SYSCONFIG_OFFSET); 355 OMAP2_PRCM_SYSCONFIG_OFFSET);
351 356
352 /* Set all domain wakeup dependencies */
353 prm_write_mod_reg(OMAP_EN_WKUP_MASK, MPU_MOD, PM_WKDEP);
354 prm_write_mod_reg(0, OMAP24XX_DSP_MOD, PM_WKDEP);
355 prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
356 prm_write_mod_reg(0, CORE_MOD, PM_WKDEP);
357 if (cpu_is_omap2430())
358 prm_write_mod_reg(0, OMAP2430_MDM_MOD, PM_WKDEP);
359
360 /* 357 /*
361 * Set CORE powerdomain memory banks to retain their contents 358 * Set CORE powerdomain memory banks to retain their contents
362 * during RETENTION 359 * during RETENTION
@@ -385,8 +382,12 @@ static void __init prcm_setup_regs(void)
385 pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF); 382 pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
386 omap2_clkdm_sleep(gfx_clkdm); 383 omap2_clkdm_sleep(gfx_clkdm);
387 384
388 /* Enable clockdomain hardware-supervised control for all clkdms */ 385 /*
389 clkdm_for_each(_pm_clkdm_enable_hwsup, NULL); 386 * Clear clockdomain wakeup dependencies and enable
387 * hardware-supervised idle for all clkdms
388 */
389 clkdm_for_each(clkdms_setup, NULL);
390 clkdm_add_wkdep(mpu_clkdm, wkup_clkdm);
390 391
391 /* Enable clock autoidle for all domains */ 392 /* Enable clock autoidle for all domains */
392 cm_write_mod_reg(OMAP24XX_AUTO_CAM | 393 cm_write_mod_reg(OMAP24XX_AUTO_CAM |
@@ -482,7 +483,7 @@ static int __init omap2_pm_init(void)
482 l = prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_REVISION_OFFSET); 483 l = prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_REVISION_OFFSET);
483 printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f); 484 printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
484 485
485 /* Look up important powerdomains, clockdomains */ 486 /* Look up important powerdomains */
486 487
487 mpu_pwrdm = pwrdm_lookup("mpu_pwrdm"); 488 mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
488 if (!mpu_pwrdm) 489 if (!mpu_pwrdm)
@@ -492,9 +493,19 @@ static int __init omap2_pm_init(void)
492 if (!core_pwrdm) 493 if (!core_pwrdm)
493 pr_err("PM: core_pwrdm not found\n"); 494 pr_err("PM: core_pwrdm not found\n");
494 495
496 /* Look up important clockdomains */
497
498 mpu_clkdm = clkdm_lookup("mpu_clkdm");
499 if (!mpu_clkdm)
500 pr_err("PM: mpu_clkdm not found\n");
501
502 wkup_clkdm = clkdm_lookup("wkup_clkdm");
503 if (!wkup_clkdm)
504 pr_err("PM: wkup_clkdm not found\n");
505
495 dsp_clkdm = clkdm_lookup("dsp_clkdm"); 506 dsp_clkdm = clkdm_lookup("dsp_clkdm");
496 if (!dsp_clkdm) 507 if (!dsp_clkdm)
497 pr_err("PM: mpu_clkdm not found\n"); 508 pr_err("PM: dsp_clkdm not found\n");
498 509
499 gfx_clkdm = clkdm_lookup("gfx_clkdm"); 510 gfx_clkdm = clkdm_lookup("gfx_clkdm");
500 if (!gfx_clkdm) 511 if (!gfx_clkdm)
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 5f59df87abf7..5087b153b093 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -998,6 +998,9 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
998 */ 998 */
999static int __init clkdms_setup(struct clockdomain *clkdm, void *unused) 999static int __init clkdms_setup(struct clockdomain *clkdm, void *unused)
1000{ 1000{
1001 clkdm_clear_all_wkdeps(clkdm);
1002 clkdm_clear_all_sleepdeps(clkdm);
1003
1001 if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO) 1004 if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
1002 omap2_clkdm_allow_idle(clkdm); 1005 omap2_clkdm_allow_idle(clkdm);
1003 else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP && 1006 else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&