diff options
Diffstat (limited to 'drivers/power/reset')
-rw-r--r-- | drivers/power/reset/ltc2952-poweroff.c | 87 |
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; |