summaryrefslogtreecommitdiff
path: root/drivers/watchdog/mpc8xxx_wdt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/watchdog/mpc8xxx_wdt.c')
-rw-r--r--drivers/watchdog/mpc8xxx_wdt.c156
1 files changed, 66 insertions, 90 deletions
diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c
index 689381a24887..5f2273aac37d 100644
--- a/drivers/watchdog/mpc8xxx_wdt.c
+++ b/drivers/watchdog/mpc8xxx_wdt.c
@@ -50,8 +50,12 @@ struct mpc8xxx_wdt_type {
bool hw_enabled;
};
-static struct mpc8xxx_wdt __iomem *wd_base;
-static int mpc8xxx_wdt_init_late(void);
+struct mpc8xxx_wdt_ddata {
+ struct mpc8xxx_wdt __iomem *base;
+ struct watchdog_device wdd;
+ struct timer_list timer;
+ spinlock_t lock;
+};
static u16 timeout = 0xffff;
module_param(timeout, ushort, 0);
@@ -68,65 +72,59 @@ module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
-/*
- * We always prescale, but if someone really doesn't want to they can set this
- * to 0
- */
-static int prescale = 1;
-
-static DEFINE_SPINLOCK(wdt_spinlock);
-
-static void mpc8xxx_wdt_keepalive(void)
+static void mpc8xxx_wdt_keepalive(struct mpc8xxx_wdt_ddata *ddata)
{
/* Ping the WDT */
- spin_lock(&wdt_spinlock);
- out_be16(&wd_base->swsrr, 0x556c);
- out_be16(&wd_base->swsrr, 0xaa39);
- spin_unlock(&wdt_spinlock);
+ spin_lock(&ddata->lock);
+ out_be16(&ddata->base->swsrr, 0x556c);
+ out_be16(&ddata->base->swsrr, 0xaa39);
+ spin_unlock(&ddata->lock);
}
-static struct watchdog_device mpc8xxx_wdt_dev;
-static void mpc8xxx_wdt_timer_ping(unsigned long arg);
-static DEFINE_TIMER(wdt_timer, mpc8xxx_wdt_timer_ping, 0,
- (unsigned long)&mpc8xxx_wdt_dev);
-
static void mpc8xxx_wdt_timer_ping(unsigned long arg)
{
- struct watchdog_device *w = (struct watchdog_device *)arg;
+ struct mpc8xxx_wdt_ddata *ddata = (void *)arg;
- mpc8xxx_wdt_keepalive();
+ mpc8xxx_wdt_keepalive(ddata);
/* We're pinging it twice faster than needed, just to be sure. */
- mod_timer(&wdt_timer, jiffies + HZ * w->timeout / 2);
+ mod_timer(&ddata->timer, jiffies + HZ * ddata->wdd.timeout / 2);
}
static int mpc8xxx_wdt_start(struct watchdog_device *w)
{
- u32 tmp = SWCRR_SWEN;
+ struct mpc8xxx_wdt_ddata *ddata =
+ container_of(w, struct mpc8xxx_wdt_ddata, wdd);
+
+ u32 tmp = SWCRR_SWEN | SWCRR_SWPR;
/* Good, fire up the show */
- if (prescale)
- tmp |= SWCRR_SWPR;
if (reset)
tmp |= SWCRR_SWRI;
tmp |= timeout << 16;
- out_be32(&wd_base->swcrr, tmp);
+ out_be32(&ddata->base->swcrr, tmp);
- del_timer_sync(&wdt_timer);
+ del_timer_sync(&ddata->timer);
return 0;
}
static int mpc8xxx_wdt_ping(struct watchdog_device *w)
{
- mpc8xxx_wdt_keepalive();
+ struct mpc8xxx_wdt_ddata *ddata =
+ container_of(w, struct mpc8xxx_wdt_ddata, wdd);
+
+ mpc8xxx_wdt_keepalive(ddata);
return 0;
}
static int mpc8xxx_wdt_stop(struct watchdog_device *w)
{
- mod_timer(&wdt_timer, jiffies);
+ struct mpc8xxx_wdt_ddata *ddata =
+ container_of(w, struct mpc8xxx_wdt_ddata, wdd);
+
+ mod_timer(&ddata->timer, jiffies);
return 0;
}
@@ -143,53 +141,57 @@ static struct watchdog_ops mpc8xxx_wdt_ops = {
.stop = mpc8xxx_wdt_stop,
};
-static struct watchdog_device mpc8xxx_wdt_dev = {
- .info = &mpc8xxx_wdt_info,
- .ops = &mpc8xxx_wdt_ops,
-};
-
-static const struct of_device_id mpc8xxx_wdt_match[];
static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
{
int ret;
- const struct of_device_id *match;
- struct device_node *np = ofdev->dev.of_node;
+ struct resource *res;
const struct mpc8xxx_wdt_type *wdt_type;
+ struct mpc8xxx_wdt_ddata *ddata;
u32 freq = fsl_get_sys_freq();
bool enabled;
unsigned int timeout_sec;
- match = of_match_device(mpc8xxx_wdt_match, &ofdev->dev);
- if (!match)
+ wdt_type = of_device_get_match_data(&ofdev->dev);
+ if (!wdt_type)
return -EINVAL;
- wdt_type = match->data;
if (!freq || freq == -1)
return -EINVAL;
- wd_base = of_iomap(np, 0);
- if (!wd_base)
+ ddata = devm_kzalloc(&ofdev->dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
return -ENOMEM;
- enabled = in_be32(&wd_base->swcrr) & SWCRR_SWEN;
+ res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
+ ddata->base = devm_ioremap_resource(&ofdev->dev, res);
+ if (IS_ERR(ddata->base))
+ return PTR_ERR(ddata->base);
+
+ enabled = in_be32(&ddata->base->swcrr) & SWCRR_SWEN;
if (!enabled && wdt_type->hw_enabled) {
pr_info("could not be enabled in software\n");
- ret = -ENOSYS;
- goto err_unmap;
+ return -ENODEV;
}
+ spin_lock_init(&ddata->lock);
+ setup_timer(&ddata->timer, mpc8xxx_wdt_timer_ping,
+ (unsigned long)ddata);
+
+ ddata->wdd.info = &mpc8xxx_wdt_info,
+ ddata->wdd.ops = &mpc8xxx_wdt_ops,
+
/* Calculate the timeout in seconds */
- if (prescale)
- timeout_sec = (timeout * wdt_type->prescaler) / freq;
- else
- timeout_sec = timeout / freq;
-
- mpc8xxx_wdt_dev.timeout = timeout_sec;
-#ifdef MODULE
- ret = mpc8xxx_wdt_init_late();
- if (ret)
- goto err_unmap;
-#endif
+ timeout_sec = (timeout * wdt_type->prescaler) / freq;
+
+ ddata->wdd.timeout = timeout_sec;
+
+ watchdog_set_nowayout(&ddata->wdd, nowayout);
+
+ ret = watchdog_register_device(&ddata->wdd);
+ if (ret) {
+ pr_err("cannot register watchdog device (err=%d)\n", ret);
+ return ret;
+ }
pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d (%d seconds)\n",
reset ? "reset" : "interrupt", timeout, timeout_sec);
@@ -200,21 +202,20 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
* userspace handles it.
*/
if (enabled)
- mod_timer(&wdt_timer, jiffies);
+ mod_timer(&ddata->timer, jiffies);
+
+ platform_set_drvdata(ofdev, ddata);
return 0;
-err_unmap:
- iounmap(wd_base);
- wd_base = NULL;
- return ret;
}
static int mpc8xxx_wdt_remove(struct platform_device *ofdev)
{
+ struct mpc8xxx_wdt_ddata *ddata = platform_get_drvdata(ofdev);
+
pr_crit("Watchdog removed, expect the %s soon!\n",
reset ? "reset" : "machine check exception");
- del_timer_sync(&wdt_timer);
- watchdog_unregister_device(&mpc8xxx_wdt_dev);
- iounmap(wd_base);
+ del_timer_sync(&ddata->timer);
+ watchdog_unregister_device(&ddata->wdd);
return 0;
}
@@ -253,31 +254,6 @@ static struct platform_driver mpc8xxx_wdt_driver = {
},
};
-/*
- * We do wdt initialization in two steps: arch_initcall probes the wdt
- * very early to start pinging the watchdog (misc devices are not yet
- * available), and later module_init() just registers the misc device.
- */
-static int mpc8xxx_wdt_init_late(void)
-{
- int ret;
-
- if (!wd_base)
- return -ENODEV;
-
- watchdog_set_nowayout(&mpc8xxx_wdt_dev, nowayout);
-
- ret = watchdog_register_device(&mpc8xxx_wdt_dev);
- if (ret) {
- pr_err("cannot register watchdog device (err=%d)\n", ret);
- return ret;
- }
- return 0;
-}
-#ifndef MODULE
-module_init(mpc8xxx_wdt_init_late);
-#endif
-
static int __init mpc8xxx_wdt_init(void)
{
return platform_driver_register(&mpc8xxx_wdt_driver);