348 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Renesas RZ/G2L WDT Watchdog Driver4 *5 * Copyright (C) 2021 Renesas Electronics Corporation6 */7#include <linux/bitops.h>8#include <linux/clk.h>9#include <linux/delay.h>10#include <linux/io.h>11#include <linux/kernel.h>12#include <linux/module.h>13#include <linux/of.h>14#include <linux/platform_device.h>15#include <linux/pm_runtime.h>16#include <linux/reset.h>17#include <linux/units.h>18#include <linux/watchdog.h>19 20#define WDTCNT 0x0021#define WDTSET 0x0422#define WDTTIM 0x0823#define WDTINT 0x0C24#define PECR 0x1025#define PEEN 0x1426#define WDTCNT_WDTEN BIT(0)27#define WDTINT_INTDISP BIT(0)28#define PEEN_FORCE BIT(0)29 30#define WDT_DEFAULT_TIMEOUT 60U31 32/* Setting period time register only 12 bit set in WDTSET[31:20] */33#define WDTSET_COUNTER_MASK (0xFFF00000)34#define WDTSET_COUNTER_VAL(f) ((f) << 20)35 36#define F2CYCLE_NSEC(f) (1000000000 / (f))37 38#define RZV2M_A_NSEC 73039 40static bool nowayout = WATCHDOG_NOWAYOUT;41module_param(nowayout, bool, 0);42MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="43 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");44 45enum rz_wdt_type {46 WDT_RZG2L,47 WDT_RZV2M,48};49 50struct rzg2l_wdt_priv {51 void __iomem *base;52 struct watchdog_device wdev;53 struct reset_control *rstc;54 unsigned long osc_clk_rate;55 unsigned long delay;56 struct clk *pclk;57 struct clk *osc_clk;58 enum rz_wdt_type devtype;59};60 61static void rzg2l_wdt_wait_delay(struct rzg2l_wdt_priv *priv)62{63 /* delay timer when change the setting register */64 ndelay(priv->delay);65}66 67static u32 rzg2l_wdt_get_cycle_usec(unsigned long cycle, u32 wdttime)68{69 u64 timer_cycle_us = 1024 * 1024ULL * (wdttime + 1) * MICRO;70 71 return div64_ul(timer_cycle_us, cycle);72}73 74static void rzg2l_wdt_write(struct rzg2l_wdt_priv *priv, u32 val, unsigned int reg)75{76 if (reg == WDTSET)77 val &= WDTSET_COUNTER_MASK;78 79 writel_relaxed(val, priv->base + reg);80 /* Registers other than the WDTINT is always synchronized with WDT_CLK */81 if (reg != WDTINT)82 rzg2l_wdt_wait_delay(priv);83}84 85static void rzg2l_wdt_init_timeout(struct watchdog_device *wdev)86{87 struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev);88 u32 time_out;89 90 /* Clear Lapsed Time Register and clear Interrupt */91 rzg2l_wdt_write(priv, WDTINT_INTDISP, WDTINT);92 /* 2 consecutive overflow cycle needed to trigger reset */93 time_out = (wdev->timeout * (MICRO / 2)) /94 rzg2l_wdt_get_cycle_usec(priv->osc_clk_rate, 0);95 rzg2l_wdt_write(priv, WDTSET_COUNTER_VAL(time_out), WDTSET);96}97 98static int rzg2l_wdt_start(struct watchdog_device *wdev)99{100 struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev);101 int ret;102 103 ret = pm_runtime_resume_and_get(wdev->parent);104 if (ret)105 return ret;106 107 ret = reset_control_deassert(priv->rstc);108 if (ret) {109 pm_runtime_put(wdev->parent);110 return ret;111 }112 113 /* Initialize time out */114 rzg2l_wdt_init_timeout(wdev);115 116 /* Initialize watchdog counter register */117 rzg2l_wdt_write(priv, 0, WDTTIM);118 119 /* Enable watchdog timer*/120 rzg2l_wdt_write(priv, WDTCNT_WDTEN, WDTCNT);121 122 return 0;123}124 125static int rzg2l_wdt_stop(struct watchdog_device *wdev)126{127 struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev);128 int ret;129 130 ret = reset_control_assert(priv->rstc);131 if (ret)132 return ret;133 134 ret = pm_runtime_put(wdev->parent);135 if (ret < 0)136 return ret;137 138 return 0;139}140 141static int rzg2l_wdt_set_timeout(struct watchdog_device *wdev, unsigned int timeout)142{143 int ret = 0;144 145 wdev->timeout = timeout;146 147 /*148 * If the watchdog is active, reset the module for updating the WDTSET149 * register by calling rzg2l_wdt_stop() (which internally calls reset_control_reset()150 * to reset the module) so that it is updated with new timeout values.151 */152 if (watchdog_active(wdev)) {153 ret = rzg2l_wdt_stop(wdev);154 if (ret)155 return ret;156 157 ret = rzg2l_wdt_start(wdev);158 }159 160 return ret;161}162 163static int rzg2l_wdt_restart(struct watchdog_device *wdev,164 unsigned long action, void *data)165{166 struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev);167 int ret;168 169 clk_prepare_enable(priv->pclk);170 clk_prepare_enable(priv->osc_clk);171 172 if (priv->devtype == WDT_RZG2L) {173 ret = reset_control_deassert(priv->rstc);174 if (ret)175 return ret;176 177 /* Generate Reset (WDTRSTB) Signal on parity error */178 rzg2l_wdt_write(priv, 0, PECR);179 180 /* Force parity error */181 rzg2l_wdt_write(priv, PEEN_FORCE, PEEN);182 } else {183 /* RZ/V2M doesn't have parity error registers */184 ret = reset_control_reset(priv->rstc);185 if (ret)186 return ret;187 188 wdev->timeout = 0;189 190 /* Initialize time out */191 rzg2l_wdt_init_timeout(wdev);192 193 /* Initialize watchdog counter register */194 rzg2l_wdt_write(priv, 0, WDTTIM);195 196 /* Enable watchdog timer*/197 rzg2l_wdt_write(priv, WDTCNT_WDTEN, WDTCNT);198 199 /* Wait 2 consecutive overflow cycles for reset */200 mdelay(DIV_ROUND_UP(2 * 0xFFFFF * 1000, priv->osc_clk_rate));201 }202 203 return 0;204}205 206static const struct watchdog_info rzg2l_wdt_ident = {207 .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,208 .identity = "Renesas RZ/G2L WDT Watchdog",209};210 211static int rzg2l_wdt_ping(struct watchdog_device *wdev)212{213 struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev);214 215 rzg2l_wdt_write(priv, WDTINT_INTDISP, WDTINT);216 217 return 0;218}219 220static const struct watchdog_ops rzg2l_wdt_ops = {221 .owner = THIS_MODULE,222 .start = rzg2l_wdt_start,223 .stop = rzg2l_wdt_stop,224 .ping = rzg2l_wdt_ping,225 .set_timeout = rzg2l_wdt_set_timeout,226 .restart = rzg2l_wdt_restart,227};228 229static void rzg2l_wdt_pm_disable(void *data)230{231 struct watchdog_device *wdev = data;232 233 pm_runtime_disable(wdev->parent);234}235 236static int rzg2l_wdt_probe(struct platform_device *pdev)237{238 struct device *dev = &pdev->dev;239 struct rzg2l_wdt_priv *priv;240 unsigned long pclk_rate;241 int ret;242 243 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);244 if (!priv)245 return -ENOMEM;246 247 priv->base = devm_platform_ioremap_resource(pdev, 0);248 if (IS_ERR(priv->base))249 return PTR_ERR(priv->base);250 251 /* Get watchdog main clock */252 priv->osc_clk = devm_clk_get(&pdev->dev, "oscclk");253 if (IS_ERR(priv->osc_clk))254 return dev_err_probe(&pdev->dev, PTR_ERR(priv->osc_clk), "no oscclk");255 256 priv->osc_clk_rate = clk_get_rate(priv->osc_clk);257 if (!priv->osc_clk_rate)258 return dev_err_probe(&pdev->dev, -EINVAL, "oscclk rate is 0");259 260 /* Get Peripheral clock */261 priv->pclk = devm_clk_get(&pdev->dev, "pclk");262 if (IS_ERR(priv->pclk))263 return dev_err_probe(&pdev->dev, PTR_ERR(priv->pclk), "no pclk");264 265 pclk_rate = clk_get_rate(priv->pclk);266 if (!pclk_rate)267 return dev_err_probe(&pdev->dev, -EINVAL, "pclk rate is 0");268 269 priv->delay = F2CYCLE_NSEC(priv->osc_clk_rate) * 6 + F2CYCLE_NSEC(pclk_rate) * 9;270 271 priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);272 if (IS_ERR(priv->rstc))273 return dev_err_probe(&pdev->dev, PTR_ERR(priv->rstc),274 "failed to get cpg reset");275 276 priv->devtype = (uintptr_t)of_device_get_match_data(dev);277 278 pm_runtime_enable(&pdev->dev);279 280 priv->wdev.info = &rzg2l_wdt_ident;281 priv->wdev.ops = &rzg2l_wdt_ops;282 priv->wdev.parent = dev;283 priv->wdev.min_timeout = 1;284 priv->wdev.max_timeout = rzg2l_wdt_get_cycle_usec(priv->osc_clk_rate, 0xfff) /285 USEC_PER_SEC;286 priv->wdev.timeout = WDT_DEFAULT_TIMEOUT;287 288 watchdog_set_drvdata(&priv->wdev, priv);289 dev_set_drvdata(dev, priv);290 ret = devm_add_action_or_reset(&pdev->dev, rzg2l_wdt_pm_disable, &priv->wdev);291 if (ret)292 return ret;293 294 watchdog_set_nowayout(&priv->wdev, nowayout);295 watchdog_stop_on_unregister(&priv->wdev);296 297 ret = watchdog_init_timeout(&priv->wdev, 0, dev);298 if (ret)299 dev_warn(dev, "Specified timeout invalid, using default");300 301 return devm_watchdog_register_device(&pdev->dev, &priv->wdev);302}303 304static const struct of_device_id rzg2l_wdt_ids[] = {305 { .compatible = "renesas,rzg2l-wdt", .data = (void *)WDT_RZG2L },306 { .compatible = "renesas,rzv2m-wdt", .data = (void *)WDT_RZV2M },307 { /* sentinel */ }308};309MODULE_DEVICE_TABLE(of, rzg2l_wdt_ids);310 311static int rzg2l_wdt_suspend_late(struct device *dev)312{313 struct rzg2l_wdt_priv *priv = dev_get_drvdata(dev);314 315 if (!watchdog_active(&priv->wdev))316 return 0;317 318 return rzg2l_wdt_stop(&priv->wdev);319}320 321static int rzg2l_wdt_resume_early(struct device *dev)322{323 struct rzg2l_wdt_priv *priv = dev_get_drvdata(dev);324 325 if (!watchdog_active(&priv->wdev))326 return 0;327 328 return rzg2l_wdt_start(&priv->wdev);329}330 331static const struct dev_pm_ops rzg2l_wdt_pm_ops = {332 LATE_SYSTEM_SLEEP_PM_OPS(rzg2l_wdt_suspend_late, rzg2l_wdt_resume_early)333};334 335static struct platform_driver rzg2l_wdt_driver = {336 .driver = {337 .name = "rzg2l_wdt",338 .of_match_table = rzg2l_wdt_ids,339 .pm = &rzg2l_wdt_pm_ops,340 },341 .probe = rzg2l_wdt_probe,342};343module_platform_driver(rzg2l_wdt_driver);344 345MODULE_DESCRIPTION("Renesas RZ/G2L WDT Watchdog Driver");346MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");347MODULE_LICENSE("GPL v2");348