mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
linux-watchdog 4.21-rc1 tag
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.14 (GNU/Linux) iEYEABECAAYFAlwopYUACgkQ+iyteGJfRsqOZwCfXM0u0XQJS6TZFtEOZp5gKq+d f/4AnRXcblmb1wJiEVItizB03leOWHqk =jry0 -----END PGP SIGNATURE----- Merge tag 'linux-watchdog-4.21-rc1' of git://www.linux-watchdog.org/linux-watchdog Pull watchdog updates from Wim Van Sebroeck: - add TQ-Systems TQMX86 watchdog driver - add Qualcomm PM8916 watchdog driver - w83627hf_wdt: add quirk for Inves system - renesas_wdt: several improvements and document r8a774c0 support - mena21_wdt, mtx-1: Convert to use GPIO descriptor - bcm281xx, ie6xx_wdt: convert to DEFINE_SHOW_ATTRIBUTE - documentation: add PM usage and kernel-api: don't reference removed functions - update bindings for MT7629 SoC - several small fixes * tag 'linux-watchdog-4.21-rc1' of git://www.linux-watchdog.org/linux-watchdog: (22 commits) watchdog: tqmx86: Add watchdog driver for the IO controller dt-bindings: watchdog: renesas-wdt: Document r8a774c0 support watchdog: docs: kernel-api: don't reference removed functions watchdog: add documentation for PM usage watchdog: mtx-1: Convert to use GPIO descriptor watchdog: mena21_wdt: Convert to GPIO descriptors dt-bindings: watchdog: Add Qualcomm PM8916 watchdog watchdog: Add pm8916 watchdog driver dt-bindings: watchdog: update bindings for MT7629 SoC watchdog: renesas_wdt: don't keep timer value during suspend/resume watchdog: ie6xx_wdt: convert to DEFINE_SHOW_ATTRIBUTE watchdog: bcm281xx: convert to DEFINE_SHOW_ATTRIBUTE watchdog: asm9260_wdt: make array mode_name static, shrinks object size watchdog/hpwdt: Update driver version. watchdog/hpwdt: Do not claim unsupported hardware watchdog/hpwdt: Exclude via blacklist Watchdog: remove outdated comment watchdog: w83627hf_wdt: Add quirk for Inves system watchdog: cpwd: add of_node_put() watchdog: renesas_wdt: don't set divider while watchdog is running ...
This commit is contained in:
commit
115502a6f3
@ -8,6 +8,7 @@ Required properties:
|
||||
"mediatek,mt6797-wdt", "mediatek,mt6589-wdt": for MT6797
|
||||
"mediatek,mt7622-wdt", "mediatek,mt6589-wdt": for MT7622
|
||||
"mediatek,mt7623-wdt", "mediatek,mt6589-wdt": for MT7623
|
||||
"mediatek,mt7629-wdt", "mediatek,mt6589-wdt": for MT7629
|
||||
|
||||
- reg : Specifies base physical address and size of the registers.
|
||||
|
||||
|
@ -0,0 +1,28 @@
|
||||
QCOM PM8916 watchdog timer controller
|
||||
|
||||
This pm8916 watchdog timer controller must be under pm8916-pon node.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "qcom,pm8916-wdt"
|
||||
|
||||
Optional properties :
|
||||
- interrupts : Watchdog pre-timeout (bark) interrupt.
|
||||
- timeout-sec : Watchdog timeout value in seconds.
|
||||
|
||||
Example:
|
||||
|
||||
pm8916_0: pm8916@0 {
|
||||
compatible = "qcom,pm8916", "qcom,spmi-pmic";
|
||||
reg = <0x0 SPMI_USID>;
|
||||
|
||||
pon@800 {
|
||||
compatible = "qcom,pm8916-pon";
|
||||
reg = <0x800>;
|
||||
|
||||
watchdog {
|
||||
compatible = "qcom,pm8916-wdt";
|
||||
interrupts = <0x0 0x8 6 IRQ_TYPE_EDGE_RISING>;
|
||||
timeout-sec = <10>;
|
||||
};
|
||||
};
|
||||
};
|
@ -9,6 +9,7 @@ Required properties:
|
||||
- "renesas,r8a7744-wdt" (RZ/G1N)
|
||||
- "renesas,r8a7745-wdt" (RZ/G1E)
|
||||
- "renesas,r8a774a1-wdt" (RZ/G2M)
|
||||
- "renesas,r8a774c0-wdt" (RZ/G2E)
|
||||
- "renesas,r8a7790-wdt" (R-Car H2)
|
||||
- "renesas,r8a7791-wdt" (R-Car M2-W)
|
||||
- "renesas,r8a7792-wdt" (R-Car V2H)
|
||||
|
@ -128,8 +128,6 @@ struct watchdog_ops {
|
||||
int (*set_pretimeout)(struct watchdog_device *, unsigned int);
|
||||
unsigned int (*get_timeleft)(struct watchdog_device *);
|
||||
int (*restart)(struct watchdog_device *);
|
||||
void (*ref)(struct watchdog_device *) __deprecated;
|
||||
void (*unref)(struct watchdog_device *) __deprecated;
|
||||
long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
|
||||
};
|
||||
|
||||
@ -218,8 +216,6 @@ they are supported. These optional routines/operations are:
|
||||
if a command is not supported. The parameters that are passed to the ioctl
|
||||
call are: watchdog_device, cmd and arg.
|
||||
|
||||
The 'ref' and 'unref' operations are no longer used and deprecated.
|
||||
|
||||
The status bits should (preferably) be set with the set_bit and clear_bit alike
|
||||
bit-operations. The status bits that are defined are:
|
||||
* WDOG_ACTIVE: this status bit indicates whether or not a watchdog timer device
|
||||
|
19
Documentation/watchdog/watchdog-pm.txt
Normal file
19
Documentation/watchdog/watchdog-pm.txt
Normal file
@ -0,0 +1,19 @@
|
||||
The Linux WatchDog Timer Power Management Guide
|
||||
===============================================
|
||||
Last reviewed: 17-Dec-2018
|
||||
|
||||
Wolfram Sang <wsa+renesas@sang-engineering.com>
|
||||
|
||||
Introduction
|
||||
------------
|
||||
This document states rules about watchdog devices and their power management
|
||||
handling to ensure a uniform behaviour for Linux systems.
|
||||
|
||||
|
||||
Ping on resume
|
||||
--------------
|
||||
On resume, a watchdog timer shall be reset to its selected value to give
|
||||
userspace enough time to resume. [1] [2]
|
||||
|
||||
[1] https://patchwork.kernel.org/patch/10252209/
|
||||
[2] https://patchwork.kernel.org/patch/10711625/
|
@ -24,6 +24,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
@ -130,20 +131,18 @@ static struct platform_device mtx1_button = {
|
||||
}
|
||||
};
|
||||
|
||||
static struct resource mtx1_wdt_res[] = {
|
||||
[0] = {
|
||||
.start = 215,
|
||||
.end = 215,
|
||||
.name = "mtx1-wdt-gpio",
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}
|
||||
static struct gpiod_lookup_table mtx1_wdt_gpio_table = {
|
||||
.dev_id = "mtx1-wdt.0",
|
||||
.table = {
|
||||
/* Global number 215 is offset 15 on Alchemy GPIO 2 */
|
||||
GPIO_LOOKUP("alchemy-gpio2", 15, NULL, GPIO_ACTIVE_HIGH),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device mtx1_wdt = {
|
||||
.name = "mtx1-wdt",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(mtx1_wdt_res),
|
||||
.resource = mtx1_wdt_res,
|
||||
};
|
||||
|
||||
static const struct gpio_led default_leds[] = {
|
||||
@ -310,6 +309,7 @@ static int __init mtx1_register_devices(void)
|
||||
}
|
||||
gpio_direction_input(mtx1_gpio_button[0].gpio);
|
||||
out:
|
||||
gpiod_add_lookup_table(&mtx1_wdt_gpio_table);
|
||||
return platform_add_devices(mtx1_devs, ARRAY_SIZE(mtx1_devs));
|
||||
}
|
||||
arch_initcall(mtx1_register_devices);
|
||||
|
@ -538,7 +538,7 @@ config COH901327_WATCHDOG
|
||||
config NPCM7XX_WATCHDOG
|
||||
bool "Nuvoton NPCM750 watchdog"
|
||||
depends on ARCH_NPCM || COMPILE_TEST
|
||||
default y if ARCH_NPCM750
|
||||
default y if ARCH_NPCM7XX
|
||||
select WATCHDOG_CORE
|
||||
help
|
||||
Say Y here to include Watchdog timer support for the
|
||||
@ -847,6 +847,14 @@ config SPRD_WATCHDOG
|
||||
Say Y here to include watchdog timer supported
|
||||
by Spreadtrum system.
|
||||
|
||||
config PM8916_WATCHDOG
|
||||
tristate "QCOM PM8916 pmic watchdog"
|
||||
depends on OF && MFD_SPMI_PMIC
|
||||
select WATCHDOG_CORE
|
||||
help
|
||||
Say Y here to include support watchdog timer embedded into the
|
||||
pm8916 module.
|
||||
|
||||
# X86 (i386 + ia64 + x86_64) Architecture
|
||||
|
||||
config ACQUIRE_WDT
|
||||
@ -1308,6 +1316,18 @@ config SMSC37B787_WDT
|
||||
|
||||
Most people will say N.
|
||||
|
||||
config TQMX86_WDT
|
||||
tristate "TQ-Systems TQMX86 Watchdog Timer"
|
||||
depends on X86
|
||||
help
|
||||
This is the driver for the hardware watchdog timer in the TQMX86 IO
|
||||
controller found on some of their ComExpress Modules.
|
||||
|
||||
To compile this driver as a module, choose M here; the module
|
||||
will be called tqmx86_wdt.
|
||||
|
||||
Most people will say N.
|
||||
|
||||
config VIA_WDT
|
||||
tristate "VIA Watchdog Timer"
|
||||
depends on X86 && PCI
|
||||
|
@ -92,6 +92,7 @@ obj-$(CONFIG_STM32_WATCHDOG) += stm32_iwdg.o
|
||||
obj-$(CONFIG_UNIPHIER_WATCHDOG) += uniphier_wdt.o
|
||||
obj-$(CONFIG_RTD119X_WATCHDOG) += rtd119x_wdt.o
|
||||
obj-$(CONFIG_SPRD_WATCHDOG) += sprd_wdt.o
|
||||
obj-$(CONFIG_PM8916_WATCHDOG) += pm8916_wdt.o
|
||||
|
||||
# X86 (i386 + ia64 + x86_64) Architecture
|
||||
obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
|
||||
@ -129,6 +130,7 @@ obj-$(CONFIG_SBC7240_WDT) += sbc7240_wdt.o
|
||||
obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o
|
||||
obj-$(CONFIG_SMSC_SCH311X_WDT) += sch311x_wdt.o
|
||||
obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o
|
||||
obj-$(CONFIG_TQMX86_WDT) += tqmx86_wdt.o
|
||||
obj-$(CONFIG_VIA_WDT) += via_wdt.o
|
||||
obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
|
||||
obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
|
||||
|
@ -278,7 +278,7 @@ static int asm9260_wdt_probe(struct platform_device *pdev)
|
||||
struct watchdog_device *wdd;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
const char * const mode_name[] = { "hw", "sw", "debug", };
|
||||
static const char * const mode_name[] = { "hw", "sw", "debug", };
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(struct asm9260_wdt_priv),
|
||||
GFP_KERNEL);
|
||||
|
@ -90,7 +90,7 @@ static int secure_register_read(struct bcm_kona_wdt *wdt, uint32_t offset)
|
||||
|
||||
#ifdef CONFIG_BCM_KONA_WDT_DEBUG
|
||||
|
||||
static int bcm_kona_wdt_dbg_show(struct seq_file *s, void *data)
|
||||
static int bcm_kona_show(struct seq_file *s, void *data)
|
||||
{
|
||||
int ctl_val, cur_val;
|
||||
unsigned long flags;
|
||||
@ -130,17 +130,7 @@ static int bcm_kona_wdt_dbg_show(struct seq_file *s, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm_kona_dbg_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, bcm_kona_wdt_dbg_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations bcm_kona_dbg_operations = {
|
||||
.open = bcm_kona_dbg_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(bcm_kona);
|
||||
|
||||
static void bcm_kona_wdt_debug_init(struct platform_device *pdev)
|
||||
{
|
||||
@ -157,7 +147,7 @@ static void bcm_kona_wdt_debug_init(struct platform_device *pdev)
|
||||
return;
|
||||
|
||||
if (debugfs_create_file("info", S_IFREG | S_IRUGO, dir, wdt,
|
||||
&bcm_kona_dbg_operations))
|
||||
&bcm_kona_fops))
|
||||
wdt->debugfs = dir;
|
||||
else
|
||||
debugfs_remove_recursive(dir);
|
||||
|
@ -570,6 +570,8 @@ static int cpwd_probe(struct platform_device *op)
|
||||
if (str_prop)
|
||||
p->timeout = simple_strtoul(str_prop, NULL, 10);
|
||||
|
||||
of_node_put(options);
|
||||
|
||||
/* CP1400s seem to have broken PLD implementations-- the
|
||||
* interrupt_mask register cannot be written, so no timer
|
||||
* interrupts can be masked within the PLD.
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include <linux/watchdog.h>
|
||||
#include <asm/nmi.h>
|
||||
|
||||
#define HPWDT_VERSION "2.0.1"
|
||||
#define HPWDT_VERSION "2.0.2"
|
||||
#define SECS_TO_TICKS(secs) ((secs) * 1000 / 128)
|
||||
#define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000)
|
||||
#define HPWDT_MAX_TIMER TICKS_TO_SECS(65535)
|
||||
@ -50,6 +50,11 @@ static const struct pci_device_id hpwdt_devices[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, hpwdt_devices);
|
||||
|
||||
static const struct pci_device_id hpwdt_blacklist[] = {
|
||||
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_HP, 0x3306, PCI_VENDOR_ID_HP, 0x1979) }, /* auxilary iLO */
|
||||
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_HP, 0x3306, PCI_VENDOR_ID_HP_3PAR, 0x0289) }, /* CL */
|
||||
{0}, /* terminate list */
|
||||
};
|
||||
|
||||
/*
|
||||
* Watchdog operations
|
||||
@ -274,12 +279,10 @@ static int hpwdt_init_one(struct pci_dev *dev,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore all auxilary iLO devices with the following PCI ID
|
||||
*/
|
||||
if (dev->subsystem_vendor == PCI_VENDOR_ID_HP &&
|
||||
dev->subsystem_device == 0x1979)
|
||||
if (pci_match_id(hpwdt_blacklist, dev)) {
|
||||
dev_dbg(&dev->dev, "Not supported on this device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (pci_enable_device(dev)) {
|
||||
dev_warn(&dev->dev,
|
||||
|
@ -193,7 +193,7 @@ static struct watchdog_device ie6xx_wdt_dev = {
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
static int ie6xx_wdt_dbg_show(struct seq_file *s, void *unused)
|
||||
static int ie6xx_wdt_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
seq_printf(s, "PV1 = 0x%08x\n",
|
||||
inl(ie6xx_wdt_data.sch_wdtba + PV1));
|
||||
@ -212,23 +212,13 @@ static int ie6xx_wdt_dbg_show(struct seq_file *s, void *unused)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ie6xx_wdt_dbg_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, ie6xx_wdt_dbg_show, NULL);
|
||||
}
|
||||
|
||||
static const struct file_operations ie6xx_wdt_dbg_operations = {
|
||||
.open = ie6xx_wdt_dbg_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(ie6xx_wdt);
|
||||
|
||||
static void ie6xx_wdt_debugfs_init(void)
|
||||
{
|
||||
/* /sys/kernel/debug/ie6xx_wdt */
|
||||
ie6xx_wdt_data.debugfs = debugfs_create_file("ie6xx_wdt",
|
||||
S_IFREG | S_IRUGO, NULL, NULL, &ie6xx_wdt_dbg_operations);
|
||||
S_IFREG | S_IRUGO, NULL, NULL, &ie6xx_wdt_fops);
|
||||
}
|
||||
|
||||
static void ie6xx_wdt_debugfs_exit(void)
|
||||
|
@ -13,10 +13,10 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/watchdog.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#define NUM_GPIOS 6
|
||||
|
||||
@ -31,7 +31,7 @@ enum a21_wdt_gpios {
|
||||
|
||||
struct a21_wdt_drv {
|
||||
struct watchdog_device wdt;
|
||||
unsigned gpios[NUM_GPIOS];
|
||||
struct gpio_desc *gpios[NUM_GPIOS];
|
||||
};
|
||||
|
||||
static bool nowayout = WATCHDOG_NOWAYOUT;
|
||||
@ -43,9 +43,9 @@ static unsigned int a21_wdt_get_bootstatus(struct a21_wdt_drv *drv)
|
||||
{
|
||||
int reset = 0;
|
||||
|
||||
reset |= gpio_get_value(drv->gpios[GPIO_WD_RST0]) ? (1 << 0) : 0;
|
||||
reset |= gpio_get_value(drv->gpios[GPIO_WD_RST1]) ? (1 << 1) : 0;
|
||||
reset |= gpio_get_value(drv->gpios[GPIO_WD_RST2]) ? (1 << 2) : 0;
|
||||
reset |= gpiod_get_value(drv->gpios[GPIO_WD_RST0]) ? (1 << 0) : 0;
|
||||
reset |= gpiod_get_value(drv->gpios[GPIO_WD_RST1]) ? (1 << 1) : 0;
|
||||
reset |= gpiod_get_value(drv->gpios[GPIO_WD_RST2]) ? (1 << 2) : 0;
|
||||
|
||||
return reset;
|
||||
}
|
||||
@ -54,7 +54,7 @@ static int a21_wdt_start(struct watchdog_device *wdt)
|
||||
{
|
||||
struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt);
|
||||
|
||||
gpio_set_value(drv->gpios[GPIO_WD_ENAB], 1);
|
||||
gpiod_set_value(drv->gpios[GPIO_WD_ENAB], 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -63,7 +63,7 @@ static int a21_wdt_stop(struct watchdog_device *wdt)
|
||||
{
|
||||
struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt);
|
||||
|
||||
gpio_set_value(drv->gpios[GPIO_WD_ENAB], 0);
|
||||
gpiod_set_value(drv->gpios[GPIO_WD_ENAB], 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -72,9 +72,9 @@ static int a21_wdt_ping(struct watchdog_device *wdt)
|
||||
{
|
||||
struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt);
|
||||
|
||||
gpio_set_value(drv->gpios[GPIO_WD_TRIG], 0);
|
||||
gpiod_set_value(drv->gpios[GPIO_WD_TRIG], 0);
|
||||
ndelay(10);
|
||||
gpio_set_value(drv->gpios[GPIO_WD_TRIG], 1);
|
||||
gpiod_set_value(drv->gpios[GPIO_WD_TRIG], 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -96,9 +96,9 @@ static int a21_wdt_set_timeout(struct watchdog_device *wdt,
|
||||
}
|
||||
|
||||
if (timeout == 1)
|
||||
gpio_set_value(drv->gpios[GPIO_WD_FAST], 1);
|
||||
gpiod_set_value(drv->gpios[GPIO_WD_FAST], 1);
|
||||
else
|
||||
gpio_set_value(drv->gpios[GPIO_WD_FAST], 0);
|
||||
gpiod_set_value(drv->gpios[GPIO_WD_FAST], 0);
|
||||
|
||||
wdt->timeout = timeout;
|
||||
|
||||
@ -127,7 +127,6 @@ static struct watchdog_device a21_wdt = {
|
||||
|
||||
static int a21_wdt_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *node;
|
||||
struct a21_wdt_drv *drv;
|
||||
unsigned int reset = 0;
|
||||
int num_gpios;
|
||||
@ -138,40 +137,40 @@ static int a21_wdt_probe(struct platform_device *pdev)
|
||||
if (!drv)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Fill GPIO pin array */
|
||||
node = pdev->dev.of_node;
|
||||
|
||||
num_gpios = of_gpio_count(node);
|
||||
num_gpios = gpiod_count(&pdev->dev, NULL);
|
||||
if (num_gpios != NUM_GPIOS) {
|
||||
dev_err(&pdev->dev, "gpios DT property wrong, got %d want %d",
|
||||
num_gpios, NUM_GPIOS);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_gpios; i++) {
|
||||
int val;
|
||||
|
||||
val = of_get_gpio(node, i);
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
drv->gpios[i] = val;
|
||||
}
|
||||
|
||||
/* Request the used GPIOs */
|
||||
for (i = 0; i < num_gpios; i++) {
|
||||
ret = devm_gpio_request(&pdev->dev, drv->gpios[i],
|
||||
"MEN A21 Watchdog");
|
||||
if (ret)
|
||||
return ret;
|
||||
enum gpiod_flags gflags;
|
||||
|
||||
if (i < GPIO_WD_RST0)
|
||||
ret = gpio_direction_output(drv->gpios[i],
|
||||
gpio_get_value(drv->gpios[i]));
|
||||
else /* GPIO_WD_RST[0..2] are inputs */
|
||||
ret = gpio_direction_input(drv->gpios[i]);
|
||||
if (ret)
|
||||
gflags = GPIOD_ASIS;
|
||||
else
|
||||
gflags = GPIOD_IN;
|
||||
drv->gpios[i] = devm_gpiod_get_index(&pdev->dev, NULL, i,
|
||||
gflags);
|
||||
if (IS_ERR(drv->gpios[i])) {
|
||||
ret = PTR_ERR(drv->gpios[i]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpiod_set_consumer_name(drv->gpios[i], "MEN A21 Watchdog");
|
||||
|
||||
/*
|
||||
* Retrieve the initial value from the GPIOs that should be
|
||||
* output, then set up the line as output with that value.
|
||||
*/
|
||||
if (i < GPIO_WD_RST0) {
|
||||
int val;
|
||||
|
||||
val = gpiod_get_value(drv->gpios[i]);
|
||||
gpiod_direction_output(drv->gpios[i], val);
|
||||
}
|
||||
}
|
||||
|
||||
watchdog_init_timeout(&a21_wdt, 30, &pdev->dev);
|
||||
@ -207,7 +206,7 @@ static void a21_wdt_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct a21_wdt_drv *drv = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
gpio_set_value(drv->gpios[GPIO_WD_ENAB], 0);
|
||||
gpiod_set_value(drv->gpios[GPIO_WD_ENAB], 0);
|
||||
}
|
||||
|
||||
static const struct of_device_id a21_wdt_ids[] = {
|
||||
|
@ -39,7 +39,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
#include <asm/mach-au1x00/au1000.h>
|
||||
|
||||
@ -55,7 +55,7 @@ static struct {
|
||||
int queue;
|
||||
int default_ticks;
|
||||
unsigned long inuse;
|
||||
unsigned gpio;
|
||||
struct gpio_desc *gpiod;
|
||||
unsigned int gstate;
|
||||
} mtx1_wdt_device;
|
||||
|
||||
@ -67,7 +67,7 @@ static void mtx1_wdt_trigger(struct timer_list *unused)
|
||||
|
||||
/* toggle wdt gpio */
|
||||
mtx1_wdt_device.gstate = !mtx1_wdt_device.gstate;
|
||||
gpio_set_value(mtx1_wdt_device.gpio, mtx1_wdt_device.gstate);
|
||||
gpiod_set_value(mtx1_wdt_device.gpiod, mtx1_wdt_device.gstate);
|
||||
|
||||
if (mtx1_wdt_device.queue && ticks)
|
||||
mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL);
|
||||
@ -90,7 +90,7 @@ static void mtx1_wdt_start(void)
|
||||
if (!mtx1_wdt_device.queue) {
|
||||
mtx1_wdt_device.queue = 1;
|
||||
mtx1_wdt_device.gstate = 1;
|
||||
gpio_set_value(mtx1_wdt_device.gpio, 1);
|
||||
gpiod_set_value(mtx1_wdt_device.gpiod, 1);
|
||||
mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL);
|
||||
}
|
||||
mtx1_wdt_device.running++;
|
||||
@ -105,7 +105,7 @@ static int mtx1_wdt_stop(void)
|
||||
if (mtx1_wdt_device.queue) {
|
||||
mtx1_wdt_device.queue = 0;
|
||||
mtx1_wdt_device.gstate = 0;
|
||||
gpio_set_value(mtx1_wdt_device.gpio, 0);
|
||||
gpiod_set_value(mtx1_wdt_device.gpiod, 0);
|
||||
}
|
||||
ticks = mtx1_wdt_device.default_ticks;
|
||||
spin_unlock_irqrestore(&mtx1_wdt_device.lock, flags);
|
||||
@ -198,12 +198,11 @@ static int mtx1_wdt_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mtx1_wdt_device.gpio = pdev->resource[0].start;
|
||||
ret = devm_gpio_request_one(&pdev->dev, mtx1_wdt_device.gpio,
|
||||
GPIOF_OUT_INIT_HIGH, "mtx1-wdt");
|
||||
if (ret < 0) {
|
||||
mtx1_wdt_device.gpiod = devm_gpiod_get(&pdev->dev,
|
||||
NULL, GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(mtx1_wdt_device.gpiod)) {
|
||||
dev_err(&pdev->dev, "failed to request gpio");
|
||||
return ret;
|
||||
return PTR_ERR(mtx1_wdt_device.gpiod);
|
||||
}
|
||||
|
||||
spin_lock_init(&mtx1_wdt_device.lock);
|
||||
|
211
drivers/watchdog/pm8916_wdt.c
Normal file
211
drivers/watchdog/pm8916_wdt.c
Normal file
@ -0,0 +1,211 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/watchdog.h>
|
||||
|
||||
#define PON_INT_RT_STS 0x10
|
||||
#define PMIC_WD_BARK_STS_BIT BIT(6)
|
||||
|
||||
#define PON_PMIC_WD_RESET_S1_TIMER 0x54
|
||||
#define PON_PMIC_WD_RESET_S2_TIMER 0x55
|
||||
|
||||
#define PON_PMIC_WD_RESET_S2_CTL 0x56
|
||||
#define RESET_TYPE_WARM 0x01
|
||||
#define RESET_TYPE_SHUTDOWN 0x04
|
||||
#define RESET_TYPE_HARD 0x07
|
||||
|
||||
#define PON_PMIC_WD_RESET_S2_CTL2 0x57
|
||||
#define S2_RESET_EN_BIT BIT(7)
|
||||
|
||||
#define PON_PMIC_WD_RESET_PET 0x58
|
||||
#define WATCHDOG_PET_BIT BIT(0)
|
||||
|
||||
#define PM8916_WDT_DEFAULT_TIMEOUT 32
|
||||
#define PM8916_WDT_MIN_TIMEOUT 1
|
||||
#define PM8916_WDT_MAX_TIMEOUT 127
|
||||
|
||||
struct pm8916_wdt {
|
||||
struct regmap *regmap;
|
||||
struct watchdog_device wdev;
|
||||
u32 baseaddr;
|
||||
};
|
||||
|
||||
static int pm8916_wdt_start(struct watchdog_device *wdev)
|
||||
{
|
||||
struct pm8916_wdt *wdt = watchdog_get_drvdata(wdev);
|
||||
|
||||
return regmap_update_bits(wdt->regmap,
|
||||
wdt->baseaddr + PON_PMIC_WD_RESET_S2_CTL2,
|
||||
S2_RESET_EN_BIT, S2_RESET_EN_BIT);
|
||||
}
|
||||
|
||||
static int pm8916_wdt_stop(struct watchdog_device *wdev)
|
||||
{
|
||||
struct pm8916_wdt *wdt = watchdog_get_drvdata(wdev);
|
||||
|
||||
return regmap_update_bits(wdt->regmap,
|
||||
wdt->baseaddr + PON_PMIC_WD_RESET_S2_CTL2,
|
||||
S2_RESET_EN_BIT, 0);
|
||||
}
|
||||
|
||||
static int pm8916_wdt_ping(struct watchdog_device *wdev)
|
||||
{
|
||||
struct pm8916_wdt *wdt = watchdog_get_drvdata(wdev);
|
||||
|
||||
return regmap_update_bits(wdt->regmap,
|
||||
wdt->baseaddr + PON_PMIC_WD_RESET_PET,
|
||||
WATCHDOG_PET_BIT, WATCHDOG_PET_BIT);
|
||||
}
|
||||
|
||||
static int pm8916_wdt_configure_timers(struct watchdog_device *wdev)
|
||||
{
|
||||
struct pm8916_wdt *wdt = watchdog_get_drvdata(wdev);
|
||||
int err;
|
||||
|
||||
err = regmap_write(wdt->regmap,
|
||||
wdt->baseaddr + PON_PMIC_WD_RESET_S1_TIMER,
|
||||
wdev->timeout - wdev->pretimeout);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return regmap_write(wdt->regmap,
|
||||
wdt->baseaddr + PON_PMIC_WD_RESET_S2_TIMER,
|
||||
wdev->pretimeout);
|
||||
}
|
||||
|
||||
static int pm8916_wdt_set_timeout(struct watchdog_device *wdev,
|
||||
unsigned int timeout)
|
||||
{
|
||||
wdev->timeout = timeout;
|
||||
|
||||
return pm8916_wdt_configure_timers(wdev);
|
||||
}
|
||||
|
||||
static int pm8916_wdt_set_pretimeout(struct watchdog_device *wdev,
|
||||
unsigned int pretimeout)
|
||||
{
|
||||
wdev->pretimeout = pretimeout;
|
||||
|
||||
return pm8916_wdt_configure_timers(wdev);
|
||||
}
|
||||
|
||||
static irqreturn_t pm8916_wdt_isr(int irq, void *arg)
|
||||
{
|
||||
struct pm8916_wdt *wdt = arg;
|
||||
int err, sts;
|
||||
|
||||
err = regmap_read(wdt->regmap, wdt->baseaddr + PON_INT_RT_STS, &sts);
|
||||
if (err)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
if (sts & PMIC_WD_BARK_STS_BIT)
|
||||
watchdog_notify_pretimeout(&wdt->wdev);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct watchdog_info pm8916_wdt_ident = {
|
||||
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
|
||||
.identity = "QCOM PM8916 PON WDT",
|
||||
};
|
||||
|
||||
static const struct watchdog_info pm8916_wdt_pt_ident = {
|
||||
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE |
|
||||
WDIOF_PRETIMEOUT,
|
||||
.identity = "QCOM PM8916 PON WDT",
|
||||
};
|
||||
|
||||
static const struct watchdog_ops pm8916_wdt_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.start = pm8916_wdt_start,
|
||||
.stop = pm8916_wdt_stop,
|
||||
.ping = pm8916_wdt_ping,
|
||||
.set_timeout = pm8916_wdt_set_timeout,
|
||||
.set_pretimeout = pm8916_wdt_set_pretimeout,
|
||||
};
|
||||
|
||||
static int pm8916_wdt_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pm8916_wdt *wdt;
|
||||
struct device *parent;
|
||||
int err, irq;
|
||||
|
||||
wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
|
||||
if (!wdt)
|
||||
return -ENOMEM;
|
||||
|
||||
parent = pdev->dev.parent;
|
||||
|
||||
/*
|
||||
* The pm8916-pon-wdt is a child of the pon device, which is a child
|
||||
* of the pm8916 mfd device. We want access to the pm8916 registers.
|
||||
* Retrieve regmap from pm8916 (parent->parent) and base address
|
||||
* from pm8916-pon (pon).
|
||||
*/
|
||||
wdt->regmap = dev_get_regmap(parent->parent, NULL);
|
||||
if (!wdt->regmap) {
|
||||
dev_err(&pdev->dev, "failed to locate regmap\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
err = device_property_read_u32(parent, "reg", &wdt->baseaddr);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed to get pm8916-pon address\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq > 0) {
|
||||
if (devm_request_irq(&pdev->dev, irq, pm8916_wdt_isr, 0,
|
||||
"pm8916_wdt", wdt))
|
||||
irq = 0;
|
||||
}
|
||||
|
||||
/* Configure watchdog to hard-reset mode */
|
||||
err = regmap_write(wdt->regmap,
|
||||
wdt->baseaddr + PON_PMIC_WD_RESET_S2_CTL,
|
||||
RESET_TYPE_HARD);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed configure watchdog\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
wdt->wdev.info = (irq > 0) ? &pm8916_wdt_pt_ident : &pm8916_wdt_ident,
|
||||
wdt->wdev.ops = &pm8916_wdt_ops,
|
||||
wdt->wdev.parent = &pdev->dev;
|
||||
wdt->wdev.min_timeout = PM8916_WDT_MIN_TIMEOUT;
|
||||
wdt->wdev.max_timeout = PM8916_WDT_MAX_TIMEOUT;
|
||||
wdt->wdev.timeout = PM8916_WDT_DEFAULT_TIMEOUT;
|
||||
wdt->wdev.pretimeout = 0;
|
||||
watchdog_set_drvdata(&wdt->wdev, wdt);
|
||||
|
||||
watchdog_init_timeout(&wdt->wdev, 0, &pdev->dev);
|
||||
pm8916_wdt_configure_timers(&wdt->wdev);
|
||||
|
||||
return devm_watchdog_register_device(&pdev->dev, &wdt->wdev);
|
||||
}
|
||||
|
||||
static const struct of_device_id pm8916_wdt_id_table[] = {
|
||||
{ .compatible = "qcom,pm8916-wdt" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pm8916_wdt_id_table);
|
||||
|
||||
static struct platform_driver pm8916_wdt_driver = {
|
||||
.probe = pm8916_wdt_probe,
|
||||
.driver = {
|
||||
.name = "pm8916-wdt",
|
||||
.of_match_table = of_match_ptr(pm8916_wdt_id_table),
|
||||
},
|
||||
};
|
||||
module_platform_driver(pm8916_wdt_driver);
|
||||
|
||||
MODULE_AUTHOR("Loic Poulain <loic.poulain@linaro.org>");
|
||||
MODULE_DESCRIPTION("Qualcomm pm8916 watchdog driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -48,7 +48,6 @@ struct rwdt_priv {
|
||||
void __iomem *base;
|
||||
struct watchdog_device wdev;
|
||||
unsigned long clk_rate;
|
||||
u16 time_left;
|
||||
u8 cks;
|
||||
};
|
||||
|
||||
@ -74,12 +73,17 @@ static int rwdt_init_timeout(struct watchdog_device *wdev)
|
||||
static int rwdt_start(struct watchdog_device *wdev)
|
||||
{
|
||||
struct rwdt_priv *priv = watchdog_get_drvdata(wdev);
|
||||
u8 val;
|
||||
|
||||
pm_runtime_get_sync(wdev->parent);
|
||||
|
||||
rwdt_write(priv, 0, RWTCSRB);
|
||||
rwdt_write(priv, priv->cks, RWTCSRA);
|
||||
/* Stop the timer before we modify any register */
|
||||
val = readb_relaxed(priv->base + RWTCSRA) & ~RWTCSRA_TME;
|
||||
rwdt_write(priv, val, RWTCSRA);
|
||||
|
||||
rwdt_init_timeout(wdev);
|
||||
rwdt_write(priv, priv->cks, RWTCSRA);
|
||||
rwdt_write(priv, 0, RWTCSRB);
|
||||
|
||||
while (readb_relaxed(priv->base + RWTCSRA) & RWTCSRA_WRFLG)
|
||||
cpu_relax();
|
||||
@ -220,8 +224,8 @@ static int rwdt_probe(struct platform_device *pdev)
|
||||
goto out_pm_disable;
|
||||
}
|
||||
|
||||
priv->wdev.info = &rwdt_ident,
|
||||
priv->wdev.ops = &rwdt_ops,
|
||||
priv->wdev.info = &rwdt_ident;
|
||||
priv->wdev.ops = &rwdt_ops;
|
||||
priv->wdev.parent = &pdev->dev;
|
||||
priv->wdev.min_timeout = 1;
|
||||
priv->wdev.max_timeout = DIV_BY_CLKS_PER_SEC(priv, 65536);
|
||||
@ -263,10 +267,9 @@ static int __maybe_unused rwdt_suspend(struct device *dev)
|
||||
{
|
||||
struct rwdt_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
if (watchdog_active(&priv->wdev)) {
|
||||
priv->time_left = readw(priv->base + RWTCNT);
|
||||
if (watchdog_active(&priv->wdev))
|
||||
rwdt_stop(&priv->wdev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -274,10 +277,9 @@ static int __maybe_unused rwdt_resume(struct device *dev)
|
||||
{
|
||||
struct rwdt_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
if (watchdog_active(&priv->wdev)) {
|
||||
if (watchdog_active(&priv->wdev))
|
||||
rwdt_start(&priv->wdev);
|
||||
rwdt_write(priv, priv->time_left, RWTCNT);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
126
drivers/watchdog/tqmx86_wdt.c
Normal file
126
drivers/watchdog/tqmx86_wdt.c
Normal file
@ -0,0 +1,126 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Watchdog driver for TQMx86 PLD.
|
||||
*
|
||||
* The watchdog supports power of 2 timeouts from 1 to 4096sec.
|
||||
* Once started, it cannot be stopped.
|
||||
*
|
||||
* Based on the vendor code written by Vadim V.Vlasov
|
||||
* <vvlasov@dev.rtsoft.ru>
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/watchdog.h>
|
||||
|
||||
/* default timeout (secs) */
|
||||
#define WDT_TIMEOUT 32
|
||||
|
||||
static unsigned int timeout;
|
||||
module_param(timeout, uint, 0);
|
||||
MODULE_PARM_DESC(timeout,
|
||||
"Watchdog timeout in seconds. (1<=timeout<=4096, default="
|
||||
__MODULE_STRING(WDT_TIMEOUT) ")");
|
||||
struct tqmx86_wdt {
|
||||
struct watchdog_device wdd;
|
||||
void __iomem *io_base;
|
||||
};
|
||||
|
||||
#define TQMX86_WDCFG 0x00 /* Watchdog Configuration Register */
|
||||
#define TQMX86_WDCS 0x01 /* Watchdog Config/Status Register */
|
||||
|
||||
static int tqmx86_wdt_start(struct watchdog_device *wdd)
|
||||
{
|
||||
struct tqmx86_wdt *priv = watchdog_get_drvdata(wdd);
|
||||
|
||||
iowrite8(0x81, priv->io_base + TQMX86_WDCS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tqmx86_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t)
|
||||
{
|
||||
struct tqmx86_wdt *priv = watchdog_get_drvdata(wdd);
|
||||
u8 val;
|
||||
|
||||
t = roundup_pow_of_two(t);
|
||||
val = ilog2(t) | 0x90;
|
||||
val += 3; /* values 0,1,2 correspond to 0.125,0.25,0.5s timeouts */
|
||||
iowrite8(val, priv->io_base + TQMX86_WDCFG);
|
||||
|
||||
wdd->timeout = t;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct watchdog_info tqmx86_wdt_info = {
|
||||
.options = WDIOF_SETTIMEOUT |
|
||||
WDIOF_KEEPALIVEPING,
|
||||
.identity = "TQMx86 Watchdog",
|
||||
};
|
||||
|
||||
static struct watchdog_ops tqmx86_wdt_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.start = tqmx86_wdt_start,
|
||||
.set_timeout = tqmx86_wdt_set_timeout,
|
||||
};
|
||||
|
||||
static int tqmx86_wdt_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tqmx86_wdt *priv;
|
||||
struct resource *res;
|
||||
int err;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
if (IS_ERR(res))
|
||||
return PTR_ERR(res);
|
||||
|
||||
priv->io_base = devm_ioport_map(&pdev->dev, res->start,
|
||||
resource_size(res));
|
||||
if (IS_ERR(priv->io_base))
|
||||
return PTR_ERR(priv->io_base);
|
||||
|
||||
watchdog_set_drvdata(&priv->wdd, priv);
|
||||
|
||||
priv->wdd.parent = &pdev->dev;
|
||||
priv->wdd.info = &tqmx86_wdt_info;
|
||||
priv->wdd.ops = &tqmx86_wdt_ops;
|
||||
priv->wdd.min_timeout = 1;
|
||||
priv->wdd.max_timeout = 4096;
|
||||
priv->wdd.max_hw_heartbeat_ms = 4096*1000;
|
||||
priv->wdd.timeout = WDT_TIMEOUT;
|
||||
|
||||
watchdog_init_timeout(&priv->wdd, timeout, &pdev->dev);
|
||||
watchdog_set_nowayout(&priv->wdd, WATCHDOG_NOWAYOUT);
|
||||
|
||||
tqmx86_wdt_set_timeout(&priv->wdd, priv->wdd.timeout);
|
||||
|
||||
err = devm_watchdog_register_device(&pdev->dev, &priv->wdd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
dev_info(&pdev->dev, "TQMx86 watchdog\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver tqmx86_wdt_driver = {
|
||||
.driver = {
|
||||
.name = "tqmx86-wdt",
|
||||
},
|
||||
.probe = tqmx86_wdt_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(tqmx86_wdt_driver);
|
||||
|
||||
MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
|
||||
MODULE_DESCRIPTION("TQMx86 Watchdog");
|
||||
MODULE_ALIAS("platform:tqmx86-wdt");
|
||||
MODULE_LICENSE("GPL");
|
@ -38,6 +38,7 @@
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/dmi.h>
|
||||
|
||||
#define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT"
|
||||
#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
|
||||
@ -46,6 +47,8 @@ static int wdt_io;
|
||||
static int cr_wdt_timeout; /* WDT timeout register */
|
||||
static int cr_wdt_control; /* WDT control register */
|
||||
static int cr_wdt_csr; /* WDT control & status register */
|
||||
static int wdt_cfg_enter = 0x87;/* key to unlock configuration space */
|
||||
static int wdt_cfg_leave = 0xAA;/* key to lock configuration space */
|
||||
|
||||
enum chips { w83627hf, w83627s, w83697hf, w83697ug, w83637hf, w83627thf,
|
||||
w83687thf, w83627ehf, w83627dhg, w83627uhg, w83667hg, w83627dhg_p,
|
||||
@ -130,8 +133,8 @@ static int superio_enter(void)
|
||||
if (!request_muxed_region(wdt_io, 2, WATCHDOG_NAME))
|
||||
return -EBUSY;
|
||||
|
||||
outb_p(0x87, WDT_EFER); /* Enter extended function mode */
|
||||
outb_p(0x87, WDT_EFER); /* Again according to manual */
|
||||
outb_p(wdt_cfg_enter, WDT_EFER); /* Enter extended function mode */
|
||||
outb_p(wdt_cfg_enter, WDT_EFER); /* Again according to manual */
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -143,7 +146,7 @@ static void superio_select(int ld)
|
||||
|
||||
static void superio_exit(void)
|
||||
{
|
||||
outb_p(0xAA, WDT_EFER); /* Leave extended function mode */
|
||||
outb_p(wdt_cfg_leave, WDT_EFER); /* Leave extended function mode */
|
||||
release_region(wdt_io, 2);
|
||||
}
|
||||
|
||||
@ -430,6 +433,32 @@ static int wdt_find(int addr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* On some systems, the NCT6791D comes with a companion chip and the
|
||||
* watchdog function is in this companion chip. We must use a different
|
||||
* unlocking sequence to access the companion chip.
|
||||
*/
|
||||
static int __init wdt_use_alt_key(const struct dmi_system_id *d)
|
||||
{
|
||||
wdt_cfg_enter = 0x88;
|
||||
wdt_cfg_leave = 0xBB;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dmi_system_id wdt_dmi_table[] __initconst = {
|
||||
{
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "INVES"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CTS"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "INVES"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "SHARKBAY"),
|
||||
},
|
||||
.callback = wdt_use_alt_key,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static int __init wdt_init(void)
|
||||
{
|
||||
int ret;
|
||||
@ -459,6 +488,9 @@ static int __init wdt_init(void)
|
||||
"NCT6102",
|
||||
};
|
||||
|
||||
/* Apply system-specific quirks */
|
||||
dmi_check_system(wdt_dmi_table);
|
||||
|
||||
wdt_io = 0x2e;
|
||||
chip = wdt_find(0x2e);
|
||||
if (chip < 0) {
|
||||
|
@ -90,9 +90,6 @@ struct watchdog_ops {
|
||||
*
|
||||
* The driver-data field may not be accessed directly. It must be accessed
|
||||
* via the watchdog_set_drvdata and watchdog_get_drvdata helpers.
|
||||
*
|
||||
* The lock field is for watchdog core internal use only and should not be
|
||||
* touched.
|
||||
*/
|
||||
struct watchdog_device {
|
||||
int id;
|
||||
|
Loading…
Reference in New Issue
Block a user