| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 |
- --- a/arch/arm/mach-sl2312/sl3516_device.c
- +++ b/arch/arm/mach-sl2312/sl3516_device.c
- @@ -76,9 +76,30 @@ static struct platform_device sata0_devi
- .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 @@ config EP93XX_WATCHDOG
- 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_S3C2410_WATCHDOG) += s3c241
- 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);
|