summaryrefslogtreecommitdiff
path: root/drivers/power/reset/ltc2952-poweroff.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power/reset/ltc2952-poweroff.c')
-rw-r--r--drivers/power/reset/ltc2952-poweroff.c87
1 files changed, 55 insertions, 32 deletions
diff --git a/drivers/power/reset/ltc2952-poweroff.c b/drivers/power/reset/ltc2952-poweroff.c
index b99bc251f5b4..7ef193b6f7fe 100644
--- a/drivers/power/reset/ltc2952-poweroff.c
+++ b/drivers/power/reset/ltc2952-poweroff.c
@@ -32,7 +32,9 @@
* - trigger (input)
* A level change indicates the shut-down trigger. If it's state reverts
* within the time-out defined by trigger_delay, the shut down is not
- * executed.
+ * executed. If no pin is assigned to this input, the driver will start the
+ * watchdog toggle immediately. The chip will only power off the system if
+ * it is requested to do so through the kill line.
*
* - watchdog (output)
* Once a shut down is triggered, the driver will toggle this signal,
@@ -116,15 +118,10 @@ static enum hrtimer_restart ltc2952_poweroff_timer_wde(struct hrtimer *timer)
return HRTIMER_RESTART;
}
-static enum hrtimer_restart
-ltc2952_poweroff_timer_trigger(struct hrtimer *timer)
+static void ltc2952_poweroff_start_wde(struct ltc2952_poweroff *data)
{
- struct ltc2952_poweroff *data = to_ltc2952(timer, timer_trigger);
- int ret = hrtimer_start(&data->timer_wde,
- data->wde_interval, HRTIMER_MODE_REL);
-
- if (ret) {
- dev_err(data->dev, "unable to start the timer\n");
+ if (hrtimer_start(&data->timer_wde, data->wde_interval,
+ HRTIMER_MODE_REL)) {
/*
* The device will not toggle the watchdog reset,
* thus shut down is only safe if the PowerPath controller
@@ -133,10 +130,17 @@ ltc2952_poweroff_timer_trigger(struct hrtimer *timer)
*
* Only sending a warning as the system will power-off anyway
*/
+ dev_err(data->dev, "unable to start the timer\n");
}
+}
- dev_info(data->dev, "executing shutdown\n");
+static enum hrtimer_restart
+ltc2952_poweroff_timer_trigger(struct hrtimer *timer)
+{
+ struct ltc2952_poweroff *data = to_ltc2952(timer, timer_trigger);
+ ltc2952_poweroff_start_wde(data);
+ dev_info(data->dev, "executing shutdown\n");
orderly_poweroff(true);
return HRTIMER_NORESTART;
@@ -190,7 +194,7 @@ static void ltc2952_poweroff_default(struct ltc2952_poweroff *data)
static int ltc2952_poweroff_init(struct platform_device *pdev)
{
- int ret, virq;
+ int ret;
struct ltc2952_poweroff *data = platform_get_drvdata(pdev);
ltc2952_poweroff_default(data);
@@ -210,29 +214,48 @@ static int ltc2952_poweroff_init(struct platform_device *pdev)
return ret;
}
- data->gpio_trigger = devm_gpiod_get(&pdev->dev, "trigger",
- GPIOD_IN);
- if (IS_ERR(ltc2952_data->gpio_trigger)) {
- ret = PTR_ERR(ltc2952_data->gpio_trigger);
- dev_err(&pdev->dev, "unable to claim gpio \"trigger\"\n");
- return ret;
- }
-
- virq = gpiod_to_irq(data->gpio_trigger);
- if (virq < 0) {
- dev_err(&pdev->dev, "cannot map GPIO as interrupt");
- return ret;
+ data->gpio_trigger = devm_gpiod_get(&pdev->dev, "trigger", GPIOD_IN);
+ if (IS_ERR(data->gpio_trigger)) {
+ /*
+ * It's not a problem if the trigger gpio isn't available, but
+ * it is worth a warning if its use was defined in the device
+ * tree.
+ */
+ if (PTR_ERR(data->gpio_trigger) != -ENOENT)
+ dev_err(&pdev->dev,
+ "unable to claim gpio \"trigger\"\n");
+ data->gpio_trigger = NULL;
}
- ret = devm_request_irq(&pdev->dev, virq,
- ltc2952_poweroff_handler,
- (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING),
- "ltc2952-poweroff",
- data);
-
- if (ret) {
- dev_err(&pdev->dev, "cannot configure an interrupt handler\n");
- return ret;
+ if (devm_request_irq(&pdev->dev, gpiod_to_irq(data->gpio_trigger),
+ ltc2952_poweroff_handler,
+ (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING),
+ "ltc2952-poweroff",
+ data)) {
+ /*
+ * Some things may have happened:
+ * - No trigger input was defined
+ * - Claiming the GPIO failed
+ * - We could not map to an IRQ
+ * - We couldn't register an interrupt handler
+ *
+ * None of these really are problems, but all of them
+ * disqualify the push button from controlling the power.
+ *
+ * It is therefore important to note that if the ltc2952
+ * detects a button press for long enough, it will still start
+ * its own powerdown window and cut the power on us if we don't
+ * start the watchdog trigger.
+ */
+ if (data->gpio_trigger) {
+ dev_warn(&pdev->dev,
+ "unable to configure the trigger interrupt\n");
+ devm_gpiod_put(&pdev->dev, data->gpio_trigger);
+ data->gpio_trigger = NULL;
+ }
+ dev_info(&pdev->dev,
+ "power down trigger input will not be used\n");
+ ltc2952_poweroff_start_wde(data);
}
return 0;