linux/drivers/reset/reset-ath79.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * AR71xx Reset Controller Driver
   4 * Author: Alban Bedel
   5 *
   6 * Copyright (C) 2015 Alban Bedel <albeu@free.fr>
   7 */
   8
   9#include <linux/io.h>
  10#include <linux/init.h>
  11#include <linux/mod_devicetable.h>
  12#include <linux/platform_device.h>
  13#include <linux/reset-controller.h>
  14#include <linux/reboot.h>
  15
  16struct ath79_reset {
  17        struct reset_controller_dev rcdev;
  18        struct notifier_block restart_nb;
  19        void __iomem *base;
  20        spinlock_t lock;
  21};
  22
  23#define FULL_CHIP_RESET 24
  24
  25static int ath79_reset_update(struct reset_controller_dev *rcdev,
  26                        unsigned long id, bool assert)
  27{
  28        struct ath79_reset *ath79_reset =
  29                container_of(rcdev, struct ath79_reset, rcdev);
  30        unsigned long flags;
  31        u32 val;
  32
  33        spin_lock_irqsave(&ath79_reset->lock, flags);
  34        val = readl(ath79_reset->base);
  35        if (assert)
  36                val |= BIT(id);
  37        else
  38                val &= ~BIT(id);
  39        writel(val, ath79_reset->base);
  40        spin_unlock_irqrestore(&ath79_reset->lock, flags);
  41
  42        return 0;
  43}
  44
  45static int ath79_reset_assert(struct reset_controller_dev *rcdev,
  46                        unsigned long id)
  47{
  48        return ath79_reset_update(rcdev, id, true);
  49}
  50
  51static int ath79_reset_deassert(struct reset_controller_dev *rcdev,
  52                                unsigned long id)
  53{
  54        return ath79_reset_update(rcdev, id, false);
  55}
  56
  57static int ath79_reset_status(struct reset_controller_dev *rcdev,
  58                        unsigned long id)
  59{
  60        struct ath79_reset *ath79_reset =
  61                container_of(rcdev, struct ath79_reset, rcdev);
  62        u32 val;
  63
  64        val = readl(ath79_reset->base);
  65
  66        return !!(val & BIT(id));
  67}
  68
  69static const struct reset_control_ops ath79_reset_ops = {
  70        .assert = ath79_reset_assert,
  71        .deassert = ath79_reset_deassert,
  72        .status = ath79_reset_status,
  73};
  74
  75static int ath79_reset_restart_handler(struct notifier_block *nb,
  76                                unsigned long action, void *data)
  77{
  78        struct ath79_reset *ath79_reset =
  79                container_of(nb, struct ath79_reset, restart_nb);
  80
  81        ath79_reset_assert(&ath79_reset->rcdev, FULL_CHIP_RESET);
  82
  83        return NOTIFY_DONE;
  84}
  85
  86static int ath79_reset_probe(struct platform_device *pdev)
  87{
  88        struct ath79_reset *ath79_reset;
  89        struct resource *res;
  90        int err;
  91
  92        ath79_reset = devm_kzalloc(&pdev->dev,
  93                                sizeof(*ath79_reset), GFP_KERNEL);
  94        if (!ath79_reset)
  95                return -ENOMEM;
  96
  97        platform_set_drvdata(pdev, ath79_reset);
  98
  99        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 100        ath79_reset->base = devm_ioremap_resource(&pdev->dev, res);
 101        if (IS_ERR(ath79_reset->base))
 102                return PTR_ERR(ath79_reset->base);
 103
 104        spin_lock_init(&ath79_reset->lock);
 105        ath79_reset->rcdev.ops = &ath79_reset_ops;
 106        ath79_reset->rcdev.owner = THIS_MODULE;
 107        ath79_reset->rcdev.of_node = pdev->dev.of_node;
 108        ath79_reset->rcdev.of_reset_n_cells = 1;
 109        ath79_reset->rcdev.nr_resets = 32;
 110
 111        err = devm_reset_controller_register(&pdev->dev, &ath79_reset->rcdev);
 112        if (err)
 113                return err;
 114
 115        ath79_reset->restart_nb.notifier_call = ath79_reset_restart_handler;
 116        ath79_reset->restart_nb.priority = 128;
 117
 118        err = register_restart_handler(&ath79_reset->restart_nb);
 119        if (err)
 120                dev_warn(&pdev->dev, "Failed to register restart handler\n");
 121
 122        return 0;
 123}
 124
 125static const struct of_device_id ath79_reset_dt_ids[] = {
 126        { .compatible = "qca,ar7100-reset", },
 127        { },
 128};
 129
 130static struct platform_driver ath79_reset_driver = {
 131        .probe  = ath79_reset_probe,
 132        .driver = {
 133                .name                   = "ath79-reset",
 134                .of_match_table         = ath79_reset_dt_ids,
 135                .suppress_bind_attrs    = true,
 136        },
 137};
 138builtin_platform_driver(ath79_reset_driver);
 139