Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Marek Behún | 570 | 100.00% | 3 | 100.00% |
Total | 570 | 3 |
// SPDX-License-Identifier: GPL-2.0 /* * CZ.NIC's Turris Omnia MCU watchdog driver * * 2024 by Marek Behún <kabel@kernel.org> */ #include <linux/bitops.h> #include <linux/device.h> #include <linux/i2c.h> #include <linux/moduleparam.h> #include <linux/types.h> #include <linux/units.h> #include <linux/watchdog.h> #include <linux/turris-omnia-mcu-interface.h> #include "turris-omnia-mcu.h" #define WATCHDOG_TIMEOUT 120 static unsigned int timeout; module_param(timeout, int, 0); MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds"); static bool nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, bool, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); static int omnia_wdt_start(struct watchdog_device *wdt) { struct omnia_mcu *mcu = watchdog_get_drvdata(wdt); return omnia_cmd_write_u8(mcu->client, OMNIA_CMD_SET_WATCHDOG_STATE, 1); } static int omnia_wdt_stop(struct watchdog_device *wdt) { struct omnia_mcu *mcu = watchdog_get_drvdata(wdt); return omnia_cmd_write_u8(mcu->client, OMNIA_CMD_SET_WATCHDOG_STATE, 0); } static int omnia_wdt_ping(struct watchdog_device *wdt) { struct omnia_mcu *mcu = watchdog_get_drvdata(wdt); return omnia_cmd_write_u8(mcu->client, OMNIA_CMD_SET_WATCHDOG_STATE, 1); } static int omnia_wdt_set_timeout(struct watchdog_device *wdt, unsigned int timeout) { struct omnia_mcu *mcu = watchdog_get_drvdata(wdt); return omnia_cmd_write_u16(mcu->client, OMNIA_CMD_SET_WDT_TIMEOUT, timeout * DECI); } static unsigned int omnia_wdt_get_timeleft(struct watchdog_device *wdt) { struct omnia_mcu *mcu = watchdog_get_drvdata(wdt); u16 timeleft; int err; err = omnia_cmd_read_u16(mcu->client, OMNIA_CMD_GET_WDT_TIMELEFT, &timeleft); if (err) { dev_err(&mcu->client->dev, "Cannot get watchdog timeleft: %d\n", err); return 0; } return timeleft / DECI; } static const struct watchdog_info omnia_wdt_info = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, .identity = "Turris Omnia MCU Watchdog", }; static const struct watchdog_ops omnia_wdt_ops = { .owner = THIS_MODULE, .start = omnia_wdt_start, .stop = omnia_wdt_stop, .ping = omnia_wdt_ping, .set_timeout = omnia_wdt_set_timeout, .get_timeleft = omnia_wdt_get_timeleft, }; int omnia_mcu_register_watchdog(struct omnia_mcu *mcu) { struct device *dev = &mcu->client->dev; u8 state; int err; if (!(mcu->features & OMNIA_FEAT_WDT_PING)) return 0; mcu->wdt.info = &omnia_wdt_info; mcu->wdt.ops = &omnia_wdt_ops; mcu->wdt.parent = dev; mcu->wdt.min_timeout = 1; mcu->wdt.max_timeout = 65535 / DECI; mcu->wdt.timeout = WATCHDOG_TIMEOUT; watchdog_init_timeout(&mcu->wdt, timeout, dev); watchdog_set_drvdata(&mcu->wdt, mcu); omnia_wdt_set_timeout(&mcu->wdt, mcu->wdt.timeout); err = omnia_cmd_read_u8(mcu->client, OMNIA_CMD_GET_WATCHDOG_STATE, &state); if (err) return dev_err_probe(dev, err, "Cannot get MCU watchdog state\n"); if (state) set_bit(WDOG_HW_RUNNING, &mcu->wdt.status); watchdog_set_nowayout(&mcu->wdt, nowayout); watchdog_stop_on_reboot(&mcu->wdt); err = devm_watchdog_register_device(dev, &mcu->wdt); if (err) return dev_err_probe(dev, err, "Cannot register MCU watchdog\n"); return 0; }
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1