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

power: reset: Add generic SYSCON register mapped poweroff.

Add a generic SYSCON register mapped poweroff mechanism.

Signed-off-by: Moritz Fischer <moritz.fischer@ettus.com>
Signed-off-by: Sebastian Reichel <sre@kernel.org>

authored by

Moritz Fischer and committed by
Sebastian Reichel
8a577608 bbaeeaaf

+110
+7
drivers/power/reset/Kconfig
··· 151 151 help 152 152 Reboot support for generic SYSCON mapped register reset. 153 153 154 + config POWER_RESET_SYSCON_POWEROFF 155 + bool "Generic SYSCON regmap poweroff driver" 156 + depends on OF 157 + select MFD_SYSCON 158 + help 159 + Poweroff support for generic SYSCON mapped register poweroff. 160 + 154 161 config POWER_RESET_RMOBILE 155 162 tristate "Renesas R-Mobile reset driver" 156 163 depends on ARCH_RMOBILE || COMPILE_TEST
+1
drivers/power/reset/Makefile
··· 17 17 obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o 18 18 obj-$(CONFIG_POWER_RESET_KEYSTONE) += keystone-reset.o 19 19 obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o 20 + obj-$(CONFIG_POWER_RESET_SYSCON_POWEROFF) += syscon-poweroff.o 20 21 obj-$(CONFIG_POWER_RESET_RMOBILE) += rmobile-reset.o
+102
drivers/power/reset/syscon-poweroff.c
··· 1 + /* 2 + * Generic Syscon Poweroff Driver 3 + * 4 + * Copyright (c) 2015, National Instruments Corp. 5 + * Author: Moritz Fischer <moritz.fischer@ettus.com> 6 + * 7 + * This program is free software; you can redistribute it and/or 8 + * modify it under the terms of the GNU General Public License as 9 + * published by the Free Software Foundation; either version 2 of 10 + * the License, or (at your option) any later version. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + */ 17 + 18 + #include <linux/kallsyms.h> 19 + #include <linux/delay.h> 20 + #include <linux/io.h> 21 + #include <linux/notifier.h> 22 + #include <linux/mfd/syscon.h> 23 + #include <linux/of_address.h> 24 + #include <linux/of_device.h> 25 + #include <linux/platform_device.h> 26 + #include <linux/pm.h> 27 + #include <linux/regmap.h> 28 + 29 + static struct regmap *map; 30 + static u32 offset; 31 + static u32 mask; 32 + 33 + void syscon_poweroff(void) 34 + { 35 + /* Issue the poweroff */ 36 + regmap_write(map, offset, mask); 37 + 38 + mdelay(1000); 39 + 40 + pr_emerg("Unable to poweroff system\n"); 41 + } 42 + 43 + static int syscon_poweroff_probe(struct platform_device *pdev) 44 + { 45 + char symname[KSYM_NAME_LEN]; 46 + 47 + map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "regmap"); 48 + if (IS_ERR(map)) { 49 + dev_err(&pdev->dev, "unable to get syscon"); 50 + return PTR_ERR(map); 51 + } 52 + 53 + if (of_property_read_u32(pdev->dev.of_node, "offset", &offset)) { 54 + dev_err(&pdev->dev, "unable to read 'offset'"); 55 + return -EINVAL; 56 + } 57 + 58 + if (of_property_read_u32(pdev->dev.of_node, "mask", &mask)) { 59 + dev_err(&pdev->dev, "unable to read 'mask'"); 60 + return -EINVAL; 61 + } 62 + 63 + if (pm_power_off) { 64 + lookup_symbol_name((ulong)pm_power_off, symname); 65 + dev_err(&pdev->dev, 66 + "pm_power_off already claimed %p %s", 67 + pm_power_off, symname); 68 + return -EBUSY; 69 + } 70 + 71 + pm_power_off = syscon_poweroff; 72 + 73 + return 0; 74 + } 75 + 76 + static int syscon_poweroff_remove(struct platform_device *pdev) 77 + { 78 + if (pm_power_off == syscon_poweroff) 79 + pm_power_off = NULL; 80 + 81 + return 0; 82 + } 83 + 84 + static const struct of_device_id syscon_poweroff_of_match[] = { 85 + { .compatible = "syscon-poweroff" }, 86 + {} 87 + }; 88 + 89 + static struct platform_driver syscon_poweroff_driver = { 90 + .probe = syscon_poweroff_probe, 91 + .remove = syscon_poweroff_remove, 92 + .driver = { 93 + .name = "syscon-poweroff", 94 + .of_match_table = syscon_poweroff_of_match, 95 + }, 96 + }; 97 + 98 + static int __init syscon_poweroff_register(void) 99 + { 100 + return platform_driver_register(&syscon_poweroff_driver); 101 + } 102 + device_initcall(syscon_poweroff_register);