reset-ath79.c (3361B)
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);