1c392b65bSJoachim Eastwood /* 2c392b65bSJoachim Eastwood * Reset driver for NXP LPC18xx/43xx Reset Generation Unit (RGU). 3c392b65bSJoachim Eastwood * 4c392b65bSJoachim Eastwood * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com> 5c392b65bSJoachim Eastwood * 6c392b65bSJoachim Eastwood * This program is free software; you can redistribute it and/or modify 7c392b65bSJoachim Eastwood * it under the terms of the GNU General Public License version 2 as 8c392b65bSJoachim Eastwood * published by the Free Software Foundation. 9c392b65bSJoachim Eastwood * 10c392b65bSJoachim Eastwood */ 11c392b65bSJoachim Eastwood 12c392b65bSJoachim Eastwood #include <linux/clk.h> 13c392b65bSJoachim Eastwood #include <linux/delay.h> 14c392b65bSJoachim Eastwood #include <linux/err.h> 15c392b65bSJoachim Eastwood #include <linux/io.h> 16c392b65bSJoachim Eastwood #include <linux/module.h> 17c392b65bSJoachim Eastwood #include <linux/of.h> 18c392b65bSJoachim Eastwood #include <linux/platform_device.h> 19c392b65bSJoachim Eastwood #include <linux/reboot.h> 20c392b65bSJoachim Eastwood #include <linux/reset-controller.h> 21c392b65bSJoachim Eastwood #include <linux/spinlock.h> 22c392b65bSJoachim Eastwood 23c392b65bSJoachim Eastwood /* LPC18xx RGU registers */ 24c392b65bSJoachim Eastwood #define LPC18XX_RGU_CTRL0 0x100 25c392b65bSJoachim Eastwood #define LPC18XX_RGU_CTRL1 0x104 26c392b65bSJoachim Eastwood #define LPC18XX_RGU_ACTIVE_STATUS0 0x150 27c392b65bSJoachim Eastwood #define LPC18XX_RGU_ACTIVE_STATUS1 0x154 28c392b65bSJoachim Eastwood 29c392b65bSJoachim Eastwood #define LPC18XX_RGU_RESETS_PER_REG 32 30c392b65bSJoachim Eastwood 31c392b65bSJoachim Eastwood /* Internal reset outputs */ 32c392b65bSJoachim Eastwood #define LPC18XX_RGU_CORE_RST 0 33c392b65bSJoachim Eastwood #define LPC43XX_RGU_M0SUB_RST 12 34c392b65bSJoachim Eastwood #define LPC43XX_RGU_M0APP_RST 56 35c392b65bSJoachim Eastwood 36c392b65bSJoachim Eastwood struct lpc18xx_rgu_data { 37c392b65bSJoachim Eastwood struct reset_controller_dev rcdev; 38c392b65bSJoachim Eastwood struct clk *clk_delay; 39c392b65bSJoachim Eastwood struct clk *clk_reg; 40c392b65bSJoachim Eastwood void __iomem *base; 41c392b65bSJoachim Eastwood spinlock_t lock; 42c392b65bSJoachim Eastwood u32 delay_us; 43c392b65bSJoachim Eastwood }; 44c392b65bSJoachim Eastwood 45c392b65bSJoachim Eastwood #define to_rgu_data(p) container_of(p, struct lpc18xx_rgu_data, rcdev) 46c392b65bSJoachim Eastwood 47c392b65bSJoachim Eastwood static void __iomem *rgu_base; 48c392b65bSJoachim Eastwood 49c392b65bSJoachim Eastwood static int lpc18xx_rgu_restart(struct notifier_block *this, unsigned long mode, 50c392b65bSJoachim Eastwood void *cmd) 51c392b65bSJoachim Eastwood { 52c392b65bSJoachim Eastwood writel(BIT(LPC18XX_RGU_CORE_RST), rgu_base + LPC18XX_RGU_CTRL0); 53c392b65bSJoachim Eastwood mdelay(2000); 54c392b65bSJoachim Eastwood 55c392b65bSJoachim Eastwood pr_emerg("%s: unable to restart system\n", __func__); 56c392b65bSJoachim Eastwood 57c392b65bSJoachim Eastwood return NOTIFY_DONE; 58c392b65bSJoachim Eastwood } 59c392b65bSJoachim Eastwood 60c392b65bSJoachim Eastwood static struct notifier_block lpc18xx_rgu_restart_nb = { 61c392b65bSJoachim Eastwood .notifier_call = lpc18xx_rgu_restart, 62c392b65bSJoachim Eastwood .priority = 192, 63c392b65bSJoachim Eastwood }; 64c392b65bSJoachim Eastwood 65c392b65bSJoachim Eastwood /* 66c392b65bSJoachim Eastwood * The LPC18xx RGU has mostly self-deasserting resets except for the 67c392b65bSJoachim Eastwood * two reset lines going to the internal Cortex-M0 cores. 68c392b65bSJoachim Eastwood * 69c392b65bSJoachim Eastwood * To prevent the M0 core resets from accidentally getting deasserted 70c392b65bSJoachim Eastwood * status register must be check and bits in control register set to 71c392b65bSJoachim Eastwood * preserve the state. 72c392b65bSJoachim Eastwood */ 73c392b65bSJoachim Eastwood static int lpc18xx_rgu_setclear_reset(struct reset_controller_dev *rcdev, 74c392b65bSJoachim Eastwood unsigned long id, bool set) 75c392b65bSJoachim Eastwood { 76c392b65bSJoachim Eastwood struct lpc18xx_rgu_data *rc = to_rgu_data(rcdev); 77c392b65bSJoachim Eastwood u32 stat_offset = LPC18XX_RGU_ACTIVE_STATUS0; 78c392b65bSJoachim Eastwood u32 ctrl_offset = LPC18XX_RGU_CTRL0; 79c392b65bSJoachim Eastwood unsigned long flags; 80c392b65bSJoachim Eastwood u32 stat, rst_bit; 81c392b65bSJoachim Eastwood 82c392b65bSJoachim Eastwood stat_offset += (id / LPC18XX_RGU_RESETS_PER_REG) * sizeof(u32); 83c392b65bSJoachim Eastwood ctrl_offset += (id / LPC18XX_RGU_RESETS_PER_REG) * sizeof(u32); 84c392b65bSJoachim Eastwood rst_bit = 1 << (id % LPC18XX_RGU_RESETS_PER_REG); 85c392b65bSJoachim Eastwood 86c392b65bSJoachim Eastwood spin_lock_irqsave(&rc->lock, flags); 87c392b65bSJoachim Eastwood stat = ~readl(rc->base + stat_offset); 88c392b65bSJoachim Eastwood if (set) 89c392b65bSJoachim Eastwood writel(stat | rst_bit, rc->base + ctrl_offset); 90c392b65bSJoachim Eastwood else 91c392b65bSJoachim Eastwood writel(stat & ~rst_bit, rc->base + ctrl_offset); 92c392b65bSJoachim Eastwood spin_unlock_irqrestore(&rc->lock, flags); 93c392b65bSJoachim Eastwood 94c392b65bSJoachim Eastwood return 0; 95c392b65bSJoachim Eastwood } 96c392b65bSJoachim Eastwood 97c392b65bSJoachim Eastwood static int lpc18xx_rgu_assert(struct reset_controller_dev *rcdev, 98c392b65bSJoachim Eastwood unsigned long id) 99c392b65bSJoachim Eastwood { 100c392b65bSJoachim Eastwood return lpc18xx_rgu_setclear_reset(rcdev, id, true); 101c392b65bSJoachim Eastwood } 102c392b65bSJoachim Eastwood 103c392b65bSJoachim Eastwood static int lpc18xx_rgu_deassert(struct reset_controller_dev *rcdev, 104c392b65bSJoachim Eastwood unsigned long id) 105c392b65bSJoachim Eastwood { 106c392b65bSJoachim Eastwood return lpc18xx_rgu_setclear_reset(rcdev, id, false); 107c392b65bSJoachim Eastwood } 108c392b65bSJoachim Eastwood 109c392b65bSJoachim Eastwood /* Only M0 cores require explicit reset deassert */ 110c392b65bSJoachim Eastwood static int lpc18xx_rgu_reset(struct reset_controller_dev *rcdev, 111c392b65bSJoachim Eastwood unsigned long id) 112c392b65bSJoachim Eastwood { 113c392b65bSJoachim Eastwood struct lpc18xx_rgu_data *rc = to_rgu_data(rcdev); 114c392b65bSJoachim Eastwood 115c392b65bSJoachim Eastwood lpc18xx_rgu_assert(rcdev, id); 116c392b65bSJoachim Eastwood udelay(rc->delay_us); 117c392b65bSJoachim Eastwood 118c392b65bSJoachim Eastwood switch (id) { 119c392b65bSJoachim Eastwood case LPC43XX_RGU_M0SUB_RST: 120c392b65bSJoachim Eastwood case LPC43XX_RGU_M0APP_RST: 121c392b65bSJoachim Eastwood lpc18xx_rgu_setclear_reset(rcdev, id, false); 122c392b65bSJoachim Eastwood } 123c392b65bSJoachim Eastwood 124c392b65bSJoachim Eastwood return 0; 125c392b65bSJoachim Eastwood } 126c392b65bSJoachim Eastwood 127c392b65bSJoachim Eastwood static int lpc18xx_rgu_status(struct reset_controller_dev *rcdev, 128c392b65bSJoachim Eastwood unsigned long id) 129c392b65bSJoachim Eastwood { 130c392b65bSJoachim Eastwood struct lpc18xx_rgu_data *rc = to_rgu_data(rcdev); 131c392b65bSJoachim Eastwood u32 bit, offset = LPC18XX_RGU_ACTIVE_STATUS0; 132c392b65bSJoachim Eastwood 133c392b65bSJoachim Eastwood offset += (id / LPC18XX_RGU_RESETS_PER_REG) * sizeof(u32); 134c392b65bSJoachim Eastwood bit = 1 << (id % LPC18XX_RGU_RESETS_PER_REG); 135c392b65bSJoachim Eastwood 136c392b65bSJoachim Eastwood return !(readl(rc->base + offset) & bit); 137c392b65bSJoachim Eastwood } 138c392b65bSJoachim Eastwood 139*1a55cad1SPhilipp Zabel static const struct reset_control_ops lpc18xx_rgu_ops = { 140c392b65bSJoachim Eastwood .reset = lpc18xx_rgu_reset, 141c392b65bSJoachim Eastwood .assert = lpc18xx_rgu_assert, 142c392b65bSJoachim Eastwood .deassert = lpc18xx_rgu_deassert, 143c392b65bSJoachim Eastwood .status = lpc18xx_rgu_status, 144c392b65bSJoachim Eastwood }; 145c392b65bSJoachim Eastwood 146c392b65bSJoachim Eastwood static int lpc18xx_rgu_probe(struct platform_device *pdev) 147c392b65bSJoachim Eastwood { 148c392b65bSJoachim Eastwood struct lpc18xx_rgu_data *rc; 149c392b65bSJoachim Eastwood struct resource *res; 150c392b65bSJoachim Eastwood u32 fcclk, firc; 151c392b65bSJoachim Eastwood int ret; 152c392b65bSJoachim Eastwood 153c392b65bSJoachim Eastwood rc = devm_kzalloc(&pdev->dev, sizeof(*rc), GFP_KERNEL); 154c392b65bSJoachim Eastwood if (!rc) 155c392b65bSJoachim Eastwood return -ENOMEM; 156c392b65bSJoachim Eastwood 157c392b65bSJoachim Eastwood res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 158c392b65bSJoachim Eastwood rc->base = devm_ioremap_resource(&pdev->dev, res); 159c392b65bSJoachim Eastwood if (IS_ERR(rc->base)) 160c392b65bSJoachim Eastwood return PTR_ERR(rc->base); 161c392b65bSJoachim Eastwood 162c392b65bSJoachim Eastwood rc->clk_reg = devm_clk_get(&pdev->dev, "reg"); 163c392b65bSJoachim Eastwood if (IS_ERR(rc->clk_reg)) { 164c392b65bSJoachim Eastwood dev_err(&pdev->dev, "reg clock not found\n"); 165c392b65bSJoachim Eastwood return PTR_ERR(rc->clk_reg); 166c392b65bSJoachim Eastwood } 167c392b65bSJoachim Eastwood 168c392b65bSJoachim Eastwood rc->clk_delay = devm_clk_get(&pdev->dev, "delay"); 169c392b65bSJoachim Eastwood if (IS_ERR(rc->clk_delay)) { 170c392b65bSJoachim Eastwood dev_err(&pdev->dev, "delay clock not found\n"); 171c392b65bSJoachim Eastwood return PTR_ERR(rc->clk_delay); 172c392b65bSJoachim Eastwood } 173c392b65bSJoachim Eastwood 174c392b65bSJoachim Eastwood ret = clk_prepare_enable(rc->clk_reg); 175c392b65bSJoachim Eastwood if (ret) { 176c392b65bSJoachim Eastwood dev_err(&pdev->dev, "unable to enable reg clock\n"); 177c392b65bSJoachim Eastwood return ret; 178c392b65bSJoachim Eastwood } 179c392b65bSJoachim Eastwood 180c392b65bSJoachim Eastwood ret = clk_prepare_enable(rc->clk_delay); 181c392b65bSJoachim Eastwood if (ret) { 182c392b65bSJoachim Eastwood dev_err(&pdev->dev, "unable to enable delay clock\n"); 183c392b65bSJoachim Eastwood goto dis_clk_reg; 184c392b65bSJoachim Eastwood } 185c392b65bSJoachim Eastwood 186c392b65bSJoachim Eastwood fcclk = clk_get_rate(rc->clk_reg) / USEC_PER_SEC; 187c392b65bSJoachim Eastwood firc = clk_get_rate(rc->clk_delay) / USEC_PER_SEC; 188c392b65bSJoachim Eastwood if (fcclk == 0 || firc == 0) 189c392b65bSJoachim Eastwood rc->delay_us = 2; 190c392b65bSJoachim Eastwood else 191c392b65bSJoachim Eastwood rc->delay_us = DIV_ROUND_UP(fcclk, firc * firc); 192c392b65bSJoachim Eastwood 193c392b65bSJoachim Eastwood spin_lock_init(&rc->lock); 194c392b65bSJoachim Eastwood 195c392b65bSJoachim Eastwood rc->rcdev.owner = THIS_MODULE; 196c392b65bSJoachim Eastwood rc->rcdev.nr_resets = 64; 197c392b65bSJoachim Eastwood rc->rcdev.ops = &lpc18xx_rgu_ops; 198c392b65bSJoachim Eastwood rc->rcdev.of_node = pdev->dev.of_node; 199c392b65bSJoachim Eastwood 200c392b65bSJoachim Eastwood platform_set_drvdata(pdev, rc); 201c392b65bSJoachim Eastwood 202c392b65bSJoachim Eastwood ret = reset_controller_register(&rc->rcdev); 203c392b65bSJoachim Eastwood if (ret) { 204c392b65bSJoachim Eastwood dev_err(&pdev->dev, "unable to register device\n"); 205c392b65bSJoachim Eastwood goto dis_clks; 206c392b65bSJoachim Eastwood } 207c392b65bSJoachim Eastwood 208c392b65bSJoachim Eastwood rgu_base = rc->base; 209c392b65bSJoachim Eastwood ret = register_restart_handler(&lpc18xx_rgu_restart_nb); 210c392b65bSJoachim Eastwood if (ret) 211c392b65bSJoachim Eastwood dev_warn(&pdev->dev, "failed to register restart handler\n"); 212c392b65bSJoachim Eastwood 213c392b65bSJoachim Eastwood return 0; 214c392b65bSJoachim Eastwood 215c392b65bSJoachim Eastwood dis_clks: 216c392b65bSJoachim Eastwood clk_disable_unprepare(rc->clk_delay); 217c392b65bSJoachim Eastwood dis_clk_reg: 218c392b65bSJoachim Eastwood clk_disable_unprepare(rc->clk_reg); 219c392b65bSJoachim Eastwood 220c392b65bSJoachim Eastwood return ret; 221c392b65bSJoachim Eastwood } 222c392b65bSJoachim Eastwood 223c392b65bSJoachim Eastwood static int lpc18xx_rgu_remove(struct platform_device *pdev) 224c392b65bSJoachim Eastwood { 225c392b65bSJoachim Eastwood struct lpc18xx_rgu_data *rc = platform_get_drvdata(pdev); 226c392b65bSJoachim Eastwood int ret; 227c392b65bSJoachim Eastwood 228c392b65bSJoachim Eastwood ret = unregister_restart_handler(&lpc18xx_rgu_restart_nb); 229c392b65bSJoachim Eastwood if (ret) 230c392b65bSJoachim Eastwood dev_warn(&pdev->dev, "failed to unregister restart handler\n"); 231c392b65bSJoachim Eastwood 232c392b65bSJoachim Eastwood reset_controller_unregister(&rc->rcdev); 233c392b65bSJoachim Eastwood 234c392b65bSJoachim Eastwood clk_disable_unprepare(rc->clk_delay); 235c392b65bSJoachim Eastwood clk_disable_unprepare(rc->clk_reg); 236c392b65bSJoachim Eastwood 237c392b65bSJoachim Eastwood return 0; 238c392b65bSJoachim Eastwood } 239c392b65bSJoachim Eastwood 240c392b65bSJoachim Eastwood static const struct of_device_id lpc18xx_rgu_match[] = { 241c392b65bSJoachim Eastwood { .compatible = "nxp,lpc1850-rgu" }, 242c392b65bSJoachim Eastwood { } 243c392b65bSJoachim Eastwood }; 244c392b65bSJoachim Eastwood MODULE_DEVICE_TABLE(of, lpc18xx_rgu_match); 245c392b65bSJoachim Eastwood 246c392b65bSJoachim Eastwood static struct platform_driver lpc18xx_rgu_driver = { 247c392b65bSJoachim Eastwood .probe = lpc18xx_rgu_probe, 248c392b65bSJoachim Eastwood .remove = lpc18xx_rgu_remove, 249c392b65bSJoachim Eastwood .driver = { 250c392b65bSJoachim Eastwood .name = "lpc18xx-reset", 251c392b65bSJoachim Eastwood .of_match_table = lpc18xx_rgu_match, 252c392b65bSJoachim Eastwood }, 253c392b65bSJoachim Eastwood }; 254c392b65bSJoachim Eastwood module_platform_driver(lpc18xx_rgu_driver); 255c392b65bSJoachim Eastwood 256c392b65bSJoachim Eastwood MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>"); 257c392b65bSJoachim Eastwood MODULE_DESCRIPTION("Reset driver for LPC18xx/43xx RGU"); 258c392b65bSJoachim Eastwood MODULE_LICENSE("GPL v2"); 259