aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power/reset
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-10-15 00:56:23 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-15 00:56:23 -0400
commit50fa86172bec2769979b5eb0cd1a244391ae4bb0 (patch)
tree5fd4949b031e1362af8b226d6372da2604de13ff /drivers/power/reset
parent6b0490816671b2f4126a99998c9bf3c8c0472de2 (diff)
parent7881c64716f3a7d60b325ed0ad4d15f49b474a43 (diff)
Merge tag 'for-v3.18' of git://git.infradead.org/battery-2.6
Pull power supply and reset updates from Sebastian Reichel: - Initial support for the following chips * max77836 (charger) * max14577 (charger) * bq27742 (battery gauge) * ltc2952 (poweroff) * stih416 (restart) * syscon-reboot (restart) * gpio-restart (restart) - cleanup of power supply core - misc fixes in power supply and reset drivers * tag 'for-v3.18' of git://git.infradead.org/battery-2.6: (48 commits) power: ab8500_fg: Fix build warning Documentation: charger: max14577: Update the date of introducing ABI power: reset: corrections for simple syscon reboot driver Documentation: power: reset: Add documentation for generic SYSCON reboot driver power: reset: Add generic SYSCON register mapped reset bq27x00_battery: Fix flag reading for bq27742 power: reset: use restart_notifier mechanism for msm-poweroff power: Add simple gpio-restart driver power: reset: st: Provide DT bindings for ST's Power Reset driver power: reset: Add restart functionality for STiH41x platforms power: charger-manager: Fix NULL pointer exception with missing cm-fuel-gauge power: max14577: Fix circular config SYSFS dependency power: gpio-charger: do not use gpio value directly power: max8925: Use of_get_child_by_name power: max8925: Fix NULL ptr dereference on memory allocation failure bq27x00_battery: Add support to bq27742 Documentation: charger: max14577: Document exported sysfs entry devicetree: mfd: max14577: Add device tree bindings document power: max17040: Add ID for MAX77836 Fuel Gauge block charger: max14577: Configure battery-dependent settings from DTS and sysfs ... Conflicts: drivers/power/reset/Kconfig drivers/power/reset/Makefile
Diffstat (limited to 'drivers/power/reset')
-rw-r--r--drivers/power/reset/Kconfig33
-rw-r--r--drivers/power/reset/Makefile4
-rw-r--r--drivers/power/reset/gpio-restart.c149
-rw-r--r--drivers/power/reset/ltc2952-poweroff.c386
-rw-r--r--drivers/power/reset/msm-poweroff.c20
-rw-r--r--drivers/power/reset/st-poweroff.c151
-rw-r--r--drivers/power/reset/syscon-reboot.c91
-rw-r--r--drivers/power/reset/xgene-reboot.c2
8 files changed, 827 insertions, 9 deletions
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index 527a0f47ef44..f65ff49bb275 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -40,7 +40,7 @@ config POWER_RESET_AXXIA
40 40
41config POWER_RESET_BRCMSTB 41config POWER_RESET_BRCMSTB
42 bool "Broadcom STB reset driver" if COMPILE_TEST 42 bool "Broadcom STB reset driver" if COMPILE_TEST
43 depends on POWER_RESET && ARM 43 depends on ARM
44 default ARCH_BRCMSTB 44 default ARCH_BRCMSTB
45 help 45 help
46 This driver provides restart support for ARM-based Broadcom STB 46 This driver provides restart support for ARM-based Broadcom STB
@@ -57,9 +57,17 @@ config POWER_RESET_GPIO
57 If your board needs a GPIO high/low to power down, say Y and 57 If your board needs a GPIO high/low to power down, say Y and
58 create a binding in your devicetree. 58 create a binding in your devicetree.
59 59
60config POWER_RESET_GPIO_RESTART
61 bool "GPIO restart driver"
62 depends on OF_GPIO
63 help
64 This driver supports restarting your board via a GPIO line.
65 If your board needs a GPIO high/low to restart, say Y and
66 create a binding in your devicetree.
67
60config POWER_RESET_HISI 68config POWER_RESET_HISI
61 bool "Hisilicon power-off driver" 69 bool "Hisilicon power-off driver"
62 depends on POWER_RESET && ARCH_HISI 70 depends on ARCH_HISI
63 help 71 help
64 Reboot support for Hisilicon boards. 72 Reboot support for Hisilicon boards.
65 73
@@ -69,6 +77,13 @@ config POWER_RESET_MSM
69 help 77 help
70 Power off and restart support for Qualcomm boards. 78 Power off and restart support for Qualcomm boards.
71 79
80config POWER_RESET_LTC2952
81 bool "LTC2952 PowerPath power-off driver"
82 depends on OF_GPIO
83 help
84 This driver supports an external powerdown trigger and board power
85 down via the LTC2952. Bindings are made in the device tree.
86
72config POWER_RESET_QNAP 87config POWER_RESET_QNAP
73 bool "QNAP power-off driver" 88 bool "QNAP power-off driver"
74 depends on OF_GPIO && PLAT_ORION 89 depends on OF_GPIO && PLAT_ORION
@@ -92,6 +107,12 @@ config POWER_RESET_SUN6I
92 help 107 help
93 Reboot support for the Allwinner A31 SoCs. 108 Reboot support for the Allwinner A31 SoCs.
94 109
110config POWER_RESET_ST
111 bool "ST restart power-off driver"
112 depends on ARCH_STI
113 help
114 Power off and reset support for STMicroelectronics boards.
115
95config POWER_RESET_VERSATILE 116config POWER_RESET_VERSATILE
96 bool "ARM Versatile family reboot driver" 117 bool "ARM Versatile family reboot driver"
97 depends on ARM 118 depends on ARM
@@ -122,4 +143,12 @@ config POWER_RESET_KEYSTONE
122 help 143 help
123 Reboot support for the KEYSTONE SoCs. 144 Reboot support for the KEYSTONE SoCs.
124 145
146config POWER_RESET_SYSCON
147 bool "Generic SYSCON regmap reset driver"
148 depends on OF
149 select MFD_SYSCON
150 help
151 Reboot support for generic SYSCON mapped register reset.
152
125endif 153endif
154
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 73221009f2bf..76ce1c59469b 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -4,12 +4,16 @@ obj-$(CONFIG_POWER_RESET_AT91_RESET) += at91-reset.o
4obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o 4obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o
5obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o 5obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o
6obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o 6obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
7obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
7obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o 8obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o
8obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o 9obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
10obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o
9obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o 11obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
10obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o 12obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
11obj-$(CONFIG_POWER_RESET_SUN6I) += sun6i-reboot.o 13obj-$(CONFIG_POWER_RESET_SUN6I) += sun6i-reboot.o
14obj-$(CONFIG_POWER_RESET_ST) += st-poweroff.o
12obj-$(CONFIG_POWER_RESET_VERSATILE) += arm-versatile-reboot.o 15obj-$(CONFIG_POWER_RESET_VERSATILE) += arm-versatile-reboot.o
13obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o 16obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o
14obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o 17obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o
15obj-$(CONFIG_POWER_RESET_KEYSTONE) += keystone-reset.o 18obj-$(CONFIG_POWER_RESET_KEYSTONE) += keystone-reset.o
19obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o
diff --git a/drivers/power/reset/gpio-restart.c b/drivers/power/reset/gpio-restart.c
new file mode 100644
index 000000000000..a76829b3f1cd
--- /dev/null
+++ b/drivers/power/reset/gpio-restart.c
@@ -0,0 +1,149 @@
1/*
2 * Toggles a GPIO pin to restart a device
3 *
4 * Copyright (C) 2014 Google, Inc.
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * Based on the gpio-poweroff driver.
16 */
17#include <linux/reboot.h>
18#include <linux/kernel.h>
19#include <linux/init.h>
20#include <linux/delay.h>
21#include <linux/platform_device.h>
22#include <linux/gpio/consumer.h>
23#include <linux/of_platform.h>
24#include <linux/module.h>
25
26struct gpio_restart {
27 struct gpio_desc *reset_gpio;
28 struct notifier_block restart_handler;
29 u32 active_delay_ms;
30 u32 inactive_delay_ms;
31 u32 wait_delay_ms;
32};
33
34static int gpio_restart_notify(struct notifier_block *this,
35 unsigned long mode, void *cmd)
36{
37 struct gpio_restart *gpio_restart =
38 container_of(this, struct gpio_restart, restart_handler);
39
40 /* drive it active, also inactive->active edge */
41 gpiod_direction_output(gpio_restart->reset_gpio, 1);
42 mdelay(gpio_restart->active_delay_ms);
43
44 /* drive inactive, also active->inactive edge */
45 gpiod_set_value(gpio_restart->reset_gpio, 0);
46 mdelay(gpio_restart->inactive_delay_ms);
47
48 /* drive it active, also inactive->active edge */
49 gpiod_set_value(gpio_restart->reset_gpio, 1);
50
51 /* give it some time */
52 mdelay(gpio_restart->wait_delay_ms);
53
54 WARN_ON(1);
55
56 return NOTIFY_DONE;
57}
58
59static int gpio_restart_probe(struct platform_device *pdev)
60{
61 struct gpio_restart *gpio_restart;
62 bool open_source = false;
63 u32 property;
64 int ret;
65
66 gpio_restart = devm_kzalloc(&pdev->dev, sizeof(*gpio_restart),
67 GFP_KERNEL);
68 if (!gpio_restart)
69 return -ENOMEM;
70
71 open_source = of_property_read_bool(pdev->dev.of_node, "open-source");
72
73 gpio_restart->reset_gpio = devm_gpiod_get(&pdev->dev, NULL,
74 open_source ? GPIOD_IN : GPIOD_OUT_LOW);
75 if (IS_ERR(gpio_restart->reset_gpio)) {
76 dev_err(&pdev->dev, "Could net get reset GPIO\n");
77 return PTR_ERR(gpio_restart->reset_gpio);
78 }
79
80 gpio_restart->restart_handler.notifier_call = gpio_restart_notify;
81 gpio_restart->restart_handler.priority = 128;
82 gpio_restart->active_delay_ms = 100;
83 gpio_restart->inactive_delay_ms = 100;
84 gpio_restart->wait_delay_ms = 3000;
85
86 ret = of_property_read_u32(pdev->dev.of_node, "priority", &property);
87 if (!ret) {
88 if (property > 255)
89 dev_err(&pdev->dev, "Invalid priority property: %u\n",
90 property);
91 else
92 gpio_restart->restart_handler.priority = property;
93 }
94
95 of_property_read_u32(pdev->dev.of_node, "active-delay",
96 &gpio_restart->active_delay_ms);
97 of_property_read_u32(pdev->dev.of_node, "inactive-delay",
98 &gpio_restart->inactive_delay_ms);
99 of_property_read_u32(pdev->dev.of_node, "wait-delay",
100 &gpio_restart->wait_delay_ms);
101
102 platform_set_drvdata(pdev, gpio_restart);
103
104 ret = register_restart_handler(&gpio_restart->restart_handler);
105 if (ret) {
106 dev_err(&pdev->dev, "%s: cannot register restart handler, %d\n",
107 __func__, ret);
108 return -ENODEV;
109 }
110
111 return 0;
112}
113
114static int gpio_restart_remove(struct platform_device *pdev)
115{
116 struct gpio_restart *gpio_restart = platform_get_drvdata(pdev);
117 int ret;
118
119 ret = unregister_restart_handler(&gpio_restart->restart_handler);
120 if (ret) {
121 dev_err(&pdev->dev,
122 "%s: cannot unregister restart handler, %d\n",
123 __func__, ret);
124 return -ENODEV;
125 }
126
127 return 0;
128}
129
130static const struct of_device_id of_gpio_restart_match[] = {
131 { .compatible = "gpio-restart", },
132 {},
133};
134
135static struct platform_driver gpio_restart_driver = {
136 .probe = gpio_restart_probe,
137 .remove = gpio_restart_remove,
138 .driver = {
139 .name = "restart-gpio",
140 .owner = THIS_MODULE,
141 .of_match_table = of_gpio_restart_match,
142 },
143};
144
145module_platform_driver(gpio_restart_driver);
146
147MODULE_AUTHOR("David Riley <davidriley@chromium.org>");
148MODULE_DESCRIPTION("GPIO restart driver");
149MODULE_LICENSE("GPL");
diff --git a/drivers/power/reset/ltc2952-poweroff.c b/drivers/power/reset/ltc2952-poweroff.c
new file mode 100644
index 000000000000..116a1cef8f7b
--- /dev/null
+++ b/drivers/power/reset/ltc2952-poweroff.c
@@ -0,0 +1,386 @@
1/*
2 * LTC2952 (PowerPath) driver
3 *
4 * Copyright (C) 2014, Xsens Technologies BV <info@xsens.com>
5 * Maintainer: René Moll <linux@r-moll.nl>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * ----------------------------------------
18 * - Description
19 * ----------------------------------------
20 *
21 * This driver is to be used with an external PowerPath Controller (LTC2952).
22 * Its function is to determine when a external shut down is triggered
23 * and react by properly shutting down the system.
24 *
25 * This driver expects a device tree with a ltc2952 entry for pin mapping.
26 *
27 * ----------------------------------------
28 * - GPIO
29 * ----------------------------------------
30 *
31 * The following GPIOs are used:
32 * - trigger (input)
33 * A level change indicates the shut-down trigger. If it's state reverts
34 * within the time-out defined by trigger_delay, the shut down is not
35 * executed.
36 *
37 * - watchdog (output)
38 * Once a shut down is triggered, the driver will toggle this signal,
39 * with an internal (wde_interval) to stall the hardware shut down.
40 *
41 * - kill (output)
42 * The last action during shut down is triggering this signalling, such
43 * that the PowerPath Control will power down the hardware.
44 *
45 * ----------------------------------------
46 * - Interrupts
47 * ----------------------------------------
48 *
49 * The driver requires a non-shared, edge-triggered interrupt on the trigger
50 * GPIO.
51 *
52 */
53
54#include <linux/kernel.h>
55#include <linux/init.h>
56#include <linux/interrupt.h>
57#include <linux/device.h>
58#include <linux/platform_device.h>
59#include <linux/ktime.h>
60#include <linux/slab.h>
61#include <linux/kmod.h>
62#include <linux/module.h>
63#include <linux/gpio/consumer.h>
64#include <linux/reboot.h>
65
66struct ltc2952_poweroff_data {
67 struct hrtimer timer_trigger;
68 struct hrtimer timer_wde;
69
70 ktime_t trigger_delay;
71 ktime_t wde_interval;
72
73 struct device *dev;
74
75 unsigned int virq;
76
77 /**
78 * 0: trigger
79 * 1: watchdog
80 * 2: kill
81 */
82 struct gpio_desc *gpio[3];
83};
84
85static int ltc2952_poweroff_panic;
86static struct ltc2952_poweroff_data *ltc2952_data;
87
88#define POWERPATH_IO_TRIGGER 0
89#define POWERPATH_IO_WATCHDOG 1
90#define POWERPATH_IO_KILL 2
91
92/**
93 * ltc2952_poweroff_timer_wde - Timer callback
94 * Toggles the watchdog reset signal each wde_interval
95 *
96 * @timer: corresponding timer
97 *
98 * Returns HRTIMER_RESTART for an infinite loop which will only stop when the
99 * machine actually shuts down
100 */
101static enum hrtimer_restart ltc2952_poweroff_timer_wde(struct hrtimer *timer)
102{
103 ktime_t now;
104 int state;
105 unsigned long overruns;
106
107 if (ltc2952_poweroff_panic)
108 return HRTIMER_NORESTART;
109
110 state = gpiod_get_value(ltc2952_data->gpio[POWERPATH_IO_WATCHDOG]);
111 gpiod_set_value(ltc2952_data->gpio[POWERPATH_IO_WATCHDOG], !state);
112
113 now = hrtimer_cb_get_time(timer);
114 overruns = hrtimer_forward(timer, now, ltc2952_data->wde_interval);
115
116 return HRTIMER_RESTART;
117}
118
119static enum hrtimer_restart ltc2952_poweroff_timer_trigger(
120 struct hrtimer *timer)
121{
122 int ret;
123
124 ret = hrtimer_start(&ltc2952_data->timer_wde,
125 ltc2952_data->wde_interval, HRTIMER_MODE_REL);
126
127 if (ret) {
128 dev_err(ltc2952_data->dev, "unable to start the timer\n");
129 /*
130 * The device will not toggle the watchdog reset,
131 * thus shut down is only safe if the PowerPath controller
132 * has a long enough time-off before triggering a hardware
133 * power-off.
134 *
135 * Only sending a warning as the system will power-off anyway
136 */
137 }
138
139 dev_info(ltc2952_data->dev, "executing shutdown\n");
140
141 orderly_poweroff(true);
142
143 return HRTIMER_NORESTART;
144}
145
146/**
147 * ltc2952_poweroff_handler - Interrupt handler
148 * Triggered each time the trigger signal changes state and (de)activates a
149 * time-out (timer_trigger). Once the time-out is actually reached the shut
150 * down is executed.
151 *
152 * @irq: IRQ number
153 * @dev_id: pointer to the main data structure
154 */
155static irqreturn_t ltc2952_poweroff_handler(int irq, void *dev_id)
156{
157 int ret;
158 struct ltc2952_poweroff_data *data = dev_id;
159
160 if (ltc2952_poweroff_panic)
161 goto irq_ok;
162
163 if (hrtimer_active(&data->timer_wde)) {
164 /* shutdown is already triggered, nothing to do any more */
165 goto irq_ok;
166 }
167
168 if (!hrtimer_active(&data->timer_trigger)) {
169 ret = hrtimer_start(&data->timer_trigger, data->trigger_delay,
170 HRTIMER_MODE_REL);
171
172 if (ret)
173 dev_err(data->dev, "unable to start the wait timer\n");
174 } else {
175 ret = hrtimer_cancel(&data->timer_trigger);
176 /* omitting return value check, timer should have been valid */
177 }
178
179irq_ok:
180 return IRQ_HANDLED;
181}
182
183static void ltc2952_poweroff_kill(void)
184{
185 gpiod_set_value(ltc2952_data->gpio[POWERPATH_IO_KILL], 1);
186}
187
188static int ltc2952_poweroff_suspend(struct platform_device *pdev,
189 pm_message_t state)
190{
191 return -ENOSYS;
192}
193
194static int ltc2952_poweroff_resume(struct platform_device *pdev)
195{
196 return -ENOSYS;
197}
198
199static void ltc2952_poweroff_default(struct ltc2952_poweroff_data *data)
200{
201 unsigned int i;
202
203 for (i = 0; i < ARRAY_SIZE(data->gpio); i++)
204 data->gpio[i] = NULL;
205
206 data->wde_interval = ktime_set(0, 300L*1E6L);
207 data->trigger_delay = ktime_set(2, 500L*1E6L);
208
209 hrtimer_init(&data->timer_trigger, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
210 data->timer_trigger.function = &ltc2952_poweroff_timer_trigger;
211
212 hrtimer_init(&data->timer_wde, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
213 data->timer_wde.function = &ltc2952_poweroff_timer_wde;
214}
215
216static int ltc2952_poweroff_init(struct platform_device *pdev)
217{
218 int ret, virq;
219 unsigned int i;
220 struct ltc2952_poweroff_data *data;
221
222 static char *name[] = {
223 "trigger",
224 "watchdog",
225 "kill",
226 NULL
227 };
228
229 data = ltc2952_data;
230 ltc2952_poweroff_default(ltc2952_data);
231
232 for (i = 0; i < ARRAY_SIZE(ltc2952_data->gpio); i++) {
233 ltc2952_data->gpio[i] = gpiod_get(&pdev->dev, name[i]);
234
235 if (IS_ERR(ltc2952_data->gpio[i])) {
236 ret = PTR_ERR(ltc2952_data->gpio[i]);
237 dev_err(&pdev->dev,
238 "unable to claim the following gpio: %s\n",
239 name[i]);
240 goto err_io;
241 }
242 }
243
244 ret = gpiod_direction_output(
245 ltc2952_data->gpio[POWERPATH_IO_WATCHDOG], 0);
246 if (ret) {
247 dev_err(&pdev->dev, "unable to use watchdog-gpio as output\n");
248 goto err_io;
249 }
250
251 ret = gpiod_direction_output(ltc2952_data->gpio[POWERPATH_IO_KILL], 0);
252 if (ret) {
253 dev_err(&pdev->dev, "unable to use kill-gpio as output\n");
254 goto err_io;
255 }
256
257 virq = gpiod_to_irq(ltc2952_data->gpio[POWERPATH_IO_TRIGGER]);
258 if (virq < 0) {
259 dev_err(&pdev->dev, "cannot map GPIO as interrupt");
260 goto err_io;
261 }
262
263 ltc2952_data->virq = virq;
264 ret = request_irq(virq,
265 ltc2952_poweroff_handler,
266 (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING),
267 "ltc2952-poweroff",
268 ltc2952_data
269 );
270
271 if (ret) {
272 dev_err(&pdev->dev, "cannot configure an interrupt handler\n");
273 goto err_io;
274 }
275
276 return 0;
277
278err_io:
279 for (i = 0; i < ARRAY_SIZE(ltc2952_data->gpio); i++)
280 if (ltc2952_data->gpio[i])
281 gpiod_put(ltc2952_data->gpio[i]);
282
283 return ret;
284}
285
286static int ltc2952_poweroff_probe(struct platform_device *pdev)
287{
288 int ret;
289
290 if (pm_power_off) {
291 dev_err(&pdev->dev, "pm_power_off already registered");
292 return -EBUSY;
293 }
294
295 ltc2952_data = kzalloc(sizeof(*ltc2952_data), GFP_KERNEL);
296 if (!ltc2952_data)
297 return -ENOMEM;
298
299 ltc2952_data->dev = &pdev->dev;
300
301 ret = ltc2952_poweroff_init(pdev);
302 if (ret)
303 goto err;
304
305 pm_power_off = &ltc2952_poweroff_kill;
306
307 dev_info(&pdev->dev, "probe successful\n");
308
309 return 0;
310
311err:
312 kfree(ltc2952_data);
313 return ret;
314}
315
316static int ltc2952_poweroff_remove(struct platform_device *pdev)
317{
318 unsigned int i;
319
320 pm_power_off = NULL;
321
322 if (ltc2952_data) {
323 free_irq(ltc2952_data->virq, ltc2952_data);
324
325 for (i = 0; i < ARRAY_SIZE(ltc2952_data->gpio); i++)
326 gpiod_put(ltc2952_data->gpio[i]);
327
328 kfree(ltc2952_data);
329 }
330
331 return 0;
332}
333
334static const struct of_device_id of_ltc2952_poweroff_match[] = {
335 { .compatible = "lltc,ltc2952"},
336 {},
337};
338MODULE_DEVICE_TABLE(of, of_ltc2952_poweroff_match);
339
340static struct platform_driver ltc2952_poweroff_driver = {
341 .probe = ltc2952_poweroff_probe,
342 .remove = ltc2952_poweroff_remove,
343 .driver = {
344 .name = "ltc2952-poweroff",
345 .owner = THIS_MODULE,
346 .of_match_table = of_ltc2952_poweroff_match,
347 },
348 .suspend = ltc2952_poweroff_suspend,
349 .resume = ltc2952_poweroff_resume,
350};
351
352static int ltc2952_poweroff_notify_panic(struct notifier_block *nb,
353 unsigned long code, void *unused)
354{
355 ltc2952_poweroff_panic = 1;
356 return NOTIFY_DONE;
357}
358
359static struct notifier_block ltc2952_poweroff_panic_nb = {
360 .notifier_call = ltc2952_poweroff_notify_panic,
361};
362
363static int __init ltc2952_poweroff_platform_init(void)
364{
365 ltc2952_poweroff_panic = 0;
366
367 atomic_notifier_chain_register(&panic_notifier_list,
368 &ltc2952_poweroff_panic_nb);
369
370 return platform_driver_register(&ltc2952_poweroff_driver);
371}
372
373static void __exit ltc2952_poweroff_platform_exit(void)
374{
375 atomic_notifier_chain_unregister(&panic_notifier_list,
376 &ltc2952_poweroff_panic_nb);
377
378 platform_driver_unregister(&ltc2952_poweroff_driver);
379}
380
381module_init(ltc2952_poweroff_platform_init);
382module_exit(ltc2952_poweroff_platform_exit);
383
384MODULE_AUTHOR("René Moll <rene.moll@xsens.com>");
385MODULE_DESCRIPTION("LTC PowerPath power-off driver");
386MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c
index 774f9a3b310d..4702efdfe466 100644
--- a/drivers/power/reset/msm-poweroff.c
+++ b/drivers/power/reset/msm-poweroff.c
@@ -20,21 +20,27 @@
20#include <linux/platform_device.h> 20#include <linux/platform_device.h>
21#include <linux/module.h> 21#include <linux/module.h>
22#include <linux/reboot.h> 22#include <linux/reboot.h>
23 23#include <linux/pm.h>
24#include <asm/system_misc.h>
25 24
26static void __iomem *msm_ps_hold; 25static void __iomem *msm_ps_hold;
27 26static int do_msm_restart(struct notifier_block *nb, unsigned long action,
28static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd) 27 void *data)
29{ 28{
30 writel(0, msm_ps_hold); 29 writel(0, msm_ps_hold);
31 mdelay(10000); 30 mdelay(10000);
31
32 return NOTIFY_DONE;
32} 33}
33 34
35static struct notifier_block restart_nb = {
36 .notifier_call = do_msm_restart,
37 .priority = 128,
38};
39
34static void do_msm_poweroff(void) 40static void do_msm_poweroff(void)
35{ 41{
36 /* TODO: Add poweroff capability */ 42 /* TODO: Add poweroff capability */
37 do_msm_restart(REBOOT_HARD, NULL); 43 do_msm_restart(&restart_nb, 0, NULL);
38} 44}
39 45
40static int msm_restart_probe(struct platform_device *pdev) 46static int msm_restart_probe(struct platform_device *pdev)
@@ -47,8 +53,10 @@ static int msm_restart_probe(struct platform_device *pdev)
47 if (IS_ERR(msm_ps_hold)) 53 if (IS_ERR(msm_ps_hold))
48 return PTR_ERR(msm_ps_hold); 54 return PTR_ERR(msm_ps_hold);
49 55
56 register_restart_handler(&restart_nb);
57
50 pm_power_off = do_msm_poweroff; 58 pm_power_off = do_msm_poweroff;
51 arm_pm_restart = do_msm_restart; 59
52 return 0; 60 return 0;
53} 61}
54 62
diff --git a/drivers/power/reset/st-poweroff.c b/drivers/power/reset/st-poweroff.c
new file mode 100644
index 000000000000..a0acf25ee2a2
--- /dev/null
+++ b/drivers/power/reset/st-poweroff.c
@@ -0,0 +1,151 @@
1/*
2 * Copyright (C) 2014 STMicroelectronics
3 *
4 * Power off Restart driver, used in STMicroelectronics devices.
5 *
6 * Author: Christophe Kerello <christophe.kerello@st.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2, as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/module.h>
14#include <linux/of.h>
15#include <linux/of_platform.h>
16#include <linux/platform_device.h>
17#include <linux/mfd/syscon.h>
18#include <linux/regmap.h>
19
20#include <asm/system_misc.h>
21
22struct reset_syscfg {
23 struct regmap *regmap;
24 /* syscfg used for reset */
25 unsigned int offset_rst;
26 unsigned int mask_rst;
27 /* syscfg used for unmask the reset */
28 unsigned int offset_rst_msk;
29 unsigned int mask_rst_msk;
30};
31
32/* STiH415 */
33#define STIH415_SYSCFG_11 0x2c
34#define STIH415_SYSCFG_15 0x3c
35
36static struct reset_syscfg stih415_reset = {
37 .offset_rst = STIH415_SYSCFG_11,
38 .mask_rst = BIT(0),
39 .offset_rst_msk = STIH415_SYSCFG_15,
40 .mask_rst_msk = BIT(0)
41};
42
43/* STiH416 */
44#define STIH416_SYSCFG_500 0x7d0
45#define STIH416_SYSCFG_504 0x7e0
46
47static struct reset_syscfg stih416_reset = {
48 .offset_rst = STIH416_SYSCFG_500,
49 .mask_rst = BIT(0),
50 .offset_rst_msk = STIH416_SYSCFG_504,
51 .mask_rst_msk = BIT(0)
52};
53
54/* STiH407 */
55#define STIH407_SYSCFG_4000 0x0
56#define STIH407_SYSCFG_4008 0x20
57
58static struct reset_syscfg stih407_reset = {
59 .offset_rst = STIH407_SYSCFG_4000,
60 .mask_rst = BIT(0),
61 .offset_rst_msk = STIH407_SYSCFG_4008,
62 .mask_rst_msk = BIT(0)
63};
64
65/* STiD127 */
66#define STID127_SYSCFG_700 0x0
67#define STID127_SYSCFG_773 0x124
68
69static struct reset_syscfg stid127_reset = {
70 .offset_rst = STID127_SYSCFG_773,
71 .mask_rst = BIT(0),
72 .offset_rst_msk = STID127_SYSCFG_700,
73 .mask_rst_msk = BIT(8)
74};
75
76static struct reset_syscfg *st_restart_syscfg;
77
78static void st_restart(enum reboot_mode reboot_mode, const char *cmd)
79{
80 /* reset syscfg updated */
81 regmap_update_bits(st_restart_syscfg->regmap,
82 st_restart_syscfg->offset_rst,
83 st_restart_syscfg->mask_rst,
84 0);
85
86 /* unmask the reset */
87 regmap_update_bits(st_restart_syscfg->regmap,
88 st_restart_syscfg->offset_rst_msk,
89 st_restart_syscfg->mask_rst_msk,
90 0);
91}
92
93static struct of_device_id st_reset_of_match[] = {
94 {
95 .compatible = "st,stih415-restart",
96 .data = (void *)&stih415_reset,
97 }, {
98 .compatible = "st,stih416-restart",
99 .data = (void *)&stih416_reset,
100 }, {
101 .compatible = "st,stih407-restart",
102 .data = (void *)&stih407_reset,
103 }, {
104 .compatible = "st,stid127-restart",
105 .data = (void *)&stid127_reset,
106 },
107 {}
108};
109
110static int st_reset_probe(struct platform_device *pdev)
111{
112 struct device_node *np = pdev->dev.of_node;
113 const struct of_device_id *match;
114 struct device *dev = &pdev->dev;
115
116 match = of_match_device(st_reset_of_match, dev);
117 if (!match)
118 return -ENODEV;
119
120 st_restart_syscfg = (struct reset_syscfg *)match->data;
121
122 st_restart_syscfg->regmap =
123 syscon_regmap_lookup_by_phandle(np, "st,syscfg");
124 if (IS_ERR(st_restart_syscfg->regmap)) {
125 dev_err(dev, "No syscfg phandle specified\n");
126 return PTR_ERR(st_restart_syscfg->regmap);
127 }
128
129 arm_pm_restart = st_restart;
130
131 return 0;
132}
133
134static struct platform_driver st_reset_driver = {
135 .probe = st_reset_probe,
136 .driver = {
137 .name = "st_reset",
138 .of_match_table = st_reset_of_match,
139 },
140};
141
142static int __init st_reset_init(void)
143{
144 return platform_driver_register(&st_reset_driver);
145}
146
147device_initcall(st_reset_init);
148
149MODULE_AUTHOR("Christophe Kerello <christophe.kerello@st.com>");
150MODULE_DESCRIPTION("STMicroelectronics Power off Restart driver");
151MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/reset/syscon-reboot.c b/drivers/power/reset/syscon-reboot.c
new file mode 100644
index 000000000000..815b901822cf
--- /dev/null
+++ b/drivers/power/reset/syscon-reboot.c
@@ -0,0 +1,91 @@
1/*
2 * Generic Syscon Reboot Driver
3 *
4 * Copyright (c) 2013, Applied Micro Circuits Corporation
5 * Author: Feng Kan <fkan@apm.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17#include <linux/delay.h>
18#include <linux/io.h>
19#include <linux/notifier.h>
20#include <linux/mfd/syscon.h>
21#include <linux/of_address.h>
22#include <linux/of_device.h>
23#include <linux/platform_device.h>
24#include <linux/reboot.h>
25#include <linux/regmap.h>
26
27struct syscon_reboot_context {
28 struct regmap *map;
29 u32 offset;
30 u32 mask;
31 struct notifier_block restart_handler;
32};
33
34static int syscon_restart_handle(struct notifier_block *this,
35 unsigned long mode, void *cmd)
36{
37 struct syscon_reboot_context *ctx =
38 container_of(this, struct syscon_reboot_context,
39 restart_handler);
40
41 /* Issue the reboot */
42 regmap_write(ctx->map, ctx->offset, ctx->mask);
43
44 mdelay(1000);
45
46 pr_emerg("Unable to restart system\n");
47 return NOTIFY_DONE;
48}
49
50static int syscon_reboot_probe(struct platform_device *pdev)
51{
52 struct syscon_reboot_context *ctx;
53 struct device *dev = &pdev->dev;
54 int err;
55
56 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
57 if (!ctx)
58 return -ENOMEM;
59
60 ctx->map = syscon_regmap_lookup_by_phandle(dev->of_node, "regmap");
61 if (IS_ERR(ctx->map))
62 return PTR_ERR(ctx->map);
63
64 if (of_property_read_u32(pdev->dev.of_node, "offset", &ctx->offset))
65 return -EINVAL;
66
67 if (of_property_read_u32(pdev->dev.of_node, "mask", &ctx->mask))
68 return -EINVAL;
69
70 ctx->restart_handler.notifier_call = syscon_restart_handle;
71 ctx->restart_handler.priority = 128;
72 err = register_restart_handler(&ctx->restart_handler);
73 if (err)
74 dev_err(dev, "can't register restart notifier (err=%d)\n", err);
75
76 return err;
77}
78
79static struct of_device_id syscon_reboot_of_match[] = {
80 { .compatible = "syscon-reboot" },
81 {}
82};
83
84static struct platform_driver syscon_reboot_driver = {
85 .probe = syscon_reboot_probe,
86 .driver = {
87 .name = "syscon-reboot",
88 .of_match_table = syscon_reboot_of_match,
89 },
90};
91module_platform_driver(syscon_reboot_driver);
diff --git a/drivers/power/reset/xgene-reboot.c b/drivers/power/reset/xgene-reboot.c
index ecd55f81b9d1..6b49be6867ab 100644
--- a/drivers/power/reset/xgene-reboot.c
+++ b/drivers/power/reset/xgene-reboot.c
@@ -40,7 +40,7 @@ struct xgene_reboot_context {
40 40
41static struct xgene_reboot_context *xgene_restart_ctx; 41static struct xgene_reboot_context *xgene_restart_ctx;
42 42
43static void xgene_restart(char str, const char *cmd) 43static void xgene_restart(enum reboot_mode mode, const char *cmd)
44{ 44{
45 struct xgene_reboot_context *ctx = xgene_restart_ctx; 45 struct xgene_reboot_context *ctx = xgene_restart_ctx;
46 unsigned long timeout; 46 unsigned long timeout;