git.kernel.org

Merge git://www.linux-watchdog.org/linux-watchdog - kernel/git/torvalds/linux.git - Linux kernel source tree

  • ️Thu Sep 14 2017

Pull watchdog updates from Wim Van Sebroeck: - add support for the watchdog on Meson8 and Meson8m2 - add support for MediaTek MT7623 and MT7622 SoC - add support for the r8a77995 wdt - explicitly request exclusive reset control for asm9260_wdt, zx2967_wdt, rt2880_wdt and mt7621_wdt - improvements to asm9260_wdt, aspeed_wdt, renesas_wdt and cadence_wdt - add support for reading freq via CCF + suspend/resume support for of_xilinx_wdt - constify watchdog_ops and various device-id structures - revert of commit 1fccb73011ea ("iTCO_wdt: all versions count down twice") (Bug 196509) * git://www.linux-watchdog.org/linux-watchdog: (40 commits) watchdog: mei_wdt: constify mei_cl_device_id watchdog: sp805: constify amba_id watchdog: ziirave: constify i2c_device_id watchdog: sc1200: constify pnp_device_id dt-bindings: watchdog: renesas-wdt: Add support for the r8a77995 wdt watchdog: renesas_wdt: update copyright dates watchdog: renesas_wdt: make 'clk' a variable local to probe() watchdog: renesas_wdt: consistently use RuntimePM for clock management watchdog: aspeed: Support configuration of external signal properties dt-bindings: watchdog: aspeed: External reset signal properties drivers/watchdog: Add optional ASPEED device tree properties drivers/watchdog: ASPEED reference dev tree properties for config watchdog: da9063_wdt: Simplify by removing unneeded struct... watchdog: bcm7038: Check the return value from clk_prepare_enable() watchdog: qcom: Check for platform_get_resource() failure watchdog: of_xilinx_wdt: Add suspend/resume support watchdog: of_xilinx_wdt: Add support for reading freq via CCF dt-bindings: watchdog: mediatek: add support for MediaTek MT7623 and MT7622 SoC watchdog: max77620_wdt: constify platform_device_id watchdog: pcwd_usb: constify usb_device_id ...

@@ -8,9 +8,49 @@ Required properties:

- reg: physical base address of the controller and length of memory mapped

region

+Optional properties:

+

+ - aspeed,reset-type = "cpu|soc|system|none"

+

+ Reset behavior - Whenever a timeout occurs the watchdog can be programmed

+ to generate one of three different, mutually exclusive, types of resets.

+

+ Type "none" can be specified to indicate that no resets are to be done.

+ This is useful in situations where another watchdog engine on chip is

+ to perform the reset.

+

+ If 'aspeed,reset-type=' is not specfied the default is to enable system

+ reset.

+

+ Reset types:

+

+ - cpu: Reset CPU on watchdog timeout

+

+ - soc: Reset 'System on Chip' on watchdog timeout

+

+ - system: Reset system on watchdog timeout

+

+ - none: No reset is performed on timeout. Assumes another watchdog

+ engine is responsible for this.

+

+ - aspeed,alt-boot: If property is present then boot from alternate block.

+ - aspeed,external-signal: If property is present then signal is sent to

+ external reset counter (only WDT1 and WDT2). If not

+ specified no external signal is sent.

+ - aspeed,ext-pulse-duration: External signal pulse duration in microseconds

+

+Optional properties for AST2500-compatible watchdogs:

+ - aspeed,ext-push-pull: If aspeed,external-signal is present, set the pin's

+ drive type to push-pull. The default is open-drain.

+ - aspeed,ext-active-high: If aspeed,external-signal is present and and the pin

+ is configured as push-pull, then set the pulse

+ polarity to active-high. The default is active-low.

+

Example:

wdt1: watchdog@1e785000 {

compatible = "aspeed,ast2400-wdt";

reg = <0x1e785000 0x1c>;

+ aspeed,reset-type = "system";

+ aspeed,external-signal;

};

@@ -2,7 +2,11 @@ Meson SoCs Watchdog timer

Required properties:

-- compatible : should be "amlogic,meson6-wdt" or "amlogic,meson8b-wdt"

+- compatible : depending on the SoC this should be one of:

+ "amlogic,meson6-wdt" on Meson6 SoCs

+ "amlogic,meson8-wdt" and "amlogic,meson6-wdt" on Meson8 SoCs

+ "amlogic,meson8b-wdt" on Meson8b SoCs

+ "amlogic,meson8m2-wdt" and "amlogic,meson8b-wdt" on Meson8m2 SoCs

- reg : Specifies base physical address and size of the registers.

Example:

@@ -6,6 +6,8 @@ Required properties:

"mediatek,mt2701-wdt", "mediatek,mt6589-wdt": for MT2701

"mediatek,mt6589-wdt": for MT6589

"mediatek,mt6797-wdt", "mediatek,mt6589-wdt": for MT6797

+ "mediatek,mt7622-wdt", "mediatek,mt6589-wdt": for MT7622

+ "mediatek,mt7623-wdt", "mediatek,mt6589-wdt": for MT7623

- reg : Specifies base physical address and size of the registers.

@@ -6,6 +6,7 @@ Required properties:

Examples with soctypes are:

- "renesas,r8a7795-wdt" (R-Car H3)

- "renesas,r8a7796-wdt" (R-Car M3-W)

+ - "renesas,r8a77995-wdt" (R-Car D3)

- "renesas,r7s72100-wdt" (RZ/A1)

When compatible with the generic version, nodes must list the SoC-specific

@@ -117,7 +117,7 @@ nowayout: Watchdog cannot be stopped once started

-------------------------------------------------

iTCO_wdt:

heartbeat: Watchdog heartbeat in seconds.

- (5<=heartbeat<=74 (TCO v1) or 1226 (TCO v2), default=30)

+ (2<heartbeat<39 (TCO v1) or 613 (TCO v2), default=30)

nowayout: Watchdog cannot be stopped once started

(default=kernel config parameter)

-------------------------------------------------

@@ -82,7 +82,7 @@ static unsigned int asm9260_wdt_gettimeleft(struct watchdog_device *wdd)

counter = ioread32(priv->iobase + HW_WDTV);

- return DIV_ROUND_CLOSEST(counter, priv->wdt_freq);

+ return counter / priv->wdt_freq;

}

static int asm9260_wdt_updatetimeout(struct watchdog_device *wdd)

@@ -296,7 +296,7 @@ static int asm9260_wdt_probe(struct platform_device *pdev)

if (ret)

return ret;

- priv->rst = devm_reset_control_get(&pdev->dev, "wdt_rst");

+ priv->rst = devm_reset_control_get_exclusive(&pdev->dev, "wdt_rst");

if (IS_ERR(priv->rst))

return PTR_ERR(priv->rst);

@@ -23,9 +23,21 @@ struct aspeed_wdt {

u32 ctrl;

};

+struct aspeed_wdt_config {

+ u32 ext_pulse_width_mask;

+};

+

+static const struct aspeed_wdt_config ast2400_config = {

+ .ext_pulse_width_mask = 0xff,

+};

+

+static const struct aspeed_wdt_config ast2500_config = {

+ .ext_pulse_width_mask = 0xfffff,

+};

+

static const struct of_device_id aspeed_wdt_of_table[] = {

- { .compatible = "aspeed,ast2400-wdt" },

- { .compatible = "aspeed,ast2500-wdt" },

+ { .compatible = "aspeed,ast2400-wdt", .data = &ast2400_config },

+ { .compatible = "aspeed,ast2500-wdt", .data = &ast2500_config },

{ },

};

MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table);

@@ -36,12 +48,45 @@ MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table);

#define WDT_CTRL 0x0C

#define WDT_CTRL_RESET_MODE_SOC (0x00 << 5)

#define WDT_CTRL_RESET_MODE_FULL_CHIP (0x01 << 5)

+#define WDT_CTRL_RESET_MODE_ARM_CPU (0x10 << 5)

#define WDT_CTRL_1MHZ_CLK BIT(4)

#define WDT_CTRL_WDT_EXT BIT(3)

#define WDT_CTRL_WDT_INTR BIT(2)

#define WDT_CTRL_RESET_SYSTEM BIT(1)

#define WDT_CTRL_ENABLE BIT(0)

+/*

+ * WDT_RESET_WIDTH controls the characteristics of the external pulse (if

+ * enabled), specifically:

+ *

+ * * Pulse duration

+ * * Drive mode: push-pull vs open-drain

+ * * Polarity: Active high or active low

+ *

+ * Pulse duration configuration is available on both the AST2400 and AST2500,

+ * though the field changes between SoCs:

+ *

+ * AST2400: Bits 7:0

+ * AST2500: Bits 19:0

+ *

+ * This difference is captured in struct aspeed_wdt_config.

+ *

+ * The AST2500 exposes the drive mode and polarity options, but not in a

+ * regular fashion. For read purposes, bit 31 represents active high or low,

+ * and bit 30 represents push-pull or open-drain. With respect to write, magic

+ * values need to be written to the top byte to change the state of the drive

+ * mode and polarity bits. Any other value written to the top byte has no

+ * effect on the state of the drive mode or polarity bits. However, the pulse

+ * width value must be preserved (as desired) if written.

+ */

+#define WDT_RESET_WIDTH 0x18

+#define WDT_RESET_WIDTH_ACTIVE_HIGH BIT(31)

+#define WDT_ACTIVE_HIGH_MAGIC (0xA5 << 24)

+#define WDT_ACTIVE_LOW_MAGIC (0x5A << 24)

+#define WDT_RESET_WIDTH_PUSH_PULL BIT(30)

+#define WDT_PUSH_PULL_MAGIC (0xA8 << 24)

+#define WDT_OPEN_DRAIN_MAGIC (0x8A << 24)

+

#define WDT_RESTART_MAGIC 0x4755

/* 32 bits at 1MHz, in milliseconds */

@@ -138,8 +183,13 @@ static const struct watchdog_info aspeed_wdt_info = {

static int aspeed_wdt_probe(struct platform_device *pdev)

{

+ const struct aspeed_wdt_config *config;

+ const struct of_device_id *ofdid;

struct aspeed_wdt *wdt;

struct resource *res;

+ struct device_node *np;

+ const char *reset_type;

+ u32 duration;

int ret;

wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);

@@ -164,20 +214,88 @@ static int aspeed_wdt_probe(struct platform_device *pdev)

wdt->wdd.timeout = WDT_DEFAULT_TIMEOUT;

watchdog_init_timeout(&wdt->wdd, 0, &pdev->dev);

+ np = pdev->dev.of_node;

+

+ ofdid = of_match_node(aspeed_wdt_of_table, np);

+ if (!ofdid)

+ return -EINVAL;

+ config = ofdid->data;

+

+ wdt->ctrl = WDT_CTRL_1MHZ_CLK;

+

/*

* Control reset on a per-device basis to ensure the

- * host is not affected by a BMC reboot, so only reset

- * the SOC and not the full chip

+ * host is not affected by a BMC reboot

*/

- wdt->ctrl = WDT_CTRL_RESET_MODE_SOC |

- WDT_CTRL_1MHZ_CLK |

- WDT_CTRL_RESET_SYSTEM;

+ ret = of_property_read_string(np, "aspeed,reset-type", &reset_type);

+ if (ret) {

+ wdt->ctrl |= WDT_CTRL_RESET_MODE_SOC | WDT_CTRL_RESET_SYSTEM;

+ } else {

+ if (!strcmp(reset_type, "cpu"))

+ wdt->ctrl |= WDT_CTRL_RESET_MODE_ARM_CPU;

+ else if (!strcmp(reset_type, "soc"))

+ wdt->ctrl |= WDT_CTRL_RESET_MODE_SOC;

+ else if (!strcmp(reset_type, "system"))

+ wdt->ctrl |= WDT_CTRL_RESET_SYSTEM;

+ else if (strcmp(reset_type, "none"))

+ return -EINVAL;

+ }

+ if (of_property_read_bool(np, "aspeed,external-signal"))

+ wdt->ctrl |= WDT_CTRL_WDT_EXT;

+

+ writel(wdt->ctrl, wdt->base + WDT_CTRL);

if (readl(wdt->base + WDT_CTRL) & WDT_CTRL_ENABLE) {

aspeed_wdt_start(&wdt->wdd);

set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);

}

+ if (of_device_is_compatible(np, "aspeed,ast2500-wdt")) {

+ u32 reg = readl(wdt->base + WDT_RESET_WIDTH);

+

+ reg &= config->ext_pulse_width_mask;

+ if (of_property_read_bool(np, "aspeed,ext-push-pull"))

+ reg |= WDT_PUSH_PULL_MAGIC;

+ else

+ reg |= WDT_OPEN_DRAIN_MAGIC;

+

+ writel(reg, wdt->base + WDT_RESET_WIDTH);

+

+ reg &= config->ext_pulse_width_mask;

+ if (of_property_read_bool(np, "aspeed,ext-active-high"))

+ reg |= WDT_ACTIVE_HIGH_MAGIC;

+ else

+ reg |= WDT_ACTIVE_LOW_MAGIC;

+

+ writel(reg, wdt->base + WDT_RESET_WIDTH);

+ }

+

+ if (!of_property_read_u32(np, "aspeed,ext-pulse-duration", &duration)) {

+ u32 max_duration = config->ext_pulse_width_mask + 1;

+

+ if (duration == 0 || duration > max_duration) {

+ dev_err(&pdev->dev, "Invalid pulse duration: %uus\n",

+ duration);

+ duration = max(1U, min(max_duration, duration));

+ dev_info(&pdev->dev, "Pulse duration set to %uus\n",

+ duration);

+ }

+

+ /*

+ * The watchdog is always configured with a 1MHz source, so

+ * there is no need to scale the microsecond value. However we

+ * need to offset it - from the datasheet:

+ *

+ * "This register decides the asserting duration of wdt_ext and

+ * wdt_rstarm signal. The default value is 0xFF. It means the

+ * default asserting duration of wdt_ext and wdt_rstarm is

+ * 256us."

+ *

+ * This implies a value of 0 gives a 1us pulse.

+ */

+ writel(duration - 1, wdt->base + WDT_RESET_WIDTH);

+ }

+

ret = devm_watchdog_register_device(&pdev->dev, &wdt->wdd);

if (ret) {

dev_err(&pdev->dev, "failed to register\n");

@@ -136,7 +136,9 @@ static int bcm7038_wdt_probe(struct platform_device *pdev)

wdt->clk = devm_clk_get(dev, NULL);

/* If unable to get clock, use default frequency */

if (!IS_ERR(wdt->clk)) {

- clk_prepare_enable(wdt->clk);

+ err = clk_prepare_enable(wdt->clk);

+ if (err)

+ return err;

wdt->rate = clk_get_rate(wdt->clk);

/* Prevent divide-by-zero exception */

if (!wdt->rate)

@@ -52,12 +52,12 @@

static int wdt_timeout;

static int nowayout = WATCHDOG_NOWAYOUT;

-module_param(wdt_timeout, int, 0);

+module_param(wdt_timeout, int, 0644);

MODULE_PARM_DESC(wdt_timeout,

"Watchdog time in seconds. (default="

__MODULE_STRING(CDNS_WDT_DEFAULT_TIMEOUT) ")");

-module_param(nowayout, int, 0);

+module_param(nowayout, int, 0644);

MODULE_PARM_DESC(nowayout,

"Watchdog cannot be stopped once started (default="

__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");

@@ -368,7 +368,7 @@ static int cdns_wdt_probe(struct platform_device *pdev)

}

platform_set_drvdata(pdev, wdt);

- dev_dbg(&pdev->dev, "Xilinx Watchdog Timer at %p with timeout %ds%s\n",

+ dev_info(&pdev->dev, "Xilinx Watchdog Timer at %p with timeout %ds%s\n",

wdt->regs, cdns_wdt_device->timeout,

nowayout ? ", nowayout" : "");

@@ -218,7 +218,7 @@ static const struct watchdog_info coh901327_ident = {

.identity = DRV_NAME,

};

-static struct watchdog_ops coh901327_ops = {

+static const struct watchdog_ops coh901327_ops = {

.owner = THIS_MODULE,

.start = coh901327_start,

.stop = coh901327_stop,

@@ -36,11 +36,6 @@ static const unsigned int wdt_timeout[] = { 0, 2, 4, 8, 16, 32, 65, 131 };

#define DA9063_WDG_TIMEOUT wdt_timeout[3]

#define DA9063_RESET_PROTECTION_MS 256

-struct da9063_watchdog {

- struct da9063 *da9063;

- struct watchdog_device wdtdev;

-};

-

static unsigned int da9063_wdt_timeout_to_sel(unsigned int secs)

{

unsigned int i;

@@ -61,14 +56,14 @@ static int _da9063_wdt_set_timeout(struct da9063 *da9063, unsigned int regval)

static int da9063_wdt_start(struct watchdog_device *wdd)

{

- struct da9063_watchdog *wdt = watchdog_get_drvdata(wdd);

+ struct da9063 *da9063 = watchdog_get_drvdata(wdd);

unsigned int selector;

int ret;

- selector = da9063_wdt_timeout_to_sel(wdt->wdtdev.timeout);

- ret = _da9063_wdt_set_timeout(wdt->da9063, selector);

+ selector = da9063_wdt_timeout_to_sel(wdd->timeout);

+ ret = _da9063_wdt_set_timeout(da9063, selector);

if (ret)

- dev_err(wdt->da9063->dev, "Watchdog failed to start (err = %d)\n",

+ dev_err(da9063->dev, "Watchdog failed to start (err = %d)\n",

ret);

return ret;

@@ -76,13 +71,13 @@ static int da9063_wdt_start(struct watchdog_device *wdd)

static int da9063_wdt_stop(struct watchdog_device *wdd)

{

- struct da9063_watchdog *wdt = watchdog_get_drvdata(wdd);

+ struct da9063 *da9063 = watchdog_get_drvdata(wdd);

int ret;

- ret = regmap_update_bits(wdt->da9063->regmap, DA9063_REG_CONTROL_D,

+ ret = regmap_update_bits(da9063->regmap, DA9063_REG_CONTROL_D,

DA9063_TWDSCALE_MASK, DA9063_TWDSCALE_DISABLE);

if (ret)

- dev_alert(wdt->da9063->dev, "Watchdog failed to stop (err = %d)\n",

+ dev_alert(da9063->dev, "Watchdog failed to stop (err = %d)\n",

ret);

return ret;

@@ -90,13 +85,13 @@ static int da9063_wdt_stop(struct watchdog_device *wdd)

static int da9063_wdt_ping(struct watchdog_device *wdd)

{

- struct da9063_watchdog *wdt = watchdog_get_drvdata(wdd);

+ struct da9063 *da9063 = watchdog_get_drvdata(wdd);

int ret;

- ret = regmap_write(wdt->da9063->regmap, DA9063_REG_CONTROL_F,

+ ret = regmap_write(da9063->regmap, DA9063_REG_CONTROL_F,

DA9063_WATCHDOG);

if (ret)

- dev_alert(wdt->da9063->dev, "Failed to ping the watchdog (err = %d)\n",

+ dev_alert(da9063->dev, "Failed to ping the watchdog (err = %d)\n",

ret);

return ret;

@@ -105,14 +100,14 @@ static int da9063_wdt_ping(struct watchdog_device *wdd)

static int da9063_wdt_set_timeout(struct watchdog_device *wdd,

unsigned int timeout)

{

- struct da9063_watchdog *wdt = watchdog_get_drvdata(wdd);

+ struct da9063 *da9063 = watchdog_get_drvdata(wdd);

unsigned int selector;

int ret;

selector = da9063_wdt_timeout_to_sel(timeout);

- ret = _da9063_wdt_set_timeout(wdt->da9063, selector);

+ ret = _da9063_wdt_set_timeout(da9063, selector);

if (ret)

- dev_err(wdt->da9063->dev, "Failed to set watchdog timeout (err = %d)\n",

+ dev_err(da9063->dev, "Failed to set watchdog timeout (err = %d)\n",

ret);

else

wdd->timeout = wdt_timeout[selector];

@@ -123,13 +118,13 @@ static int da9063_wdt_set_timeout(struct watchdog_device *wdd,

static int da9063_wdt_restart(struct watchdog_device *wdd, unsigned long action,

void *data)

{

- struct da9063_watchdog *wdt = watchdog_get_drvdata(wdd);

+ struct da9063 *da9063 = watchdog_get_drvdata(wdd);

int ret;

- ret = regmap_write(wdt->da9063->regmap, DA9063_REG_CONTROL_F,

+ ret = regmap_write(da9063->regmap, DA9063_REG_CONTROL_F,

DA9063_SHUTDOWN);

if (ret)

- dev_alert(wdt->da9063->dev, "Failed to shutdown (err = %d)\n",

+ dev_alert(da9063->dev, "Failed to shutdown (err = %d)\n",

ret);

return ret;

@@ -152,7 +147,7 @@ static const struct watchdog_ops da9063_watchdog_ops = {

static int da9063_wdt_probe(struct platform_device *pdev)

{

struct da9063 *da9063;

- struct da9063_watchdog *wdt;

+ struct watchdog_device *wdd;

if (!pdev->dev.parent)

return -EINVAL;

@@ -161,27 +156,25 @@ static int da9063_wdt_probe(struct platform_device *pdev)

if (!da9063)

return -EINVAL;

- wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);

- if (!wdt)

+ wdd = devm_kzalloc(&pdev->dev, sizeof(*wdd), GFP_KERNEL);

+ if (!wdd)

return -ENOMEM;

- wdt->da9063 = da9063;

-

- wdt->wdtdev.info = &da9063_watchdog_info;

- wdt->wdtdev.ops = &da9063_watchdog_ops;

- wdt->wdtdev.min_timeout = DA9063_WDT_MIN_TIMEOUT;

- wdt->wdtdev.max_timeout = DA9063_WDT_MAX_TIMEOUT;

- wdt->wdtdev.min_hw_heartbeat_ms = DA9063_RESET_PROTECTION_MS;

- wdt->wdtdev.timeout = DA9063_WDG_TIMEOUT;

- wdt->wdtdev.parent = &pdev->dev;

+ wdd->info = &da9063_watchdog_info;

+ wdd->ops = &da9063_watchdog_ops;

+ wdd->min_timeout = DA9063_WDT_MIN_TIMEOUT;

+ wdd->max_timeout = DA9063_WDT_MAX_TIMEOUT;

+ wdd->min_hw_heartbeat_ms = DA9063_RESET_PROTECTION_MS;

+ wdd->timeout = DA9063_WDG_TIMEOUT;

+ wdd->parent = &pdev->dev;

- wdt->wdtdev.status = WATCHDOG_NOWAYOUT_INIT_STATUS;

+ wdd->status = WATCHDOG_NOWAYOUT_INIT_STATUS;

- watchdog_set_restart_priority(&wdt->wdtdev, 128);

+ watchdog_set_restart_priority(wdd, 128);

- watchdog_set_drvdata(&wdt->wdtdev, wdt);

+ watchdog_set_drvdata(wdd, da9063);

- return devm_watchdog_register_device(&pdev->dev, &wdt->wdtdev);

+ return devm_watchdog_register_device(&pdev->dev, wdd);

}

static struct platform_driver da9063_wdt_driver = {

@@ -213,7 +213,7 @@ static const struct watchdog_ops wdt_ops = {

.set_timeout = wdt_set_timeout,

};

-static struct watchdog_info wdt_info = {

+static const struct watchdog_info wdt_info = {

.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,

.firmware_version = 0,

.identity = "z Watchdog",

@@ -306,15 +306,16 @@ static int iTCO_wdt_ping(struct watchdog_device *wd_dev)

iTCO_vendor_pre_keepalive(p->smi_res, wd_dev->timeout);

- /* Reset the timeout status bit so that the timer

- * needs to count down twice again before rebooting */

- outw(0x0008, TCO1_STS(p)); /* write 1 to clear bit */

-

/* Reload the timer by writing to the TCO Timer Counter register */

- if (p->iTCO_version >= 2)

+ if (p->iTCO_version >= 2) {

outw(0x01, TCO_RLD(p));

- else if (p->iTCO_version == 1)

+ } else if (p->iTCO_version == 1) {

+ /* Reset the timeout status bit so that the timer

+ * needs to count down twice again before rebooting */

+ outw(0x0008, TCO1_STS(p)); /* write 1 to clear bit */

+

outb(0x01, TCO_RLD(p));

+ }

spin_unlock(&p->io_lock);

return 0;

@@ -327,8 +328,11 @@ static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t)

unsigned char val8;

unsigned int tmrval;

- /* The timer counts down twice before rebooting */

- tmrval = seconds_to_ticks(p, t) / 2;

+ tmrval = seconds_to_ticks(p, t);

+

+ /* For TCO v1 the timer counts down twice before rebooting */

+ if (p->iTCO_version == 1)

+ tmrval /= 2;

/* from the specs: */

/* "Values of 0h-3h are ignored and should not be attempted" */

@@ -381,8 +385,6 @@ static unsigned int iTCO_wdt_get_timeleft(struct watchdog_device *wd_dev)

spin_lock(&p->io_lock);

val16 = inw(TCO_RLD(p));

val16 &= 0x3ff;

- if (!(inw(TCO1_STS(p)) & 0x0008))

- val16 += (inw(TCOv2_TMR(p)) & 0x3ff);

spin_unlock(&p->io_lock);

time_left = ticks_to_seconds(p, val16);

@@ -253,7 +253,7 @@ static const struct watchdog_info ident = {

.identity = WATCHDOG_NAME,

};

-static struct watchdog_ops wdt_ops = {

+static const struct watchdog_ops wdt_ops = {

.owner = THIS_MODULE,

.start = wdt_start,

.stop = wdt_stop,

@@ -201,7 +201,7 @@ static int max77620_wdt_remove(struct platform_device *pdev)

return 0;

}

-static struct platform_device_id max77620_wdt_devtype[] = {

+static const struct platform_device_id max77620_wdt_devtype[] = {

{ .name = "max77620-watchdog", },

{ },

};

@@ -670,7 +670,7 @@ static int mei_wdt_remove(struct mei_cl_device *cldev)

#define MEI_UUID_WD UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, \

0x89, 0x9D, 0xA9, 0x15, 0x14, 0xCB, 0x32, 0xAB)

-static struct mei_cl_device_id mei_wdt_tbl[] = {

+static const struct mei_cl_device_id mei_wdt_tbl[] = {

{ .uuid = MEI_UUID_WD, .version = MEI_CL_VERSION_ANY },

/* required last entry */

{ }

@@ -155,7 +155,9 @@ static const struct watchdog_ops meson_wdt_ops = {

static const struct of_device_id meson_wdt_dt_ids[] = {

{ .compatible = "amlogic,meson6-wdt", .data = &meson6_wdt_data },

+ { .compatible = "amlogic,meson8-wdt", .data = &meson6_wdt_data },

{ .compatible = "amlogic,meson8b-wdt", .data = &meson8b_wdt_data },

+ { .compatible = "amlogic,meson8m2-wdt", .data = &meson8b_wdt_data },

{ /* sentinel */ }

};

MODULE_DEVICE_TABLE(of, meson_wdt_dt_ids);

@@ -105,7 +105,7 @@ static int mt7621_wdt_bootcause(void)

return 0;

}

-static struct watchdog_info mt7621_wdt_info = {

+static const struct watchdog_info mt7621_wdt_info = {

.identity = "Mediatek Watchdog",

.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,

};

@@ -135,7 +135,7 @@ static int mt7621_wdt_probe(struct platform_device *pdev)

if (IS_ERR(mt7621_wdt_base))

return PTR_ERR(mt7621_wdt_base);

- mt7621_wdt_reset = devm_reset_control_get(&pdev->dev, NULL);

+ mt7621_wdt_reset = devm_reset_control_get_exclusive(&pdev->dev, NULL);

if (!IS_ERR(mt7621_wdt_reset))

reset_control_deassert(mt7621_wdt_reset);

@@ -51,9 +51,16 @@ struct xwdt_device {

static int xilinx_wdt_start(struct watchdog_device *wdd)

{

+ int ret;

u32 control_status_reg;

struct xwdt_device *xdev = watchdog_get_drvdata(wdd);

+ ret = clk_enable(xdev->clk);

+ if (ret) {

+ dev_err(wdd->parent, "Failed to enable clock\n");

+ return ret;

+ }

+

spin_lock(&xdev->spinlock);

/* Clean previous status and enable the watchdog timer */

@@ -85,6 +92,9 @@ static int xilinx_wdt_stop(struct watchdog_device *wdd)

iowrite32(0, xdev->base + XWT_TWCSR1_OFFSET);

spin_unlock(&xdev->spinlock);

+

+ clk_disable(xdev->clk);

+

pr_info("Stopped!\n");

return 0;

@@ -167,11 +177,6 @@ static int xwdt_probe(struct platform_device *pdev)

if (IS_ERR(xdev->base))

return PTR_ERR(xdev->base);

- rc = of_property_read_u32(pdev->dev.of_node, "clock-frequency", &pfreq);

- if (rc)

- dev_warn(&pdev->dev,

- "The watchdog clock frequency cannot be obtained\n");

-

rc = of_property_read_u32(pdev->dev.of_node, "xlnx,wdt-interval",

&xdev->wdt_interval);

if (rc)

@@ -186,6 +191,26 @@ static int xwdt_probe(struct platform_device *pdev)

watchdog_set_nowayout(xilinx_wdt_wdd, enable_once);

+ xdev->clk = devm_clk_get(&pdev->dev, NULL);

+ if (IS_ERR(xdev->clk)) {

+ if (PTR_ERR(xdev->clk) != -ENOENT)

+ return PTR_ERR(xdev->clk);

+

+ /*

+ * Clock framework support is optional, continue on

+ * anyways if we don't find a matching clock.

+ */

+ xdev->clk = NULL;

+

+ rc = of_property_read_u32(pdev->dev.of_node, "clock-frequency",

+ &pfreq);

+ if (rc)

+ dev_warn(&pdev->dev,

+ "The watchdog clock freq cannot be obtained\n");

+ } else {

+ pfreq = clk_get_rate(xdev->clk);

+ }

+

/*

* Twice of the 2^wdt_interval / freq because the first wdt overflow is

* ignored (interrupt), reset is only generated at second wdt overflow

@@ -197,14 +222,6 @@ static int xwdt_probe(struct platform_device *pdev)

spin_lock_init(&xdev->spinlock);

watchdog_set_drvdata(xilinx_wdt_wdd, xdev);

- xdev->clk = devm_clk_get(&pdev->dev, NULL);

- if (IS_ERR(xdev->clk)) {

- if (PTR_ERR(xdev->clk) == -ENOENT)

- xdev->clk = NULL;

- else

- return PTR_ERR(xdev->clk);

- }

-

rc = clk_prepare_enable(xdev->clk);

if (rc) {

dev_err(&pdev->dev, "unable to enable clock\n");

@@ -223,6 +240,8 @@ static int xwdt_probe(struct platform_device *pdev)

goto err_clk_disable;

}

+ clk_disable(xdev->clk);

+

dev_info(&pdev->dev, "Xilinx Watchdog Timer at %p with timeout %ds\n",

xdev->base, xilinx_wdt_wdd->timeout);

@@ -245,6 +264,43 @@ static int xwdt_remove(struct platform_device *pdev)

return 0;

}

+/**

+ * xwdt_suspend - Suspend the device.

+ *

+ * @dev: handle to the device structure.

+ * Return: 0 always.

+ */

+static int __maybe_unused xwdt_suspend(struct device *dev)

+{

+ struct platform_device *pdev = to_platform_device(dev);

+ struct xwdt_device *xdev = platform_get_drvdata(pdev);

+

+ if (watchdog_active(&xdev->xilinx_wdt_wdd))

+ xilinx_wdt_stop(&xdev->xilinx_wdt_wdd);

+

+ return 0;

+}

+

+/**

+ * xwdt_resume - Resume the device.

+ *

+ * @dev: handle to the device structure.

+ * Return: 0 on success, errno otherwise.

+ */

+static int __maybe_unused xwdt_resume(struct device *dev)

+{

+ struct platform_device *pdev = to_platform_device(dev);

+ struct xwdt_device *xdev = platform_get_drvdata(pdev);

+ int ret = 0;

+

+ if (watchdog_active(&xdev->xilinx_wdt_wdd))

+ ret = xilinx_wdt_start(&xdev->xilinx_wdt_wdd);

+

+ return ret;

+}

+

+static SIMPLE_DEV_PM_OPS(xwdt_pm_ops, xwdt_suspend, xwdt_resume);

+

/* Match table for of_platform binding */

static const struct of_device_id xwdt_of_match[] = {

{ .compatible = "xlnx,xps-timebase-wdt-1.00.a", },

@@ -259,6 +315,7 @@ static struct platform_driver xwdt_driver = {

.driver = {

.name = WATCHDOG_NAME,

.of_match_table = xwdt_of_match,

+ .pm = &xwdt_pm_ops,

},

};

@@ -74,7 +74,7 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="

#define USB_PCWD_PRODUCT_ID 0x1140

/* table of devices that work with this driver */

-static struct usb_device_id usb_pcwd_table[] = {

+static const struct usb_device_id usb_pcwd_table[] = {

{ USB_DEVICE(USB_PCWD_VENDOR_ID, USB_PCWD_PRODUCT_ID) },

{ } /* Terminating entry */

};

@@ -162,6 +162,8 @@ static int qcom_wdt_probe(struct platform_device *pdev)

return -ENOMEM;

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

+ if (!res)

+ return -ENOMEM;

/* We use CPU0's DGT for the watchdog */

if (of_property_read_u32(np, "cpu-offset", &percpu_offset))

@@ -1,8 +1,8 @@

/*

* Watchdog driver for Renesas WDT watchdog

*

- * Copyright (C) 2015-16 Wolfram Sang, Sang Engineering <wsa@sang-engineering.com>

- * Copyright (C) 2015-16 Renesas Electronics Corporation

+ * Copyright (C) 2015-17 Wolfram Sang, Sang Engineering <wsa@sang-engineering.com>

+ * Copyright (C) 2015-17 Renesas Electronics Corporation

*

* 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

@@ -23,10 +23,22 @@

#define RWTCSRA_WOVF BIT(4)

#define RWTCSRA_WRFLG BIT(5)

#define RWTCSRA_TME BIT(7)

+#define RWTCSRB 8

#define RWDT_DEFAULT_TIMEOUT 60U

-static const unsigned int clk_divs[] = { 1, 4, 16, 32, 64, 128, 1024 };

+/*

+ * In probe, clk_rate is checked to be not more than 16 bit * biggest clock

+ * divider (12 bits). d is only a factor to fully utilize the WDT counter and

+ * will not exceed its 16 bits. Thus, no overflow, we stay below 32 bits.

+ */

+#define MUL_BY_CLKS_PER_SEC(p, d) \

+ DIV_ROUND_UP((d) * (p)->clk_rate, clk_divs[(p)->cks])

+

+/* d is 16 bit, clk_divs 12 bit -> no 32 bit overflow */

+#define DIV_BY_CLKS_PER_SEC(p, d) ((d) * clk_divs[(p)->cks] / (p)->clk_rate)

+

+static const unsigned int clk_divs[] = { 1, 4, 16, 32, 64, 128, 1024, 4096 };

static bool nowayout = WATCHDOG_NOWAYOUT;

module_param(nowayout, bool, 0);

@@ -36,8 +48,7 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="

struct rwdt_priv {

void __iomem *base;

struct watchdog_device wdev;

- struct clk *clk;

- unsigned int clks_per_sec;

+ unsigned long clk_rate;

u8 cks;

};

@@ -55,7 +66,7 @@ static int rwdt_init_timeout(struct watchdog_device *wdev)

{

struct rwdt_priv *priv = watchdog_get_drvdata(wdev);

- rwdt_write(priv, 65536 - wdev->timeout * priv->clks_per_sec, RWTCNT);

+ rwdt_write(priv, 65536 - MUL_BY_CLKS_PER_SEC(priv, wdev->timeout), RWTCNT);

return 0;

}

@@ -64,8 +75,9 @@ static int rwdt_start(struct watchdog_device *wdev)

{

struct rwdt_priv *priv = watchdog_get_drvdata(wdev);

- clk_prepare_enable(priv->clk);

+ pm_runtime_get_sync(wdev->parent);

+ rwdt_write(priv, 0, RWTCSRB);

rwdt_write(priv, priv->cks, RWTCSRA);

rwdt_init_timeout(wdev);

@@ -82,7 +94,7 @@ static int rwdt_stop(struct watchdog_device *wdev)

struct rwdt_priv *priv = watchdog_get_drvdata(wdev);

rwdt_write(priv, priv->cks, RWTCSRA);

- clk_disable_unprepare(priv->clk);

+ pm_runtime_put(wdev->parent);

return 0;

}

@@ -92,7 +104,7 @@ static unsigned int rwdt_get_timeleft(struct watchdog_device *wdev)

struct rwdt_priv *priv = watchdog_get_drvdata(wdev);

u16 val = readw_relaxed(priv->base + RWTCNT);

- return DIV_ROUND_CLOSEST(65536 - val, priv->clks_per_sec);

+ return DIV_BY_CLKS_PER_SEC(priv, 65536 - val);

}

static const struct watchdog_info rwdt_ident = {

@@ -112,8 +124,8 @@ static int rwdt_probe(struct platform_device *pdev)

{

struct rwdt_priv *priv;

struct resource *res;

- unsigned long rate;

- unsigned int clks_per_sec;

+ struct clk *clk;

+ unsigned long clks_per_sec;

int ret, i;

priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);

@@ -125,36 +137,40 @@ static int rwdt_probe(struct platform_device *pdev)

if (IS_ERR(priv->base))

return PTR_ERR(priv->base);

- priv->clk = devm_clk_get(&pdev->dev, NULL);

- if (IS_ERR(priv->clk))

- return PTR_ERR(priv->clk);

+ clk = devm_clk_get(&pdev->dev, NULL);

+ if (IS_ERR(clk))

+ return PTR_ERR(clk);

+

+ pm_runtime_enable(&pdev->dev);

- rate = clk_get_rate(priv->clk);

- if (!rate)

- return -ENOENT;

+ pm_runtime_get_sync(&pdev->dev);

+ priv->clk_rate = clk_get_rate(clk);

+ pm_runtime_put(&pdev->dev);

+

+ if (!priv->clk_rate) {

+ ret = -ENOENT;

+ goto out_pm_disable;

+ }

for (i = ARRAY_SIZE(clk_divs) - 1; i >= 0; i--) {

- clks_per_sec = DIV_ROUND_UP(rate, clk_divs[i]);

- if (clks_per_sec) {

- priv->clks_per_sec = clks_per_sec;

+ clks_per_sec = priv->clk_rate / clk_divs[i];

+ if (clks_per_sec && clks_per_sec < 65536) {

priv->cks = i;

break;

}

}

- if (!clks_per_sec) {

+ if (i < 0) {

dev_err(&pdev->dev, "Can't find suitable clock divider\n");

- return -ERANGE;

+ ret = -ERANGE;

+ goto out_pm_disable;

}

- pm_runtime_enable(&pdev->dev);

- pm_runtime_get_sync(&pdev->dev);

-

priv->wdev.info = &rwdt_ident,

priv->wdev.ops = &rwdt_ops,

priv->wdev.parent = &pdev->dev;

priv->wdev.min_timeout = 1;

- priv->wdev.max_timeout = 65536 / clks_per_sec;

+ priv->wdev.max_timeout = DIV_BY_CLKS_PER_SEC(priv, 65536);

priv->wdev.timeout = min(priv->wdev.max_timeout, RWDT_DEFAULT_TIMEOUT);

platform_set_drvdata(pdev, priv);

@@ -167,13 +183,14 @@ static int rwdt_probe(struct platform_device *pdev)

dev_warn(&pdev->dev, "Specified timeout value invalid, using default\n");

ret = watchdog_register_device(&priv->wdev);

- if (ret < 0) {

- pm_runtime_put(&pdev->dev);

- pm_runtime_disable(&pdev->dev);

- return ret;

- }

+ if (ret < 0)

+ goto out_pm_disable;

return 0;

+

+ out_pm_disable:

+ pm_runtime_disable(&pdev->dev);

+ return ret;

}

static int rwdt_remove(struct platform_device *pdev)

@@ -181,7 +198,6 @@ static int rwdt_remove(struct platform_device *pdev)

struct rwdt_priv *priv = platform_get_drvdata(pdev);

watchdog_unregister_device(&priv->wdev);

- pm_runtime_put(&pdev->dev);

pm_runtime_disable(&pdev->dev);

return 0;

@@ -119,7 +119,7 @@ static int rt288x_wdt_bootcause(void)

return 0;

}

-static struct watchdog_info rt288x_wdt_info = {

+static const struct watchdog_info rt288x_wdt_info = {

.identity = "Ralink Watchdog",

.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,

};

@@ -152,7 +152,7 @@ static int rt288x_wdt_probe(struct platform_device *pdev)

if (IS_ERR(rt288x_wdt_clk))

return PTR_ERR(rt288x_wdt_clk);

- rt288x_wdt_reset = devm_reset_control_get(&pdev->dev, NULL);

+ rt288x_wdt_reset = devm_reset_control_get_exclusive(&pdev->dev, NULL);

if (!IS_ERR(rt288x_wdt_reset))

reset_control_deassert(rt288x_wdt_reset);

@@ -342,7 +342,7 @@ static int __init sc1200wdt_probe(void)

#if defined CONFIG_PNP

-static struct pnp_device_id scl200wdt_pnp_devices[] = {

+static const struct pnp_device_id scl200wdt_pnp_devices[] = {

/* National Semiconductor PC87307/PC97307 watchdog component */

{.id = "NSC0800", .driver_data = 0},

{.id = ""},

@@ -281,7 +281,7 @@ static int __maybe_unused sp805_wdt_resume(struct device *dev)

static SIMPLE_DEV_PM_OPS(sp805_wdt_dev_pm_ops, sp805_wdt_suspend,

sp805_wdt_resume);

-static struct amba_id sp805_wdt_ids[] = {

+static const struct amba_id sp805_wdt_ids[] = {

{

.id = 0x00141805,

.mask = 0x00ffffff,

@@ -140,7 +140,7 @@ static const struct watchdog_info stm32_iwdg_info = {

.identity = "STM32 Independent Watchdog",

};

-static struct watchdog_ops stm32_iwdg_ops = {

+static const struct watchdog_ops stm32_iwdg_ops = {

.owner = THIS_MODULE,

.start = stm32_iwdg_start,

.ping = stm32_iwdg_ping,

@@ -112,7 +112,7 @@ static const struct watchdog_info ts72xx_wdt_ident = {

.identity = "TS-72XX WDT",

};

-static struct watchdog_ops ts72xx_wdt_ops = {

+static const struct watchdog_ops ts72xx_wdt_ops = {

.owner = THIS_MODULE,

.start = ts72xx_wdt_start,

.stop = ts72xx_wdt_stop,

@@ -429,7 +429,7 @@ static int __init wdt_init(void)

{

int ret;

int chip;

- const char * const chip_name[] = {

+ static const char * const chip_name[] = {

"W83627HF",

"W83627S",

"W83697HF",

@@ -737,7 +737,7 @@ static int ziirave_wdt_remove(struct i2c_client *client)

return 0;

}

-static struct i2c_device_id ziirave_wdt_id[] = {

+static const struct i2c_device_id ziirave_wdt_id[] = {

{ "rave-wdt", 0 },

{ }

};

@@ -229,7 +229,7 @@ static int zx2967_wdt_probe(struct platform_device *pdev)

}

clk_set_rate(wdt->clock, ZX2967_WDT_CLK_FREQ);

- rstc = devm_reset_control_get(dev, NULL);

+ rstc = devm_reset_control_get_exclusive(dev, NULL);

if (IS_ERR(rstc)) {

dev_err(dev, "failed to get rstc");

ret = PTR_ERR(rstc);