]> Git Repo - J-linux.git/blob - drivers/platform/cznic/turris-omnia-mcu-watchdog.c
Merge tag 'platform-drivers-x86-v6.13-3' of git://git.kernel.org/pub/scm/linux/kernel...
[J-linux.git] / drivers / platform / cznic / turris-omnia-mcu-watchdog.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * CZ.NIC's Turris Omnia MCU watchdog driver
4  *
5  * 2024 by Marek BehĂșn <[email protected]>
6  */
7
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>
15
16 #include <linux/turris-omnia-mcu-interface.h>
17 #include "turris-omnia-mcu.h"
18
19 #define WATCHDOG_TIMEOUT                120
20
21 static unsigned int timeout;
22 module_param(timeout, int, 0);
23 MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds");
24
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) ")");
29
30 static int omnia_wdt_start(struct watchdog_device *wdt)
31 {
32         struct omnia_mcu *mcu = watchdog_get_drvdata(wdt);
33
34         return omnia_cmd_write_u8(mcu->client, OMNIA_CMD_SET_WATCHDOG_STATE, 1);
35 }
36
37 static int omnia_wdt_stop(struct watchdog_device *wdt)
38 {
39         struct omnia_mcu *mcu = watchdog_get_drvdata(wdt);
40
41         return omnia_cmd_write_u8(mcu->client, OMNIA_CMD_SET_WATCHDOG_STATE, 0);
42 }
43
44 static int omnia_wdt_ping(struct watchdog_device *wdt)
45 {
46         struct omnia_mcu *mcu = watchdog_get_drvdata(wdt);
47
48         return omnia_cmd_write_u8(mcu->client, OMNIA_CMD_SET_WATCHDOG_STATE, 1);
49 }
50
51 static int omnia_wdt_set_timeout(struct watchdog_device *wdt,
52                                  unsigned int timeout)
53 {
54         struct omnia_mcu *mcu = watchdog_get_drvdata(wdt);
55
56         return omnia_cmd_write_u16(mcu->client, OMNIA_CMD_SET_WDT_TIMEOUT,
57                                    timeout * DECI);
58 }
59
60 static unsigned int omnia_wdt_get_timeleft(struct watchdog_device *wdt)
61 {
62         struct omnia_mcu *mcu = watchdog_get_drvdata(wdt);
63         u16 timeleft;
64         int err;
65
66         err = omnia_cmd_read_u16(mcu->client, OMNIA_CMD_GET_WDT_TIMELEFT,
67                                  &timeleft);
68         if (err) {
69                 dev_err(&mcu->client->dev, "Cannot get watchdog timeleft: %d\n",
70                         err);
71                 return 0;
72         }
73
74         return timeleft / DECI;
75 }
76
77 static const struct watchdog_info omnia_wdt_info = {
78         .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
79         .identity = "Turris Omnia MCU Watchdog",
80 };
81
82 static const struct watchdog_ops omnia_wdt_ops = {
83         .owner          = THIS_MODULE,
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,
89 };
90
91 int omnia_mcu_register_watchdog(struct omnia_mcu *mcu)
92 {
93         struct device *dev = &mcu->client->dev;
94         u8 state;
95         int err;
96
97         if (!(mcu->features & OMNIA_FEAT_WDT_PING))
98                 return 0;
99
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;
105
106         mcu->wdt.timeout = WATCHDOG_TIMEOUT;
107         watchdog_init_timeout(&mcu->wdt, timeout, dev);
108
109         watchdog_set_drvdata(&mcu->wdt, mcu);
110
111         omnia_wdt_set_timeout(&mcu->wdt, mcu->wdt.timeout);
112
113         err = omnia_cmd_read_u8(mcu->client, OMNIA_CMD_GET_WATCHDOG_STATE,
114                                 &state);
115         if (err)
116                 return dev_err_probe(dev, err,
117                                      "Cannot get MCU watchdog state\n");
118
119         if (state)
120                 set_bit(WDOG_HW_RUNNING, &mcu->wdt.status);
121
122         watchdog_set_nowayout(&mcu->wdt, nowayout);
123         watchdog_stop_on_reboot(&mcu->wdt);
124         err = devm_watchdog_register_device(dev, &mcu->wdt);
125         if (err)
126                 return dev_err_probe(dev, err,
127                                      "Cannot register MCU watchdog\n");
128
129         return 0;
130 }
This page took 0.035931 seconds and 4 git commands to generate.