mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 12:43:29 +02:00
watchdog: sama5d4_wdt: addition of sam9x60 compatible watchdog
Add support for SAM9X60 WDT into sama5d4_wdt. This means that this driver gets a flag inside the data struct that represents the sam9x60 support. This flag differentiates between the two hardware blocks, and is set according to the compatible of the driver instantiation. Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com> Reviewed-by-off-by: Guenter Roeck <linux@roeck-us.net> Link: https://lore.kernel.org/r/1574067012-18559-3-git-send-email-eugen.hristev@microchip.com Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
This commit is contained in:
committed by
Wim Van Sebroeck
parent
d5226fa6db
commit
bb44aa09e5
@@ -24,7 +24,10 @@
|
|||||||
#define AT91_WDT_MR 0x04 /* Watchdog Mode Register */
|
#define AT91_WDT_MR 0x04 /* Watchdog Mode Register */
|
||||||
#define AT91_WDT_WDV (0xfffUL << 0) /* Counter Value */
|
#define AT91_WDT_WDV (0xfffUL << 0) /* Counter Value */
|
||||||
#define AT91_WDT_SET_WDV(x) ((x) & AT91_WDT_WDV)
|
#define AT91_WDT_SET_WDV(x) ((x) & AT91_WDT_WDV)
|
||||||
|
#define AT91_SAM9X60_PERIODRST BIT(4) /* Period Reset */
|
||||||
|
#define AT91_SAM9X60_RPTHRST BIT(5) /* Minimum Restart Period */
|
||||||
#define AT91_WDT_WDFIEN BIT(12) /* Fault Interrupt Enable */
|
#define AT91_WDT_WDFIEN BIT(12) /* Fault Interrupt Enable */
|
||||||
|
#define AT91_SAM9X60_WDDIS BIT(12) /* Watchdog Disable */
|
||||||
#define AT91_WDT_WDRSTEN BIT(13) /* Reset Processor */
|
#define AT91_WDT_WDRSTEN BIT(13) /* Reset Processor */
|
||||||
#define AT91_WDT_WDRPROC BIT(14) /* Timer Restart */
|
#define AT91_WDT_WDRPROC BIT(14) /* Timer Restart */
|
||||||
#define AT91_WDT_WDDIS BIT(15) /* Watchdog Disable */
|
#define AT91_WDT_WDDIS BIT(15) /* Watchdog Disable */
|
||||||
@@ -37,4 +40,22 @@
|
|||||||
#define AT91_WDT_WDUNF BIT(0) /* Watchdog Underflow */
|
#define AT91_WDT_WDUNF BIT(0) /* Watchdog Underflow */
|
||||||
#define AT91_WDT_WDERR BIT(1) /* Watchdog Error */
|
#define AT91_WDT_WDERR BIT(1) /* Watchdog Error */
|
||||||
|
|
||||||
|
/* Watchdog Timer Value Register */
|
||||||
|
#define AT91_SAM9X60_VR 0x08
|
||||||
|
|
||||||
|
/* Watchdog Window Level Register */
|
||||||
|
#define AT91_SAM9X60_WLR 0x0c
|
||||||
|
/* Watchdog Period Value */
|
||||||
|
#define AT91_SAM9X60_COUNTER (0xfffUL << 0)
|
||||||
|
#define AT91_SAM9X60_SET_COUNTER(x) ((x) & AT91_SAM9X60_COUNTER)
|
||||||
|
|
||||||
|
/* Interrupt Enable Register */
|
||||||
|
#define AT91_SAM9X60_IER 0x14
|
||||||
|
/* Period Interrupt Enable */
|
||||||
|
#define AT91_SAM9X60_PERINT BIT(0)
|
||||||
|
/* Interrupt Disable Register */
|
||||||
|
#define AT91_SAM9X60_IDR 0x18
|
||||||
|
/* Interrupt Status Register */
|
||||||
|
#define AT91_SAM9X60_ISR 0x1c
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
/*
|
/*
|
||||||
* Driver for Atmel SAMA5D4 Watchdog Timer
|
* Driver for Atmel SAMA5D4 Watchdog Timer
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015 Atmel Corporation
|
* Copyright (C) 2015-2019 Microchip Technology Inc. and its subsidiaries
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/reboot.h>
|
#include <linux/reboot.h>
|
||||||
@@ -29,7 +30,10 @@ struct sama5d4_wdt {
|
|||||||
struct watchdog_device wdd;
|
struct watchdog_device wdd;
|
||||||
void __iomem *reg_base;
|
void __iomem *reg_base;
|
||||||
u32 mr;
|
u32 mr;
|
||||||
|
u32 ir;
|
||||||
unsigned long last_ping;
|
unsigned long last_ping;
|
||||||
|
bool need_irq;
|
||||||
|
bool sam9x60_support;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int wdt_timeout;
|
static int wdt_timeout;
|
||||||
@@ -78,7 +82,12 @@ static int sama5d4_wdt_start(struct watchdog_device *wdd)
|
|||||||
{
|
{
|
||||||
struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd);
|
struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd);
|
||||||
|
|
||||||
wdt->mr &= ~AT91_WDT_WDDIS;
|
if (wdt->sam9x60_support) {
|
||||||
|
writel_relaxed(wdt->ir, wdt->reg_base + AT91_SAM9X60_IER);
|
||||||
|
wdt->mr &= ~AT91_SAM9X60_WDDIS;
|
||||||
|
} else {
|
||||||
|
wdt->mr &= ~AT91_WDT_WDDIS;
|
||||||
|
}
|
||||||
wdt_write(wdt, AT91_WDT_MR, wdt->mr);
|
wdt_write(wdt, AT91_WDT_MR, wdt->mr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -88,7 +97,12 @@ static int sama5d4_wdt_stop(struct watchdog_device *wdd)
|
|||||||
{
|
{
|
||||||
struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd);
|
struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd);
|
||||||
|
|
||||||
wdt->mr |= AT91_WDT_WDDIS;
|
if (wdt->sam9x60_support) {
|
||||||
|
writel_relaxed(wdt->ir, wdt->reg_base + AT91_SAM9X60_IDR);
|
||||||
|
wdt->mr |= AT91_SAM9X60_WDDIS;
|
||||||
|
} else {
|
||||||
|
wdt->mr |= AT91_WDT_WDDIS;
|
||||||
|
}
|
||||||
wdt_write(wdt, AT91_WDT_MR, wdt->mr);
|
wdt_write(wdt, AT91_WDT_MR, wdt->mr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -109,6 +123,14 @@ static int sama5d4_wdt_set_timeout(struct watchdog_device *wdd,
|
|||||||
struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd);
|
struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd);
|
||||||
u32 value = WDT_SEC2TICKS(timeout);
|
u32 value = WDT_SEC2TICKS(timeout);
|
||||||
|
|
||||||
|
if (wdt->sam9x60_support) {
|
||||||
|
wdt_write(wdt, AT91_SAM9X60_WLR,
|
||||||
|
AT91_SAM9X60_SET_COUNTER(value));
|
||||||
|
|
||||||
|
wdd->timeout = timeout;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
wdt->mr &= ~AT91_WDT_WDV;
|
wdt->mr &= ~AT91_WDT_WDV;
|
||||||
wdt->mr |= AT91_WDT_SET_WDV(value);
|
wdt->mr |= AT91_WDT_SET_WDV(value);
|
||||||
|
|
||||||
@@ -143,8 +165,14 @@ static const struct watchdog_ops sama5d4_wdt_ops = {
|
|||||||
static irqreturn_t sama5d4_wdt_irq_handler(int irq, void *dev_id)
|
static irqreturn_t sama5d4_wdt_irq_handler(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
struct sama5d4_wdt *wdt = platform_get_drvdata(dev_id);
|
struct sama5d4_wdt *wdt = platform_get_drvdata(dev_id);
|
||||||
|
u32 reg;
|
||||||
|
|
||||||
if (wdt_read(wdt, AT91_WDT_SR)) {
|
if (wdt->sam9x60_support)
|
||||||
|
reg = wdt_read(wdt, AT91_SAM9X60_ISR);
|
||||||
|
else
|
||||||
|
reg = wdt_read(wdt, AT91_WDT_SR);
|
||||||
|
|
||||||
|
if (reg) {
|
||||||
pr_crit("Atmel Watchdog Software Reset\n");
|
pr_crit("Atmel Watchdog Software Reset\n");
|
||||||
emergency_restart();
|
emergency_restart();
|
||||||
pr_crit("Reboot didn't succeed\n");
|
pr_crit("Reboot didn't succeed\n");
|
||||||
@@ -157,13 +185,14 @@ static int of_sama5d4_wdt_init(struct device_node *np, struct sama5d4_wdt *wdt)
|
|||||||
{
|
{
|
||||||
const char *tmp;
|
const char *tmp;
|
||||||
|
|
||||||
wdt->mr = AT91_WDT_WDDIS;
|
if (wdt->sam9x60_support)
|
||||||
|
wdt->mr = AT91_SAM9X60_WDDIS;
|
||||||
|
else
|
||||||
|
wdt->mr = AT91_WDT_WDDIS;
|
||||||
|
|
||||||
if (!of_property_read_string(np, "atmel,watchdog-type", &tmp) &&
|
if (!of_property_read_string(np, "atmel,watchdog-type", &tmp) &&
|
||||||
!strcmp(tmp, "software"))
|
!strcmp(tmp, "software"))
|
||||||
wdt->mr |= AT91_WDT_WDFIEN;
|
wdt->need_irq = true;
|
||||||
else
|
|
||||||
wdt->mr |= AT91_WDT_WDRSTEN;
|
|
||||||
|
|
||||||
if (of_property_read_bool(np, "atmel,idle-halt"))
|
if (of_property_read_bool(np, "atmel,idle-halt"))
|
||||||
wdt->mr |= AT91_WDT_WDIDLEHLT;
|
wdt->mr |= AT91_WDT_WDIDLEHLT;
|
||||||
@@ -176,21 +205,46 @@ static int of_sama5d4_wdt_init(struct device_node *np, struct sama5d4_wdt *wdt)
|
|||||||
|
|
||||||
static int sama5d4_wdt_init(struct sama5d4_wdt *wdt)
|
static int sama5d4_wdt_init(struct sama5d4_wdt *wdt)
|
||||||
{
|
{
|
||||||
u32 reg;
|
u32 reg, val;
|
||||||
|
|
||||||
|
val = WDT_SEC2TICKS(WDT_DEFAULT_TIMEOUT);
|
||||||
/*
|
/*
|
||||||
* When booting and resuming, the bootloader may have changed the
|
* When booting and resuming, the bootloader may have changed the
|
||||||
* watchdog configuration.
|
* watchdog configuration.
|
||||||
* If the watchdog is already running, we can safely update it.
|
* If the watchdog is already running, we can safely update it.
|
||||||
* Else, we have to disable it properly.
|
* Else, we have to disable it properly.
|
||||||
*/
|
*/
|
||||||
if (wdt_enabled) {
|
if (!wdt_enabled) {
|
||||||
wdt_write_nosleep(wdt, AT91_WDT_MR, wdt->mr);
|
|
||||||
} else {
|
|
||||||
reg = wdt_read(wdt, AT91_WDT_MR);
|
reg = wdt_read(wdt, AT91_WDT_MR);
|
||||||
if (!(reg & AT91_WDT_WDDIS))
|
if (wdt->sam9x60_support && (!(reg & AT91_SAM9X60_WDDIS)))
|
||||||
|
wdt_write_nosleep(wdt, AT91_WDT_MR,
|
||||||
|
reg | AT91_SAM9X60_WDDIS);
|
||||||
|
else if (!wdt->sam9x60_support &&
|
||||||
|
(!(reg & AT91_WDT_WDDIS)))
|
||||||
wdt_write_nosleep(wdt, AT91_WDT_MR,
|
wdt_write_nosleep(wdt, AT91_WDT_MR,
|
||||||
reg | AT91_WDT_WDDIS);
|
reg | AT91_WDT_WDDIS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wdt->sam9x60_support) {
|
||||||
|
if (wdt->need_irq)
|
||||||
|
wdt->ir = AT91_SAM9X60_PERINT;
|
||||||
|
else
|
||||||
|
wdt->mr |= AT91_SAM9X60_PERIODRST;
|
||||||
|
|
||||||
|
wdt_write(wdt, AT91_SAM9X60_IER, wdt->ir);
|
||||||
|
wdt_write(wdt, AT91_SAM9X60_WLR, AT91_SAM9X60_SET_COUNTER(val));
|
||||||
|
} else {
|
||||||
|
wdt->mr |= AT91_WDT_SET_WDD(WDT_SEC2TICKS(MAX_WDT_TIMEOUT));
|
||||||
|
wdt->mr |= AT91_WDT_SET_WDV(val);
|
||||||
|
|
||||||
|
if (wdt->need_irq)
|
||||||
|
wdt->mr |= AT91_WDT_WDFIEN;
|
||||||
|
else
|
||||||
|
wdt->mr |= AT91_WDT_WDRSTEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
wdt_write_nosleep(wdt, AT91_WDT_MR, wdt->mr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +255,6 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
|
|||||||
struct sama5d4_wdt *wdt;
|
struct sama5d4_wdt *wdt;
|
||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
u32 irq = 0;
|
u32 irq = 0;
|
||||||
u32 timeout;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
|
wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
|
||||||
@@ -215,6 +268,8 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
|
|||||||
wdd->min_timeout = MIN_WDT_TIMEOUT;
|
wdd->min_timeout = MIN_WDT_TIMEOUT;
|
||||||
wdd->max_timeout = MAX_WDT_TIMEOUT;
|
wdd->max_timeout = MAX_WDT_TIMEOUT;
|
||||||
wdt->last_ping = jiffies;
|
wdt->last_ping = jiffies;
|
||||||
|
wdt->sam9x60_support = of_device_is_compatible(dev->of_node,
|
||||||
|
"microchip,sam9x60-wdt");
|
||||||
|
|
||||||
watchdog_set_drvdata(wdd, wdt);
|
watchdog_set_drvdata(wdd, wdt);
|
||||||
|
|
||||||
@@ -224,15 +279,19 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
wdt->reg_base = regs;
|
wdt->reg_base = regs;
|
||||||
|
|
||||||
irq = irq_of_parse_and_map(dev->of_node, 0);
|
|
||||||
if (!irq)
|
|
||||||
dev_warn(dev, "failed to get IRQ from DT\n");
|
|
||||||
|
|
||||||
ret = of_sama5d4_wdt_init(dev->of_node, wdt);
|
ret = of_sama5d4_wdt_init(dev->of_node, wdt);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if ((wdt->mr & AT91_WDT_WDFIEN) && irq) {
|
if (wdt->need_irq) {
|
||||||
|
irq = irq_of_parse_and_map(dev->of_node, 0);
|
||||||
|
if (!irq) {
|
||||||
|
dev_warn(dev, "failed to get IRQ from DT\n");
|
||||||
|
wdt->need_irq = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wdt->need_irq) {
|
||||||
ret = devm_request_irq(dev, irq, sama5d4_wdt_irq_handler,
|
ret = devm_request_irq(dev, irq, sama5d4_wdt_irq_handler,
|
||||||
IRQF_SHARED | IRQF_IRQPOLL |
|
IRQF_SHARED | IRQF_IRQPOLL |
|
||||||
IRQF_NO_SUSPEND, pdev->name, pdev);
|
IRQF_NO_SUSPEND, pdev->name, pdev);
|
||||||
@@ -244,11 +303,6 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
watchdog_init_timeout(wdd, wdt_timeout, dev);
|
watchdog_init_timeout(wdd, wdt_timeout, dev);
|
||||||
|
|
||||||
timeout = WDT_SEC2TICKS(wdd->timeout);
|
|
||||||
|
|
||||||
wdt->mr |= AT91_WDT_SET_WDD(WDT_SEC2TICKS(MAX_WDT_TIMEOUT));
|
|
||||||
wdt->mr |= AT91_WDT_SET_WDV(timeout);
|
|
||||||
|
|
||||||
ret = sama5d4_wdt_init(wdt);
|
ret = sama5d4_wdt_init(wdt);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
@@ -269,7 +323,12 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id sama5d4_wdt_of_match[] = {
|
static const struct of_device_id sama5d4_wdt_of_match[] = {
|
||||||
{ .compatible = "atmel,sama5d4-wdt", },
|
{
|
||||||
|
.compatible = "atmel,sama5d4-wdt",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.compatible = "microchip,sam9x60-wdt",
|
||||||
|
},
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, sama5d4_wdt_of_match);
|
MODULE_DEVICE_TABLE(of, sama5d4_wdt_of_match);
|
||||||
|
Reference in New Issue
Block a user