blob: 73c3d93e5318b9ab2c7d6287c01e4a8b83d8de5e [file] [log] [blame]
Loc Ho67778e0e2013-07-02 14:38:58 -06001/*
2 * AppliedMicro X-Gene SoC Reboot Driver
3 *
4 * Copyright (c) 2013, Applied Micro Circuits Corporation
5 * Author: Feng Kan <fkan@apm.com>
6 * Author: Loc Ho <lho@apm.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 *
23 * This driver provides system reboot functionality for APM X-Gene SoC.
24 * For system shutdown, this is board specify. If a board designer
25 * implements GPIO shutdown, use the gpio-poweroff.c driver.
26 */
Guenter Roeck745e1972014-09-30 10:48:31 -070027#include <linux/delay.h>
Loc Ho67778e0e2013-07-02 14:38:58 -060028#include <linux/io.h>
Guenter Roeck8f57f232014-09-30 10:48:32 -070029#include <linux/notifier.h>
Loc Ho67778e0e2013-07-02 14:38:58 -060030#include <linux/of_device.h>
31#include <linux/of_address.h>
32#include <linux/platform_device.h>
Guenter Roeck8f57f232014-09-30 10:48:32 -070033#include <linux/reboot.h>
Loc Ho67778e0e2013-07-02 14:38:58 -060034#include <linux/stat.h>
35#include <linux/slab.h>
Loc Ho67778e0e2013-07-02 14:38:58 -060036
37struct xgene_reboot_context {
Guenter Roeck43160712014-09-30 10:48:30 -070038 struct device *dev;
Loc Ho67778e0e2013-07-02 14:38:58 -060039 void *csr;
40 u32 mask;
Guenter Roeck8f57f232014-09-30 10:48:32 -070041 struct notifier_block restart_handler;
Loc Ho67778e0e2013-07-02 14:38:58 -060042};
43
Guenter Roeck8f57f232014-09-30 10:48:32 -070044static int xgene_restart_handler(struct notifier_block *this,
45 unsigned long mode, void *cmd)
Loc Ho67778e0e2013-07-02 14:38:58 -060046{
Guenter Roeck8f57f232014-09-30 10:48:32 -070047 struct xgene_reboot_context *ctx =
48 container_of(this, struct xgene_reboot_context,
49 restart_handler);
Loc Ho67778e0e2013-07-02 14:38:58 -060050
51 /* Issue the reboot */
Guenter Roeck8f57f232014-09-30 10:48:32 -070052 writel(ctx->mask, ctx->csr);
Loc Ho67778e0e2013-07-02 14:38:58 -060053
Guenter Roeck745e1972014-09-30 10:48:31 -070054 mdelay(1000);
Loc Ho67778e0e2013-07-02 14:38:58 -060055
Guenter Roeck43160712014-09-30 10:48:30 -070056 dev_emerg(ctx->dev, "Unable to restart system\n");
Guenter Roeck8f57f232014-09-30 10:48:32 -070057
58 return NOTIFY_DONE;
Loc Ho67778e0e2013-07-02 14:38:58 -060059}
60
61static int xgene_reboot_probe(struct platform_device *pdev)
62{
63 struct xgene_reboot_context *ctx;
Guenter Roeck43160712014-09-30 10:48:30 -070064 struct device *dev = &pdev->dev;
Guenter Roeck8f57f232014-09-30 10:48:32 -070065 int err;
Loc Ho67778e0e2013-07-02 14:38:58 -060066
Guenter Roeck43160712014-09-30 10:48:30 -070067 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
Guenter Roeckef288f92014-09-30 10:48:28 -070068 if (!ctx)
69 return -ENOMEM;
Loc Ho67778e0e2013-07-02 14:38:58 -060070
Guenter Roeck43160712014-09-30 10:48:30 -070071 ctx->csr = of_iomap(dev->of_node, 0);
Loc Ho67778e0e2013-07-02 14:38:58 -060072 if (!ctx->csr) {
Guenter Roeck43160712014-09-30 10:48:30 -070073 dev_err(dev, "can not map resource\n");
Loc Ho67778e0e2013-07-02 14:38:58 -060074 return -ENODEV;
75 }
76
Guenter Roeck43160712014-09-30 10:48:30 -070077 if (of_property_read_u32(dev->of_node, "mask", &ctx->mask))
Loc Ho67778e0e2013-07-02 14:38:58 -060078 ctx->mask = 0xFFFFFFFF;
79
Guenter Roeck43160712014-09-30 10:48:30 -070080 ctx->dev = dev;
Guenter Roeck8f57f232014-09-30 10:48:32 -070081 ctx->restart_handler.notifier_call = xgene_restart_handler;
82 ctx->restart_handler.priority = 128;
83 err = register_restart_handler(&ctx->restart_handler);
Arvind Yadav896af832016-09-14 16:25:39 +053084 if (err) {
85 iounmap(ctx->csr);
Guenter Roeck8f57f232014-09-30 10:48:32 -070086 dev_err(dev, "cannot register restart handler (err=%d)\n", err);
Arvind Yadav896af832016-09-14 16:25:39 +053087 }
Loc Ho67778e0e2013-07-02 14:38:58 -060088
Guenter Roeck8f57f232014-09-30 10:48:32 -070089 return err;
Loc Ho67778e0e2013-07-02 14:38:58 -060090}
91
Fabian Frederick8fb08852015-03-16 20:17:12 +010092static const struct of_device_id xgene_reboot_of_match[] = {
Loc Ho67778e0e2013-07-02 14:38:58 -060093 { .compatible = "apm,xgene-reboot" },
94 {}
95};
96
97static struct platform_driver xgene_reboot_driver = {
98 .probe = xgene_reboot_probe,
99 .driver = {
100 .name = "xgene-reboot",
101 .of_match_table = xgene_reboot_of_match,
102 },
103};
104
105static int __init xgene_reboot_init(void)
106{
107 return platform_driver_register(&xgene_reboot_driver);
108}
109device_initcall(xgene_reboot_init);