summaryrefslogtreecommitdiff
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
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>
-rw-r--r--drivers/hwmon/ab8500.c2
-rw-r--r--drivers/hwmon/abx500.c1
-rw-r--r--drivers/hwmon/dbx500.c1
-rw-r--r--drivers/mfd/ab8500-sysctrl.c50
-rw-r--r--include/linux/mfd/abx500/ab8500.h7
5 files changed, 57 insertions, 4 deletions
diff --git a/drivers/hwmon/ab8500.c b/drivers/hwmon/ab8500.c
index 45a8ef675b3..db601e3158d 100644
--- a/drivers/hwmon/ab8500.c
+++ b/drivers/hwmon/ab8500.c
@@ -117,6 +117,8 @@ static int ab8500_temp_irq_handler(int irq, struct abx500_temp *data)
mutex_lock(&data->lock);
data->crit_alarm[4] = 1;
mutex_unlock(&data->lock);
+
+ hwmon_notify(data->crit_alarm[4], NULL);
sysfs_notify(&data->pdev->dev.kobj, NULL, "temp5_crit_alarm");
dev_info(&data->pdev->dev, "AB8500 thermal warning,"
" power off in %lu s\n", data->power_off_delay);
diff --git a/drivers/hwmon/abx500.c b/drivers/hwmon/abx500.c
index 6666dc27065..68da2d03dbd 100644
--- a/drivers/hwmon/abx500.c
+++ b/drivers/hwmon/abx500.c
@@ -163,6 +163,7 @@ static void gpadc_monitor(struct work_struct *work)
ret);
break;
}
+ hwmon_notify(data->max_alarm[i], NULL);
sysfs_notify(&data->pdev->dev.kobj, NULL, alarm_node);
}
if (updated_max_hyst_alarm) {
diff --git a/drivers/hwmon/dbx500.c b/drivers/hwmon/dbx500.c
index a26e08b3707..cd44e78030c 100644
--- a/drivers/hwmon/dbx500.c
+++ b/drivers/hwmon/dbx500.c
@@ -323,6 +323,7 @@ static irqreturn_t prcmu_hotmon_high_irq_handler(int irq, void *irq_data)
data->max_alarm[0] = 1;
mutex_unlock(&data->lock);
+ hwmon_notify(data->max_alarm[0], NULL);
sysfs_notify(&pdev->dev.kobj, NULL, "temp1_max_alarm");
dev_dbg(&pdev->dev, "DBX500 thermal warning, power off in %lu s\n",
(data->power_off_delay) / 1000);
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;
}
diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
index c1016272ab2..f746cf3ca34 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -266,6 +266,10 @@ struct ab8500_gpio_platform_data;
/**
* struct ab8500_platform_data - AB8500 platform data
+ * @pm_power_off: Should machine pm power off hook be registered or not
+ * @thermal_power_off_pending: Set if there was a thermal alarm
+ * @thermal_set_time_sec: Time of the thermal alarm
+ * @thermal_time_out: Time out before the thermal alarm should be ignored
* @irq_base: start of AB8500 IRQs, AB8500_NR_IRQS will be used
* @init: board-specific initialization after detection of ab8500
* @num_regulator_reg_init: number of regulator init registers
@@ -279,6 +283,9 @@ struct ab8500_gpio_platform_data;
struct ab8500_platform_data {
int irq_base;
bool pm_power_off;
+ bool thermal_power_off_pending;
+ long thermal_set_time_sec;
+ long thermal_time_out;
void (*init) (struct ab8500 *);
int num_regulator_reg_init;
struct ab8500_regulator_reg_init *regulator_reg_init;