xref: /openbmc/linux/drivers/watchdog/sp805_wdt.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
13b190545SBing Fan // SPDX-License-Identifier: GPL-2.0+
24a370278SViresh KUMAR /*
34a370278SViresh KUMAR  * drivers/char/watchdog/sp805-wdt.c
44a370278SViresh KUMAR  *
54a370278SViresh KUMAR  * Watchdog driver for ARM SP805 watchdog module
64a370278SViresh KUMAR  *
74a370278SViresh KUMAR  * Copyright (C) 2010 ST Microelectronics
8da89947bSViresh Kumar  * Viresh Kumar <vireshk@kernel.org>
94a370278SViresh KUMAR  *
104a370278SViresh KUMAR  * This file is licensed under the terms of the GNU General Public
114a370278SViresh KUMAR  * License version 2 or later. This program is licensed "as is" without any
124a370278SViresh KUMAR  * warranty of any kind, whether express or implied.
134a370278SViresh KUMAR  */
144a370278SViresh KUMAR 
154a370278SViresh KUMAR #include <linux/device.h>
164a370278SViresh KUMAR #include <linux/resource.h>
174a370278SViresh KUMAR #include <linux/amba/bus.h>
184a370278SViresh KUMAR #include <linux/bitops.h>
194a370278SViresh KUMAR #include <linux/clk.h>
204a370278SViresh KUMAR #include <linux/io.h>
214a370278SViresh KUMAR #include <linux/ioport.h>
224a370278SViresh KUMAR #include <linux/kernel.h>
234a370278SViresh KUMAR #include <linux/math64.h>
244a370278SViresh KUMAR #include <linux/module.h>
254a370278SViresh KUMAR #include <linux/moduleparam.h>
2616ac4abeSViresh Kumar #include <linux/pm.h>
2705f0a994SAndy Shevchenko #include <linux/property.h>
284a370278SViresh KUMAR #include <linux/slab.h>
294a370278SViresh KUMAR #include <linux/spinlock.h>
304a370278SViresh KUMAR #include <linux/types.h>
314a370278SViresh KUMAR #include <linux/watchdog.h>
324a370278SViresh KUMAR 
334a370278SViresh KUMAR /* default timeout in seconds */
344a370278SViresh KUMAR #define DEFAULT_TIMEOUT		60
354a370278SViresh KUMAR 
364a370278SViresh KUMAR #define MODULE_NAME		"sp805-wdt"
374a370278SViresh KUMAR 
384a370278SViresh KUMAR /* watchdog register offsets and masks */
394a370278SViresh KUMAR #define WDTLOAD			0x000
404a370278SViresh KUMAR 	#define LOAD_MIN	0x00000001
414a370278SViresh KUMAR 	#define LOAD_MAX	0xFFFFFFFF
424a370278SViresh KUMAR #define WDTVALUE		0x004
434a370278SViresh KUMAR #define WDTCONTROL		0x008
444a370278SViresh KUMAR 	/* control register masks */
454a370278SViresh KUMAR 	#define	INT_ENABLE	(1 << 0)
464a370278SViresh KUMAR 	#define	RESET_ENABLE	(1 << 1)
47fa5072edSRay Jui 	#define	ENABLE_MASK	(INT_ENABLE | RESET_ENABLE)
484a370278SViresh KUMAR #define WDTINTCLR		0x00C
494a370278SViresh KUMAR #define WDTRIS			0x010
504a370278SViresh KUMAR #define WDTMIS			0x014
514a370278SViresh KUMAR 	#define INT_MASK	(1 << 0)
524a370278SViresh KUMAR #define WDTLOCK			0xC00
534a370278SViresh KUMAR 	#define	UNLOCK		0x1ACCE551
544a370278SViresh KUMAR 	#define	LOCK		0x00000001
554a370278SViresh KUMAR 
564a370278SViresh KUMAR /**
574a370278SViresh KUMAR  * struct sp805_wdt: sp805 wdt device structure
584a516539SViresh Kumar  * @wdd: instance of struct watchdog_device
59bfae14b6SViresh Kumar  * @lock: spin lock protecting dev structure and io access
60bfae14b6SViresh Kumar  * @base: base address of wdt
613452239eSAndy Shevchenko  * @clk: (optional) clock structure of wdt
623452239eSAndy Shevchenko  * @rate: (optional) clock rate when provided via properties
63bfae14b6SViresh Kumar  * @adev: amba device structure of wdt
64bfae14b6SViresh Kumar  * @status: current status of wdt
65bfae14b6SViresh Kumar  * @load_val: load value to be set for current timeout
664a370278SViresh KUMAR  */
674a370278SViresh KUMAR struct sp805_wdt {
684a516539SViresh Kumar 	struct watchdog_device		wdd;
694a370278SViresh KUMAR 	spinlock_t			lock;
704a370278SViresh KUMAR 	void __iomem			*base;
714a370278SViresh KUMAR 	struct clk			*clk;
72dc0e4a3bSSrinath Mannam 	u64				rate;
734a370278SViresh KUMAR 	struct amba_device		*adev;
744a370278SViresh KUMAR 	unsigned int			load_val;
754a370278SViresh KUMAR };
764a370278SViresh KUMAR 
7786a1e189SWim Van Sebroeck static bool nowayout = WATCHDOG_NOWAYOUT;
784a516539SViresh Kumar module_param(nowayout, bool, 0);
794a516539SViresh Kumar MODULE_PARM_DESC(nowayout,
804a516539SViresh Kumar 		"Set to 1 to keep watchdog running after device release");
814a370278SViresh KUMAR 
82fa5072edSRay Jui /* returns true if wdt is running; otherwise returns false */
wdt_is_running(struct watchdog_device * wdd)83fa5072edSRay Jui static bool wdt_is_running(struct watchdog_device *wdd)
84fa5072edSRay Jui {
85fa5072edSRay Jui 	struct sp805_wdt *wdt = watchdog_get_drvdata(wdd);
86fa5072edSRay Jui 	u32 wdtcontrol = readl_relaxed(wdt->base + WDTCONTROL);
87fa5072edSRay Jui 
88fa5072edSRay Jui 	return (wdtcontrol & ENABLE_MASK) == ENABLE_MASK;
89fa5072edSRay Jui }
90fa5072edSRay Jui 
91*097a4a16SJiangshan Yi /* This routine finds load value that will reset system in required timeout */
wdt_setload(struct watchdog_device * wdd,unsigned int timeout)924a516539SViresh Kumar static int wdt_setload(struct watchdog_device *wdd, unsigned int timeout)
934a370278SViresh KUMAR {
944a516539SViresh Kumar 	struct sp805_wdt *wdt = watchdog_get_drvdata(wdd);
954a370278SViresh KUMAR 	u64 load, rate;
964a370278SViresh KUMAR 
97dc0e4a3bSSrinath Mannam 	rate = wdt->rate;
984a370278SViresh KUMAR 
994a370278SViresh KUMAR 	/*
1004a370278SViresh KUMAR 	 * sp805 runs counter with given value twice, after the end of first
1014a370278SViresh KUMAR 	 * counter it gives an interrupt and then starts counter again. If
10225985edcSLucas De Marchi 	 * interrupt already occurred then it resets the system. This is why
1034a370278SViresh KUMAR 	 * load is half of what should be required.
1044a370278SViresh KUMAR 	 */
1054a370278SViresh KUMAR 	load = div_u64(rate, 2) * timeout - 1;
1064a370278SViresh KUMAR 
1074a370278SViresh KUMAR 	load = (load > LOAD_MAX) ? LOAD_MAX : load;
1084a370278SViresh KUMAR 	load = (load < LOAD_MIN) ? LOAD_MIN : load;
1094a370278SViresh KUMAR 
1104a370278SViresh KUMAR 	spin_lock(&wdt->lock);
1114a370278SViresh KUMAR 	wdt->load_val = load;
1124a370278SViresh KUMAR 	/* roundup timeout to closest positive integer value */
113938626d9SViresh Kumar 	wdd->timeout = div_u64((load + 1) * 2 + (rate / 2), rate);
1144a370278SViresh KUMAR 	spin_unlock(&wdt->lock);
1154a516539SViresh Kumar 
1164a516539SViresh Kumar 	return 0;
1174a370278SViresh KUMAR }
1184a370278SViresh KUMAR 
1194a370278SViresh KUMAR /* returns number of seconds left for reset to occur */
wdt_timeleft(struct watchdog_device * wdd)1204a516539SViresh Kumar static unsigned int wdt_timeleft(struct watchdog_device *wdd)
1214a370278SViresh KUMAR {
1224a516539SViresh Kumar 	struct sp805_wdt *wdt = watchdog_get_drvdata(wdd);
123dc0e4a3bSSrinath Mannam 	u64 load;
1244a370278SViresh KUMAR 
1254a370278SViresh KUMAR 	spin_lock(&wdt->lock);
126d2e8919bSViresh Kumar 	load = readl_relaxed(wdt->base + WDTVALUE);
1274a370278SViresh KUMAR 
1284a370278SViresh KUMAR 	/*If the interrupt is inactive then time left is WDTValue + WDTLoad. */
129d2e8919bSViresh Kumar 	if (!(readl_relaxed(wdt->base + WDTRIS) & INT_MASK))
1304a370278SViresh KUMAR 		load += wdt->load_val + 1;
1314a370278SViresh KUMAR 	spin_unlock(&wdt->lock);
1324a370278SViresh KUMAR 
133dc0e4a3bSSrinath Mannam 	return div_u64(load, wdt->rate);
1344a370278SViresh KUMAR }
1354a370278SViresh KUMAR 
1366c5c0d48SJongsung Kim static int
wdt_restart(struct watchdog_device * wdd,unsigned long mode,void * cmd)1376c5c0d48SJongsung Kim wdt_restart(struct watchdog_device *wdd, unsigned long mode, void *cmd)
1386c5c0d48SJongsung Kim {
1396c5c0d48SJongsung Kim 	struct sp805_wdt *wdt = watchdog_get_drvdata(wdd);
1406c5c0d48SJongsung Kim 
141ea104a9eSMichael Walle 	writel_relaxed(UNLOCK, wdt->base + WDTLOCK);
1426c5c0d48SJongsung Kim 	writel_relaxed(0, wdt->base + WDTCONTROL);
1436c5c0d48SJongsung Kim 	writel_relaxed(0, wdt->base + WDTLOAD);
1446c5c0d48SJongsung Kim 	writel_relaxed(INT_ENABLE | RESET_ENABLE, wdt->base + WDTCONTROL);
1456c5c0d48SJongsung Kim 
146ea104a9eSMichael Walle 	/* Flush posted writes. */
147ea104a9eSMichael Walle 	readl_relaxed(wdt->base + WDTLOCK);
148ea104a9eSMichael Walle 
1496c5c0d48SJongsung Kim 	return 0;
1506c5c0d48SJongsung Kim }
1516c5c0d48SJongsung Kim 
wdt_config(struct watchdog_device * wdd,bool ping)1524a516539SViresh Kumar static int wdt_config(struct watchdog_device *wdd, bool ping)
1534a370278SViresh KUMAR {
1544a516539SViresh Kumar 	struct sp805_wdt *wdt = watchdog_get_drvdata(wdd);
1554a516539SViresh Kumar 	int ret;
1564a516539SViresh Kumar 
1574a516539SViresh Kumar 	if (!ping) {
158d9df0ef1SViresh Kumar 
15963fbbc16SJulia Lawall 		ret = clk_prepare_enable(wdt->clk);
1604a516539SViresh Kumar 		if (ret) {
1614a516539SViresh Kumar 			dev_err(&wdt->adev->dev, "clock enable fail");
1624a516539SViresh Kumar 			return ret;
1634a516539SViresh Kumar 		}
1644a516539SViresh Kumar 	}
1654a516539SViresh Kumar 
1664a370278SViresh KUMAR 	spin_lock(&wdt->lock);
1674a370278SViresh KUMAR 
168d2e8919bSViresh Kumar 	writel_relaxed(UNLOCK, wdt->base + WDTLOCK);
169d2e8919bSViresh Kumar 	writel_relaxed(wdt->load_val, wdt->base + WDTLOAD);
170d2e8919bSViresh Kumar 	writel_relaxed(INT_MASK, wdt->base + WDTINTCLR);
17155e07177SSandeep Tripathy 
17255e07177SSandeep Tripathy 	if (!ping)
1734a516539SViresh Kumar 		writel_relaxed(INT_ENABLE | RESET_ENABLE, wdt->base +
1744a516539SViresh Kumar 				WDTCONTROL);
1754a516539SViresh Kumar 
176d2e8919bSViresh Kumar 	writel_relaxed(LOCK, wdt->base + WDTLOCK);
1774a370278SViresh KUMAR 
178081d83a3SNick Bowler 	/* Flush posted writes. */
179d2e8919bSViresh Kumar 	readl_relaxed(wdt->base + WDTLOCK);
1804a370278SViresh KUMAR 	spin_unlock(&wdt->lock);
1814a516539SViresh Kumar 
1824a516539SViresh Kumar 	return 0;
1834a516539SViresh Kumar }
1844a516539SViresh Kumar 
wdt_ping(struct watchdog_device * wdd)1854a516539SViresh Kumar static int wdt_ping(struct watchdog_device *wdd)
1864a516539SViresh Kumar {
1874a516539SViresh Kumar 	return wdt_config(wdd, true);
1884a516539SViresh Kumar }
1894a516539SViresh Kumar 
1904a516539SViresh Kumar /* enables watchdog timers reset */
wdt_enable(struct watchdog_device * wdd)1914a516539SViresh Kumar static int wdt_enable(struct watchdog_device *wdd)
1924a516539SViresh Kumar {
1934a516539SViresh Kumar 	return wdt_config(wdd, false);
1944a370278SViresh KUMAR }
1954a370278SViresh KUMAR 
1964a370278SViresh KUMAR /* disables watchdog timers reset */
wdt_disable(struct watchdog_device * wdd)1974a516539SViresh Kumar static int wdt_disable(struct watchdog_device *wdd)
1984a370278SViresh KUMAR {
1994a516539SViresh Kumar 	struct sp805_wdt *wdt = watchdog_get_drvdata(wdd);
2004a516539SViresh Kumar 
2014a370278SViresh KUMAR 	spin_lock(&wdt->lock);
2024a370278SViresh KUMAR 
203d2e8919bSViresh Kumar 	writel_relaxed(UNLOCK, wdt->base + WDTLOCK);
204d2e8919bSViresh Kumar 	writel_relaxed(0, wdt->base + WDTCONTROL);
205d2e8919bSViresh Kumar 	writel_relaxed(LOCK, wdt->base + WDTLOCK);
2064a370278SViresh KUMAR 
207081d83a3SNick Bowler 	/* Flush posted writes. */
208d2e8919bSViresh Kumar 	readl_relaxed(wdt->base + WDTLOCK);
2094a370278SViresh KUMAR 	spin_unlock(&wdt->lock);
2104a516539SViresh Kumar 
21163fbbc16SJulia Lawall 	clk_disable_unprepare(wdt->clk);
2124a516539SViresh Kumar 
2134a516539SViresh Kumar 	return 0;
2144a370278SViresh KUMAR }
2154a370278SViresh KUMAR 
2164a516539SViresh Kumar static const struct watchdog_info wdt_info = {
2174a370278SViresh KUMAR 	.options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
2184a370278SViresh KUMAR 	.identity = MODULE_NAME,
2194a370278SViresh KUMAR };
2204a370278SViresh KUMAR 
2214a516539SViresh Kumar static const struct watchdog_ops wdt_ops = {
2224a370278SViresh KUMAR 	.owner		= THIS_MODULE,
2234a516539SViresh Kumar 	.start		= wdt_enable,
2244a516539SViresh Kumar 	.stop		= wdt_disable,
2254a516539SViresh Kumar 	.ping		= wdt_ping,
2264a516539SViresh Kumar 	.set_timeout	= wdt_setload,
2274a516539SViresh Kumar 	.get_timeleft	= wdt_timeleft,
2286c5c0d48SJongsung Kim 	.restart	= wdt_restart,
2294a370278SViresh KUMAR };
2304a370278SViresh KUMAR 
2312d991a16SBill Pemberton static int
sp805_wdt_probe(struct amba_device * adev,const struct amba_id * id)232aa25afadSRussell King sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
2334a370278SViresh KUMAR {
2344a516539SViresh Kumar 	struct sp805_wdt *wdt;
23505f0a994SAndy Shevchenko 	u64 rate = 0;
2364a370278SViresh KUMAR 	int ret = 0;
2374a370278SViresh KUMAR 
238fb35a5adSViresh Kumar 	wdt = devm_kzalloc(&adev->dev, sizeof(*wdt), GFP_KERNEL);
2394a370278SViresh KUMAR 	if (!wdt) {
2404a370278SViresh KUMAR 		ret = -ENOMEM;
241fb35a5adSViresh Kumar 		goto err;
242fb35a5adSViresh Kumar 	}
243fb35a5adSViresh Kumar 
2449d11e4f8SJingoo Han 	wdt->base = devm_ioremap_resource(&adev->dev, &adev->res);
2459d11e4f8SJingoo Han 	if (IS_ERR(wdt->base))
2469d11e4f8SJingoo Han 		return PTR_ERR(wdt->base);
2474a370278SViresh KUMAR 
248dc0e4a3bSSrinath Mannam 	/*
24905f0a994SAndy Shevchenko 	 * When driver probe with ACPI device, clock devices
250dc0e4a3bSSrinath Mannam 	 * are not available, so watchdog rate get from
251dc0e4a3bSSrinath Mannam 	 * clock-frequency property given in _DSD object.
252dc0e4a3bSSrinath Mannam 	 */
25305f0a994SAndy Shevchenko 	device_property_read_u64(&adev->dev, "clock-frequency", &rate);
25405f0a994SAndy Shevchenko 
25505f0a994SAndy Shevchenko 	wdt->clk = devm_clk_get_optional(&adev->dev, NULL);
25605f0a994SAndy Shevchenko 	if (IS_ERR(wdt->clk))
25705f0a994SAndy Shevchenko 		return dev_err_probe(&adev->dev, PTR_ERR(wdt->clk), "Clock not found\n");
25805f0a994SAndy Shevchenko 
25905f0a994SAndy Shevchenko 	wdt->rate = clk_get_rate(wdt->clk);
26005f0a994SAndy Shevchenko 	if (!wdt->rate)
26105f0a994SAndy Shevchenko 		wdt->rate = rate;
262dc0e4a3bSSrinath Mannam 	if (!wdt->rate) {
263dc0e4a3bSSrinath Mannam 		dev_err(&adev->dev, "no clock-frequency property\n");
264dc0e4a3bSSrinath Mannam 		return -ENODEV;
265dc0e4a3bSSrinath Mannam 	}
2664a370278SViresh KUMAR 
2674a370278SViresh KUMAR 	wdt->adev = adev;
2684a516539SViresh Kumar 	wdt->wdd.info = &wdt_info;
2694a516539SViresh Kumar 	wdt->wdd.ops = &wdt_ops;
2706551881cSPratyush Anand 	wdt->wdd.parent = &adev->dev;
2714a370278SViresh KUMAR 
2724a516539SViresh Kumar 	spin_lock_init(&wdt->lock);
2734a516539SViresh Kumar 	watchdog_set_nowayout(&wdt->wdd, nowayout);
2744a516539SViresh Kumar 	watchdog_set_drvdata(&wdt->wdd, wdt);
2756c5c0d48SJongsung Kim 	watchdog_set_restart_priority(&wdt->wdd, 128);
276ac97c937SEliav Farber 	watchdog_stop_on_unregister(&wdt->wdd);
277b8008858SRay Jui 
278b8008858SRay Jui 	/*
279b8008858SRay Jui 	 * If 'timeout-sec' devicetree property is specified, use that.
280b8008858SRay Jui 	 * Otherwise, use DEFAULT_TIMEOUT
281b8008858SRay Jui 	 */
282b8008858SRay Jui 	wdt->wdd.timeout = DEFAULT_TIMEOUT;
283b8008858SRay Jui 	watchdog_init_timeout(&wdt->wdd, 0, &adev->dev);
284b8008858SRay Jui 	wdt_setload(&wdt->wdd, wdt->wdd.timeout);
2854a516539SViresh Kumar 
286fa5072edSRay Jui 	/*
287fa5072edSRay Jui 	 * If HW is already running, enable/reset the wdt and set the running
288fa5072edSRay Jui 	 * bit to tell the wdt subsystem
289fa5072edSRay Jui 	 */
290fa5072edSRay Jui 	if (wdt_is_running(&wdt->wdd)) {
291fa5072edSRay Jui 		wdt_enable(&wdt->wdd);
292fa5072edSRay Jui 		set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
293fa5072edSRay Jui 	}
294fa5072edSRay Jui 
29542e967f3SZhao Qiang 	watchdog_stop_on_reboot(&wdt->wdd);
2964a516539SViresh Kumar 	ret = watchdog_register_device(&wdt->wdd);
297199801cdSWolfram Sang 	if (ret)
29807bf971aSJingoo Han 		goto err;
2994a516539SViresh Kumar 	amba_set_drvdata(adev, wdt);
3004a370278SViresh KUMAR 
3014a370278SViresh KUMAR 	dev_info(&adev->dev, "registration successful\n");
3024a370278SViresh KUMAR 	return 0;
3034a370278SViresh KUMAR 
3044a370278SViresh KUMAR err:
3054a370278SViresh KUMAR 	dev_err(&adev->dev, "Probe Failed!!!\n");
3064a370278SViresh KUMAR 	return ret;
3074a370278SViresh KUMAR }
3084a370278SViresh KUMAR 
sp805_wdt_remove(struct amba_device * adev)3093fd269e7SUwe Kleine-König static void sp805_wdt_remove(struct amba_device *adev)
3104a370278SViresh KUMAR {
3114a516539SViresh Kumar 	struct sp805_wdt *wdt = amba_get_drvdata(adev);
3124a516539SViresh Kumar 
3134a516539SViresh Kumar 	watchdog_unregister_device(&wdt->wdd);
3144a516539SViresh Kumar 	watchdog_set_drvdata(&wdt->wdd, NULL);
3154a370278SViresh KUMAR }
3164a370278SViresh KUMAR 
sp805_wdt_suspend(struct device * dev)31760d6dd53SRussell King static int __maybe_unused sp805_wdt_suspend(struct device *dev)
31816ac4abeSViresh Kumar {
3194a516539SViresh Kumar 	struct sp805_wdt *wdt = dev_get_drvdata(dev);
3204a516539SViresh Kumar 
3214a516539SViresh Kumar 	if (watchdog_active(&wdt->wdd))
3224a516539SViresh Kumar 		return wdt_disable(&wdt->wdd);
32316ac4abeSViresh Kumar 
32416ac4abeSViresh Kumar 	return 0;
32516ac4abeSViresh Kumar }
32616ac4abeSViresh Kumar 
sp805_wdt_resume(struct device * dev)32760d6dd53SRussell King static int __maybe_unused sp805_wdt_resume(struct device *dev)
32816ac4abeSViresh Kumar {
3294a516539SViresh Kumar 	struct sp805_wdt *wdt = dev_get_drvdata(dev);
33016ac4abeSViresh Kumar 
3314a516539SViresh Kumar 	if (watchdog_active(&wdt->wdd))
3324a516539SViresh Kumar 		return wdt_enable(&wdt->wdd);
33316ac4abeSViresh Kumar 
3344a516539SViresh Kumar 	return 0;
33516ac4abeSViresh Kumar }
33616ac4abeSViresh Kumar 
33716ac4abeSViresh Kumar static SIMPLE_DEV_PM_OPS(sp805_wdt_dev_pm_ops, sp805_wdt_suspend,
33816ac4abeSViresh Kumar 		sp805_wdt_resume);
33916ac4abeSViresh Kumar 
34005ce42ffSArvind Yadav static const struct amba_id sp805_wdt_ids[] = {
3414a370278SViresh KUMAR 	{
3424a370278SViresh KUMAR 		.id	= 0x00141805,
3434a370278SViresh KUMAR 		.mask	= 0x00ffffff,
3444a370278SViresh KUMAR 	},
3453b190545SBing Fan 	{
3463b190545SBing Fan 		.id     = 0x001bb824,
3473b190545SBing Fan 		.mask   = 0x00ffffff,
3483b190545SBing Fan 	},
3494a370278SViresh KUMAR 	{ 0, 0 },
3504a370278SViresh KUMAR };
3514a370278SViresh KUMAR 
35217885b05SDave Martin MODULE_DEVICE_TABLE(amba, sp805_wdt_ids);
35317885b05SDave Martin 
3544a370278SViresh KUMAR static struct amba_driver sp805_wdt_driver = {
3554a370278SViresh KUMAR 	.drv = {
3564a370278SViresh KUMAR 		.name	= MODULE_NAME,
35716ac4abeSViresh Kumar 		.pm	= &sp805_wdt_dev_pm_ops,
3584a370278SViresh KUMAR 	},
3594a370278SViresh KUMAR 	.id_table	= sp805_wdt_ids,
3604a370278SViresh KUMAR 	.probe		= sp805_wdt_probe,
36182268714SBill Pemberton 	.remove = sp805_wdt_remove,
3624a370278SViresh KUMAR };
3634a370278SViresh KUMAR 
3649e5ed094Sviresh kumar module_amba_driver(sp805_wdt_driver);
3654a370278SViresh KUMAR 
366da89947bSViresh Kumar MODULE_AUTHOR("Viresh Kumar <vireshk@kernel.org>");
3674a370278SViresh KUMAR MODULE_DESCRIPTION("ARM SP805 Watchdog Driver");
3684a370278SViresh KUMAR MODULE_LICENSE("GPL");
369