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