1 // SPDX-License-Identifier: GPL-2.0-only
3 * intel-mid_wdt: generic Intel MID SCU watchdog driver
5 * Platforms supported so far:
8 * Copyright (C) 2014 Intel Corporation. All rights reserved.
9 * Contact: David Cohen <david.a.cohen@linux.intel.com>
12 #include <linux/interrupt.h>
13 #include <linux/module.h>
14 #include <linux/nmi.h>
15 #include <linux/platform_device.h>
16 #include <linux/watchdog.h>
17 #include <linux/platform_data/intel-mid_wdt.h>
19 #include <asm/intel_scu_ipc.h>
20 #include <asm/intel-mid.h>
22 #define IPC_WATCHDOG 0xf8
24 #define MID_WDT_PRETIMEOUT 15
25 #define MID_WDT_TIMEOUT_MIN (1 + MID_WDT_PRETIMEOUT)
26 #define MID_WDT_TIMEOUT_MAX 170
27 #define MID_WDT_DEFAULT_TIMEOUT 90
29 /* SCU watchdog messages */
31 SCU_WATCHDOG_START
= 0,
33 SCU_WATCHDOG_KEEPALIVE
,
36 static inline int wdt_command(int sub
, u32
*in
, int inlen
)
38 return intel_scu_ipc_command(IPC_WATCHDOG
, sub
, in
, inlen
, NULL
, 0);
41 static int wdt_start(struct watchdog_device
*wd
)
43 struct device
*dev
= watchdog_get_drvdata(wd
);
45 int timeout
= wd
->timeout
;
49 } ipc_wd_start
= { timeout
- MID_WDT_PRETIMEOUT
, timeout
};
52 * SCU expects the input size for watchdog IPC to
55 in_size
= DIV_ROUND_UP(sizeof(ipc_wd_start
), 4);
57 ret
= wdt_command(SCU_WATCHDOG_START
, (u32
*)&ipc_wd_start
, in_size
);
59 dev_crit(dev
, "error starting watchdog: %d\n", ret
);
64 static int wdt_ping(struct watchdog_device
*wd
)
66 struct device
*dev
= watchdog_get_drvdata(wd
);
69 ret
= wdt_command(SCU_WATCHDOG_KEEPALIVE
, NULL
, 0);
71 dev_crit(dev
, "Error executing keepalive: %d\n", ret
);
76 static int wdt_stop(struct watchdog_device
*wd
)
78 struct device
*dev
= watchdog_get_drvdata(wd
);
81 ret
= wdt_command(SCU_WATCHDOG_STOP
, NULL
, 0);
83 dev_crit(dev
, "Error stopping watchdog: %d\n", ret
);
88 static irqreturn_t
mid_wdt_irq(int irq
, void *dev_id
)
90 panic("Kernel Watchdog");
92 /* This code should not be reached */
96 static const struct watchdog_info mid_wdt_info
= {
97 .identity
= "Intel MID SCU watchdog",
98 .options
= WDIOF_KEEPALIVEPING
| WDIOF_SETTIMEOUT
| WDIOF_MAGICCLOSE
,
101 static const struct watchdog_ops mid_wdt_ops
= {
102 .owner
= THIS_MODULE
,
108 static int mid_wdt_probe(struct platform_device
*pdev
)
110 struct device
*dev
= &pdev
->dev
;
111 struct watchdog_device
*wdt_dev
;
112 struct intel_mid_wdt_pdata
*pdata
= dev
->platform_data
;
116 dev_err(dev
, "missing platform data\n");
121 ret
= pdata
->probe(pdev
);
126 wdt_dev
= devm_kzalloc(dev
, sizeof(*wdt_dev
), GFP_KERNEL
);
130 wdt_dev
->info
= &mid_wdt_info
;
131 wdt_dev
->ops
= &mid_wdt_ops
;
132 wdt_dev
->min_timeout
= MID_WDT_TIMEOUT_MIN
;
133 wdt_dev
->max_timeout
= MID_WDT_TIMEOUT_MAX
;
134 wdt_dev
->timeout
= MID_WDT_DEFAULT_TIMEOUT
;
135 wdt_dev
->parent
= dev
;
137 watchdog_set_nowayout(wdt_dev
, WATCHDOG_NOWAYOUT
);
138 watchdog_set_drvdata(wdt_dev
, dev
);
140 ret
= devm_request_irq(dev
, pdata
->irq
, mid_wdt_irq
,
141 IRQF_SHARED
| IRQF_NO_SUSPEND
, "watchdog",
144 dev_err(dev
, "error requesting warning irq %d\n", pdata
->irq
);
149 * The firmware followed by U-Boot leaves the watchdog running
150 * with the default threshold which may vary. When we get here
151 * we should make a decision to prevent any side effects before
152 * user space daemon will take care of it. The best option,
153 * taking into consideration that there is no way to read values
154 * back from hardware, is to enforce watchdog being run with
155 * deterministic values.
157 ret
= wdt_start(wdt_dev
);
161 /* Make sure the watchdog is serviced */
162 set_bit(WDOG_HW_RUNNING
, &wdt_dev
->status
);
164 ret
= devm_watchdog_register_device(dev
, wdt_dev
);
168 dev_info(dev
, "Intel MID watchdog device probed\n");
173 static struct platform_driver mid_wdt_driver
= {
174 .probe
= mid_wdt_probe
,
176 .name
= "intel_mid_wdt",
180 module_platform_driver(mid_wdt_driver
);
182 MODULE_AUTHOR("David Cohen <david.a.cohen@linux.intel.com>");
183 MODULE_DESCRIPTION("Watchdog Driver for Intel MID platform");
184 MODULE_LICENSE("GPL");