1*a636cd6cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2aae03dc9SOleksij Rempel /*
3aae03dc9SOleksij Rempel * Watchdog driver for Alphascale ASM9260.
4aae03dc9SOleksij Rempel *
5aae03dc9SOleksij Rempel * Copyright (c) 2014 Oleksij Rempel <linux@rempel-privat.de>
6aae03dc9SOleksij Rempel */
7aae03dc9SOleksij Rempel
8aae03dc9SOleksij Rempel #include <linux/bitops.h>
9aae03dc9SOleksij Rempel #include <linux/clk.h>
10aae03dc9SOleksij Rempel #include <linux/delay.h>
11aae03dc9SOleksij Rempel #include <linux/interrupt.h>
12aae03dc9SOleksij Rempel #include <linux/io.h>
13aae03dc9SOleksij Rempel #include <linux/module.h>
14aae03dc9SOleksij Rempel #include <linux/of.h>
15aae03dc9SOleksij Rempel #include <linux/platform_device.h>
16aae03dc9SOleksij Rempel #include <linux/reset.h>
17aae03dc9SOleksij Rempel #include <linux/watchdog.h>
18aae03dc9SOleksij Rempel
19aae03dc9SOleksij Rempel #define CLOCK_FREQ 1000000
20aae03dc9SOleksij Rempel
21aae03dc9SOleksij Rempel /* Watchdog Mode register */
22aae03dc9SOleksij Rempel #define HW_WDMOD 0x00
23aae03dc9SOleksij Rempel /* Wake interrupt. Set by HW, can't be cleared. */
24aae03dc9SOleksij Rempel #define BM_MOD_WDINT BIT(3)
25aae03dc9SOleksij Rempel /* This bit set if timeout reached. Cleared by SW. */
26aae03dc9SOleksij Rempel #define BM_MOD_WDTOF BIT(2)
27aae03dc9SOleksij Rempel /* HW Reset on timeout */
28aae03dc9SOleksij Rempel #define BM_MOD_WDRESET BIT(1)
29aae03dc9SOleksij Rempel /* WD enable */
30aae03dc9SOleksij Rempel #define BM_MOD_WDEN BIT(0)
31aae03dc9SOleksij Rempel
32aae03dc9SOleksij Rempel /*
33aae03dc9SOleksij Rempel * Watchdog Timer Constant register
34aae03dc9SOleksij Rempel * Minimal value is 0xff, the meaning of this value
35aae03dc9SOleksij Rempel * depends on used clock: T = WDCLK * (0xff + 1) * 4
36aae03dc9SOleksij Rempel */
37aae03dc9SOleksij Rempel #define HW_WDTC 0x04
38aae03dc9SOleksij Rempel #define BM_WDTC_MAX(freq) (0x7fffffff / (freq))
39aae03dc9SOleksij Rempel
40aae03dc9SOleksij Rempel /* Watchdog Feed register */
41aae03dc9SOleksij Rempel #define HW_WDFEED 0x08
42aae03dc9SOleksij Rempel
43aae03dc9SOleksij Rempel /* Watchdog Timer Value register */
44aae03dc9SOleksij Rempel #define HW_WDTV 0x0c
45aae03dc9SOleksij Rempel
46aae03dc9SOleksij Rempel #define ASM9260_WDT_DEFAULT_TIMEOUT 30
47aae03dc9SOleksij Rempel
48aae03dc9SOleksij Rempel enum asm9260_wdt_mode {
49aae03dc9SOleksij Rempel HW_RESET,
50aae03dc9SOleksij Rempel SW_RESET,
51aae03dc9SOleksij Rempel DEBUG,
52aae03dc9SOleksij Rempel };
53aae03dc9SOleksij Rempel
54aae03dc9SOleksij Rempel struct asm9260_wdt_priv {
55aae03dc9SOleksij Rempel struct device *dev;
56aae03dc9SOleksij Rempel struct watchdog_device wdd;
57aae03dc9SOleksij Rempel struct clk *clk;
58aae03dc9SOleksij Rempel struct clk *clk_ahb;
59aae03dc9SOleksij Rempel struct reset_control *rst;
60aae03dc9SOleksij Rempel
61aae03dc9SOleksij Rempel void __iomem *iobase;
62aae03dc9SOleksij Rempel int irq;
63aae03dc9SOleksij Rempel unsigned long wdt_freq;
64aae03dc9SOleksij Rempel enum asm9260_wdt_mode mode;
65aae03dc9SOleksij Rempel };
66aae03dc9SOleksij Rempel
asm9260_wdt_feed(struct watchdog_device * wdd)67aae03dc9SOleksij Rempel static int asm9260_wdt_feed(struct watchdog_device *wdd)
68aae03dc9SOleksij Rempel {
69aae03dc9SOleksij Rempel struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd);
70aae03dc9SOleksij Rempel
71aae03dc9SOleksij Rempel iowrite32(0xaa, priv->iobase + HW_WDFEED);
72aae03dc9SOleksij Rempel iowrite32(0x55, priv->iobase + HW_WDFEED);
73aae03dc9SOleksij Rempel
74aae03dc9SOleksij Rempel return 0;
75aae03dc9SOleksij Rempel }
76aae03dc9SOleksij Rempel
asm9260_wdt_gettimeleft(struct watchdog_device * wdd)77aae03dc9SOleksij Rempel static unsigned int asm9260_wdt_gettimeleft(struct watchdog_device *wdd)
78aae03dc9SOleksij Rempel {
79aae03dc9SOleksij Rempel struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd);
80aae03dc9SOleksij Rempel u32 counter;
81aae03dc9SOleksij Rempel
82aae03dc9SOleksij Rempel counter = ioread32(priv->iobase + HW_WDTV);
83aae03dc9SOleksij Rempel
84d94fa465SWolfram Sang return counter / priv->wdt_freq;
85aae03dc9SOleksij Rempel }
86aae03dc9SOleksij Rempel
asm9260_wdt_updatetimeout(struct watchdog_device * wdd)87aae03dc9SOleksij Rempel static int asm9260_wdt_updatetimeout(struct watchdog_device *wdd)
88aae03dc9SOleksij Rempel {
89aae03dc9SOleksij Rempel struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd);
90aae03dc9SOleksij Rempel u32 counter;
91aae03dc9SOleksij Rempel
92aae03dc9SOleksij Rempel counter = wdd->timeout * priv->wdt_freq;
93aae03dc9SOleksij Rempel
94aae03dc9SOleksij Rempel iowrite32(counter, priv->iobase + HW_WDTC);
95aae03dc9SOleksij Rempel
96aae03dc9SOleksij Rempel return 0;
97aae03dc9SOleksij Rempel }
98aae03dc9SOleksij Rempel
asm9260_wdt_enable(struct watchdog_device * wdd)99aae03dc9SOleksij Rempel static int asm9260_wdt_enable(struct watchdog_device *wdd)
100aae03dc9SOleksij Rempel {
101aae03dc9SOleksij Rempel struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd);
102aae03dc9SOleksij Rempel u32 mode = 0;
103aae03dc9SOleksij Rempel
104aae03dc9SOleksij Rempel if (priv->mode == HW_RESET)
105aae03dc9SOleksij Rempel mode = BM_MOD_WDRESET;
106aae03dc9SOleksij Rempel
107aae03dc9SOleksij Rempel iowrite32(BM_MOD_WDEN | mode, priv->iobase + HW_WDMOD);
108aae03dc9SOleksij Rempel
109aae03dc9SOleksij Rempel asm9260_wdt_updatetimeout(wdd);
110aae03dc9SOleksij Rempel
111aae03dc9SOleksij Rempel asm9260_wdt_feed(wdd);
112aae03dc9SOleksij Rempel
113aae03dc9SOleksij Rempel return 0;
114aae03dc9SOleksij Rempel }
115aae03dc9SOleksij Rempel
asm9260_wdt_disable(struct watchdog_device * wdd)116aae03dc9SOleksij Rempel static int asm9260_wdt_disable(struct watchdog_device *wdd)
117aae03dc9SOleksij Rempel {
118aae03dc9SOleksij Rempel struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd);
119aae03dc9SOleksij Rempel
120aae03dc9SOleksij Rempel /* The only way to disable WD is to reset it. */
121aae03dc9SOleksij Rempel reset_control_assert(priv->rst);
122aae03dc9SOleksij Rempel reset_control_deassert(priv->rst);
123aae03dc9SOleksij Rempel
124aae03dc9SOleksij Rempel return 0;
125aae03dc9SOleksij Rempel }
126aae03dc9SOleksij Rempel
asm9260_wdt_settimeout(struct watchdog_device * wdd,unsigned int to)127aae03dc9SOleksij Rempel static int asm9260_wdt_settimeout(struct watchdog_device *wdd, unsigned int to)
128aae03dc9SOleksij Rempel {
129aae03dc9SOleksij Rempel wdd->timeout = to;
130aae03dc9SOleksij Rempel asm9260_wdt_updatetimeout(wdd);
131aae03dc9SOleksij Rempel
132aae03dc9SOleksij Rempel return 0;
133aae03dc9SOleksij Rempel }
134aae03dc9SOleksij Rempel
asm9260_wdt_sys_reset(struct asm9260_wdt_priv * priv)135aae03dc9SOleksij Rempel static void asm9260_wdt_sys_reset(struct asm9260_wdt_priv *priv)
136aae03dc9SOleksij Rempel {
137aae03dc9SOleksij Rempel /* init WD if it was not started */
138aae03dc9SOleksij Rempel
139aae03dc9SOleksij Rempel iowrite32(BM_MOD_WDEN | BM_MOD_WDRESET, priv->iobase + HW_WDMOD);
140aae03dc9SOleksij Rempel
141aae03dc9SOleksij Rempel iowrite32(0xff, priv->iobase + HW_WDTC);
142aae03dc9SOleksij Rempel /* first pass correct sequence */
143aae03dc9SOleksij Rempel asm9260_wdt_feed(&priv->wdd);
144aae03dc9SOleksij Rempel /*
145aae03dc9SOleksij Rempel * Then write wrong pattern to the feed to trigger reset
146aae03dc9SOleksij Rempel * ASAP.
147aae03dc9SOleksij Rempel */
148aae03dc9SOleksij Rempel iowrite32(0xff, priv->iobase + HW_WDFEED);
149aae03dc9SOleksij Rempel
150aae03dc9SOleksij Rempel mdelay(1000);
151aae03dc9SOleksij Rempel }
152aae03dc9SOleksij Rempel
asm9260_wdt_irq(int irq,void * devid)153aae03dc9SOleksij Rempel static irqreturn_t asm9260_wdt_irq(int irq, void *devid)
154aae03dc9SOleksij Rempel {
155aae03dc9SOleksij Rempel struct asm9260_wdt_priv *priv = devid;
156aae03dc9SOleksij Rempel u32 stat;
157aae03dc9SOleksij Rempel
158aae03dc9SOleksij Rempel stat = ioread32(priv->iobase + HW_WDMOD);
159aae03dc9SOleksij Rempel if (!(stat & BM_MOD_WDINT))
160aae03dc9SOleksij Rempel return IRQ_NONE;
161aae03dc9SOleksij Rempel
162aae03dc9SOleksij Rempel if (priv->mode == DEBUG) {
163aae03dc9SOleksij Rempel dev_info(priv->dev, "Watchdog Timeout. Do nothing.\n");
164aae03dc9SOleksij Rempel } else {
165aae03dc9SOleksij Rempel dev_info(priv->dev, "Watchdog Timeout. Doing SW Reset.\n");
166aae03dc9SOleksij Rempel asm9260_wdt_sys_reset(priv);
167aae03dc9SOleksij Rempel }
168aae03dc9SOleksij Rempel
169aae03dc9SOleksij Rempel return IRQ_HANDLED;
170aae03dc9SOleksij Rempel }
171aae03dc9SOleksij Rempel
asm9260_restart(struct watchdog_device * wdd,unsigned long action,void * data)17255dbe8f3SGuenter Roeck static int asm9260_restart(struct watchdog_device *wdd, unsigned long action,
17355dbe8f3SGuenter Roeck void *data)
174aae03dc9SOleksij Rempel {
17555dbe8f3SGuenter Roeck struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd);
176aae03dc9SOleksij Rempel
177aae03dc9SOleksij Rempel asm9260_wdt_sys_reset(priv);
178aae03dc9SOleksij Rempel
17955dbe8f3SGuenter Roeck return 0;
180aae03dc9SOleksij Rempel }
181aae03dc9SOleksij Rempel
182aae03dc9SOleksij Rempel static const struct watchdog_info asm9260_wdt_ident = {
183aae03dc9SOleksij Rempel .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING
184aae03dc9SOleksij Rempel | WDIOF_MAGICCLOSE,
185aae03dc9SOleksij Rempel .identity = "Alphascale asm9260 Watchdog",
186aae03dc9SOleksij Rempel };
187aae03dc9SOleksij Rempel
188b893e344SBhumika Goyal static const struct watchdog_ops asm9260_wdt_ops = {
189aae03dc9SOleksij Rempel .owner = THIS_MODULE,
190aae03dc9SOleksij Rempel .start = asm9260_wdt_enable,
191aae03dc9SOleksij Rempel .stop = asm9260_wdt_disable,
192aae03dc9SOleksij Rempel .get_timeleft = asm9260_wdt_gettimeleft,
193aae03dc9SOleksij Rempel .ping = asm9260_wdt_feed,
194aae03dc9SOleksij Rempel .set_timeout = asm9260_wdt_settimeout,
19555dbe8f3SGuenter Roeck .restart = asm9260_restart,
196aae03dc9SOleksij Rempel };
197aae03dc9SOleksij Rempel
asm9260_clk_disable_unprepare(void * data)198f57df835SGuenter Roeck static void asm9260_clk_disable_unprepare(void *data)
199f57df835SGuenter Roeck {
200f57df835SGuenter Roeck clk_disable_unprepare(data);
201f57df835SGuenter Roeck }
202f57df835SGuenter Roeck
asm9260_wdt_get_dt_clks(struct asm9260_wdt_priv * priv)203ac36856fSArnd Bergmann static int asm9260_wdt_get_dt_clks(struct asm9260_wdt_priv *priv)
204aae03dc9SOleksij Rempel {
205aae03dc9SOleksij Rempel int err;
206aae03dc9SOleksij Rempel unsigned long clk;
207aae03dc9SOleksij Rempel
208aae03dc9SOleksij Rempel priv->clk = devm_clk_get(priv->dev, "mod");
209aae03dc9SOleksij Rempel if (IS_ERR(priv->clk)) {
210aae03dc9SOleksij Rempel dev_err(priv->dev, "Failed to get \"mod\" clk\n");
211aae03dc9SOleksij Rempel return PTR_ERR(priv->clk);
212aae03dc9SOleksij Rempel }
213aae03dc9SOleksij Rempel
214aae03dc9SOleksij Rempel /* configure AHB clock */
215aae03dc9SOleksij Rempel priv->clk_ahb = devm_clk_get(priv->dev, "ahb");
216aae03dc9SOleksij Rempel if (IS_ERR(priv->clk_ahb)) {
217aae03dc9SOleksij Rempel dev_err(priv->dev, "Failed to get \"ahb\" clk\n");
218aae03dc9SOleksij Rempel return PTR_ERR(priv->clk_ahb);
219aae03dc9SOleksij Rempel }
220aae03dc9SOleksij Rempel
221aae03dc9SOleksij Rempel err = clk_prepare_enable(priv->clk_ahb);
222aae03dc9SOleksij Rempel if (err) {
223aae03dc9SOleksij Rempel dev_err(priv->dev, "Failed to enable ahb_clk!\n");
224aae03dc9SOleksij Rempel return err;
225aae03dc9SOleksij Rempel }
226f57df835SGuenter Roeck err = devm_add_action_or_reset(priv->dev,
227f57df835SGuenter Roeck asm9260_clk_disable_unprepare,
228f57df835SGuenter Roeck priv->clk_ahb);
229f57df835SGuenter Roeck if (err)
230f57df835SGuenter Roeck return err;
231aae03dc9SOleksij Rempel
232aae03dc9SOleksij Rempel err = clk_set_rate(priv->clk, CLOCK_FREQ);
233aae03dc9SOleksij Rempel if (err) {
234aae03dc9SOleksij Rempel dev_err(priv->dev, "Failed to set rate!\n");
235aae03dc9SOleksij Rempel return err;
236aae03dc9SOleksij Rempel }
237aae03dc9SOleksij Rempel
238aae03dc9SOleksij Rempel err = clk_prepare_enable(priv->clk);
239aae03dc9SOleksij Rempel if (err) {
240aae03dc9SOleksij Rempel dev_err(priv->dev, "Failed to enable clk!\n");
241aae03dc9SOleksij Rempel return err;
242aae03dc9SOleksij Rempel }
243f57df835SGuenter Roeck err = devm_add_action_or_reset(priv->dev,
244f57df835SGuenter Roeck asm9260_clk_disable_unprepare,
245f57df835SGuenter Roeck priv->clk);
246f57df835SGuenter Roeck if (err)
247f57df835SGuenter Roeck return err;
248aae03dc9SOleksij Rempel
249aae03dc9SOleksij Rempel /* wdt has internal divider */
250aae03dc9SOleksij Rempel clk = clk_get_rate(priv->clk);
251aae03dc9SOleksij Rempel if (!clk) {
252aae03dc9SOleksij Rempel dev_err(priv->dev, "Failed, clk is 0!\n");
253aae03dc9SOleksij Rempel return -EINVAL;
254aae03dc9SOleksij Rempel }
255aae03dc9SOleksij Rempel
256aae03dc9SOleksij Rempel priv->wdt_freq = clk / 2;
257aae03dc9SOleksij Rempel
258aae03dc9SOleksij Rempel return 0;
259aae03dc9SOleksij Rempel }
260aae03dc9SOleksij Rempel
asm9260_wdt_get_dt_mode(struct asm9260_wdt_priv * priv)261ac36856fSArnd Bergmann static void asm9260_wdt_get_dt_mode(struct asm9260_wdt_priv *priv)
262aae03dc9SOleksij Rempel {
263aae03dc9SOleksij Rempel const char *tmp;
264aae03dc9SOleksij Rempel int ret;
265aae03dc9SOleksij Rempel
266aae03dc9SOleksij Rempel /* default mode */
267aae03dc9SOleksij Rempel priv->mode = HW_RESET;
268aae03dc9SOleksij Rempel
269aae03dc9SOleksij Rempel ret = of_property_read_string(priv->dev->of_node,
270aae03dc9SOleksij Rempel "alphascale,mode", &tmp);
271aae03dc9SOleksij Rempel if (ret < 0)
272aae03dc9SOleksij Rempel return;
273aae03dc9SOleksij Rempel
274aae03dc9SOleksij Rempel if (!strcmp(tmp, "hw"))
275aae03dc9SOleksij Rempel priv->mode = HW_RESET;
276aae03dc9SOleksij Rempel else if (!strcmp(tmp, "sw"))
277aae03dc9SOleksij Rempel priv->mode = SW_RESET;
278aae03dc9SOleksij Rempel else if (!strcmp(tmp, "debug"))
279aae03dc9SOleksij Rempel priv->mode = DEBUG;
280aae03dc9SOleksij Rempel else
281aae03dc9SOleksij Rempel dev_warn(priv->dev, "unknown reset-type: %s. Using default \"hw\" mode.",
282aae03dc9SOleksij Rempel tmp);
283aae03dc9SOleksij Rempel }
284aae03dc9SOleksij Rempel
asm9260_wdt_probe(struct platform_device * pdev)285ac36856fSArnd Bergmann static int asm9260_wdt_probe(struct platform_device *pdev)
286aae03dc9SOleksij Rempel {
287f57df835SGuenter Roeck struct device *dev = &pdev->dev;
288aae03dc9SOleksij Rempel struct asm9260_wdt_priv *priv;
289aae03dc9SOleksij Rempel struct watchdog_device *wdd;
290aae03dc9SOleksij Rempel int ret;
291b1bbb0cbSColin Ian King static const char * const mode_name[] = { "hw", "sw", "debug", };
292aae03dc9SOleksij Rempel
293f57df835SGuenter Roeck priv = devm_kzalloc(dev, sizeof(struct asm9260_wdt_priv), GFP_KERNEL);
294aae03dc9SOleksij Rempel if (!priv)
295aae03dc9SOleksij Rempel return -ENOMEM;
296aae03dc9SOleksij Rempel
297f57df835SGuenter Roeck priv->dev = dev;
298aae03dc9SOleksij Rempel
2990f0a6a28SGuenter Roeck priv->iobase = devm_platform_ioremap_resource(pdev, 0);
300aae03dc9SOleksij Rempel if (IS_ERR(priv->iobase))
301aae03dc9SOleksij Rempel return PTR_ERR(priv->iobase);
302aae03dc9SOleksij Rempel
303f57df835SGuenter Roeck priv->rst = devm_reset_control_get_exclusive(dev, "wdt_rst");
304aae03dc9SOleksij Rempel if (IS_ERR(priv->rst))
305aae03dc9SOleksij Rempel return PTR_ERR(priv->rst);
306aae03dc9SOleksij Rempel
3073c829f47SAlexey Khoroshilov ret = asm9260_wdt_get_dt_clks(priv);
3083c829f47SAlexey Khoroshilov if (ret)
3093c829f47SAlexey Khoroshilov return ret;
3103c829f47SAlexey Khoroshilov
311aae03dc9SOleksij Rempel wdd = &priv->wdd;
312aae03dc9SOleksij Rempel wdd->info = &asm9260_wdt_ident;
313aae03dc9SOleksij Rempel wdd->ops = &asm9260_wdt_ops;
314aae03dc9SOleksij Rempel wdd->min_timeout = 1;
315aae03dc9SOleksij Rempel wdd->max_timeout = BM_WDTC_MAX(priv->wdt_freq);
316f57df835SGuenter Roeck wdd->parent = dev;
317aae03dc9SOleksij Rempel
318aae03dc9SOleksij Rempel watchdog_set_drvdata(wdd, priv);
319aae03dc9SOleksij Rempel
320aae03dc9SOleksij Rempel /*
321aae03dc9SOleksij Rempel * If 'timeout-sec' unspecified in devicetree, assume a 30 second
322aae03dc9SOleksij Rempel * default, unless the max timeout is less than 30 seconds, then use
323aae03dc9SOleksij Rempel * the max instead.
324aae03dc9SOleksij Rempel */
325aae03dc9SOleksij Rempel wdd->timeout = ASM9260_WDT_DEFAULT_TIMEOUT;
326f57df835SGuenter Roeck watchdog_init_timeout(wdd, 0, dev);
327aae03dc9SOleksij Rempel
328aae03dc9SOleksij Rempel asm9260_wdt_get_dt_mode(priv);
329aae03dc9SOleksij Rempel
330aae03dc9SOleksij Rempel if (priv->mode != HW_RESET)
331aae03dc9SOleksij Rempel priv->irq = platform_get_irq(pdev, 0);
332aae03dc9SOleksij Rempel
333aae03dc9SOleksij Rempel if (priv->irq > 0) {
334aae03dc9SOleksij Rempel /*
335aae03dc9SOleksij Rempel * Not all supported platforms specify an interrupt for the
336aae03dc9SOleksij Rempel * watchdog, so let's make it optional.
337aae03dc9SOleksij Rempel */
338f57df835SGuenter Roeck ret = devm_request_irq(dev, priv->irq, asm9260_wdt_irq, 0,
339f57df835SGuenter Roeck pdev->name, priv);
340aae03dc9SOleksij Rempel if (ret < 0)
341f57df835SGuenter Roeck dev_warn(dev, "failed to request IRQ\n");
342aae03dc9SOleksij Rempel }
343aae03dc9SOleksij Rempel
34455dbe8f3SGuenter Roeck watchdog_set_restart_priority(wdd, 128);
34555dbe8f3SGuenter Roeck
346f57df835SGuenter Roeck watchdog_stop_on_reboot(wdd);
347f57df835SGuenter Roeck watchdog_stop_on_unregister(wdd);
348f57df835SGuenter Roeck ret = devm_watchdog_register_device(dev, wdd);
349aae03dc9SOleksij Rempel if (ret)
350f57df835SGuenter Roeck return ret;
351aae03dc9SOleksij Rempel
352aae03dc9SOleksij Rempel platform_set_drvdata(pdev, priv);
353aae03dc9SOleksij Rempel
354f57df835SGuenter Roeck dev_info(dev, "Watchdog enabled (timeout: %d sec, mode: %s)\n",
355aae03dc9SOleksij Rempel wdd->timeout, mode_name[priv->mode]);
356aae03dc9SOleksij Rempel return 0;
357aae03dc9SOleksij Rempel }
358aae03dc9SOleksij Rempel
359aae03dc9SOleksij Rempel static const struct of_device_id asm9260_wdt_of_match[] = {
360aae03dc9SOleksij Rempel { .compatible = "alphascale,asm9260-wdt"},
361aae03dc9SOleksij Rempel {},
362aae03dc9SOleksij Rempel };
363aae03dc9SOleksij Rempel MODULE_DEVICE_TABLE(of, asm9260_wdt_of_match);
364aae03dc9SOleksij Rempel
365aae03dc9SOleksij Rempel static struct platform_driver asm9260_wdt_driver = {
366aae03dc9SOleksij Rempel .driver = {
367aae03dc9SOleksij Rempel .name = "asm9260-wdt",
368aae03dc9SOleksij Rempel .of_match_table = asm9260_wdt_of_match,
369aae03dc9SOleksij Rempel },
370aae03dc9SOleksij Rempel .probe = asm9260_wdt_probe,
371aae03dc9SOleksij Rempel };
372aae03dc9SOleksij Rempel module_platform_driver(asm9260_wdt_driver);
373aae03dc9SOleksij Rempel
374aae03dc9SOleksij Rempel MODULE_DESCRIPTION("asm9260 WatchDog Timer Driver");
375aae03dc9SOleksij Rempel MODULE_AUTHOR("Oleksij Rempel <linux@rempel-privat.de>");
376aae03dc9SOleksij Rempel MODULE_LICENSE("GPL");
377