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