0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046 #include <linux/kernel.h>
0047 #include <linux/init.h>
0048 #include <linux/interrupt.h>
0049 #include <linux/device.h>
0050 #include <linux/platform_device.h>
0051 #include <linux/ktime.h>
0052 #include <linux/slab.h>
0053 #include <linux/kmod.h>
0054 #include <linux/module.h>
0055 #include <linux/panic_notifier.h>
0056 #include <linux/mod_devicetable.h>
0057 #include <linux/gpio/consumer.h>
0058 #include <linux/reboot.h>
0059 #include <linux/property.h>
0060
0061 struct ltc2952_poweroff {
0062 struct hrtimer timer_trigger;
0063 struct hrtimer timer_wde;
0064
0065 ktime_t trigger_delay;
0066 ktime_t wde_interval;
0067
0068 struct device *dev;
0069
0070 struct gpio_desc *gpio_trigger;
0071 struct gpio_desc *gpio_watchdog;
0072 struct gpio_desc *gpio_kill;
0073
0074 bool kernel_panic;
0075 struct notifier_block panic_notifier;
0076 };
0077
0078 #define to_ltc2952(p, m) container_of(p, struct ltc2952_poweroff, m)
0079
0080
0081
0082
0083
0084 static struct ltc2952_poweroff *ltc2952_data;
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095 static enum hrtimer_restart ltc2952_poweroff_timer_wde(struct hrtimer *timer)
0096 {
0097 int state;
0098 struct ltc2952_poweroff *data = to_ltc2952(timer, timer_wde);
0099
0100 if (data->kernel_panic)
0101 return HRTIMER_NORESTART;
0102
0103 state = gpiod_get_value(data->gpio_watchdog);
0104 gpiod_set_value(data->gpio_watchdog, !state);
0105
0106 hrtimer_forward_now(timer, data->wde_interval);
0107
0108 return HRTIMER_RESTART;
0109 }
0110
0111 static void ltc2952_poweroff_start_wde(struct ltc2952_poweroff *data)
0112 {
0113 hrtimer_start(&data->timer_wde, data->wde_interval, HRTIMER_MODE_REL);
0114 }
0115
0116 static enum hrtimer_restart
0117 ltc2952_poweroff_timer_trigger(struct hrtimer *timer)
0118 {
0119 struct ltc2952_poweroff *data = to_ltc2952(timer, timer_trigger);
0120
0121 ltc2952_poweroff_start_wde(data);
0122 dev_info(data->dev, "executing shutdown\n");
0123 orderly_poweroff(true);
0124
0125 return HRTIMER_NORESTART;
0126 }
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137 static irqreturn_t ltc2952_poweroff_handler(int irq, void *dev_id)
0138 {
0139 struct ltc2952_poweroff *data = dev_id;
0140
0141 if (data->kernel_panic || hrtimer_active(&data->timer_wde)) {
0142
0143 return IRQ_HANDLED;
0144 }
0145
0146 if (gpiod_get_value(data->gpio_trigger)) {
0147 hrtimer_start(&data->timer_trigger, data->trigger_delay,
0148 HRTIMER_MODE_REL);
0149 } else {
0150 hrtimer_cancel(&data->timer_trigger);
0151 }
0152 return IRQ_HANDLED;
0153 }
0154
0155 static void ltc2952_poweroff_kill(void)
0156 {
0157 gpiod_set_value(ltc2952_data->gpio_kill, 1);
0158 }
0159
0160 static void ltc2952_poweroff_default(struct ltc2952_poweroff *data)
0161 {
0162 data->wde_interval = 300L * NSEC_PER_MSEC;
0163 data->trigger_delay = ktime_set(2, 500L * NSEC_PER_MSEC);
0164
0165 hrtimer_init(&data->timer_trigger, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
0166 data->timer_trigger.function = ltc2952_poweroff_timer_trigger;
0167
0168 hrtimer_init(&data->timer_wde, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
0169 data->timer_wde.function = ltc2952_poweroff_timer_wde;
0170 }
0171
0172 static int ltc2952_poweroff_init(struct platform_device *pdev)
0173 {
0174 int ret;
0175 u32 trigger_delay_ms;
0176 struct ltc2952_poweroff *data = platform_get_drvdata(pdev);
0177
0178 ltc2952_poweroff_default(data);
0179
0180 if (!device_property_read_u32(&pdev->dev, "trigger-delay-ms",
0181 &trigger_delay_ms)) {
0182 data->trigger_delay = ktime_set(trigger_delay_ms / MSEC_PER_SEC,
0183 (trigger_delay_ms % MSEC_PER_SEC) * NSEC_PER_MSEC);
0184 }
0185
0186 data->gpio_watchdog = devm_gpiod_get(&pdev->dev, "watchdog",
0187 GPIOD_OUT_LOW);
0188 if (IS_ERR(data->gpio_watchdog)) {
0189 ret = PTR_ERR(data->gpio_watchdog);
0190 dev_err(&pdev->dev, "unable to claim gpio \"watchdog\"\n");
0191 return ret;
0192 }
0193
0194 data->gpio_kill = devm_gpiod_get(&pdev->dev, "kill", GPIOD_OUT_LOW);
0195 if (IS_ERR(data->gpio_kill)) {
0196 ret = PTR_ERR(data->gpio_kill);
0197 dev_err(&pdev->dev, "unable to claim gpio \"kill\"\n");
0198 return ret;
0199 }
0200
0201 data->gpio_trigger = devm_gpiod_get_optional(&pdev->dev, "trigger",
0202 GPIOD_IN);
0203 if (IS_ERR(data->gpio_trigger)) {
0204
0205
0206
0207
0208
0209 dev_err(&pdev->dev, "unable to claim gpio \"trigger\"\n");
0210 data->gpio_trigger = NULL;
0211 }
0212
0213 if (devm_request_irq(&pdev->dev, gpiod_to_irq(data->gpio_trigger),
0214 ltc2952_poweroff_handler,
0215 (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING),
0216 "ltc2952-poweroff",
0217 data)) {
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233 if (data->gpio_trigger) {
0234 dev_warn(&pdev->dev,
0235 "unable to configure the trigger interrupt\n");
0236 devm_gpiod_put(&pdev->dev, data->gpio_trigger);
0237 data->gpio_trigger = NULL;
0238 }
0239 dev_info(&pdev->dev,
0240 "power down trigger input will not be used\n");
0241 ltc2952_poweroff_start_wde(data);
0242 }
0243
0244 return 0;
0245 }
0246
0247 static int ltc2952_poweroff_notify_panic(struct notifier_block *nb,
0248 unsigned long code, void *unused)
0249 {
0250 struct ltc2952_poweroff *data = to_ltc2952(nb, panic_notifier);
0251
0252 data->kernel_panic = true;
0253 return NOTIFY_DONE;
0254 }
0255
0256 static int ltc2952_poweroff_probe(struct platform_device *pdev)
0257 {
0258 int ret;
0259 struct ltc2952_poweroff *data;
0260
0261 if (pm_power_off) {
0262 dev_err(&pdev->dev, "pm_power_off already registered");
0263 return -EBUSY;
0264 }
0265
0266 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
0267 if (!data)
0268 return -ENOMEM;
0269
0270 data->dev = &pdev->dev;
0271 platform_set_drvdata(pdev, data);
0272
0273 ret = ltc2952_poweroff_init(pdev);
0274 if (ret)
0275 return ret;
0276
0277
0278 ltc2952_data = data;
0279 pm_power_off = ltc2952_poweroff_kill;
0280
0281 data->panic_notifier.notifier_call = ltc2952_poweroff_notify_panic;
0282 atomic_notifier_chain_register(&panic_notifier_list,
0283 &data->panic_notifier);
0284 dev_info(&pdev->dev, "probe successful\n");
0285
0286 return 0;
0287 }
0288
0289 static int ltc2952_poweroff_remove(struct platform_device *pdev)
0290 {
0291 struct ltc2952_poweroff *data = platform_get_drvdata(pdev);
0292
0293 pm_power_off = NULL;
0294 hrtimer_cancel(&data->timer_trigger);
0295 hrtimer_cancel(&data->timer_wde);
0296 atomic_notifier_chain_unregister(&panic_notifier_list,
0297 &data->panic_notifier);
0298 return 0;
0299 }
0300
0301 static const struct of_device_id of_ltc2952_poweroff_match[] = {
0302 { .compatible = "lltc,ltc2952"},
0303 {},
0304 };
0305 MODULE_DEVICE_TABLE(of, of_ltc2952_poweroff_match);
0306
0307 static struct platform_driver ltc2952_poweroff_driver = {
0308 .probe = ltc2952_poweroff_probe,
0309 .remove = ltc2952_poweroff_remove,
0310 .driver = {
0311 .name = "ltc2952-poweroff",
0312 .of_match_table = of_ltc2952_poweroff_match,
0313 },
0314 };
0315
0316 module_platform_driver(ltc2952_poweroff_driver);
0317
0318 MODULE_AUTHOR("René Moll <rene.moll@xsens.com>");
0319 MODULE_DESCRIPTION("LTC PowerPath power-off driver");
0320 MODULE_LICENSE("GPL v2");