1 /* 2 * Watchdog driver for Renesas WDT watchdog 3 * 4 * Copyright (C) 2015-16 Wolfram Sang, Sang Engineering <wsa@sang-engineering.com> 5 * Copyright (C) 2015-16 Renesas Electronics Corporation 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 as published by 9 * the Free Software Foundation. 10 */ 11 #include <linux/bitops.h> 12 #include <linux/clk.h> 13 #include <linux/io.h> 14 #include <linux/kernel.h> 15 #include <linux/module.h> 16 #include <linux/of.h> 17 #include <linux/platform_device.h> 18 #include <linux/pm_runtime.h> 19 #include <linux/watchdog.h> 20 21 #define RWTCNT 0 22 #define RWTCSRA 4 23 #define RWTCSRA_WOVF BIT(4) 24 #define RWTCSRA_WRFLG BIT(5) 25 #define RWTCSRA_TME BIT(7) 26 27 #define RWDT_DEFAULT_TIMEOUT 60U 28 29 static const unsigned int clk_divs[] = { 1, 4, 16, 32, 64, 128, 1024 }; 30 31 static bool nowayout = WATCHDOG_NOWAYOUT; 32 module_param(nowayout, bool, 0); 33 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" 34 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 35 36 struct rwdt_priv { 37 void __iomem *base; 38 struct watchdog_device wdev; 39 struct clk *clk; 40 unsigned int clks_per_sec; 41 u8 cks; 42 }; 43 44 static void rwdt_write(struct rwdt_priv *priv, u32 val, unsigned int reg) 45 { 46 if (reg == RWTCNT) 47 val |= 0x5a5a0000; 48 else 49 val |= 0xa5a5a500; 50 51 writel_relaxed(val, priv->base + reg); 52 } 53 54 static int rwdt_init_timeout(struct watchdog_device *wdev) 55 { 56 struct rwdt_priv *priv = watchdog_get_drvdata(wdev); 57 58 rwdt_write(priv, 65536 - wdev->timeout * priv->clks_per_sec, RWTCNT); 59 60 return 0; 61 } 62 63 static int rwdt_start(struct watchdog_device *wdev) 64 { 65 struct rwdt_priv *priv = watchdog_get_drvdata(wdev); 66 67 clk_prepare_enable(priv->clk); 68 69 rwdt_write(priv, priv->cks, RWTCSRA); 70 rwdt_init_timeout(wdev); 71 72 while (readb_relaxed(priv->base + RWTCSRA) & RWTCSRA_WRFLG) 73 cpu_relax(); 74 75 rwdt_write(priv, priv->cks | RWTCSRA_TME, RWTCSRA); 76 77 return 0; 78 } 79 80 static int rwdt_stop(struct watchdog_device *wdev) 81 { 82 struct rwdt_priv *priv = watchdog_get_drvdata(wdev); 83 84 rwdt_write(priv, priv->cks, RWTCSRA); 85 clk_disable_unprepare(priv->clk); 86 87 return 0; 88 } 89 90 static unsigned int rwdt_get_timeleft(struct watchdog_device *wdev) 91 { 92 struct rwdt_priv *priv = watchdog_get_drvdata(wdev); 93 u16 val = readw_relaxed(priv->base + RWTCNT); 94 95 return DIV_ROUND_CLOSEST(65536 - val, priv->clks_per_sec); 96 } 97 98 static const struct watchdog_info rwdt_ident = { 99 .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT, 100 .identity = "Renesas WDT Watchdog", 101 }; 102 103 static const struct watchdog_ops rwdt_ops = { 104 .owner = THIS_MODULE, 105 .start = rwdt_start, 106 .stop = rwdt_stop, 107 .ping = rwdt_init_timeout, 108 .get_timeleft = rwdt_get_timeleft, 109 }; 110 111 static int rwdt_probe(struct platform_device *pdev) 112 { 113 struct rwdt_priv *priv; 114 struct resource *res; 115 unsigned long rate; 116 unsigned int clks_per_sec; 117 int ret, i; 118 119 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 120 if (!priv) 121 return -ENOMEM; 122 123 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 124 priv->base = devm_ioremap_resource(&pdev->dev, res); 125 if (IS_ERR(priv->base)) 126 return PTR_ERR(priv->base); 127 128 priv->clk = devm_clk_get(&pdev->dev, NULL); 129 if (IS_ERR(priv->clk)) 130 return PTR_ERR(priv->clk); 131 132 rate = clk_get_rate(priv->clk); 133 if (!rate) 134 return -ENOENT; 135 136 for (i = ARRAY_SIZE(clk_divs) - 1; i >= 0; i--) { 137 clks_per_sec = DIV_ROUND_UP(rate, clk_divs[i]); 138 if (clks_per_sec) { 139 priv->clks_per_sec = clks_per_sec; 140 priv->cks = i; 141 break; 142 } 143 } 144 145 if (!clks_per_sec) { 146 dev_err(&pdev->dev, "Can't find suitable clock divider\n"); 147 return -ERANGE; 148 } 149 150 pm_runtime_enable(&pdev->dev); 151 pm_runtime_get_sync(&pdev->dev); 152 153 priv->wdev.info = &rwdt_ident, 154 priv->wdev.ops = &rwdt_ops, 155 priv->wdev.parent = &pdev->dev; 156 priv->wdev.min_timeout = 1; 157 priv->wdev.max_timeout = 65536 / clks_per_sec; 158 priv->wdev.timeout = min(priv->wdev.max_timeout, RWDT_DEFAULT_TIMEOUT); 159 160 platform_set_drvdata(pdev, priv); 161 watchdog_set_drvdata(&priv->wdev, priv); 162 watchdog_set_nowayout(&priv->wdev, nowayout); 163 164 /* This overrides the default timeout only if DT configuration was found */ 165 ret = watchdog_init_timeout(&priv->wdev, 0, &pdev->dev); 166 if (ret) 167 dev_warn(&pdev->dev, "Specified timeout value invalid, using default\n"); 168 169 ret = watchdog_register_device(&priv->wdev); 170 if (ret < 0) { 171 pm_runtime_put(&pdev->dev); 172 pm_runtime_disable(&pdev->dev); 173 return ret; 174 } 175 176 return 0; 177 } 178 179 static int rwdt_remove(struct platform_device *pdev) 180 { 181 struct rwdt_priv *priv = platform_get_drvdata(pdev); 182 183 watchdog_unregister_device(&priv->wdev); 184 pm_runtime_put(&pdev->dev); 185 pm_runtime_disable(&pdev->dev); 186 187 return 0; 188 } 189 190 /* 191 * This driver does also fit for R-Car Gen2 (r8a779[0-4]) WDT. However, for SMP 192 * to work there, one also needs a RESET (RST) driver which does not exist yet 193 * due to HW issues. This needs to be solved before adding compatibles here. 194 */ 195 static const struct of_device_id rwdt_ids[] = { 196 { .compatible = "renesas,rcar-gen3-wdt", }, 197 { /* sentinel */ } 198 }; 199 MODULE_DEVICE_TABLE(of, rwdt_ids); 200 201 static struct platform_driver rwdt_driver = { 202 .driver = { 203 .name = "renesas_wdt", 204 .of_match_table = rwdt_ids, 205 }, 206 .probe = rwdt_probe, 207 .remove = rwdt_remove, 208 }; 209 module_platform_driver(rwdt_driver); 210 211 MODULE_DESCRIPTION("Renesas WDT Watchdog Driver"); 212 MODULE_LICENSE("GPL v2"); 213 MODULE_AUTHOR("Wolfram Sang <wsa@sang-engineering.com>"); 214