aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/watchdog/Kconfig13
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/intel-mid_wdt.c184
-rw-r--r--include/linux/platform_data/intel-mid_wdt.h22
4 files changed, 220 insertions, 0 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index cbd5ac7b8832..c845527b503a 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -665,6 +665,19 @@ config INTEL_SCU_WATCHDOG
665 665
666 To compile this driver as a module, choose M here. 666 To compile this driver as a module, choose M here.
667 667
668config INTEL_MID_WATCHDOG
669 tristate "Intel MID Watchdog Timer"
670 depends on X86_INTEL_MID
671 select WATCHDOG_CORE
672 ---help---
673 Watchdog timer driver built into the Intel SCU for Intel MID
674 Platforms.
675
676 This driver currently supports only the watchdog evolution
677 implementation in SCU, available for Merrifield generation.
678
679 To compile this driver as a module, choose M here.
680
668config ITCO_WDT 681config ITCO_WDT
669 tristate "Intel TCO Timer/Watchdog" 682 tristate "Intel TCO Timer/Watchdog"
670 depends on (X86 || IA64) && PCI 683 depends on (X86 || IA64) && PCI
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 1384531eaa45..7b8a91ed20e7 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -112,6 +112,7 @@ obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
112obj-$(CONFIG_MACHZ_WDT) += machzwd.o 112obj-$(CONFIG_MACHZ_WDT) += machzwd.o
113obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o 113obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
114obj-$(CONFIG_INTEL_SCU_WATCHDOG) += intel_scu_watchdog.o 114obj-$(CONFIG_INTEL_SCU_WATCHDOG) += intel_scu_watchdog.o
115obj-$(CONFIG_INTEL_MID_WATCHDOG) += intel-mid_wdt.o
115 116
116# M32R Architecture 117# M32R Architecture
117 118
diff --git a/drivers/watchdog/intel-mid_wdt.c b/drivers/watchdog/intel-mid_wdt.c
new file mode 100644
index 000000000000..ca66e8e74635
--- /dev/null
+++ b/drivers/watchdog/intel-mid_wdt.c
@@ -0,0 +1,184 @@
1/*
2 * intel-mid_wdt: generic Intel MID SCU watchdog driver
3 *
4 * Platforms supported so far:
5 * - Merrifield only
6 *
7 * Copyright (C) 2014 Intel Corporation. All rights reserved.
8 * Contact: David Cohen <david.a.cohen@linux.intel.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of version 2 of the GNU General
12 * Public License as published by the Free Software Foundation.
13 */
14
15#include <linux/interrupt.h>
16#include <linux/module.h>
17#include <linux/nmi.h>
18#include <linux/platform_device.h>
19#include <linux/watchdog.h>
20#include <linux/platform_data/intel-mid_wdt.h>
21
22#include <asm/intel_scu_ipc.h>
23#include <asm/intel-mid.h>
24
25#define IPC_WATCHDOG 0xf8
26
27#define MID_WDT_PRETIMEOUT 15
28#define MID_WDT_TIMEOUT_MIN (1 + MID_WDT_PRETIMEOUT)
29#define MID_WDT_TIMEOUT_MAX 170
30#define MID_WDT_DEFAULT_TIMEOUT 90
31
32/* SCU watchdog messages */
33enum {
34 SCU_WATCHDOG_START = 0,
35 SCU_WATCHDOG_STOP,
36 SCU_WATCHDOG_KEEPALIVE,
37};
38
39static inline int wdt_command(int sub, u32 *in, int inlen)
40{
41 return intel_scu_ipc_command(IPC_WATCHDOG, sub, in, inlen, NULL, 0);
42}
43
44static int wdt_start(struct watchdog_device *wd)
45{
46 int ret, in_size;
47 int timeout = wd->timeout;
48 struct ipc_wd_start {
49 u32 pretimeout;
50 u32 timeout;
51 } ipc_wd_start = { timeout - MID_WDT_PRETIMEOUT, timeout };
52
53 /*
54 * SCU expects the input size for watchdog IPC to
55 * be based on 4 bytes
56 */
57 in_size = DIV_ROUND_UP(sizeof(ipc_wd_start), 4);
58
59 ret = wdt_command(SCU_WATCHDOG_START, (u32 *)&ipc_wd_start, in_size);
60 if (ret) {
61 struct device *dev = watchdog_get_drvdata(wd);
62 dev_crit(dev, "error starting watchdog: %d\n", ret);
63 }
64
65 return ret;
66}
67
68static int wdt_ping(struct watchdog_device *wd)
69{
70 int ret;
71
72 ret = wdt_command(SCU_WATCHDOG_KEEPALIVE, NULL, 0);
73 if (ret) {
74 struct device *dev = watchdog_get_drvdata(wd);
75 dev_crit(dev, "Error executing keepalive: 0x%x\n", ret);
76 }
77
78 return ret;
79}
80
81static int wdt_stop(struct watchdog_device *wd)
82{
83 int ret;
84
85 ret = wdt_command(SCU_WATCHDOG_STOP, NULL, 0);
86 if (ret) {
87 struct device *dev = watchdog_get_drvdata(wd);
88 dev_crit(dev, "Error stopping watchdog: 0x%x\n", ret);
89 }
90
91 return ret;
92}
93
94static irqreturn_t mid_wdt_irq(int irq, void *dev_id)
95{
96 panic("Kernel Watchdog");
97
98 /* This code should not be reached */
99 return IRQ_HANDLED;
100}
101
102static const struct watchdog_info mid_wdt_info = {
103 .identity = "Intel MID SCU watchdog",
104 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
105};
106
107static const struct watchdog_ops mid_wdt_ops = {
108 .owner = THIS_MODULE,
109 .start = wdt_start,
110 .stop = wdt_stop,
111 .ping = wdt_ping,
112};
113
114static int mid_wdt_probe(struct platform_device *pdev)
115{
116 struct watchdog_device *wdt_dev;
117 struct intel_mid_wdt_pdata *pdata = pdev->dev.platform_data;
118 int ret;
119
120 if (!pdata) {
121 dev_err(&pdev->dev, "missing platform data\n");
122 return -EINVAL;
123 }
124
125 if (pdata->probe) {
126 ret = pdata->probe(pdev);
127 if (ret)
128 return ret;
129 }
130
131 wdt_dev = devm_kzalloc(&pdev->dev, sizeof(*wdt_dev), GFP_KERNEL);
132 if (!wdt_dev)
133 return -ENOMEM;
134
135 wdt_dev->info = &mid_wdt_info;
136 wdt_dev->ops = &mid_wdt_ops;
137 wdt_dev->min_timeout = MID_WDT_TIMEOUT_MIN;
138 wdt_dev->max_timeout = MID_WDT_TIMEOUT_MAX;
139 wdt_dev->timeout = MID_WDT_DEFAULT_TIMEOUT;
140
141 watchdog_set_drvdata(wdt_dev, &pdev->dev);
142 platform_set_drvdata(pdev, wdt_dev);
143
144 ret = devm_request_irq(&pdev->dev, pdata->irq, mid_wdt_irq,
145 IRQF_SHARED | IRQF_NO_SUSPEND, "watchdog",
146 wdt_dev);
147 if (ret) {
148 dev_err(&pdev->dev, "error requesting warning irq %d\n",
149 pdata->irq);
150 return ret;
151 }
152
153 ret = watchdog_register_device(wdt_dev);
154 if (ret) {
155 dev_err(&pdev->dev, "error registering watchdog device\n");
156 return ret;
157 }
158
159 dev_info(&pdev->dev, "Intel MID watchdog device probed\n");
160
161 return 0;
162}
163
164static int mid_wdt_remove(struct platform_device *pdev)
165{
166 struct watchdog_device *wd = platform_get_drvdata(pdev);
167 watchdog_unregister_device(wd);
168 return 0;
169}
170
171static struct platform_driver mid_wdt_driver = {
172 .probe = mid_wdt_probe,
173 .remove = mid_wdt_remove,
174 .driver = {
175 .owner = THIS_MODULE,
176 .name = "intel_mid_wdt",
177 },
178};
179
180module_platform_driver(mid_wdt_driver);
181
182MODULE_AUTHOR("David Cohen <david.a.cohen@linux.intel.com>");
183MODULE_DESCRIPTION("Watchdog Driver for Intel MID platform");
184MODULE_LICENSE("GPL");
diff --git a/include/linux/platform_data/intel-mid_wdt.h b/include/linux/platform_data/intel-mid_wdt.h
new file mode 100644
index 000000000000..b98253466ace
--- /dev/null
+++ b/include/linux/platform_data/intel-mid_wdt.h
@@ -0,0 +1,22 @@
1/*
2 * intel-mid_wdt: generic Intel MID SCU watchdog driver
3 *
4 * Copyright (C) 2014 Intel Corporation. All rights reserved.
5 * Contact: David Cohen <david.a.cohen@linux.intel.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2 of the GNU General
9 * Public License as published by the Free Software Foundation.
10 */
11
12#ifndef __INTEL_MID_WDT_H__
13#define __INTEL_MID_WDT_H__
14
15#include <linux/platform_device.h>
16
17struct intel_mid_wdt_pdata {
18 int irq;
19 int (*probe)(struct platform_device *pdev);
20};
21
22#endif /*__INTEL_MID_WDT_H__*/