Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * AR71xx Reset Controller Driver
0004  * Author: Alban Bedel
0005  *
0006  * Copyright (C) 2015 Alban Bedel <albeu@free.fr>
0007  */
0008 
0009 #include <linux/io.h>
0010 #include <linux/init.h>
0011 #include <linux/mod_devicetable.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/reset-controller.h>
0014 #include <linux/reboot.h>
0015 
0016 struct ath79_reset {
0017     struct reset_controller_dev rcdev;
0018     struct notifier_block restart_nb;
0019     void __iomem *base;
0020     spinlock_t lock;
0021 };
0022 
0023 #define FULL_CHIP_RESET 24
0024 
0025 static int ath79_reset_update(struct reset_controller_dev *rcdev,
0026             unsigned long id, bool assert)
0027 {
0028     struct ath79_reset *ath79_reset =
0029         container_of(rcdev, struct ath79_reset, rcdev);
0030     unsigned long flags;
0031     u32 val;
0032 
0033     spin_lock_irqsave(&ath79_reset->lock, flags);
0034     val = readl(ath79_reset->base);
0035     if (assert)
0036         val |= BIT(id);
0037     else
0038         val &= ~BIT(id);
0039     writel(val, ath79_reset->base);
0040     spin_unlock_irqrestore(&ath79_reset->lock, flags);
0041 
0042     return 0;
0043 }
0044 
0045 static int ath79_reset_assert(struct reset_controller_dev *rcdev,
0046             unsigned long id)
0047 {
0048     return ath79_reset_update(rcdev, id, true);
0049 }
0050 
0051 static int ath79_reset_deassert(struct reset_controller_dev *rcdev,
0052                 unsigned long id)
0053 {
0054     return ath79_reset_update(rcdev, id, false);
0055 }
0056 
0057 static int ath79_reset_status(struct reset_controller_dev *rcdev,
0058             unsigned long id)
0059 {
0060     struct ath79_reset *ath79_reset =
0061         container_of(rcdev, struct ath79_reset, rcdev);
0062     u32 val;
0063 
0064     val = readl(ath79_reset->base);
0065 
0066     return !!(val & BIT(id));
0067 }
0068 
0069 static const struct reset_control_ops ath79_reset_ops = {
0070     .assert = ath79_reset_assert,
0071     .deassert = ath79_reset_deassert,
0072     .status = ath79_reset_status,
0073 };
0074 
0075 static int ath79_reset_restart_handler(struct notifier_block *nb,
0076                 unsigned long action, void *data)
0077 {
0078     struct ath79_reset *ath79_reset =
0079         container_of(nb, struct ath79_reset, restart_nb);
0080 
0081     ath79_reset_assert(&ath79_reset->rcdev, FULL_CHIP_RESET);
0082 
0083     return NOTIFY_DONE;
0084 }
0085 
0086 static int ath79_reset_probe(struct platform_device *pdev)
0087 {
0088     struct ath79_reset *ath79_reset;
0089     struct resource *res;
0090     int err;
0091 
0092     ath79_reset = devm_kzalloc(&pdev->dev,
0093                 sizeof(*ath79_reset), GFP_KERNEL);
0094     if (!ath79_reset)
0095         return -ENOMEM;
0096 
0097     platform_set_drvdata(pdev, ath79_reset);
0098 
0099     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0100     ath79_reset->base = devm_ioremap_resource(&pdev->dev, res);
0101     if (IS_ERR(ath79_reset->base))
0102         return PTR_ERR(ath79_reset->base);
0103 
0104     spin_lock_init(&ath79_reset->lock);
0105     ath79_reset->rcdev.ops = &ath79_reset_ops;
0106     ath79_reset->rcdev.owner = THIS_MODULE;
0107     ath79_reset->rcdev.of_node = pdev->dev.of_node;
0108     ath79_reset->rcdev.of_reset_n_cells = 1;
0109     ath79_reset->rcdev.nr_resets = 32;
0110 
0111     err = devm_reset_controller_register(&pdev->dev, &ath79_reset->rcdev);
0112     if (err)
0113         return err;
0114 
0115     ath79_reset->restart_nb.notifier_call = ath79_reset_restart_handler;
0116     ath79_reset->restart_nb.priority = 128;
0117 
0118     err = register_restart_handler(&ath79_reset->restart_nb);
0119     if (err)
0120         dev_warn(&pdev->dev, "Failed to register restart handler\n");
0121 
0122     return 0;
0123 }
0124 
0125 static const struct of_device_id ath79_reset_dt_ids[] = {
0126     { .compatible = "qca,ar7100-reset", },
0127     { },
0128 };
0129 
0130 static struct platform_driver ath79_reset_driver = {
0131     .probe  = ath79_reset_probe,
0132     .driver = {
0133         .name           = "ath79-reset",
0134         .of_match_table     = ath79_reset_dt_ids,
0135         .suppress_bind_attrs    = true,
0136     },
0137 };
0138 builtin_platform_driver(ath79_reset_driver);