summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxingyu.wu <xingyu.wu@starfivetech.com>2022-05-30 06:42:04 +0300
committerxingyu.wu <xingyu.wu@starfivetech.com>2022-05-30 09:59:29 +0300
commit59fd78c392082faee3b7160e455e81fec85692cb (patch)
treea98fc2ed8a8ce76e60c6ca184f3ab16ec70c198f
parent029a826dbe8f8dd02af75fe0070fca27579233c1 (diff)
downloadlinux-59fd78c392082faee3b7160e455e81fec85692cb.tar.xz
watchdog:starfive:Modify real timeout sec setting and read
According to watchdog reset after twice timeout in hardware, adjust real timeout sec setting and read by divider. Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com>
-rwxr-xr-xdrivers/watchdog/starfive-wdt.c30
1 files changed, 27 insertions, 3 deletions
diff --git a/drivers/watchdog/starfive-wdt.c b/drivers/watchdog/starfive-wdt.c
index f572936b99c8..96899306d085 100755
--- a/drivers/watchdog/starfive-wdt.c
+++ b/drivers/watchdog/starfive-wdt.c
@@ -141,6 +141,9 @@ struct stf_si5_wdt {
u32 reload; /*restore the count*/
void __iomem *base;
spinlock_t lock;
+
+ unsigned int interrupt_flag;
+ struct resource *wdt_irq;
};
#ifdef CONFIG_OF
@@ -443,12 +446,19 @@ static unsigned int si5wdt_get_timeleft(struct watchdog_device *wdd)
u32 count;
si5wdt_unlock(wdt);
- count = si5wdt_get_count(wdt);
+ count = si5wdt_get_count(wdt) + (1 - wdt->interrupt_flag) * wdt->count;
si5wdt_lock(wdt);
return si5wdt_ticks_to_sec(wdt, count);
}
+static void si5wdt_irq_flag_clr(struct stf_si5_wdt *wdt)
+{
+ if (wdt->interrupt_flag)
+ enable_irq(wdt->wdt_irq->start);
+ wdt->interrupt_flag = 0;
+}
+
static int si5wdt_keepalive(struct watchdog_device *wdd)
{
struct stf_si5_wdt *wdt = watchdog_get_drvdata(wdd);
@@ -456,6 +466,8 @@ static int si5wdt_keepalive(struct watchdog_device *wdd)
spin_lock(&wdt->lock);
si5wdt_unlock(wdt);
+ si5wdt_int_clr(wdt);
+ si5wdt_irq_flag_clr(wdt);
si5wdt_set_relod_count(wdt, wdt->count);
si5wdt_lock(wdt);
@@ -470,6 +482,12 @@ static irqreturn_t si5wdt_interrupt_handler(int irq, void *data)
* We don't clear the IRQ status. It's supposed to be done by the
* following ping operations.
*/
+ struct platform_device *pdev = data;
+ struct stf_si5_wdt *wdt = platform_get_drvdata(pdev);
+
+ /* Clear the IRQ status and set flag. */
+ disable_irq_nosync(wdt->wdt_irq->start);
+ wdt->interrupt_flag = 1;
return IRQ_HANDLED;
}
@@ -504,6 +522,7 @@ static int si5wdt_start(struct watchdog_device *wdd)
else
si5wdt_enable_reset(wdt);
+ si5wdt_irq_flag_clr(wdt);
si5wdt_set_count(wdt, wdt->count);
si5wdt_int_enable(wdt);
si5wdt_enable(wdt);
@@ -529,6 +548,7 @@ static int si5wdt_restart(struct watchdog_device *wdd, unsigned long action,
else
si5wdt_enable_reset(wdt);
+ si5wdt_irq_flag_clr(wdt);
/* put initial values into count and data */
si5wdt_set_count(wdt, wdt->count);
@@ -556,7 +576,7 @@ static int si5wdt_set_timeout(struct watchdog_device *wdd,
if (timeout < 1)
return -EINVAL;
- count = timeout * freq;
+ count = timeout * freq / 2;
if (count > SI5_WATCHDOG_MAXCNT) {
dev_warn(wdt->dev, "timeout %d too big,use the MAX-timeout set.\n",
@@ -565,11 +585,12 @@ static int si5wdt_set_timeout(struct watchdog_device *wdd,
count = timeout * freq;
}
- dev_info(wdt->dev, "Heartbeat: timeout=%d, count=%d (%08x)\n",
+ dev_info(wdt->dev, "Heartbeat: timeout=%d, count/2=%d (%08x)\n",
timeout, count, count);
si5wdt_unlock(wdt);
si5wdt_disable(wdt);
+ si5wdt_irq_flag_clr(wdt);
si5wdt_set_relod_count(wdt, count);
si5wdt_enable(wdt);
si5wdt_lock(wdt);
@@ -643,6 +664,8 @@ static int si5wdt_probe(struct platform_device *pdev)
ret = -ENOENT;
goto err;
}
+ wdt->wdt_irq = wdt_irq;
+ si5wdt_irq_flag_clr(wdt);
/* get the memory region for the watchdog timer */
wdt->base = devm_platform_ioremap_resource(pdev, 0);
@@ -782,6 +805,7 @@ static int si5wdt_resume(struct device *dev)
si5wdt_unlock(wdt);
+ si5wdt_irq_flag_clr(wdt);
/* Restore watchdog state. */
si5wdt_set_relod_count(wdt, wdt->reload);