Convert driver from legacy to use the watchdog core and platform driver. Add new pnx833x_wdt_device platform device for pnx833x_wdt driver. Signed-off-by: Sergey Yasinsky <seregajsv@xxxxxxxxx> --- arch/mips/pnx833x/common/platform.c | 6 + drivers/watchdog/Kconfig | 2 +- drivers/watchdog/pnx833x_wdt.c | 244 +++++++++------------------- 3 files changed, 80 insertions(+), 172 deletions(-) diff --git a/arch/mips/pnx833x/common/platform.c b/arch/mips/pnx833x/common/platform.c index 5fa0373f1c9e..3371f860efc2 100644 --- a/arch/mips/pnx833x/common/platform.c +++ b/arch/mips/pnx833x/common/platform.c @@ -207,12 +207,18 @@ static struct platform_device pnx833x_flash_nand = { }, }; +static struct platform_device pnx833x_wdt_device = { + .name = "pnx833x_wdt", + .id = -1, +}; + static struct platform_device *pnx833x_platform_devices[] __initdata = { &pnx833x_uart_device, &pnx833x_usb_ehci_device, &pnx833x_ethernet_device, &pnx833x_sata_device, &pnx833x_flash_nand, + &pnx833x_wdt_device, }; static int __init pnx833x_platform_init(void) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index ab7aad5a1e69..e9b86dbbb8fa 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1686,7 +1686,7 @@ config WDT_MTX1 config PNX833X_WDT tristate "PNX833x Hardware Watchdog" depends on SOC_PNX8335 - depends on BROKEN + select WATCHDOG_CORE help Hardware driver for the PNX833x's watchdog. This is a watchdog timer that will reboot the machine after a programmable diff --git a/drivers/watchdog/pnx833x_wdt.c b/drivers/watchdog/pnx833x_wdt.c index 4097d076aab8..8896e1cb109e 100644 --- a/drivers/watchdog/pnx833x_wdt.c +++ b/drivers/watchdog/pnx833x_wdt.c @@ -17,21 +17,11 @@ #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/fs.h> -#include <linux/mm.h> -#include <linux/miscdevice.h> +#include <linux/platform_device.h> #include <linux/watchdog.h> -#include <linux/notifier.h> -#include <linux/reboot.h> -#include <linux/init.h> #include <asm/mach-pnx833x/pnx833x.h> -#define WATCHDOG_TIMEOUT 30 /* 30 sec Maximum timeout */ #define WATCHDOG_COUNT_FREQUENCY 68000000U /* Watchdog counts at 68MHZ. */ -#define PNX_WATCHDOG_TIMEOUT (WATCHDOG_TIMEOUT * WATCHDOG_COUNT_FREQUENCY) -#define PNX_TIMEOUT_VALUE 2040000000U /** CONFIG block */ #define PNX833X_CONFIG (0x07000U) @@ -43,13 +33,11 @@ #define PNX833X_RESET (0x08000U) #define PNX833X_RESET_CONFIG (0x08) -static int pnx833x_wdt_alive; - -/* Set default timeout in MHZ.*/ -static int pnx833x_wdt_timeout = PNX_WATCHDOG_TIMEOUT; +#define WATCHDOG_DEFAULT_TIMEOUT 30 +static int pnx833x_wdt_timeout; module_param(pnx833x_wdt_timeout, int, 0); -MODULE_PARM_DESC(timeout, "Watchdog timeout in Mhz. (68Mhz clock), default=" - __MODULE_STRING(PNX_TIMEOUT_VALUE) "(30 seconds)."); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=" + __MODULE_STRING(WATCHDOG_DEFAULT_TIMEOUT) ")"); static bool nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, bool, 0); @@ -62,21 +50,21 @@ module_param(start_enabled, int, 0); MODULE_PARM_DESC(start_enabled, "Watchdog is started on module insertion " "(default=" __MODULE_STRING(START_DEFAULT) ")"); -static void pnx833x_wdt_start(void) +static int pnx833x_wdt_start(struct watchdog_device *wdd) { /* Enable watchdog causing reset. */ PNX833X_REG(PNX833X_RESET + PNX833X_RESET_CONFIG) |= 0x1; /* Set timeout.*/ - PNX833X_REG(PNX833X_CONFIG + - PNX833X_CONFIG_CPU_WATCHDOG_COMPARE) = pnx833x_wdt_timeout; + PNX833X_REG(PNX833X_CONFIG + PNX833X_CONFIG_CPU_WATCHDOG_COMPARE) = + wdd->timeout * WATCHDOG_COUNT_FREQUENCY; /* Enable watchdog. */ PNX833X_REG(PNX833X_CONFIG + PNX833X_CONFIG_CPU_COUNTERS_CONTROL) |= 0x1; - pr_info("Started watchdog timer\n"); + return 0; } -static void pnx833x_wdt_stop(void) +static int pnx833x_wdt_stop(struct watchdog_device *wdd) { /* Disable watchdog causing reset. */ PNX833X_REG(PNX833X_RESET + PNX833X_CONFIG) &= 0xFFFFFFFE; @@ -84,193 +72,107 @@ static void pnx833x_wdt_stop(void) PNX833X_REG(PNX833X_CONFIG + PNX833X_CONFIG_CPU_COUNTERS_CONTROL) &= 0xFFFFFFFE; - pr_info("Stopped watchdog timer\n"); -} - -static void pnx833x_wdt_ping(void) -{ - PNX833X_REG(PNX833X_CONFIG + - PNX833X_CONFIG_CPU_WATCHDOG_COMPARE) = pnx833x_wdt_timeout; -} - -/* - * Allow only one person to hold it open - */ -static int pnx833x_wdt_open(struct inode *inode, struct file *file) -{ - if (test_and_set_bit(0, &pnx833x_wdt_alive)) - return -EBUSY; - - if (nowayout) - __module_get(THIS_MODULE); - - /* Activate timer */ - if (!start_enabled) - pnx833x_wdt_start(); - - pnx833x_wdt_ping(); - - pr_info("Started watchdog timer\n"); - - return stream_open(inode, file); -} - -static int pnx833x_wdt_release(struct inode *inode, struct file *file) -{ - /* Shut off the timer. - * Lock it in if it's a module and we defined ...NOWAYOUT */ - if (!nowayout) - pnx833x_wdt_stop(); /* Turn the WDT off */ - - clear_bit(0, &pnx833x_wdt_alive); return 0; } -static ssize_t pnx833x_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) +static int pnx833x_wdt_ping(struct watchdog_device *wdd) { - /* Refresh the timer. */ - if (len) - pnx833x_wdt_ping(); + PNX833X_REG(PNX833X_CONFIG + PNX833X_CONFIG_CPU_WATCHDOG_COMPARE) = + wdd->timeout * WATCHDOG_COUNT_FREQUENCY; - return len; + return 0; } -static long pnx833x_wdt_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) +static int pnx833x_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t) { - int options, new_timeout = 0; - uint32_t timeout, timeout_left = 0; - - static const struct watchdog_info ident = { - .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT, - .firmware_version = 0, - .identity = "Hardware Watchdog for PNX833x", - }; - - switch (cmd) { - default: - return -ENOTTY; - - case WDIOC_GETSUPPORT: - if (copy_to_user((struct watchdog_info *)arg, - &ident, sizeof(ident))) - return -EFAULT; - return 0; - - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - return put_user(0, (int *)arg); - - case WDIOC_SETOPTIONS: - if (get_user(options, (int *)arg)) - return -EFAULT; - - if (options & WDIOS_DISABLECARD) - pnx833x_wdt_stop(); - - if (options & WDIOS_ENABLECARD) - pnx833x_wdt_start(); - - return 0; - - case WDIOC_KEEPALIVE: - pnx833x_wdt_ping(); - return 0; - - case WDIOC_SETTIMEOUT: - { - if (get_user(new_timeout, (int *)arg)) - return -EFAULT; - - pnx833x_wdt_timeout = new_timeout; - PNX833X_REG(PNX833X_CONFIG + - PNX833X_CONFIG_CPU_WATCHDOG_COMPARE) = new_timeout; - return put_user(new_timeout, (int *)arg); - } - - case WDIOC_GETTIMEOUT: - timeout = PNX833X_REG(PNX833X_CONFIG + - PNX833X_CONFIG_CPU_WATCHDOG_COMPARE); - return put_user(timeout, (int *)arg); - - case WDIOC_GETTIMELEFT: - timeout_left = PNX833X_REG(PNX833X_CONFIG + - PNX833X_CONFIG_CPU_WATCHDOG); - return put_user(timeout_left, (int *)arg); - - } + PNX833X_REG(PNX833X_CONFIG + PNX833X_CONFIG_CPU_WATCHDOG_COMPARE) = + t * WATCHDOG_COUNT_FREQUENCY; + wdd->timeout = t; + return 0; } -static int pnx833x_wdt_notify_sys(struct notifier_block *this, - unsigned long code, void *unused) +static unsigned int pnx833x_wdt_get_timeleft(struct watchdog_device *wdd) { - if (code == SYS_DOWN || code == SYS_HALT) - pnx833x_wdt_stop(); /* Turn the WDT off */ + unsigned int timeout = PNX833X_REG(PNX833X_CONFIG + + PNX833X_CONFIG_CPU_WATCHDOG_COMPARE); + unsigned int curval = PNX833X_REG(PNX833X_CONFIG + + PNX833X_CONFIG_CPU_WATCHDOG); - return NOTIFY_DONE; + return (timeout - curval) / WATCHDOG_COUNT_FREQUENCY; } -static const struct file_operations pnx833x_wdt_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .write = pnx833x_wdt_write, - .unlocked_ioctl = pnx833x_wdt_ioctl, - .compat_ioctl = compat_ptr_ioctl, - .open = pnx833x_wdt_open, - .release = pnx833x_wdt_release, +static const struct watchdog_info pnx833x_wdt_ident = { + .identity = "PNX833x Watchdog Timer", + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE | WDIOF_CARDRESET }; -static struct miscdevice pnx833x_wdt_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &pnx833x_wdt_fops, +static struct watchdog_ops pnx833x_wdt_ops = { + .owner = THIS_MODULE, + .start = pnx833x_wdt_start, + .stop = pnx833x_wdt_stop, + .ping = pnx833x_wdt_ping, + .set_timeout = pnx833x_wdt_set_timeout, + .get_timeleft = pnx833x_wdt_get_timeleft, }; -static struct notifier_block pnx833x_wdt_notifier = { - .notifier_call = pnx833x_wdt_notify_sys, -}; - -static int __init watchdog_init(void) +static int pnx833x_wdt_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; + struct watchdog_device *wdd; int ret, cause; + wdd = devm_kzalloc(dev, sizeof(*wdd), GFP_KERNEL); + if (!wdd) + return -ENOMEM; + platform_set_drvdata(pdev, wdd); + wdd->info = &pnx833x_wdt_ident; + wdd->ops = &pnx833x_wdt_ops; + wdd->min_timeout = 1; + wdd->max_timeout = U32_MAX / WATCHDOG_COUNT_FREQUENCY; + wdd->timeout = WATCHDOG_DEFAULT_TIMEOUT; + wdd->parent = dev; + watchdog_set_nowayout(wdd, nowayout); + watchdog_init_timeout(wdd, pnx833x_wdt_timeout, dev); + /* Lets check the reason for the reset.*/ cause = PNX833X_REG(PNX833X_RESET); /*If bit 31 is set then watchdog was cause of reset.*/ - if (cause & 0x80000000) { - pr_info("The system was previously reset due to the watchdog firing - please investigate...\n"); - } + if (cause & 0x80000000) + wdd->bootstatus = WDIOF_CARDRESET; - ret = register_reboot_notifier(&pnx833x_wdt_notifier); - if (ret) { - pr_err("cannot register reboot notifier (err=%d)\n", ret); - return ret; + if (start_enabled) { + pnx833x_wdt_start(wdd); + set_bit(WDOG_HW_RUNNING, &wdd->status); } - ret = misc_register(&pnx833x_wdt_miscdev); + ret = watchdog_register_device(wdd); if (ret) { - pr_err("cannot register miscdev on minor=%d (err=%d)\n", - WATCHDOG_MINOR, ret); - unregister_reboot_notifier(&pnx833x_wdt_notifier); + pr_err("Failed to register watchdog device"); return ret; } - pr_info("Hardware Watchdog Timer for PNX833x: Version 0.1\n"); - - if (start_enabled) - pnx833x_wdt_start(); + pr_info("Hardware Watchdog Timer for PNX833x\n"); return 0; } -static void __exit watchdog_exit(void) +static int pnx833x_wdt_remove(struct platform_device *pdev) { - misc_deregister(&pnx833x_wdt_miscdev); - unregister_reboot_notifier(&pnx833x_wdt_notifier); + struct watchdog_device *wdd = platform_get_drvdata(pdev); + + watchdog_unregister_device(wdd); + return 0; } -module_init(watchdog_init); -module_exit(watchdog_exit); +static struct platform_driver pnx833x_wdt_driver = { + .probe = pnx833x_wdt_probe, + .remove = pnx833x_wdt_remove, + .driver = { + .name = "pnx833x_wdt", + } +}; + +module_platform_driver(pnx833x_wdt_driver); MODULE_AUTHOR("Daniel Laird/Andre McCurdy"); MODULE_DESCRIPTION("Hardware Watchdog Device for PNX833x"); -- 2.26.2