summaryrefslogtreecommitdiff
path: root/drivers/mfd
diff options
context:
space:
mode:
authorDaniel Willerud <daniel.willerud@stericsson.com>2011-08-25 17:39:18 +0200
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-05-22 11:00:51 +0200
commitd8e4caf56945aed91c1610b6adeb2f23df02cbc4 (patch)
tree66ad1c28205d3b10f37aa126fd986bb80c0f05a7 /drivers/mfd
parent1232e887f97a3e9ea82b6193cda5e58ba7605736 (diff)
ux500: Thermal power off
To determine whether the system had a thermal power off or a regular software power off upon the next boot, the system must utilize the thermal power off bit, ThDB8500SWoff, in AB8500 register STw4500Ctrl1. ST-Ericsson ID: 354533 ST-Ericsson Linux next: N/A ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I07440dcdc39a86cb72aa95d86411a1f020b05cae Signed-off-by: Daniel Willerud <daniel.willerud@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/28515 Reviewed-by: QABUILD Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/ab8500-sysctrl.c50
1 files changed, 46 insertions, 4 deletions
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c
index cf58f694539..2a328cfaf43 100644
--- a/drivers/mfd/ab8500-sysctrl.c
+++ b/drivers/mfd/ab8500-sysctrl.c
@@ -14,11 +14,15 @@
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/abx500/ab8500-sysctrl.h>
+#include <linux/time.h>
+#include <linux/hwmon.h>
static struct device *sysctrl_dev;
void ab8500_power_off(void)
{
+ struct ab8500_platform_data *plat;
+ struct timespec ts;
sigset_t old;
sigset_t all;
static char *pss[] = {"ab8500_ac", "ab8500_usb"};
@@ -66,14 +70,51 @@ void ab8500_power_off(void)
shutdown:
sigfillset(&all);
+ plat = dev_get_platdata(sysctrl_dev->parent);
+ getnstimeofday(&ts);
if (!sigprocmask(SIG_BLOCK, &all, &old)) {
- (void)ab8500_sysctrl_set(AB8500_STW4500CTRL1,
- AB8500_STW4500CTRL1_SWOFF |
- AB8500_STW4500CTRL1_SWRESET4500N);
- (void)sigprocmask(SIG_SETMASK, &old, NULL);
+ if (ts.tv_sec == 0 ||
+ (ts.tv_sec - plat->thermal_set_time_sec >
+ plat->thermal_time_out))
+ plat->thermal_power_off_pending = false;
+ if (!plat->thermal_power_off_pending) {
+ (void)ab8500_sysctrl_set(AB8500_STW4500CTRL1,
+ AB8500_STW4500CTRL1_SWOFF |
+ AB8500_STW4500CTRL1_SWRESET4500N);
+ (void)sigprocmask(SIG_SETMASK, &old, NULL);
+ } else {
+ (void)ab8500_sysctrl_set(AB8500_STW4500CTRL1,
+ AB8500_STW4500CTRL1_THDB8500SWOFF |
+ AB8500_STW4500CTRL1_SWRESET4500N);
+ (void)sigprocmask(SIG_SETMASK, &old, NULL);
+ }
}
}
+static int ab8500_notifier_call(struct notifier_block *this,
+ unsigned long val, void *data)
+{
+ struct ab8500_platform_data *plat;
+ static struct timespec ts;
+ if (sysctrl_dev == NULL)
+ return -EAGAIN;
+
+ plat = dev_get_platdata(sysctrl_dev->parent);
+ if (val) {
+ getnstimeofday(&ts);
+ plat->thermal_set_time_sec = ts.tv_sec;
+ plat->thermal_power_off_pending = true;
+ } else {
+ plat->thermal_set_time_sec = 0;
+ plat->thermal_power_off_pending = false;
+ }
+ return 0;
+}
+
+static struct notifier_block ab8500_notifier = {
+ .notifier_call = ab8500_notifier_call,
+};
+
static inline bool valid_bank(u8 bank)
{
return ((bank == AB8500_SYS_CTRL1_BLOCK) ||
@@ -118,6 +159,7 @@ static int __devinit ab8500_sysctrl_probe(struct platform_device *pdev)
plat = dev_get_platdata(pdev->dev.parent);
if (plat->pm_power_off)
pm_power_off = ab8500_power_off;
+ hwmon_notifier_register(&ab8500_notifier);
return 0;
}