On 05/04/2015 05:04 AM, fu.wei@linaro.org wrote:
From: Fu Wei fu.wei@linaro.org
Signed-off-by: Fu Wei fu.wei@linaro.org
Please fix the subject.
Also, "checkpatch --strict" reports
total: 2 errors, 9 warnings, 20 checks, 700 lines checked
which is a bit on the high side for an explicit review. Please run it yourself and fix what it reports.
Some more comments inline.
Thanks, Guenter
drivers/watchdog/Kconfig | 10 + drivers/watchdog/Makefile | 1 + drivers/watchdog/sbsa_gwdt.c | 578 +++++++++++++++++++++++++++++++++++++++++++ drivers/watchdog/sbsa_gwdt.h | 99 ++++++++ 4 files changed, 688 insertions(+) create mode 100644 drivers/watchdog/sbsa_gwdt.c create mode 100644 drivers/watchdog/sbsa_gwdt.h
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index e5e7c55..46d6f46 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -152,6 +152,16 @@ config ARM_SP805_WATCHDOG ARM Primecell SP805 Watchdog timer. This will reboot your system when the timeout is reached.
+config ARM_SBSA_WATCHDOG
- tristate "ARM SBSA Generic Watchdog"
- depends on ARM64 && ARM_AMBA
- select WATCHDOG_CORE
- help
ARM SBSA Generic Watchdog timer. This has two Watchdog Signal(WS0/WS1),
will trigger a warnning interrupt(do panic) in the first timeout(WS0);
will reboot your system when the second timeout(WS1) is reached.
More details: DEN0029B - Server Base System Architecture (SBSA)
- config AT91RM9200_WATCHDOG tristate "AT91RM9200 watchdog" depends on SOC_AT91RM9200 && MFD_SYSCON
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 5c19294..471f1b7c 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
# ARM Architecture obj-$(CONFIG_ARM_SP805_WATCHDOG) += sp805_wdt.o +obj-$(CONFIG_ARM_SBSA_WATCHDOG) += sbsa_gwdt.o obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o obj-$(CONFIG_AT91SAM9X_WATCHDOG) += at91sam9_wdt.o obj-$(CONFIG_CADENCE_WATCHDOG) += cadence_wdt.o diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c new file mode 100644 index 0000000..feee069 --- /dev/null +++ b/drivers/watchdog/sbsa_gwdt.c @@ -0,0 +1,578 @@ +/*
- SBSA(Server Base System Architecture) Generic Watchdog driver
- Copyright (c) 2015, Linaro Ltd.
- Author: Fu Wei fu.wei@linaro.org
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License 2 as published
- by the Free Software Foundation.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- Note: This SBSA Generic watchdog driver is compatible with
the pretimeout concept of Linux kernel.
But timeout and pretimeout are set by the different REGs.
The first watch period is set by writing WCV directly,
that can support more than 10s timeout with the system counter
at 400MHz.
And the second watch period is set by WOR which will be loaded
automatically by hardware, when WS0 is triggered.
More details: DEN0029B - Server Base System Architecture (SBSA)
- Kernel/API: P---------| pretimeout
|-------------------------------T timeout
- SBSA GWDT: P--WOR---WS1 pretimeout
|-------WCV----------WS0~~~~~~~~T timeout
- */
+#include <asm/arch_timer.h>
+#include <linux/acpi.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/uaccess.h> +#include <linux/watchdog.h>
+#include "sbsa_gwdt.h"
+/* For the second watch period,
- the timeout value comes from WOR(a 32bit wide. register).
- This gives a maximum watch period of around 10s
- at a maximum system counter frequency.
- The System Counter shall run at maximum of 400MHz.
- (Server Base System Architecture ARM-DEN-0029 Version 2.3)
- */
+#define DEFAULT_TIMEOUT 15 /* seconds, the 1st + 2nd watch period*/ +#define DEFAULT_PRETIMEOUT 5 /* seconds, the 2nd watch period*/
+/*store the System Counter clock frequency, in Hz.*/ +static u32 sbsa_gwdt_rate;
+static unsigned int timeout = 0; +module_param(timeout, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(timeout,
- "Watchdog timeout in seconds. (>=0, default="
- __MODULE_STRING(DEFAULT_TIMEOUT) ")");
+static unsigned int max_timeout = UINT_MAX; +module_param(max_timeout, uint, S_IRUGO); +MODULE_PARM_DESC(max_timeout,
- "Watchdog max timeout in seconds. (>=0, default="
- __MODULE_STRING(UINT_MAX) ")");
+static unsigned int pretimeout = 0; +module_param(pretimeout, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(pretimeout,
- "Watchdog pretimeout in seconds. (>=0, default="
- __MODULE_STRING(DEFAULT_PRETIMEOUT) ")");
+static bool nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, bool, S_IRUGO); +MODULE_PARM_DESC(nowayout,
- "Watchdog cannot be stopped once started (default="
- __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+/*
- Architected system timer support.
- */
+static void sbsa_gwdt_cf_write(unsigned int reg, u32 val,
struct watchdog_device *wdd)
+{
- struct sbsa_gwdt *gwdt = to_sbsa_gwdt(wdd);
- struct sbsa_gwdt_device_data *device_data = &gwdt->device_data;
- writel_relaxed(val, device_data->control_base + reg);
+}
+static void sbsa_gwdt_rf_write(unsigned int reg, u32 val,
struct watchdog_device *wdd)
+{
- struct sbsa_gwdt *gwdt = to_sbsa_gwdt(wdd);
- struct sbsa_gwdt_device_data *device_data = &gwdt->device_data;
- writel_relaxed(val, device_data->refresh_base + reg);
+}
+static u32 sbsa_gwdt_cf_read(unsigned int reg, struct watchdog_device *wdd) +{
- struct sbsa_gwdt *gwdt = to_sbsa_gwdt(wdd);
- struct sbsa_gwdt_device_data *device_data = &gwdt->device_data;
- return readl_relaxed(device_data->control_base + reg);
+}
+static u32 sbsa_gwdt_rf_read(unsigned int reg, struct watchdog_device *wdd) +{
- struct sbsa_gwdt *gwdt = to_sbsa_gwdt(wdd);
- struct sbsa_gwdt_device_data *device_data = &gwdt->device_data;
- return readl_relaxed(device_data->refresh_base + reg);
+}
+/*
- help founctions for accessing 64bit WCV register
- mutex_lock must be called prior to calling this function.
- */
+static u64 sbsa_gwdt_get_wcv(struct watchdog_device *wdd) +{
- u32 wcv_lo, wcv_hi;
- wcv_lo = sbsa_gwdt_cf_read(SBSA_GWDT_WCV_LO, wdd);
- wcv_hi = sbsa_gwdt_cf_read(SBSA_GWDT_WCV_HI, wdd);
- return (((u64)wcv_hi << 32) | wcv_lo);
+}
+void sbsa_gwdt_set_wcv(struct watchdog_device *wdd, u64 value) +{
- u32 wcv_lo, wcv_hi;
- wcv_lo = (u32)(value & U32_MAX);
- wcv_hi = (u32)((value >> 32) & U32_MAX);
Those typecasts are unnecessary.
- sbsa_gwdt_cf_write(SBSA_GWDT_WCV_LO, wcv_lo, wdd);
- sbsa_gwdt_cf_write(SBSA_GWDT_WCV_HI, wcv_hi, wdd);
- if (sbsa_gwdt_get_wcv(wdd) != value)
pr_err("sbsa_gwdt: set wcv fail!\n");
A function which can have an error should return an error code, not void.
- return;
+}
+void reload_timeout_to_wcv(struct watchdog_device *wdd) +{
- struct sbsa_gwdt *gwdt = to_sbsa_gwdt(wdd);
- u64 cntvct, wcv;
- /* refresh the wcv */
- cntvct = arch_counter_get_cntvct();
- wcv = cntvct + (wdd->timeout - gwdt->pretimeout) * sbsa_gwdt_rate;
- sbsa_gwdt_set_wcv(wdd, wcv);
- return;
+} +/* Use the following function to set the limit of timeout
- after updating pretimeout */
+void sbsa_gwdt_set_timeout_limits(struct sbsa_gwdt *gwdt) +{
- struct watchdog_device *wdd = &gwdt->wdd;
- unsigned int first_period_max = (U64_MAX / sbsa_gwdt_rate);
- wdd->min_timeout = gwdt->pretimeout + 1;
- wdd->max_timeout = min((gwdt->pretimeout + first_period_max),
Please no unnecessary ( ).
max_timeout);
- return;
+}
+/* Use the following function to check if a pretimeout value is invalid */ +static inline bool watchdog_pretimeout_invalid(struct sbsa_gwdt *gwdt,
unsigned int t)
+{
- return ((gwdt->max_pretimeout != 0) && (t > gwdt->max_pretimeout));
Please no unnecessary ( ).
+}
+static int sbsa_gwdt_set_timeout(struct watchdog_device *wdd,
unsigned int timeout)
+{
- if (watchdog_timeout_invalid(wdd, timeout)) {
pr_err("sbsa_gwdt: timeout %d is out of range(%d~%d), unchanged\n",
timeout, wdd->min_timeout, wdd->max_timeout);
return -EINVAL;
- }
The watchdog core already checks if the timeout range is valid. No need to check it again.
- wdd->timeout = timeout;
- /* refresh the wcv */
- reload_timeout_to_wcv(wdd);
- return 0;
+}
+static int sbsa_gwdt_set_pretimeout(struct watchdog_device *wdd,
unsigned int pretimeout)
+{
- struct sbsa_gwdt *gwdt = to_sbsa_gwdt(wdd);
- u32 wor;
- if (watchdog_pretimeout_invalid(gwdt, pretimeout)) {
pr_err("sbsa_gwdt: pretimeout %d is out of range(0~%d),skip\n",
pretimeout, gwdt->max_pretimeout);
return -EINVAL;
- }
Same here.
- gwdt->pretimeout = pretimeout;
- sbsa_gwdt_set_timeout_limits(gwdt);
- /* refresh the WOR, that will cause an explicit watchdog refresh */
- wor = pretimeout * sbsa_gwdt_rate;
- sbsa_gwdt_cf_write(SBSA_GWDT_WOR, wor, wdd);
- return 0;
+}
+static unsigned int sbsa_gwdt_get_timeleft(struct watchdog_device *wdd) +{
- u64 timeleft = sbsa_gwdt_get_wcv(wdd) - arch_counter_get_cntvct();
- return (unsigned int)(timeleft / sbsa_gwdt_rate);
+}
+static int sbsa_gwdt_start(struct watchdog_device *wdd) +{
- struct sbsa_gwdt *gwdt = to_sbsa_gwdt(wdd);
- struct sbsa_gwdt_device_data *device_data = &gwdt->device_data;
- u32 status;
- int ret;
- ret = sbsa_gwdt_set_timeout(wdd, wdd->timeout);
- if (ret)
return ret;
- mutex_lock(&device_data->lock);
- status = sbsa_gwdt_cf_read(SBSA_GWDT_WCS, wdd);
- status |= SBSA_GWDT_WCS_EN;
- /* writing WCS will cause an explicit watchdog refresh */
- sbsa_gwdt_cf_write(SBSA_GWDT_WCS, status, wdd);
- status = sbsa_gwdt_cf_read(SBSA_GWDT_WCS, wdd);
- mutex_unlock(&device_data->lock);
- /* Check if the watchdog was enabled */
- if (!(status & SBSA_GWDT_WCS_EN))
return -EACCES;
EACCES is "permission denied". This is not the case here.
- return 0;
+}
+static int sbsa_gwdt_stop(struct watchdog_device *wdd) +{
- struct sbsa_gwdt *gwdt = to_sbsa_gwdt(wdd);
- struct sbsa_gwdt_device_data *device_data = &gwdt->device_data;
- u32 status;
- mutex_lock(&device_data->lock);
- status = sbsa_gwdt_cf_read(SBSA_GWDT_WCS, wdd);
- status &= ~SBSA_GWDT_WCS_EN;
- /* writing WCS will cause an explicit watchdog refresh */
- sbsa_gwdt_cf_write(SBSA_GWDT_WCS, status, wdd);
- status = sbsa_gwdt_cf_read(SBSA_GWDT_WCS, wdd);
- mutex_unlock(&device_data->lock);
- /* Check if the watchdog was disabled */
- if (status & SBSA_GWDT_WCS_EN)
return -EACCES;
Same as above.
- return 0;
+}
+static int sbsa_gwdt_keepalive(struct watchdog_device *wdd) +{
- struct sbsa_gwdt *gwdt = to_sbsa_gwdt(wdd);
- struct sbsa_gwdt_device_data *device_data = &gwdt->device_data;
- mutex_lock(&device_data->lock);
- /* Writing WRR for an explicit watchdog refresh
* You can write anyting(like 0xc0ffee)
*/
- sbsa_gwdt_rf_write(SBSA_GWDT_WRR, 0xc0ffee, wdd);
- mutex_unlock(&device_data->lock);
- reload_timeout_to_wcv(wdd);
- return 0;
+}
+static long sbsa_gwdt_ioctl(struct watchdog_device *wdd, unsigned int cmd,
unsigned long arg)
+{
- struct sbsa_gwdt *gwdt = watchdog_get_drvdata(wdd);
- void __user *argp = (void __user *)arg;
- int ret = -ENOIOCTLCMD;
- unsigned int __user *p = argp;
- unsigned int new_value;
- /* FIXME: what else do we need here?? */
- switch (cmd) {
- case WDIOC_SETPRETIMEOUT:
if (get_user(new_value, p))
return -EFAULT;
ret = sbsa_gwdt_set_pretimeout(wdd, new_value);
break;
- case WDIOC_GETPRETIMEOUT:
ret = put_user(gwdt->pretimeout, (unsigned int __user *)arg);
break;
- }
- return ret;
+}
+static irqreturn_t sbsa_gwdt_interrupt(int irq, void *dev_id) +{
- struct sbsa_gwdt *gwdt = (struct sbsa_gwdt *)dev_id;
- struct watchdog_device *wdd = &gwdt->wdd;
- u32 status;
- unsigned int left;
- pr_debug("SBSA Watchdog: in %s\n", __func__);
- status = sbsa_gwdt_cf_read(SBSA_GWDT_WCS, wdd);
- if (status & SBSA_GWDT_WCS_WS0) {
pr_crit("SBSA Watchdog WS0 is triggered\n");
left = sbsa_gwdt_get_timeleft(wdd);
pr_crit("please try to feed the dog in %ds!\n", left);
Pleae no unnecessary noise.
Really, what do you expect the user to do here ? To be online, watch the kernel log, and do something frantic ?
/* FIXME:anything we can do here? */
panic("SBSA Watchdog pre-timeout");
Isn't this a pretimeout ?
- }
- return IRQ_HANDLED;
+}
+static struct watchdog_info sbsa_gwdt_info = {
- .identity = "SBSA Generic Watchdog",
- .options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE |
WDIOF_PRETIMEOUT |
WDIOF_CARDRESET,
+};
+static struct watchdog_ops sbsa_gwdt_ops = {
- .owner = THIS_MODULE,
- .start = sbsa_gwdt_start,
- .stop = sbsa_gwdt_stop,
- .ping = sbsa_gwdt_keepalive,
- .set_timeout = sbsa_gwdt_set_timeout,
- .ioctl = sbsa_gwdt_ioctl,
- .get_timeleft = sbsa_gwdt_get_timeleft,
+};
+static int sbsa_gwdt_probe(struct platform_device *pdev) +{
- struct device *dev = &pdev->dev;
- struct sbsa_gwdt *gwdt;
- struct sbsa_gwdt_device_data *device_data;
- struct watchdog_device *wdd;
- struct resource *res;
- void *rf_base, *cf_base;
- int irq;
- u32 status, flags;
- u32 w_iidr, idr;
- int ret = 0;
- /*
* Try to determine the frequency from the cp15 interface
*/
- sbsa_gwdt_rate = arch_timer_get_cntfrq();
- /* Check the system counter frequency. */
- if (!sbsa_gwdt_rate)
dev_err(dev, "System Counter frequency not available\n");
- gwdt = devm_kzalloc(dev, sizeof(*gwdt), GFP_KERNEL);
- if (!gwdt)
return -ENOMEM;
- wdd = &gwdt->wdd;
- wdd->parent = dev;
- device_data = &gwdt->device_data;
- mutex_init(&device_data->lock);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"refresh_frame");
- rf_base = devm_ioremap_resource(dev, res);
- if (IS_ERR(rf_base))
return PTR_ERR(rf_base);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"control_frame");
- cf_base = devm_ioremap_resource(dev, res);
- if (IS_ERR(rf_base))
return PTR_ERR(rf_base);
- irq = platform_get_irq_byname(pdev, "ws0");
- if (IS_ERR(irq)) {
dev_err(dev, "required ws0 interrupt missing\n");
return PTR_ERR(irq);
- }
- res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ws0");
- if (!res)
dev_warn(dev, "ws0 interrupt flags missing, ignore\n");
- else
flags = res->flags;
Not really sure why you get ws0 twice. Why don't you just use platform_get_resource_byname() and use it to get the irq number as well ? Sure, that may not for for devicetree based initialization, but then you won't have flags available anyway, and always printing that warning on devicetree based systems isn't very useful either.
- device_data->refresh_base = rf_base;
- device_data->control_base = cf_base;
- device_data->irq = irq;
- device_data->flags = flags;
- ret = devm_request_irq(dev, irq, sbsa_gwdt_interrupt,
IRQF_TIMER, pdev->name, gwdt);
- if (ret) {
dev_err(dev, "unable to request IRQ %d, disabling device\n",
irq);
return ret;
- }
- /* get device information from refresh/control frame */
- w_iidr = sbsa_gwdt_rf_read(SBSA_GWDT_W_IIDR, &gwdt->wdd);
- idr = sbsa_gwdt_rf_read(SBSA_GWDT_IDR, &gwdt->wdd);
- dev_info(dev, "W_IIDR %x IDR %x in RF.\n", w_iidr, idr);
- /* update device information to device_data for future use*/
- device_data->info.pid = SBSA_GWDT_W_IIDR_PID(w_iidr);
- device_data->info.arch_ver = SBSA_GWDT_W_IIDR_ARCH_VER(w_iidr);
- device_data->info.revision = SBSA_GWDT_W_IIDR_REV(w_iidr);
- device_data->info.vid_bank = SBSA_GWDT_W_IIDR_VID_BANK(w_iidr);
- device_data->info.vid = SBSA_GWDT_W_IIDR_VID(w_iidr);
- wdd->info = &sbsa_gwdt_info;
- wdd->ops = &sbsa_gwdt_ops;
- watchdog_set_drvdata(wdd, gwdt);
- status = sbsa_gwdt_cf_read(SBSA_GWDT_WCS, wdd);
- if (status & SBSA_GWDT_WCS_WS1) {
dev_warn(dev, "System was reseted by SBSA Watchdog, WCS %x\n",
status);
wdd->bootstatus |= WDIOF_CARDRESET;
gwdt->wcv_dump = sbsa_gwdt_get_wcv(wdd);
- }
- watchdog_set_nowayout(wdd, nowayout);
- gwdt->max_pretimeout = min((U32_MAX / sbsa_gwdt_rate),
(max_timeout - 1));
Please no unnecessary ( ).
- if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
u32 timeouts[2];
ret = of_property_read_u32_array(pdev->dev.of_node,
"timeout-sec", timeouts, 2);
if (ret && timeout && pretimeout) {
timeout = timeouts[0];
pretimeout = timeouts[1];
}
- }
- if ((!timeout) || (!pretimeout)) {
Please no unnecessary ( ).
dev_info(dev, "get timeouts from DT or param fail."
"Use DEFAULT.\n");
timeout = DEFAULT_TIMEOUT;
pretimeout = DEFAULT_PRETIMEOUT;
- }
- sbsa_gwdt_set_pretimeout(wdd, pretimeout);
- sbsa_gwdt_set_timeout(wdd, timeout);
- platform_set_drvdata(pdev, gwdt);
- ret = watchdog_register_device(wdd);
- if (ret)
return ret;
- /* Check if watchdog is already enabled */
- if (status & SBSA_GWDT_WCS_EN) {
dev_warn(dev, "already enabled!\n");
sbsa_gwdt_keepalive(wdd);
- }
- dev_info(dev, "registered with %ds timeout, %ds pretimeout\n",
wdd->timeout, gwdt->pretimeout);
- return 0;
+}
+static void sbsa_gwdt_shutdown(struct platform_device *pdev) +{
- struct sbsa_gwdt *gwdt = platform_get_drvdata(pdev);
- sbsa_gwdt_stop(&gwdt->wdd);
+}
+static int sbsa_gwdt_remove(struct platform_device *pdev) +{
- struct sbsa_gwdt *gwdt = platform_get_drvdata(pdev);
- struct watchdog_device *wdd = &gwdt->wdd;
- int ret = 0;
- if (!nowayout)
ret = sbsa_gwdt_stop(wdd);
- watchdog_unregister_device(wdd);
- return ret;
+}
+#ifdef CONFIG_PM_SLEEP +/* Disable watchdog if it is active during suspend */ +static int sbsa_gwdt_suspend(struct device *dev) +{
- struct sbsa_gwdt *gwdt = dev_get_drvdata(dev);
- struct sbsa_gwdt_device_data *device_data = &gwdt->device_data;
- struct watchdog_device *wdd = &gwdt->wdd;
- mutex_lock(&device_data->lock);
- gwdt->pm_status_store = sbsa_gwdt_cf_read(SBSA_GWDT_WCS, wdd);
- mutex_unlock(&device_data->lock);
- if (gwdt->pm_status_store & SBSA_GWDT_WCS_EN)
return sbsa_gwdt_stop(wdd);
- return 0;
+}
+/* Enable watchdog and configure it if necessary */ +static int sbsa_gwdt_resume(struct device *dev) +{
- struct sbsa_gwdt *gwdt = dev_get_drvdata(dev);
- struct watchdog_device *wdd = &gwdt->wdd;
- /*
* If watchdog was stopped before suspend be sure it gets disabled
* again, for the case BIOS has enabled it during resume
*/
- if (gwdt->pm_status_store & SBSA_GWDT_WCS_EN)
return sbsa_gwdt_start(wdd);
- else
return sbsa_gwdt_stop(wdd);
+} +#endif
+#if IS_BUILTIN(CONFIG_OF) +static const struct of_device_id sbsa_gwdt_of_match[] = {
- { .compatible = "arm,sbsa-gwdt", },
- {},
+}; +MODULE_DEVICE_TABLE(of, sbsa_gwdt_of_match); +#endif
+static struct dev_pm_ops sbsa_gwdt_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(sbsa_gwdt_suspend, sbsa_gwdt_resume)
+};
+static struct platform_driver sbsa_gwdt_driver = {
- .driver = {
.name = "sbsa-gwdt",
.pm = &sbsa_gwdt_pm_ops,
.of_match_table = sbsa_gwdt_of_match,
- },
- .probe = sbsa_gwdt_probe,
- .remove = sbsa_gwdt_remove,
- .shutdown = sbsa_gwdt_shutdown,
+};
+module_platform_driver(sbsa_gwdt_driver);
+MODULE_DESCRIPTION("SBSA Generic Watchdog Driver"); +MODULE_AUTHOR("Fu Wei fu.wei@linaro.org"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/watchdog/sbsa_gwdt.h b/drivers/watchdog/sbsa_gwdt.h new file mode 100644 index 0000000..5dc8ace --- /dev/null +++ b/drivers/watchdog/sbsa_gwdt.h @@ -0,0 +1,99 @@ +/*
- SBSA(Server Base System Architecture) Generic Watchdog driver definitions
- Copyright (c) 2015, Linaro Ltd.
- Author: Fu Wei fu.wei@linaro.org
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License 2 as published
- by the Free Software Foundation.
- */
+#ifndef _SBSA_GENERIC_WATCHDOG_H_ +#define _SBSA_GENERIC_WATCHDOG_H_
+/* SBSA Generic Watchdog register definitions */ +/* refresh frame */ +#define SBSA_GWDT_WRR (0x000)
+/* control frame */ +#define SBSA_GWDT_WCS (0x000) +#define SBSA_GWDT_WOR (0x008) +#define SBSA_GWDT_WCV_LO (0x010) +#define SBSA_GWDT_WCV_HI (0x014)
+/* refresh/control frame */ +#define SBSA_GWDT_W_IIDR (0xfcc) +#define SBSA_GWDT_IDR (0xfd0)
All those ( ) are unnecessary.
+/* Watchdog Control and Status Register */ +#define SBSA_GWDT_WCS_EN (1 << 0) +#define SBSA_GWDT_WCS_WS0 (1 << 1) +#define SBSA_GWDT_WCS_WS1 (1 << 2)
+/* Watchdog Interface Identification Register */ +#define SBSA_GWDT_W_IIDR_PID(x) ((x >> 20) & 0xfff) +#define SBSA_GWDT_W_IIDR_ARCH_VER(x) ((x >> 16) & 0xf) +#define SBSA_GWDT_W_IIDR_REV(x) ((x >> 12) & 0xf) +#define SBSA_GWDT_W_IIDR_IMPLEMENTER(x) (x & 0xfff) +#define SBSA_GWDT_W_IIDR_VID_BANK(x) ((x >> 8) & 0xf) +#define SBSA_GWDT_W_IIDR_VID(x) (x & 0x7f)
+/* Watchdog Identification Register */ +#define SBSA_GWDT_IDR_W_PIDR2 (0xfe8) +#define SBSA_GWDT_IDR_W_PIDR2_ARCH_VER(x) ((x >> 4) & 0xf)
+/**
- struct sbsa_gwdt_info - SBSA Generic Watchdog device hardware information
- @pid: GWDT ProductID
- @arch_ver: GWDT architecture version
- @revision: GWDT revision number
- @vid_bank: GWDT The JEP106 continuation code of the implementer
- @vid: GWDT The JEP106 identity code of the implementer
- @refresh_pa: the watchdog refresh frame(PA)
- @control_pa: the watchdog control frame(PA)
- */
+struct sbsa_gwdt_info {
- unsigned int pid;
- unsigned int arch_ver;
- unsigned int revision;
- unsigned int vid_bank;
- unsigned int vid;
- void *refresh_pa;
- void *control_pa;
+};
+/**
- struct sbsa_gwdt_device_data - Internal representation of the SBSA GWDT
- @refresh_base: VA of the watchdog refresh frame
- @control_base: VA of the watchdog control frame
- @irq: Watchdog Timer GSIV (WS0)
- @flags: Watchdog Timer Flags
- @dev: Pointer to kernel device structure
- @info: SBSA Generic Watchdog info structure
- @lock: GWDT mutex
- */
+struct sbsa_gwdt_device_data {
- void __iomem *refresh_base;
- void __iomem *control_base;
- int irq;
- u32 flags;
- struct device *dev;
- struct sbsa_gwdt_info info;
- struct mutex lock;
+};
+struct sbsa_gwdt {
- struct sbsa_gwdt_device_data device_data;
- struct watchdog_device wdd;
- unsigned int pretimeout; /* seconds */
- unsigned int max_pretimeout;
- u64 wcv_dump;
+#ifdef CONFIG_PM_SLEEP
- u8 pm_status_store;
+#endif +};
+#define to_sbsa_gwdt(e) container_of(e, struct sbsa_gwdt, wdd)
+#endif /* _SBSA_GENERIC_WATCHDOG_H_ */