1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * 4 * Copyright (C) 2012 ARM Limited 5 */ 6 7 #include <linux/delay.h> 8 #include <linux/notifier.h> 9 #include <linux/of.h> 10 #include <linux/platform_device.h> 11 #include <linux/property.h> 12 #include <linux/reboot.h> 13 #include <linux/stat.h> 14 #include <linux/vexpress.h> 15 16 static void vexpress_reset_do(struct device *dev, const char *what) 17 { 18 int err = -ENOENT; 19 struct regmap *reg = dev_get_drvdata(dev); 20 21 if (reg) { 22 err = regmap_write(reg, 0, 0); 23 if (!err) 24 mdelay(1000); 25 } 26 27 dev_emerg(dev, "Unable to %s (%d)\n", what, err); 28 } 29 30 static struct device *vexpress_power_off_device; 31 static atomic_t vexpress_restart_nb_refcnt = ATOMIC_INIT(0); 32 33 static void vexpress_power_off(void) 34 { 35 vexpress_reset_do(vexpress_power_off_device, "power off"); 36 } 37 38 static struct device *vexpress_restart_device; 39 40 static int vexpress_restart(struct notifier_block *this, unsigned long mode, 41 void *cmd) 42 { 43 vexpress_reset_do(vexpress_restart_device, "restart"); 44 45 return NOTIFY_DONE; 46 } 47 48 static struct notifier_block vexpress_restart_nb = { 49 .notifier_call = vexpress_restart, 50 .priority = 128, 51 }; 52 53 static ssize_t vexpress_reset_active_show(struct device *dev, 54 struct device_attribute *attr, char *buf) 55 { 56 return sprintf(buf, "%d\n", vexpress_restart_device == dev); 57 } 58 59 static ssize_t vexpress_reset_active_store(struct device *dev, 60 struct device_attribute *attr, const char *buf, size_t count) 61 { 62 long value; 63 int err = kstrtol(buf, 0, &value); 64 65 if (!err && value) 66 vexpress_restart_device = dev; 67 68 return err ? err : count; 69 } 70 71 static DEVICE_ATTR(active, S_IRUGO | S_IWUSR, vexpress_reset_active_show, 72 vexpress_reset_active_store); 73 74 75 enum vexpress_reset_func { FUNC_RESET, FUNC_SHUTDOWN, FUNC_REBOOT }; 76 77 static const struct of_device_id vexpress_reset_of_match[] = { 78 { 79 .compatible = "arm,vexpress-reset", 80 .data = (void *)FUNC_RESET, 81 }, { 82 .compatible = "arm,vexpress-shutdown", 83 .data = (void *)FUNC_SHUTDOWN 84 }, { 85 .compatible = "arm,vexpress-reboot", 86 .data = (void *)FUNC_REBOOT 87 }, 88 {} 89 }; 90 91 static int _vexpress_register_restart_handler(struct device *dev) 92 { 93 int err; 94 95 vexpress_restart_device = dev; 96 if (atomic_inc_return(&vexpress_restart_nb_refcnt) == 1) { 97 err = register_restart_handler(&vexpress_restart_nb); 98 if (err) { 99 dev_err(dev, "cannot register restart handler (err=%d)\n", err); 100 atomic_dec(&vexpress_restart_nb_refcnt); 101 return err; 102 } 103 } 104 device_create_file(dev, &dev_attr_active); 105 106 return 0; 107 } 108 109 static int vexpress_reset_probe(struct platform_device *pdev) 110 { 111 enum vexpress_reset_func func; 112 struct regmap *regmap; 113 int ret = 0; 114 115 regmap = devm_regmap_init_vexpress_config(&pdev->dev); 116 if (IS_ERR(regmap)) 117 return PTR_ERR(regmap); 118 dev_set_drvdata(&pdev->dev, regmap); 119 120 func = (uintptr_t)device_get_match_data(&pdev->dev); 121 switch (func) { 122 case FUNC_SHUTDOWN: 123 vexpress_power_off_device = &pdev->dev; 124 pm_power_off = vexpress_power_off; 125 break; 126 case FUNC_RESET: 127 if (!vexpress_restart_device) 128 ret = _vexpress_register_restart_handler(&pdev->dev); 129 break; 130 case FUNC_REBOOT: 131 ret = _vexpress_register_restart_handler(&pdev->dev); 132 break; 133 } 134 135 return ret; 136 } 137 138 static struct platform_driver vexpress_reset_driver = { 139 .probe = vexpress_reset_probe, 140 .driver = { 141 .name = "vexpress-reset", 142 .of_match_table = vexpress_reset_of_match, 143 .suppress_bind_attrs = true, 144 }, 145 }; 146 builtin_platform_driver(vexpress_reset_driver); 147