提交 939ae589 编写于 作者: L Linus Torvalds

Merge git://www.linux-watchdog.org/linux-watchdog

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 1fccb730 ("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))
......
/*
* 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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册