FILE
turris-omnia-mcu-watchdog.c
File preview with syntax highlighting.
linux-6.19.14/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 <kabel@kernel.org> 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 21static unsigned int timeout; 22module_param(timeout, int, 0); 23MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds"); 24 25static bool nowayout = WATCHDOG_NOWAYOUT; 26module_param(nowayout, bool, 0); 27MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" 28 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 29 30static 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 37static 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 44static 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 51static 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 60static 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 77static const struct watchdog_info omnia_wdt_info = { 78 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 79 .identity = "Turris Omnia MCU Watchdog", 80}; 81 82static 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 91int 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}
~/
Read-only file preview.