linux/drivers/power/reset/st-poweroff.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2014 STMicroelectronics
   4 *
   5 * Power off Restart driver, used in STMicroelectronics devices.
   6 *
   7 * Author: Christophe Kerello <christophe.kerello@st.com>
   8 */
   9
  10#include <linux/module.h>
  11#include <linux/of.h>
  12#include <linux/of_platform.h>
  13#include <linux/platform_device.h>
  14#include <linux/mfd/syscon.h>
  15#include <linux/reboot.h>
  16#include <linux/regmap.h>
  17
  18struct reset_syscfg {
  19        struct regmap *regmap;
  20        /* syscfg used for reset */
  21        unsigned int offset_rst;
  22        unsigned int mask_rst;
  23        /* syscfg used for unmask the reset */
  24        unsigned int offset_rst_msk;
  25        unsigned int mask_rst_msk;
  26};
  27
  28/* STiH407 */
  29#define STIH407_SYSCFG_4000     0x0
  30#define STIH407_SYSCFG_4008     0x20
  31
  32static struct reset_syscfg stih407_reset = {
  33        .offset_rst = STIH407_SYSCFG_4000,
  34        .mask_rst = BIT(0),
  35        .offset_rst_msk = STIH407_SYSCFG_4008,
  36        .mask_rst_msk = BIT(0)
  37};
  38
  39
  40static struct reset_syscfg *st_restart_syscfg;
  41
  42static int st_restart(struct notifier_block *this, unsigned long mode,
  43                      void *cmd)
  44{
  45        /* reset syscfg updated */
  46        regmap_update_bits(st_restart_syscfg->regmap,
  47                           st_restart_syscfg->offset_rst,
  48                           st_restart_syscfg->mask_rst,
  49                           0);
  50
  51        /* unmask the reset */
  52        regmap_update_bits(st_restart_syscfg->regmap,
  53                           st_restart_syscfg->offset_rst_msk,
  54                           st_restart_syscfg->mask_rst_msk,
  55                           0);
  56
  57        return NOTIFY_DONE;
  58}
  59
  60static struct notifier_block st_restart_nb = {
  61        .notifier_call = st_restart,
  62        .priority = 192,
  63};
  64
  65static const struct of_device_id st_reset_of_match[] = {
  66        {
  67                .compatible = "st,stih407-restart",
  68                .data = (void *)&stih407_reset,
  69        },
  70        {}
  71};
  72
  73static int st_reset_probe(struct platform_device *pdev)
  74{
  75        struct device_node *np = pdev->dev.of_node;
  76        const struct of_device_id *match;
  77        struct device *dev = &pdev->dev;
  78
  79        match = of_match_device(st_reset_of_match, dev);
  80        if (!match)
  81                return -ENODEV;
  82
  83        st_restart_syscfg = (struct reset_syscfg *)match->data;
  84
  85        st_restart_syscfg->regmap =
  86                syscon_regmap_lookup_by_phandle(np, "st,syscfg");
  87        if (IS_ERR(st_restart_syscfg->regmap)) {
  88                dev_err(dev, "No syscfg phandle specified\n");
  89                return PTR_ERR(st_restart_syscfg->regmap);
  90        }
  91
  92        return register_restart_handler(&st_restart_nb);
  93}
  94
  95static struct platform_driver st_reset_driver = {
  96        .probe = st_reset_probe,
  97        .driver = {
  98                .name = "st_reset",
  99                .of_match_table = st_reset_of_match,
 100        },
 101};
 102
 103static int __init st_reset_init(void)
 104{
 105        return platform_driver_register(&st_reset_driver);
 106}
 107
 108device_initcall(st_reset_init);
 109
 110MODULE_AUTHOR("Christophe Kerello <christophe.kerello@st.com>");
 111MODULE_DESCRIPTION("STMicroelectronics Power off Restart driver");
 112MODULE_LICENSE("GPL v2");
 113