1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2020 TOSHIBA CORPORATION 4 * Copyright (c) 2020 Toshiba Electronic Devices & Storage Corporation 5 * Copyright (c) 2020 Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp> 6 */ 7 8 #include <linux/clk.h> 9 #include <linux/io.h> 10 #include <linux/kernel.h> 11 #include <linux/module.h> 12 #include <linux/of.h> 13 #include <linux/platform_device.h> 14 #include <linux/watchdog.h> 15 16 #define WDT_CNT 0x00 17 #define WDT_MIN 0x04 18 #define WDT_MAX 0x08 19 #define WDT_CTL 0x0c 20 #define WDT_CMD 0x10 21 #define WDT_CMD_CLEAR 0x4352 22 #define WDT_CMD_START_STOP 0x5354 23 #define WDT_DIV 0x30 24 25 #define VISCONTI_WDT_FREQ 2000000 /* 2MHz */ 26 #define WDT_DEFAULT_TIMEOUT 10U /* in seconds */ 27 28 static bool nowayout = WATCHDOG_NOWAYOUT; 29 module_param(nowayout, bool, 0); 30 MODULE_PARM_DESC( 31 nowayout, 32 "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT)")"); 33 34 struct visconti_wdt_priv { 35 struct watchdog_device wdev; 36 void __iomem *base; 37 u32 div; 38 }; 39 40 static int visconti_wdt_start(struct watchdog_device *wdev) 41 { 42 struct visconti_wdt_priv *priv = watchdog_get_drvdata(wdev); 43 u32 timeout = wdev->timeout * VISCONTI_WDT_FREQ; 44 45 writel(priv->div, priv->base + WDT_DIV); 46 writel(0, priv->base + WDT_MIN); 47 writel(timeout, priv->base + WDT_MAX); 48 writel(0, priv->base + WDT_CTL); 49 writel(WDT_CMD_START_STOP, priv->base + WDT_CMD); 50 51 return 0; 52 } 53 54 static int visconti_wdt_stop(struct watchdog_device *wdev) 55 { 56 struct visconti_wdt_priv *priv = watchdog_get_drvdata(wdev); 57 58 writel(1, priv->base + WDT_CTL); 59 writel(WDT_CMD_START_STOP, priv->base + WDT_CMD); 60 61 return 0; 62 } 63 64 static int visconti_wdt_ping(struct watchdog_device *wdd) 65 { 66 struct visconti_wdt_priv *priv = watchdog_get_drvdata(wdd); 67 68 writel(WDT_CMD_CLEAR, priv->base + WDT_CMD); 69 70 return 0; 71 } 72 73 static unsigned int visconti_wdt_get_timeleft(struct watchdog_device *wdev) 74 { 75 struct visconti_wdt_priv *priv = watchdog_get_drvdata(wdev); 76 u32 timeout = wdev->timeout * VISCONTI_WDT_FREQ; 77 u32 cnt = readl(priv->base + WDT_CNT); 78 79 if (timeout <= cnt) 80 return 0; 81 timeout -= cnt; 82 83 return timeout / VISCONTI_WDT_FREQ; 84 } 85 86 static int visconti_wdt_set_timeout(struct watchdog_device *wdev, unsigned int timeout) 87 { 88 u32 val; 89 struct visconti_wdt_priv *priv = watchdog_get_drvdata(wdev); 90 91 wdev->timeout = timeout; 92 val = wdev->timeout * VISCONTI_WDT_FREQ; 93 94 /* Clear counter before setting timeout because WDT expires */ 95 writel(WDT_CMD_CLEAR, priv->base + WDT_CMD); 96 writel(val, priv->base + WDT_MAX); 97 98 return 0; 99 } 100 101 static const struct watchdog_info visconti_wdt_info = { 102 .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, 103 .identity = "Visconti Watchdog", 104 }; 105 106 static const struct watchdog_ops visconti_wdt_ops = { 107 .owner = THIS_MODULE, 108 .start = visconti_wdt_start, 109 .stop = visconti_wdt_stop, 110 .ping = visconti_wdt_ping, 111 .get_timeleft = visconti_wdt_get_timeleft, 112 .set_timeout = visconti_wdt_set_timeout, 113 }; 114 115 static int visconti_wdt_probe(struct platform_device *pdev) 116 { 117 struct watchdog_device *wdev; 118 struct visconti_wdt_priv *priv; 119 struct device *dev = &pdev->dev; 120 struct clk *clk; 121 int ret; 122 unsigned long clk_freq; 123 124 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 125 if (!priv) 126 return -ENOMEM; 127 128 priv->base = devm_platform_ioremap_resource(pdev, 0); 129 if (IS_ERR(priv->base)) 130 return PTR_ERR(priv->base); 131 132 clk = devm_clk_get_enabled(dev, NULL); 133 if (IS_ERR(clk)) 134 return dev_err_probe(dev, PTR_ERR(clk), "Could not get clock\n"); 135 136 clk_freq = clk_get_rate(clk); 137 if (!clk_freq) 138 return -EINVAL; 139 140 priv->div = clk_freq / VISCONTI_WDT_FREQ; 141 142 /* Initialize struct watchdog_device. */ 143 wdev = &priv->wdev; 144 wdev->info = &visconti_wdt_info; 145 wdev->ops = &visconti_wdt_ops; 146 wdev->parent = dev; 147 wdev->min_timeout = 1; 148 wdev->max_timeout = 0xffffffff / VISCONTI_WDT_FREQ; 149 wdev->timeout = min(wdev->max_timeout, WDT_DEFAULT_TIMEOUT); 150 151 watchdog_set_drvdata(wdev, priv); 152 watchdog_set_nowayout(wdev, nowayout); 153 watchdog_stop_on_unregister(wdev); 154 155 /* This overrides the default timeout only if DT configuration was found */ 156 ret = watchdog_init_timeout(wdev, 0, dev); 157 if (ret) 158 dev_warn(dev, "Specified timeout value invalid, using default\n"); 159 160 return devm_watchdog_register_device(dev, wdev); 161 } 162 163 static const struct of_device_id visconti_wdt_of_match[] = { 164 { .compatible = "toshiba,visconti-wdt", }, 165 {} 166 }; 167 MODULE_DEVICE_TABLE(of, visconti_wdt_of_match); 168 169 static struct platform_driver visconti_wdt_driver = { 170 .driver = { 171 .name = "visconti_wdt", 172 .of_match_table = visconti_wdt_of_match, 173 }, 174 .probe = visconti_wdt_probe, 175 }; 176 module_platform_driver(visconti_wdt_driver); 177 178 MODULE_DESCRIPTION("TOSHIBA Visconti Watchdog Driver"); 179 MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp"); 180 MODULE_LICENSE("GPL v2"); 181