diff options
Diffstat (limited to 'drivers/watchdog')
26 files changed, 315 insertions, 123 deletions
diff --git a/drivers/watchdog/asm9260_wdt.c b/drivers/watchdog/asm9260_wdt.c index 53da001f0838..7dd0da644a7f 100644 --- a/drivers/watchdog/asm9260_wdt.c +++ b/drivers/watchdog/asm9260_wdt.c @@ -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); diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c index 1c652582de40..79cc766cd30f 100644 --- a/drivers/watchdog/aspeed_wdt.c +++ b/drivers/watchdog/aspeed_wdt.c @@ -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"); diff --git a/drivers/watchdog/bcm7038_wdt.c b/drivers/watchdog/bcm7038_wdt.c index c1b8e534fb55..f88f546e8050 100644 --- a/drivers/watchdog/bcm7038_wdt.c +++ b/drivers/watchdog/bcm7038_wdt.c @@ -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) diff --git a/drivers/watchdog/cadence_wdt.c b/drivers/watchdog/cadence_wdt.c index 05c000081e9d..064cf7b6c1c5 100644 --- a/drivers/watchdog/cadence_wdt.c +++ b/drivers/watchdog/cadence_wdt.c @@ -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" : ""); diff --git a/drivers/watchdog/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c index 38dd60f0cfcc..4410337f4f7f 100644 --- a/drivers/watchdog/coh901327_wdt.c +++ b/drivers/watchdog/coh901327_wdt.c @@ -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, diff --git a/drivers/watchdog/da9063_wdt.c b/drivers/watchdog/da9063_wdt.c index 4691c5509129..2a20fc163ed0 100644 --- a/drivers/watchdog/da9063_wdt.c +++ b/drivers/watchdog/da9063_wdt.c @@ -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 = { diff --git a/drivers/watchdog/diag288_wdt.c b/drivers/watchdog/diag288_wdt.c index 6f591084bb7a..806a04a676b7 100644 --- a/drivers/watchdog/diag288_wdt.c +++ b/drivers/watchdog/diag288_wdt.c @@ -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", diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index c4f65873bfa4..347f0389b089 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -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); diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c index dd1e7eaef50f..e96faea24925 100644 --- a/drivers/watchdog/it87_wdt.c +++ b/drivers/watchdog/it87_wdt.c @@ -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, diff --git a/drivers/watchdog/max77620_wdt.c b/drivers/watchdog/max77620_wdt.c index 68c41fa2be27..2c9f53eaff4f 100644 --- a/drivers/watchdog/max77620_wdt.c +++ b/drivers/watchdog/max77620_wdt.c @@ -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", }, { }, }; diff --git a/drivers/watchdog/mei_wdt.c b/drivers/watchdog/mei_wdt.c index b29c6fde7473..ea60b29494fb 100644 --- a/drivers/watchdog/mei_wdt.c +++ b/drivers/watchdog/mei_wdt.c @@ -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 */ { } diff --git a/drivers/watchdog/meson_wdt.c b/drivers/watchdog/meson_wdt.c index 491b9bf13d84..304274c67735 100644 --- a/drivers/watchdog/meson_wdt.c +++ b/drivers/watchdog/meson_wdt.c @@ -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); diff --git a/drivers/watchdog/mt7621_wdt.c b/drivers/watchdog/mt7621_wdt.c index 48a06067075d..db38f8017218 100644 --- a/drivers/watchdog/mt7621_wdt.c +++ b/drivers/watchdog/mt7621_wdt.c @@ -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); diff --git a/drivers/watchdog/of_xilinx_wdt.c b/drivers/watchdog/of_xilinx_wdt.c index fae7fe929ea3..1cf286945b7a 100644 --- a/drivers/watchdog/of_xilinx_wdt.c +++ b/drivers/watchdog/of_xilinx_wdt.c @@ -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, }, }; diff --git a/drivers/watchdog/pcwd_usb.c b/drivers/watchdog/pcwd_usb.c index 5615f4013924..b9e376c8e2e3 100644 --- a/drivers/watchdog/pcwd_usb.c +++ b/drivers/watchdog/pcwd_usb.c @@ -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 */ }; diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c index 4f47b5e90956..780971318810 100644 --- a/drivers/watchdog/qcom-wdt.c +++ b/drivers/watchdog/qcom-wdt.c @@ -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)) diff --git a/drivers/watchdog/renesas_wdt.c b/drivers/watchdog/renesas_wdt.c index cf61c92f7ecd..831ef83f6de1 100644 --- a/drivers/watchdog/renesas_wdt.c +++ b/drivers/watchdog/renesas_wdt.c @@ -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; diff --git a/drivers/watchdog/rt2880_wdt.c b/drivers/watchdog/rt2880_wdt.c index 05524baf7dcc..98967f0a7d10 100644 --- a/drivers/watchdog/rt2880_wdt.c +++ b/drivers/watchdog/rt2880_wdt.c @@ -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); diff --git a/drivers/watchdog/sc1200wdt.c b/drivers/watchdog/sc1200wdt.c index b34d3d5ba632..8e4e2fc13f87 100644 --- a/drivers/watchdog/sc1200wdt.c +++ b/drivers/watchdog/sc1200wdt.c @@ -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 = ""}, diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c index e7a715e82021..03805bc5d67a 100644 --- a/drivers/watchdog/sp805_wdt.c +++ b/drivers/watchdog/sp805_wdt.c @@ -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, diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c index 6c501b7dba29..be64a8699de3 100644 --- a/drivers/watchdog/stm32_iwdg.c +++ b/drivers/watchdog/stm32_iwdg.c @@ -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, diff --git a/drivers/watchdog/ts72xx_wdt.c b/drivers/watchdog/ts72xx_wdt.c index 17c25daebcce..811e43c39ec4 100644 --- a/drivers/watchdog/ts72xx_wdt.c +++ b/drivers/watchdog/ts72xx_wdt.c @@ -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, diff --git a/drivers/watchdog/twl4030_wdt.c b/drivers/watchdog/twl4030_wdt.c index 9bf3cc0f3961..569fe85e52da 100644 --- a/drivers/watchdog/twl4030_wdt.c +++ b/drivers/watchdog/twl4030_wdt.c @@ -24,7 +24,7 @@ #include <linux/kernel.h> #include <linux/watchdog.h> #include <linux/platform_device.h> -#include <linux/i2c/twl.h> +#include <linux/mfd/twl.h> #define TWL4030_WATCHDOG_CFG_REG_OFFS 0x3 diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c index d9ba0496713c..7817836bff55 100644 --- a/drivers/watchdog/w83627hf_wdt.c +++ b/drivers/watchdog/w83627hf_wdt.c @@ -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", diff --git a/drivers/watchdog/ziirave_wdt.c b/drivers/watchdog/ziirave_wdt.c index b4e0cea5a64e..d3594aa3a374 100644 --- a/drivers/watchdog/ziirave_wdt.c +++ b/drivers/watchdog/ziirave_wdt.c @@ -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 }, { } }; diff --git a/drivers/watchdog/zx2967_wdt.c b/drivers/watchdog/zx2967_wdt.c index 69ec5855584b..9261f7c77f6d 100644 --- a/drivers/watchdog/zx2967_wdt.c +++ b/drivers/watchdog/zx2967_wdt.c @@ -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); |