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/io.h> 16 #include <linux/module.h> 17 #include <linux/platform_device.h> 18 #include <linux/reset-controller.h> 19 #include <linux/reboot.h> 20 21 struct ath79_reset { 22 struct reset_controller_dev rcdev; 23 struct notifier_block restart_nb; 24 void __iomem *base; 25 spinlock_t lock; 26 }; 27 28 #define FULL_CHIP_RESET 24 29 30 static int ath79_reset_update(struct reset_controller_dev *rcdev, 31 unsigned long id, bool assert) 32 { 33 struct ath79_reset *ath79_reset = 34 container_of(rcdev, struct ath79_reset, rcdev); 35 unsigned long flags; 36 u32 val; 37 38 spin_lock_irqsave(&ath79_reset->lock, flags); 39 val = readl(ath79_reset->base); 40 if (assert) 41 val |= BIT(id); 42 else 43 val &= ~BIT(id); 44 writel(val, ath79_reset->base); 45 spin_unlock_irqrestore(&ath79_reset->lock, flags); 46 47 return 0; 48 } 49 50 static int ath79_reset_assert(struct reset_controller_dev *rcdev, 51 unsigned long id) 52 { 53 return ath79_reset_update(rcdev, id, true); 54 } 55 56 static int ath79_reset_deassert(struct reset_controller_dev *rcdev, 57 unsigned long id) 58 { 59 return ath79_reset_update(rcdev, id, false); 60 } 61 62 static int ath79_reset_status(struct reset_controller_dev *rcdev, 63 unsigned long id) 64 { 65 struct ath79_reset *ath79_reset = 66 container_of(rcdev, struct ath79_reset, rcdev); 67 u32 val; 68 69 val = readl(ath79_reset->base); 70 71 return !!(val & BIT(id)); 72 } 73 74 static const struct reset_control_ops ath79_reset_ops = { 75 .assert = ath79_reset_assert, 76 .deassert = ath79_reset_deassert, 77 .status = ath79_reset_status, 78 }; 79 80 static int ath79_reset_restart_handler(struct notifier_block *nb, 81 unsigned long action, void *data) 82 { 83 struct ath79_reset *ath79_reset = 84 container_of(nb, struct ath79_reset, restart_nb); 85 86 ath79_reset_assert(&ath79_reset->rcdev, FULL_CHIP_RESET); 87 88 return NOTIFY_DONE; 89 } 90 91 static int ath79_reset_probe(struct platform_device *pdev) 92 { 93 struct ath79_reset *ath79_reset; 94 struct resource *res; 95 int err; 96 97 ath79_reset = devm_kzalloc(&pdev->dev, 98 sizeof(*ath79_reset), GFP_KERNEL); 99 if (!ath79_reset) 100 return -ENOMEM; 101 102 platform_set_drvdata(pdev, ath79_reset); 103 104 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 105 ath79_reset->base = devm_ioremap_resource(&pdev->dev, res); 106 if (IS_ERR(ath79_reset->base)) 107 return PTR_ERR(ath79_reset->base); 108 109 spin_lock_init(&ath79_reset->lock); 110 ath79_reset->rcdev.ops = &ath79_reset_ops; 111 ath79_reset->rcdev.owner = THIS_MODULE; 112 ath79_reset->rcdev.of_node = pdev->dev.of_node; 113 ath79_reset->rcdev.of_reset_n_cells = 1; 114 ath79_reset->rcdev.nr_resets = 32; 115 116 err = devm_reset_controller_register(&pdev->dev, &ath79_reset->rcdev); 117 if (err) 118 return err; 119 120 ath79_reset->restart_nb.notifier_call = ath79_reset_restart_handler; 121 ath79_reset->restart_nb.priority = 128; 122 123 err = register_restart_handler(&ath79_reset->restart_nb); 124 if (err) 125 dev_warn(&pdev->dev, "Failed to register restart handler\n"); 126 127 return 0; 128 } 129 130 static int ath79_reset_remove(struct platform_device *pdev) 131 { 132 struct ath79_reset *ath79_reset = platform_get_drvdata(pdev); 133 134 unregister_restart_handler(&ath79_reset->restart_nb); 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