rename and renumber storm patches
[openwrt/openwrt.git] / target / linux / storm / patches / 009-watchdog.patch
diff --git a/target/linux/storm/patches/009-watchdog.patch b/target/linux/storm/patches/009-watchdog.patch
new file mode 100644 (file)
index 0000000..3055a94
--- /dev/null
@@ -0,0 +1,398 @@
+--- a/arch/arm/mach-sl2312/sl3516_device.c
++++ b/arch/arm/mach-sl2312/sl3516_device.c
+@@ -76,9 +76,30 @@
+       .resource       = sl3516_sata0_resources,
+ };
++static struct resource sl351x_wdt_resources[] = {
++      [0] = {
++              .start  = SL2312_WAQTCHDOG_BASE + 0x00,
++              .end    = SL2312_WAQTCHDOG_BASE + 0x1C,
++              .flags  = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start  = IRQ_WATCHDOG,
++              .end    = IRQ_WATCHDOG,
++              .flags  = IORESOURCE_IRQ,
++      },
++};
++
++static struct platform_device sl351x_wdt = {
++      .name           = "sl351x-wdt",
++      .id             = -1,
++      .resource       = sl351x_wdt_resources,
++      .num_resources  = ARRAY_SIZE(sl351x_wdt_resources),
++};
++
+ static struct platform_device *sata_devices[] __initdata = {
+       &sata_device,
+       &sata0_device,
++      &sl351x_wdt,
+ };
+ static int __init sl3516_init(void)
+--- a/drivers/char/watchdog/Kconfig
++++ b/drivers/char/watchdog/Kconfig
+@@ -171,6 +171,17 @@
+         To compile this driver as a module, choose M here: the
+         module will be called ep93xx_wdt.
++config WATCHDOG_SL351X
++      tristate "SL351x Watchdog"
++      depends on WATCHDOG && ARCH_SL2312
++      help
++        This driver adds watchdog support for the integrated watchdog in the
++        SL351x processors (Farraday core). If you have one of these processors
++        and wish to have watchdog support enabled, say Y, otherwise say N.
++
++        To compile this driver as a module, choose M here: the
++        module will be called sl351x_wdt.
++
+ config OMAP_WATCHDOG
+       tristate "OMAP Watchdog"
+       depends on ARCH_OMAP16XX || ARCH_OMAP24XX
+--- a/drivers/char/watchdog/Makefile
++++ b/drivers/char/watchdog/Makefile
+@@ -36,6 +36,7 @@
+ obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
+ obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
+ obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
++obj-$(CONFIG_WATCHDOG_SL351X) += sl351x_wdt.o
+ obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
+ obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
+ obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
+--- /dev/null
++++ b/drivers/char/watchdog/sl351x_wdt.c
+@@ -0,0 +1,332 @@
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/fs.h>
++#include <linux/mm.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/miscdevice.h>
++#include <linux/watchdog.h>
++#include <linux/platform_device.h>
++#include <asm/uaccess.h>
++#include <asm/arch/sl2312.h>
++#include <asm/arch/hardware.h>
++#include <asm/arch/irqs.h>
++#include <asm/arch/watchdog.h>
++#include <asm/io.h>
++#include <linux/interrupt.h>
++
++#define WATCHDOG_TEST 1
++#define PFX "sl351x-wdt: "
++
++#define _WATCHDOG_COUNTER  0x00
++#define _WATCHDOG_LOAD     0x04
++#define _WATCHDOG_RESTART  0x08
++#define _WATCHDOG_CR       0x0C
++#define _WATCHDOG_STATUS   0x10
++#define _WATCHDOG_CLEAR    0x14
++#define _WATCHDOG_INTRLEN  0x18
++
++static struct resource  *wdt_mem;
++static struct resource  *wdt_irq;
++static void __iomem     *wdt_base;
++static int            wdt_margin = WATCHDOG_TIMEOUT_MARGIN;   /* in range of 0 .. 60s */
++
++static int open_state = WATCHDOG_DRIVER_CLOSE;
++static int wd_expire = 0;
++
++static void watchdog_enable(void)
++{
++      unsigned long wdcr;
++
++      wdcr = readl(wdt_base + _WATCHDOG_CR);
++      wdcr |= (WATCHDOG_WDENABLE_MSK|WATCHDOG_WDRST_MSK);
++#ifdef WATCHDOG_TEST
++      wdcr |= WATCHDOG_WDINTR_MSK;
++//    wdcr &= ~WATCHDOG_WDRST_MSK;
++#endif
++      wdcr &= ~WATCHDOG_WDCLOCK_MSK;
++      writel(wdcr, wdt_base + _WATCHDOG_CR);
++}
++
++static void watchdog_set_timeout(unsigned long timeout)
++{
++      timeout = WATCHDOG_TIMEOUT_SCALE * timeout;
++      writel(timeout, wdt_base + _WATCHDOG_LOAD);
++      writel(WATCHDOG_RESTART_VALUE, wdt_base + _WATCHDOG_RESTART);
++}
++
++static void watchdog_keepalive(void)
++{
++      writel(WATCHDOG_RESTART_VALUE, wdt_base + _WATCHDOG_RESTART);
++}
++
++static void watchdog_disable(void)
++{
++      unsigned long wdcr;
++
++      wdcr = readl(wdt_base + _WATCHDOG_CR);
++      wdcr &= ~WATCHDOG_WDENABLE_MSK;
++      writel(wdcr, wdt_base + _WATCHDOG_CR);
++}
++
++
++#ifdef WATCHDOG_TEST
++static irqreturn_t watchdog_irq(int irq, void *dev_id, struct pt_regs *regs)
++{
++      unsigned int clear;
++
++      writel(WATCHDOG_CLEAR_STATUS, wdt_base + _WATCHDOG_CLEAR);
++      printk(KERN_INFO PFX "Watchdog timeout, resetting system...\n");
++
++      clear = __raw_readl(IO_ADDRESS(SL2312_INTERRUPT_BASE)+0x0C);
++      clear &= 0x01;
++      __raw_writel(clear,IO_ADDRESS(SL2312_INTERRUPT_BASE)+0x08);
++      wd_expire = 1;
++      return IRQ_HANDLED;
++}
++
++#endif
++
++#define OPTIONS WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE
++static struct watchdog_info sl351x_wdt_ident = {
++      .options          =     OPTIONS,
++      .firmware_version =     0,
++      .identity         =     "sl351x Watchdog",
++};
++
++struct file_operations watchdog_fops = {
++      .write          = watchdog_write,
++      .read           = watchdog_read,
++      .open           = watchdog_open,
++      .release        = watchdog_release,
++      .ioctl          = watchdog_ioctl,
++};
++
++static int watchdog_open(struct inode *inode, struct file *filp)
++{
++      if (open_state == WATCHDOG_DRIVER_OPEN)
++              return -EBUSY;
++
++      wd_expire = 0;
++
++      watchdog_disable();
++      watchdog_set_timeout(wdt_margin);
++      watchdog_enable();
++
++      printk(KERN_INFO PFX "watchog timer enabled, margin: %ds.\n", wdt_margin);
++      open_state = WATCHDOG_DRIVER_OPEN;
++
++      return nonseekable_open(inode, filp);
++}
++
++static int watchdog_release(struct inode *inode, struct file *filp)
++{
++      watchdog_disable();
++
++      open_state = WATCHDOG_DRIVER_CLOSE;
++      wd_expire = 0;
++      printk(KERN_INFO PFX "watchog timer disabled, margin: %ds.\n", wdt_margin);
++
++      return 0;
++}
++
++static ssize_t watchdog_read(struct file *filp, char *buf, size_t count, loff_t *off)
++{
++      int i;
++      unsigned long val;
++
++
++      for(i=0;i< count;i++)
++      {
++              if ((i%4)==0)
++                      val = *((unsigned long *)WATCHDOG_COUNTER);
++              buf[i] = (val & 0xFF);
++              val >>= 8;
++      }
++      return count;
++}
++
++static ssize_t watchdog_write(struct file *filp, const char *buf, size_t len, loff_t *off)
++{
++      /*  Refresh the timer. */
++      if (len) {
++              watchdog_keepalive();
++      }
++      return len;
++
++}
++
++static int watchdog_ioctl(struct inode *inode, struct file *filp,
++                        unsigned int cmd, unsigned long arg)
++{
++      void __user *argp = (void __user *)arg;
++      int margin;
++
++      switch(cmd)
++      {
++      case WDIOC_GETSUPPORT:
++              return copy_to_user(argp, &sl351x_wdt_ident,
++                                  sizeof(sl351x_wdt_ident)) ? -EFAULT : 0;
++
++      case WDIOC_GETSTATUS:
++      case WDIOC_GETBOOTSTATUS:
++              return put_user(0, (int __user*)argp);
++
++      case WDIOC_KEEPALIVE:
++              watchdog_keepalive();
++              return 0;
++
++      case WDIOC_SETTIMEOUT:
++              if (get_user(margin, (int __user*)argp))
++                      return -EFAULT;
++
++              /* Arbitrary, can't find the card's limits */
++              if ((margin < 0) || (margin > 60))
++                      return -EINVAL;
++
++              // watchdog_disable();
++              wdt_margin = margin;
++              watchdog_set_timeout(margin);
++              watchdog_keepalive();
++              // watchdog_enable();
++
++              /* Fall through */
++
++      case WDIOC_GETTIMEOUT:
++              return put_user(wdt_margin, (int *)arg);
++
++      default:
++              return -ENOIOCTLCMD;
++      }
++}
++
++static struct miscdevice wd_dev= {
++      WATCHDOG_MINOR,
++      "watchdog",
++      &watchdog_fops
++};
++
++static char banner[] __initdata = KERN_INFO "SL351x Watchdog Timer, (c) 2007 WILIBOX\n";
++
++static int sl351x_wdt_probe(struct platform_device *pdev)
++{
++      struct resource *res;
++      int ret, size;
++      unsigned long wdcr;
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      if (res == NULL) {
++              printk(KERN_INFO PFX "failed to get memory region resouce\n");
++              return -ENOMEM;
++      }
++
++      size = (res->end-res->start)+1;
++
++      wdt_mem = request_mem_region(res->start, size, pdev->name);
++      if (wdt_mem == NULL) {
++              printk(KERN_INFO PFX "failed to get memory region\n");
++              return -ENOENT;
++      }
++
++      wdt_base = ioremap(res->start, size);
++      if (wdt_base == NULL) {
++              printk(KERN_INFO PFX "failed to ioremap() region\n");
++              return -EINVAL;
++      }
++
++      res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++      if (res == NULL) {
++               printk(KERN_INFO PFX "failed to get irq resource\n");
++               return -ENOENT;
++      }
++
++      wdt_irq = res;
++
++      ret = request_irq(res->start, watchdog_irq, 0, pdev->name, pdev);
++      if (ret != 0) {
++              printk(KERN_INFO PFX "failed to install irq (%d)\n", ret);
++              return ret;
++      }
++
++      wdcr = readl(wdt_base + _WATCHDOG_CR);
++      if (wdcr & WATCHDOG_WDENABLE_MSK) {
++              printk(KERN_INFO PFX "Found watchdog in enabled state, reseting ...\n");
++              wdcr &= ~WATCHDOG_WDENABLE_MSK;
++              writel(wdcr, wdt_base + _WATCHDOG_CR);
++      }
++
++      ret = misc_register(&wd_dev);
++
++      return ret;
++}
++
++static int sl351x_wdt_remove(struct platform_device *pdev)
++{
++      if (wdt_base != NULL) {
++              iounmap(wdt_base);
++              wdt_base = NULL;
++      }
++
++      if (wdt_irq != NULL) {
++              free_irq(wdt_irq->start, pdev);
++              release_resource(wdt_irq);
++              wdt_irq = NULL;
++      }
++
++      if (wdt_mem != NULL) {
++              release_resource(wdt_mem);
++              wdt_mem = NULL;
++      }
++
++      misc_deregister(&wd_dev);
++
++      return 0;
++}
++
++static void sl351x_wdt_shutdown(struct platform_device *dev)
++{
++      watchdog_disable();
++}
++
++#ifdef CONFIG_PM
++static int sl351x_wdt_suspend(struct platform_device *dev, pm_message_t state)
++{
++      watchdog_disable();
++}
++
++static int sl351x_wdt_resume(struct platform_device *dev)
++{
++      watchdog_set_timeout(wdt_margin);
++      watchdog_enable();
++}
++
++#else
++#define sl351x_wdt_suspend    NULL
++#define sl351x_wdt_resume     NULL
++#endif
++
++static struct platform_driver sl351x_wdt_driver = {
++      .probe          = sl351x_wdt_probe,
++      .remove         = sl351x_wdt_remove,
++      .shutdown       = sl351x_wdt_shutdown,
++      .suspend        = sl351x_wdt_suspend,
++      .resume         = sl351x_wdt_resume,
++      .driver         = {
++              .owner  = THIS_MODULE,
++              .name   = "sl351x-wdt",
++      },
++};
++
++static int __init watchdog_init(void)
++{
++      printk(banner);
++      return platform_driver_register(&sl351x_wdt_driver);
++}
++
++static void __exit watchdog_exit(void)
++{
++      platform_driver_unregister(&sl351x_wdt_driver);
++}
++
++module_init(watchdog_init);
++module_exit(watchdog_exit);