Commit 4fe19a13 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://www.linux-watchdog.org/linux-watchdog

Pull watchdog updates from Wim Van Sebroeck:
 "This includes some fixes and code improvements (like
  clk_prepare_enable and clk_disable_unprepare), conversion from the
  omap_wdt and twl4030_wdt drivers to the watchdog framework, addition
  of the SB8x0 chipset support and the DA9055 Watchdog driver and some
  OF support for the davinci_wdt driver."

* git://www.linux-watchdog.org/linux-watchdog: (22 commits)
  watchdog: mei: avoid oops in watchdog unregister code path
  watchdog: Orion: Fix possible null-deference in orion_wdt_probe
  watchdog: sp5100_tco: Add SB8x0 chipset support
  watchdog: davinci_wdt: add OF support
  watchdog: da9052: Fix invalid free of devm_ allocated data
  watchdog: twl4030_wdt: Change TWL4030_MODULE_PM_RECEIVER to TWL_MODULE_PM_RECEIVER
  watchdog: remove depends on CONFIG_EXPERIMENTAL
  watchdog: Convert dev_printk(KERN_<LEVEL> to dev_<level>(
  watchdog: DA9055 Watchdog driver
  watchdog: omap_wdt: eliminate goto
  watchdog: omap_wdt: delete redundant platform_set_drvdata() calls
  watchdog: omap_wdt: convert to devm_ functions
  watchdog: omap_wdt: convert to new watchdog core
  watchdog: WatchDog Timer Driver Core: fix comment
  watchdog: s3c2410_wdt: use clk_prepare_enable and clk_disable_unprepare
  watchdog: imx2_wdt: Select the driver via ARCH_MXC
  watchdog: cpu5wdt.c: add missing del_timer call
  watchdog: hpwdt.c: Increase version string
  watchdog: Convert twl4030_wdt to watchdog core
  davinci_wdt: preparation for switch to common clock framework
  ...
parents 769cb858 d6921700
DaVinci Watchdog Timer (WDT) Controller
Required properties:
- compatible : Should be "ti,davinci-wdt"
- reg : Should contain WDT registers location and length
Examples:
wdt: wdt@2320000 {
compatible = "ti,davinci-wdt";
reg = <0x02320000 0x80>;
};
...@@ -370,7 +370,7 @@ void mei_watchdog_register(struct mei_device *dev) ...@@ -370,7 +370,7 @@ void mei_watchdog_register(struct mei_device *dev)
void mei_watchdog_unregister(struct mei_device *dev) void mei_watchdog_unregister(struct mei_device *dev)
{ {
if (test_bit(WDOG_UNREGISTERED, &amt_wd_dev.status)) if (watchdog_get_drvdata(&amt_wd_dev) == NULL)
return; return;
watchdog_set_drvdata(&amt_wd_dev, NULL); watchdog_set_drvdata(&amt_wd_dev, NULL);
......
...@@ -76,6 +76,16 @@ config DA9052_WATCHDOG ...@@ -76,6 +76,16 @@ config DA9052_WATCHDOG
Alternatively say M to compile the driver as a module, Alternatively say M to compile the driver as a module,
which will be called da9052_wdt. which will be called da9052_wdt.
config DA9055_WATCHDOG
tristate "Dialog Semiconductor DA9055 Watchdog"
depends on MFD_DA9055
help
If you say yes here you get support for watchdog on the Dialog
Semiconductor DA9055 PMIC.
This driver can also be built as a module. If so, the module
will be called da9055_wdt.
config WM831X_WATCHDOG config WM831X_WATCHDOG
tristate "WM831x watchdog" tristate "WM831x watchdog"
depends on MFD_WM831X depends on MFD_WM831X
...@@ -232,6 +242,7 @@ config EP93XX_WATCHDOG ...@@ -232,6 +242,7 @@ config EP93XX_WATCHDOG
config OMAP_WATCHDOG config OMAP_WATCHDOG
tristate "OMAP Watchdog" tristate "OMAP Watchdog"
depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS
select WATCHDOG_CORE
help help
Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog. Say 'Y' Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog. Say 'Y'
here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog timer. here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog timer.
...@@ -300,6 +311,7 @@ config COH901327_WATCHDOG ...@@ -300,6 +311,7 @@ config COH901327_WATCHDOG
config TWL4030_WATCHDOG config TWL4030_WATCHDOG
tristate "TWL4030 Watchdog" tristate "TWL4030 Watchdog"
depends on TWL4030_CORE depends on TWL4030_CORE
select WATCHDOG_CORE
help help
Support for TI TWL4030 watchdog. Say 'Y' here to enable the Support for TI TWL4030 watchdog. Say 'Y' here to enable the
watchdog timer support for TWL4030 chips. watchdog timer support for TWL4030 chips.
...@@ -342,7 +354,7 @@ config MAX63XX_WATCHDOG ...@@ -342,7 +354,7 @@ config MAX63XX_WATCHDOG
config IMX2_WDT config IMX2_WDT
tristate "IMX2+ Watchdog" tristate "IMX2+ Watchdog"
depends on IMX_HAVE_PLATFORM_IMX2_WDT depends on ARCH_MXC
help help
This is the driver for the hardware watchdog This is the driver for the hardware watchdog
on the Freescale IMX2 and later processors. on the Freescale IMX2 and later processors.
...@@ -431,7 +443,7 @@ config ALIM7101_WDT ...@@ -431,7 +443,7 @@ config ALIM7101_WDT
config F71808E_WDT config F71808E_WDT
tristate "Fintek F71808E, F71862FG, F71869, F71882FG and F71889FG Watchdog" tristate "Fintek F71808E, F71862FG, F71869, F71882FG and F71889FG Watchdog"
depends on X86 && EXPERIMENTAL depends on X86
help help
This is the driver for the hardware watchdog on the Fintek This is the driver for the hardware watchdog on the Fintek
F71808E, F71862FG, F71869, F71882FG and F71889FG Super I/O controllers. F71808E, F71862FG, F71869, F71882FG and F71889FG Super I/O controllers.
...@@ -622,7 +634,7 @@ config IT8712F_WDT ...@@ -622,7 +634,7 @@ config IT8712F_WDT
config IT87_WDT config IT87_WDT
tristate "IT87 Watchdog Timer" tristate "IT87 Watchdog Timer"
depends on X86 && EXPERIMENTAL depends on X86
---help--- ---help---
This is the driver for the hardware watchdog on the ITE IT8702, This is the driver for the hardware watchdog on the ITE IT8702,
IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 and IT8728 IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 and IT8728
......
...@@ -164,6 +164,7 @@ obj-$(CONFIG_XEN_WDT) += xen_wdt.o ...@@ -164,6 +164,7 @@ obj-$(CONFIG_XEN_WDT) += xen_wdt.o
# Architecture Independent # Architecture Independent
obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o
obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o
obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o
obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o
obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o
......
...@@ -284,6 +284,7 @@ static void ath97_wdt_shutdown(struct platform_device *pdev) ...@@ -284,6 +284,7 @@ static void ath97_wdt_shutdown(struct platform_device *pdev)
} }
static struct platform_driver ath79_wdt_driver = { static struct platform_driver ath79_wdt_driver = {
.probe = ath79_wdt_probe,
.remove = ath79_wdt_remove, .remove = ath79_wdt_remove,
.shutdown = ath97_wdt_shutdown, .shutdown = ath97_wdt_shutdown,
.driver = { .driver = {
...@@ -292,17 +293,7 @@ static struct platform_driver ath79_wdt_driver = { ...@@ -292,17 +293,7 @@ static struct platform_driver ath79_wdt_driver = {
}, },
}; };
static int __init ath79_wdt_init(void) module_platform_driver(ath79_wdt_driver);
{
return platform_driver_probe(&ath79_wdt_driver, ath79_wdt_probe);
}
module_init(ath79_wdt_init);
static void __exit ath79_wdt_exit(void)
{
platform_driver_unregister(&ath79_wdt_driver);
}
module_exit(ath79_wdt_exit);
MODULE_DESCRIPTION("Atheros AR71XX/AR724X/AR913X hardware watchdog driver"); MODULE_DESCRIPTION("Atheros AR71XX/AR724X/AR913X hardware watchdog driver");
MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org"); MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org");
......
...@@ -266,6 +266,7 @@ static void cpu5wdt_exit(void) ...@@ -266,6 +266,7 @@ static void cpu5wdt_exit(void)
if (cpu5wdt_device.queue) { if (cpu5wdt_device.queue) {
cpu5wdt_device.queue = 0; cpu5wdt_device.queue = 0;
wait_for_completion(&cpu5wdt_device.stop); wait_for_completion(&cpu5wdt_device.stop);
del_timer(&cpu5wdt_device.timer);
} }
misc_deregister(&cpu5wdt_misc); misc_deregister(&cpu5wdt_misc);
......
...@@ -53,10 +53,6 @@ static const struct { ...@@ -53,10 +53,6 @@ static const struct {
static void da9052_wdt_release_resources(struct kref *r) static void da9052_wdt_release_resources(struct kref *r)
{ {
struct da9052_wdt_data *driver_data =
container_of(r, struct da9052_wdt_data, kref);
kfree(driver_data);
} }
static int da9052_wdt_set_timeout(struct watchdog_device *wdt_dev, static int da9052_wdt_set_timeout(struct watchdog_device *wdt_dev,
......
/*
* System monitoring driver for DA9055 PMICs.
*
* Copyright(c) 2012 Dialog Semiconductor Ltd.
*
* Author: David Dajun Chen <dchen@diasemi.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/watchdog.h>
#include <linux/delay.h>
#include <linux/mfd/da9055/core.h>
#include <linux/mfd/da9055/reg.h>
static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
#define DA9055_DEF_TIMEOUT 4
#define DA9055_TWDMIN 256
struct da9055_wdt_data {
struct watchdog_device wdt;
struct da9055 *da9055;
struct kref kref;
};
static const struct {
u8 reg_val;
int user_time; /* In seconds */
} da9055_wdt_maps[] = {
{ 0, 0 },
{ 1, 2 },
{ 2, 4 },
{ 3, 8 },
{ 4, 16 },
{ 5, 32 },
{ 5, 33 }, /* Actual time 32.768s so included both 32s and 33s */
{ 6, 65 },
{ 6, 66 }, /* Actual time 65.536s so include both, 65s and 66s */
{ 7, 131 },
};
static int da9055_wdt_set_timeout(struct watchdog_device *wdt_dev,
unsigned int timeout)
{
struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
struct da9055 *da9055 = driver_data->da9055;
int ret, i;
for (i = 0; i < ARRAY_SIZE(da9055_wdt_maps); i++)
if (da9055_wdt_maps[i].user_time == timeout)
break;
if (i == ARRAY_SIZE(da9055_wdt_maps))
ret = -EINVAL;
else
ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B,
DA9055_TWDSCALE_MASK,
da9055_wdt_maps[i].reg_val <<
DA9055_TWDSCALE_SHIFT);
if (ret < 0)
dev_err(da9055->dev,
"Failed to update timescale bit, %d\n", ret);
wdt_dev->timeout = timeout;
return ret;
}
static int da9055_wdt_ping(struct watchdog_device *wdt_dev)
{
struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
struct da9055 *da9055 = driver_data->da9055;
int ret;
/*
* We have a minimum time for watchdog window called TWDMIN. A write
* to the watchdog before this elapsed time will cause an error.
*/
mdelay(DA9055_TWDMIN);
/* Reset the watchdog timer */
ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_E,
DA9055_WATCHDOG_MASK, 1);
return ret;
}
static void da9055_wdt_release_resources(struct kref *r)
{
struct da9055_wdt_data *driver_data =
container_of(r, struct da9055_wdt_data, kref);
kfree(driver_data);
}
static void da9055_wdt_ref(struct watchdog_device *wdt_dev)
{
struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
kref_get(&driver_data->kref);
}
static void da9055_wdt_unref(struct watchdog_device *wdt_dev)
{
struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
kref_put(&driver_data->kref, da9055_wdt_release_resources);
}
static int da9055_wdt_start(struct watchdog_device *wdt_dev)
{
return da9055_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
}
static int da9055_wdt_stop(struct watchdog_device *wdt_dev)
{
return da9055_wdt_set_timeout(wdt_dev, 0);
}
static struct watchdog_info da9055_wdt_info = {
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
.identity = "DA9055 Watchdog",
};
static const struct watchdog_ops da9055_wdt_ops = {
.owner = THIS_MODULE,
.start = da9055_wdt_start,
.stop = da9055_wdt_stop,
.ping = da9055_wdt_ping,
.set_timeout = da9055_wdt_set_timeout,
.ref = da9055_wdt_ref,
.unref = da9055_wdt_unref,
};
static int da9055_wdt_probe(struct platform_device *pdev)
{
struct da9055 *da9055 = dev_get_drvdata(pdev->dev.parent);
struct da9055_wdt_data *driver_data;
struct watchdog_device *da9055_wdt;
int ret;
driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data),
GFP_KERNEL);
if (!driver_data) {
dev_err(da9055->dev, "Failed to allocate watchdog device\n");
return -ENOMEM;
}
driver_data->da9055 = da9055;
da9055_wdt = &driver_data->wdt;
da9055_wdt->timeout = DA9055_DEF_TIMEOUT;
da9055_wdt->info = &da9055_wdt_info;
da9055_wdt->ops = &da9055_wdt_ops;
watchdog_set_nowayout(da9055_wdt, nowayout);
watchdog_set_drvdata(da9055_wdt, driver_data);
kref_init(&driver_data->kref);
ret = da9055_wdt_stop(da9055_wdt);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to stop watchdog, %d\n", ret);
goto err;
}
dev_set_drvdata(&pdev->dev, driver_data);
ret = watchdog_register_device(&driver_data->wdt);
if (ret != 0)
dev_err(da9055->dev, "watchdog_register_device() failed: %d\n",
ret);
err:
return ret;
}
static int da9055_wdt_remove(struct platform_device *pdev)
{
struct da9055_wdt_data *driver_data = dev_get_drvdata(&pdev->dev);
watchdog_unregister_device(&driver_data->wdt);
kref_put(&driver_data->kref, da9055_wdt_release_resources);
return 0;
}
static struct platform_driver da9055_wdt_driver = {
.probe = da9055_wdt_probe,
.remove = da9055_wdt_remove,
.driver = {
.name = "da9055-watchdog",
},
};
module_platform_driver(da9055_wdt_driver);
MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
MODULE_DESCRIPTION("DA9055 watchdog");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:da9055-watchdog");
...@@ -208,7 +208,7 @@ static int davinci_wdt_probe(struct platform_device *pdev) ...@@ -208,7 +208,7 @@ static int davinci_wdt_probe(struct platform_device *pdev)
if (WARN_ON(IS_ERR(wdt_clk))) if (WARN_ON(IS_ERR(wdt_clk)))
return PTR_ERR(wdt_clk); return PTR_ERR(wdt_clk);
clk_enable(wdt_clk); clk_prepare_enable(wdt_clk);
if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT) if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
heartbeat = DEFAULT_HEARTBEAT; heartbeat = DEFAULT_HEARTBEAT;
...@@ -256,16 +256,23 @@ static int davinci_wdt_remove(struct platform_device *pdev) ...@@ -256,16 +256,23 @@ static int davinci_wdt_remove(struct platform_device *pdev)
wdt_mem = NULL; wdt_mem = NULL;
} }
clk_disable(wdt_clk); clk_disable_unprepare(wdt_clk);
clk_put(wdt_clk); clk_put(wdt_clk);
return 0; return 0;
} }
static const struct of_device_id davinci_wdt_of_match[] = {
{ .compatible = "ti,davinci-wdt", },
{},
};
MODULE_DEVICE_TABLE(of, davinci_wdt_of_match);
static struct platform_driver platform_wdt_driver = { static struct platform_driver platform_wdt_driver = {
.driver = { .driver = {
.name = "watchdog", .name = "watchdog",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = davinci_wdt_of_match,
}, },
.probe = davinci_wdt_probe, .probe = davinci_wdt_probe,
.remove = davinci_wdt_remove, .remove = davinci_wdt_remove,
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
#endif /* CONFIG_HPWDT_NMI_DECODING */ #endif /* CONFIG_HPWDT_NMI_DECODING */
#include <asm/nmi.h> #include <asm/nmi.h>
#define HPWDT_VERSION "1.3.0" #define HPWDT_VERSION "1.3.1"
#define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128)
#define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000) #define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000)
#define HPWDT_MAX_TIMER TICKS_TO_SECS(65535) #define HPWDT_MAX_TIMER TICKS_TO_SECS(65535)
......
...@@ -80,8 +80,7 @@ static irqreturn_t mpcore_wdt_fire(int irq, void *arg) ...@@ -80,8 +80,7 @@ static irqreturn_t mpcore_wdt_fire(int irq, void *arg)
/* Check it really was our interrupt */ /* Check it really was our interrupt */
if (readl(wdt->base + TWD_WDOG_INTSTAT)) { if (readl(wdt->base + TWD_WDOG_INTSTAT)) {
dev_printk(KERN_CRIT, wdt->dev, dev_crit(wdt->dev, "Triggered - Reboot ignored\n");
"Triggered - Reboot ignored.\n");
/* Clear the interrupt on the watchdog */ /* Clear the interrupt on the watchdog */
writel(1, wdt->base + TWD_WDOG_INTSTAT); writel(1, wdt->base + TWD_WDOG_INTSTAT);
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -123,7 +122,7 @@ static void mpcore_wdt_stop(struct mpcore_wdt *wdt) ...@@ -123,7 +122,7 @@ static void mpcore_wdt_stop(struct mpcore_wdt *wdt)
static void mpcore_wdt_start(struct mpcore_wdt *wdt) static void mpcore_wdt_start(struct mpcore_wdt *wdt)
{ {
dev_printk(KERN_INFO, wdt->dev, "enabling watchdog.\n"); dev_info(wdt->dev, "enabling watchdog\n");
/* This loads the count register but does NOT start the count yet */ /* This loads the count register but does NOT start the count yet */
mpcore_wdt_keepalive(wdt); mpcore_wdt_keepalive(wdt);
...@@ -180,7 +179,7 @@ static int mpcore_wdt_release(struct inode *inode, struct file *file) ...@@ -180,7 +179,7 @@ static int mpcore_wdt_release(struct inode *inode, struct file *file)
if (wdt->expect_close == 42) if (wdt->expect_close == 42)
mpcore_wdt_stop(wdt); mpcore_wdt_stop(wdt);
else { else {
dev_printk(KERN_CRIT, wdt->dev, dev_crit(wdt->dev,
"unexpected close, not stopping watchdog!\n"); "unexpected close, not stopping watchdog!\n");
mpcore_wdt_keepalive(wdt); mpcore_wdt_keepalive(wdt);
} }
...@@ -351,7 +350,7 @@ static int mpcore_wdt_probe(struct platform_device *pdev) ...@@ -351,7 +350,7 @@ static int mpcore_wdt_probe(struct platform_device *pdev)
ret = devm_request_irq(wdt->dev, wdt->irq, mpcore_wdt_fire, 0, ret = devm_request_irq(wdt->dev, wdt->irq, mpcore_wdt_fire, 0,
"mpcore_wdt", wdt); "mpcore_wdt", wdt);
if (ret) { if (ret) {
dev_printk(KERN_ERR, wdt->dev, dev_err(wdt->dev,
"cannot register IRQ%d for watchdog\n", "cannot register IRQ%d for watchdog\n",
wdt->irq); wdt->irq);
return ret; return ret;
...@@ -365,7 +364,7 @@ static int mpcore_wdt_probe(struct platform_device *pdev) ...@@ -365,7 +364,7 @@ static int mpcore_wdt_probe(struct platform_device *pdev)
mpcore_wdt_miscdev.parent = &pdev->dev; mpcore_wdt_miscdev.parent = &pdev->dev;
ret = misc_register(&mpcore_wdt_miscdev); ret = misc_register(&mpcore_wdt_miscdev);
if (ret) { if (ret) {
dev_printk(KERN_ERR, wdt->dev, dev_err(wdt->dev,
"cannot register miscdev on minor=%d (err=%d)\n", "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret); WATCHDOG_MINOR, ret);
return ret; return ret;
......
This diff is collapsed.
...@@ -156,6 +156,8 @@ static int orion_wdt_probe(struct platform_device *pdev) ...@@ -156,6 +156,8 @@ static int orion_wdt_probe(struct platform_device *pdev)
wdt_tclk = clk_get_rate(clk); wdt_tclk = clk_get_rate(clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
wdt_reg = devm_ioremap(&pdev->dev, res->start, resource_size(res)); wdt_reg = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (!wdt_reg) if (!wdt_reg)
return -ENOMEM; return -ENOMEM;
......
...@@ -354,7 +354,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev) ...@@ -354,7 +354,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
goto err_map; goto err_map;
} }
clk_enable(wdt_clock); clk_prepare_enable(wdt_clock);
ret = s3c2410wdt_cpufreq_register(); ret = s3c2410wdt_cpufreq_register();
if (ret < 0) { if (ret < 0) {
...@@ -421,7 +421,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev) ...@@ -421,7 +421,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
s3c2410wdt_cpufreq_deregister(); s3c2410wdt_cpufreq_deregister();
err_clk: err_clk:
clk_disable(wdt_clock); clk_disable_unprepare(wdt_clock);
clk_put(wdt_clock); clk_put(wdt_clock);
wdt_clock = NULL; wdt_clock = NULL;
...@@ -445,7 +445,7 @@ static int s3c2410wdt_remove(struct platform_device *dev) ...@@ -445,7 +445,7 @@ static int s3c2410wdt_remove(struct platform_device *dev)
s3c2410wdt_cpufreq_deregister(); s3c2410wdt_cpufreq_deregister();
clk_disable(wdt_clock); clk_disable_unprepare(wdt_clock);
clk_put(wdt_clock); clk_put(wdt_clock);
wdt_clock = NULL; wdt_clock = NULL;
......
This diff is collapsed.
...@@ -9,33 +9,57 @@ ...@@ -9,33 +9,57 @@
/* /*
* Some address definitions for the Watchdog * Some address definitions for the Watchdog
*/ */
#define SP5100_WDT_MEM_MAP_SIZE 0x08 #define SP5100_WDT_MEM_MAP_SIZE 0x08
#define SP5100_WDT_CONTROL(base) ((base) + 0x00) /* Watchdog Control */ #define SP5100_WDT_CONTROL(base) ((base) + 0x00) /* Watchdog Control */
#define SP5100_WDT_COUNT(base) ((base) + 0x04) /* Watchdog Count */ #define SP5100_WDT_COUNT(base) ((base) + 0x04) /* Watchdog Count */
#define SP5100_WDT_START_STOP_BIT 1 #define SP5100_WDT_START_STOP_BIT (1 << 0)
#define SP5100_WDT_TRIGGER_BIT (1 << 7) #define SP5100_WDT_TRIGGER_BIT (1 << 7)
#define SP5100_PCI_WATCHDOG_MISC_REG 0x41
#define SP5100_PCI_WATCHDOG_DECODE_EN (1 << 3)
#define SP5100_PM_IOPORTS_SIZE 0x02 #define SP5100_PM_IOPORTS_SIZE 0x02
/* These two IO registers are hardcoded and there doesn't seem to be a way to /*
* These two IO registers are hardcoded and there doesn't seem to be a way to
* read them from a register. * read them from a register.
*/ */
/* For SP5100/SB7x0 chipset */
#define SP5100_IO_PM_INDEX_REG 0xCD6 #define SP5100_IO_PM_INDEX_REG 0xCD6
#define SP5100_IO_PM_DATA_REG 0xCD7 #define SP5100_IO_PM_DATA_REG 0xCD7
#define SP5100_SB_RESOURCE_MMIO_BASE 0x9C
#define SP5100_PM_WATCHDOG_CONTROL 0x69 #define SP5100_PM_WATCHDOG_CONTROL 0x69
#define SP5100_PM_WATCHDOG_BASE0 0x6C #define SP5100_PM_WATCHDOG_BASE 0x6C
#define SP5100_PM_WATCHDOG_BASE1 0x6D
#define SP5100_PM_WATCHDOG_BASE2 0x6E
#define SP5100_PM_WATCHDOG_BASE3 0x6F
#define SP5100_PM_WATCHDOG_FIRED (1 << 1) #define SP5100_PM_WATCHDOG_FIRED (1 << 1)
#define SP5100_PM_WATCHDOG_ACTION_RESET (1 << 2) #define SP5100_PM_WATCHDOG_ACTION_RESET (1 << 2)
#define SP5100_PM_WATCHDOG_DISABLE 1 #define SP5100_PCI_WATCHDOG_MISC_REG 0x41
#define SP5100_PCI_WATCHDOG_DECODE_EN (1 << 3)
#define SP5100_PM_WATCHDOG_DISABLE (1 << 0)
#define SP5100_PM_WATCHDOG_SECOND_RES (3 << 1) #define SP5100_PM_WATCHDOG_SECOND_RES (3 << 1)
#define SP5100_DEVNAME "SP5100 TCO"
/* For SB8x0(or later) chipset */
#define SB800_IO_PM_INDEX_REG 0xCD6
#define SB800_IO_PM_DATA_REG 0xCD7
#define SB800_PM_ACPI_MMIO_EN 0x24
#define SB800_PM_WATCHDOG_CONTROL 0x48
#define SB800_PM_WATCHDOG_BASE 0x48
#define SB800_PM_WATCHDOG_CONFIG 0x4C
#define SB800_PCI_WATCHDOG_DECODE_EN (1 << 0)
#define SB800_PM_WATCHDOG_DISABLE (1 << 2)
#define SB800_PM_WATCHDOG_SECOND_RES (3 << 0)
#define SB800_ACPI_MMIO_DECODE_EN (1 << 0)
#define SB800_ACPI_MMIO_SEL (1 << 2)
#define SB800_PM_WDT_MMIO_OFFSET 0xB00
#define SB800_DEVNAME "SB800 TCO"
...@@ -130,16 +130,10 @@ static int wdt_config(struct watchdog_device *wdd, bool ping) ...@@ -130,16 +130,10 @@ static int wdt_config(struct watchdog_device *wdd, bool ping)
int ret; int ret;
if (!ping) { if (!ping) {
ret = clk_prepare(wdt->clk);
if (ret) {
dev_err(&wdt->adev->dev, "clock prepare fail");
return ret;
}
ret = clk_enable(wdt->clk); ret = clk_prepare_enable(wdt->clk);
if (ret) { if (ret) {
dev_err(&wdt->adev->dev, "clock enable fail"); dev_err(&wdt->adev->dev, "clock enable fail");
clk_unprepare(wdt->clk);
return ret; return ret;
} }
} }
...@@ -190,8 +184,7 @@ static int wdt_disable(struct watchdog_device *wdd) ...@@ -190,8 +184,7 @@ static int wdt_disable(struct watchdog_device *wdd)
readl_relaxed(wdt->base + WDTLOCK); readl_relaxed(wdt->base + WDTLOCK);
spin_unlock(&wdt->lock); spin_unlock(&wdt->lock);
clk_disable(wdt->clk); clk_disable_unprepare(wdt->clk);
clk_unprepare(wdt->clk);
return 0; return 0;
} }
......
...@@ -22,26 +22,12 @@ ...@@ -22,26 +22,12 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/i2c/twl.h> #include <linux/i2c/twl.h>
#define TWL4030_WATCHDOG_CFG_REG_OFFS 0x3 #define TWL4030_WATCHDOG_CFG_REG_OFFS 0x3
#define TWL4030_WDT_STATE_OPEN 0x1
#define TWL4030_WDT_STATE_ACTIVE 0x8
static struct platform_device *twl4030_wdt_dev;
struct twl4030_wdt {
struct miscdevice miscdev;
int timer_margin;
unsigned long state;
};
static bool nowayout = WATCHDOG_NOWAYOUT; static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0); module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
...@@ -49,175 +35,75 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " ...@@ -49,175 +35,75 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
static int twl4030_wdt_write(unsigned char val) static int twl4030_wdt_write(unsigned char val)
{ {
return twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, val, return twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, val,
TWL4030_WATCHDOG_CFG_REG_OFFS); TWL4030_WATCHDOG_CFG_REG_OFFS);
} }
static int twl4030_wdt_enable(struct twl4030_wdt *wdt) static int twl4030_wdt_start(struct watchdog_device *wdt)
{ {
return twl4030_wdt_write(wdt->timer_margin + 1); return twl4030_wdt_write(wdt->timeout + 1);
} }
static int twl4030_wdt_disable(struct twl4030_wdt *wdt) static int twl4030_wdt_stop(struct watchdog_device *wdt)
{ {
return twl4030_wdt_write(0); return twl4030_wdt_write(0);
} }
static int twl4030_wdt_set_timeout(struct twl4030_wdt *wdt, int timeout) static int twl4030_wdt_set_timeout(struct watchdog_device *wdt,
{ unsigned int timeout)
if (timeout < 0 || timeout > 30) {
dev_warn(wdt->miscdev.parent,
"Timeout can only be in the range [0-30] seconds");
return -EINVAL;
}
wdt->timer_margin = timeout;
return twl4030_wdt_enable(wdt);
}
static ssize_t twl4030_wdt_write_fop(struct file *file,
const char __user *data, size_t len, loff_t *ppos)
{
struct twl4030_wdt *wdt = file->private_data;
if (len)
twl4030_wdt_enable(wdt);
return len;
}
static long twl4030_wdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{ {
void __user *argp = (void __user *)arg; wdt->timeout = timeout;
int __user *p = argp;
int new_margin;
struct twl4030_wdt *wdt = file->private_data;
static const struct watchdog_info twl4030_wd_ident = {
.identity = "TWL4030 Watchdog",
.options = WDIOF_SETTIMEOUT,
.firmware_version = 0,
};
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &twl4030_wd_ident,
sizeof(twl4030_wd_ident)) ? -EFAULT : 0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
twl4030_wdt_enable(wdt);
break;
case WDIOC_SETTIMEOUT:
if (get_user(new_margin, p))
return -EFAULT;
if (twl4030_wdt_set_timeout(wdt, new_margin))
return -EINVAL;
return put_user(wdt->timer_margin, p);
case WDIOC_GETTIMEOUT:
return put_user(wdt->timer_margin, p);
default:
return -ENOTTY;
}
return 0; return 0;
} }
static int twl4030_wdt_open(struct inode *inode, struct file *file) static const struct watchdog_info twl4030_wdt_info = {
{ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
struct twl4030_wdt *wdt = platform_get_drvdata(twl4030_wdt_dev); .identity = "TWL4030 Watchdog",
};
/* /dev/watchdog can only be opened once */
if (test_and_set_bit(0, &wdt->state))
return -EBUSY;
wdt->state |= TWL4030_WDT_STATE_ACTIVE;
file->private_data = (void *) wdt;
twl4030_wdt_enable(wdt);
return nonseekable_open(inode, file);
}
static int twl4030_wdt_release(struct inode *inode, struct file *file)
{
struct twl4030_wdt *wdt = file->private_data;
if (nowayout) {
dev_alert(wdt->miscdev.parent,
"Unexpected close, watchdog still running!\n");
twl4030_wdt_enable(wdt);
} else {
if (twl4030_wdt_disable(wdt))
return -EFAULT;
wdt->state &= ~TWL4030_WDT_STATE_ACTIVE;
}
clear_bit(0, &wdt->state);
return 0;
}
static const struct file_operations twl4030_wdt_fops = { static const struct watchdog_ops twl4030_wdt_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .start = twl4030_wdt_start,
.open = twl4030_wdt_open, .stop = twl4030_wdt_stop,
.release = twl4030_wdt_release, .set_timeout = twl4030_wdt_set_timeout,
.unlocked_ioctl = twl4030_wdt_ioctl,
.write = twl4030_wdt_write_fop,
}; };
static int twl4030_wdt_probe(struct platform_device *pdev) static int twl4030_wdt_probe(struct platform_device *pdev)
{ {
int ret = 0; int ret = 0;
struct twl4030_wdt *wdt; struct watchdog_device *wdt;
wdt = kzalloc(sizeof(struct twl4030_wdt), GFP_KERNEL); wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
if (!wdt) if (!wdt)
return -ENOMEM; return -ENOMEM;
wdt->state = 0; wdt->info = &twl4030_wdt_info;
wdt->timer_margin = 30; wdt->ops = &twl4030_wdt_ops;
wdt->miscdev.parent = &pdev->dev; wdt->status = 0;
wdt->miscdev.fops = &twl4030_wdt_fops; wdt->timeout = 30;
wdt->miscdev.minor = WATCHDOG_MINOR; wdt->min_timeout = 1;
wdt->miscdev.name = "watchdog"; wdt->max_timeout = 30;
watchdog_set_nowayout(wdt, nowayout);
platform_set_drvdata(pdev, wdt); platform_set_drvdata(pdev, wdt);
twl4030_wdt_dev = pdev; twl4030_wdt_stop(wdt);
twl4030_wdt_disable(wdt);
ret = misc_register(&wdt->miscdev); ret = watchdog_register_device(wdt);
if (ret) { if (ret) {
dev_err(wdt->miscdev.parent,
"Failed to register misc device\n");
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
kfree(wdt);
twl4030_wdt_dev = NULL;
return ret; return ret;
} }
return 0; return 0;
} }
static int twl4030_wdt_remove(struct platform_device *pdev) static int twl4030_wdt_remove(struct platform_device *pdev)
{ {
struct twl4030_wdt *wdt = platform_get_drvdata(pdev); struct watchdog_device *wdt = platform_get_drvdata(pdev);
if (wdt->state & TWL4030_WDT_STATE_ACTIVE)
if (twl4030_wdt_disable(wdt))
return -EFAULT;
wdt->state &= ~TWL4030_WDT_STATE_ACTIVE;
misc_deregister(&wdt->miscdev);
watchdog_unregister_device(wdt);
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
kfree(wdt);
twl4030_wdt_dev = NULL;
return 0; return 0;
} }
...@@ -225,18 +111,18 @@ static int twl4030_wdt_remove(struct platform_device *pdev) ...@@ -225,18 +111,18 @@ static int twl4030_wdt_remove(struct platform_device *pdev)
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int twl4030_wdt_suspend(struct platform_device *pdev, pm_message_t state) static int twl4030_wdt_suspend(struct platform_device *pdev, pm_message_t state)
{ {
struct twl4030_wdt *wdt = platform_get_drvdata(pdev); struct watchdog_device *wdt = platform_get_drvdata(pdev);
if (wdt->state & TWL4030_WDT_STATE_ACTIVE) if (watchdog_active(wdt))
return twl4030_wdt_disable(wdt); return twl4030_wdt_stop(wdt);
return 0; return 0;
} }
static int twl4030_wdt_resume(struct platform_device *pdev) static int twl4030_wdt_resume(struct platform_device *pdev)
{ {
struct twl4030_wdt *wdt = platform_get_drvdata(pdev); struct watchdog_device *wdt = platform_get_drvdata(pdev);
if (wdt->state & TWL4030_WDT_STATE_ACTIVE) if (watchdog_active(wdt))
return twl4030_wdt_enable(wdt); return twl4030_wdt_start(wdt);
return 0; return 0;
} }
...@@ -260,6 +146,5 @@ module_platform_driver(twl4030_wdt_driver); ...@@ -260,6 +146,5 @@ module_platform_driver(twl4030_wdt_driver);
MODULE_AUTHOR("Nokia Corporation"); MODULE_AUTHOR("Nokia Corporation");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
MODULE_ALIAS("platform:twl4030_wdt"); MODULE_ALIAS("platform:twl4030_wdt");
...@@ -129,7 +129,7 @@ static inline void *watchdog_get_drvdata(struct watchdog_device *wdd) ...@@ -129,7 +129,7 @@ static inline void *watchdog_get_drvdata(struct watchdog_device *wdd)
return wdd->driver_data; return wdd->driver_data;
} }
/* drivers/watchdog/core/watchdog_core.c */ /* drivers/watchdog/watchdog_core.c */
extern int watchdog_register_device(struct watchdog_device *); extern int watchdog_register_device(struct watchdog_device *);
extern void watchdog_unregister_device(struct watchdog_device *); extern void watchdog_unregister_device(struct watchdog_device *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment