brintos

brintos / linux-shallow public Read only

0
0
Text · 3.2 KiB · 3ad146e Raw
131 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * CZ.NIC's Turris Omnia MCU watchdog driver4 *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		12020 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}131