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/bitops.h>
13 #include <linux/device.h>
14 #include <linux/errno.h>
15 #include <linux/interrupt.h>
16 #include <linux/math.h>
17 #include <linux/module.h>
18 #include <linux/panic.h>
19 #include <linux/platform_device.h>
20 #include <linux/types.h>
21 #include <linux/watchdog.h>
23 #include <linux/platform_data/x86/intel-mid_wdt.h>
24 #include <linux/platform_data/x86/intel_scu_ipc.h>
26 #define IPC_WATCHDOG 0xf8
28 #define MID_WDT_PRETIMEOUT 15
29 #define MID_WDT_TIMEOUT_MIN (1 + MID_WDT_PRETIMEOUT)
30 #define MID_WDT_TIMEOUT_MAX 170
31 #define MID_WDT_DEFAULT_TIMEOUT 90
33 /* SCU watchdog messages */
35 SCU_WATCHDOG_START
= 0,
37 SCU_WATCHDOG_KEEPALIVE
,
41 struct watchdog_device wd
;
43 struct intel_scu_ipc_dev
*scu
;
47 wdt_command(struct mid_wdt
*mid
, int sub
, const void *in
, size_t inlen
, size_t size
)
49 struct intel_scu_ipc_dev
*scu
= mid
->scu
;
51 return intel_scu_ipc_dev_command_with_size(scu
, IPC_WATCHDOG
, sub
, in
,
52 inlen
, size
, NULL
, 0);
55 static int wdt_start(struct watchdog_device
*wd
)
57 struct mid_wdt
*mid
= watchdog_get_drvdata(wd
);
59 int timeout
= wd
->timeout
;
63 } ipc_wd_start
= { timeout
- MID_WDT_PRETIMEOUT
, timeout
};
66 * SCU expects the input size for watchdog IPC to be 2 which is the
67 * size of the structure in dwords. SCU IPC normally takes bytes
68 * but this is a special case where we specify size to be different
71 in_size
= DIV_ROUND_UP(sizeof(ipc_wd_start
), 4);
73 ret
= wdt_command(mid
, SCU_WATCHDOG_START
, &ipc_wd_start
,
74 sizeof(ipc_wd_start
), in_size
);
76 dev_crit(mid
->dev
, "error starting watchdog: %d\n", ret
);
81 static int wdt_ping(struct watchdog_device
*wd
)
83 struct mid_wdt
*mid
= watchdog_get_drvdata(wd
);
86 ret
= wdt_command(mid
, SCU_WATCHDOG_KEEPALIVE
, NULL
, 0, 0);
88 dev_crit(mid
->dev
, "Error executing keepalive: %d\n", ret
);
93 static int wdt_stop(struct watchdog_device
*wd
)
95 struct mid_wdt
*mid
= watchdog_get_drvdata(wd
);
98 ret
= wdt_command(mid
, SCU_WATCHDOG_STOP
, NULL
, 0, 0);
100 dev_crit(mid
->dev
, "Error stopping watchdog: %d\n", ret
);
105 static irqreturn_t
mid_wdt_irq(int irq
, void *dev_id
)
107 panic("Kernel Watchdog");
109 /* This code should not be reached */
113 static const struct watchdog_info mid_wdt_info
= {
114 .identity
= "Intel MID SCU watchdog",
115 .options
= WDIOF_KEEPALIVEPING
| WDIOF_SETTIMEOUT
| WDIOF_MAGICCLOSE
,
118 static const struct watchdog_ops mid_wdt_ops
= {
119 .owner
= THIS_MODULE
,
125 static int mid_wdt_probe(struct platform_device
*pdev
)
127 struct device
*dev
= &pdev
->dev
;
128 struct watchdog_device
*wdt_dev
;
129 struct intel_mid_wdt_pdata
*pdata
= dev_get_platdata(dev
);
134 dev_err(dev
, "missing platform data\n");
139 ret
= pdata
->probe(pdev
);
144 mid
= devm_kzalloc(dev
, sizeof(*mid
), GFP_KERNEL
);
151 wdt_dev
->info
= &mid_wdt_info
;
152 wdt_dev
->ops
= &mid_wdt_ops
;
153 wdt_dev
->min_timeout
= MID_WDT_TIMEOUT_MIN
;
154 wdt_dev
->max_timeout
= MID_WDT_TIMEOUT_MAX
;
155 wdt_dev
->timeout
= MID_WDT_DEFAULT_TIMEOUT
;
156 wdt_dev
->parent
= dev
;
158 watchdog_set_nowayout(wdt_dev
, WATCHDOG_NOWAYOUT
);
159 watchdog_set_drvdata(wdt_dev
, mid
);
161 mid
->scu
= devm_intel_scu_ipc_dev_get(dev
);
163 return -EPROBE_DEFER
;
165 ret
= devm_request_irq(dev
, pdata
->irq
, mid_wdt_irq
,
166 IRQF_SHARED
| IRQF_NO_SUSPEND
, "watchdog",
169 dev_err(dev
, "error requesting warning irq %d\n", pdata
->irq
);
174 * The firmware followed by U-Boot leaves the watchdog running
175 * with the default threshold which may vary. When we get here
176 * we should make a decision to prevent any side effects before
177 * user space daemon will take care of it. The best option,
178 * taking into consideration that there is no way to read values
179 * back from hardware, is to enforce watchdog being run with
180 * deterministic values.
182 ret
= wdt_start(wdt_dev
);
186 /* Make sure the watchdog is serviced */
187 set_bit(WDOG_HW_RUNNING
, &wdt_dev
->status
);
189 ret
= devm_watchdog_register_device(dev
, wdt_dev
);
193 dev_info(dev
, "Intel MID watchdog device probed\n");
198 static struct platform_driver mid_wdt_driver
= {
199 .probe
= mid_wdt_probe
,
201 .name
= "intel_mid_wdt",
205 module_platform_driver(mid_wdt_driver
);
207 MODULE_AUTHOR("David Cohen <david.a.cohen@linux.intel.com>");
208 MODULE_DESCRIPTION("Watchdog Driver for Intel MID platform");
209 MODULE_LICENSE("GPL");
210 MODULE_ALIAS("platform:intel_mid_wdt");