summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Aaberg <jonas.aberg@stericsson.com>2011-12-22 09:34:40 +0100
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-06-04 19:45:08 +0800
commitca2d9e858b38d71a97b535b0dca41fe02dae7a0b (patch)
tree09188b43ae4c2ecb2c40f4bde5e43817ece9d17f
parent9ce0109275e82697ada4b005325e663ba72c3181 (diff)
[ANDROID]: ARM: u8500: pm: debug: Add suspend test casepm-android
Add automatic suspend testcase that can be used from android. To use, write the number of time you wish to do suspend to <debugfs>/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 <jonas.aberg@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/43663
-rw-r--r--arch/arm/mach-ux500/pm/suspend.c4
-rw-r--r--arch/arm/mach-ux500/pm/suspend_dbg.c80
-rw-r--r--arch/arm/mach-ux500/pm/suspend_dbg.h13
-rw-r--r--arch/arm/mach-ux500/test/Kconfig4
-rw-r--r--arch/arm/mach-ux500/test/pwr.c75
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 <linux/suspend.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
+#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/wakelock.h>
#include <mach/pm.h>
+#include <mach/pm-timer.h>
+
+/* 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 <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/db8500-prcmu.h>
+#include <linux/wakelock.h>
#include <mach/hardware.h>
#include <mach/pm.h>
+#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);