firmware/br-ext-chip-allwinner/board/v83x/kernel/patches/00000-drivers_watchdog_axp2...

227 lines
6.2 KiB
Diff

diff -drupN a/drivers/watchdog/axp2xx_wdt.c b/drivers/watchdog/axp2xx_wdt.c
--- a/drivers/watchdog/axp2xx_wdt.c 1970-01-01 03:00:00.000000000 +0300
+++ b/drivers/watchdog/axp2xx_wdt.c 2022-06-12 05:28:14.000000000 +0300
@@ -0,0 +1,222 @@
+/*
+ * driver/watchdog/axp2xx_wdt.c
+ *
+ * Copyright (C) 2019
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#define pr_fmt(x) KBUILD_MODNAME ": " x
+
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+#include <linux/mfd/axp2101.h>
+#include <linux/bitops.h>
+
+ /* for AXP2101_MODULE_EN (0x18) */
+#define AXP2101_WATCHDOG_EN BIT(0)
+
+ /* for AXP2101_WATCHDOG_CFG (0x19) */
+#define AXP2101_WATCHDOG_CLR BIT(3)
+
+#define AXP2101_WATCHDOG_RST_CFG_MASK GENMASK(5, 4)
+#define AXP2101_WATCHDOG_RST_SHIFT 4
+#define AXP2101_WATCHDOG_RST_IRQ (0 << AXP2101_WATCHDOG_RST_SHIFT)
+#define AXP2101_WATCHDOG_RST_IRQ_SYS (1 << AXP2101_WATCHDOG_RST_SHIFT)
+#define AXP2101_WATCHDOG_RST_IRQ_SYS_PWROK (2 << AXP2101_WATCHDOG_RST_SHIFT)
+#define AXP2101_WATCHDOG_RST_IRQ_SYS_PWRONOFF (3 << AXP2101_WATCHDOG_RST_SHIFT)
+
+#define AXP2101_WATCHDOG_TIMER_MASK GENMASK(2, 0)
+#define AXP2101_WATCHDOG_TIMER_1S 0
+#define AXP2101_WATCHDOG_TIMER_2S 1
+#define AXP2101_WATCHDOG_TIMER_4S 2
+#define AXP2101_WATCHDOG_TIMER_8S 3
+#define AXP2101_WATCHDOG_TIMER_16S 4
+#define AXP2101_WATCHDOG_TIMER_32S 5
+#define AXP2101_WATCHDOG_TIMER_64S 6
+#define AXP2101_WATCHDOG_TIMER_128S 7
+
+#define DEFAULT_HEART_BEAT_MS 4000
+#define DEFAULT_TIMEOUT 5
+
+struct axp2xx_watchdog {
+ struct watchdog_device wd;
+ struct regmap *regmap;
+ struct axp20x_dev *axp20x;
+};
+
+static int axp2101_wdt_start(struct watchdog_device *wdt)
+{
+ struct axp2xx_watchdog *axp2xx_wdt = watchdog_get_drvdata(wdt);
+ struct regmap *regmap = axp2xx_wdt->regmap;
+
+ /* ping */
+ regmap_update_bits(regmap, AXP2101_WATCHDOG_CFG, AXP2101_WATCHDOG_CLR,
+ AXP2101_WATCHDOG_CLR);
+ regmap_update_bits(regmap, AXP2101_MODULE_EN, AXP2101_WATCHDOG_EN,
+ AXP2101_WATCHDOG_EN);
+ return 0;
+}
+
+static int axp2101_wdt_stop(struct watchdog_device *wdt)
+{
+ struct axp2xx_watchdog *axp2xx_wdt = watchdog_get_drvdata(wdt);
+ struct regmap *regmap = axp2xx_wdt->regmap;
+
+ regmap_update_bits(regmap, AXP2101_MODULE_EN, AXP2101_WATCHDOG_EN, 0);
+
+ return 0;
+}
+
+static int axp2101_wdt_ping(struct watchdog_device *wdt)
+{
+ struct axp2xx_watchdog *axp2xx_wdt = watchdog_get_drvdata(wdt);
+ struct regmap *regmap = axp2xx_wdt->regmap;
+
+ regmap_update_bits(regmap, AXP2101_WATCHDOG_CFG, AXP2101_WATCHDOG_CLR,
+ AXP2101_WATCHDOG_CLR);
+ return 0;
+}
+int axp2101_wdt_set_timeout(struct watchdog_device *wdt, unsigned int sec)
+{
+ struct axp2xx_watchdog *axp2xx_wdt = watchdog_get_drvdata(wdt);
+
+ axp2101_wdt_stop(&axp2xx_wdt->wd);
+ axp2xx_wdt->wd.timeout = sec;
+ axp2101_wdt_start(&axp2xx_wdt->wd);
+ return 0;
+}
+
+static struct watchdog_ops axp2101_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = axp2101_wdt_start,
+ .stop = axp2101_wdt_stop,
+ .ping = axp2101_wdt_ping,
+ .set_timeout = axp2101_wdt_set_timeout,
+
+};
+
+static struct watchdog_info axp2xx_wdt_info = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+ .firmware_version = 1,
+ .identity = "axp2xx_wdt",
+};
+
+static int axp2xx_wdt_probe(struct platform_device *pd)
+{
+ int ret;
+ struct axp2xx_watchdog *axp2xx_wd;
+ struct axp20x_dev *axp20x = dev_get_drvdata(pd->dev.parent);
+
+ axp2xx_wd = devm_kzalloc(&pd->dev, sizeof(struct axp2xx_watchdog),
+ GFP_KERNEL);
+ if (!axp2xx_wd) {
+ pr_err("can not request memory\n");
+ return -ENOMEM;
+ }
+
+ switch (axp20x->variant) {
+ case AXP2101_ID:
+ axp2xx_wd->wd.ops = &axp2101_wdt_ops;
+ regmap_update_bits(axp20x->regmap, AXP2101_WATCHDOG_CFG,
+ AXP2101_WATCHDOG_RST_CFG_MASK,
+ AXP2101_WATCHDOG_RST_IRQ_SYS_PWRONOFF);
+ regmap_update_bits(axp20x->regmap, AXP2101_WATCHDOG_CFG,
+ AXP2101_WATCHDOG_TIMER_MASK,
+ AXP2101_WATCHDOG_TIMER_4S);
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+
+ axp2xx_wd->wd.parent = &pd->dev;
+ axp2xx_wd->wd.info = &axp2xx_wdt_info;
+ axp2xx_wd->wd.max_hw_heartbeat_ms = DEFAULT_HEART_BEAT_MS;
+ axp2xx_wd->regmap = axp20x->regmap;
+ axp2xx_wd->axp20x = axp20x;
+
+ ret = watchdog_init_timeout(&axp2xx_wd->wd, DEFAULT_TIMEOUT, &pd->dev);
+ if (ret < 0) {
+ pr_err("axp2xx_wdt set error timeout\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pd, axp2xx_wd);
+ watchdog_set_drvdata(&axp2xx_wd->wd, axp2xx_wd);
+
+ ret = watchdog_register_device(&axp2xx_wd->wd);
+ if (ret)
+ pr_err("can not register axp2xx watchdog\n");
+
+ return ret;
+}
+
+static int axp2xx_wdt_remove(struct platform_device *pd)
+{
+ struct axp2xx_watchdog *axp2xx_wdt = platform_get_drvdata(pd);
+
+ watchdog_unregister_device(&axp2xx_wdt->wd);
+
+ return 0;
+}
+
+
+#ifdef CONFIG_PM_SLEEP
+static int axp2xx_suspend(struct platform_device *pd, pm_message_t state)
+{
+ struct axp2xx_watchdog *axp2xx_wdt = platform_get_drvdata(pd);
+
+ if (watchdog_active(&axp2xx_wdt->wd))
+ axp2101_wdt_stop(&axp2xx_wdt->wd);
+
+ return 0;
+}
+
+static int axp2xx_resume(struct platform_device *pd)
+{
+ struct axp2xx_watchdog *axp2xx_wdt = platform_get_drvdata(pd);
+
+ if (watchdog_active(&axp2xx_wdt->wd))
+ axp2101_wdt_start(&axp2xx_wdt->wd);
+
+ return 0;
+}
+#endif
+
+static struct platform_driver axp2xx_wdt_driver = {
+ .probe = axp2xx_wdt_probe,
+ .remove = axp2xx_wdt_remove,
+#if CONFIG_PM_SLEEP
+ .suspend = axp2xx_suspend,
+ .resume = axp2xx_resume,
+#endif
+ .driver = {
+ .name = "axp2xx-watchdog",
+ },
+};
+
+static int __init axp2xx_wdt_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&axp2xx_wdt_driver);
+ if (ret)
+ pr_err("register axp2xx wdt driver failed %d\n", ret);
+
+ return ret;
+}
+
+static void __exit apx2xx_wdt_exit(void)
+{
+ platform_driver_unregister(&axp2xx_wdt_driver);
+}
+
+subsys_initcall(axp2xx_wdt_init);
+
+MODULE_DESCRIPTION("xpower axp2xx watchdog driver");
+MODULE_AUTHOR("F.Y <fuyao@allwinnertech.com>");
+MODULE_LICENSE("GPL v2");