Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

power: reset: ltc2952: make trigger input optional

Currently the ltc2952 supports only one button sequence to initiate
powerdown. This is not always desirable, as even prolonged button
presses can happen in use.

Allow ltc2952 users to pick their own power down sequence, by making the
trigger input optional. Since this still means that the ltc2952 may
power down the platform if the power button is pressed for about 5
seconds, we still need to make sure to start the watchdog toggle to
prolong the system power for as long as we need it.

This will still allow the system to control power using the kill signal.

Signed-off-by: Frans Klaver <frans.klaver@xsens.com>
Signed-off-by: Sebastian Reichel <sre@kernel.org>

authored by

Frans Klaver and committed by
Sebastian Reichel
ee181853 c1ada2ff

+55 -32
+55 -32
drivers/power/reset/ltc2952-poweroff.c
··· 32 32 * - trigger (input) 33 33 * A level change indicates the shut-down trigger. If it's state reverts 34 34 * within the time-out defined by trigger_delay, the shut down is not 35 - * executed. 35 + * executed. If no pin is assigned to this input, the driver will start the 36 + * watchdog toggle immediately. The chip will only power off the system if 37 + * it is requested to do so through the kill line. 36 38 * 37 39 * - watchdog (output) 38 40 * Once a shut down is triggered, the driver will toggle this signal, ··· 118 116 return HRTIMER_RESTART; 119 117 } 120 118 121 - static enum hrtimer_restart 122 - ltc2952_poweroff_timer_trigger(struct hrtimer *timer) 119 + static void ltc2952_poweroff_start_wde(struct ltc2952_poweroff *data) 123 120 { 124 - struct ltc2952_poweroff *data = to_ltc2952(timer, timer_trigger); 125 - int ret = hrtimer_start(&data->timer_wde, 126 - data->wde_interval, HRTIMER_MODE_REL); 127 - 128 - if (ret) { 129 - dev_err(data->dev, "unable to start the timer\n"); 121 + if (hrtimer_start(&data->timer_wde, data->wde_interval, 122 + HRTIMER_MODE_REL)) { 130 123 /* 131 124 * The device will not toggle the watchdog reset, 132 125 * thus shut down is only safe if the PowerPath controller ··· 130 133 * 131 134 * Only sending a warning as the system will power-off anyway 132 135 */ 136 + dev_err(data->dev, "unable to start the timer\n"); 133 137 } 138 + } 134 139 140 + static enum hrtimer_restart 141 + ltc2952_poweroff_timer_trigger(struct hrtimer *timer) 142 + { 143 + struct ltc2952_poweroff *data = to_ltc2952(timer, timer_trigger); 144 + 145 + ltc2952_poweroff_start_wde(data); 135 146 dev_info(data->dev, "executing shutdown\n"); 136 - 137 147 orderly_poweroff(true); 138 148 139 149 return HRTIMER_NORESTART; ··· 194 190 195 191 static int ltc2952_poweroff_init(struct platform_device *pdev) 196 192 { 197 - int ret, virq; 193 + int ret; 198 194 struct ltc2952_poweroff *data = platform_get_drvdata(pdev); 199 195 200 196 ltc2952_poweroff_default(data); ··· 214 210 return ret; 215 211 } 216 212 217 - data->gpio_trigger = devm_gpiod_get(&pdev->dev, "trigger", 218 - GPIOD_IN); 219 - if (IS_ERR(ltc2952_data->gpio_trigger)) { 220 - ret = PTR_ERR(ltc2952_data->gpio_trigger); 221 - dev_err(&pdev->dev, "unable to claim gpio \"trigger\"\n"); 222 - return ret; 213 + data->gpio_trigger = devm_gpiod_get(&pdev->dev, "trigger", GPIOD_IN); 214 + if (IS_ERR(data->gpio_trigger)) { 215 + /* 216 + * It's not a problem if the trigger gpio isn't available, but 217 + * it is worth a warning if its use was defined in the device 218 + * tree. 219 + */ 220 + if (PTR_ERR(data->gpio_trigger) != -ENOENT) 221 + dev_err(&pdev->dev, 222 + "unable to claim gpio \"trigger\"\n"); 223 + data->gpio_trigger = NULL; 223 224 } 224 225 225 - virq = gpiod_to_irq(data->gpio_trigger); 226 - if (virq < 0) { 227 - dev_err(&pdev->dev, "cannot map GPIO as interrupt"); 228 - return ret; 229 - } 230 - 231 - ret = devm_request_irq(&pdev->dev, virq, 232 - ltc2952_poweroff_handler, 233 - (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING), 234 - "ltc2952-poweroff", 235 - data); 236 - 237 - if (ret) { 238 - dev_err(&pdev->dev, "cannot configure an interrupt handler\n"); 239 - return ret; 226 + if (devm_request_irq(&pdev->dev, gpiod_to_irq(data->gpio_trigger), 227 + ltc2952_poweroff_handler, 228 + (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING), 229 + "ltc2952-poweroff", 230 + data)) { 231 + /* 232 + * Some things may have happened: 233 + * - No trigger input was defined 234 + * - Claiming the GPIO failed 235 + * - We could not map to an IRQ 236 + * - We couldn't register an interrupt handler 237 + * 238 + * None of these really are problems, but all of them 239 + * disqualify the push button from controlling the power. 240 + * 241 + * It is therefore important to note that if the ltc2952 242 + * detects a button press for long enough, it will still start 243 + * its own powerdown window and cut the power on us if we don't 244 + * start the watchdog trigger. 245 + */ 246 + if (data->gpio_trigger) { 247 + dev_warn(&pdev->dev, 248 + "unable to configure the trigger interrupt\n"); 249 + devm_gpiod_put(&pdev->dev, data->gpio_trigger); 250 + data->gpio_trigger = NULL; 251 + } 252 + dev_info(&pdev->dev, 253 + "power down trigger input will not be used\n"); 254 + ltc2952_poweroff_start_wde(data); 240 255 } 241 256 242 257 return 0;