diff options
| -rw-r--r-- | Documentation/devicetree/bindings/watchdog/allwinner,sun4i-a10-wdt.yaml | 2 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/watchdog/fsl-imx7ulp-wdt.yaml | 4 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml | 4 | ||||
| -rw-r--r-- | drivers/watchdog/Kconfig | 22 | ||||
| -rw-r--r-- | drivers/watchdog/Makefile | 1 | ||||
| -rw-r--r-- | drivers/watchdog/aspeed_wdt.c | 81 | ||||
| -rw-r--r-- | drivers/watchdog/cros_ec_wdt.c | 10 | ||||
| -rw-r--r-- | drivers/watchdog/lenovo_se30_wdt.c | 394 | ||||
| -rw-r--r-- | drivers/watchdog/nic7018_wdt.c | 9 | ||||
| -rw-r--r-- | drivers/watchdog/npcm_wdt.c | 9 | ||||
| -rw-r--r-- | drivers/watchdog/s3c2410_wdt.c | 10 | ||||
| -rw-r--r-- | drivers/watchdog/sunxi_wdt.c | 11 | ||||
| -rw-r--r-- | drivers/watchdog/watchdog_core.c | 6 | 
13 files changed, 535 insertions, 28 deletions
| diff --git a/Documentation/devicetree/bindings/watchdog/allwinner,sun4i-a10-wdt.yaml b/Documentation/devicetree/bindings/watchdog/allwinner,sun4i-a10-wdt.yaml index 64c8f7393809..b35ac03d5172 100644 --- a/Documentation/devicetree/bindings/watchdog/allwinner,sun4i-a10-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/allwinner,sun4i-a10-wdt.yaml @@ -32,6 +32,7 @@ properties:        - items:            - const: allwinner,sun20i-d1-wdt-reset            - const: allwinner,sun20i-d1-wdt +      - const: allwinner,sun55i-a523-wdt    reg:      maxItems: 1 @@ -60,6 +61,7 @@ if:            - allwinner,sun20i-d1-wdt-reset            - allwinner,sun50i-r329-wdt            - allwinner,sun50i-r329-wdt-reset +          - allwinner,sun55i-a523-wdt  then:    properties: diff --git a/Documentation/devicetree/bindings/watchdog/fsl-imx7ulp-wdt.yaml b/Documentation/devicetree/bindings/watchdog/fsl-imx7ulp-wdt.yaml index a09686b3030d..6ec391b9723a 100644 --- a/Documentation/devicetree/bindings/watchdog/fsl-imx7ulp-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/fsl-imx7ulp-wdt.yaml @@ -22,6 +22,10 @@ properties:            - const: fsl,imx8ulp-wdt            - const: fsl,imx7ulp-wdt        - const: fsl,imx93-wdt +      - items: +          - enum: +              - fsl,imx94-wdt +          - const: fsl,imx93-wdt    reg:      maxItems: 1 diff --git a/Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml b/Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml index 29ada89fdcdc..3e0a8747a357 100644 --- a/Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml @@ -75,6 +75,10 @@ properties:                - renesas,r8a779h0-wdt     # R-Car V4M            - const: renesas,rcar-gen4-wdt # R-Car Gen4 +      - items: +          - const: renesas,r9a09g047-wdt # RZ/G3E +          - const: renesas,r9a09g057-wdt # RZ/V2H(P) +        - const: renesas,r9a09g057-wdt       # RZ/V2H(P)    reg: diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index f81705f8539a..0d8d37f712e8 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -279,6 +279,18 @@ config LENOVO_SE10_WDT  	  This driver can also be built as a module. If so, the module  	  will be called lenovo-se10-wdt. +config LENOVO_SE30_WDT +	tristate "Lenovo SE30 Watchdog" +	depends on (X86 && DMI) || COMPILE_TEST +	depends on HAS_IOPORT +	select WATCHDOG_CORE +	help +	  If you say yes here you get support for the watchdog +	  functionality for the Lenovo SE30 platform. + +	  This driver can also be built as a module. If so, the module +	  will be called lenovo-se30-wdt. +  config MENF21BMC_WATCHDOG  	tristate "MEN 14F021P00 BMC Watchdog"  	depends on MFD_MENF21BMC || COMPILE_TEST @@ -963,13 +975,14 @@ config RENESAS_RZG2LWDT  	  Renesas RZ/G2L SoCs. These watchdogs can be used to reset a system.  config RENESAS_RZV2HWDT -	tristate "Renesas RZ/V2H(P) WDT Watchdog" -	depends on ARCH_R9A09G057 || COMPILE_TEST +	tristate "Renesas RZ/{G3E,V2H(P)} WDT Watchdog" +	depends on ARCH_RENESAS || COMPILE_TEST  	depends on PM || COMPILE_TEST  	select WATCHDOG_CORE  	help  	  This driver adds watchdog support for the integrated watchdogs in the -	  Renesas RZ/V2H(P) SoCs. These watchdogs can be used to reset a system. +	  Renesas RZ/{G3E,V2H(P)} SoCs. These watchdogs can be used to reset a +	  system.  config ASPEED_WATCHDOG  	tristate "Aspeed BMC watchdog support" @@ -1730,7 +1743,8 @@ config NI903X_WDT  config NIC7018_WDT  	tristate "NIC7018 Watchdog" -	depends on X86 && ACPI +	depends on HAS_IOPORT +	depends on ACPI || COMPILE_TEST  	select WATCHDOG_CORE  	help  	  Support for National Instruments NIC7018 Watchdog. diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 8411626fa162..c9482904bf87 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -124,6 +124,7 @@ obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o  obj-$(CONFIG_IE6XX_WDT) += ie6xx_wdt.o  obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o  obj-$(CONFIG_LENOVO_SE10_WDT) += lenovo_se10_wdt.o +obj-$(CONFIG_LENOVO_SE30_WDT) += lenovo_se30_wdt.o  ifeq ($(CONFIG_ITCO_VENDOR_SUPPORT),y)  obj-$(CONFIG_ITCO_WDT) += iTCO_vendor_support.o  endif diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c index b4773a6aaf8c..837e15701c0e 100644 --- a/drivers/watchdog/aspeed_wdt.c +++ b/drivers/watchdog/aspeed_wdt.c @@ -11,21 +11,30 @@  #include <linux/io.h>  #include <linux/kernel.h>  #include <linux/kstrtox.h> +#include <linux/mfd/syscon.h>  #include <linux/module.h>  #include <linux/of.h>  #include <linux/of_irq.h>  #include <linux/platform_device.h> +#include <linux/regmap.h>  #include <linux/watchdog.h>  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) ")"); +struct aspeed_wdt_scu { +	const char *compatible; +	u32 reset_status_reg; +	u32 wdt_reset_mask; +	u32 wdt_reset_mask_shift; +};  struct aspeed_wdt_config {  	u32 ext_pulse_width_mask;  	u32 irq_shift;  	u32 irq_mask; +	struct aspeed_wdt_scu scu;  };  struct aspeed_wdt { @@ -39,18 +48,36 @@ static const struct aspeed_wdt_config ast2400_config = {  	.ext_pulse_width_mask = 0xff,  	.irq_shift = 0,  	.irq_mask = 0, +	.scu = { +		.compatible = "aspeed,ast2400-scu", +		.reset_status_reg = 0x3c, +		.wdt_reset_mask = 0x1, +		.wdt_reset_mask_shift = 1, +	},  };  static const struct aspeed_wdt_config ast2500_config = {  	.ext_pulse_width_mask = 0xfffff,  	.irq_shift = 12,  	.irq_mask = GENMASK(31, 12), +	.scu = { +		.compatible = "aspeed,ast2500-scu", +		.reset_status_reg = 0x3c, +		.wdt_reset_mask = 0x1, +		.wdt_reset_mask_shift = 2, +	},  };  static const struct aspeed_wdt_config ast2600_config = {  	.ext_pulse_width_mask = 0xfffff,  	.irq_shift = 0,  	.irq_mask = GENMASK(31, 10), +	.scu = { +		.compatible = "aspeed,ast2600-scu", +		.reset_status_reg = 0x74, +		.wdt_reset_mask = 0xf, +		.wdt_reset_mask_shift = 16, +	},  };  static const struct of_device_id aspeed_wdt_of_table[] = { @@ -213,6 +240,56 @@ static int aspeed_wdt_restart(struct watchdog_device *wdd,  	return 0;  } +static void aspeed_wdt_update_bootstatus(struct platform_device *pdev, +					 struct aspeed_wdt *wdt) +{ +	const struct resource *res; +	struct aspeed_wdt_scu scu = wdt->cfg->scu; +	struct regmap *scu_base; +	u32 reset_mask_width; +	u32 reset_mask_shift; +	u32 idx = 0; +	u32 status; +	int ret; + +	if (!of_device_is_compatible(pdev->dev.of_node, "aspeed,ast2400-wdt")) { +		res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +		idx = ((intptr_t)wdt->base & 0x00000fff) / (uintptr_t)resource_size(res); +	} + +	scu_base = syscon_regmap_lookup_by_compatible(scu.compatible); +	if (IS_ERR(scu_base)) { +		wdt->wdd.bootstatus = WDIOS_UNKNOWN; +		return; +	} + +	ret = regmap_read(scu_base, scu.reset_status_reg, &status); +	if (ret) { +		wdt->wdd.bootstatus = WDIOS_UNKNOWN; +		return; +	} + +	reset_mask_width = hweight32(scu.wdt_reset_mask); +	reset_mask_shift = scu.wdt_reset_mask_shift + +			   reset_mask_width * idx; + +	if (status & (scu.wdt_reset_mask << reset_mask_shift)) +		wdt->wdd.bootstatus = WDIOF_CARDRESET; + +	/* clear wdt reset event flag */ +	if (of_device_is_compatible(pdev->dev.of_node, "aspeed,ast2400-wdt") || +	    of_device_is_compatible(pdev->dev.of_node, "aspeed,ast2500-wdt")) { +		ret = regmap_read(scu_base, scu.reset_status_reg, &status); +		if (!ret) { +			status &= ~(scu.wdt_reset_mask << reset_mask_shift); +			regmap_write(scu_base, scu.reset_status_reg, status); +		} +	} else { +		regmap_write(scu_base, scu.reset_status_reg, +			     scu.wdt_reset_mask << reset_mask_shift); +	} +} +  /* access_cs0 shows if cs0 is accessible, hence the reverted bit */  static ssize_t access_cs0_show(struct device *dev,  			       struct device_attribute *attr, char *buf) @@ -458,10 +535,10 @@ static int aspeed_wdt_probe(struct platform_device *pdev)  		writel(duration - 1, wdt->base + WDT_RESET_WIDTH);  	} +	aspeed_wdt_update_bootstatus(pdev, wdt); +  	status = readl(wdt->base + WDT_TIMEOUT_STATUS);  	if (status & WDT_TIMEOUT_STATUS_BOOT_SECONDARY) { -		wdt->wdd.bootstatus = WDIOF_CARDRESET; -  		if (of_device_is_compatible(np, "aspeed,ast2400-wdt") ||  		    of_device_is_compatible(np, "aspeed,ast2500-wdt"))  			wdt->wdd.groups = bswitch_groups; diff --git a/drivers/watchdog/cros_ec_wdt.c b/drivers/watchdog/cros_ec_wdt.c index ba045e29f9a5..716c23f4388c 100644 --- a/drivers/watchdog/cros_ec_wdt.c +++ b/drivers/watchdog/cros_ec_wdt.c @@ -58,7 +58,7 @@ static int cros_ec_wdt_ping(struct watchdog_device *wdd)  	arg.req.command = EC_HANG_DETECT_CMD_RELOAD;  	ret = cros_ec_wdt_send_cmd(cros_ec, &arg);  	if (ret < 0) -		dev_dbg(wdd->parent, "Failed to ping watchdog (%d)", ret); +		dev_dbg(wdd->parent, "Failed to ping watchdog (%d)\n", ret);  	return ret;  } @@ -74,7 +74,7 @@ static int cros_ec_wdt_start(struct watchdog_device *wdd)  	arg.req.reboot_timeout_sec = wdd->timeout;  	ret = cros_ec_wdt_send_cmd(cros_ec, &arg);  	if (ret < 0) -		dev_dbg(wdd->parent, "Failed to start watchdog (%d)", ret); +		dev_dbg(wdd->parent, "Failed to start watchdog (%d)\n", ret);  	return ret;  } @@ -88,7 +88,7 @@ static int cros_ec_wdt_stop(struct watchdog_device *wdd)  	arg.req.command = EC_HANG_DETECT_CMD_CANCEL;  	ret = cros_ec_wdt_send_cmd(cros_ec, &arg);  	if (ret < 0) -		dev_dbg(wdd->parent, "Failed to stop watchdog (%d)", ret); +		dev_dbg(wdd->parent, "Failed to stop watchdog (%d)\n", ret);  	return ret;  } @@ -136,7 +136,7 @@ static int cros_ec_wdt_probe(struct platform_device *pdev)  	arg.req.command = EC_HANG_DETECT_CMD_GET_STATUS;  	ret = cros_ec_wdt_send_cmd(cros_ec, &arg);  	if (ret < 0) -		return dev_err_probe(dev, ret, "Failed to get watchdog bootstatus"); +		return dev_err_probe(dev, ret, "Failed to get watchdog bootstatus\n");  	wdd->parent = &pdev->dev;  	wdd->info = &cros_ec_wdt_ident; @@ -150,7 +150,7 @@ static int cros_ec_wdt_probe(struct platform_device *pdev)  	arg.req.command = EC_HANG_DETECT_CMD_CLEAR_STATUS;  	ret = cros_ec_wdt_send_cmd(cros_ec, &arg);  	if (ret < 0) -		return dev_err_probe(dev, ret, "Failed to clear watchdog bootstatus"); +		return dev_err_probe(dev, ret, "Failed to clear watchdog bootstatus\n");  	watchdog_stop_on_reboot(wdd);  	watchdog_stop_on_unregister(wdd); diff --git a/drivers/watchdog/lenovo_se30_wdt.c b/drivers/watchdog/lenovo_se30_wdt.c new file mode 100644 index 000000000000..024b842499b3 --- /dev/null +++ b/drivers/watchdog/lenovo_se30_wdt.c @@ -0,0 +1,394 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * WDT driver for Lenovo SE30 device + */ + +#define dev_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/io.h> +#include <linux/dmi.h> +#include <linux/delay.h> +#include <linux/iommu.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/platform_device.h> +#include <linux/watchdog.h> + +#define IOREGION_OFFSET	4 /* Use EC port 1 */ +#define IOREGION_LENGTH	4 + +#define WATCHDOG_TIMEOUT	60 + +#define MIN_TIMEOUT	1 +#define MAX_TIMEOUT	255 +#define MAX_WAIT	10 + +static int timeout; /* in seconds */ +module_param(timeout, int, 0); +MODULE_PARM_DESC(timeout, +		 "Watchdog timeout in seconds. 1 <= timeout <= 255, default=" +		 __MODULE_STRING(WATCHDOG_TIMEOUT) "."); + +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) ")"); + +#define LNV_SE30_NAME	"lenovo-se30-wdt" +#define LNV_SE30_ID	0x0110 +#define CHIPID_MASK	0xFFF0 + +#define CHIPID_REG	0x20 +#define SIO_REG		0x2e +#define LDN_REG		0x07 +#define UNLOCK_KEY	0x87 +#define LOCK_KEY	0xAA +#define LD_NUM_SHM	0x0F +#define LD_BASE_ADDR	0xF8 + +#define WDT_MODULE	0x10 +#define WDT_CFG_INDEX	0x15 /* WD configuration register */ +#define WDT_CNT_INDEX	0x16 /* WD timer count register */ +#define WDT_CFG_RESET	0x2 + +/* Host Interface WIN2 offset definition */ +#define SHM_WIN_SIZE		0xFF +#define SHM_WIN_MOD_OFFSET	0x01 +#define SHM_WIN_CMD_OFFSET	0x02 +#define SHM_WIN_SEL_OFFSET	0x03 +#define SHM_WIN_CTL_OFFSET	0x04 +#define VAL_SHM_WIN_CTRL_WR	0x40 +#define VAL_SHM_WIN_CTRL_RD	0x80 +#define SHM_WIN_ID_OFFSET	0x08 +#define SHM_WIN_DAT_OFFSET	0x10 + +struct nct6692_reg { +	unsigned char mod; +	unsigned char cmd; +	unsigned char sel; +	unsigned int idx; +}; + +/* Watchdog is based on NCT6692 device */ +struct lenovo_se30_wdt { +	unsigned char __iomem *shm_base_addr; +	struct nct6692_reg wdt_cfg; +	struct nct6692_reg wdt_cnt; +	struct watchdog_device wdt; +}; + +static inline void superio_outb(int ioreg, int reg, int val) +{ +	outb(reg, ioreg); +	outb(val, ioreg + 1); +} + +static inline int superio_inb(int ioreg, int reg) +{ +	outb(reg, ioreg); +	return inb(ioreg + 1); +} + +static inline int superio_enter(int key, int addr, const char *name) +{ +	if (!request_muxed_region(addr, 2, name)) { +		pr_err("I/O address 0x%04x already in use\n", addr); +		return -EBUSY; +	} +	outb(key, addr); /* Enter extended function mode */ +	outb(key, addr); /* Again according to manual */ + +	return 0; +} + +static inline void superio_exit(int key, int addr) +{ +	outb(key, addr); /* Leave extended function mode */ +	release_region(addr, 2); +} + +static int shm_get_ready(unsigned char __iomem *shm_base_addr, +			 const struct nct6692_reg *reg) +{ +	unsigned char pre_id, new_id; +	int loop = 0; + +	iowrite8(reg->mod, shm_base_addr + SHM_WIN_MOD_OFFSET); +	iowrite8(reg->cmd, shm_base_addr + SHM_WIN_CMD_OFFSET); +	iowrite8(reg->sel, shm_base_addr + SHM_WIN_SEL_OFFSET); + +	pre_id = ioread8(shm_base_addr + SHM_WIN_ID_OFFSET); +	iowrite8(VAL_SHM_WIN_CTRL_RD, shm_base_addr + SHM_WIN_CTL_OFFSET); + +	/* Loop checking when interface is ready */ +	while (loop < MAX_WAIT) { +		new_id = ioread8(shm_base_addr + SHM_WIN_ID_OFFSET); +		if (new_id != pre_id) +			return 0; +		loop++; +		usleep_range(10, 125); +	} +	return -ETIMEDOUT; +} + +static int read_shm_win(unsigned char __iomem *shm_base_addr, +			const struct nct6692_reg *reg, +			unsigned char idx_offset, +			unsigned char *data) +{ +	int err = shm_get_ready(shm_base_addr, reg); + +	if (err) +		return err; +	*data = ioread8(shm_base_addr + SHM_WIN_DAT_OFFSET + reg->idx + idx_offset); +	return 0; +} + +static int write_shm_win(unsigned char __iomem *shm_base_addr, +			 const struct nct6692_reg *reg, +			 unsigned char idx_offset, +			 unsigned char val) +{ +	int err = shm_get_ready(shm_base_addr, reg); + +	if (err) +		return err; +	iowrite8(val, shm_base_addr + SHM_WIN_DAT_OFFSET + reg->idx + idx_offset); +	iowrite8(VAL_SHM_WIN_CTRL_WR, shm_base_addr + SHM_WIN_CTL_OFFSET); +	err = shm_get_ready(shm_base_addr, reg); +	return err; +} + +static int lenovo_se30_wdt_enable(struct lenovo_se30_wdt *data, unsigned int timeout) +{ +	if (timeout) { +		int err = write_shm_win(data->shm_base_addr, &data->wdt_cfg, 0, WDT_CFG_RESET); + +		if (err) +			return err; +	} +	return write_shm_win(data->shm_base_addr, &data->wdt_cnt, 0, timeout); +} + +static int lenovo_se30_wdt_start(struct watchdog_device *wdog) +{ +	struct lenovo_se30_wdt *data = watchdog_get_drvdata(wdog); + +	return lenovo_se30_wdt_enable(data, wdog->timeout); +} + +static int lenovo_se30_wdt_stop(struct watchdog_device *wdog) +{ +	struct lenovo_se30_wdt *data = watchdog_get_drvdata(wdog); + +	return lenovo_se30_wdt_enable(data, 0); +} + +static unsigned int lenovo_se30_wdt_get_timeleft(struct watchdog_device *wdog) +{ +	struct lenovo_se30_wdt *data = watchdog_get_drvdata(wdog); +	unsigned char timeleft; +	int err; + +	err = read_shm_win(data->shm_base_addr, &data->wdt_cnt, 0, &timeleft); +	if (err) +		return 0; +	return timeleft; +} + +static int lenovo_se30_wdt_ping(struct watchdog_device *wdt) +{ +	struct lenovo_se30_wdt *data = watchdog_get_drvdata(wdt); +	int err = 0; + +	/* +	 * Device does not support refreshing WDT_TIMER_REG register when +	 * the watchdog is active.  Need to disable, feed and enable again +	 */ +	err = lenovo_se30_wdt_enable(data, 0); +	if (err) +		return err; + +	err = write_shm_win(data->shm_base_addr, &data->wdt_cnt, 0, wdt->timeout); +	if (!err) +		err = lenovo_se30_wdt_enable(data, wdt->timeout); + +	return err; +} + +static const struct watchdog_info lenovo_se30_wdt_info = { +	.options	= WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | +			  WDIOF_MAGICCLOSE, +	.identity	= "Lenovo SE30 watchdog", +}; + +static const struct watchdog_ops lenovo_se30_wdt_ops = { +	.owner		= THIS_MODULE, +	.start		= lenovo_se30_wdt_start, +	.stop		= lenovo_se30_wdt_stop, +	.ping		= lenovo_se30_wdt_ping, +	.get_timeleft	= lenovo_se30_wdt_get_timeleft, +}; + +static int lenovo_se30_wdt_probe(struct platform_device *pdev) +{ +	struct device *dev = &pdev->dev; +	struct lenovo_se30_wdt *priv; +	unsigned long base_phys; +	unsigned short val; +	int err; + +	err = superio_enter(UNLOCK_KEY, SIO_REG, LNV_SE30_NAME); +	if (err) +		return err; + +	val = superio_inb(SIO_REG, CHIPID_REG) << 8; +	val |= superio_inb(SIO_REG, CHIPID_REG + 1); + +	if ((val & CHIPID_MASK) != LNV_SE30_ID) { +		superio_exit(LOCK_KEY, SIO_REG); +		return -ENODEV; +	} + +	superio_outb(SIO_REG, LDN_REG, LD_NUM_SHM); +	base_phys = (superio_inb(SIO_REG, LD_BASE_ADDR) | +			 (superio_inb(SIO_REG, LD_BASE_ADDR + 1) << 8) | +			 (superio_inb(SIO_REG, LD_BASE_ADDR + 2) << 16) | +			 (superio_inb(SIO_REG, LD_BASE_ADDR + 3) << 24)) & +			0xFFFFFFFF; + +	superio_exit(LOCK_KEY, SIO_REG); +	if (base_phys == 0xFFFFFFFF || base_phys == 0) +		return -ENODEV; + +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); +	if (!priv) +		return -ENOMEM; + +	if (!devm_request_mem_region(dev, base_phys, SHM_WIN_SIZE, LNV_SE30_NAME)) +		return -EBUSY; + +	priv->shm_base_addr = devm_ioremap(dev, base_phys, SHM_WIN_SIZE); + +	priv->wdt_cfg.mod = WDT_MODULE; +	priv->wdt_cfg.idx = WDT_CFG_INDEX; +	priv->wdt_cnt.mod = WDT_MODULE; +	priv->wdt_cnt.idx = WDT_CNT_INDEX; + +	priv->wdt.ops = &lenovo_se30_wdt_ops; +	priv->wdt.info = &lenovo_se30_wdt_info; +	priv->wdt.timeout = WATCHDOG_TIMEOUT; /* Set default timeout */ +	priv->wdt.min_timeout = MIN_TIMEOUT; +	priv->wdt.max_timeout = MAX_TIMEOUT; +	priv->wdt.parent = dev; + +	watchdog_init_timeout(&priv->wdt, timeout, dev); +	watchdog_set_drvdata(&priv->wdt, priv); +	watchdog_set_nowayout(&priv->wdt, nowayout); +	watchdog_stop_on_reboot(&priv->wdt); +	watchdog_stop_on_unregister(&priv->wdt); + +	return devm_watchdog_register_device(dev, &priv->wdt); +} + +static struct platform_device *pdev; + +static struct platform_driver lenovo_se30_wdt_driver = { +	.driver = { +		.name = LNV_SE30_NAME, +	}, +	.probe  = lenovo_se30_wdt_probe, +}; + +static int lenovo_se30_create_platform_device(const struct dmi_system_id *id) +{ +	int err; + +	pdev = platform_device_alloc(LNV_SE30_NAME, -1); +	if (!pdev) +		return -ENOMEM; + +	err = platform_device_add(pdev); +	if (err) +		platform_device_put(pdev); + +	return err; +} + +static const struct dmi_system_id lenovo_se30_wdt_dmi_table[] __initconst = { +	{ +		.ident = "LENOVO-SE30", +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), +			DMI_MATCH(DMI_PRODUCT_NAME, "11NA"), +		}, +		.callback = lenovo_se30_create_platform_device, +	}, +	{ +		.ident = "LENOVO-SE30", +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), +			DMI_MATCH(DMI_PRODUCT_NAME, "11NB"), +		}, +		.callback = lenovo_se30_create_platform_device, +	}, +	{ +		.ident = "LENOVO-SE30", +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), +			DMI_MATCH(DMI_PRODUCT_NAME, "11NC"), +		}, +		.callback = lenovo_se30_create_platform_device, +	}, +	{ +		.ident = "LENOVO-SE30", +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), +			DMI_MATCH(DMI_PRODUCT_NAME, "11NH"), +		}, +		.callback = lenovo_se30_create_platform_device, +	}, +	{ +		.ident = "LENOVO-SE30", +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), +			DMI_MATCH(DMI_PRODUCT_NAME, "11NJ"), +		}, +		.callback = lenovo_se30_create_platform_device, +	}, +	{ +		.ident = "LENOVO-SE30", +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), +			DMI_MATCH(DMI_PRODUCT_NAME, "11NK"), +		}, +		.callback = lenovo_se30_create_platform_device, +	}, +	{} +}; +MODULE_DEVICE_TABLE(dmi, lenovo_se30_wdt_dmi_table); + +static int __init lenovo_se30_wdt_init(void) +{ +	if (!dmi_check_system(lenovo_se30_wdt_dmi_table)) +		return -ENODEV; + +	return platform_driver_register(&lenovo_se30_wdt_driver); +} + +static void __exit lenovo_se30_wdt_exit(void) +{ +	if (pdev) +		platform_device_unregister(pdev); +	platform_driver_unregister(&lenovo_se30_wdt_driver); +} + +module_init(lenovo_se30_wdt_init); +module_exit(lenovo_se30_wdt_exit); + +MODULE_AUTHOR("Mark Pearson <mpearson-lenovo@squebb.ca>"); +MODULE_AUTHOR("David Ober <dober@lenovo.com>"); +MODULE_DESCRIPTION("Lenovo SE30 watchdog driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/watchdog/nic7018_wdt.c b/drivers/watchdog/nic7018_wdt.c index 44982b37ba6f..44b5298f599a 100644 --- a/drivers/watchdog/nic7018_wdt.c +++ b/drivers/watchdog/nic7018_wdt.c @@ -3,12 +3,13 @@   * Copyright (C) 2016 National Instruments Corp.   */ -#include <linux/acpi.h>  #include <linux/bitops.h>  #include <linux/device.h>  #include <linux/io.h> +#include <linux/mod_devicetable.h>  #include <linux/module.h>  #include <linux/platform_device.h> +#include <linux/types.h>  #include <linux/watchdog.h>  #define LOCK			0xA5 @@ -229,8 +230,8 @@ static void nic7018_remove(struct platform_device *pdev)  }  static const struct acpi_device_id nic7018_device_ids[] = { -	{"NIC7018", 0}, -	{"", 0}, +	{ "NIC7018" }, +	{ }  };  MODULE_DEVICE_TABLE(acpi, nic7018_device_ids); @@ -239,7 +240,7 @@ static struct platform_driver watchdog_driver = {  	.remove = nic7018_remove,  	.driver = {  		.name = KBUILD_MODNAME, -		.acpi_match_table = ACPI_PTR(nic7018_device_ids), +		.acpi_match_table = nic7018_device_ids,  	},  }; diff --git a/drivers/watchdog/npcm_wdt.c b/drivers/watchdog/npcm_wdt.c index a5dd1c230137..e62ea054bc61 100644 --- a/drivers/watchdog/npcm_wdt.c +++ b/drivers/watchdog/npcm_wdt.c @@ -68,8 +68,7 @@ static int npcm_wdt_start(struct watchdog_device *wdd)  	struct npcm_wdt *wdt = to_npcm_wdt(wdd);  	u32 val; -	if (wdt->clk) -		clk_prepare_enable(wdt->clk); +	clk_prepare_enable(wdt->clk);  	if (wdd->timeout < 2)  		val = 0x800; @@ -105,8 +104,7 @@ static int npcm_wdt_stop(struct watchdog_device *wdd)  	writel(0, wdt->reg); -	if (wdt->clk) -		clk_disable_unprepare(wdt->clk); +	clk_disable_unprepare(wdt->clk);  	return 0;  } @@ -156,8 +154,7 @@ static int npcm_wdt_restart(struct watchdog_device *wdd,  	struct npcm_wdt *wdt = to_npcm_wdt(wdd);  	/* For reset, we start the WDT clock and leave it running. */ -	if (wdt->clk) -		clk_prepare_enable(wdt->clk); +	clk_prepare_enable(wdt->clk);  	writel(NPCM_WTR | NPCM_WTRE | NPCM_WTE, wdt->reg);  	udelay(1000); diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 30450e99e5e9..bdd81d8074b2 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -72,6 +72,8 @@  #define EXYNOS850_CLUSTER1_WDTRESET_BIT		23  #define EXYNOSAUTOV9_CLUSTER0_WDTRESET_BIT	25  #define EXYNOSAUTOV9_CLUSTER1_WDTRESET_BIT	24 +#define EXYNOSAUTOV920_CLUSTER0_WDTRESET_BIT	0 +#define EXYNOSAUTOV920_CLUSTER1_WDTRESET_BIT	1  #define GS_CLUSTER0_NONCPU_OUT			0x1220  #define GS_CLUSTER1_NONCPU_OUT			0x1420 @@ -312,9 +314,9 @@ static const struct s3c2410_wdt_variant drv_data_exynosautov920_cl0 = {  	.mask_bit = 2,  	.mask_reset_inv = true,  	.rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, -	.rst_stat_bit = EXYNOSAUTOV9_CLUSTER0_WDTRESET_BIT, +	.rst_stat_bit = EXYNOSAUTOV920_CLUSTER0_WDTRESET_BIT,  	.cnt_en_reg = EXYNOSAUTOV920_CLUSTER0_NONCPU_OUT, -	.cnt_en_bit = 7, +	.cnt_en_bit = 8,  	.quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET |  		  QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN |  		  QUIRK_HAS_DBGACK_BIT, @@ -325,9 +327,9 @@ static const struct s3c2410_wdt_variant drv_data_exynosautov920_cl1 = {  	.mask_bit = 2,  	.mask_reset_inv = true,  	.rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, -	.rst_stat_bit = EXYNOSAUTOV9_CLUSTER1_WDTRESET_BIT, +	.rst_stat_bit = EXYNOSAUTOV920_CLUSTER1_WDTRESET_BIT,  	.cnt_en_reg = EXYNOSAUTOV920_CLUSTER1_NONCPU_OUT, -	.cnt_en_bit = 7, +	.cnt_en_bit = 8,  	.quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET |  		  QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN |  		  QUIRK_HAS_DBGACK_BIT, diff --git a/drivers/watchdog/sunxi_wdt.c b/drivers/watchdog/sunxi_wdt.c index b85354a99582..b6c761acc3de 100644 --- a/drivers/watchdog/sunxi_wdt.c +++ b/drivers/watchdog/sunxi_wdt.c @@ -236,10 +236,21 @@ static const struct sunxi_wdt_reg sun20i_wdt_reg = {  	.wdt_key_val = 0x16aa0000,  }; +static const struct sunxi_wdt_reg sun55i_wdt_reg = { +	.wdt_ctrl = 0x0c, +	.wdt_cfg = 0x10, +	.wdt_mode = 0x14, +	.wdt_timeout_shift = 4, +	.wdt_reset_mask = 0x03, +	.wdt_reset_val = 0x01, +	.wdt_key_val = 0x16aa0000, +}; +  static const struct of_device_id sunxi_wdt_dt_ids[] = {  	{ .compatible = "allwinner,sun4i-a10-wdt", .data = &sun4i_wdt_reg },  	{ .compatible = "allwinner,sun6i-a31-wdt", .data = &sun6i_wdt_reg },  	{ .compatible = "allwinner,sun20i-d1-wdt", .data = &sun20i_wdt_reg }, +	{ .compatible = "allwinner,sun55i-a523-wdt", .data = &sun55i_wdt_reg },  	{ /* sentinel */ }  };  MODULE_DEVICE_TABLE(of, sunxi_wdt_dt_ids); diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c index d46d8c8c01f2..6152dba4b52c 100644 --- a/drivers/watchdog/watchdog_core.c +++ b/drivers/watchdog/watchdog_core.c @@ -33,7 +33,8 @@  #include <linux/init.h>		/* For __init/__exit/... */  #include <linux/idr.h>		/* For ida_* macros */  #include <linux/err.h>		/* For IS_ERR macros */ -#include <linux/of.h>		/* For of_get_timeout_sec */ +#include <linux/of.h>		/* For of_alias_get_id */ +#include <linux/property.h>	/* For device_property_read_u32 */  #include <linux/suspend.h>  #include "watchdog_core.h"	/* For watchdog_dev_register/... */ @@ -137,8 +138,7 @@ int watchdog_init_timeout(struct watchdog_device *wdd,  	}  	/* try to get the timeout_sec property */ -	if (dev && dev->of_node && -	    of_property_read_u32(dev->of_node, "timeout-sec", &t) == 0) { +	if (dev && device_property_read_u32(dev, "timeout-sec", &t) == 0) {  		if (t && !watchdog_timeout_invalid(wdd, t)) {  			wdd->timeout = t;  			return 0; | 
