watchdog: bcm2835_wdt: Use watchdog core to install restart handler
Use the infrastructure provided by the watchdog core to install the restart handler. Acked-by: Eric Anholt <eric@anholt.net> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
parent
55dbe8f325
commit
71e9b2f0bf
|
@ -14,7 +14,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/reboot.h>
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
@ -49,7 +48,6 @@
|
||||||
struct bcm2835_wdt {
|
struct bcm2835_wdt {
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
struct notifier_block restart_handler;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned int heartbeat;
|
static unsigned int heartbeat;
|
||||||
|
@ -99,11 +97,37 @@ static unsigned int bcm2835_wdt_get_timeleft(struct watchdog_device *wdog)
|
||||||
return WDOG_TICKS_TO_SECS(ret & PM_WDOG_TIME_SET);
|
return WDOG_TICKS_TO_SECS(ret & PM_WDOG_TIME_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __bcm2835_restart(struct bcm2835_wdt *wdt)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
/* use a timeout of 10 ticks (~150us) */
|
||||||
|
writel_relaxed(10 | PM_PASSWORD, wdt->base + PM_WDOG);
|
||||||
|
val = readl_relaxed(wdt->base + PM_RSTC);
|
||||||
|
val &= PM_RSTC_WRCFG_CLR;
|
||||||
|
val |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET;
|
||||||
|
writel_relaxed(val, wdt->base + PM_RSTC);
|
||||||
|
|
||||||
|
/* No sleeping, possibly atomic. */
|
||||||
|
mdelay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bcm2835_restart(struct watchdog_device *wdog,
|
||||||
|
unsigned long action, void *data)
|
||||||
|
{
|
||||||
|
struct bcm2835_wdt *wdt = watchdog_get_drvdata(wdog);
|
||||||
|
|
||||||
|
__bcm2835_restart(wdt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct watchdog_ops bcm2835_wdt_ops = {
|
static const struct watchdog_ops bcm2835_wdt_ops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.start = bcm2835_wdt_start,
|
.start = bcm2835_wdt_start,
|
||||||
.stop = bcm2835_wdt_stop,
|
.stop = bcm2835_wdt_stop,
|
||||||
.get_timeleft = bcm2835_wdt_get_timeleft,
|
.get_timeleft = bcm2835_wdt_get_timeleft,
|
||||||
|
.restart = bcm2835_restart,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct watchdog_info bcm2835_wdt_info = {
|
static const struct watchdog_info bcm2835_wdt_info = {
|
||||||
|
@ -120,26 +144,6 @@ static struct watchdog_device bcm2835_wdt_wdd = {
|
||||||
.timeout = WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET),
|
.timeout = WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET),
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
|
||||||
bcm2835_restart(struct notifier_block *this, unsigned long mode, void *cmd)
|
|
||||||
{
|
|
||||||
struct bcm2835_wdt *wdt = container_of(this, struct bcm2835_wdt,
|
|
||||||
restart_handler);
|
|
||||||
u32 val;
|
|
||||||
|
|
||||||
/* use a timeout of 10 ticks (~150us) */
|
|
||||||
writel_relaxed(10 | PM_PASSWORD, wdt->base + PM_WDOG);
|
|
||||||
val = readl_relaxed(wdt->base + PM_RSTC);
|
|
||||||
val &= PM_RSTC_WRCFG_CLR;
|
|
||||||
val |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET;
|
|
||||||
writel_relaxed(val, wdt->base + PM_RSTC);
|
|
||||||
|
|
||||||
/* No sleeping, possibly atomic. */
|
|
||||||
mdelay(1);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can't really power off, but if we do the normal reset scheme, and
|
* We can't really power off, but if we do the normal reset scheme, and
|
||||||
* indicate to bootcode.bin not to reboot, then most of the chip will be
|
* indicate to bootcode.bin not to reboot, then most of the chip will be
|
||||||
|
@ -163,7 +167,7 @@ static void bcm2835_power_off(void)
|
||||||
writel_relaxed(val, wdt->base + PM_RSTS);
|
writel_relaxed(val, wdt->base + PM_RSTS);
|
||||||
|
|
||||||
/* Continue with normal reset mechanism */
|
/* Continue with normal reset mechanism */
|
||||||
bcm2835_restart(&wdt->restart_handler, REBOOT_HARD, NULL);
|
__bcm2835_restart(wdt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bcm2835_wdt_probe(struct platform_device *pdev)
|
static int bcm2835_wdt_probe(struct platform_device *pdev)
|
||||||
|
@ -201,6 +205,9 @@ static int bcm2835_wdt_probe(struct platform_device *pdev)
|
||||||
*/
|
*/
|
||||||
set_bit(WDOG_HW_RUNNING, &bcm2835_wdt_wdd.status);
|
set_bit(WDOG_HW_RUNNING, &bcm2835_wdt_wdd.status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watchdog_set_restart_priority(&bcm2835_wdt_wdd, 128);
|
||||||
|
|
||||||
err = watchdog_register_device(&bcm2835_wdt_wdd);
|
err = watchdog_register_device(&bcm2835_wdt_wdd);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(dev, "Failed to register watchdog device");
|
dev_err(dev, "Failed to register watchdog device");
|
||||||
|
@ -208,9 +215,6 @@ static int bcm2835_wdt_probe(struct platform_device *pdev)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
wdt->restart_handler.notifier_call = bcm2835_restart;
|
|
||||||
wdt->restart_handler.priority = 128;
|
|
||||||
register_restart_handler(&wdt->restart_handler);
|
|
||||||
if (pm_power_off == NULL)
|
if (pm_power_off == NULL)
|
||||||
pm_power_off = bcm2835_power_off;
|
pm_power_off = bcm2835_power_off;
|
||||||
|
|
||||||
|
@ -222,7 +226,6 @@ static int bcm2835_wdt_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct bcm2835_wdt *wdt = platform_get_drvdata(pdev);
|
struct bcm2835_wdt *wdt = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
unregister_restart_handler(&wdt->restart_handler);
|
|
||||||
if (pm_power_off == bcm2835_power_off)
|
if (pm_power_off == bcm2835_power_off)
|
||||||
pm_power_off = NULL;
|
pm_power_off = NULL;
|
||||||
watchdog_unregister_device(&bcm2835_wdt_wdd);
|
watchdog_unregister_device(&bcm2835_wdt_wdd);
|
||||||
|
|
Loading…
Reference in New Issue