11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 267778e0eSLoc Ho /* 367778e0eSLoc Ho * AppliedMicro X-Gene SoC Reboot Driver 467778e0eSLoc Ho * 567778e0eSLoc Ho * Copyright (c) 2013, Applied Micro Circuits Corporation 667778e0eSLoc Ho * Author: Feng Kan <fkan@apm.com> 767778e0eSLoc Ho * Author: Loc Ho <lho@apm.com> 867778e0eSLoc Ho * 967778e0eSLoc Ho * This driver provides system reboot functionality for APM X-Gene SoC. 1067778e0eSLoc Ho * For system shutdown, this is board specify. If a board designer 1167778e0eSLoc Ho * implements GPIO shutdown, use the gpio-poweroff.c driver. 1267778e0eSLoc Ho */ 13745e1976SGuenter Roeck #include <linux/delay.h> 1467778e0eSLoc Ho #include <linux/io.h> 158f57f231SGuenter Roeck #include <linux/notifier.h> 1667778e0eSLoc Ho #include <linux/of_device.h> 1767778e0eSLoc Ho #include <linux/of_address.h> 1867778e0eSLoc Ho #include <linux/platform_device.h> 198f57f231SGuenter Roeck #include <linux/reboot.h> 2067778e0eSLoc Ho #include <linux/stat.h> 2167778e0eSLoc Ho #include <linux/slab.h> 2267778e0eSLoc Ho 2367778e0eSLoc Ho struct xgene_reboot_context { 2443160718SGuenter Roeck struct device *dev; 2567778e0eSLoc Ho void *csr; 2667778e0eSLoc Ho u32 mask; 278f57f231SGuenter Roeck struct notifier_block restart_handler; 2867778e0eSLoc Ho }; 2967778e0eSLoc Ho 308f57f231SGuenter Roeck static int xgene_restart_handler(struct notifier_block *this, 318f57f231SGuenter Roeck unsigned long mode, void *cmd) 3267778e0eSLoc Ho { 338f57f231SGuenter Roeck struct xgene_reboot_context *ctx = 348f57f231SGuenter Roeck container_of(this, struct xgene_reboot_context, 358f57f231SGuenter Roeck restart_handler); 3667778e0eSLoc Ho 3767778e0eSLoc Ho /* Issue the reboot */ 3867778e0eSLoc Ho writel(ctx->mask, ctx->csr); 3967778e0eSLoc Ho 40745e1976SGuenter Roeck mdelay(1000); 4167778e0eSLoc Ho 4243160718SGuenter Roeck dev_emerg(ctx->dev, "Unable to restart system\n"); 438f57f231SGuenter Roeck 448f57f231SGuenter Roeck return NOTIFY_DONE; 4567778e0eSLoc Ho } 4667778e0eSLoc Ho 4767778e0eSLoc Ho static int xgene_reboot_probe(struct platform_device *pdev) 4867778e0eSLoc Ho { 4967778e0eSLoc Ho struct xgene_reboot_context *ctx; 5043160718SGuenter Roeck struct device *dev = &pdev->dev; 518f57f231SGuenter Roeck int err; 5267778e0eSLoc Ho 5343160718SGuenter Roeck ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 54ef288f9fSGuenter Roeck if (!ctx) 55ef288f9fSGuenter Roeck return -ENOMEM; 5667778e0eSLoc Ho 5743160718SGuenter Roeck ctx->csr = of_iomap(dev->of_node, 0); 5867778e0eSLoc Ho if (!ctx->csr) { 5943160718SGuenter Roeck dev_err(dev, "can not map resource\n"); 6067778e0eSLoc Ho return -ENODEV; 6167778e0eSLoc Ho } 6267778e0eSLoc Ho 6343160718SGuenter Roeck if (of_property_read_u32(dev->of_node, "mask", &ctx->mask)) 6467778e0eSLoc Ho ctx->mask = 0xFFFFFFFF; 6567778e0eSLoc Ho 6643160718SGuenter Roeck ctx->dev = dev; 678f57f231SGuenter Roeck ctx->restart_handler.notifier_call = xgene_restart_handler; 688f57f231SGuenter Roeck ctx->restart_handler.priority = 128; 698f57f231SGuenter Roeck err = register_restart_handler(&ctx->restart_handler); 70896af83eSArvind Yadav if (err) { 71896af83eSArvind Yadav iounmap(ctx->csr); 728f57f231SGuenter Roeck dev_err(dev, "cannot register restart handler (err=%d)\n", err); 73896af83eSArvind Yadav } 7467778e0eSLoc Ho 758f57f231SGuenter Roeck return err; 7667778e0eSLoc Ho } 7767778e0eSLoc Ho 788fb08855SFabian Frederick static const struct of_device_id xgene_reboot_of_match[] = { 7967778e0eSLoc Ho { .compatible = "apm,xgene-reboot" }, 8067778e0eSLoc Ho {} 8167778e0eSLoc Ho }; 8267778e0eSLoc Ho 8367778e0eSLoc Ho static struct platform_driver xgene_reboot_driver = { 8467778e0eSLoc Ho .probe = xgene_reboot_probe, 8567778e0eSLoc Ho .driver = { 8667778e0eSLoc Ho .name = "xgene-reboot", 8767778e0eSLoc Ho .of_match_table = xgene_reboot_of_match, 8867778e0eSLoc Ho }, 8967778e0eSLoc Ho }; 9067778e0eSLoc Ho 9167778e0eSLoc Ho static int __init xgene_reboot_init(void) 9267778e0eSLoc Ho { 9367778e0eSLoc Ho return platform_driver_register(&xgene_reboot_driver); 9467778e0eSLoc Ho } 9567778e0eSLoc Ho device_initcall(xgene_reboot_init); 96