Linux Audio

Check our new training course

Loading...
v5.9
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * drivers/watchdog/shwdt.c
  4 *
  5 * Watchdog driver for integrated watchdog in the SuperH processors.
  6 *
  7 * Copyright (C) 2001 - 2012  Paul Mundt <lethal@linux-sh.org>
  8 *
 
 
 
 
 
  9 * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
 10 *     Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
 11 *
 12 * 19-Apr-2002 Rob Radez <rob@osinvestor.com>
 13 *     Added expect close support, made emulated timeout runtime changeable
 14 *     general cleanups, add some ioctls
 15 */
 16
 17#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 18
 19#include <linux/module.h>
 20#include <linux/moduleparam.h>
 21#include <linux/platform_device.h>
 22#include <linux/init.h>
 23#include <linux/types.h>
 24#include <linux/spinlock.h>
 25#include <linux/watchdog.h>
 26#include <linux/pm_runtime.h>
 27#include <linux/fs.h>
 28#include <linux/mm.h>
 29#include <linux/slab.h>
 30#include <linux/io.h>
 31#include <linux/clk.h>
 32#include <linux/err.h>
 33#include <asm/watchdog.h>
 34
 35#define DRV_NAME "sh-wdt"
 36
 37/*
 38 * Default clock division ratio is 5.25 msecs. For an additional table of
 39 * values, consult the asm-sh/watchdog.h. Overload this at module load
 40 * time.
 41 *
 42 * In order for this to work reliably we need to have HZ set to 1000 or
 43 * something quite higher than 100 (or we need a proper high-res timer
 44 * implementation that will deal with this properly), otherwise the 10ms
 45 * resolution of a jiffy is enough to trigger the overflow. For things like
 46 * the SH-4 and SH-5, this isn't necessarily that big of a problem, though
 47 * for the SH-2 and SH-3, this isn't recommended unless the WDT is absolutely
 48 * necssary.
 49 *
 50 * As a result of this timing problem, the only modes that are particularly
 51 * feasible are the 4096 and the 2048 divisors, which yield 5.25 and 2.62ms
 52 * overflow periods respectively.
 53 *
 54 * Also, since we can't really expect userspace to be responsive enough
 55 * before the overflow happens, we maintain two separate timers .. One in
 56 * the kernel for clearing out WOVF every 2ms or so (again, this depends on
 57 * HZ == 1000), and another for monitoring userspace writes to the WDT device.
 58 *
 59 * As such, we currently use a configurable heartbeat interval which defaults
 60 * to 30s. In this case, the userspace daemon is only responsible for periodic
 61 * writes to the device before the next heartbeat is scheduled. If the daemon
 62 * misses its deadline, the kernel timer will allow the WDT to overflow.
 63 */
 64static int clock_division_ratio = WTCSR_CKS_4096;
 65#define next_ping_period(cks)	(jiffies + msecs_to_jiffies(cks - 4))
 66
 67#define WATCHDOG_HEARTBEAT 30			/* 30 sec default heartbeat */
 68static int heartbeat = WATCHDOG_HEARTBEAT;	/* in seconds */
 69static bool nowayout = WATCHDOG_NOWAYOUT;
 70static unsigned long next_heartbeat;
 71
 72struct sh_wdt {
 73	void __iomem		*base;
 74	struct device		*dev;
 75	struct clk		*clk;
 76	spinlock_t		lock;
 77
 78	struct timer_list	timer;
 79};
 80
 81static int sh_wdt_start(struct watchdog_device *wdt_dev)
 82{
 83	struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
 84	unsigned long flags;
 85	u8 csr;
 86
 87	pm_runtime_get_sync(wdt->dev);
 88	clk_enable(wdt->clk);
 89
 90	spin_lock_irqsave(&wdt->lock, flags);
 91
 92	next_heartbeat = jiffies + (heartbeat * HZ);
 93	mod_timer(&wdt->timer, next_ping_period(clock_division_ratio));
 94
 95	csr = sh_wdt_read_csr();
 96	csr |= WTCSR_WT | clock_division_ratio;
 97	sh_wdt_write_csr(csr);
 98
 99	sh_wdt_write_cnt(0);
100
101	/*
102	 * These processors have a bit of an inconsistent initialization
103	 * process.. starting with SH-3, RSTS was moved to WTCSR, and the
104	 * RSTCSR register was removed.
105	 *
106	 * On the SH-2 however, in addition with bits being in different
107	 * locations, we must deal with RSTCSR outright..
108	 */
109	csr = sh_wdt_read_csr();
110	csr |= WTCSR_TME;
111	csr &= ~WTCSR_RSTS;
112	sh_wdt_write_csr(csr);
113
114#ifdef CONFIG_CPU_SH2
115	csr = sh_wdt_read_rstcsr();
116	csr &= ~RSTCSR_RSTS;
117	sh_wdt_write_rstcsr(csr);
118#endif
119	spin_unlock_irqrestore(&wdt->lock, flags);
120
121	return 0;
122}
123
124static int sh_wdt_stop(struct watchdog_device *wdt_dev)
125{
126	struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
127	unsigned long flags;
128	u8 csr;
129
130	spin_lock_irqsave(&wdt->lock, flags);
131
132	del_timer(&wdt->timer);
133
134	csr = sh_wdt_read_csr();
135	csr &= ~WTCSR_TME;
136	sh_wdt_write_csr(csr);
137
138	spin_unlock_irqrestore(&wdt->lock, flags);
139
140	clk_disable(wdt->clk);
141	pm_runtime_put_sync(wdt->dev);
142
143	return 0;
144}
145
146static int sh_wdt_keepalive(struct watchdog_device *wdt_dev)
147{
148	struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
149	unsigned long flags;
150
151	spin_lock_irqsave(&wdt->lock, flags);
152	next_heartbeat = jiffies + (heartbeat * HZ);
153	spin_unlock_irqrestore(&wdt->lock, flags);
154
155	return 0;
156}
157
158static int sh_wdt_set_heartbeat(struct watchdog_device *wdt_dev, unsigned t)
159{
160	struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
161	unsigned long flags;
162
163	if (unlikely(t < 1 || t > 3600)) /* arbitrary upper limit */
164		return -EINVAL;
165
166	spin_lock_irqsave(&wdt->lock, flags);
167	heartbeat = t;
168	wdt_dev->timeout = t;
169	spin_unlock_irqrestore(&wdt->lock, flags);
170
171	return 0;
172}
173
174static void sh_wdt_ping(struct timer_list *t)
175{
176	struct sh_wdt *wdt = from_timer(wdt, t, timer);
177	unsigned long flags;
178
179	spin_lock_irqsave(&wdt->lock, flags);
180	if (time_before(jiffies, next_heartbeat)) {
181		u8 csr;
182
183		csr = sh_wdt_read_csr();
184		csr &= ~WTCSR_IOVF;
185		sh_wdt_write_csr(csr);
186
187		sh_wdt_write_cnt(0);
188
189		mod_timer(&wdt->timer, next_ping_period(clock_division_ratio));
190	} else
191		dev_warn(wdt->dev, "Heartbeat lost! Will not ping "
192		         "the watchdog\n");
193	spin_unlock_irqrestore(&wdt->lock, flags);
194}
195
196static const struct watchdog_info sh_wdt_info = {
197	.options		= WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
198				  WDIOF_MAGICCLOSE,
199	.firmware_version	= 1,
200	.identity		= "SH WDT",
201};
202
203static const struct watchdog_ops sh_wdt_ops = {
204	.owner		= THIS_MODULE,
205	.start		= sh_wdt_start,
206	.stop		= sh_wdt_stop,
207	.ping		= sh_wdt_keepalive,
208	.set_timeout	= sh_wdt_set_heartbeat,
209};
210
211static struct watchdog_device sh_wdt_dev = {
212	.info	= &sh_wdt_info,
213	.ops	= &sh_wdt_ops,
214};
215
216static int sh_wdt_probe(struct platform_device *pdev)
217{
218	struct sh_wdt *wdt;
 
219	int rc;
220
221	/*
222	 * As this driver only covers the global watchdog case, reject
223	 * any attempts to register per-CPU watchdogs.
224	 */
225	if (pdev->id != -1)
226		return -EINVAL;
227
228	wdt = devm_kzalloc(&pdev->dev, sizeof(struct sh_wdt), GFP_KERNEL);
229	if (unlikely(!wdt))
230		return -ENOMEM;
231
232	wdt->dev = &pdev->dev;
233
234	wdt->clk = devm_clk_get(&pdev->dev, NULL);
235	if (IS_ERR(wdt->clk)) {
236		/*
237		 * Clock framework support is optional, continue on
238		 * anyways if we don't find a matching clock.
239		 */
240		wdt->clk = NULL;
241	}
242
243	wdt->base = devm_platform_ioremap_resource(pdev, 0);
 
244	if (IS_ERR(wdt->base))
245		return PTR_ERR(wdt->base);
246
247	watchdog_set_nowayout(&sh_wdt_dev, nowayout);
248	watchdog_set_drvdata(&sh_wdt_dev, wdt);
249	sh_wdt_dev.parent = &pdev->dev;
250
251	spin_lock_init(&wdt->lock);
252
253	rc = sh_wdt_set_heartbeat(&sh_wdt_dev, heartbeat);
254	if (unlikely(rc)) {
255		/* Default timeout if invalid */
256		sh_wdt_set_heartbeat(&sh_wdt_dev, WATCHDOG_HEARTBEAT);
257
258		dev_warn(&pdev->dev,
259			 "heartbeat value must be 1<=x<=3600, using %d\n",
260			 sh_wdt_dev.timeout);
261	}
262
263	dev_info(&pdev->dev, "configured with heartbeat=%d sec (nowayout=%d)\n",
264		 sh_wdt_dev.timeout, nowayout);
265
266	rc = watchdog_register_device(&sh_wdt_dev);
267	if (unlikely(rc)) {
268		dev_err(&pdev->dev, "Can't register watchdog (err=%d)\n", rc);
269		return rc;
270	}
271
272	timer_setup(&wdt->timer, sh_wdt_ping, 0);
273	wdt->timer.expires	= next_ping_period(clock_division_ratio);
274
275	dev_info(&pdev->dev, "initialized.\n");
276
277	pm_runtime_enable(&pdev->dev);
278
279	return 0;
280}
281
282static int sh_wdt_remove(struct platform_device *pdev)
283{
284	watchdog_unregister_device(&sh_wdt_dev);
285
286	pm_runtime_disable(&pdev->dev);
287
288	return 0;
289}
290
291static void sh_wdt_shutdown(struct platform_device *pdev)
292{
293	sh_wdt_stop(&sh_wdt_dev);
294}
295
296static struct platform_driver sh_wdt_driver = {
297	.driver		= {
298		.name	= DRV_NAME,
299	},
300
301	.probe		= sh_wdt_probe,
302	.remove		= sh_wdt_remove,
303	.shutdown	= sh_wdt_shutdown,
304};
305
306static int __init sh_wdt_init(void)
307{
308	if (unlikely(clock_division_ratio < 0x5 ||
309		     clock_division_ratio > 0x7)) {
310		clock_division_ratio = WTCSR_CKS_4096;
311
312		pr_info("divisor must be 0x5<=x<=0x7, using %d\n",
313			clock_division_ratio);
314	}
315
316	return platform_driver_register(&sh_wdt_driver);
317}
318
319static void __exit sh_wdt_exit(void)
320{
321	platform_driver_unregister(&sh_wdt_driver);
322}
323module_init(sh_wdt_init);
324module_exit(sh_wdt_exit);
325
326MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
327MODULE_DESCRIPTION("SuperH watchdog driver");
328MODULE_LICENSE("GPL");
329MODULE_ALIAS("platform:" DRV_NAME);
330
331module_param(clock_division_ratio, int, 0);
332MODULE_PARM_DESC(clock_division_ratio,
333	"Clock division ratio. Valid ranges are from 0x5 (1.31ms) "
334	"to 0x7 (5.25ms). (default=" __MODULE_STRING(WTCSR_CKS_4096) ")");
335
336module_param(heartbeat, int, 0);
337MODULE_PARM_DESC(heartbeat,
338	"Watchdog heartbeat in seconds. (1 <= heartbeat <= 3600, default="
339				__MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
340
341module_param(nowayout, bool, 0);
342MODULE_PARM_DESC(nowayout,
343	"Watchdog cannot be stopped once started (default="
344				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
v4.17
 
  1/*
  2 * drivers/watchdog/shwdt.c
  3 *
  4 * Watchdog driver for integrated watchdog in the SuperH processors.
  5 *
  6 * Copyright (C) 2001 - 2012  Paul Mundt <lethal@linux-sh.org>
  7 *
  8 * This program is free software; you can redistribute it and/or modify it
  9 * under the terms of the GNU General Public License as published by the
 10 * Free Software Foundation; either version 2 of the License, or (at your
 11 * option) any later version.
 12 *
 13 * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
 14 *     Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
 15 *
 16 * 19-Apr-2002 Rob Radez <rob@osinvestor.com>
 17 *     Added expect close support, made emulated timeout runtime changeable
 18 *     general cleanups, add some ioctls
 19 */
 20
 21#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 22
 23#include <linux/module.h>
 24#include <linux/moduleparam.h>
 25#include <linux/platform_device.h>
 26#include <linux/init.h>
 27#include <linux/types.h>
 28#include <linux/spinlock.h>
 29#include <linux/watchdog.h>
 30#include <linux/pm_runtime.h>
 31#include <linux/fs.h>
 32#include <linux/mm.h>
 33#include <linux/slab.h>
 34#include <linux/io.h>
 35#include <linux/clk.h>
 36#include <linux/err.h>
 37#include <asm/watchdog.h>
 38
 39#define DRV_NAME "sh-wdt"
 40
 41/*
 42 * Default clock division ratio is 5.25 msecs. For an additional table of
 43 * values, consult the asm-sh/watchdog.h. Overload this at module load
 44 * time.
 45 *
 46 * In order for this to work reliably we need to have HZ set to 1000 or
 47 * something quite higher than 100 (or we need a proper high-res timer
 48 * implementation that will deal with this properly), otherwise the 10ms
 49 * resolution of a jiffy is enough to trigger the overflow. For things like
 50 * the SH-4 and SH-5, this isn't necessarily that big of a problem, though
 51 * for the SH-2 and SH-3, this isn't recommended unless the WDT is absolutely
 52 * necssary.
 53 *
 54 * As a result of this timing problem, the only modes that are particularly
 55 * feasible are the 4096 and the 2048 divisors, which yield 5.25 and 2.62ms
 56 * overflow periods respectively.
 57 *
 58 * Also, since we can't really expect userspace to be responsive enough
 59 * before the overflow happens, we maintain two separate timers .. One in
 60 * the kernel for clearing out WOVF every 2ms or so (again, this depends on
 61 * HZ == 1000), and another for monitoring userspace writes to the WDT device.
 62 *
 63 * As such, we currently use a configurable heartbeat interval which defaults
 64 * to 30s. In this case, the userspace daemon is only responsible for periodic
 65 * writes to the device before the next heartbeat is scheduled. If the daemon
 66 * misses its deadline, the kernel timer will allow the WDT to overflow.
 67 */
 68static int clock_division_ratio = WTCSR_CKS_4096;
 69#define next_ping_period(cks)	(jiffies + msecs_to_jiffies(cks - 4))
 70
 71#define WATCHDOG_HEARTBEAT 30			/* 30 sec default heartbeat */
 72static int heartbeat = WATCHDOG_HEARTBEAT;	/* in seconds */
 73static bool nowayout = WATCHDOG_NOWAYOUT;
 74static unsigned long next_heartbeat;
 75
 76struct sh_wdt {
 77	void __iomem		*base;
 78	struct device		*dev;
 79	struct clk		*clk;
 80	spinlock_t		lock;
 81
 82	struct timer_list	timer;
 83};
 84
 85static int sh_wdt_start(struct watchdog_device *wdt_dev)
 86{
 87	struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
 88	unsigned long flags;
 89	u8 csr;
 90
 91	pm_runtime_get_sync(wdt->dev);
 92	clk_enable(wdt->clk);
 93
 94	spin_lock_irqsave(&wdt->lock, flags);
 95
 96	next_heartbeat = jiffies + (heartbeat * HZ);
 97	mod_timer(&wdt->timer, next_ping_period(clock_division_ratio));
 98
 99	csr = sh_wdt_read_csr();
100	csr |= WTCSR_WT | clock_division_ratio;
101	sh_wdt_write_csr(csr);
102
103	sh_wdt_write_cnt(0);
104
105	/*
106	 * These processors have a bit of an inconsistent initialization
107	 * process.. starting with SH-3, RSTS was moved to WTCSR, and the
108	 * RSTCSR register was removed.
109	 *
110	 * On the SH-2 however, in addition with bits being in different
111	 * locations, we must deal with RSTCSR outright..
112	 */
113	csr = sh_wdt_read_csr();
114	csr |= WTCSR_TME;
115	csr &= ~WTCSR_RSTS;
116	sh_wdt_write_csr(csr);
117
118#ifdef CONFIG_CPU_SH2
119	csr = sh_wdt_read_rstcsr();
120	csr &= ~RSTCSR_RSTS;
121	sh_wdt_write_rstcsr(csr);
122#endif
123	spin_unlock_irqrestore(&wdt->lock, flags);
124
125	return 0;
126}
127
128static int sh_wdt_stop(struct watchdog_device *wdt_dev)
129{
130	struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
131	unsigned long flags;
132	u8 csr;
133
134	spin_lock_irqsave(&wdt->lock, flags);
135
136	del_timer(&wdt->timer);
137
138	csr = sh_wdt_read_csr();
139	csr &= ~WTCSR_TME;
140	sh_wdt_write_csr(csr);
141
142	spin_unlock_irqrestore(&wdt->lock, flags);
143
144	clk_disable(wdt->clk);
145	pm_runtime_put_sync(wdt->dev);
146
147	return 0;
148}
149
150static int sh_wdt_keepalive(struct watchdog_device *wdt_dev)
151{
152	struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
153	unsigned long flags;
154
155	spin_lock_irqsave(&wdt->lock, flags);
156	next_heartbeat = jiffies + (heartbeat * HZ);
157	spin_unlock_irqrestore(&wdt->lock, flags);
158
159	return 0;
160}
161
162static int sh_wdt_set_heartbeat(struct watchdog_device *wdt_dev, unsigned t)
163{
164	struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
165	unsigned long flags;
166
167	if (unlikely(t < 1 || t > 3600)) /* arbitrary upper limit */
168		return -EINVAL;
169
170	spin_lock_irqsave(&wdt->lock, flags);
171	heartbeat = t;
172	wdt_dev->timeout = t;
173	spin_unlock_irqrestore(&wdt->lock, flags);
174
175	return 0;
176}
177
178static void sh_wdt_ping(struct timer_list *t)
179{
180	struct sh_wdt *wdt = from_timer(wdt, t, timer);
181	unsigned long flags;
182
183	spin_lock_irqsave(&wdt->lock, flags);
184	if (time_before(jiffies, next_heartbeat)) {
185		u8 csr;
186
187		csr = sh_wdt_read_csr();
188		csr &= ~WTCSR_IOVF;
189		sh_wdt_write_csr(csr);
190
191		sh_wdt_write_cnt(0);
192
193		mod_timer(&wdt->timer, next_ping_period(clock_division_ratio));
194	} else
195		dev_warn(wdt->dev, "Heartbeat lost! Will not ping "
196		         "the watchdog\n");
197	spin_unlock_irqrestore(&wdt->lock, flags);
198}
199
200static const struct watchdog_info sh_wdt_info = {
201	.options		= WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
202				  WDIOF_MAGICCLOSE,
203	.firmware_version	= 1,
204	.identity		= "SH WDT",
205};
206
207static const struct watchdog_ops sh_wdt_ops = {
208	.owner		= THIS_MODULE,
209	.start		= sh_wdt_start,
210	.stop		= sh_wdt_stop,
211	.ping		= sh_wdt_keepalive,
212	.set_timeout	= sh_wdt_set_heartbeat,
213};
214
215static struct watchdog_device sh_wdt_dev = {
216	.info	= &sh_wdt_info,
217	.ops	= &sh_wdt_ops,
218};
219
220static int sh_wdt_probe(struct platform_device *pdev)
221{
222	struct sh_wdt *wdt;
223	struct resource *res;
224	int rc;
225
226	/*
227	 * As this driver only covers the global watchdog case, reject
228	 * any attempts to register per-CPU watchdogs.
229	 */
230	if (pdev->id != -1)
231		return -EINVAL;
232
233	wdt = devm_kzalloc(&pdev->dev, sizeof(struct sh_wdt), GFP_KERNEL);
234	if (unlikely(!wdt))
235		return -ENOMEM;
236
237	wdt->dev = &pdev->dev;
238
239	wdt->clk = devm_clk_get(&pdev->dev, NULL);
240	if (IS_ERR(wdt->clk)) {
241		/*
242		 * Clock framework support is optional, continue on
243		 * anyways if we don't find a matching clock.
244		 */
245		wdt->clk = NULL;
246	}
247
248	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
249	wdt->base = devm_ioremap_resource(wdt->dev, res);
250	if (IS_ERR(wdt->base))
251		return PTR_ERR(wdt->base);
252
253	watchdog_set_nowayout(&sh_wdt_dev, nowayout);
254	watchdog_set_drvdata(&sh_wdt_dev, wdt);
255	sh_wdt_dev.parent = &pdev->dev;
256
257	spin_lock_init(&wdt->lock);
258
259	rc = sh_wdt_set_heartbeat(&sh_wdt_dev, heartbeat);
260	if (unlikely(rc)) {
261		/* Default timeout if invalid */
262		sh_wdt_set_heartbeat(&sh_wdt_dev, WATCHDOG_HEARTBEAT);
263
264		dev_warn(&pdev->dev,
265			 "heartbeat value must be 1<=x<=3600, using %d\n",
266			 sh_wdt_dev.timeout);
267	}
268
269	dev_info(&pdev->dev, "configured with heartbeat=%d sec (nowayout=%d)\n",
270		 sh_wdt_dev.timeout, nowayout);
271
272	rc = watchdog_register_device(&sh_wdt_dev);
273	if (unlikely(rc)) {
274		dev_err(&pdev->dev, "Can't register watchdog (err=%d)\n", rc);
275		return rc;
276	}
277
278	timer_setup(&wdt->timer, sh_wdt_ping, 0);
279	wdt->timer.expires	= next_ping_period(clock_division_ratio);
280
281	dev_info(&pdev->dev, "initialized.\n");
282
283	pm_runtime_enable(&pdev->dev);
284
285	return 0;
286}
287
288static int sh_wdt_remove(struct platform_device *pdev)
289{
290	watchdog_unregister_device(&sh_wdt_dev);
291
292	pm_runtime_disable(&pdev->dev);
293
294	return 0;
295}
296
297static void sh_wdt_shutdown(struct platform_device *pdev)
298{
299	sh_wdt_stop(&sh_wdt_dev);
300}
301
302static struct platform_driver sh_wdt_driver = {
303	.driver		= {
304		.name	= DRV_NAME,
305	},
306
307	.probe		= sh_wdt_probe,
308	.remove		= sh_wdt_remove,
309	.shutdown	= sh_wdt_shutdown,
310};
311
312static int __init sh_wdt_init(void)
313{
314	if (unlikely(clock_division_ratio < 0x5 ||
315		     clock_division_ratio > 0x7)) {
316		clock_division_ratio = WTCSR_CKS_4096;
317
318		pr_info("divisor must be 0x5<=x<=0x7, using %d\n",
319			clock_division_ratio);
320	}
321
322	return platform_driver_register(&sh_wdt_driver);
323}
324
325static void __exit sh_wdt_exit(void)
326{
327	platform_driver_unregister(&sh_wdt_driver);
328}
329module_init(sh_wdt_init);
330module_exit(sh_wdt_exit);
331
332MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
333MODULE_DESCRIPTION("SuperH watchdog driver");
334MODULE_LICENSE("GPL");
335MODULE_ALIAS("platform:" DRV_NAME);
336
337module_param(clock_division_ratio, int, 0);
338MODULE_PARM_DESC(clock_division_ratio,
339	"Clock division ratio. Valid ranges are from 0x5 (1.31ms) "
340	"to 0x7 (5.25ms). (default=" __MODULE_STRING(WTCSR_CKS_4096) ")");
341
342module_param(heartbeat, int, 0);
343MODULE_PARM_DESC(heartbeat,
344	"Watchdog heartbeat in seconds. (1 <= heartbeat <= 3600, default="
345				__MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
346
347module_param(nowayout, bool, 0);
348MODULE_PARM_DESC(nowayout,
349	"Watchdog cannot be stopped once started (default="
350				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");