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
)
47 int timeout
= wd
->timeout
;
51 } ipc_wd_start
= { timeout
- MID_WDT_PRETIMEOUT
, timeout
};
54 * SCU expects the input size for watchdog IPC to
57 in_size
= DIV_ROUND_UP(sizeof(ipc_wd_start
), 4);
59 ret
= wdt_command(SCU_WATCHDOG_START
, (u32
*)&ipc_wd_start
, in_size
);
61 struct device
*dev
= watchdog_get_drvdata(wd
);
62 dev_crit(dev
, "error starting watchdog: %d\n", ret
);
68 static int wdt_ping(struct watchdog_device
*wd
)
72 ret
= wdt_command(SCU_WATCHDOG_KEEPALIVE
, NULL
, 0);
74 struct device
*dev
= watchdog_get_drvdata(wd
);
75 dev_crit(dev
, "Error executing keepalive: 0x%x\n", ret
);
81 static int wdt_stop(struct watchdog_device
*wd
)
85 ret
= wdt_command(SCU_WATCHDOG_STOP
, NULL
, 0);
87 struct device
*dev
= watchdog_get_drvdata(wd
);
88 dev_crit(dev
, "Error stopping watchdog: 0x%x\n", ret
);
94 static irqreturn_t
mid_wdt_irq(int irq
, void *dev_id
)
96 panic("Kernel Watchdog");
98 /* This code should not be reached */
102 static const struct watchdog_info mid_wdt_info
= {
103 .identity
= "Intel MID SCU watchdog",
104 .options
= WDIOF_KEEPALIVEPING
| WDIOF_SETTIMEOUT
| WDIOF_MAGICCLOSE
,
107 static const struct watchdog_ops mid_wdt_ops
= {
108 .owner
= THIS_MODULE
,
114 static int mid_wdt_probe(struct platform_device
*pdev
)
116 struct watchdog_device
*wdt_dev
;
117 struct intel_mid_wdt_pdata
*pdata
= pdev
->dev
.platform_data
;
121 dev_err(&pdev
->dev
, "missing platform data\n");
126 ret
= pdata
->probe(pdev
);
131 wdt_dev
= devm_kzalloc(&pdev
->dev
, sizeof(*wdt_dev
), GFP_KERNEL
);
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 wdt_dev
->parent
= &pdev
->dev
;
142 watchdog_set_drvdata(wdt_dev
, &pdev
->dev
);
143 platform_set_drvdata(pdev
, wdt_dev
);
145 ret
= devm_request_irq(&pdev
->dev
, pdata
->irq
, mid_wdt_irq
,
146 IRQF_SHARED
| IRQF_NO_SUSPEND
, "watchdog",
149 dev_err(&pdev
->dev
, "error requesting warning irq %d\n",
154 ret
= watchdog_register_device(wdt_dev
);
156 dev_err(&pdev
->dev
, "error registering watchdog device\n");
160 dev_info(&pdev
->dev
, "Intel MID watchdog device probed\n");
165 static int mid_wdt_remove(struct platform_device
*pdev
)
167 struct watchdog_device
*wd
= platform_get_drvdata(pdev
);
168 watchdog_unregister_device(wd
);
172 static struct platform_driver mid_wdt_driver
= {
173 .probe
= mid_wdt_probe
,
174 .remove
= mid_wdt_remove
,
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");