drm/tests: hdmi: Fix memory leaks in drm_display_mode_from_cea_vic()
[drm/drm-misc.git] / drivers / platform / cznic / turris-omnia-mcu-watchdog.c
blob3ad146ec1d809b2bc62558180490e86b08ce8d15
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * CZ.NIC's Turris Omnia MCU watchdog driver
5 * 2024 by Marek BehĂșn <kabel@kernel.org>
6 */
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,
52 unsigned int timeout)
54 struct omnia_mcu *mcu = watchdog_get_drvdata(wdt);
56 return omnia_cmd_write_u16(mcu->client, OMNIA_CMD_SET_WDT_TIMEOUT,
57 timeout * DECI);
60 static unsigned int omnia_wdt_get_timeleft(struct watchdog_device *wdt)
62 struct omnia_mcu *mcu = watchdog_get_drvdata(wdt);
63 u16 timeleft;
64 int err;
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;
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 = {
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,
91 int omnia_mcu_register_watchdog(struct omnia_mcu *mcu)
93 struct device *dev = &mcu->client->dev;
94 u8 state;
95 int err;
97 if (!(mcu->features & OMNIA_FEAT_WDT_PING))
98 return 0;
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,
114 &state);
115 if (err)
116 return dev_err_probe(dev, err,
117 "Cannot get MCU watchdog state\n");
119 if (state)
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);
125 if (err)
126 return dev_err_probe(dev, err,
127 "Cannot register MCU watchdog\n");
129 return 0;