File Index
Files and directories
Sign in
FILE

turris-omnia-mcu-watchdog.c

File preview with syntax highlighting.

linux-6.19.14/drivers/platform/cznic/turris-omnia-mcu-watchdog.c 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.