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