xref: /linux/drivers/watchdog/npcm_wdt.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2018 Nuvoton Technology corporation.
3 // Copyright (c) 2018 IBM Corp.
4 
5 #include <linux/bitops.h>
6 #include <linux/clk.h>
7 #include <linux/delay.h>
8 #include <linux/interrupt.h>
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/of_irq.h>
12 #include <linux/platform_device.h>
13 #include <linux/slab.h>
14 #include <linux/watchdog.h>
15 
16 #define NPCM_WTCR	0x1C
17 
18 #define NPCM_WTCLK	(BIT(10) | BIT(11))	/* Clock divider */
19 #define NPCM_WTE	BIT(7)			/* Enable */
20 #define NPCM_WTIE	BIT(6)			/* Enable irq */
21 #define NPCM_WTIS	(BIT(4) | BIT(5))	/* Interval selection */
22 #define NPCM_WTIF	BIT(3)			/* Interrupt flag*/
23 #define NPCM_WTRF	BIT(2)			/* Reset flag */
24 #define NPCM_WTRE	BIT(1)			/* Reset enable */
25 #define NPCM_WTR	BIT(0)			/* Reset counter */
26 
27 /*
28  * Watchdog timeouts
29  *
30  * 170     msec:    WTCLK=01 WTIS=00     VAL= 0x400
31  * 670     msec:    WTCLK=01 WTIS=01     VAL= 0x410
32  * 1360    msec:    WTCLK=10 WTIS=00     VAL= 0x800
33  * 2700    msec:    WTCLK=01 WTIS=10     VAL= 0x420
34  * 5360    msec:    WTCLK=10 WTIS=01     VAL= 0x810
35  * 10700   msec:    WTCLK=01 WTIS=11     VAL= 0x430
36  * 21600   msec:    WTCLK=10 WTIS=10     VAL= 0x820
37  * 43000   msec:    WTCLK=11 WTIS=00     VAL= 0xC00
38  * 85600   msec:    WTCLK=10 WTIS=11     VAL= 0x830
39  * 172000  msec:    WTCLK=11 WTIS=01     VAL= 0xC10
40  * 687000  msec:    WTCLK=11 WTIS=10     VAL= 0xC20
41  * 2750000 msec:    WTCLK=11 WTIS=11     VAL= 0xC30
42  */
43 
44 struct npcm_wdt {
45 	struct watchdog_device  wdd;
46 	void __iomem		*reg;
47 	struct clk		*clk;
48 };
49 
to_npcm_wdt(struct watchdog_device * wdd)50 static inline struct npcm_wdt *to_npcm_wdt(struct watchdog_device *wdd)
51 {
52 	return container_of(wdd, struct npcm_wdt, wdd);
53 }
54 
npcm_wdt_ping(struct watchdog_device * wdd)55 static int npcm_wdt_ping(struct watchdog_device *wdd)
56 {
57 	struct npcm_wdt *wdt = to_npcm_wdt(wdd);
58 	u32 val;
59 
60 	val = readl(wdt->reg);
61 	writel(val | NPCM_WTR, wdt->reg);
62 
63 	return 0;
64 }
65 
npcm_wdt_start(struct watchdog_device * wdd)66 static int npcm_wdt_start(struct watchdog_device *wdd)
67 {
68 	struct npcm_wdt *wdt = to_npcm_wdt(wdd);
69 	u32 val;
70 
71 	if (wdt->clk)
72 		clk_prepare_enable(wdt->clk);
73 
74 	if (wdd->timeout < 2)
75 		val = 0x800;
76 	else if (wdd->timeout < 3)
77 		val = 0x420;
78 	else if (wdd->timeout < 6)
79 		val = 0x810;
80 	else if (wdd->timeout < 11)
81 		val = 0x430;
82 	else if (wdd->timeout < 22)
83 		val = 0x820;
84 	else if (wdd->timeout < 44)
85 		val = 0xC00;
86 	else if (wdd->timeout < 87)
87 		val = 0x830;
88 	else if (wdd->timeout < 173)
89 		val = 0xC10;
90 	else if (wdd->timeout < 688)
91 		val = 0xC20;
92 	else
93 		val = 0xC30;
94 
95 	val |= NPCM_WTRE | NPCM_WTE | NPCM_WTR | NPCM_WTIE;
96 
97 	writel(val, wdt->reg);
98 
99 	return 0;
100 }
101 
npcm_wdt_stop(struct watchdog_device * wdd)102 static int npcm_wdt_stop(struct watchdog_device *wdd)
103 {
104 	struct npcm_wdt *wdt = to_npcm_wdt(wdd);
105 
106 	writel(0, wdt->reg);
107 
108 	if (wdt->clk)
109 		clk_disable_unprepare(wdt->clk);
110 
111 	return 0;
112 }
113 
npcm_wdt_set_timeout(struct watchdog_device * wdd,unsigned int timeout)114 static int npcm_wdt_set_timeout(struct watchdog_device *wdd,
115 				unsigned int timeout)
116 {
117 	if (timeout < 2)
118 		wdd->timeout = 1;
119 	else if (timeout < 3)
120 		wdd->timeout = 2;
121 	else if (timeout < 6)
122 		wdd->timeout = 5;
123 	else if (timeout < 11)
124 		wdd->timeout = 10;
125 	else if (timeout < 22)
126 		wdd->timeout = 21;
127 	else if (timeout < 44)
128 		wdd->timeout = 43;
129 	else if (timeout < 87)
130 		wdd->timeout = 86;
131 	else if (timeout < 173)
132 		wdd->timeout = 172;
133 	else if (timeout < 688)
134 		wdd->timeout = 687;
135 	else
136 		wdd->timeout = 2750;
137 
138 	if (watchdog_active(wdd))
139 		npcm_wdt_start(wdd);
140 
141 	return 0;
142 }
143 
npcm_wdt_interrupt(int irq,void * data)144 static irqreturn_t npcm_wdt_interrupt(int irq, void *data)
145 {
146 	struct npcm_wdt *wdt = data;
147 
148 	watchdog_notify_pretimeout(&wdt->wdd);
149 
150 	return IRQ_HANDLED;
151 }
152 
npcm_wdt_restart(struct watchdog_device * wdd,unsigned long action,void * data)153 static int npcm_wdt_restart(struct watchdog_device *wdd,
154 			    unsigned long action, void *data)
155 {
156 	struct npcm_wdt *wdt = to_npcm_wdt(wdd);
157 
158 	/* For reset, we start the WDT clock and leave it running. */
159 	if (wdt->clk)
160 		clk_prepare_enable(wdt->clk);
161 
162 	writel(NPCM_WTR | NPCM_WTRE | NPCM_WTE, wdt->reg);
163 	udelay(1000);
164 
165 	return 0;
166 }
167 
npcm_is_running(struct watchdog_device * wdd)168 static bool npcm_is_running(struct watchdog_device *wdd)
169 {
170 	struct npcm_wdt *wdt = to_npcm_wdt(wdd);
171 
172 	return readl(wdt->reg) & NPCM_WTE;
173 }
174 
175 static const struct watchdog_info npcm_wdt_info = {
176 	.identity	= KBUILD_MODNAME,
177 	.options	= WDIOF_SETTIMEOUT
178 			| WDIOF_KEEPALIVEPING
179 			| WDIOF_MAGICCLOSE,
180 };
181 
182 static const struct watchdog_ops npcm_wdt_ops = {
183 	.owner = THIS_MODULE,
184 	.start = npcm_wdt_start,
185 	.stop = npcm_wdt_stop,
186 	.ping = npcm_wdt_ping,
187 	.set_timeout = npcm_wdt_set_timeout,
188 	.restart = npcm_wdt_restart,
189 };
190 
npcm_wdt_probe(struct platform_device * pdev)191 static int npcm_wdt_probe(struct platform_device *pdev)
192 {
193 	struct device *dev = &pdev->dev;
194 	struct npcm_wdt *wdt;
195 	int irq;
196 	int ret;
197 
198 	wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
199 	if (!wdt)
200 		return -ENOMEM;
201 
202 	wdt->reg = devm_platform_ioremap_resource(pdev, 0);
203 	if (IS_ERR(wdt->reg))
204 		return PTR_ERR(wdt->reg);
205 
206 	wdt->clk = devm_clk_get_optional(&pdev->dev, NULL);
207 	if (IS_ERR(wdt->clk))
208 		return PTR_ERR(wdt->clk);
209 
210 	irq = platform_get_irq(pdev, 0);
211 	if (irq < 0)
212 		return irq;
213 
214 	wdt->wdd.info = &npcm_wdt_info;
215 	wdt->wdd.ops = &npcm_wdt_ops;
216 	wdt->wdd.min_timeout = 1;
217 	wdt->wdd.max_timeout = 2750;
218 	wdt->wdd.parent = dev;
219 
220 	wdt->wdd.timeout = 86;
221 	watchdog_init_timeout(&wdt->wdd, 0, dev);
222 
223 	/* Ensure timeout is able to be represented by the hardware */
224 	npcm_wdt_set_timeout(&wdt->wdd, wdt->wdd.timeout);
225 
226 	if (npcm_is_running(&wdt->wdd)) {
227 		/* Restart with the default or device-tree specified timeout */
228 		npcm_wdt_start(&wdt->wdd);
229 		set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
230 	}
231 
232 	ret = devm_request_irq(dev, irq, npcm_wdt_interrupt, 0, "watchdog",
233 			       wdt);
234 	if (ret)
235 		return ret;
236 
237 	ret = devm_watchdog_register_device(dev, &wdt->wdd);
238 	if (ret)
239 		return ret;
240 
241 	dev_info(dev, "NPCM watchdog driver enabled\n");
242 
243 	return 0;
244 }
245 
246 #ifdef CONFIG_OF
247 static const struct of_device_id npcm_wdt_match[] = {
248 	{.compatible = "nuvoton,wpcm450-wdt"},
249 	{.compatible = "nuvoton,npcm750-wdt"},
250 	{},
251 };
252 MODULE_DEVICE_TABLE(of, npcm_wdt_match);
253 #endif
254 
255 static struct platform_driver npcm_wdt_driver = {
256 	.probe		= npcm_wdt_probe,
257 	.driver		= {
258 		.name	= "npcm-wdt",
259 		.of_match_table = of_match_ptr(npcm_wdt_match),
260 	},
261 };
262 module_platform_driver(npcm_wdt_driver);
263 
264 MODULE_AUTHOR("Joel Stanley");
265 MODULE_DESCRIPTION("Watchdog driver for NPCM");
266 MODULE_LICENSE("GPL v2");
267