0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/delay.h>
0009 #include <linux/io.h>
0010 #include <linux/notifier.h>
0011 #include <linux/mfd/syscon.h>
0012 #include <linux/of_address.h>
0013 #include <linux/of_device.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/reboot.h>
0016 #include <linux/regmap.h>
0017
0018 struct syscon_reboot_context {
0019 struct regmap *map;
0020 u32 offset;
0021 u32 value;
0022 u32 mask;
0023 struct notifier_block restart_handler;
0024 };
0025
0026 static int syscon_restart_handle(struct notifier_block *this,
0027 unsigned long mode, void *cmd)
0028 {
0029 struct syscon_reboot_context *ctx =
0030 container_of(this, struct syscon_reboot_context,
0031 restart_handler);
0032
0033
0034 regmap_update_bits(ctx->map, ctx->offset, ctx->mask, ctx->value);
0035
0036 mdelay(1000);
0037
0038 pr_emerg("Unable to restart system\n");
0039 return NOTIFY_DONE;
0040 }
0041
0042 static int syscon_reboot_probe(struct platform_device *pdev)
0043 {
0044 struct syscon_reboot_context *ctx;
0045 struct device *dev = &pdev->dev;
0046 int mask_err, value_err;
0047 int err;
0048
0049 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
0050 if (!ctx)
0051 return -ENOMEM;
0052
0053 ctx->map = syscon_regmap_lookup_by_phandle(dev->of_node, "regmap");
0054 if (IS_ERR(ctx->map)) {
0055 ctx->map = syscon_node_to_regmap(dev->parent->of_node);
0056 if (IS_ERR(ctx->map))
0057 return PTR_ERR(ctx->map);
0058 }
0059
0060 if (of_property_read_u32(pdev->dev.of_node, "offset", &ctx->offset))
0061 return -EINVAL;
0062
0063 value_err = of_property_read_u32(pdev->dev.of_node, "value", &ctx->value);
0064 mask_err = of_property_read_u32(pdev->dev.of_node, "mask", &ctx->mask);
0065 if (value_err && mask_err) {
0066 dev_err(dev, "unable to read 'value' and 'mask'");
0067 return -EINVAL;
0068 }
0069
0070 if (value_err) {
0071
0072 ctx->value = ctx->mask;
0073 ctx->mask = 0xFFFFFFFF;
0074 } else if (mask_err) {
0075
0076 ctx->mask = 0xFFFFFFFF;
0077 }
0078
0079 ctx->restart_handler.notifier_call = syscon_restart_handle;
0080 ctx->restart_handler.priority = 192;
0081 err = register_restart_handler(&ctx->restart_handler);
0082 if (err)
0083 dev_err(dev, "can't register restart notifier (err=%d)\n", err);
0084
0085 return err;
0086 }
0087
0088 static const struct of_device_id syscon_reboot_of_match[] = {
0089 { .compatible = "syscon-reboot" },
0090 {}
0091 };
0092
0093 static struct platform_driver syscon_reboot_driver = {
0094 .probe = syscon_reboot_probe,
0095 .driver = {
0096 .name = "syscon-reboot",
0097 .of_match_table = syscon_reboot_of_match,
0098 },
0099 };
0100 builtin_platform_driver(syscon_reboot_driver);