// SPDX-License-Identifier: GPL-2.0-or-later /* * LTC2952 (PowerPath) driver * * Copyright (C) 2014, Xsens Technologies BV <[email protected]> * Maintainer: René Moll <[email protected]> * * ---------------------------------------- * - Description * ---------------------------------------- * * This driver is to be used with an external PowerPath Controller (LTC2952). * Its function is to determine when a external shut down is triggered * and react by properly shutting down the system. * * This driver expects a device tree with a ltc2952 entry for pin mapping. * * ---------------------------------------- * - GPIO * ---------------------------------------- * * The following GPIOs are used: * - 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. 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, * with an internal (wde_interval) to stall the hardware shut down. * * - kill (output) * The last action during shut down is triggering this signalling, such * that the PowerPath Control will power down the hardware. * * ---------------------------------------- * - Interrupts * ---------------------------------------- * * The driver requires a non-shared, edge-triggered interrupt on the trigger * GPIO. */ #include <linux/kernel.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/device.h> #include <linux/platform_device.h> #include <linux/ktime.h> #include <linux/slab.h> #include <linux/kmod.h> #include <linux/module.h> #include <linux/panic_notifier.h> #include <linux/mod_devicetable.h> #include <linux/gpio/consumer.h> #include <linux/reboot.h> #include <linux/property.h> struct ltc2952_poweroff { … }; #define to_ltc2952(p, m) … /* * This global variable is only needed for pm_power_off. We should * remove it entirely once we don't need the global state anymore. */ static struct ltc2952_poweroff *ltc2952_data; /** * ltc2952_poweroff_timer_wde - Timer callback * Toggles the watchdog reset signal each wde_interval * * @timer: corresponding timer * * Returns HRTIMER_RESTART for an infinite loop which will only stop when the * machine actually shuts down */ static enum hrtimer_restart ltc2952_poweroff_timer_wde(struct hrtimer *timer) { … } static void ltc2952_poweroff_start_wde(struct ltc2952_poweroff *data) { … } static enum hrtimer_restart ltc2952_poweroff_timer_trigger(struct hrtimer *timer) { … } /** * ltc2952_poweroff_handler - Interrupt handler * Triggered each time the trigger signal changes state and (de)activates a * time-out (timer_trigger). Once the time-out is actually reached the shut * down is executed. * * @irq: IRQ number * @dev_id: pointer to the main data structure */ static irqreturn_t ltc2952_poweroff_handler(int irq, void *dev_id) { … } static void ltc2952_poweroff_kill(void) { … } static void ltc2952_poweroff_default(struct ltc2952_poweroff *data) { … } static int ltc2952_poweroff_init(struct platform_device *pdev) { … } static int ltc2952_poweroff_notify_panic(struct notifier_block *nb, unsigned long code, void *unused) { … } static int ltc2952_poweroff_probe(struct platform_device *pdev) { … } static void ltc2952_poweroff_remove(struct platform_device *pdev) { … } static const struct of_device_id of_ltc2952_poweroff_match[] = …; MODULE_DEVICE_TABLE(of, of_ltc2952_poweroff_match); static struct platform_driver ltc2952_poweroff_driver = …; module_platform_driver(…) …; MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …;