From ca2d9e858b38d71a97b535b0dca41fe02dae7a0b Mon Sep 17 00:00:00 2001 From: Jonas Aaberg Date: Thu, 22 Dec 2011 09:34:40 +0100 Subject: [ANDROID]: ARM: u8500: pm: debug: Add suspend test case Add automatic suspend testcase that can be used from android. To use, write the number of time you wish to do suspend to /pwr_test/suspend and when done read the same file. It will answer PASS or FAIL. ST-Ericsson Linux next: - ST-Ericsson ID: 370799 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: Iad7d5365e7cde8b9aeeb87e99318e5455d56201f Signed-off-by: Jonas Aaberg Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/43663 --- arch/arm/mach-ux500/pm/suspend.c | 4 ++ arch/arm/mach-ux500/pm/suspend_dbg.c | 80 +++++++++++++++++++++++++++++++++++- arch/arm/mach-ux500/pm/suspend_dbg.h | 13 ++++++ arch/arm/mach-ux500/test/Kconfig | 4 +- arch/arm/mach-ux500/test/pwr.c | 75 +++++++++++++++++++++++++++++++++ 5 files changed, 173 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-ux500/pm/suspend.c b/arch/arm/mach-ux500/pm/suspend.c index df527964182..9dd4d86a2f3 100644 --- a/arch/arm/mach-ux500/pm/suspend.c +++ b/arch/arm/mach-ux500/pm/suspend.c @@ -76,6 +76,8 @@ static int suspend(bool do_deepsleep) prcmu_enable_wakeups(PRCMU_WAKEUP(ABB)); #endif + ux500_suspend_dbg_test_set_wakeup(); + context_vape_save(); context_fsmc_save(); @@ -258,6 +260,8 @@ static void ux500_suspend_end(void) (void) prcmu_qos_update_requirement(PRCMU_QOS_ARM_OPP, "suspend", 25); suspend_state = PM_SUSPEND_ON; + + ux500_suspend_dbg_end(); } static struct platform_suspend_ops ux500_suspend_ops = { diff --git a/arch/arm/mach-ux500/pm/suspend_dbg.c b/arch/arm/mach-ux500/pm/suspend_dbg.c index 1b7d871ba52..68afa96e547 100644 --- a/arch/arm/mach-ux500/pm/suspend_dbg.c +++ b/arch/arm/mach-ux500/pm/suspend_dbg.c @@ -14,10 +14,16 @@ #include #include #include +#include #include #include +#include #include +#include + +/* To reach main_wake_lock */ +#include "../../../../kernel/power/power.h" #ifdef CONFIG_UX500_SUSPEND_STANDBY static u32 sleep_enabled = 1; @@ -100,6 +106,79 @@ int ux500_suspend_dbg_begin(suspend_state_t state) return 0; } +/* The number of failed suspend attempts in a row before giving up */ +#define TEST_FAILS 10 + +static int suspend_test_count; +static int suspend_test_current; +static int suspend_test_fail_count; + +void ux500_suspend_dbg_test_set_wakeup(void) +{ + if (suspend_test_count == 0) + return; + + ux500_rtcrtt_off(); + + /* Make sure the rtc writes have been accepted */ + udelay(120); + + if (cpu_is_u9500()) + prcmu_enable_wakeups(PRCMU_WAKEUP(ABB) | PRCMU_WAKEUP(RTC) | + PRCMU_WAKEUP(HSI0)); + else + prcmu_enable_wakeups(PRCMU_WAKEUP(ABB) | PRCMU_WAKEUP(RTC)); + + /* Program RTC to generate an interrupt 1s later */ + ux500_rtcrtt_next(1000000); +} + +void ux500_suspend_dbg_test_start(int num) +{ + suspend_test_count = num; + suspend_test_current = deepsleeps_done; + suspend_test_fail_count = 0; +} + +bool ux500_suspend_test_success(bool *ongoing) +{ + (*ongoing) = ((suspend_test_fail_count < TEST_FAILS) && + (suspend_test_count > 0)); + return suspend_test_fail_count < TEST_FAILS; +} + +void ux500_suspend_dbg_end(void) +{ + static int attempts; + + if (suspend_test_count > 0) { + attempts++; + pr_info("Suspend test: %d done\n", attempts); + suspend_test_count--; + wake_lock(&main_wake_lock); + + if (suspend_test_current < deepsleeps_done) { + suspend_test_current = deepsleeps_done; + suspend_test_fail_count = 0; + } else { + suspend_test_fail_count++; + } + + if (suspend_test_fail_count > TEST_FAILS) { + suspend_test_count = 0; + pr_err("suspend: Aborting after %d " + "failed suspend in a row\n", + TEST_FAILS); + } else if (suspend_test_count > 0) { + msleep(100); + wake_unlock(&main_wake_lock); + } + + if (suspend_test_count == 0) + attempts = 0; + } +} + void ux500_suspend_dbg_init(void) { struct dentry *suspend_dir; @@ -145,7 +224,6 @@ void ux500_suspend_dbg_init(void) if (IS_ERR_OR_NULL(file)) goto error; - file = debugfs_create_u32("sleep_failed", S_IRUGO, suspend_dir, &sleeps_failed); diff --git a/arch/arm/mach-ux500/pm/suspend_dbg.h b/arch/arm/mach-ux500/pm/suspend_dbg.h index 29bfec7e269..1e45fa05e5e 100644 --- a/arch/arm/mach-ux500/pm/suspend_dbg.h +++ b/arch/arm/mach-ux500/pm/suspend_dbg.h @@ -28,6 +28,10 @@ bool ux500_suspend_deepsleep_enabled(void); void ux500_suspend_dbg_sleep_status(bool is_deepsleep); void ux500_suspend_dbg_init(void); int ux500_suspend_dbg_begin(suspend_state_t state); +void ux500_suspend_dbg_end(void); +void ux500_suspend_dbg_test_set_wakeup(void); +void ux500_suspend_dbg_test_start(int num); +bool ux500_suspend_test_success(bool *ongoing); #else static inline bool ux500_suspend_enabled(void) @@ -57,6 +61,15 @@ static inline int ux500_suspend_dbg_begin(suspend_state_t state) { return 0; } +static inline void ux500_suspend_dbg_end(void) { } +static inline void ux500_suspend_dbg_test_set_wakeup(void) { } +static inline void ux500_suspend_dbg_test_start(int num) +{ } +static inline bool ux500_suspend_test_success(bool *ongoing) +{ + (*ongoing) = false; + return false; +} #endif diff --git a/arch/arm/mach-ux500/test/Kconfig b/arch/arm/mach-ux500/test/Kconfig index a071166d092..bb8ed548826 100644 --- a/arch/arm/mach-ux500/test/Kconfig +++ b/arch/arm/mach-ux500/test/Kconfig @@ -1,6 +1,6 @@ config DB8500_PWR_TEST bool "Power usage module test" - depends on (UX500_SOC_DB8500 && DEBUG_FS && REGULATOR_AB8500_DEBUG) + depends on (UX500_SOC_DB8500 && DEBUG_FS && REGULATOR_AB8500_DEBUG && UX500_SUSPEND_DBG) help - Add power module tests for idle + Add power module tests for idle and suspend diff --git a/arch/arm/mach-ux500/test/pwr.c b/arch/arm/mach-ux500/test/pwr.c index 5d5d24a38ab..b03492a8fa5 100644 --- a/arch/arm/mach-ux500/test/pwr.c +++ b/arch/arm/mach-ux500/test/pwr.c @@ -19,13 +19,18 @@ #include #include #include +#include #include #include +#include "../pm/suspend_dbg.h" #include "../../../drivers/regulator/dbx500-prcmu.h" #include "../../../drivers/regulator/ab8500-debug.h" +/* To reach main_wake_lock */ +#include "../../../../kernel/power/power.h" + #define PRCC_PCKSR 0x010 #define PRCC_KCKSR 0x014 @@ -777,6 +782,50 @@ static int pwr_test_idle(struct seq_file *s, void *data) return 0; } +static bool suspend_testing; +static int suspend_test_length; + +static ssize_t pm_test_suspend_set(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + long unsigned val; + int err; + + err = kstrtoul_from_user(user_buf, count, 0, &val); + + if (err) + return err; + + suspend_test_length = (int)val; + + ux500_suspend_dbg_test_start(suspend_test_length); + + suspend_testing = true; + wake_unlock(&main_wake_lock); + + pr_info("Will do suspend %d times.\n", suspend_test_length); + return count; +} + +static int pwr_test_suspend_status(struct seq_file *s, void *data) +{ + bool ongoing = true; + bool success; + + if (!suspend_testing) { + pr_info("Suspend test not started\n"); + seq_printf(s, "FAIL\n"); + return 0; + } + + success = ux500_suspend_test_success(&ongoing); + + seq_printf(s, + "%s\n", ongoing ? "ONGOING" : (success ? "PASS" : "FAIL")); + + return 0; +} int dbx500_regulator_testcase(struct dbx500_regulator_info *regulator_info, int num_regulators) @@ -794,6 +843,14 @@ static int pwr_test_debugfs_open(struct inode *inode, NULL); } +static int pwr_test_suspend_debugfs_open(struct inode *inode, + struct file *file) +{ + return single_open(file, + pwr_test_suspend_status, + inode->i_private); +} + static const struct file_operations pwr_test_debugfs_ops = { .open = pwr_test_debugfs_open, .read = seq_read, @@ -801,6 +858,14 @@ static const struct file_operations pwr_test_debugfs_ops = { .release = single_release, }; +static const struct file_operations pwr_test_suspend_debugfs_ops = { + .open = pwr_test_suspend_debugfs_open, + .read = seq_read, + .write = pm_test_suspend_set, + .llseek = seq_lseek, + .release = single_release, +}; + static struct dentry *debugfs_dir; static int __init pwr_test_init(void) @@ -820,6 +885,16 @@ static int __init pwr_test_init(void) err = PTR_ERR(err_ptr); goto out; } + + err_ptr = debugfs_create_file("suspend", + S_IWUSR | S_IFREG | S_IRUGO, + debugfs_dir, NULL, + &pwr_test_suspend_debugfs_ops); + if (IS_ERR(err_ptr)) { + err = PTR_ERR(err_ptr); + goto out; + } + return 0; out: debugfs_remove_recursive(debugfs_dir); -- cgit v1.2.3