summaryrefslogtreecommitdiff
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-03-25 13:56:18 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2022-03-25 13:56:18 -0700
commit8350e8331b3971533d6e6112ab596eda2c2ffffd (patch)
tree1add05c103644650616f17f1ae90ae2fc91482ee /drivers/watchdog
parente35a4a4e13c35f500a8d38e836b5e335c7515494 (diff)
parentd99460ed5cdcc28feba6b992630b04650e410902 (diff)
Merge tag 'mfd-next-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
Pull MFD updates from Lee Jones: "New Drivers: - Add support for Maxim MAX77714 PMIC Removed Drivers: - Remove support for ST-Ericsson AB8500 DebugFS New Device Support: - Add support for Silergy SY7636A to Simple MFD I2C - Add support for MediaTek MT6366 PMIC to MT6358 IRQ - Add support for Charger to Intel PMIC CRC - Add support for Raptor Lake to Intel LPSS PCI New Functionality: - Add support for Reboot to Rockchip RK808 Fix-ups: - Device Tree changes (includcing YAML conversion) for silergy,sy7636a, maxim,max77843, google,cros-ec, maxim,max14577, maxim,max77802, maxim,max77714, qcom,tcsr, qcom,spmi-pmic, stericsson,ab8500, stericsson,db8500-prcmu, samsung,exynos5433-lpass, mt6397, syscon, brcm,cru - Visible to menuconfig; simple-mfd-i2c - Clean-up or clarify code; max77686, intel_soc_pmic_crc - Improve error handling; mc13xxx-core, stmfx, asic3 - Pass device information to child devices; iqs62x, intel-lpss-acpi - Individually identify IRQ domains; intel_soc_pmic_core - Remove superfluous code; dbx500-prcmu, exynos-lpass - Staticify and constify; arizona-i2c - Mark sometimes used data as __maybe_unused; atmel-flexcom - Account for different ACPI tables on AOSP/Windows platforms; arizona-spi - Use provided (platform) APIs; ab8500-core - Trivial (whitespace, spelling); rohm-bd9576" * tag 'mfd-next-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (50 commits) dt-bindings: mfd: syscon: Add microchip,lan966x-cpu-syscon compatible mfd: bd9576: fix typos in comments mfd: Use platform_get_irq() to get the interrupt mfd: db8500-prcmu: Remove unused inline function mfd: arizona-spi: Add Android board ACPI table handling mfd: arizona-spi: Split Windows ACPI init code into its own function mfd: asic3: Add missing iounmap() on error asic3_mfd_probe MAINTAINERS: Rectify entry for ROHM MULTIFUNCTION BD9571MWV-M PMIC DEVICE DRIVERS mfd: intel-lpss: Provide an SSP type to the driver dt-bindings: mfd: brcm,cru: Rename pinctrl node dt-bindings: Add compatibles for undocumented trivial syscons mfd: atmel-flexcom: Fix compilation warning dt-bindings: mfd: Add compatible for the MediaTek MT6366 PMIC dt-bindings: mfd: samsung,exynos5433-lpass: Convert to dtschema mfd: exynos-lpass: Drop unneeded syscon.h include mfd: intel-lpss: Add Intel Raptor Lake PCH-S PCI IDs mfd: ab8500: Drop debugfs module mfd: sta2x11: Use GFP_KERNEL instead of GFP_ATOMIC mfd: ab8500: Rewrite bindings in YAML mfd: qcom-spmi-pmic: Add pm8953 compatible ...
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/Kconfig2
-rw-r--r--drivers/watchdog/max77620_wdt.c85
2 files changed, 70 insertions, 17 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index aa42f0686591..085f5a4ad06c 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -678,7 +678,7 @@ config MAX63XX_WATCHDOG
config MAX77620_WATCHDOG
tristate "Maxim Max77620 Watchdog Timer"
- depends on MFD_MAX77620 || COMPILE_TEST
+ depends on MFD_MAX77620 || MFD_MAX77714 || COMPILE_TEST
select WATCHDOG_CORE
help
This is the driver for the Max77620 watchdog timer.
diff --git a/drivers/watchdog/max77620_wdt.c b/drivers/watchdog/max77620_wdt.c
index be6a53c30002..b76ad6ba0915 100644
--- a/drivers/watchdog/max77620_wdt.c
+++ b/drivers/watchdog/max77620_wdt.c
@@ -3,8 +3,10 @@
* Maxim MAX77620 Watchdog Driver
*
* Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2022 Luca Ceresoli
*
* Author: Laxman Dewangan <ldewangan@nvidia.com>
+ * Author: Luca Ceresoli <luca@lucaceresoli.net>
*/
#include <linux/err.h>
@@ -13,6 +15,7 @@
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/mfd/max77620.h>
+#include <linux/mfd/max77714.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -20,17 +23,57 @@
static bool nowayout = WATCHDOG_NOWAYOUT;
+/**
+ * struct max77620_variant - Data specific to a chip variant
+ * @wdt_info: watchdog descriptor
+ * @reg_onoff_cnfg2: ONOFF_CNFG2 register offset
+ * @reg_cnfg_glbl2: CNFG_GLBL2 register offset
+ * @reg_cnfg_glbl3: CNFG_GLBL3 register offset
+ * @wdtc_mask: WDTC bit mask in CNFG_GLBL3 (=bits to update to ping the watchdog)
+ * @bit_wd_rst_wk: WD_RST_WK bit offset within ONOFF_CNFG2
+ * @cnfg_glbl2_cfg_bits: configuration bits to enable in CNFG_GLBL2 register
+ */
+struct max77620_variant {
+ u8 reg_onoff_cnfg2;
+ u8 reg_cnfg_glbl2;
+ u8 reg_cnfg_glbl3;
+ u8 wdtc_mask;
+ u8 bit_wd_rst_wk;
+ u8 cnfg_glbl2_cfg_bits;
+};
+
struct max77620_wdt {
struct device *dev;
struct regmap *rmap;
+ const struct max77620_variant *drv_data;
struct watchdog_device wdt_dev;
};
+static const struct max77620_variant max77620_wdt_data = {
+ .reg_onoff_cnfg2 = MAX77620_REG_ONOFFCNFG2,
+ .reg_cnfg_glbl2 = MAX77620_REG_CNFGGLBL2,
+ .reg_cnfg_glbl3 = MAX77620_REG_CNFGGLBL3,
+ .wdtc_mask = MAX77620_WDTC_MASK,
+ .bit_wd_rst_wk = MAX77620_ONOFFCNFG2_WD_RST_WK,
+ /* Set WDT clear in OFF and sleep mode */
+ .cnfg_glbl2_cfg_bits = MAX77620_WDTSLPC | MAX77620_WDTOFFC,
+};
+
+static const struct max77620_variant max77714_wdt_data = {
+ .reg_onoff_cnfg2 = MAX77714_CNFG2_ONOFF,
+ .reg_cnfg_glbl2 = MAX77714_CNFG_GLBL2,
+ .reg_cnfg_glbl3 = MAX77714_CNFG_GLBL3,
+ .wdtc_mask = MAX77714_WDTC,
+ .bit_wd_rst_wk = MAX77714_WD_RST_WK,
+ /* Set WDT clear in sleep mode (there is no WDTOFFC on MAX77714) */
+ .cnfg_glbl2_cfg_bits = MAX77714_WDTSLPC,
+};
+
static int max77620_wdt_start(struct watchdog_device *wdt_dev)
{
struct max77620_wdt *wdt = watchdog_get_drvdata(wdt_dev);
- return regmap_update_bits(wdt->rmap, MAX77620_REG_CNFGGLBL2,
+ return regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2,
MAX77620_WDTEN, MAX77620_WDTEN);
}
@@ -38,7 +81,7 @@ static int max77620_wdt_stop(struct watchdog_device *wdt_dev)
{
struct max77620_wdt *wdt = watchdog_get_drvdata(wdt_dev);
- return regmap_update_bits(wdt->rmap, MAX77620_REG_CNFGGLBL2,
+ return regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2,
MAX77620_WDTEN, 0);
}
@@ -46,8 +89,8 @@ static int max77620_wdt_ping(struct watchdog_device *wdt_dev)
{
struct max77620_wdt *wdt = watchdog_get_drvdata(wdt_dev);
- return regmap_update_bits(wdt->rmap, MAX77620_REG_CNFGGLBL3,
- MAX77620_WDTC_MASK, 0x1);
+ return regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl3,
+ wdt->drv_data->wdtc_mask, 0x1);
}
static int max77620_wdt_set_timeout(struct watchdog_device *wdt_dev,
@@ -80,12 +123,17 @@ static int max77620_wdt_set_timeout(struct watchdog_device *wdt_dev,
break;
}
- ret = regmap_update_bits(wdt->rmap, MAX77620_REG_CNFGGLBL3,
- MAX77620_WDTC_MASK, 0x1);
+ /*
+ * "If the value of TWD needs to be changed, clear the system
+ * watchdog timer first [...], then change the value of TWD."
+ * (MAX77714 datasheet but applies to MAX77620 too)
+ */
+ ret = regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl3,
+ wdt->drv_data->wdtc_mask, 0x1);
if (ret < 0)
return ret;
- ret = regmap_update_bits(wdt->rmap, MAX77620_REG_CNFGGLBL2,
+ ret = regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2,
MAX77620_TWD_MASK, regval);
if (ret < 0)
return ret;
@@ -109,6 +157,7 @@ static const struct watchdog_ops max77620_wdt_ops = {
static int max77620_wdt_probe(struct platform_device *pdev)
{
+ const struct platform_device_id *id = platform_get_device_id(pdev);
struct device *dev = &pdev->dev;
struct max77620_wdt *wdt;
struct watchdog_device *wdt_dev;
@@ -120,6 +169,8 @@ static int max77620_wdt_probe(struct platform_device *pdev)
return -ENOMEM;
wdt->dev = dev;
+ wdt->drv_data = (const struct max77620_variant *) id->driver_data;
+
wdt->rmap = dev_get_regmap(dev->parent, NULL);
if (!wdt->rmap) {
dev_err(wdt->dev, "Failed to get parent regmap\n");
@@ -136,25 +187,25 @@ static int max77620_wdt_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, wdt);
/* Enable WD_RST_WK - WDT expire results in a restart */
- ret = regmap_update_bits(wdt->rmap, MAX77620_REG_ONOFFCNFG2,
- MAX77620_ONOFFCNFG2_WD_RST_WK,
- MAX77620_ONOFFCNFG2_WD_RST_WK);
+ ret = regmap_update_bits(wdt->rmap, wdt->drv_data->reg_onoff_cnfg2,
+ wdt->drv_data->bit_wd_rst_wk,
+ wdt->drv_data->bit_wd_rst_wk);
if (ret < 0) {
dev_err(wdt->dev, "Failed to set WD_RST_WK: %d\n", ret);
return ret;
}
- /* Set WDT clear in OFF and sleep mode */
- ret = regmap_update_bits(wdt->rmap, MAX77620_REG_CNFGGLBL2,
- MAX77620_WDTOFFC | MAX77620_WDTSLPC,
- MAX77620_WDTOFFC | MAX77620_WDTSLPC);
+ /* Set the "auto WDT clear" bits available on the chip */
+ ret = regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2,
+ wdt->drv_data->cnfg_glbl2_cfg_bits,
+ wdt->drv_data->cnfg_glbl2_cfg_bits);
if (ret < 0) {
dev_err(wdt->dev, "Failed to set WDT OFF mode: %d\n", ret);
return ret;
}
/* Check if WDT running and if yes then set flags properly */
- ret = regmap_read(wdt->rmap, MAX77620_REG_CNFGGLBL2, &regval);
+ ret = regmap_read(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2, &regval);
if (ret < 0) {
dev_err(wdt->dev, "Failed to read WDT CFG register: %d\n", ret);
return ret;
@@ -186,7 +237,8 @@ static int max77620_wdt_probe(struct platform_device *pdev)
}
static const struct platform_device_id max77620_wdt_devtype[] = {
- { .name = "max77620-watchdog", },
+ { "max77620-watchdog", (kernel_ulong_t)&max77620_wdt_data },
+ { "max77714-watchdog", (kernel_ulong_t)&max77714_wdt_data },
{ },
};
MODULE_DEVICE_TABLE(platform, max77620_wdt_devtype);
@@ -208,4 +260,5 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_AUTHOR("Luca Ceresoli <luca@lucaceresoli.net>");
MODULE_LICENSE("GPL v2");