Skip to content
Snippets Groups Projects
Commit 040354b9 authored by paris_yeh's avatar paris_yeh Committed by Ed Tam
Browse files

keys: notify system preparing to force reset if resetkey is defined


On flo/deb hardware platform, the power key button is able to reset
whole system forcely via predefined timer at PMIC side. Add notifying
call chains to let registered drivers have a chance to prepare data
backup before power is cut off by PMIC firmware.

Change-Id: I25fe00020950f0d4208caffda172f46396082a4d
Signed-off-by: default avatarparis_yeh <paris_yeh@asus.com>
parent b5b6b5c3
No related branches found
No related tags found
No related merge requests found
...@@ -40,6 +40,9 @@ struct gpio_button_data { ...@@ -40,6 +40,9 @@ struct gpio_button_data {
spinlock_t lock; spinlock_t lock;
bool disabled; bool disabled;
bool key_pressed; bool key_pressed;
struct work_struct reset_work;
struct timer_list reset_timer;
unsigned int timer_hwreset; /* in msecs */
}; };
struct gpio_keys_drvdata { struct gpio_keys_drvdata {
...@@ -332,6 +335,28 @@ static char *key_descriptions[] = { ...@@ -332,6 +335,28 @@ static char *key_descriptions[] = {
}; };
#endif #endif
/* Routines for resetkey-transition notifications */
static BLOCKING_NOTIFIER_HEAD(resetkey_chain_head);
int register_resetkey_notifier(struct notifier_block *nb)
{
return blocking_notifier_chain_register(&resetkey_chain_head, nb);
}
EXPORT_SYMBOL_GPL(register_resetkey_notifier);
int unregister_resetkey_notifier(struct notifier_block *nb)
{
return blocking_notifier_chain_unregister(&resetkey_chain_head, nb);
}
EXPORT_SYMBOL_GPL(unregister_resetkey_notifier);
int resetkey_notifier_call_chain(unsigned long val)
{
int ret = blocking_notifier_call_chain(&resetkey_chain_head, val, NULL);
return notifier_to_errno(ret);
}
static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata) static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
{ {
const struct gpio_keys_button *button = bdata->button; const struct gpio_keys_button *button = bdata->button;
...@@ -363,6 +388,13 @@ static void gpio_keys_gpio_work_func(struct work_struct *work) ...@@ -363,6 +388,13 @@ static void gpio_keys_gpio_work_func(struct work_struct *work)
pr_info("gpio_keys: %s %s\n", state ? "Pressed" : "Released", pr_info("gpio_keys: %s %s\n", state ? "Pressed" : "Released",
key_descriptions[button->code - KEY_VOLUMEDOWN]); key_descriptions[button->code - KEY_VOLUMEDOWN]);
#endif #endif
if (button->can_reset) {
if (state)
mod_timer(&bdata->reset_timer,
jiffies + msecs_to_jiffies(bdata->timer_hwreset));
else
del_timer_sync(&bdata->reset_timer);
}
gpio_keys_gpio_report_event(bdata); gpio_keys_gpio_report_event(bdata);
} }
...@@ -373,6 +405,19 @@ static void gpio_keys_gpio_timer(unsigned long _data) ...@@ -373,6 +405,19 @@ static void gpio_keys_gpio_timer(unsigned long _data)
schedule_work(&bdata->work); schedule_work(&bdata->work);
} }
static void reset_keys_work_func(struct work_struct *work)
{
pr_info("gpio_keys: notify listeners pmic preparing to reset\n");
resetkey_notifier_call_chain(RESETKEY_PREPARE_HWREST);
}
static void powerkey_gpio_timer(unsigned long _data)
{
struct gpio_button_data *bdata = (struct gpio_button_data *)_data;
schedule_work(&bdata->reset_work);
}
static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id) static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
{ {
struct gpio_button_data *bdata = dev_id; struct gpio_button_data *bdata = dev_id;
...@@ -493,6 +538,13 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev, ...@@ -493,6 +538,13 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
isr = gpio_keys_gpio_isr; isr = gpio_keys_gpio_isr;
irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
if (button->can_reset) {
INIT_WORK(&bdata->reset_work, reset_keys_work_func);
bdata->timer_hwreset = button->reset_interval;
setup_timer(&bdata->reset_timer, powerkey_gpio_timer,
(unsigned long)bdata);
}
} else { } else {
if (!button->irq) { if (!button->irq) {
dev_err(dev, "No IRQ specified\n"); dev_err(dev, "No IRQ specified\n");
......
...@@ -15,6 +15,8 @@ struct gpio_keys_button { ...@@ -15,6 +15,8 @@ struct gpio_keys_button {
bool can_disable; bool can_disable;
int value; /* axis value for EV_ABS */ int value; /* axis value for EV_ABS */
unsigned int irq; /* Irq number in case of interrupt keys */ unsigned int irq; /* Irq number in case of interrupt keys */
bool can_reset; /* key is able to reset system */
int reset_interval; /* reset key interval in msec */
}; };
struct gpio_keys_platform_data { struct gpio_keys_platform_data {
...@@ -28,4 +30,12 @@ struct gpio_keys_platform_data { ...@@ -28,4 +30,12 @@ struct gpio_keys_platform_data {
const char *name; /* input device name */ const char *name; /* input device name */
}; };
#define RESETKEY_PRESS 0x0001 /* power key is pressed */
#define RESETKEY_RELEASE 0x0002 /* power key is released */
#define RESETKEY_PREPARE_HWREST 0x0003 /* Going to reset whole system by pmic*/
extern int register_resetkey_notifier(struct notifier_block *nb);
extern int unregister_resetkey_notifier(struct notifier_block *nb);
#endif #endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment