aboutsummaryrefslogtreecommitdiff
path: root/drivers/watchdog
diff options
context:
space:
mode:
authormerging other branches <null@invalid>2008-11-26 16:07:01 +0000
committerAndy Green <agreen@pads.home.warmcat.com>2008-11-26 16:07:01 +0000
commit6d2c293d6578048e7b71e0c44897144f15f350ae (patch)
treecba36be2a06ee7bfa0aab1a3c7d36bd67ea37402 /drivers/watchdog
parent524f4a1dfe71a8b353a244140164e09828abb68c (diff)
MERGE-via-balaji-tracking-hist-MERGE-via-stable-tracking-hist-MERGE-via-mokopatches-tracking-via-master-s3c-hsmmc-clean
balaji-tracking-hist top was efb2d57c0e0ed62324d79d6c5793fe797c157266
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/Kconfig8
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/pcf50606_wdt.c213
3 files changed, 221 insertions, 1 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 4fd3fa5546b..7ec506f5014 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -233,6 +233,12 @@ config ORION5X_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called orion5x_wdt.
+config PCF50606_WATCHDOG
+ tristate "NXP PCF50606 Watchdog"
+ depends on MFD_PCF50606
+ help
+ Say Y here to include support for NXP PCF50606 watchdog timer.
+
# ARM26 Architecture
# AVR32 Architecture
@@ -784,7 +790,7 @@ config WATCHDOG_RTAS
tristate "RTAS watchdog"
depends on PPC_RTAS
help
- This driver adds watchdog support for the RTAS watchdog.
+ his driver adds watchdog support for the RTAS watchdog.
To compile this driver as a module, choose M here. The module
will be called wdrtas.
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index e352bbb7630..496ec41bdbc 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
obj-$(CONFIG_ORION5X_WATCHDOG) += orion5x_wdt.o
+obj-$(CONFIG_PCF50606_WATCHDOG) += pcf50606_wdt.o
# ARM26 Architecture
diff --git a/drivers/watchdog/pcf50606_wdt.c b/drivers/watchdog/pcf50606_wdt.c
new file mode 100644
index 00000000000..ba8a472abf6
--- /dev/null
+++ b/drivers/watchdog/pcf50606_wdt.c
@@ -0,0 +1,213 @@
+/* Philips PCF50606 Watchdog Timer Driver
+ *
+ * (C) 2006-2008 by Openmoko, Inc.
+ * Author: Balaji Rao <balajirrao@openmoko.org>
+ * All rights reserved.
+ *
+ * Broken down from monstrous PCF50606 driver mainly by
+ * Harald Welte, Matt Hsu, Andy Green and Werner Almesberger
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+
+#include <linux/mfd/pcf50606/core.h>
+#include <linux/mfd/pcf50606/wdt.h>
+
+static struct pcf50606 *pcf;
+static unsigned long wdt_status;
+#define WDT_IN_USE 0
+#define WDT_OK_TO_CLOSE 1
+#define WDT_REGION_INITED 2
+#define WDT_DEVICE_INITED 3
+
+static int allow_close;
+#define CLOSE_STATE_NOT 0x0000
+#define CLOSE_STATE_ALLOW 0x2342
+
+static void pcf50606_wdt_start(void)
+{
+ pcf50606_reg_set_bit_mask(pcf, PCF50606_REG_OOCC1, PCF50606_OOCC1_WDTRST,
+ PCF50606_OOCC1_WDTRST);
+}
+
+static void pcf50606_wdt_stop(void)
+{
+ pcf50606_reg_clear_bits(pcf, PCF50606_REG_OOCS, PCF50606_OOCS_WDTEXP);
+}
+
+static void pcf50606_wdt_keepalive(void)
+{
+ pcf50606_wdt_start();
+}
+
+static int pcf50606_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+ return -EBUSY;
+
+ pcf50606_wdt_start();
+
+ return nonseekable_open(inode, file);
+}
+
+static int pcf50606_wdt_release(struct inode *inode, struct file *file)
+{
+ if (allow_close == CLOSE_STATE_ALLOW)
+ pcf50606_wdt_stop();
+ else {
+ printk(KERN_CRIT "Unexpected close, not stopping watchdog!\n");
+ pcf50606_wdt_keepalive();
+ }
+
+ allow_close = CLOSE_STATE_NOT;
+ clear_bit(WDT_IN_USE, &wdt_status);
+
+ return 0;
+}
+
+static ssize_t pcf50606_wdt_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
+{
+ if (len) {
+ size_t i;
+
+ for (i = 0; i != len; i++) {
+ char c;
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V')
+ allow_close = CLOSE_STATE_ALLOW;
+ }
+ pcf50606_wdt_keepalive();
+ }
+
+ return len;
+}
+
+static struct watchdog_info pcf50606_wdt_ident = {
+ .options = WDIOF_MAGICCLOSE,
+ .firmware_version = 0,
+ .identity = "PCF50606 Watchdog",
+};
+
+static int pcf50606_wdt_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp, &pcf50606_wdt_ident,
+ sizeof(pcf50606_wdt_ident)) ? -EFAULT : 0;
+ break;
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, p);
+ case WDIOC_KEEPALIVE:
+ pcf50606_wdt_keepalive();
+ return 0;
+ case WDIOC_GETTIMEOUT:
+ return put_user(8, p);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+static struct file_operations pcf50606_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = &pcf50606_wdt_write,
+ .ioctl = &pcf50606_wdt_ioctl,
+ .open = &pcf50606_wdt_open,
+ .release = &pcf50606_wdt_release,
+};
+
+static struct miscdevice pcf50606_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &pcf50606_wdt_fops,
+};
+
+static void pcf50606_wdt_irq(struct pcf50606 *pcf, int irq, void *unused)
+{
+ pcf50606_reg_set_bit_mask(pcf, PCF50606_REG_OOCC1,
+ PCF50606_OOCC1_WDTRST,
+ PCF50606_OOCC1_WDTRST);
+}
+
+int __init pcf50606_wdt_probe(struct platform_device *pdev)
+{
+ struct pcf50606 *pcf;
+ int err;
+
+ pcf = platform_get_drvdata(pdev);
+
+ err = misc_register(&pcf50606_wdt_miscdev);
+ if (err) {
+ dev_err(&pdev->dev, "cannot register miscdev on "
+ "minor=%d (%d)\n", WATCHDOG_MINOR, err);
+ return err;
+ }
+ set_bit(WDT_DEVICE_INITED, &wdt_status);
+
+ /* Set up IRQ handlers */
+ pcf->irq_handler[PCF50606_IRQ_CHGWD10S].handler = pcf50606_wdt_irq;
+
+ return 0;
+}
+
+static int __devexit pcf50606_wdt_remove(struct platform_device *pdev)
+{
+ struct pcf50606 *pcf;
+
+ pcf = platform_get_drvdata(pdev);
+
+ misc_deregister(&pcf50606_wdt_miscdev);
+
+ pcf->irq_handler[PCF50606_IRQ_CHGWD10S].handler = NULL;
+
+ return 0;
+}
+
+struct platform_driver pcf50606_wdt_driver = {
+ .driver = {
+ .name = "pcf50606-wdt",
+ },
+ .probe = pcf50606_wdt_probe,
+ .remove = __devexit_p(pcf50606_wdt_remove),
+};
+
+static int __init pcf50606_wdt_init(void)
+{
+ return platform_driver_register(&pcf50606_wdt_driver);
+}
+module_init(pcf50606_wdt_init);
+
+static void __exit pcf50606_wdt_exit(void)
+{
+ platform_driver_unregister(&pcf50606_wdt_driver);
+}
+module_exit(pcf50606_wdt_exit);
+
+MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
+MODULE_DESCRIPTION("PCF50606 wdt driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pcf50606-wdt");
+