1 // SPDX-License-Identifier: GPL-2.0
3 * CZ.NIC's Turris Omnia MCU watchdog driver
5 * 2024 by Marek BehĂșn <kabel@kernel.org>
8 #include <linux/bitops.h>
9 #include <linux/device.h>
10 #include <linux/i2c.h>
11 #include <linux/moduleparam.h>
12 #include <linux/types.h>
13 #include <linux/units.h>
14 #include <linux/watchdog.h>
16 #include <linux/turris-omnia-mcu-interface.h>
17 #include "turris-omnia-mcu.h"
19 #define WATCHDOG_TIMEOUT 120
21 static unsigned int timeout
;
22 module_param(timeout
, int, 0);
23 MODULE_PARM_DESC(timeout
, "Watchdog timeout in seconds");
25 static bool nowayout
= WATCHDOG_NOWAYOUT
;
26 module_param(nowayout
, bool, 0);
27 MODULE_PARM_DESC(nowayout
, "Watchdog cannot be stopped once started (default="
28 __MODULE_STRING(WATCHDOG_NOWAYOUT
) ")");
30 static int omnia_wdt_start(struct watchdog_device
*wdt
)
32 struct omnia_mcu
*mcu
= watchdog_get_drvdata(wdt
);
34 return omnia_cmd_write_u8(mcu
->client
, OMNIA_CMD_SET_WATCHDOG_STATE
, 1);
37 static int omnia_wdt_stop(struct watchdog_device
*wdt
)
39 struct omnia_mcu
*mcu
= watchdog_get_drvdata(wdt
);
41 return omnia_cmd_write_u8(mcu
->client
, OMNIA_CMD_SET_WATCHDOG_STATE
, 0);
44 static int omnia_wdt_ping(struct watchdog_device
*wdt
)
46 struct omnia_mcu
*mcu
= watchdog_get_drvdata(wdt
);
48 return omnia_cmd_write_u8(mcu
->client
, OMNIA_CMD_SET_WATCHDOG_STATE
, 1);
51 static int omnia_wdt_set_timeout(struct watchdog_device
*wdt
,
54 struct omnia_mcu
*mcu
= watchdog_get_drvdata(wdt
);
56 return omnia_cmd_write_u16(mcu
->client
, OMNIA_CMD_SET_WDT_TIMEOUT
,
60 static unsigned int omnia_wdt_get_timeleft(struct watchdog_device
*wdt
)
62 struct omnia_mcu
*mcu
= watchdog_get_drvdata(wdt
);
66 err
= omnia_cmd_read_u16(mcu
->client
, OMNIA_CMD_GET_WDT_TIMELEFT
,
69 dev_err(&mcu
->client
->dev
, "Cannot get watchdog timeleft: %d\n",
74 return timeleft
/ DECI
;
77 static const struct watchdog_info omnia_wdt_info
= {
78 .options
= WDIOF_SETTIMEOUT
| WDIOF_KEEPALIVEPING
| WDIOF_MAGICCLOSE
,
79 .identity
= "Turris Omnia MCU Watchdog",
82 static const struct watchdog_ops omnia_wdt_ops
= {
84 .start
= omnia_wdt_start
,
85 .stop
= omnia_wdt_stop
,
86 .ping
= omnia_wdt_ping
,
87 .set_timeout
= omnia_wdt_set_timeout
,
88 .get_timeleft
= omnia_wdt_get_timeleft
,
91 int omnia_mcu_register_watchdog(struct omnia_mcu
*mcu
)
93 struct device
*dev
= &mcu
->client
->dev
;
97 if (!(mcu
->features
& OMNIA_FEAT_WDT_PING
))
100 mcu
->wdt
.info
= &omnia_wdt_info
;
101 mcu
->wdt
.ops
= &omnia_wdt_ops
;
102 mcu
->wdt
.parent
= dev
;
103 mcu
->wdt
.min_timeout
= 1;
104 mcu
->wdt
.max_timeout
= 65535 / DECI
;
106 mcu
->wdt
.timeout
= WATCHDOG_TIMEOUT
;
107 watchdog_init_timeout(&mcu
->wdt
, timeout
, dev
);
109 watchdog_set_drvdata(&mcu
->wdt
, mcu
);
111 omnia_wdt_set_timeout(&mcu
->wdt
, mcu
->wdt
.timeout
);
113 err
= omnia_cmd_read_u8(mcu
->client
, OMNIA_CMD_GET_WATCHDOG_STATE
,
116 return dev_err_probe(dev
, err
,
117 "Cannot get MCU watchdog state\n");
120 set_bit(WDOG_HW_RUNNING
, &mcu
->wdt
.status
);
122 watchdog_set_nowayout(&mcu
->wdt
, nowayout
);
123 watchdog_stop_on_reboot(&mcu
->wdt
);
124 err
= devm_watchdog_register_device(dev
, &mcu
->wdt
);
126 return dev_err_probe(dev
, err
,
127 "Cannot register MCU watchdog\n");