* [PATCH V5 05/10] MIPS: lantiq: add watchdog support [not found] <1301470076-17279-1-git-send-email-blogic@openwrt.org> @ 2011-03-30 7:27 ` John Crispin 2011-03-30 9:36 ` Wim Van Sebroeck 2011-04-07 14:31 ` Sergei Shtylyov 0 siblings, 2 replies; 5+ messages in thread From: John Crispin @ 2011-03-30 7:27 UTC (permalink / raw) To: Ralf Baechle Cc: John Crispin, Ralph Hempel, Wim Van Sebroeck, linux-mips, linux-watchdog This patch adds the driver for the watchdog found inside the Lantiq SoC family. Signed-off-by: John Crispin <blogic@openwrt.org> Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> Cc: Wim Van Sebroeck <wim@iguana.be> Cc: linux-mips@linux-mips.org Cc: linux-watchdog@vger.kernel.org --- Changes in V2 * add comments to explain register access * cleanup resource allocation * cleanup clock handling * whitespace fixes Changes in V3 * whitespace * change __iomem void to void __iomem * typo fixes * comment style * fix exit path in init function Changes in V4 * fixes register offsets (we use a smaller memory window) * typo in the comments * add __init to probe function drivers/watchdog/Kconfig | 6 + drivers/watchdog/Makefile | 1 + drivers/watchdog/lantiq_wdt.c | 217 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 224 insertions(+), 0 deletions(-) create mode 100644 drivers/watchdog/lantiq_wdt.c diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index b69d714..cee7738 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -990,6 +990,12 @@ config BCM63XX_WDT To compile this driver as a loadable module, choose M here. The module will be called bcm63xx_wdt. +config LANTIQ_WDT + tristate "Lantiq SoC watchdog" + depends on LANTIQ + help + Hardware driver for the Lantiq SoC Watchdog Timer. + # PARISC Architecture # POWERPC Architecture diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index d520bf9..0d84e48 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -123,6 +123,7 @@ obj-$(CONFIG_AR7_WDT) += ar7_wdt.o obj-$(CONFIG_TXX9_WDT) += txx9wdt.o obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o +obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o # PARISC Architecture diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c new file mode 100644 index 0000000..0a78dfb --- /dev/null +++ b/drivers/watchdog/lantiq_wdt.c @@ -0,0 +1,217 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Based on EP93xx wdt driver + */ + +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/platform_device.h> +#include <linux/uaccess.h> +#include <linux/clk.h> +#include <linux/io.h> + +#include <lantiq.h> + +/* Section 3.4 of the datasheet + * The password sequence protects the WDT control register from unintended + * write actions, which might cause malfunction of the WDT. + * + * essentially the following two magic passwords need to be written to allow + * io access to the wdt core + */ +#define LTQ_WDT_PW1 0x00BE0000 +#define LTQ_WDT_PW2 0x00DC0000 + +#define LTQ_WDT_CR 0x0 /* watchdog control register */ +#define LTQ_WDT_SR 0x8 /* watchdog status register */ + +#define LTQ_WDT_SR_EN (0x1 << 31) /* enable bit */ +#define LTQ_WDT_SR_PWD (0x3 << 26) /* turn on power */ +#define LTQ_WDT_SR_CLKDIV (0x3 << 24) /* turn on clock and set */ + /* divider to 0x40000 */ +#define LTQ_WDT_DIVIDER 0x40000 +#define LTQ_MAX_TIMEOUT ((1 << 16) - 1) /* the reload field is 16 bit */ + +#ifndef CONFIG_WATCHDOG_NOWAYOUT +static int ltq_wdt_ok_to_close; +#endif + +static int ltq_wdt_timeout = 30; +static void __iomem *ltq_wdt_membase; +static unsigned long ltq_io_region_clk_rate; + +static void +ltq_wdt_enable(unsigned int timeout) +{ + timeout = ((timeout * (ltq_io_region_clk_rate / LTQ_WDT_DIVIDER)) + + 0x1000); + if (timeout > LTQ_MAX_TIMEOUT) + timeout = LTQ_MAX_TIMEOUT; + + /* write the first password magic */ + ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR); + /* write the second magic plus the configuration and new timeout */ + ltq_w32(LTQ_WDT_SR_EN | LTQ_WDT_SR_PWD | LTQ_WDT_SR_CLKDIV | + LTQ_WDT_PW2 | timeout, ltq_wdt_membase + LTQ_WDT_CR); +} + +static void +ltq_wdt_disable(void) +{ +#ifndef CONFIG_WATCHDOG_NOWAYOUT + ltq_wdt_ok_to_close = 0; +#endif + /* write the first password magic */ + ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR); + /* write the second password magic with no config + * this turns the watchdog off + */ + ltq_w32(LTQ_WDT_PW2, ltq_wdt_membase + LTQ_WDT_CR); +} + +static ssize_t +ltq_wdt_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + size_t i; + + if (!len) + return 0; +#ifndef CONFIG_WATCHDOG_NOWAYOUT + for (i = 0; i != len; i++) { + char c; + + if (get_user(c, data + i)) + return -EFAULT; + if (c == 'V') + ltq_wdt_ok_to_close = 1; + } +#endif + ltq_wdt_enable(ltq_wdt_timeout); + return len; +} + +static struct watchdog_info ident = { + .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, + .identity = "ltq_wdt", +}; + +static long +ltq_wdt_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret = -ENOTTY; + + switch (cmd) { + case WDIOC_GETSUPPORT: + ret = copy_to_user((struct watchdog_info __user *)arg, &ident, + sizeof(ident)) ? -EFAULT : 0; + break; + + case WDIOC_GETTIMEOUT: + ret = put_user(ltq_wdt_timeout, (int __user *)arg); + break; + + case WDIOC_SETTIMEOUT: + ret = get_user(ltq_wdt_timeout, (int __user *)arg); + if (!ret) + ltq_wdt_enable(ltq_wdt_timeout); + break; + + case WDIOC_KEEPALIVE: + ltq_wdt_enable(ltq_wdt_timeout); + ret = 0; + break; + } + return ret; +} + +static int +ltq_wdt_open(struct inode *inode, struct file *file) +{ + ltq_wdt_enable(ltq_wdt_timeout); + return nonseekable_open(inode, file); +} + +static int +ltq_wdt_release(struct inode *inode, struct file *file) +{ +#ifndef CONFIG_WATCHDOG_NOWAYOUT + if (ltq_wdt_ok_to_close) + ltq_wdt_disable(); + else +#endif + pr_err("ltq_wdt: watchdog closed without warning\n"); + return 0; +} + +static const struct file_operations ltq_wdt_fops = { + .owner = THIS_MODULE, + .write = ltq_wdt_write, + .unlocked_ioctl = ltq_wdt_ioctl, + .open = ltq_wdt_open, + .release = ltq_wdt_release, + .llseek = no_llseek, +}; + +static struct miscdevice ltq_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = <q_wdt_fops, +}; + +static int __init +ltq_wdt_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct clk *clk; + + if (!res) { + dev_err(&pdev->dev, "cannot obtain I/O memory region"); + return -ENOENT; + } + res = devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), dev_name(&pdev->dev)); + if (!res) { + dev_err(&pdev->dev, "cannot request I/O memory region"); + return -EBUSY; + } + ltq_wdt_membase = devm_ioremap_nocache(&pdev->dev, res->start, + resource_size(res)); + if (!ltq_wdt_membase) { + dev_err(&pdev->dev, "cannot remap I/O memory region\n"); + return -ENOMEM; + } + /* we do not need to enable the clock as it is always running */ + clk = clk_get(&pdev->dev, "io"); + BUG_ON(!clk); + ltq_io_region_clk_rate = clk_get_rate(clk); + clk_put(clk); + return misc_register(<q_wdt_miscdev); +} + +static struct platform_driver ltq_wdt_driver = { + .driver = { + .name = "ltq_wdt", + .owner = THIS_MODULE, + }, +}; + +static int __init +init_ltq_wdt(void) +{ + return platform_driver_probe(<q_wdt_driver, ltq_wdt_probe); +} + +module_init(init_ltq_wdt); + +MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); +MODULE_DESCRIPTION("Lantiq SoC Watchdog"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); -- 1.7.2.3 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH V5 05/10] MIPS: lantiq: add watchdog support 2011-03-30 7:27 ` [PATCH V5 05/10] MIPS: lantiq: add watchdog support John Crispin @ 2011-03-30 9:36 ` Wim Van Sebroeck 2011-03-30 9:41 ` John Crispin 2011-04-04 9:24 ` John Crispin 2011-04-07 14:31 ` Sergei Shtylyov 1 sibling, 2 replies; 5+ messages in thread From: Wim Van Sebroeck @ 2011-03-30 9:36 UTC (permalink / raw) To: John Crispin; +Cc: Ralf Baechle, Ralph Hempel, linux-mips, linux-watchdog Hi John, > Changes in V2 > * add comments to explain register access > * cleanup resource allocation > * cleanup clock handling > * whitespace fixes > > Changes in V3 > * whitespace > * change __iomem void to void __iomem > * typo fixes > * comment style > * fix exit path in init function > > Changes in V4 > * fixes register offsets (we use a smaller memory window) > * typo in the comments > * add __init to probe function What were the changes for V5? > +#ifndef CONFIG_WATCHDOG_NOWAYOUT > +static int ltq_wdt_ok_to_close; > +#endif ... > +static void > +ltq_wdt_disable(void) > +{ > +#ifndef CONFIG_WATCHDOG_NOWAYOUT > + ltq_wdt_ok_to_close = 0; > +#endif > + /* write the first password magic */ > + ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR); > + /* write the second password magic with no config > + * this turns the watchdog off > + */ > + ltq_w32(LTQ_WDT_PW2, ltq_wdt_membase + LTQ_WDT_CR); > +} Don't like this ifdef/ifndef stuff. The nowayout things can be done in the /dev/watchdog handling. > +static long > +ltq_wdt_ioctl(struct file *file, > + unsigned int cmd, unsigned long arg) > +{ > + int ret = -ENOTTY; > + > + switch (cmd) { > + case WDIOC_GETSUPPORT: > + ret = copy_to_user((struct watchdog_info __user *)arg, &ident, > + sizeof(ident)) ? -EFAULT : 0; > + break; > + > + case WDIOC_GETTIMEOUT: > + ret = put_user(ltq_wdt_timeout, (int __user *)arg); > + break; > + > + case WDIOC_SETTIMEOUT: > + ret = get_user(ltq_wdt_timeout, (int __user *)arg); > + if (!ret) > + ltq_wdt_enable(ltq_wdt_timeout); > + break; > + > + case WDIOC_KEEPALIVE: > + ltq_wdt_enable(ltq_wdt_timeout); > + ret = 0; > + break; > + } > + return ret; > +} Please add WDIOC_GETSTATUS and WDIOC_GETBOOTSTATUS iotcl calls. > +static int > +ltq_wdt_open(struct inode *inode, struct file *file) > +{ > + ltq_wdt_enable(ltq_wdt_timeout); > + return nonseekable_open(inode, file); > +} > + > +static int > +ltq_wdt_release(struct inode *inode, struct file *file) > +{ > +#ifndef CONFIG_WATCHDOG_NOWAYOUT > + if (ltq_wdt_ok_to_close) > + ltq_wdt_disable(); > + else > +#endif > + pr_err("ltq_wdt: watchdog closed without warning\n"); > + return 0; > +} Please add the code to make sure that /dev/watchdog can be opened once. The rest I will look into at a later moment. Kind regards, Wim. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH V5 05/10] MIPS: lantiq: add watchdog support 2011-03-30 9:36 ` Wim Van Sebroeck @ 2011-03-30 9:41 ` John Crispin 2011-04-04 9:24 ` John Crispin 1 sibling, 0 replies; 5+ messages in thread From: John Crispin @ 2011-03-30 9:41 UTC (permalink / raw) To: Wim Van Sebroeck; +Cc: Ralf Baechle, Ralph Hempel, linux-mips, linux-watchdog Hi, >> * add __init to probe function >> > What were the changes for V5? > > v5 was related to irq handling in the mips specific code. the wdt did not have changes between v4 and v5 thanks for the comments, i will fold them into the next series John ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH V5 05/10] MIPS: lantiq: add watchdog support 2011-03-30 9:36 ` Wim Van Sebroeck 2011-03-30 9:41 ` John Crispin @ 2011-04-04 9:24 ` John Crispin 1 sibling, 0 replies; 5+ messages in thread From: John Crispin @ 2011-04-04 9:24 UTC (permalink / raw) To: Wim Van Sebroeck; +Cc: Ralf Baechle, Ralph Hempel, linux-watchdog Hi Wim, some questions inline >> +ltq_wdt_disable(void) >> +{ >> +#ifndef CONFIG_WATCHDOG_NOWAYOUT >> + ltq_wdt_ok_to_close = 0; >> +#endif >> + /* write the first password magic */ >> + ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR); >> + /* write the second password magic with no config >> + * this turns the watchdog off >> + */ >> + ltq_w32(LTQ_WDT_PW2, ltq_wdt_membase + LTQ_WDT_CR); >> +} >> > Don't like this ifdef/ifndef stuff. The nowayout things can be done in the /dev/watchdog handling. > > Sorry i am not sure what you mean by "can be done in the /dev/watchdog handling". could you be so kind and elaborate. looking at some of the other drivers, there seem to be 2 strategies for this. 1) using the #ifdef 2) using a module parameter do you mean the later ? > Please add the code to make sure that /dev/watchdog can be opened once. > > Do you mean "only" once ? thanks for the clarification, John ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH V5 05/10] MIPS: lantiq: add watchdog support 2011-03-30 7:27 ` [PATCH V5 05/10] MIPS: lantiq: add watchdog support John Crispin 2011-03-30 9:36 ` Wim Van Sebroeck @ 2011-04-07 14:31 ` Sergei Shtylyov 1 sibling, 0 replies; 5+ messages in thread From: Sergei Shtylyov @ 2011-04-07 14:31 UTC (permalink / raw) To: John Crispin Cc: Ralf Baechle, Ralph Hempel, Wim Van Sebroeck, linux-mips, linux-watchdog Hello. John Crispin wrote: > This patch adds the driver for the watchdog found inside the Lantiq SoC family. > Signed-off-by: John Crispin <blogic@openwrt.org> > Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> > Cc: Wim Van Sebroeck <wim@iguana.be> > Cc: linux-mips@linux-mips.org > Cc: linux-watchdog@vger.kernel.org > diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c > new file mode 100644 > index 0000000..0a78dfb > --- /dev/null > +++ b/drivers/watchdog/lantiq_wdt.c > @@ -0,0 +1,217 @@ [...] > +/* Section 3.4 of the datasheet > + * The password sequence protects the WDT control register from unintended > + * write actions, which might cause malfunction of the WDT. > + * > + * essentially the following two magic passwords need to be written to allow > + * io access to the wdt core s/io/IO/, s/wdt/WDT. Be consistent. :-) > +static void > +ltq_wdt_enable(unsigned int timeout) This function is always called with 'ltw_wdt_timeout' as a parameter. Seems better to use it internally, and not pass it every time. > +{ > + timeout = ((timeout * (ltq_io_region_clk_rate / LTQ_WDT_DIVIDER)) > + + 0x1000); The parens around rvalue are not needed. [...] > +static ssize_t > +ltq_wdt_write(struct file *file, const char __user *data, > + size_t len, loff_t *ppos) > +{ > + size_t i; > + > + if (!len) > + return 0; > +#ifndef CONFIG_WATCHDOG_NOWAYOUT Er, Documentation/CodingStyle asks not to use #ifdef inside the code. You could create a special function here... > + for (i = 0; i != len; i++) { > + char c; > + > + if (get_user(c, data + i)) > + return -EFAULT; > + if (c == 'V') > + ltq_wdt_ok_to_close = 1; > + } > +#endif > + ltq_wdt_enable(ltq_wdt_timeout); > + return len; > +} [...] > +static int __init > +ltq_wdt_probe(struct platform_device *pdev) > +{ > + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + struct clk *clk; > + > + if (!res) { > + dev_err(&pdev->dev, "cannot obtain I/O memory region"); > + return -ENOENT; > + } > + res = devm_request_mem_region(&pdev->dev, res->start, > + resource_size(res), dev_name(&pdev->dev)); > + if (!res) { > + dev_err(&pdev->dev, "cannot request I/O memory region"); > + return -EBUSY; > + } > + ltq_wdt_membase = devm_ioremap_nocache(&pdev->dev, res->start, > + resource_size(res)); > + if (!ltq_wdt_membase) { > + dev_err(&pdev->dev, "cannot remap I/O memory region\n"); > + return -ENOMEM; > + } > + /* we do not need to enable the clock as it is always running */ > + clk = clk_get(&pdev->dev, "io"); > + BUG_ON(!clk); WARN_ON(). We shouldn't kill the whole machine I think. > +static int __init > +init_ltq_wdt(void) > +{ > + return platform_driver_probe(<q_wdt_driver, ltq_wdt_probe); > +} > + > +module_init(init_ltq_wdt); How about module_exit()? WBR, Sergei ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2011-04-07 14:31 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <1301470076-17279-1-git-send-email-blogic@openwrt.org>
2011-03-30 7:27 ` [PATCH V5 05/10] MIPS: lantiq: add watchdog support John Crispin
2011-03-30 9:36 ` Wim Van Sebroeck
2011-03-30 9:41 ` John Crispin
2011-04-04 9:24 ` John Crispin
2011-04-07 14:31 ` Sergei Shtylyov
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox