Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2014 STMicroelectronics
0004  *
0005  * Power off Restart driver, used in STMicroelectronics devices.
0006  *
0007  * Author: Christophe Kerello <christophe.kerello@st.com>
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     /* syscfg used for reset */
0021     unsigned int offset_rst;
0022     unsigned int mask_rst;
0023     /* syscfg used for unmask the reset */
0024     unsigned int offset_rst_msk;
0025     unsigned int mask_rst_msk;
0026 };
0027 
0028 /* STiH407 */
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     /* reset syscfg updated */
0046     regmap_update_bits(st_restart_syscfg->regmap,
0047                st_restart_syscfg->offset_rst,
0048                st_restart_syscfg->mask_rst,
0049                0);
0050 
0051     /* unmask the reset */
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");