Lines Matching +full:shut +full:- +full:down +full:- +full:gpios
1 // SPDX-License-Identifier: GPL-2.0-or-later
6 * Maintainer: René Moll <linux@r-moll.nl>
8 * ----------------------------------------
9 * - Description
10 * ----------------------------------------
13 * Its function is to determine when a external shut down is triggered
14 * and react by properly shutting down the system.
18 * ----------------------------------------
19 * - GPIO
20 * ----------------------------------------
22 * The following GPIOs are used:
23 * - trigger (input)
24 * A level change indicates the shut-down trigger. If it's state reverts
25 * within the time-out defined by trigger_delay, the shut down is not
30 * - watchdog (output)
31 * Once a shut down is triggered, the driver will toggle this signal,
32 * with an internal (wde_interval) to stall the hardware shut down.
34 * - kill (output)
35 * The last action during shut down is triggering this signalling, such
36 * that the PowerPath Control will power down the hardware.
38 * ----------------------------------------
39 * - Interrupts
40 * ----------------------------------------
42 * The driver requires a non-shared, edge-triggered interrupt on the trigger
87 * ltc2952_poweroff_timer_wde - Timer callback
93 * machine actually shuts down
100 if (data->kernel_panic) in ltc2952_poweroff_timer_wde()
103 state = gpiod_get_value(data->gpio_watchdog); in ltc2952_poweroff_timer_wde()
104 gpiod_set_value(data->gpio_watchdog, !state); in ltc2952_poweroff_timer_wde()
106 hrtimer_forward_now(timer, data->wde_interval); in ltc2952_poweroff_timer_wde()
113 hrtimer_start(&data->timer_wde, data->wde_interval, HRTIMER_MODE_REL); in ltc2952_poweroff_start_wde()
122 dev_info(data->dev, "executing shutdown\n"); in ltc2952_poweroff_timer_trigger()
129 * ltc2952_poweroff_handler - Interrupt handler
131 * time-out (timer_trigger). Once the time-out is actually reached the shut
132 * down is executed.
141 if (data->kernel_panic || hrtimer_active(&data->timer_wde)) { in ltc2952_poweroff_handler()
146 if (gpiod_get_value(data->gpio_trigger)) { in ltc2952_poweroff_handler()
147 hrtimer_start(&data->timer_trigger, data->trigger_delay, in ltc2952_poweroff_handler()
150 hrtimer_cancel(&data->timer_trigger); in ltc2952_poweroff_handler()
157 gpiod_set_value(ltc2952_data->gpio_kill, 1); in ltc2952_poweroff_kill()
162 data->wde_interval = 300L * NSEC_PER_MSEC; in ltc2952_poweroff_default()
163 data->trigger_delay = ktime_set(2, 500L * NSEC_PER_MSEC); in ltc2952_poweroff_default()
165 hrtimer_init(&data->timer_trigger, CLOCK_MONOTONIC, HRTIMER_MODE_REL); in ltc2952_poweroff_default()
166 data->timer_trigger.function = ltc2952_poweroff_timer_trigger; in ltc2952_poweroff_default()
168 hrtimer_init(&data->timer_wde, CLOCK_MONOTONIC, HRTIMER_MODE_REL); in ltc2952_poweroff_default()
169 data->timer_wde.function = ltc2952_poweroff_timer_wde; in ltc2952_poweroff_default()
180 if (!device_property_read_u32(&pdev->dev, "trigger-delay-ms", in ltc2952_poweroff_init()
182 data->trigger_delay = ktime_set(trigger_delay_ms / MSEC_PER_SEC, in ltc2952_poweroff_init()
186 data->gpio_watchdog = devm_gpiod_get(&pdev->dev, "watchdog", in ltc2952_poweroff_init()
188 if (IS_ERR(data->gpio_watchdog)) { in ltc2952_poweroff_init()
189 ret = PTR_ERR(data->gpio_watchdog); in ltc2952_poweroff_init()
190 dev_err(&pdev->dev, "unable to claim gpio \"watchdog\"\n"); in ltc2952_poweroff_init()
194 data->gpio_kill = devm_gpiod_get(&pdev->dev, "kill", GPIOD_OUT_LOW); in ltc2952_poweroff_init()
195 if (IS_ERR(data->gpio_kill)) { in ltc2952_poweroff_init()
196 ret = PTR_ERR(data->gpio_kill); in ltc2952_poweroff_init()
197 dev_err(&pdev->dev, "unable to claim gpio \"kill\"\n"); in ltc2952_poweroff_init()
201 data->gpio_trigger = devm_gpiod_get_optional(&pdev->dev, "trigger", in ltc2952_poweroff_init()
203 if (IS_ERR(data->gpio_trigger)) { in ltc2952_poweroff_init()
209 dev_err(&pdev->dev, "unable to claim gpio \"trigger\"\n"); in ltc2952_poweroff_init()
210 data->gpio_trigger = NULL; in ltc2952_poweroff_init()
213 if (devm_request_irq(&pdev->dev, gpiod_to_irq(data->gpio_trigger), in ltc2952_poweroff_init()
216 "ltc2952-poweroff", in ltc2952_poweroff_init()
220 * - No trigger input was defined in ltc2952_poweroff_init()
221 * - Claiming the GPIO failed in ltc2952_poweroff_init()
222 * - We could not map to an IRQ in ltc2952_poweroff_init()
223 * - We couldn't register an interrupt handler in ltc2952_poweroff_init()
233 if (data->gpio_trigger) { in ltc2952_poweroff_init()
234 dev_warn(&pdev->dev, in ltc2952_poweroff_init()
236 devm_gpiod_put(&pdev->dev, data->gpio_trigger); in ltc2952_poweroff_init()
237 data->gpio_trigger = NULL; in ltc2952_poweroff_init()
239 dev_info(&pdev->dev, in ltc2952_poweroff_init()
240 "power down trigger input will not be used\n"); in ltc2952_poweroff_init()
252 data->kernel_panic = true; in ltc2952_poweroff_notify_panic()
262 dev_err(&pdev->dev, "pm_power_off already registered"); in ltc2952_poweroff_probe()
263 return -EBUSY; in ltc2952_poweroff_probe()
266 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); in ltc2952_poweroff_probe()
268 return -ENOMEM; in ltc2952_poweroff_probe()
270 data->dev = &pdev->dev; in ltc2952_poweroff_probe()
281 data->panic_notifier.notifier_call = ltc2952_poweroff_notify_panic; in ltc2952_poweroff_probe()
283 &data->panic_notifier); in ltc2952_poweroff_probe()
284 dev_info(&pdev->dev, "probe successful\n"); in ltc2952_poweroff_probe()
294 hrtimer_cancel(&data->timer_trigger); in ltc2952_poweroff_remove()
295 hrtimer_cancel(&data->timer_wde); in ltc2952_poweroff_remove()
297 &data->panic_notifier); in ltc2952_poweroff_remove()
310 .name = "ltc2952-poweroff",
318 MODULE_DESCRIPTION("LTC PowerPath power-off driver");