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