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

mfd: rn5t618: Register restart handler

Use the PMIC's repower capability for reboots. Register a restart
handler and use a slightly elevated priority of 192 since the PMIC
has suprior reset capability (causing a system wide reset).

Signed-off-by: Stefan Agner <stefan@agner.ch>
Reviewed-by: Marcel Ziswiler <marcel.ziswiler@toradex.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>

authored by

Stefan Agner and committed by
Lee Jones
a370f60a fd65ae4c

+37 -6
+37 -6
drivers/mfd/rn5t618.c
··· 12 12 * along with this program. If not, see <http://www.gnu.org/licenses/>. 13 13 */ 14 14 15 + #include <linux/delay.h> 15 16 #include <linux/i2c.h> 16 17 #include <linux/mfd/core.h> 17 18 #include <linux/mfd/rn5t618.h> 18 19 #include <linux/module.h> 19 20 #include <linux/of_device.h> 21 + #include <linux/reboot.h> 20 22 #include <linux/regmap.h> 21 23 22 24 static const struct mfd_cell rn5t618_cells[] = { ··· 52 50 }; 53 51 54 52 static struct rn5t618 *rn5t618_pm_power_off; 53 + static struct notifier_block rn5t618_restart_handler; 55 54 56 - static void rn5t618_power_off(void) 55 + static void rn5t618_trigger_poweroff_sequence(bool repower) 57 56 { 58 57 /* disable automatic repower-on */ 59 58 regmap_update_bits(rn5t618_pm_power_off->regmap, RN5T618_REPCNT, 60 - RN5T618_REPCNT_REPWRON, 0); 59 + RN5T618_REPCNT_REPWRON, 60 + repower ? RN5T618_REPCNT_REPWRON : 0); 61 61 /* start power-off sequence */ 62 62 regmap_update_bits(rn5t618_pm_power_off->regmap, RN5T618_SLPCNT, 63 63 RN5T618_SLPCNT_SWPWROFF, RN5T618_SLPCNT_SWPWROFF); 64 + } 65 + 66 + static void rn5t618_power_off(void) 67 + { 68 + rn5t618_trigger_poweroff_sequence(false); 69 + } 70 + 71 + static int rn5t618_restart(struct notifier_block *this, 72 + unsigned long mode, void *cmd) 73 + { 74 + rn5t618_trigger_poweroff_sequence(true); 75 + 76 + /* 77 + * Re-power factor detection on PMIC side is not instant. 1ms 78 + * proved to be enough time until reset takes effect. 79 + */ 80 + mdelay(1); 81 + 82 + return NOTIFY_DONE; 64 83 } 65 84 66 85 static const struct of_device_id rn5t618_of_match[] = { ··· 125 102 return ret; 126 103 } 127 104 105 + rn5t618_pm_power_off = priv; 128 106 if (of_device_is_system_power_controller(i2c->dev.of_node)) { 129 - if (!pm_power_off) { 130 - rn5t618_pm_power_off = priv; 107 + if (!pm_power_off) 131 108 pm_power_off = rn5t618_power_off; 132 - } else { 109 + else 133 110 dev_warn(&i2c->dev, "Poweroff callback already assigned\n"); 134 - } 111 + } 112 + 113 + rn5t618_restart_handler.notifier_call = rn5t618_restart; 114 + rn5t618_restart_handler.priority = 192; 115 + 116 + ret = register_restart_handler(&rn5t618_restart_handler); 117 + if (ret) { 118 + dev_err(&i2c->dev, "cannot register restart handler, %d\n", ret); 119 + return ret; 135 120 } 136 121 137 122 return 0;