0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/module.h>
0011 #include <linux/of.h>
0012 #include <linux/of_platform.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/mfd/syscon.h>
0015 #include <linux/reboot.h>
0016 #include <linux/regmap.h>
0017
0018 struct reset_syscfg {
0019 struct regmap *regmap;
0020
0021 unsigned int offset_rst;
0022 unsigned int mask_rst;
0023
0024 unsigned int offset_rst_msk;
0025 unsigned int mask_rst_msk;
0026 };
0027
0028
0029 #define STIH407_SYSCFG_4000 0x0
0030 #define STIH407_SYSCFG_4008 0x20
0031
0032 static struct reset_syscfg stih407_reset = {
0033 .offset_rst = STIH407_SYSCFG_4000,
0034 .mask_rst = BIT(0),
0035 .offset_rst_msk = STIH407_SYSCFG_4008,
0036 .mask_rst_msk = BIT(0)
0037 };
0038
0039
0040 static struct reset_syscfg *st_restart_syscfg;
0041
0042 static int st_restart(struct notifier_block *this, unsigned long mode,
0043 void *cmd)
0044 {
0045
0046 regmap_update_bits(st_restart_syscfg->regmap,
0047 st_restart_syscfg->offset_rst,
0048 st_restart_syscfg->mask_rst,
0049 0);
0050
0051
0052 regmap_update_bits(st_restart_syscfg->regmap,
0053 st_restart_syscfg->offset_rst_msk,
0054 st_restart_syscfg->mask_rst_msk,
0055 0);
0056
0057 return NOTIFY_DONE;
0058 }
0059
0060 static struct notifier_block st_restart_nb = {
0061 .notifier_call = st_restart,
0062 .priority = 192,
0063 };
0064
0065 static const struct of_device_id st_reset_of_match[] = {
0066 {
0067 .compatible = "st,stih407-restart",
0068 .data = (void *)&stih407_reset,
0069 },
0070 {}
0071 };
0072
0073 static int st_reset_probe(struct platform_device *pdev)
0074 {
0075 struct device_node *np = pdev->dev.of_node;
0076 const struct of_device_id *match;
0077 struct device *dev = &pdev->dev;
0078
0079 match = of_match_device(st_reset_of_match, dev);
0080 if (!match)
0081 return -ENODEV;
0082
0083 st_restart_syscfg = (struct reset_syscfg *)match->data;
0084
0085 st_restart_syscfg->regmap =
0086 syscon_regmap_lookup_by_phandle(np, "st,syscfg");
0087 if (IS_ERR(st_restart_syscfg->regmap)) {
0088 dev_err(dev, "No syscfg phandle specified\n");
0089 return PTR_ERR(st_restart_syscfg->regmap);
0090 }
0091
0092 return register_restart_handler(&st_restart_nb);
0093 }
0094
0095 static struct platform_driver st_reset_driver = {
0096 .probe = st_reset_probe,
0097 .driver = {
0098 .name = "st_reset",
0099 .of_match_table = st_reset_of_match,
0100 },
0101 };
0102
0103 static int __init st_reset_init(void)
0104 {
0105 return platform_driver_register(&st_reset_driver);
0106 }
0107
0108 device_initcall(st_reset_init);
0109
0110 MODULE_AUTHOR("Christophe Kerello <christophe.kerello@st.com>");
0111 MODULE_DESCRIPTION("STMicroelectronics Power off Restart driver");
0112 MODULE_LICENSE("GPL v2");