summaryrefslogtreecommitdiffstats
path: root/target/linux/mvebu/patches-6.6/820-v6.11-05-platform-cznic-turris-omnia-mcu-Add-support-for-MCU-.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/mvebu/patches-6.6/820-v6.11-05-platform-cznic-turris-omnia-mcu-Add-support-for-MCU-.patch')
-rw-r--r--target/linux/mvebu/patches-6.6/820-v6.11-05-platform-cznic-turris-omnia-mcu-Add-support-for-MCU-.patch250
1 files changed, 250 insertions, 0 deletions
diff --git a/target/linux/mvebu/patches-6.6/820-v6.11-05-platform-cznic-turris-omnia-mcu-Add-support-for-MCU-.patch b/target/linux/mvebu/patches-6.6/820-v6.11-05-platform-cznic-turris-omnia-mcu-Add-support-for-MCU-.patch
new file mode 100644
index 0000000000..cf3f88bfcf
--- /dev/null
+++ b/target/linux/mvebu/patches-6.6/820-v6.11-05-platform-cznic-turris-omnia-mcu-Add-support-for-MCU-.patch
@@ -0,0 +1,250 @@
+From 33ae4e4c86bc6ff298489fb8b743e2743dd0af6d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
+Date: Mon, 1 Jul 2024 13:30:07 +0200
+Subject: [PATCH 05/11] platform: cznic: turris-omnia-mcu: Add support for MCU
+ watchdog
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add support for the watchdog mechanism provided by the MCU.
+
+Signed-off-by: Marek BehĂșn <kabel@kernel.org>
+Reviewed-by: Andy Shevchenko <andy@kernel.org>
+Reviewed-by: Guenter Roeck <linux@roeck-us.net>
+Acked-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Link: https://lore.kernel.org/r/20240701113010.16447-6-kabel@kernel.org
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+---
+ drivers/platform/cznic/Kconfig | 2 +
+ drivers/platform/cznic/Makefile | 1 +
+ .../platform/cznic/turris-omnia-mcu-base.c | 4 +
+ .../cznic/turris-omnia-mcu-watchdog.c | 130 ++++++++++++++++++
+ drivers/platform/cznic/turris-omnia-mcu.h | 24 ++++
+ 5 files changed, 161 insertions(+)
+ create mode 100644 drivers/platform/cznic/turris-omnia-mcu-watchdog.c
+
+--- a/drivers/platform/cznic/Kconfig
++++ b/drivers/platform/cznic/Kconfig
+@@ -19,6 +19,7 @@ config TURRIS_OMNIA_MCU
+ select GPIOLIB
+ select GPIOLIB_IRQCHIP
+ select RTC_CLASS
++ select WATCHDOG_CORE
+ help
+ Say Y here to add support for the features implemented by the
+ microcontroller on the CZ.NIC's Turris Omnia SOHO router.
+@@ -26,6 +27,7 @@ config TURRIS_OMNIA_MCU
+ - board poweroff into true low power mode (with voltage regulators
+ disabled) and the ability to configure wake up from this mode (via
+ rtcwake)
++ - MCU watchdog
+ - GPIO pins
+ - to get front button press events (the front button can be
+ configured either to generate press events to the CPU or to change
+--- a/drivers/platform/cznic/Makefile
++++ b/drivers/platform/cznic/Makefile
+@@ -4,3 +4,4 @@ obj-$(CONFIG_TURRIS_OMNIA_MCU) += turris
+ turris-omnia-mcu-y := turris-omnia-mcu-base.o
+ turris-omnia-mcu-y += turris-omnia-mcu-gpio.o
+ turris-omnia-mcu-y += turris-omnia-mcu-sys-off-wakeup.o
++turris-omnia-mcu-y += turris-omnia-mcu-watchdog.o
+--- a/drivers/platform/cznic/turris-omnia-mcu-base.c
++++ b/drivers/platform/cznic/turris-omnia-mcu-base.c
+@@ -376,6 +376,10 @@ static int omnia_mcu_probe(struct i2c_cl
+ if (err)
+ return err;
+
++ err = omnia_mcu_register_watchdog(mcu);
++ if (err)
++ return err;
++
+ return omnia_mcu_register_gpiochip(mcu);
+ }
+
+--- /dev/null
++++ b/drivers/platform/cznic/turris-omnia-mcu-watchdog.c
+@@ -0,0 +1,130 @@
++// 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;
++}
+--- a/drivers/platform/cznic/turris-omnia-mcu.h
++++ b/drivers/platform/cznic/turris-omnia-mcu.h
+@@ -13,6 +13,7 @@
+ #include <linux/if_ether.h>
+ #include <linux/mutex.h>
+ #include <linux/types.h>
++#include <linux/watchdog.h>
+ #include <linux/workqueue.h>
+ #include <asm/byteorder.h>
+ #include <asm/unaligned.h>
+@@ -43,6 +44,9 @@ struct omnia_mcu {
+ struct rtc_device *rtcdev;
+ u32 rtc_alarm;
+ bool front_button_poweron;
++
++ /* MCU watchdog */
++ struct watchdog_device wdt;
+ };
+
+ int omnia_cmd_write_read(const struct i2c_client *client,
+@@ -55,6 +59,25 @@ static inline int omnia_cmd_write(const
+ return omnia_cmd_write_read(client, cmd, len, NULL, 0);
+ }
+
++static inline int omnia_cmd_write_u8(const struct i2c_client *client, u8 cmd,
++ u8 val)
++{
++ u8 buf[2] = { cmd, val };
++
++ return omnia_cmd_write(client, buf, sizeof(buf));
++}
++
++static inline int omnia_cmd_write_u16(const struct i2c_client *client, u8 cmd,
++ u16 val)
++{
++ u8 buf[3];
++
++ buf[0] = cmd;
++ put_unaligned_le16(val, &buf[1]);
++
++ return omnia_cmd_write(client, buf, sizeof(buf));
++}
++
+ static inline int omnia_cmd_write_u32(const struct i2c_client *client, u8 cmd,
+ u32 val)
+ {
+@@ -158,5 +181,6 @@ extern const struct attribute_group omni
+
+ int omnia_mcu_register_gpiochip(struct omnia_mcu *mcu);
+ int omnia_mcu_register_sys_off_and_wakeup(struct omnia_mcu *mcu);
++int omnia_mcu_register_watchdog(struct omnia_mcu *mcu);
+
+ #endif /* __TURRIS_OMNIA_MCU_H */