2 * intel-mid_wdt: generic Intel MID SCU watchdog driver
4 * Platforms supported so far:
7 * Copyright (C) 2014 Intel Corporation. All rights reserved.
8 * Contact: David Cohen <david.a.cohen@linux.intel.com>
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.
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>
22 #include <asm/intel_scu_ipc.h>
23 #include <asm/intel-mid.h>
25 #define IPC_WATCHDOG 0xf8
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
32 /* SCU watchdog messages */
34 SCU_WATCHDOG_START
= 0,
36 SCU_WATCHDOG_KEEPALIVE
,
39 static inline int wdt_command(int sub
, u32
*in
, int inlen
)
41 return intel_scu_ipc_command(IPC_WATCHDOG
, sub
, in
, inlen
, NULL
, 0);
44 static int wdt_start(struct watchdog_device
*wd
)
46 struct device
*dev
= watchdog_get_drvdata(wd
);
48 int timeout
= wd
->timeout
;
52 } ipc_wd_start
= { timeout
- MID_WDT_PRETIMEOUT
, timeout
};
55 * SCU expects the input size for watchdog IPC to
58 in_size
= DIV_ROUND_UP(sizeof(ipc_wd_start
), 4);
60 ret
= wdt_command(SCU_WATCHDOG_START
, (u32
*)&ipc_wd_start
, in_size
);
62 dev_crit(dev
, "error starting watchdog: %d\n", ret
);
67 static int wdt_ping(struct watchdog_device
*wd
)
69 struct device
*dev
= watchdog_get_drvdata(wd
);
72 ret
= wdt_command(SCU_WATCHDOG_KEEPALIVE
, NULL
, 0);
74 dev_crit(dev
, "Error executing keepalive: %d\n", ret
);
79 static int wdt_stop(struct watchdog_device
*wd
)
81 struct device
*dev
= watchdog_get_drvdata(wd
);
84 ret
= wdt_command(SCU_WATCHDOG_STOP
, NULL
, 0);
86 dev_crit(dev
, "Error stopping watchdog: %d\n", ret
);
91 static irqreturn_t
mid_wdt_irq(int irq
, void *dev_id
)
93 panic("Kernel Watchdog");
95 /* This code should not be reached */
99 static const struct watchdog_info mid_wdt_info
= {
100 .identity
= "Intel MID SCU watchdog",
101 .options
= WDIOF_KEEPALIVEPING
| WDIOF_SETTIMEOUT
| WDIOF_MAGICCLOSE
,
104 static const struct watchdog_ops mid_wdt_ops
= {
105 .owner
= THIS_MODULE
,
111 static int mid_wdt_probe(struct platform_device
*pdev
)
113 struct watchdog_device
*wdt_dev
;
114 struct intel_mid_wdt_pdata
*pdata
= pdev
->dev
.platform_data
;
118 dev_err(&pdev
->dev
, "missing platform data\n");
123 ret
= pdata
->probe(pdev
);
128 wdt_dev
= devm_kzalloc(&pdev
->dev
, sizeof(*wdt_dev
), GFP_KERNEL
);
132 wdt_dev
->info
= &mid_wdt_info
;
133 wdt_dev
->ops
= &mid_wdt_ops
;
134 wdt_dev
->min_timeout
= MID_WDT_TIMEOUT_MIN
;
135 wdt_dev
->max_timeout
= MID_WDT_TIMEOUT_MAX
;
136 wdt_dev
->timeout
= MID_WDT_DEFAULT_TIMEOUT
;
137 wdt_dev
->parent
= &pdev
->dev
;
139 watchdog_set_drvdata(wdt_dev
, &pdev
->dev
);
141 ret
= devm_request_irq(&pdev
->dev
, pdata
->irq
, mid_wdt_irq
,
142 IRQF_SHARED
| IRQF_NO_SUSPEND
, "watchdog",
145 dev_err(&pdev
->dev
, "error requesting warning irq %d\n",
150 /* Make sure the watchdog is not running */
153 ret
= devm_watchdog_register_device(&pdev
->dev
, wdt_dev
);
155 dev_err(&pdev
->dev
, "error registering watchdog device\n");
159 dev_info(&pdev
->dev
, "Intel MID watchdog device probed\n");
164 static struct platform_driver mid_wdt_driver
= {
165 .probe
= mid_wdt_probe
,
167 .name
= "intel_mid_wdt",
171 module_platform_driver(mid_wdt_driver
);
173 MODULE_AUTHOR("David Cohen <david.a.cohen@linux.intel.com>");
174 MODULE_DESCRIPTION("Watchdog Driver for Intel MID platform");
175 MODULE_LICENSE("GPL");